orcommit 1.2.21 → 1.2.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +155 -124
- package/dist/cli.d.ts +17 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +118 -26
- package/dist/cli.js.map +1 -1
- package/dist/modules/api.d.ts +5 -5
- package/dist/modules/api.d.ts.map +1 -1
- package/dist/modules/api.js +31 -11
- package/dist/modules/api.js.map +1 -1
- package/dist/modules/config.d.ts +38 -7
- package/dist/modules/config.d.ts.map +1 -1
- package/dist/modules/config.js +117 -12
- package/dist/modules/config.js.map +1 -1
- package/dist/modules/core.d.ts.map +1 -1
- package/dist/modules/core.js +13 -6
- package/dist/modules/core.js.map +1 -1
- package/dist/types/index.d.ts +18 -7
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +13 -0
- package/dist/types/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,181 +1,217 @@
|
|
|
1
1
|
# ORCommit
|
|
2
2
|
|
|
3
|
-
### AI-powered
|
|
3
|
+
### AI-powered git commit messages — secure, conventional, multi-provider
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
6
|
<img src="https://unpkg.com/orcommit@latest/preview.png" alt="ORCommit Banner" width="600" />
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
|
-
> Generate **accurate, conventional, and secure** git commit messages using **OpenAI, Claude, OpenRouter, or local models (Ollama)**.
|
|
10
|
-
|
|
11
9
|
```bash
|
|
12
10
|
git add .
|
|
13
11
|
orc commit
|
|
14
12
|
```
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
✔ Secret scanning (Gitleaks)
|
|
18
|
-
✔ Cloud & local AI
|
|
19
|
-
✔ Zero-config to start
|
|
14
|
+
ORCommit reads your staged diff and writes a clean, [Conventional Commit](https://www.conventionalcommits.org/) message for you — using OpenRouter, OpenAI, a local model (Ollama), or any OpenAI-compatible API. It scans for secrets before committing, so you don't leak keys into git history.
|
|
20
15
|
|
|
21
16
|
<p align="center">
|
|
22
17
|
<a href="https://badge.fury.io/js/orcommit"><img src="https://badge.fury.io/js/orcommit.svg" alt="npm version"></a>
|
|
23
|
-
<a href="https://github.com/ellerbrock/typescript-badges/"><img src="https://badges.frapsoft.com/typescript/code/typescript.svg?v=101" alt="TypeScript"></a>
|
|
24
18
|
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
|
|
25
19
|
</p>
|
|
26
20
|
|
|
27
21
|
---
|
|
28
22
|
|
|
29
|
-
##
|
|
23
|
+
## Install
|
|
30
24
|
|
|
31
|
-
|
|
25
|
+
```bash
|
|
26
|
+
npm install -g orcommit
|
|
27
|
+
```
|
|
32
28
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
> **Never use `sudo npm install -g`.** A root-owned install breaks every later
|
|
30
|
+
> update with `EACCES`. If the install asks for elevated permissions, fix your
|
|
31
|
+
> npm prefix once (no sudo ever again):
|
|
32
|
+
>
|
|
33
|
+
> ```bash
|
|
34
|
+
> mkdir -p ~/.npm-global
|
|
35
|
+
> npm config set prefix ~/.npm-global
|
|
36
|
+
> echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.zshrc
|
|
37
|
+
> source ~/.zshrc
|
|
38
|
+
> ```
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
Update with `npm install -g orcommit@latest`. ORCommit tells you when a new
|
|
41
|
+
version exists — it never auto-installs and never asks for sudo.
|
|
40
42
|
|
|
41
43
|
---
|
|
42
44
|
|
|
43
|
-
##
|
|
45
|
+
## Setup (60 seconds)
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
Pick a provider and give it a key.
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
* OpenAI (GPT‑4o, GPT‑4o‑mini)
|
|
49
|
-
* Local models via **Ollama** (offline & private)
|
|
49
|
+
**OpenRouter** (recommended — 200+ models, one key):
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
```bash
|
|
52
|
+
orc config set openrouter YOUR_API_KEY
|
|
53
|
+
```
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
**OpenAI:**
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
57
|
+
```bash
|
|
58
|
+
orc config set openai YOUR_API_KEY
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Then commit:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
git add .
|
|
65
|
+
orc commit
|
|
66
|
+
```
|
|
64
67
|
|
|
65
|
-
|
|
68
|
+
That's it. **Whichever provider you configure last becomes the active one** —
|
|
69
|
+
configure a key (or a custom provider), and it's immediately used. You normally
|
|
70
|
+
keep just one active provider and never think about it.
|
|
66
71
|
|
|
67
|
-
|
|
68
|
-
* Blocks API keys, tokens, private keys
|
|
69
|
-
* Prevents committing `node_modules/`, `vendor/`, etc.
|
|
70
|
-
* Secure API key storage (600 permissions)
|
|
72
|
+
---
|
|
71
73
|
|
|
72
|
-
|
|
74
|
+
## How it works
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
* Optional push after commit
|
|
76
|
-
* Git hooks support
|
|
76
|
+
When you run `orc commit`, ORCommit:
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
1. **Reads** your staged diff (`git add` first — it only looks at staged changes).
|
|
79
|
+
2. **Scans** it for secrets with Gitleaks. If it finds an API key, token, or
|
|
80
|
+
private key, it **stops** — nothing is committed.
|
|
81
|
+
3. **Sends** the diff to your AI provider, which returns a structured commit
|
|
82
|
+
message (schema-constrained JSON, so no brittle text parsing).
|
|
83
|
+
4. **Shows** you the message. You confirm, regenerate with feedback, or edit it.
|
|
84
|
+
5. **Commits** (and optionally pushes).
|
|
79
85
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
* Strict TypeScript + comprehensive tests
|
|
86
|
+
Large diffs are chunked automatically, and messages are cached per-repository so
|
|
87
|
+
the same diff isn't re-billed.
|
|
83
88
|
|
|
84
89
|
---
|
|
85
90
|
|
|
86
|
-
##
|
|
91
|
+
## Everyday commands
|
|
87
92
|
|
|
88
93
|
```bash
|
|
89
|
-
|
|
90
|
-
orc
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
orc commit
|
|
94
|
+
orc commit # interactive — review before committing
|
|
95
|
+
orc commit -y # auto-confirm, skip the prompt
|
|
96
|
+
orc commit -p openai # use a specific provider for this commit
|
|
97
|
+
orc commit --dry-run # generate the message, don't commit
|
|
98
|
+
orc commit --context "..." # give the AI extra context
|
|
99
|
+
orc commit --emoji # gitmoji style
|
|
100
|
+
orc commit --breaking # mark as a breaking change
|
|
94
101
|
```
|
|
95
102
|
|
|
96
|
-
|
|
103
|
+
| Command | What it does |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `orc commit` | Generate and create a commit |
|
|
106
|
+
| `orc config` | Manage providers and settings |
|
|
107
|
+
| `orc test [provider]` | Check a provider's connection works |
|
|
108
|
+
| `orc doctor` | Diagnose install / PATH / update problems |
|
|
109
|
+
| `orc cache` | Manage the commit-message cache |
|
|
97
110
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
> ```bash
|
|
104
|
-
> mkdir -p ~/.npm-global
|
|
105
|
-
> npm config set prefix ~/.npm-global
|
|
106
|
-
> echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.zshrc
|
|
107
|
-
> source ~/.zshrc
|
|
108
|
-
> ```
|
|
111
|
+
Full flag list: `orc commit --help`.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Managing providers
|
|
109
116
|
|
|
110
|
-
|
|
117
|
+
See everything that's configured:
|
|
111
118
|
|
|
112
119
|
```bash
|
|
113
|
-
|
|
120
|
+
orc config get # all providers + the current default
|
|
121
|
+
orc config path # where the config file lives
|
|
114
122
|
```
|
|
115
123
|
|
|
116
|
-
|
|
117
|
-
never asks for sudo.
|
|
124
|
+
Set or change a key / model on an existing provider:
|
|
118
125
|
|
|
119
|
-
|
|
126
|
+
```bash
|
|
127
|
+
orc config set <provider> <api-key>
|
|
128
|
+
orc config model <provider> <model>
|
|
129
|
+
```
|
|
120
130
|
|
|
121
|
-
|
|
122
|
-
installs, run the built-in diagnostic — it inspects your npm prefix, every `orc`
|
|
123
|
-
on your `PATH`, and the installed-vs-latest version, then prints exact fixes:
|
|
131
|
+
Add **any OpenAI-compatible endpoint** as a custom provider:
|
|
124
132
|
|
|
125
133
|
```bash
|
|
126
|
-
orc
|
|
134
|
+
orc config provider <name> \
|
|
135
|
+
--base-url <url> \
|
|
136
|
+
--key <api-key> \
|
|
137
|
+
--model <model> \
|
|
138
|
+
--auth-header <header> # optional — default: Authorization
|
|
139
|
+
--auth-scheme <scheme> # optional — default: Bearer (pass "" to send the key raw)
|
|
127
140
|
```
|
|
128
141
|
|
|
129
|
-
|
|
142
|
+
> Custom providers **must** set `--model`. ORCommit only ships default models for
|
|
143
|
+
> the built-in `openrouter` and `openai` providers — it can't guess a third
|
|
144
|
+
> party's catalog.
|
|
130
145
|
|
|
131
|
-
|
|
146
|
+
Use a provider for one commit, or remove it:
|
|
132
147
|
|
|
133
148
|
```bash
|
|
134
|
-
orc commit
|
|
135
|
-
orc
|
|
136
|
-
orc commit --context "..." # extra context
|
|
137
|
-
orc commit --emoji # gitmoji
|
|
138
|
-
orc commit --breaking # breaking change
|
|
139
|
-
orc commit --dry-run # preview only
|
|
140
|
-
orc doctor # diagnose install / PATH / update issues
|
|
149
|
+
orc commit -p <name>
|
|
150
|
+
orc config remove-provider <name> # can't remove the current default — switch first
|
|
141
151
|
```
|
|
142
152
|
|
|
143
|
-
|
|
153
|
+
### Switching the active provider
|
|
144
154
|
|
|
145
|
-
|
|
155
|
+
Configuring a provider already makes it active, so usually there's nothing to
|
|
156
|
+
do. To switch back to an already-configured provider (e.g. your default ran out
|
|
157
|
+
of credit and you want to use another one you'd set up earlier):
|
|
146
158
|
|
|
147
|
-
|
|
159
|
+
```bash
|
|
160
|
+
orc config default <name>
|
|
161
|
+
```
|
|
148
162
|
|
|
149
|
-
|
|
163
|
+
Or pass `-p <name>` on a single commit without changing the active provider.
|
|
150
164
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
* 🚫 Prevents committing dependency folders
|
|
165
|
+
Removing the active provider automatically falls back to another configured one
|
|
166
|
+
— you never end up with the default pointing at a provider that's gone.
|
|
154
167
|
|
|
155
|
-
|
|
168
|
+
---
|
|
156
169
|
|
|
157
|
-
|
|
170
|
+
## Example: a custom provider (cmdop)
|
|
158
171
|
|
|
159
|
-
|
|
172
|
+
[cmdop](https://cmdop.com)'s router is OpenAI-compatible but authenticates with
|
|
173
|
+
an `X-API-Key` header (not `Authorization: Bearer`) and uses model aliases like
|
|
174
|
+
`@cheap` / `@fast` / `@balanced` / `@smart`:
|
|
160
175
|
|
|
161
|
-
|
|
176
|
+
```bash
|
|
177
|
+
orc config provider cmdop \
|
|
178
|
+
--base-url https://router.cmdop.com/v1 \
|
|
179
|
+
--key YOUR_CMDOP_API_KEY \
|
|
180
|
+
--model @fast \
|
|
181
|
+
--auth-header X-API-Key
|
|
162
182
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
183
|
+
orc commit -p cmdop
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
This adds an entry to `~/.config/orcommit.json`:
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"providers": {
|
|
191
|
+
"cmdop": {
|
|
192
|
+
"baseUrl": "https://router.cmdop.com/v1",
|
|
193
|
+
"apiKey": "YOUR_CMDOP_API_KEY",
|
|
194
|
+
"model": "@fast",
|
|
195
|
+
"authHeader": "X-API-Key"
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Because `authHeader` isn't `Authorization`, the key is sent **raw** (no `Bearer`
|
|
202
|
+
prefix). For endpoints that use bearer auth with a non-standard scheme, use
|
|
203
|
+
`--auth-scheme` instead.
|
|
166
204
|
|
|
167
205
|
---
|
|
168
206
|
|
|
169
|
-
##
|
|
207
|
+
## Configuration
|
|
170
208
|
|
|
171
|
-
Config
|
|
209
|
+
Config lives at `~/.config/orcommit.json` (permissions `600`). A minimal file:
|
|
172
210
|
|
|
173
211
|
```json
|
|
174
212
|
{
|
|
175
213
|
"providers": {
|
|
176
|
-
"openrouter": {
|
|
177
|
-
"model": "google/gemini-2.5-flash-lite"
|
|
178
|
-
}
|
|
214
|
+
"openrouter": { "model": "google/gemini-2.5-flash-lite" }
|
|
179
215
|
},
|
|
180
216
|
"preferences": {
|
|
181
217
|
"defaultProvider": "openrouter",
|
|
@@ -186,47 +222,42 @@ Config is stored at `~/.config/orcommit.json` (permissions `600`).
|
|
|
186
222
|
```
|
|
187
223
|
|
|
188
224
|
> A low `temperature` (default `0.3`) keeps messages grounded in the actual diff
|
|
189
|
-
>
|
|
225
|
+
> instead of drifting into generic phrasing.
|
|
190
226
|
|
|
191
|
-
|
|
227
|
+
API keys can also come from the environment:
|
|
192
228
|
|
|
193
229
|
```bash
|
|
194
230
|
export OPENROUTER_API_KEY="your-key"
|
|
195
231
|
export OPENAI_API_KEY="your-key"
|
|
196
232
|
```
|
|
197
233
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
## 📚 Documentation
|
|
201
|
-
|
|
202
|
-
* [CLI Reference](https://github.com/markolofsen/openrouter-commit/blob/main/docs/cli.md)
|
|
203
|
-
* [Security Model](https://github.com/markolofsen/openrouter-commit/blob/main/docs/security.md)
|
|
204
|
-
* [Architecture](https://github.com/markolofsen/openrouter-commit/blob/main/docs/architecture.md)
|
|
205
|
-
* [Advanced Usage](https://github.com/markolofsen/openrouter-commit/blob/main/docs/advanced.md)
|
|
234
|
+
Defaults out of the box: `google/gemini-2.5-flash-lite` on OpenRouter (cheap,
|
|
235
|
+
fast, good structured output) and `gpt-4o-mini` on OpenAI.
|
|
206
236
|
|
|
207
237
|
---
|
|
208
238
|
|
|
209
|
-
##
|
|
239
|
+
## Troubleshooting
|
|
210
240
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
241
|
+
| Problem | Fix |
|
|
242
|
+
|---|---|
|
|
243
|
+
| `402 Insufficient credits` | Your provider is out of credit. Top up, switch with `orc config default <name>`, or commit once via `-p <name>`. |
|
|
244
|
+
| Wrong version / won't update / duplicate installs | Run `orc doctor`. |
|
|
245
|
+
| Provider not responding | Run `orc test <provider>` to check the connection. |
|
|
215
246
|
|
|
216
247
|
---
|
|
217
248
|
|
|
218
|
-
##
|
|
249
|
+
## Documentation
|
|
219
250
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
251
|
+
* [CLI Reference](https://github.com/markolofsen/openrouter-commit/blob/main/docs/cli.md)
|
|
252
|
+
* [Security Model](https://github.com/markolofsen/openrouter-commit/blob/main/docs/security.md)
|
|
253
|
+
* [Architecture](https://github.com/markolofsen/openrouter-commit/blob/main/docs/architecture.md)
|
|
254
|
+
* [Advanced Usage](https://github.com/markolofsen/openrouter-commit/blob/main/docs/advanced.md)
|
|
223
255
|
|
|
224
256
|
---
|
|
225
257
|
|
|
226
|
-
##
|
|
258
|
+
## About
|
|
227
259
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
---
|
|
260
|
+
ORCommit is built and maintained by **[Reforms.ai](https://reforms.ai)**.
|
|
261
|
+
Commercial support and custom AI integrations are available.
|
|
231
262
|
|
|
232
|
-
|
|
263
|
+
MIT License — see [LICENSE](LICENSE).
|
package/dist/cli.d.ts
CHANGED
|
@@ -25,6 +25,18 @@ declare class CliApplication {
|
|
|
25
25
|
* Handle model configuration command
|
|
26
26
|
*/
|
|
27
27
|
private handleConfigModel;
|
|
28
|
+
/**
|
|
29
|
+
* Handle full custom-provider configuration in one call
|
|
30
|
+
*/
|
|
31
|
+
private handleConfigProvider;
|
|
32
|
+
/**
|
|
33
|
+
* Handle removing a configured provider
|
|
34
|
+
*/
|
|
35
|
+
private handleConfigRemoveProvider;
|
|
36
|
+
/**
|
|
37
|
+
* Handle setting the active (default) provider
|
|
38
|
+
*/
|
|
39
|
+
private handleConfigDefault;
|
|
28
40
|
/**
|
|
29
41
|
* Handle custom prompt configuration
|
|
30
42
|
*/
|
|
@@ -61,12 +73,15 @@ declare class CliApplication {
|
|
|
61
73
|
* Validate commit type
|
|
62
74
|
*/
|
|
63
75
|
private validateCommitType;
|
|
76
|
+
private static readonly PROVIDER_NAME_RE;
|
|
64
77
|
/**
|
|
65
|
-
* Validate provider
|
|
78
|
+
* Validate provider name (commander option parser). Accepts any
|
|
79
|
+
* syntactically valid provider identifier.
|
|
66
80
|
*/
|
|
67
81
|
private validateProvider;
|
|
68
82
|
/**
|
|
69
|
-
* Check
|
|
83
|
+
* Check whether a provider name is syntactically valid (not whether it is
|
|
84
|
+
* one of the built-ins — any registered provider is allowed).
|
|
70
85
|
*/
|
|
71
86
|
private isValidProvider;
|
|
72
87
|
/**
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAiBA;;GAEG;AACH,cAAM,cAAc;IAClB,OAAO,CAAC,OAAO,CAAU;;IAQzB;;OAEG;IACH,OAAO,CAAC,aAAa;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAiBA;;GAEG;AACH,cAAM,cAAc;IAClB,OAAO,CAAC,OAAO,CAAU;;IAQzB;;OAEG;IACH,OAAO,CAAC,aAAa;IA8KrB;;OAEG;YACW,mBAAmB;IAwBjC;;OAEG;YACW,eAAe;IAgB7B;;OAEG;YACW,eAAe;IAmD7B;;OAEG;YACW,iBAAiB;IAgB/B;;OAEG;YACW,oBAAoB;IA0BlC;;OAEG;YACW,0BAA0B;IAgBxC;;OAEG;YACW,mBAAmB;IAgBjC;;OAEG;YACW,kBAAkB;IAkBhC;;OAEG;YACW,iBAAiB;IA+B/B;;OAEG;YACW,mBAAmB;IAYjC;;OAEG;YACW,eAAe;IAQ7B;;OAEG;YACW,gBAAgB;IAmB9B;;OAEG;YACW,gBAAgB;IAc9B;;OAEG;YACW,kBAAkB;IAchC;;OAEG;YACW,eAAe;IAgB7B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAgB1B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAsB;IAE9D;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAOxB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAIvB;;OAEG;IACG,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAqC3B;AASD,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -40,7 +40,7 @@ class CliApplication {
|
|
|
40
40
|
// NOTE: no -v short flag here — -v is reserved program-wide for --version.
|
|
41
41
|
.option('--verbose', 'Enable verbose logging', false)
|
|
42
42
|
.option('-w, --watch', 'Watch for changes and auto-generate commits', false)
|
|
43
|
-
.option('-p, --provider <provider>', 'Specify AI provider (
|
|
43
|
+
.option('-p, --provider <provider>', 'Specify AI provider (any configured provider)', this.validateProvider)
|
|
44
44
|
// Extended formatting options
|
|
45
45
|
.option('--emoji', 'Include emoji in commit message', false)
|
|
46
46
|
.option('--one-line', 'Generate single-line commit message', false)
|
|
@@ -69,7 +69,7 @@ class CliApplication {
|
|
|
69
69
|
.description('Manage configuration settings');
|
|
70
70
|
configCmd
|
|
71
71
|
.command('set <provider> <key>')
|
|
72
|
-
.description('Set API key for provider (
|
|
72
|
+
.description('Set API key for a provider (creates it if new)')
|
|
73
73
|
.action(async (provider, key) => {
|
|
74
74
|
await this.handleConfigSet(provider, key);
|
|
75
75
|
});
|
|
@@ -85,6 +85,29 @@ class CliApplication {
|
|
|
85
85
|
.action(async (provider, model) => {
|
|
86
86
|
await this.handleConfigModel(provider, model);
|
|
87
87
|
});
|
|
88
|
+
configCmd
|
|
89
|
+
.command('provider <name>')
|
|
90
|
+
.description('Configure a custom provider (baseUrl, key, model, auth header)')
|
|
91
|
+
.option('--base-url <url>', 'API base URL (e.g. https://router.cmdop.com/v1)')
|
|
92
|
+
.option('--key <key>', 'API key')
|
|
93
|
+
.option('--model <model>', 'Default model (e.g. @fast)')
|
|
94
|
+
.option('--auth-header <header>', "Auth header name (default 'Authorization'; use 'X-API-Key' for cmdop)")
|
|
95
|
+
.option('--auth-scheme <scheme>', "Scheme prefix for Authorization header (default 'Bearer'; pass empty to send raw)")
|
|
96
|
+
.action(async (name, opts) => {
|
|
97
|
+
await this.handleConfigProvider(name, opts);
|
|
98
|
+
});
|
|
99
|
+
configCmd
|
|
100
|
+
.command('remove-provider <name>')
|
|
101
|
+
.description('Remove a configured provider')
|
|
102
|
+
.action(async (name) => {
|
|
103
|
+
await this.handleConfigRemoveProvider(name);
|
|
104
|
+
});
|
|
105
|
+
configCmd
|
|
106
|
+
.command('default <name>')
|
|
107
|
+
.description('Set the active (default) provider')
|
|
108
|
+
.action(async (name) => {
|
|
109
|
+
await this.handleConfigDefault(name);
|
|
110
|
+
});
|
|
88
111
|
configCmd
|
|
89
112
|
.command('prompt [text]')
|
|
90
113
|
.description('Set or clear custom system prompt (omit text to clear)')
|
|
@@ -182,7 +205,7 @@ class CliApplication {
|
|
|
182
205
|
async handleConfigSet(provider, key) {
|
|
183
206
|
try {
|
|
184
207
|
if (!this.isValidProvider(provider)) {
|
|
185
|
-
logger.error(`Invalid provider: ${provider}
|
|
208
|
+
logger.error(`Invalid provider name: ${provider}`);
|
|
186
209
|
process.exit(1);
|
|
187
210
|
}
|
|
188
211
|
await configManager.setApiKey(provider, key);
|
|
@@ -201,32 +224,38 @@ class CliApplication {
|
|
|
201
224
|
const config = await configManager.load();
|
|
202
225
|
if (provider) {
|
|
203
226
|
if (!this.isValidProvider(provider)) {
|
|
204
|
-
logger.error(`Invalid provider: ${provider}
|
|
227
|
+
logger.error(`Invalid provider name: ${provider}`);
|
|
205
228
|
process.exit(1);
|
|
206
229
|
}
|
|
207
|
-
const
|
|
208
|
-
const
|
|
209
|
-
const model =
|
|
230
|
+
const maskedKey = await configManager.getMaskedApiKey(provider);
|
|
231
|
+
const providerConfig = config.providers[provider];
|
|
232
|
+
const model = providerConfig?.model || 'default';
|
|
210
233
|
logger.table({
|
|
211
234
|
Provider: provider,
|
|
212
235
|
'API Key': maskedKey,
|
|
213
236
|
Model: model,
|
|
237
|
+
'Base URL': providerConfig?.baseUrl || 'default',
|
|
238
|
+
'Auth Header': providerConfig?.authHeader || 'Authorization',
|
|
214
239
|
});
|
|
215
240
|
}
|
|
216
241
|
else {
|
|
217
|
-
// Show all configuration
|
|
218
|
-
const
|
|
219
|
-
const
|
|
220
|
-
logger.table({
|
|
242
|
+
// Show all configuration — iterate over every configured provider.
|
|
243
|
+
const providers = await configManager.listProviders();
|
|
244
|
+
const table = {
|
|
221
245
|
'Default Provider': config.preferences.defaultProvider,
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
246
|
+
};
|
|
247
|
+
for (const name of providers) {
|
|
248
|
+
const maskedKey = await configManager.getMaskedApiKey(name);
|
|
249
|
+
const model = config.providers[name]?.model || 'default';
|
|
250
|
+
table[`${name} API Key`] = maskedKey;
|
|
251
|
+
table[`${name} Model`] = model;
|
|
252
|
+
}
|
|
253
|
+
table['Max Tokens'] = config.preferences.maxTokens;
|
|
254
|
+
table['Temperature'] = config.preferences.temperature;
|
|
255
|
+
table['Auto Confirm'] = config.preferences.autoConfirm;
|
|
256
|
+
table['Language'] = config.preferences.language;
|
|
257
|
+
table['Format'] = config.preferences.commitFormat;
|
|
258
|
+
logger.table(table);
|
|
230
259
|
}
|
|
231
260
|
}
|
|
232
261
|
catch (error) {
|
|
@@ -240,7 +269,7 @@ class CliApplication {
|
|
|
240
269
|
async handleConfigModel(provider, model) {
|
|
241
270
|
try {
|
|
242
271
|
if (!this.isValidProvider(provider)) {
|
|
243
|
-
logger.error(`Invalid provider: ${provider}
|
|
272
|
+
logger.error(`Invalid provider name: ${provider}`);
|
|
244
273
|
process.exit(1);
|
|
245
274
|
}
|
|
246
275
|
await configManager.setModel(provider, model);
|
|
@@ -251,6 +280,63 @@ class CliApplication {
|
|
|
251
280
|
process.exit(1);
|
|
252
281
|
}
|
|
253
282
|
}
|
|
283
|
+
/**
|
|
284
|
+
* Handle full custom-provider configuration in one call
|
|
285
|
+
*/
|
|
286
|
+
async handleConfigProvider(name, opts) {
|
|
287
|
+
try {
|
|
288
|
+
if (!this.isValidProvider(name)) {
|
|
289
|
+
logger.error(`Invalid provider name: ${name}`);
|
|
290
|
+
process.exit(1);
|
|
291
|
+
}
|
|
292
|
+
await configManager.setProvider(name, {
|
|
293
|
+
baseUrl: opts.baseUrl,
|
|
294
|
+
apiKey: opts.key,
|
|
295
|
+
model: opts.model,
|
|
296
|
+
authHeader: opts.authHeader,
|
|
297
|
+
authScheme: opts.authScheme,
|
|
298
|
+
});
|
|
299
|
+
logger.success(`Provider '${name}' configured`);
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
logger.error('Failed to configure provider', error);
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Handle removing a configured provider
|
|
308
|
+
*/
|
|
309
|
+
async handleConfigRemoveProvider(name) {
|
|
310
|
+
try {
|
|
311
|
+
if (!this.isValidProvider(name)) {
|
|
312
|
+
logger.error(`Invalid provider name: ${name}`);
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
await configManager.removeProvider(name);
|
|
316
|
+
logger.success(`Provider '${name}' removed`);
|
|
317
|
+
}
|
|
318
|
+
catch (error) {
|
|
319
|
+
logger.error('Failed to remove provider', error);
|
|
320
|
+
process.exit(1);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Handle setting the active (default) provider
|
|
325
|
+
*/
|
|
326
|
+
async handleConfigDefault(name) {
|
|
327
|
+
try {
|
|
328
|
+
if (!this.isValidProvider(name)) {
|
|
329
|
+
logger.error(`Invalid provider name: ${name}`);
|
|
330
|
+
process.exit(1);
|
|
331
|
+
}
|
|
332
|
+
await configManager.setDefaultProvider(name);
|
|
333
|
+
logger.success(`Active provider set to '${name}'`);
|
|
334
|
+
}
|
|
335
|
+
catch (error) {
|
|
336
|
+
logger.error('Failed to set default provider', error);
|
|
337
|
+
process.exit(1);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
254
340
|
/**
|
|
255
341
|
* Handle custom prompt configuration
|
|
256
342
|
*/
|
|
@@ -281,7 +367,7 @@ class CliApplication {
|
|
|
281
367
|
const config = await configManager.load();
|
|
282
368
|
const testProvider = provider || config.preferences.defaultProvider;
|
|
283
369
|
if (!this.isValidProvider(testProvider)) {
|
|
284
|
-
logger.error(`Invalid provider: ${testProvider}
|
|
370
|
+
logger.error(`Invalid provider name: ${testProvider}`);
|
|
285
371
|
process.exit(1);
|
|
286
372
|
}
|
|
287
373
|
const progress = logger.startProgress(`Testing ${testProvider} connection...`);
|
|
@@ -406,20 +492,26 @@ class CliApplication {
|
|
|
406
492
|
}
|
|
407
493
|
return value;
|
|
408
494
|
}
|
|
495
|
+
// Syntactically valid provider name: non-empty, alphanumerics, dashes,
|
|
496
|
+
// underscores. Provider is now an open dictionary, so this is a soft-format
|
|
497
|
+
// check, not a whitelist of two literals.
|
|
498
|
+
static PROVIDER_NAME_RE = /^[a-zA-Z0-9_-]+$/;
|
|
409
499
|
/**
|
|
410
|
-
* Validate provider
|
|
500
|
+
* Validate provider name (commander option parser). Accepts any
|
|
501
|
+
* syntactically valid provider identifier.
|
|
411
502
|
*/
|
|
412
503
|
validateProvider(value) {
|
|
413
|
-
if (value
|
|
414
|
-
throw new Error(`Invalid provider: ${value}
|
|
504
|
+
if (!value || !CliApplication.PROVIDER_NAME_RE.test(value)) {
|
|
505
|
+
throw new Error(`Invalid provider name: ${value}`);
|
|
415
506
|
}
|
|
416
507
|
return value;
|
|
417
508
|
}
|
|
418
509
|
/**
|
|
419
|
-
* Check
|
|
510
|
+
* Check whether a provider name is syntactically valid (not whether it is
|
|
511
|
+
* one of the built-ins — any registered provider is allowed).
|
|
420
512
|
*/
|
|
421
513
|
isValidProvider(provider) {
|
|
422
|
-
return provider
|
|
514
|
+
return Boolean(provider) && CliApplication.PROVIDER_NAME_RE.test(provider);
|
|
423
515
|
}
|
|
424
516
|
/**
|
|
425
517
|
* Run the CLI application
|