@namzu/cli 2.4.0 → 2.6.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-entry.d.ts","sourceRoot":"","sources":["../../src/tui/credential-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAA;AAEjG;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK3C;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAexF;AAED,qDAAqD;AACrD,MAAM,MAAM,YAAY,GACrB;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE;AAC/B,oEAAoE;GAClE;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAA;CAAE,GACjC;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,qBAAqB,EAC5B,YAAY,EAAE,YAAY,GACxB,MAAM,CAmBR;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,qBAAqB,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAQ7F"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Typing a credential into a running namzu, for this session only.
3
+ *
4
+ * Someone who has just installed namzu and has no key reaches a screen that
5
+ * lists three sources and says "then restart namzu". That is accurate and it is
6
+ * a cliff: the product tells them to leave it in order to use it.
7
+ *
8
+ * ## Why session-only, stated as a decision rather than a limitation
9
+ *
10
+ * The obvious durable home is the OS keychain, and here it does not exist. The
11
+ * keychain helper in this package is macOS-only, and it reads and writes a
12
+ * DIFFERENT product's credential store — namzu borrows an OAuth token from it.
13
+ * Writing a namzu key into that envelope would put our secret under their name.
14
+ * On Windows, which is where this was asked for, there is no keychain path at
15
+ * all.
16
+ *
17
+ * So the durable options were a plaintext file or a per-platform credential
18
+ * store nobody has written. Keeping the key in memory for the session is the
19
+ * honest third answer: nothing lands on disk, it works everywhere, and the
20
+ * screen names the environment variable that makes it durable. A secret at rest
21
+ * should be something the operator chose, not something that arrived because
22
+ * they typed into a text field.
23
+ *
24
+ * Everything decidable lives here rather than in the component, because this
25
+ * package has no component tests and a secret is the worst thing to leave
26
+ * unverifiable.
27
+ */
28
+ /**
29
+ * What a key looks like on screen. Never the key.
30
+ *
31
+ * Enough tail to tell two keys apart when you have pasted the wrong one, and
32
+ * never enough to reconstruct one from a screen recording or a scrollback that
33
+ * outlives the session. The length is not revealed either: a fixed-width mask
34
+ * would leak it, and key length distinguishes vendors and sometimes tiers.
35
+ */
36
+ export function maskKey(key) {
37
+ const trimmed = key.trim();
38
+ if (trimmed.length === 0)
39
+ return '';
40
+ const tail = trimmed.slice(-4);
41
+ return trimmed.length <= 4 ? '••••' : `••••••••${tail}`;
42
+ }
43
+ /**
44
+ * Whether a typed key is worth trying at all.
45
+ *
46
+ * Deliberately shallow. Anything beyond "not empty, no whitespace, not obviously
47
+ * a shell fragment" is guessing at vendor formats that change, and a validator
48
+ * that rejects a NEW valid key format is worse than one that lets the provider
49
+ * answer. The provider is the authority; this only catches the paste that
50
+ * plainly went wrong.
51
+ */
52
+ export function keyLooksUsable(key) {
53
+ const trimmed = key.trim();
54
+ if (trimmed.length === 0)
55
+ return { ok: false, reason: 'No key entered.' };
56
+ if (/\s/.test(trimmed)) {
57
+ return { ok: false, reason: 'That contains a space — check for a truncated or wrapped paste.' };
58
+ }
59
+ if (trimmed.startsWith('$') || trimmed.includes('=')) {
60
+ return {
61
+ ok: false,
62
+ // The classic: pasting `ANTHROPIC_API_KEY=sk-…` or `$MY_KEY` from a
63
+ // shell profile rather than the value.
64
+ reason: 'That looks like a shell assignment or variable. Paste the key itself.',
65
+ };
66
+ }
67
+ return { ok: true };
68
+ }
69
+ /**
70
+ * What namzu tells the operator it did with what they typed.
71
+ *
72
+ * Every branch says three things: that it worked or did not, that the key is
73
+ * held for this session only, and the environment variable that persists it.
74
+ * The middle one is the part a person is most likely to assume otherwise —
75
+ * typing a credential into an application usually means it was saved.
76
+ */
77
+ export function describeDisposition(entry, verification) {
78
+ const persist = entry.envVars[0];
79
+ const durable = persist
80
+ ? `To keep it, set ${persist} in your shell and restart.`
81
+ : 'To keep it, configure the credential in your environment and restart.';
82
+ if (verification.kind === 'rejected') {
83
+ return `${entry.label} rejected that key: ${verification.reason}\nNothing was stored.`;
84
+ }
85
+ const checked = verification.kind === 'verified'
86
+ ? `${entry.label} accepted the key.`
87
+ : // Said plainly rather than implied. A driver with no cheap check
88
+ // cannot confirm a key without spending a turn, and claiming it is
89
+ // good would be inventing a verification that did not happen.
90
+ `Key accepted. ${entry.label} offers no way to check it without a request, so the first message will be the test.`;
91
+ return `${checked}\nHeld in memory for this session only — it is not written anywhere. ${durable}`;
92
+ }
93
+ /**
94
+ * The detected-provider record a typed key produces.
95
+ *
96
+ * Shaped exactly like a discovered one so every downstream path — session
97
+ * construction, the model picker, `/provider` — treats it identically. The only
98
+ * difference is `source`, so a surface can say where it came from.
99
+ */
100
+ export function sessionCredential(entry, key) {
101
+ return {
102
+ entry,
103
+ source: { kind: 'session' },
104
+ apiKey: key.trim(),
105
+ ...(entry.defaultBaseUrl !== undefined ? { baseUrl: entry.defaultBaseUrl } : {}),
106
+ alternatives: [],
107
+ };
108
+ }
109
+ //# sourceMappingURL=credential-entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-entry.js","sourceRoot":"","sources":["../../src/tui/credential-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH;;;;;;;GAOG;AACH,MAAM,UAAU,OAAO,CAAC,GAAW;IAClC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAA;IAC1B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAA;IACnC,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAC9B,OAAO,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAA;AACxD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACzC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAA;IAC1B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAA;IACzE,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,iEAAiE,EAAE,CAAA;IAChG,CAAC;IACD,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACtD,OAAO;YACN,EAAE,EAAE,KAAK;YACT,oEAAoE;YACpE,uCAAuC;YACvC,MAAM,EAAE,uEAAuE;SAC/E,CAAA;IACF,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;AACpB,CAAC;AASD;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAClC,KAA4B,EAC5B,YAA0B;IAE1B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAChC,MAAM,OAAO,GAAG,OAAO;QACtB,CAAC,CAAC,mBAAmB,OAAO,6BAA6B;QACzD,CAAC,CAAC,uEAAuE,CAAA;IAE1E,IAAI,YAAY,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QACtC,OAAO,GAAG,KAAK,CAAC,KAAK,uBAAuB,YAAY,CAAC,MAAM,uBAAuB,CAAA;IACvF,CAAC;IAED,MAAM,OAAO,GACZ,YAAY,CAAC,IAAI,KAAK,UAAU;QAC/B,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,oBAAoB;QACpC,CAAC,CAAC,iEAAiE;YAClE,mEAAmE;YACnE,8DAA8D;YAC9D,iBAAiB,KAAK,CAAC,KAAK,sFAAsF,CAAA;IAErH,OAAO,GAAG,OAAO,wEAAwE,OAAO,EAAE,CAAA;AACnG,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAA4B,EAAE,GAAW;IAC1E,OAAO;QACN,KAAK;QACL,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QAC3B,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE;QAClB,GAAG,CAAC,KAAK,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChF,YAAY,EAAE,EAAE;KAChB,CAAA;AACF,CAAC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * What the model step of the picker offers, and what it says about the list.
3
+ *
4
+ * Pure on purpose. The TUI has no component tests, so logic that lives inside a
5
+ * React component is logic nobody can check — and the owner is currently the
6
+ * only person able to see this screen at all. Everything decidable is decided
7
+ * here, and `Picker` is left as a thin caller.
8
+ *
9
+ * ## The default is always offered
10
+ *
11
+ * Every branch returns at least the provider's `defaultModel`. A screen that
12
+ * can end with nothing selectable is a dead end for someone who came here to
13
+ * get on with a task, and the default is exactly the value they would have got
14
+ * by not visiting this step.
15
+ *
16
+ * ## The notice says which case it is
17
+ *
18
+ * "No models" is the same words for four different facts — the driver does not
19
+ * implement listing, the provider publishes none, it timed out, it errored —
20
+ * and three of them are not "this provider has no models". The timeout matters
21
+ * most: the honest line is "it did not answer in time", because the operator
22
+ * can retry that, and cannot retry a provider that genuinely has one model.
23
+ */
24
+ import type { ModelListing } from './agent.js';
25
+ export interface ModelChoice {
26
+ readonly id: string;
27
+ readonly label: string;
28
+ /** Shown beside the row. `(default)` for the provider's own default. */
29
+ readonly note?: string;
30
+ }
31
+ export interface ModelStep {
32
+ readonly choices: readonly ModelChoice[];
33
+ /**
34
+ * Why the list is short or absent, or `null` when it is a real full list.
35
+ *
36
+ * Rendered above the choices. `null` means the list is exactly what the
37
+ * provider said it was, so a notice would be noise.
38
+ */
39
+ readonly notice: string | null;
40
+ /** Index of the row to start on: the current model, else the default. */
41
+ readonly initialIndex: number;
42
+ }
43
+ /**
44
+ * Build the model step for one provider.
45
+ *
46
+ * @param defaultModel The provider's own default, always offered.
47
+ * @param listing What asking the provider produced.
48
+ * @param currentModel The model in force now, if any — so re-opening the picker
49
+ * starts on what is already selected rather than resetting to the default.
50
+ */
51
+ export declare function modelStep(defaultModel: string, listing: ModelListing, currentModel?: string): ModelStep;
52
+ //# sourceMappingURL=model-choices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-choices.d.ts","sourceRoot":"","sources":["../../src/tui/model-choices.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAA;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,yEAAyE;IACzE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;CAC7B;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACxB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,YAAY,EACrB,YAAY,CAAC,EAAE,MAAM,GACnB,SAAS,CA4CX"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * What the model step of the picker offers, and what it says about the list.
3
+ *
4
+ * Pure on purpose. The TUI has no component tests, so logic that lives inside a
5
+ * React component is logic nobody can check — and the owner is currently the
6
+ * only person able to see this screen at all. Everything decidable is decided
7
+ * here, and `Picker` is left as a thin caller.
8
+ *
9
+ * ## The default is always offered
10
+ *
11
+ * Every branch returns at least the provider's `defaultModel`. A screen that
12
+ * can end with nothing selectable is a dead end for someone who came here to
13
+ * get on with a task, and the default is exactly the value they would have got
14
+ * by not visiting this step.
15
+ *
16
+ * ## The notice says which case it is
17
+ *
18
+ * "No models" is the same words for four different facts — the driver does not
19
+ * implement listing, the provider publishes none, it timed out, it errored —
20
+ * and three of them are not "this provider has no models". The timeout matters
21
+ * most: the honest line is "it did not answer in time", because the operator
22
+ * can retry that, and cannot retry a provider that genuinely has one model.
23
+ */
24
+ /**
25
+ * Build the model step for one provider.
26
+ *
27
+ * @param defaultModel The provider's own default, always offered.
28
+ * @param listing What asking the provider produced.
29
+ * @param currentModel The model in force now, if any — so re-opening the picker
30
+ * starts on what is already selected rather than resetting to the default.
31
+ */
32
+ export function modelStep(defaultModel, listing, currentModel) {
33
+ const fallback = (notice) => ({
34
+ choices: [{ id: defaultModel, label: defaultModel, note: '(default)' }],
35
+ notice,
36
+ initialIndex: 0,
37
+ });
38
+ if (listing.kind === 'unsupported') {
39
+ return fallback('This provider does not publish a model list. Showing its default.');
40
+ }
41
+ if (listing.kind === 'timeout') {
42
+ // Deliberately not "no models". The provider may have hundreds; it just
43
+ // did not answer inside 3s, and that is a retryable condition.
44
+ return fallback('The provider did not answer in time. Showing its default — try again to list.');
45
+ }
46
+ if (listing.kind === 'failed') {
47
+ return fallback(`Could not list models: ${listing.reason}. Showing the default.`);
48
+ }
49
+ if (listing.models.length === 0) {
50
+ return fallback('The provider returned no models. Showing its default.');
51
+ }
52
+ // A real list. Make sure the default is in it and marked, because a list
53
+ // that omits the value the user would otherwise get is missing the one entry
54
+ // they can be sure works.
55
+ const seen = new Set();
56
+ const choices = [];
57
+ for (const m of listing.models) {
58
+ if (seen.has(m.id))
59
+ continue;
60
+ seen.add(m.id);
61
+ choices.push({
62
+ id: m.id,
63
+ label: m.name,
64
+ ...(m.id === defaultModel ? { note: '(default)' } : {}),
65
+ });
66
+ }
67
+ if (!seen.has(defaultModel)) {
68
+ choices.unshift({ id: defaultModel, label: defaultModel, note: '(default)' });
69
+ }
70
+ const wanted = currentModel ?? defaultModel;
71
+ const idx = choices.findIndex((c) => c.id === wanted);
72
+ return { choices, notice: null, initialIndex: idx >= 0 ? idx : 0 };
73
+ }
74
+ //# sourceMappingURL=model-choices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-choices.js","sourceRoot":"","sources":["../../src/tui/model-choices.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAwBH;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CACxB,YAAoB,EACpB,OAAqB,EACrB,YAAqB;IAErB,MAAM,QAAQ,GAAG,CAAC,MAAc,EAAa,EAAE,CAAC,CAAC;QAChD,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;QACvE,MAAM;QACN,YAAY,EAAE,CAAC;KACf,CAAC,CAAA;IAEF,IAAI,OAAO,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;QACpC,OAAO,QAAQ,CAAC,mEAAmE,CAAC,CAAA;IACrF,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAChC,wEAAwE;QACxE,+DAA+D;QAC/D,OAAO,QAAQ,CAAC,+EAA+E,CAAC,CAAA;IACjG,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,QAAQ,CAAC,0BAA0B,OAAO,CAAC,MAAM,wBAAwB,CAAC,CAAA;IAClF,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,QAAQ,CAAC,uDAAuD,CAAC,CAAA;IACzE,CAAC;IAED,yEAAyE;IACzE,6EAA6E;IAC7E,0BAA0B;IAC1B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,MAAM,OAAO,GAAkB,EAAE,CAAA;IACjC,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QAChC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAAE,SAAQ;QAC5B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QACd,OAAO,CAAC,IAAI,CAAC;YACZ,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,KAAK,EAAE,CAAC,CAAC,IAAI;YACb,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,YAAY,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACvD,CAAC,CAAA;IACH,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAA;IAC9E,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,IAAI,YAAY,CAAA;IAC3C,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,CAAA;IAErD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;AACnE,CAAC"}
@@ -64,6 +64,51 @@ export declare function discoverUserCommands(opts?: {
64
64
  cwd?: string;
65
65
  reserved?: readonly string[];
66
66
  }): UserCommand[];
67
+ export type HeadlessExpansion =
68
+ /** Not a command. Send it as written. */
69
+ {
70
+ readonly kind: 'unchanged';
71
+ readonly prompt: string;
72
+ } | {
73
+ readonly kind: 'expanded';
74
+ readonly prompt: string;
75
+ readonly name: string;
76
+ } | {
77
+ readonly kind: 'refused';
78
+ readonly reason: string;
79
+ };
80
+ /**
81
+ * Resolve a headless prompt that may name one of the operator's own commands.
82
+ *
83
+ * `namzu run "/ozet hedef.js"` used to send that string to the model verbatim.
84
+ * The model, reasonably, tried to make sense of it — offering to create a file
85
+ * called `ozet hedef.js`. The run exited 0 with confident output that had
86
+ * nothing to do with the command. It did not fail; it quietly did something
87
+ * else, which is the shape worth removing.
88
+ *
89
+ * ## Why a leading `/` is not enough to call it a command
90
+ *
91
+ * `namzu run "/usr/local/bin is missing"` and `namzu run "/clear the cache in
92
+ * redis"` are ordinary prompts. Treating every leading slash as a command would
93
+ * break them, and breaking a working prompt to fix a broken one is not a trade
94
+ * worth making. So the test is not the slash — it is whether the first token
95
+ * names a command **this project actually declares**.
96
+ *
97
+ * That asymmetry is the whole rule. A file in `.namzu/commands/` is an explicit
98
+ * declaration by the operator, so matching it is high-confidence. A built-in's
99
+ * name is a common English word that nobody declared, so matching it is not.
100
+ *
101
+ * The one exception is a prompt that is EXACTLY a built-in and nothing else:
102
+ * `namzu run "/help"` is not a sentence anybody means literally, and answering
103
+ * it with a model improvising on the string is the same silent misfire. With
104
+ * arguments — `/clear the cache` — it stays prose, because there the words
105
+ * carry a meaning the command name does not.
106
+ */
107
+ export declare function expandHeadlessCommand(prompt: string, opts?: {
108
+ home?: string;
109
+ cwd?: string;
110
+ builtins?: readonly string[];
111
+ }): HeadlessExpansion;
67
112
  export type ExpandResult = {
68
113
  readonly ok: true;
69
114
  readonly prompt: string;
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/user-commands/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAOH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,SAAS,CAAA;AAElD,MAAM,WAAW,WAAW;IAC3B,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAA;IAClC;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,sEAAsE;AACtE,eAAO,MAAM,eAAe,eAAe,CAAA;AAE3C,wBAAgB,eAAe,CAAC,IAAI,GAAE,MAAkB,GAAG,MAAM,CAEhE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAEtE;AAmDD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CACnC,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAO,GACtE,WAAW,EAAE,CAgBf;AAED,MAAM,MAAM,YAAY,GACrB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAElD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CAkB9E"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/user-commands/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAOH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,SAAS,CAAA;AAElD,MAAM,WAAW,WAAW;IAC3B,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAA;IAClC;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,sEAAsE;AACtE,eAAO,MAAM,eAAe,eAAe,CAAA;AAE3C,wBAAgB,eAAe,CAAC,IAAI,GAAE,MAAkB,GAAG,MAAM,CAEhE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAEtE;AAmDD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CACnC,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAO,GACtE,WAAW,EAAE,CAgBf;AAED,MAAM,MAAM,iBAAiB;AAC5B,yCAAyC;AACvC;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC7E;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,qBAAqB,CACpC,MAAM,EAAE,MAAM,EACd,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAO,GACtE,iBAAiB,CA4BnB;AAED,MAAM,MAAM,YAAY,GACrB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAElD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CAkB9E"}
@@ -111,6 +111,61 @@ export function discoverUserCommands(opts = {}) {
111
111
  : c)
112
112
  .sort((a, b) => a.name.localeCompare(b.name));
113
113
  }
114
+ /**
115
+ * Resolve a headless prompt that may name one of the operator's own commands.
116
+ *
117
+ * `namzu run "/ozet hedef.js"` used to send that string to the model verbatim.
118
+ * The model, reasonably, tried to make sense of it — offering to create a file
119
+ * called `ozet hedef.js`. The run exited 0 with confident output that had
120
+ * nothing to do with the command. It did not fail; it quietly did something
121
+ * else, which is the shape worth removing.
122
+ *
123
+ * ## Why a leading `/` is not enough to call it a command
124
+ *
125
+ * `namzu run "/usr/local/bin is missing"` and `namzu run "/clear the cache in
126
+ * redis"` are ordinary prompts. Treating every leading slash as a command would
127
+ * break them, and breaking a working prompt to fix a broken one is not a trade
128
+ * worth making. So the test is not the slash — it is whether the first token
129
+ * names a command **this project actually declares**.
130
+ *
131
+ * That asymmetry is the whole rule. A file in `.namzu/commands/` is an explicit
132
+ * declaration by the operator, so matching it is high-confidence. A built-in's
133
+ * name is a common English word that nobody declared, so matching it is not.
134
+ *
135
+ * The one exception is a prompt that is EXACTLY a built-in and nothing else:
136
+ * `namzu run "/help"` is not a sentence anybody means literally, and answering
137
+ * it with a model improvising on the string is the same silent misfire. With
138
+ * arguments — `/clear the cache` — it stays prose, because there the words
139
+ * carry a meaning the command name does not.
140
+ */
141
+ export function expandHeadlessCommand(prompt, opts = {}) {
142
+ const trimmed = prompt.trim();
143
+ if (!trimmed.startsWith('/'))
144
+ return { kind: 'unchanged', prompt };
145
+ const [token, ...rest] = trimmed.slice(1).split(/\s+/);
146
+ const name = token ?? '';
147
+ if (!name)
148
+ return { kind: 'unchanged', prompt };
149
+ const builtins = new Set(opts.builtins ?? []);
150
+ if (rest.length === 0 && builtins.has(name)) {
151
+ return {
152
+ kind: 'refused',
153
+ reason: `/${name} is an interactive command and does nothing in \`namzu run\`. Run \`namzu\` for the terminal agent, or pass a prompt instead.`,
154
+ };
155
+ }
156
+ const commands = discoverUserCommands({
157
+ ...(opts.home !== undefined ? { home: opts.home } : {}),
158
+ ...(opts.cwd !== undefined ? { cwd: opts.cwd } : {}),
159
+ reserved: [...builtins],
160
+ });
161
+ const found = commands.find((c) => c.name === name);
162
+ if (!found)
163
+ return { kind: 'unchanged', prompt };
164
+ const expanded = expandCommand(found, rest.join(' '));
165
+ return expanded.ok
166
+ ? { kind: 'expanded', prompt: expanded.prompt, name }
167
+ : { kind: 'refused', reason: expanded.reason };
168
+ }
114
169
  /**
115
170
  * Fill a command's template with the arguments it was invoked with.
116
171
  *
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/user-commands/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/user-commands/store.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@namzu/cli",
3
- "version": "2.4.0",
3
+ "version": "2.6.0",
4
4
  "description": "Operator CLI for the Namzu agent platform — namzu doctor + future commands. Dual-purpose: standalone bin (`namzu doctor`) and library (`import { runDoctor } from '@namzu/cli'`).",
5
5
  "keywords": [
6
6
  "namzu",
@@ -45,14 +45,15 @@
45
45
  "react": "^19.2.6",
46
46
  "yaml": "^2.9.0",
47
47
  "@namzu/anthropic": "3.1.1",
48
- "@namzu/ollama": "2.0.1",
49
- "@namzu/openrouter": "2.0.1",
50
48
  "@namzu/openai": "1.1.1",
49
+ "@namzu/openrouter": "2.0.1",
50
+ "@namzu/ollama": "2.0.1",
51
51
  "@namzu/sdk": "^15.1.0"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@biomejs/biome": "^1.9.4",
55
55
  "@types/react": "^19.2.15",
56
+ "ink-testing-library": "^4.0.0",
56
57
  "typescript": "^5.5.0",
57
58
  "vitest": "^3.2.6"
58
59
  },