Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,3 @@ Explain the change and why it’s needed.
- [ ] Linted locally (`npm run lint`) and tests pass (`npm test`).
- [ ] If user‑facing, commit message uses `feat:` or `fix:` (or `BREAKING CHANGE` where appropriate).
- [ ] Updated docs if needed.

4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: CI

on:
push:
branches: [ main, master ]
branches: [main, master]
pull_request:
branches: [ main, master ]
branches: [main, master]

jobs:
build:
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/commitlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,3 @@ jobs:
- name: Lint commit messages
run: |
npx commitlint --from=${{ github.event.pull_request.base.sha }} --to=${{ github.sha }} --verbose

2 changes: 1 addition & 1 deletion .husky/pre-push
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ if [ -n "$CI" ] || [ "$HUSKY" = "0" ] || [ -n "$HUSKY_SKIP_HOOKS" ]; then
exit 0
fi

npm test && npm run build
npm run lint --fix && npm run format:check && npm test && npm run build
8 changes: 8 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"printWidth": 100,
"singleQuote": true,
"semi": true,
"trailingComma": "es5",
"arrowParens": "always",
"tabWidth": 2
}
4 changes: 1 addition & 3 deletions .releaserc.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
{
"branches": [
"main"
],
"branches": ["main"],
"plugins": [
["@semantic-release/commit-analyzer", { "preset": "conventionalcommits" }],
["@semantic-release/release-notes-generator", { "preset": "conventionalcommits" }],
Expand Down
6 changes: 6 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Repository Guidelines

## Project Structure & Module Organization

- `src/` TypeScript source (ESM). Entry: `src/index.ts` → `main.ts`; shared helpers in `src/shared/`.
- `bin/` CLI launcher (`openrouter`) that loads `dist/index.js`.
- `dist/` build output (generated by `npm run build`). Do not edit.
Expand All @@ -9,6 +10,7 @@
- Config files: global `~/.config/openrouter-cli/config.json`; project overrides `.openrouterrc(.json|.yaml|.yml)`.

## Build, Test, and Development Commands

- `npm run dev` — run CLI in TS directly (ts-node ESM). Example: `npm run dev -- ask "Hello"`.
- `npm run build` — compile TypeScript to `dist/`.
- `npm test` / `npm run test:watch` — run Vitest once / in watch mode.
Expand All @@ -17,21 +19,25 @@
- After build: `openrouter --help` (via `bin/openrouter`) or `node dist/index.js`.

## Coding Style & Naming Conventions

- TypeScript, ESM, 2-space indentation, single quotes allowed; prefer explicit return types for exported functions.
- File names: lowercase (e.g., `main.ts`, `repl.ts`, `shared/openrouter.ts`).
- ESM import paths in TS include `.js` (e.g., `import { x } from './main.js'`).
- Use helpers to protect secrets; never log API keys. Config files are written with chmod `600` when possible.
- Linting via flat-config ESLint (`eslint.config.js`); pre-commit runs `lint-staged`.

## Testing Guidelines

- Framework: Vitest. Place tests in `tests/*.spec.ts` with clear, isolated cases.
- Cover config precedence, URL joining, and CLI option parsing. Example: see `tests/openrouter.spec.ts` for `joinUrl`.
- Run `npm test` locally; keep tests deterministic (no network). Mock I/O when needed.

## Commit & Pull Request Guidelines

- Follow Conventional Commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`, `test:`; use scopes when helpful (e.g., `feat(config): ...`). Use `npm run commit`.
- PRs: concise description, linked issues, CLI examples (commands/output), and updated docs when behavior changes. Ensure `lint`, `test`, and `build` pass.

## Security & Configuration Tips

- Prefer `OPENROUTER_API_KEY`/`OPENAI_API_KEY`; avoid committing secrets. Use `openrouter config --api-key` only if persistence is required.
- Example: `openrouter config --model meta-llama/llama-3.1-8b-instruct --domain https://openrouter.ai/api/v1`.
12 changes: 5 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
## 1.0.0-beta.1 (2025-09-07)


### ⚠ BREAKING CHANGES

* **story/iteration-one:** new features
- **story/iteration-one:** new features

### Features

* add initial project structure and configuration files ([03c77bd](https://github.com/jwill9999/openrouter-cli/commit/03c77bdb9eef1a5daa496383e6708625419fc6b2))
* **story/iteration-one:** add husky, github workflows, releases and tags, npm release ([147b78c](https://github.com/jwill9999/openrouter-cli/commit/147b78cee9d56fd1d6cfe33e382db215e7b7e760))
* **story/iteration-one:** fix release workflow ([ac42562](https://github.com/jwill9999/openrouter-cli/commit/ac42562cf525ae42e5804b25a080bf5bc877dfa0))

- add initial project structure and configuration files ([03c77bd](https://github.com/jwill9999/openrouter-cli/commit/03c77bdb9eef1a5daa496383e6708625419fc6b2))
- **story/iteration-one:** add husky, github workflows, releases and tags, npm release ([147b78c](https://github.com/jwill9999/openrouter-cli/commit/147b78cee9d56fd1d6cfe33e382db215e7b7e760))
- **story/iteration-one:** fix release workflow ([ac42562](https://github.com/jwill9999/openrouter-cli/commit/ac42562cf525ae42e5804b25a080bf5bc877dfa0))

### Bug Fixes

* **story/iteration-one:** Fix failing release ([496821b](https://github.com/jwill9999/openrouter-cli/commit/496821b94161f14f717b791dfd686f0cbe798479))
- **story/iteration-one:** Fix failing release ([496821b](https://github.com/jwill9999/openrouter-cli/commit/496821b94161f14f717b791dfd686f0cbe798479))
112 changes: 80 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,97 @@
[![npm latest](https://img.shields.io/npm/v/@letuscode/openrouter-cli)](https://www.npmjs.com/package/@letuscode/openrouter-cli)
[![npm beta](https://img.shields.io/npm/v/@letuscode/openrouter-cli/beta)](https://www.npmjs.com/package/@letuscode/openrouter-cli?activeTab=versions)

OpenAI‑compatible CLI for OpenRouter. Ask questions, run a REPL, and manage per‑project or global settings.
OpenAI‑compatible CLI for OpenRouter. Ask questions, chat in a REPL, and fuzzy‑search models.

Requirements
- Node.js 18.17+ (ESM)
You can change your model any time. In a terminal, run `openrouter models` to browse, or in the REPL type `/model` to search inline. Tip: search for `free` to see free models.

## Install

Install
- Global: `npm i -g @letuscode/openrouter-cli`
- One‑off: `npx @letuscode/openrouter-cli --help`

Quick start
1) Run the wizard: `openrouter init` (select provider, set domain/model, and add an API key)
2) Ask something: `openrouter ask --no-stream "Hello!"`
3) Chat interactively: `openrouter repl`

Core commands
- `openrouter init` — interactive setup (provider, domain, key, model, profile)
- `openrouter config` — view config or set API key
- Examples:
- `openrouter config --list`
- `openrouter config --api-key sk-...` (stores in base config)
- `openrouter config --profile dev --api-key sk-...` (stores in profile)
- `openrouter test` — verify connectivity (`/models`)
- `openrouter test [--profile dev] [--no-init]`
- `openrouter ask` — one‑shot prompt
- `openrouter ask "your question" [-s SYSTEM] [--format auto|plain|md] [--profile NAME] [--no-stream] [--no-init]`
Tip: Running `openrouter` with no args starts the setup wizard and then opens the REPL (in a terminal).

### Requirements

- Node.js 18.17+ (ESM)

## Quick start

1. Create an API key: https://openrouter.ai/keys
2. Run setup: `openrouter` (or `openrouter init`) — enter your key if asked, then pick a model
3. Ask once: `openrouter ask "Hello!"` — formatted answer by default
4. Chat: `openrouter repl` — formatted replies; toggle streaming when you like

## Everyday commands

- `openrouter` (or `openrouter init`) — setup; uses the OpenRouter domain automatically; asks for a key only if missing; lets you pick a model; opens the REPL afterwards
- `openrouter ask "…"` — answer a single question (formatted by default)
- `openrouter repl` — interactive chat
- REPL commands: `exit`, `/model <name>`, `/system <text>`, `/format md|plain`, `/stream on|off`
- In the REPL:
- `/model` → inline search; type a few letters, pick a match
- `/model <id>` → set a specific model
- `/format md|plain` → formatted or plain replies (non‑stream)
- `/stream on|off` → stream tokens or wait for a full reply
- `exit` → quit
- `openrouter models [query]` — browse models (fuzzy search) in a terminal; prints a table in non‑TTY
- `openrouter config --list` — show current settings (keys are masked)
- `openrouter config --api-key sk-…` — set your key once (or use the env var below)

## Behavior & defaults

- Ask: non‑stream + markdown rendering by default. Add `--stream` to stream tokens.
- REPL: streaming OFF by default; markdown rendering for full replies; inline `/model` search.

Configuration
- API key via env (recommended): `export OPENROUTER_API_KEY=...` (or `OPENAI_API_KEY`)
- Global config file: `~/.config/openrouter-cli/config.json` (chmod 600 where possible; keys never logged)
## Configuration

- API key via env (recommended): `export OPENROUTER_API_KEY=…` (or `OPENAI_API_KEY`)
- Global config file: `~/.config/openrouter-cli/config.json` (private; keys never logged)
- Project overrides: add `.openrouterrc` (JSON or YAML) in your project root
- Example `.openrouterrc` (JSON):
{
"domain": "http://localhost:11434/v1",
"model": "gemma2:9b-instruct"
"domain": "https://openrouter.ai/api/v1",
"model": "openrouter/auto"
}
- Changing default provider, domain, or model: re‑run `openrouter init` (this is the only way to update these defaults).
- More details: see `docs/CONFIGURATION.md`.
- Domain: fixed to the OpenRouter domain today (no prompt); kept in config for future provider choices
- Change your default model any time by running `openrouter` again
- Precedence: project rc > profile > global; env keys override persisted keys

## Model search

- `openrouter models` opens an interactive search in a terminal (type 2–3 letters)
- `openrouter models llama` starts with “llama” suggestions; prints a table in non‑TTY

### Example: inline model search in REPL

```text
(openai/gpt-oss-20b:free) > /model
Search models (>=2 chars, blank to cancel): free
Matches:
1. openai/gpt-oss-120b:free — OpenAI: gpt-oss-120b (free)
2. openai/gpt-oss-20b:free — OpenAI: gpt-oss-20b (free)
Pick 1-10 or type a model id:
```

## Output & accessibility

- Non‑stream answers render markdown (bold/italic, headings, lists, inline code). Streaming prints raw tokens for responsiveness.
- A “Thinking” spinner shows while waiting; colors/spinners honor `NO_COLOR` and TTY detection.

## Troubleshooting

- Missing API key: set `OPENROUTER_API_KEY` or run `openrouter` again. View current config: `openrouter config --list`.
- “Policy / free endpoints” error: open https://openrouter.ai/settings/privacy and enable free endpoints, or choose a different model (`openrouter models`).
- Picker shows a table: run in a terminal (TTY). Check: `node -p "process.stdout.isTTY && process.stdin.isTTY"`.
- Friendly errors are shown; details are logged to `~/.config/openrouter-cli/cli.log`.

## Advanced flags (optional)

- Ask: `--stream`, `--format auto|plain|md`, `-s, --system <text>`, `--profile <name>`, `--no-init`
- Models: `--non-interactive`
- Config (debug): `--danger-reset`, `--override-json '<json>'`

Troubleshooting
- “Missing API key”: set `OPENROUTER_API_KEY` or run `openrouter init` (or `openrouter config --api-key sk-...`).
- Non‑TTY/CI: pass `--no-init` to skip interactive prompts.
## License

License
- MIT
1 change: 0 additions & 1 deletion bin/openrouter
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
#!/usr/bin/env node
import('../dist/index.js');

2 changes: 1 addition & 1 deletion commitlint.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ module.exports = {
'subject-case': [0],
// Allow long auto-generated release notes from semantic-release
'body-max-line-length': [0],
'footer-max-line-length': [0]
'footer-max-line-length': [0],
},
};
Loading