@namzu/cli 2.5.0 → 2.6.1
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/dist/integrations/providers/discover.d.ts +11 -0
- package/dist/integrations/providers/discover.d.ts.map +1 -1
- package/dist/integrations/providers/discover.js.map +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +30 -1
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/Picker.d.ts +27 -2
- package/dist/tui/Picker.d.ts.map +1 -1
- package/dist/tui/Picker.js +139 -8
- package/dist/tui/Picker.js.map +1 -1
- package/dist/tui/agent.d.ts +61 -6
- package/dist/tui/agent.d.ts.map +1 -1
- package/dist/tui/agent.js +50 -13
- package/dist/tui/agent.js.map +1 -1
- package/dist/tui/bottom-spacer.d.ts +72 -0
- package/dist/tui/bottom-spacer.d.ts.map +1 -0
- package/dist/tui/bottom-spacer.js +83 -0
- package/dist/tui/bottom-spacer.js.map +1 -0
- package/dist/tui/credential-entry.d.ts +81 -0
- package/dist/tui/credential-entry.d.ts.map +1 -0
- package/dist/tui/credential-entry.js +109 -0
- package/dist/tui/credential-entry.js.map +1 -0
- package/dist/tui/model-choices.d.ts +52 -0
- package/dist/tui/model-choices.d.ts.map +1 -0
- package/dist/tui/model-choices.js +74 -0
- package/dist/tui/model-choices.js.map +1 -0
- package/package.json +4 -3
|
@@ -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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@namzu/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.1",
|
|
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/ollama": "2.0.1",
|
|
48
|
-
"@namzu/anthropic": "3.1.1",
|
|
49
48
|
"@namzu/openai": "1.1.1",
|
|
49
|
+
"@namzu/sdk": "^16.0.0",
|
|
50
50
|
"@namzu/openrouter": "2.0.1",
|
|
51
|
-
"@namzu/
|
|
51
|
+
"@namzu/anthropic": "3.1.1"
|
|
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
|
},
|