@namzu/cli 4.2.0 → 4.3.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/doctor/checks/chain.d.ts +21 -0
- package/dist/doctor/checks/chain.d.ts.map +1 -1
- package/dist/doctor/checks/chain.js +78 -13
- package/dist/doctor/checks/chain.js.map +1 -1
- package/dist/integrations/providers/index.d.ts +1 -0
- package/dist/integrations/providers/index.d.ts.map +1 -1
- package/dist/integrations/providers/index.js +1 -0
- package/dist/integrations/providers/index.js.map +1 -1
- package/dist/integrations/providers/register.d.ts +65 -0
- package/dist/integrations/providers/register.d.ts.map +1 -0
- package/dist/integrations/providers/register.js +120 -0
- package/dist/integrations/providers/register.js.map +1 -0
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +63 -10
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/Composer.d.ts +21 -1
- package/dist/tui/Composer.d.ts.map +1 -1
- package/dist/tui/Composer.js +24 -2
- package/dist/tui/Composer.js.map +1 -1
- package/dist/tui/StatusBar.d.ts +55 -0
- package/dist/tui/StatusBar.d.ts.map +1 -1
- package/dist/tui/StatusBar.js +138 -10
- package/dist/tui/StatusBar.js.map +1 -1
- package/dist/tui/agent.d.ts.map +1 -1
- package/dist/tui/agent.js +3 -70
- package/dist/tui/agent.js.map +1 -1
- package/package.json +3 -3
|
@@ -22,6 +22,27 @@ export interface ProviderChainCheckOptions {
|
|
|
22
22
|
* is the worst moment to find out the key was never set. So every member's
|
|
23
23
|
* credential is resolved here, on a day when nothing is broken.
|
|
24
24
|
*
|
|
25
|
+
* ## Two ways a chain is unusable, and this reports both
|
|
26
|
+
*
|
|
27
|
+
* A credential is the obvious one. The other is a capability DISAGREEMENT: a
|
|
28
|
+
* run negotiates tools, vision and documents once, against the primary, and
|
|
29
|
+
* keeps that answer across a swap — so a chain whose members declare different
|
|
30
|
+
* abilities would land a run on a member holding a request shaped for someone
|
|
31
|
+
* else. `createAgentSession` refuses such a chain outright, which means an
|
|
32
|
+
* operator who has one learns about it by trying to start a session.
|
|
33
|
+
*
|
|
34
|
+
* That check used to be unreachable from here. Reading what a provider declares
|
|
35
|
+
* requires its package to be registered, and the only registration path lived
|
|
36
|
+
* inside the interactive session module — so `doctor` could report which
|
|
37
|
+
* members had keys and not whether the chain it was describing could run at
|
|
38
|
+
* all. A diagnostic that cannot see what the thing it diagnoses sees is
|
|
39
|
+
* checking the wrong thing. `ensureRegistered` now lives beside the registry
|
|
40
|
+
* (`integrations/providers/register.ts`) and both reach it.
|
|
41
|
+
*
|
|
42
|
+
* The cost is real and worth naming: this check dynamically imports the driver
|
|
43
|
+
* package of every member in the chain. That is the price of reading a
|
|
44
|
+
* declaration, and it is paid on a command whose entire job is to look.
|
|
45
|
+
*
|
|
25
46
|
* Exported separately from the `DoctorCheck` so it can be driven with an
|
|
26
47
|
* explicit home and environment. The check itself is still exercised through
|
|
27
48
|
* `providerChainCheck.run`, because a helper proven in isolation says nothing
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../../../src/doctor/checks/chain.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../../../src/doctor/checks/chain.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAMhE,OAAO,EAAE,KAAK,eAAe,EAAqB,MAAM,0CAA0C,CAAA;AAKlG,MAAM,WAAW,yBAAyB;IACzC,wEAAwE;IACxE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,eAAe,CAAC,KAAK,CAAC,CAAA;IACrC,uFAAuF;IACvF,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAsB,qBAAqB,CAC1C,OAAO,GAAE,yBAA8B,GACrC,OAAO,CAAC,iBAAiB,CAAC,CAoJ5B;AAED,eAAO,MAAM,kBAAkB,EAAE,WAIhC,CAAA"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { homedir } from 'node:os';
|
|
2
|
+
import { chainCapabilityDisagreements, unresolvedMembers, } from '../../integrations/providers/chain-capabilities.js';
|
|
2
3
|
import { discoverProviders } from '../../integrations/providers/discover.js';
|
|
3
4
|
import { preferencesPath, readPreferences } from '../../integrations/providers/preferences.js';
|
|
5
|
+
import { resolveChainCapabilities } from '../../integrations/providers/register.js';
|
|
4
6
|
import { PROVIDER_REGISTRY } from '../../integrations/providers/registry.js';
|
|
5
7
|
/**
|
|
6
8
|
* The configured provider chain, in the operator's declared order.
|
|
@@ -17,6 +19,27 @@ import { PROVIDER_REGISTRY } from '../../integrations/providers/registry.js';
|
|
|
17
19
|
* is the worst moment to find out the key was never set. So every member's
|
|
18
20
|
* credential is resolved here, on a day when nothing is broken.
|
|
19
21
|
*
|
|
22
|
+
* ## Two ways a chain is unusable, and this reports both
|
|
23
|
+
*
|
|
24
|
+
* A credential is the obvious one. The other is a capability DISAGREEMENT: a
|
|
25
|
+
* run negotiates tools, vision and documents once, against the primary, and
|
|
26
|
+
* keeps that answer across a swap — so a chain whose members declare different
|
|
27
|
+
* abilities would land a run on a member holding a request shaped for someone
|
|
28
|
+
* else. `createAgentSession` refuses such a chain outright, which means an
|
|
29
|
+
* operator who has one learns about it by trying to start a session.
|
|
30
|
+
*
|
|
31
|
+
* That check used to be unreachable from here. Reading what a provider declares
|
|
32
|
+
* requires its package to be registered, and the only registration path lived
|
|
33
|
+
* inside the interactive session module — so `doctor` could report which
|
|
34
|
+
* members had keys and not whether the chain it was describing could run at
|
|
35
|
+
* all. A diagnostic that cannot see what the thing it diagnoses sees is
|
|
36
|
+
* checking the wrong thing. `ensureRegistered` now lives beside the registry
|
|
37
|
+
* (`integrations/providers/register.ts`) and both reach it.
|
|
38
|
+
*
|
|
39
|
+
* The cost is real and worth naming: this check dynamically imports the driver
|
|
40
|
+
* package of every member in the chain. That is the price of reading a
|
|
41
|
+
* declaration, and it is paid on a command whose entire job is to look.
|
|
42
|
+
*
|
|
20
43
|
* Exported separately from the `DoctorCheck` so it can be driven with an
|
|
21
44
|
* explicit home and environment. The check itself is still exercised through
|
|
22
45
|
* `providerChainCheck.run`, because a helper proven in isolation says nothing
|
|
@@ -91,23 +114,65 @@ export async function describeProviderChain(options = {}) {
|
|
|
91
114
|
lines.push(`${index + 1}. ${position} · ${entry.label} · ${model} · ${state}`);
|
|
92
115
|
}
|
|
93
116
|
const chain = lines.join('\n');
|
|
94
|
-
|
|
117
|
+
// What each member DECLARES. Type-level, so no credential is needed — which
|
|
118
|
+
// is what makes it answerable about the fallback nobody has configured yet,
|
|
119
|
+
// the member most worth asking about.
|
|
120
|
+
const resolved = await resolveChainCapabilities(members);
|
|
121
|
+
const disagreements = chainCapabilityDisagreements(members, resolved);
|
|
122
|
+
const accepted = read.prefs.allowCapabilityMismatch === true;
|
|
123
|
+
const unreadable = unresolvedMembers(members, resolved);
|
|
124
|
+
const primaryUnreadable = resolved[0]?.kind === 'unresolved';
|
|
125
|
+
const sections = [chain];
|
|
126
|
+
if (disagreements.length > 0) {
|
|
127
|
+
sections.push(accepted
|
|
128
|
+
? 'The members declare different capabilities, and you have accepted that:'
|
|
129
|
+
: 'The members declare different capabilities, so a session will be REFUSED:', ...disagreements.map((d) => ` - ${d.sentence}`));
|
|
130
|
+
}
|
|
131
|
+
if (unreadable.length > 0) {
|
|
132
|
+
// Kept separate from the disagreements above, for the reason the session
|
|
133
|
+
// keeps them separate: a member whose declaration could not be read is not
|
|
134
|
+
// a member that disagrees, and reporting it as one would name a conflict
|
|
135
|
+
// nobody established.
|
|
136
|
+
sections.push('Could not read what these members declare:', ...unreadable.map((line) => ` - ${line}`));
|
|
137
|
+
}
|
|
138
|
+
const message = sections.join('\n');
|
|
139
|
+
// Ordered by what stops a run. An unaccepted disagreement and an unusable
|
|
140
|
+
// primary both mean no session starts at all; everything else leaves namzu
|
|
141
|
+
// working with less than the operator declared.
|
|
142
|
+
if (disagreements.length > 0 && !accepted) {
|
|
143
|
+
return {
|
|
144
|
+
status: 'fail',
|
|
145
|
+
message: `provider chain cannot be honoured as written:\n${message}`,
|
|
146
|
+
remediation: 'Drop the member that disagrees, or set "allowCapabilityMismatch": true in your preferences to accept the limitation. namzu will not choose between advertising abilities a fallback lacks and costing your primary a capability on every run.',
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
if (primaryUnusable || primaryUnreadable) {
|
|
150
|
+
return {
|
|
151
|
+
status: 'fail',
|
|
152
|
+
message: `${unusable} of ${members.length} chain member(s) cannot be used:\n${message}`,
|
|
153
|
+
remediation: primaryUnusable
|
|
154
|
+
? 'The primary provider has no usable credential, so no run can start. Set its key, or run `namzu` to pick a provider that has one.'
|
|
155
|
+
: 'The primary provider could not be loaded, so no run can start. Run `namzu` to pick a provider that can.',
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (unusable > 0 || unreadable.length > 0 || disagreements.length > 0) {
|
|
95
159
|
return {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
160
|
+
// `warn`, not `fail`: the primary still runs, so namzu is usable and the
|
|
161
|
+
// operator is not blocked by a degraded spare.
|
|
162
|
+
status: 'warn',
|
|
163
|
+
message: unusable > 0
|
|
164
|
+
? `${unusable} of ${members.length} chain member(s) cannot be used:\n${message}`
|
|
165
|
+
: `provider chain usable, with limitations:\n${message}`,
|
|
166
|
+
remediation: unusable > 0
|
|
167
|
+
? 'The primary still works, so runs will start. But a fallback with no credential is not a fallback — set its key, or take it out of the chain.'
|
|
168
|
+
: 'The primary still works. A fallback that declares less than your primary will serve shorter or less capable turns if the chain ever falls over to it.',
|
|
100
169
|
};
|
|
101
170
|
}
|
|
102
171
|
return {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
message: `${unusable} of ${members.length} chain member(s) cannot be used:\n${chain}`,
|
|
108
|
-
remediation: primaryUnusable
|
|
109
|
-
? 'The primary provider has no usable credential, so no run can start. Set its key, or run `namzu` to pick a provider that has one.'
|
|
110
|
-
: 'The primary still works, so runs will start. But a fallback with no credential is not a fallback — set its key, or take it out of the chain.',
|
|
172
|
+
status: 'pass',
|
|
173
|
+
message: members.length === 1
|
|
174
|
+
? `1 provider configured (no fallback):\n${message}`
|
|
175
|
+
: `${members.length} providers configured, in order:\n${message}`,
|
|
111
176
|
};
|
|
112
177
|
}
|
|
113
178
|
export const providerChainCheck = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chain.js","sourceRoot":"","sources":["../../../src/doctor/checks/chain.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAIjC,OAAO,EAAwB,iBAAiB,EAAE,MAAM,0CAA0C,CAAA;AAClG,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAA;AAC9F,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAA;AAU5E
|
|
1
|
+
{"version":3,"file":"chain.js","sourceRoot":"","sources":["../../../src/doctor/checks/chain.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,4 +4,5 @@ export { ensureFreshAnthropicToken, type OAuthMetadata, refreshAgentOAuthToken,
|
|
|
4
4
|
export { type CapabilityDisagreement, chainCapabilityDisagreements, describeAcceptedMismatch, describeCapabilityRefusal, type MemberCapabilities, unresolvedMembers, } from './chain-capabilities.js';
|
|
5
5
|
export { chainPositionName, type Preferences, PREFERENCES_FILE_VERSION, PreferencesError, preferencesPath, primaryProvider, type ProviderChoice, type ReadResult, readPreferences, writePreferences, } from './preferences.js';
|
|
6
6
|
export { ALL_PROVIDER_IDS, PROVIDER_REGISTRY, type ProviderId, type ProviderRegistryEntry, type SdkProviderType, } from './registry.js';
|
|
7
|
+
export { ensureRegistered, isRegistered, resolveChainCapabilities } from './register.js';
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/integrations/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,iBAAiB,EACjB,YAAY,GACZ,MAAM,eAAe,CAAA;AACtB,OAAO,EACN,KAAK,oBAAoB,EACzB,qBAAqB,EACrB,2BAA2B,GAC3B,MAAM,eAAe,CAAA;AACtB,OAAO,EACN,yBAAyB,EACzB,KAAK,aAAa,EAClB,sBAAsB,GACtB,MAAM,YAAY,CAAA;AACnB,OAAO,EACN,KAAK,sBAAsB,EAC3B,4BAA4B,EAC5B,wBAAwB,EACxB,yBAAyB,EACzB,KAAK,kBAAkB,EACvB,iBAAiB,GACjB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACN,iBAAiB,EACjB,KAAK,WAAW,EAChB,wBAAwB,EACxB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,eAAe,EACf,gBAAgB,GAChB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACN,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,UAAU,EACf,KAAK,qBAAqB,EAC1B,KAAK,eAAe,GACpB,MAAM,eAAe,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/integrations/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,iBAAiB,EACjB,YAAY,GACZ,MAAM,eAAe,CAAA;AACtB,OAAO,EACN,KAAK,oBAAoB,EACzB,qBAAqB,EACrB,2BAA2B,GAC3B,MAAM,eAAe,CAAA;AACtB,OAAO,EACN,yBAAyB,EACzB,KAAK,aAAa,EAClB,sBAAsB,GACtB,MAAM,YAAY,CAAA;AACnB,OAAO,EACN,KAAK,sBAAsB,EAC3B,4BAA4B,EAC5B,wBAAwB,EACxB,yBAAyB,EACzB,KAAK,kBAAkB,EACvB,iBAAiB,GACjB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACN,iBAAiB,EACjB,KAAK,WAAW,EAChB,wBAAwB,EACxB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,eAAe,EACf,gBAAgB,GAChB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACN,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,UAAU,EACf,KAAK,qBAAqB,EAC1B,KAAK,eAAe,GACpB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -4,4 +4,5 @@ export { ensureFreshAnthropicToken, refreshAgentOAuthToken, } from './oauth.js';
|
|
|
4
4
|
export { chainCapabilityDisagreements, describeAcceptedMismatch, describeCapabilityRefusal, unresolvedMembers, } from './chain-capabilities.js';
|
|
5
5
|
export { chainPositionName, PREFERENCES_FILE_VERSION, PreferencesError, preferencesPath, primaryProvider, readPreferences, writePreferences, } from './preferences.js';
|
|
6
6
|
export { ALL_PROVIDER_IDS, PROVIDER_REGISTRY, } from './registry.js';
|
|
7
|
+
export { ensureRegistered, isRegistered, resolveChainCapabilities } from './register.js';
|
|
7
8
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/integrations/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,iBAAiB,EACjB,YAAY,GACZ,MAAM,eAAe,CAAA;AACtB,OAAO,EAEN,qBAAqB,EACrB,2BAA2B,GAC3B,MAAM,eAAe,CAAA;AACtB,OAAO,EACN,yBAAyB,EAEzB,sBAAsB,GACtB,MAAM,YAAY,CAAA;AACnB,OAAO,EAEN,4BAA4B,EAC5B,wBAAwB,EACxB,yBAAyB,EAEzB,iBAAiB,GACjB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACN,iBAAiB,EAEjB,wBAAwB,EACxB,gBAAgB,EAChB,eAAe,EACf,eAAe,EAGf,eAAe,EACf,gBAAgB,GAChB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACN,gBAAgB,EAChB,iBAAiB,GAIjB,MAAM,eAAe,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/integrations/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,iBAAiB,EACjB,YAAY,GACZ,MAAM,eAAe,CAAA;AACtB,OAAO,EAEN,qBAAqB,EACrB,2BAA2B,GAC3B,MAAM,eAAe,CAAA;AACtB,OAAO,EACN,yBAAyB,EAEzB,sBAAsB,GACtB,MAAM,YAAY,CAAA;AACnB,OAAO,EAEN,4BAA4B,EAC5B,wBAAwB,EACxB,yBAAyB,EAEzB,iBAAiB,GACjB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACN,iBAAiB,EAEjB,wBAAwB,EACxB,gBAAgB,EAChB,eAAe,EACf,eAAe,EAGf,eAAe,EACf,gBAAgB,GAChB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACN,gBAAgB,EAChB,iBAAiB,GAIjB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Put a driver package into the SDK's `ProviderRegistry`, once per process.
|
|
3
|
+
*
|
|
4
|
+
* This is the only place the wired driver packages are imported, so it decides
|
|
5
|
+
* what a `namzu` invocation actually pulls in and when. The imports are dynamic
|
|
6
|
+
* for that reason: a run on one provider does not load the other three, and a
|
|
7
|
+
* command that never touches a model loads none.
|
|
8
|
+
*
|
|
9
|
+
* ## Why it lives here rather than in the session module
|
|
10
|
+
*
|
|
11
|
+
* It used to be module-private inside the interactive session, which made
|
|
12
|
+
* reading what a provider DECLARES a privilege of having started a session.
|
|
13
|
+
* Registration is a precondition of that read — the SDK cannot report the
|
|
14
|
+
* capabilities of a package nobody imported — so `namzu doctor`, whose whole
|
|
15
|
+
* job is to answer questions about the setup before a session exists, could not
|
|
16
|
+
* ask. The alternative was for the diagnostic to import the session module and
|
|
17
|
+
* with it the query runtime, the subagent runtime, MCP, memory and skills, for
|
|
18
|
+
* one map lookup.
|
|
19
|
+
*
|
|
20
|
+
* So it sits beside `PROVIDER_REGISTRY`, which is the data it switches over,
|
|
21
|
+
* and both the session and the doctor reach it without either importing the
|
|
22
|
+
* other.
|
|
23
|
+
*
|
|
24
|
+
* ## One set, and that is load-bearing
|
|
25
|
+
*
|
|
26
|
+
* `registered` makes registration idempotent. It must exist exactly once: two
|
|
27
|
+
* copies would each believe a provider was unregistered and register it twice,
|
|
28
|
+
* and the SDK's registry rejects that with a duplicate-provider error. That is
|
|
29
|
+
* the whole reason this is a module rather than a function anyone may copy —
|
|
30
|
+
* the state is the API as much as the function is.
|
|
31
|
+
*/
|
|
32
|
+
import type { MemberCapabilities } from './chain-capabilities.js';
|
|
33
|
+
import type { ProviderChoice } from './preferences.js';
|
|
34
|
+
import { type ProviderId } from './registry.js';
|
|
35
|
+
/**
|
|
36
|
+
* Import and register the driver for `id`, unless it is already registered.
|
|
37
|
+
*
|
|
38
|
+
* Throws for a provider that has a registry entry but no wiring here. That
|
|
39
|
+
* asymmetry is a known defect, not a design: the entry, the label, the default
|
|
40
|
+
* model and the discovery probe all cooperate to advertise a provider that
|
|
41
|
+
* cannot be built. See issue #257.
|
|
42
|
+
*/
|
|
43
|
+
export declare function ensureRegistered(id: ProviderId): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Has this provider's driver been registered in THIS process?
|
|
46
|
+
*
|
|
47
|
+
* Read by the chain builder to skip a member whose registration failed, so the
|
|
48
|
+
* failure is reported once — as an unresolved capability — rather than twice in
|
|
49
|
+
* different words.
|
|
50
|
+
*/
|
|
51
|
+
export declare function isRegistered(id: ProviderId): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* What each member of the chain DECLARES it can do.
|
|
54
|
+
*
|
|
55
|
+
* Type-level, via the registry, so nothing is constructed and no credential is
|
|
56
|
+
* needed — which is the whole point: the member most worth checking is the
|
|
57
|
+
* fallback nobody has set up yet, and a check that demanded a key would be
|
|
58
|
+
* unusable in exactly that case.
|
|
59
|
+
*
|
|
60
|
+
* A member that cannot be registered is reported as unresolved rather than
|
|
61
|
+
* assumed to agree. Registration is also why this cannot be a pure function: a
|
|
62
|
+
* provider package is only imported when something needs it.
|
|
63
|
+
*/
|
|
64
|
+
export declare function resolveChainCapabilities(members: readonly ProviderChoice[]): Promise<readonly MemberCapabilities[]>;
|
|
65
|
+
//# sourceMappingURL=register.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/integrations/providers/register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAMH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,eAAe,CAAA;AAIlE;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BpE;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,UAAU,GAAG,OAAO,CAEpD;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,EAAE,SAAS,cAAc,EAAE,GAChC,OAAO,CAAC,SAAS,kBAAkB,EAAE,CAAC,CAuBxC"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Put a driver package into the SDK's `ProviderRegistry`, once per process.
|
|
3
|
+
*
|
|
4
|
+
* This is the only place the wired driver packages are imported, so it decides
|
|
5
|
+
* what a `namzu` invocation actually pulls in and when. The imports are dynamic
|
|
6
|
+
* for that reason: a run on one provider does not load the other three, and a
|
|
7
|
+
* command that never touches a model loads none.
|
|
8
|
+
*
|
|
9
|
+
* ## Why it lives here rather than in the session module
|
|
10
|
+
*
|
|
11
|
+
* It used to be module-private inside the interactive session, which made
|
|
12
|
+
* reading what a provider DECLARES a privilege of having started a session.
|
|
13
|
+
* Registration is a precondition of that read — the SDK cannot report the
|
|
14
|
+
* capabilities of a package nobody imported — so `namzu doctor`, whose whole
|
|
15
|
+
* job is to answer questions about the setup before a session exists, could not
|
|
16
|
+
* ask. The alternative was for the diagnostic to import the session module and
|
|
17
|
+
* with it the query runtime, the subagent runtime, MCP, memory and skills, for
|
|
18
|
+
* one map lookup.
|
|
19
|
+
*
|
|
20
|
+
* So it sits beside `PROVIDER_REGISTRY`, which is the data it switches over,
|
|
21
|
+
* and both the session and the doctor reach it without either importing the
|
|
22
|
+
* other.
|
|
23
|
+
*
|
|
24
|
+
* ## One set, and that is load-bearing
|
|
25
|
+
*
|
|
26
|
+
* `registered` makes registration idempotent. It must exist exactly once: two
|
|
27
|
+
* copies would each believe a provider was unregistered and register it twice,
|
|
28
|
+
* and the SDK's registry rejects that with a duplicate-provider error. That is
|
|
29
|
+
* the whole reason this is a module rather than a function anyone may copy —
|
|
30
|
+
* the state is the API as much as the function is.
|
|
31
|
+
*/
|
|
32
|
+
import { ProviderRegistry } from '@namzu/sdk';
|
|
33
|
+
import { resolveProviderCapabilities } from '@namzu/sdk';
|
|
34
|
+
import { PROVIDER_REGISTRY } from './registry.js';
|
|
35
|
+
const registered = new Set();
|
|
36
|
+
/**
|
|
37
|
+
* Import and register the driver for `id`, unless it is already registered.
|
|
38
|
+
*
|
|
39
|
+
* Throws for a provider that has a registry entry but no wiring here. That
|
|
40
|
+
* asymmetry is a known defect, not a design: the entry, the label, the default
|
|
41
|
+
* model and the discovery probe all cooperate to advertise a provider that
|
|
42
|
+
* cannot be built. See issue #257.
|
|
43
|
+
*/
|
|
44
|
+
export async function ensureRegistered(id) {
|
|
45
|
+
if (registered.has(id))
|
|
46
|
+
return;
|
|
47
|
+
switch (id) {
|
|
48
|
+
case 'anthropic': {
|
|
49
|
+
const mod = await import('@namzu/anthropic');
|
|
50
|
+
mod.registerAnthropic();
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
case 'openai': {
|
|
54
|
+
const mod = await import('@namzu/openai');
|
|
55
|
+
mod.registerOpenAI();
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
case 'openrouter': {
|
|
59
|
+
const mod = await import('@namzu/openrouter');
|
|
60
|
+
mod.registerOpenRouter();
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
case 'ollama': {
|
|
64
|
+
const mod = await import('@namzu/ollama');
|
|
65
|
+
mod.registerOllama();
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
default:
|
|
69
|
+
throw new Error(`provider "${id}" is not wired yet; pick another or wait for support`);
|
|
70
|
+
}
|
|
71
|
+
registered.add(id);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Has this provider's driver been registered in THIS process?
|
|
75
|
+
*
|
|
76
|
+
* Read by the chain builder to skip a member whose registration failed, so the
|
|
77
|
+
* failure is reported once — as an unresolved capability — rather than twice in
|
|
78
|
+
* different words.
|
|
79
|
+
*/
|
|
80
|
+
export function isRegistered(id) {
|
|
81
|
+
return registered.has(id);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* What each member of the chain DECLARES it can do.
|
|
85
|
+
*
|
|
86
|
+
* Type-level, via the registry, so nothing is constructed and no credential is
|
|
87
|
+
* needed — which is the whole point: the member most worth checking is the
|
|
88
|
+
* fallback nobody has set up yet, and a check that demanded a key would be
|
|
89
|
+
* unusable in exactly that case.
|
|
90
|
+
*
|
|
91
|
+
* A member that cannot be registered is reported as unresolved rather than
|
|
92
|
+
* assumed to agree. Registration is also why this cannot be a pure function: a
|
|
93
|
+
* provider package is only imported when something needs it.
|
|
94
|
+
*/
|
|
95
|
+
export async function resolveChainCapabilities(members) {
|
|
96
|
+
const out = [];
|
|
97
|
+
for (const member of members) {
|
|
98
|
+
if (!(member.id in PROVIDER_REGISTRY)) {
|
|
99
|
+
out.push({ kind: 'unresolved', reason: `"${member.id}" is not a provider namzu knows` });
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
await ensureRegistered(member.id);
|
|
104
|
+
out.push({
|
|
105
|
+
kind: 'known',
|
|
106
|
+
capabilities: resolveProviderCapabilities({
|
|
107
|
+
capabilities: ProviderRegistry.getCapabilities(member.id),
|
|
108
|
+
}),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
out.push({
|
|
113
|
+
kind: 'unresolved',
|
|
114
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=register.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/integrations/providers/register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAE7C,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAA;AAIxD,OAAO,EAAE,iBAAiB,EAAmB,MAAM,eAAe,CAAA;AAElE,MAAM,UAAU,GAAG,IAAI,GAAG,EAAc,CAAA;AAExC;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,EAAc;IACpD,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAAE,OAAM;IAC9B,QAAQ,EAAE,EAAE,CAAC;QACZ,KAAK,WAAW,CAAC,CAAC,CAAC;YAClB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAA;YAC5C,GAAG,CAAC,iBAAiB,EAAE,CAAA;YACvB,MAAK;QACN,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACf,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAA;YACzC,GAAG,CAAC,cAAc,EAAE,CAAA;YACpB,MAAK;QACN,CAAC;QACD,KAAK,YAAY,CAAC,CAAC,CAAC;YACnB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAA;YAC7C,GAAG,CAAC,kBAAkB,EAAE,CAAA;YACxB,MAAK;QACN,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACf,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAA;YACzC,GAAG,CAAC,cAAc,EAAE,CAAA;YACpB,MAAK;QACN,CAAC;QACD;YACC,MAAM,IAAI,KAAK,CAAC,aAAa,EAAE,sDAAsD,CAAC,CAAA;IACxF,CAAC;IACD,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AACnB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,EAAc;IAC1C,OAAO,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AAC1B,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC7C,OAAkC;IAElC,MAAM,GAAG,GAAyB,EAAE,CAAA;IACpC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC9B,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,iBAAiB,CAAC,EAAE,CAAC;YACvC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,MAAM,CAAC,EAAE,iCAAiC,EAAE,CAAC,CAAA;YACxF,SAAQ;QACT,CAAC;QACD,IAAI,CAAC;YACJ,MAAM,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YACjC,GAAG,CAAC,IAAI,CAAC;gBACR,IAAI,EAAE,OAAO;gBACb,YAAY,EAAE,2BAA2B,CAAC;oBACzC,YAAY,EAAE,gBAAgB,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;iBACK,CAAC;aAChE,CAAC,CAAA;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,GAAG,CAAC,IAAI,CAAC;gBACR,IAAI,EAAE,YAAY;gBAClB,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC,CAAA;QACH,CAAC;IACF,CAAC;IACD,OAAO,GAAG,CAAA;AACX,CAAC"}
|
package/dist/tui/App.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/tui/App.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA0DH,OAAO,KAAK,EAAqB,UAAU,EAAE,MAAM,YAAY,CAAA;AAE/D,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAA;CACxB;AAWD,wBAAgB,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/tui/App.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA0DH,OAAO,KAAK,EAAqB,UAAU,EAAE,MAAM,YAAY,CAAA;AAE/D,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAA;CACxB;AAWD,wBAAgB,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,QAAQ,2CAq/BpC"}
|
package/dist/tui/App.js
CHANGED
|
@@ -682,11 +682,49 @@ export function App({ ctx }) {
|
|
|
682
682
|
}
|
|
683
683
|
void hydrateSession(prefs, detected);
|
|
684
684
|
}, [detected, hydrateSession, pushMessage]);
|
|
685
|
+
/**
|
|
686
|
+
* Leaving the picker returns to whatever was on screen before it.
|
|
687
|
+
*
|
|
688
|
+
* The picker has two entry points and used to have one exit. Opened by
|
|
689
|
+
* `/model` from a working session, cancelling sent the operator to
|
|
690
|
+
* `unhealthy` — a phase with a disabled composer, from which `/model` cannot
|
|
691
|
+
* be typed again — so declining to change model threw away the session they
|
|
692
|
+
* already had.
|
|
693
|
+
*
|
|
694
|
+
* `unhealthy` means namzu tried and cannot serve: it is set when a probe
|
|
695
|
+
* throws, and when a session comes up with no provider, both carrying an
|
|
696
|
+
* `errorHint` saying what failed. Cancelling is not a failure, and borrowing
|
|
697
|
+
* the failure phase to express it is what made a working session look broken.
|
|
698
|
+
*
|
|
699
|
+
* With nothing behind the picker — first run, no session — there is no screen
|
|
700
|
+
* to return to, so leaving the picker is leaving the program. That is also
|
|
701
|
+
* what the empty picker's own footer has always claimed `esc` does.
|
|
702
|
+
*/
|
|
685
703
|
const handlePickerCancel = useCallback(() => {
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
704
|
+
if (session?.hasProvider) {
|
|
705
|
+
setPhase('ready');
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
exit();
|
|
709
|
+
}, [session, exit]);
|
|
689
710
|
useInput((input, key) => {
|
|
711
|
+
// The provider picker owns its own keyboard — arrows, digits, enter,
|
|
712
|
+
// esc and the typed-key screen are all its business. Ctrl+C is not: it
|
|
713
|
+
// is the one key that must work on every screen, and this handler used
|
|
714
|
+
// to be switched off for the whole picker phase. Ink runs with
|
|
715
|
+
// `exitOnCtrlC: false` and raw mode means the tty raises no SIGINT, so
|
|
716
|
+
// nothing else was going to answer it.
|
|
717
|
+
//
|
|
718
|
+
// One press, not the two the ready screen asks for. The ladder works by
|
|
719
|
+
// printing "press again" into the transcript, and the transcript is not
|
|
720
|
+
// rendered during the picker — so the old behaviour was not quite "the
|
|
721
|
+
// key is dead" but the worse "the first press does something invisible
|
|
722
|
+
// and the second exits", with nothing on screen naming either.
|
|
723
|
+
if (phase === 'picker') {
|
|
724
|
+
if (key.ctrl && input === 'c')
|
|
725
|
+
exit();
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
690
728
|
// Resume picker owns the keyboard while open.
|
|
691
729
|
if (phase === 'resume') {
|
|
692
730
|
if (key.upArrow)
|
|
@@ -793,11 +831,18 @@ export function App({ ctx }) {
|
|
|
793
831
|
exitArmedRef.current = false;
|
|
794
832
|
}, 2000);
|
|
795
833
|
}
|
|
796
|
-
},
|
|
834
|
+
},
|
|
835
|
+
// Active on every phase. It was gated off during the picker, which is what
|
|
836
|
+
// left that screen without a usable exit; the picker branch above returns
|
|
837
|
+
// immediately, so the Picker still owns everything except Ctrl+C.
|
|
838
|
+
{ isActive: true });
|
|
797
839
|
// Background is left natural — we inherit the terminal's own background
|
|
798
840
|
// and only theme the foreground. Forcing
|
|
799
841
|
// a filled bg left mismatched patches around bordered areas, so we don't.
|
|
800
|
-
return (_jsxs(Box, { flexDirection: "column", children: [phase !== 'ready' ? (_jsx(Banner, { version: ctx.version, session: session, bypass: ctx.skipPermissions === true, cwd: ctx.cwd })) : null, _jsxs(Box, { flexDirection: "column", paddingX: 1, children: [phase === 'trust' ? (_jsx(TrustPrompt, { cwd: ctx.cwd })) : phase === 'resume' ? (_jsx(ResumePicker, { conversations: resumeList, selected: selectedResume })) : phase === 'picker' ? (_jsx(Picker, { detected: detected, currentProvider: currentProvider, currentModel: session?.modelSummary ?? null, onSubmit: handlePickerSubmit, onCancel: handlePickerCancel, onCredential: handleTypedCredential })) : (_jsxs(_Fragment, { children: [_jsx(TranscriptFrame, { children: _jsx(Transcript, { messages: messages.filter((m) => !m.pending), pending: messages.find((m) => m.pending) ?? null, state: state, expanded: expanded, resetKey: resetKey, header: phase === 'ready' ? (_jsx(Banner, { version: ctx.version, session: session, bypass: ctx.skipPermissions === true, cwd: ctx.cwd })) : undefined }) }), spacerRows > 0 ? _jsx(Box, { height: spacerRows }) : null, _jsx(LiveActivity, { activeTools: activeTools, thinking: state === 'thinking' && !messages.some((m) => m.pending) }), permission ?
|
|
842
|
+
return (_jsxs(Box, { flexDirection: "column", children: [phase !== 'ready' ? (_jsx(Banner, { version: ctx.version, session: session, bypass: ctx.skipPermissions === true, cwd: ctx.cwd })) : null, _jsxs(Box, { flexDirection: "column", paddingX: 1, children: [phase === 'trust' ? (_jsx(TrustPrompt, { cwd: ctx.cwd })) : phase === 'resume' ? (_jsx(ResumePicker, { conversations: resumeList, selected: selectedResume })) : phase === 'picker' ? (_jsx(Picker, { detected: detected, currentProvider: currentProvider, currentModel: session?.modelSummary ?? null, onSubmit: handlePickerSubmit, onCancel: handlePickerCancel, onCredential: handleTypedCredential })) : (_jsxs(_Fragment, { children: [_jsx(TranscriptFrame, { children: _jsx(Transcript, { messages: messages.filter((m) => !m.pending), pending: messages.find((m) => m.pending) ?? null, state: state, expanded: expanded, resetKey: resetKey, header: phase === 'ready' ? (_jsx(Banner, { version: ctx.version, session: session, bypass: ctx.skipPermissions === true, cwd: ctx.cwd })) : undefined }) }), spacerRows > 0 ? _jsx(Box, { height: spacerRows }) : null, _jsx(LiveActivity, { activeTools: activeTools, thinking: state === 'thinking' && !messages.some((m) => m.pending) }), permission ? _jsx(PermissionOverlay, { toolCalls: permission.toolCalls }) : null, _jsxs(ComposerFrame, { focus: state === 'idle' && phase === 'ready', hidden: permission !== null, children: [queued.length > 0 && permission === null ? (_jsx(Box, { paddingX: 1, children: _jsxs(Text, { color: theme.text.muted, children: ["\u23CE ", queued.length, " message", queued.length > 1 ? 's' : '', " queued \u2014 sending when ready"] }) })) : null, _jsx(Composer, { disabled: phase !== 'ready' || state === 'awaiting-permission', hidden: permission !== null,
|
|
843
|
+
// A turn is running, so Esc is the interrupt and not
|
|
844
|
+
// the composer's clear.
|
|
845
|
+
escapeInterrupts: state === 'thinking' || state === 'tool', onSubmit: handleSubmit, userCommands: userCommands, history: history })] })] })), _jsx(Box, { paddingTop: 1, children: _jsx(StatusBar, { cwd: ctx.cwd, provider: session?.providerSummary ?? null, model: session?.modelSummary ?? null, state: state, hint: hintForPhase(phase, state, session?.hasProvider === true), usage: usage, context: context }) })] })] }));
|
|
801
846
|
}
|
|
802
847
|
function Banner({ version, session, bypass, cwd, }) {
|
|
803
848
|
const cols = process.stdout.columns ?? 80;
|
|
@@ -812,10 +857,10 @@ function TranscriptFrame({ children }) {
|
|
|
812
857
|
// Borderless, edge-to-edge — the message glyph gutter provides structure.
|
|
813
858
|
return _jsx(Box, { flexDirection: "column", children: children });
|
|
814
859
|
}
|
|
815
|
-
function ComposerFrame({ focus, children, }) {
|
|
860
|
+
function ComposerFrame({ focus, hidden = false, children, }) {
|
|
816
861
|
// Input-field look: a rounded rule above and below the composer, no side
|
|
817
862
|
// borders, so the input reads as a field rather than a heavy box.
|
|
818
|
-
return (_jsx(Box, { flexDirection: "column", borderStyle:
|
|
863
|
+
return (_jsx(Box, { flexDirection: "column", ...(hidden ? {} : { borderStyle: 'round' }), borderTop: true, borderBottom: true, borderLeft: false, borderRight: false, borderColor: focus ? theme.border.focus : theme.border.default, marginTop: hidden ? 0 : 1, children: children }));
|
|
819
864
|
}
|
|
820
865
|
// Tool call label: the tool name title-cased, then its most identifying
|
|
821
866
|
// argument — `Bash(ls -la)`, `Read(file.ts)`. A bare tool name in a transcript
|
|
@@ -824,7 +869,9 @@ function formatToolCall(toolName, summary) {
|
|
|
824
869
|
const display = toolName.length > 0 ? toolName[0]?.toUpperCase() + toolName.slice(1) : toolName;
|
|
825
870
|
return summary.length > 0 ? `${display}(${summary})` : display;
|
|
826
871
|
}
|
|
827
|
-
function hintForPhase(phase, state
|
|
872
|
+
function hintForPhase(phase, state,
|
|
873
|
+
/** Whether there is a working session behind the picker to go back to. */
|
|
874
|
+
canReturn = false) {
|
|
828
875
|
// Enter is absent because Enter grants nothing here, deliberately — see the
|
|
829
876
|
// trust branch in the key handler above.
|
|
830
877
|
if (phase === 'trust')
|
|
@@ -833,8 +880,14 @@ function hintForPhase(phase, state) {
|
|
|
833
880
|
return '↑↓ navigate · enter resume · esc cancel';
|
|
834
881
|
if (phase === 'probing')
|
|
835
882
|
return 'discovering providers…';
|
|
836
|
-
|
|
837
|
-
|
|
883
|
+
// Esc does two different things here depending on how the picker was reached,
|
|
884
|
+
// so the hint says which. Naming Ctrl+C matters more here than anywhere else:
|
|
885
|
+
// it is the screen a new user meets before they know the program has keys.
|
|
886
|
+
if (phase === 'picker') {
|
|
887
|
+
return canReturn
|
|
888
|
+
? '↑↓ navigate · enter accept · esc keep current · Ctrl+C exit'
|
|
889
|
+
: '↑↓ navigate · enter accept · esc or Ctrl+C exit';
|
|
890
|
+
}
|
|
838
891
|
if (phase === 'unhealthy')
|
|
839
892
|
return 'Ctrl+C ×2 to exit';
|
|
840
893
|
// Enter is absent because Enter decides nothing here, deliberately — see the
|