dsh-ssh-tui 0.6.4 → 0.7.0-rc.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/lib/doctor.js ADDED
@@ -0,0 +1,380 @@
1
+ /**
2
+ * `/doctor`: one pass over the deployment's composition, dependencies, and
3
+ * compatibility, each verdict carrying the row, line, or path behind it.
4
+ *
5
+ * `/diag` answers "why can't I get in?" about one session's channel, lock, and
6
+ * Host. `/doctor` answers the other half — "is this install composed the way
7
+ * the plugin needs?" — which is where 0.6.3's regression lived: 0.5.1 dropped
8
+ * the roster rows to pass a store check, and the only symptom was `/mode`
9
+ * reporting a missing service months later. Every check therefore reports the
10
+ * concrete row (with its line) or path, plus the command that acts on it.
11
+ *
12
+ * The verdicts are a pure function of collected facts, so they are testable
13
+ * without a Host, a profile, or a filesystem; collection lives in
14
+ * `collectDoctor` and every probe is best-effort. Nothing leaves the machine.
15
+ * @module dsh-ssh-tui/doctor
16
+ */
17
+ import { existsSync, realpathSync } from 'node:fs';
18
+ import { readFile } from 'node:fs/promises';
19
+ import { createRequire } from 'node:module';
20
+ import { dirname, join } from 'node:path';
21
+ import { fileURLToPath } from 'node:url';
22
+ import { t } from './i18n/index.js';
23
+ import { analyzePatch, duplicatePatchRows, missingRosterRows, patchNamesRow, rosterPatchPath, ROSTER_ROWS, } from './preset-rows.js';
24
+ import { subagentModelMatchesProvider } from './subagent-model.js';
25
+ /** Where a row was found, as one detail line. */
26
+ function rowDetail(row) {
27
+ return t('doctor.detail.row', { id: row.id, line: String(row.line) });
28
+ }
29
+ /**
30
+ * Every check, in report order. Pure: same facts in, same verdicts out.
31
+ * @param facts - one collected snapshot.
32
+ * @returns the checks, each with its conclusion and evidence.
33
+ */
34
+ export function doctorChecks(facts) {
35
+ const { analysis } = facts.patch;
36
+ const rosterRow = ROSTER_ROWS[0];
37
+ const codeRuntimeRow = ROSTER_ROWS[1];
38
+ const subagentRow = ROSTER_ROWS[2];
39
+ const checks = [];
40
+ // 1. The patch file itself: everything else reads from it.
41
+ if (!facts.patch.readable) {
42
+ checks.push({
43
+ id: 'patch',
44
+ status: 'fail',
45
+ summary: t('doctor.patch.missing', { path: facts.patchPath }),
46
+ details: [t('doctor.patch.missingHint')],
47
+ fixable: true,
48
+ });
49
+ }
50
+ else if (!analysis.parseable) {
51
+ checks.push({
52
+ id: 'patch',
53
+ status: 'fail',
54
+ summary: t('doctor.patch.broken', { error: analysis.error ?? '' }),
55
+ details: [facts.patchPath, t('doctor.patch.brokenHint')],
56
+ });
57
+ }
58
+ else {
59
+ checks.push({
60
+ id: 'patch',
61
+ status: 'ok',
62
+ summary: t('doctor.patch.ok', { rows: String(analysis.rows.length) }),
63
+ details: [facts.patchPath],
64
+ });
65
+ }
66
+ // 2. The roster service: without it /mode cannot switch and the preset-owned
67
+ // tools are absent from the catalog.
68
+ if (facts.services.roster) {
69
+ checks.push({ id: 'roster', status: 'ok', summary: t('doctor.roster.ok'), details: [] });
70
+ }
71
+ else {
72
+ const declared = rosterRow !== undefined && analysis.parseable && patchNamesRow(analysis.rows, rosterRow);
73
+ checks.push({
74
+ id: 'roster',
75
+ status: 'fail',
76
+ summary: t('doctor.roster.fail'),
77
+ details: rosterRow === undefined
78
+ ? []
79
+ : declared
80
+ ? [t('doctor.detail.declaredNoService', { id: rosterRow.id })]
81
+ : [t('doctor.detail.missingRow', { id: rosterRow.id })],
82
+ fixable: !declared,
83
+ });
84
+ }
85
+ // 3. code-runtime: the PTC preset mounts it, so its absence is the second
86
+ // half of the same regression.
87
+ if (facts.services.codeRuntime) {
88
+ checks.push({ id: 'code-runtime', status: 'ok', summary: t('doctor.codeRuntime.ok'), details: [] });
89
+ }
90
+ else {
91
+ const declared = codeRuntimeRow !== undefined && analysis.parseable && patchNamesRow(analysis.rows, codeRuntimeRow);
92
+ checks.push({
93
+ id: 'code-runtime',
94
+ status: 'fail',
95
+ summary: t('doctor.codeRuntime.fail'),
96
+ details: codeRuntimeRow === undefined
97
+ ? []
98
+ : declared
99
+ ? [t('doctor.detail.declaredNoService', { id: codeRuntimeRow.id })]
100
+ : [t('doctor.detail.missingRow', { id: codeRuntimeRow.id })],
101
+ fixable: !declared,
102
+ });
103
+ }
104
+ // 4. The subagent settings row has no runtime service to probe, so the patch
105
+ // text is the only evidence.
106
+ if (!analysis.parseable) {
107
+ checks.push({ id: 'subagent-settings', status: 'warn', summary: t('doctor.subagentSettings.unknown'), details: [] });
108
+ }
109
+ else if (subagentRow === undefined || patchNamesRow(analysis.rows, subagentRow)) {
110
+ checks.push({ id: 'subagent-settings', status: 'ok', summary: t('doctor.subagentSettings.ok'), details: [] });
111
+ }
112
+ else {
113
+ checks.push({
114
+ id: 'subagent-settings',
115
+ status: 'warn',
116
+ summary: t('doctor.subagentSettings.warn'),
117
+ details: [t('doctor.detail.missingRow', { id: subagentRow.id })],
118
+ fixable: true,
119
+ });
120
+ }
121
+ // 5. Duplicate inserts fail at load time with "service has been registered".
122
+ const duplicates = duplicatePatchRows(analysis.rows);
123
+ if (duplicates.length === 0) {
124
+ checks.push({ id: 'duplicates', status: 'ok', summary: t('doctor.duplicates.ok'), details: [] });
125
+ }
126
+ else {
127
+ checks.push({
128
+ id: 'duplicates',
129
+ status: 'fail',
130
+ summary: t('doctor.duplicates.fail', { count: String(duplicates.length) }),
131
+ details: duplicates.map(rowDetail),
132
+ fixable: true,
133
+ });
134
+ }
135
+ // 6. A row mounted by both the profile layer and this plugin's bundle layer.
136
+ const conflicts = facts.bundleRows.filter(bundle => analysis.rows.some(row => row.kind === 'insert' && (row.id === bundle.id || (row.name !== undefined && row.name === bundle.name))));
137
+ if (conflicts.length === 0) {
138
+ checks.push({ id: 'bundle-conflicts', status: 'ok', summary: t('doctor.bundle.ok'), details: [] });
139
+ }
140
+ else {
141
+ checks.push({
142
+ id: 'bundle-conflicts',
143
+ status: 'fail',
144
+ summary: t('doctor.bundle.fail', { count: String(conflicts.length) }),
145
+ details: conflicts.map(row => t('doctor.detail.missingRow', { id: row.id })),
146
+ });
147
+ }
148
+ // 7. The host version against the manifest's declared window.
149
+ const releases = facts.compatibility?.releases ?? {};
150
+ const declared = Object.keys(releases);
151
+ const status = releases[facts.hostVersion];
152
+ if (status === 'compatible') {
153
+ checks.push({
154
+ id: 'version',
155
+ status: 'ok',
156
+ summary: t('doctor.version.ok', { version: facts.hostVersion }),
157
+ details: facts.compatibility?.range === undefined ? [] : [t('doctor.detail.range', { range: facts.compatibility.range })],
158
+ });
159
+ }
160
+ else if (status !== undefined) {
161
+ checks.push({
162
+ id: 'version',
163
+ status: 'warn',
164
+ summary: t('doctor.version.unknown', { version: facts.hostVersion, status }),
165
+ details: [t('doctor.detail.declared', { versions: declared.join(', ') })],
166
+ });
167
+ }
168
+ else {
169
+ checks.push({
170
+ id: 'version',
171
+ status: 'warn',
172
+ summary: t('doctor.version.absent', { version: facts.hostVersion }),
173
+ details: declared.length === 0 ? [] : [t('doctor.detail.declared', { versions: declared.join(', ') })],
174
+ });
175
+ }
176
+ // 8. Two copies of dsh-scope make preset composition refuse an unscoped
177
+ // context; npm's nested install is the usual source.
178
+ if (facts.scopeCopies.length === 1) {
179
+ checks.push({
180
+ id: 'scope-copies',
181
+ status: 'ok',
182
+ summary: t('doctor.scope.ok'),
183
+ details: [...facts.scopeCopies],
184
+ });
185
+ }
186
+ else if (facts.scopeCopies.length === 0) {
187
+ checks.push({ id: 'scope-copies', status: 'warn', summary: t('doctor.scope.unknown'), details: [] });
188
+ }
189
+ else {
190
+ checks.push({
191
+ id: 'scope-copies',
192
+ status: 'fail',
193
+ summary: t('doctor.scope.fail', { count: String(facts.scopeCopies.length) }),
194
+ details: [...facts.scopeCopies],
195
+ });
196
+ }
197
+ // 9. Routing self-consistency, when settings could be read.
198
+ if (facts.routing !== undefined) {
199
+ checks.push(routingCheck(facts.routing));
200
+ }
201
+ return checks;
202
+ }
203
+ /** The selected provider, its model list, and the subagent selection, compared. */
204
+ function routingCheck(routing) {
205
+ const problems = [];
206
+ const provider = routing.provider;
207
+ if (provider !== undefined && !routing.routes.includes(provider)) {
208
+ problems.push(t('doctor.routing.providerMissing', { provider, routes: routing.routes.join(', ') || '—' }));
209
+ }
210
+ if (provider !== undefined && routing.model !== undefined && routing.routeModels.length > 0
211
+ && !routing.routeModels.includes(routing.model)) {
212
+ problems.push(t('doctor.routing.modelMissing', { model: routing.model, provider }));
213
+ }
214
+ const subProvider = routing.subProvider ?? provider;
215
+ if (subProvider !== undefined && routing.subModel !== undefined
216
+ && !subagentModelMatchesProvider(subProvider, routing.subModel)) {
217
+ problems.push(t('doctor.routing.subMismatch', { model: routing.subModel, provider: subProvider }));
218
+ }
219
+ if (problems.length === 0) {
220
+ return { id: 'routing', status: 'ok', summary: t('doctor.routing.ok'), details: [] };
221
+ }
222
+ return {
223
+ id: 'routing',
224
+ status: 'warn',
225
+ summary: t('doctor.routing.warn', { count: String(problems.length) }),
226
+ details: problems,
227
+ };
228
+ }
229
+ /** `[ok]` / `⚠` / `✖`, in the same vocabulary the tool cards use. */
230
+ function statusMark(status) {
231
+ return status === 'ok' ? '●' : status === 'warn' ? '⚠' : '✖';
232
+ }
233
+ /** The whole report as transcript lines. Pure. */
234
+ export function formatDoctorReport(facts, checks) {
235
+ const lines = [];
236
+ lines.push(t('doctor.title'));
237
+ lines.push(t('doctor.rowContext', {
238
+ profile: facts.profile,
239
+ plugin: facts.pluginVersion,
240
+ dsh: facts.hostVersion,
241
+ node: facts.nodeVersion,
242
+ }));
243
+ lines.push(t('doctor.rowPatch', { path: facts.patchPath }));
244
+ const counts = {
245
+ ok: checks.filter(check => check.status === 'ok').length,
246
+ warn: checks.filter(check => check.status === 'warn').length,
247
+ fail: checks.filter(check => check.status === 'fail').length,
248
+ };
249
+ lines.push(t('doctor.rowSummary', { ok: String(counts.ok), warn: String(counts.warn), fail: String(counts.fail) }));
250
+ lines.push('');
251
+ for (const check of checks) {
252
+ lines.push(`${statusMark(check.status)} ${check.summary}`);
253
+ for (const detail of check.details)
254
+ lines.push(` ${detail}`);
255
+ if (check.fixable === true && check.status !== 'ok')
256
+ lines.push(` ${t('doctor.fixHint')}`);
257
+ }
258
+ return lines;
259
+ }
260
+ /**
261
+ * Distinct installs of `@deepseek-ai/dsh-scope` reachable from the anchors.
262
+ *
263
+ * Anchors are the running CLI entry and the plugin's module base, the same two
264
+ * the provider catalog walks: a nested npm install puts a second copy under one
265
+ * of them, and preset composition then fails with "refusing to compose an
266
+ * unscoped context".
267
+ * @param anchors - file or directory paths that plausibly sit inside the install.
268
+ * @returns real paths, deduplicated; empty when none was found.
269
+ */
270
+ export function findScopeCopies(anchors) {
271
+ const found = new Set();
272
+ for (const anchor of anchors) {
273
+ if (anchor === undefined || anchor === '')
274
+ continue;
275
+ let current = anchor.startsWith('file:') ? fileURLToPath(anchor) : anchor;
276
+ for (let depth = 0; depth < 10; depth += 1) {
277
+ const candidate = join(current, 'node_modules', '@deepseek-ai', 'dsh-scope', 'package.json');
278
+ if (existsSync(candidate)) {
279
+ try {
280
+ found.add(realpathSync(dirname(candidate)));
281
+ }
282
+ catch {
283
+ found.add(dirname(candidate));
284
+ }
285
+ }
286
+ const parent = dirname(current);
287
+ if (parent === current)
288
+ break;
289
+ current = parent;
290
+ }
291
+ }
292
+ return [...found];
293
+ }
294
+ /** The plugin's own manifest, read once for the compatibility declaration. */
295
+ function readManifest() {
296
+ try {
297
+ const require = createRequire(import.meta.url);
298
+ return require('../package.json');
299
+ }
300
+ catch {
301
+ return {};
302
+ }
303
+ }
304
+ /** The bundle patch this package ships, if it is readable. */
305
+ async function readBundleRows() {
306
+ try {
307
+ const text = await readFile(new URL('../cordis.patch.yml', import.meta.url), 'utf8');
308
+ return analyzePatch(text).rows;
309
+ }
310
+ catch {
311
+ return [];
312
+ }
313
+ }
314
+ /**
315
+ * Gather one snapshot. Every probe is best-effort: a failure is reported by the
316
+ * check that needed it, never thrown.
317
+ * @param options - identity, services, and the already-read routing facts.
318
+ * @returns the facts {@link doctorChecks} turns into verdicts.
319
+ */
320
+ export async function collectDoctor(options) {
321
+ const manifest = readManifest();
322
+ const patchPath = rosterPatchPath(options.dshHome, options.profile);
323
+ let readable = true;
324
+ let text = '';
325
+ try {
326
+ text = await readFile(patchPath, 'utf8');
327
+ }
328
+ catch {
329
+ readable = false;
330
+ }
331
+ const compatibility = manifest.dsh?.compatibility;
332
+ const releases = compatibility?.dshReleases ?? {};
333
+ return {
334
+ pluginVersion: typeof manifest.version === 'string' ? manifest.version : '0.0.0',
335
+ hostVersion: options.hostVersion,
336
+ nodeVersion: process.version,
337
+ profile: options.profile,
338
+ dshHome: options.dshHome,
339
+ patchPath,
340
+ services: options.services,
341
+ patch: { readable, text, analysis: readable ? analyzePatch(text) : { parseable: true, rows: [] } },
342
+ bundleRows: await readBundleRows(),
343
+ ...(compatibility === undefined
344
+ ? {}
345
+ : {
346
+ compatibility: {
347
+ ...(compatibility.dsh === undefined ? {} : { range: compatibility.dsh }),
348
+ releases,
349
+ },
350
+ }),
351
+ scopeCopies: findScopeCopies(options.anchors),
352
+ ...(options.routing === undefined ? {} : { routing: options.routing }),
353
+ };
354
+ }
355
+ /** Rows `/doctor --fix` would mount, given the services the composition registered. */
356
+ export function rowsToRepair(facts) {
357
+ if (!facts.patch.analysis.parseable)
358
+ return [];
359
+ const missing = missingRosterRows(facts.patch.analysis.rows);
360
+ return missing.filter(row => (row.id === ROSTER_ROWS[0]?.id && !facts.services.roster)
361
+ || (row.id === ROSTER_ROWS[1]?.id && !facts.services.codeRuntime)
362
+ || row.id === ROSTER_ROWS[2]?.id);
363
+ }
364
+ /** The scope-key signature of the module-copy trap, seen in a host's stderr. */
365
+ const COPY_TRAP_PATTERN = /unscoped context|scope key/u;
366
+ /**
367
+ * What to tell a user whose boot died on the module-copy trap.
368
+ *
369
+ * `/doctor` cannot answer this one: the composition fails before the TUI exists,
370
+ * so the launcher's own failure report is the only place the hint can land. The
371
+ * signature is `agent-presets` refusing an unscoped context, which happens when
372
+ * the plugin and the host resolve different `@deepseek-ai/dsh-scope` instances
373
+ * (a profile that links the plugin into a checkout is the usual shape).
374
+ * @param detail - the host failure text the launcher is about to print.
375
+ * @returns the hint, or `undefined` for every other failure.
376
+ */
377
+ export function copyTrapHint(detail) {
378
+ return COPY_TRAP_PATTERN.test(detail) ? t('doctor.copyTrapHint') : undefined;
379
+ }
380
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
package/lib/i18n/en.js CHANGED
@@ -132,6 +132,7 @@ export const en = {
132
132
  'toolTitle.bash': 'terminal',
133
133
  'toolTitle.pwsh': 'terminal',
134
134
  'toolTitle.present': 'deliver files',
135
+ 'tool.bodyMoreLines': ' … {count} more lines (Enter for the full view; a slow link draws only the first few)',
135
136
  'toolTitle.read_image': 'read image',
136
137
  'toolTitle.run_code': 'run code',
137
138
  'toolTitle.list_subagent_models': 'subagent models',
@@ -265,6 +266,110 @@ export const en = {
265
266
  'diag.v.locksOff': 'DSH_TUI_NO_SESSION_LOCK is set: locking is off, so two Hosts could write one session at once.',
266
267
  'diag.v.rttUnknown': 'the link probe is unknown: the terminal did not answer CSI 6n (some Windows terminals do not), so paint throttling fell back to its default.',
267
268
  'diag.v.detachedBusy': 'this Host was left behind by a busy disconnect (running-detached): it exits and releases the write lock once the current turn settles.',
269
+ 'doctor.title': 'DeepSeek Harness — deployment checkup (/doctor)',
270
+ 'doctor.rowContext': 'profile {profile} · plugin {plugin} · dsh {dsh} · node {node}',
271
+ 'doctor.rowPatch': 'profile patch: {path}',
272
+ 'doctor.rowSummary': 'verdicts: {ok} ok · {warn} attention · {fail} failed',
273
+ 'doctor.detail.row': 'line {line}: {id}',
274
+ 'doctor.detail.missingRow': 'missing row: {id}',
275
+ 'doctor.detail.declaredNoService': 'the patch declares {id}, but this launch registered no such service: if a restart does not fix it, look at module resolution (the nested-install copy trap)',
276
+ 'doctor.detail.range': 'declared range: {range}',
277
+ 'doctor.detail.declared': 'declared table: {versions}',
278
+ 'doctor.patch.ok': 'the profile patch parses ({rows} rows)',
279
+ 'doctor.patch.missing': 'the profile patch cannot be read: {path}',
280
+ 'doctor.patch.missingHint': 'the repair creates it from the profile template',
281
+ 'doctor.patch.broken': 'the profile patch does not parse: {error}',
282
+ 'doctor.patch.brokenHint': 'the loader refuses this patch at boot; fix the YAML above first',
283
+ 'doctor.roster.ok': 'the roster is composed: /mode can switch and the preset tools are in the catalog',
284
+ 'doctor.roster.fail': 'the roster is not composed: /mode reports a missing service and the preset tools are absent',
285
+ 'doctor.codeRuntime.ok': 'code-runtime is registered: the PTC preset can mount',
286
+ 'doctor.codeRuntime.fail': 'code-runtime is not registered: mounting the PTC preset will fail',
287
+ 'doctor.subagentSettings.ok': 'the subagent model-selection settings row is mounted',
288
+ 'doctor.subagentSettings.warn': 'the subagent model-selection settings row is missing: the subagent tool finds no host section',
289
+ 'doctor.subagentSettings.unknown': 'the patch does not parse, so the subagent settings row cannot be judged',
290
+ 'doctor.duplicates.ok': 'no row is mounted twice',
291
+ 'doctor.duplicates.fail': '{count} rows are mounted twice: the second mount fails with "service has been registered"',
292
+ 'doctor.bundle.ok': 'the profile layer and the bundle layer mount no row twice',
293
+ 'doctor.bundle.fail': 'the profile layer and the bundle layer both mount {count} rows',
294
+ 'doctor.version.ok': 'dsh {version} is in the declared table (compatible)',
295
+ 'doctor.version.unknown': 'dsh {version} is declared but its status is {status}',
296
+ 'doctor.version.absent': 'dsh {version} is not in the declared table',
297
+ 'doctor.scope.ok': 'exactly one @deepseek-ai/dsh-scope install',
298
+ 'doctor.scope.unknown': 'no @deepseek-ai/dsh-scope install was located (usual for a global install)',
299
+ 'doctor.scope.fail': '{count} copies of @deepseek-ai/dsh-scope found: preset composition refuses an unscoped context',
300
+ 'doctor.routing.ok': 'the default route and the subagent model are self-consistent',
301
+ 'doctor.routing.warn': '{count} routing self-consistency problems',
302
+ 'doctor.routing.providerMissing': 'the default provider {provider} is not a configured route (configured: {routes})',
303
+ 'doctor.routing.modelMissing': 'the model {model} is not in the {provider} route model list',
304
+ 'doctor.routing.subMismatch': 'the subagent model {model} is not the same family as its parent route {provider}',
305
+ 'doctor.fixHint': 'fix: /doctor --fix (backs up before writing)',
306
+ 'doctor.fix.none': 'no row needs repairing',
307
+ 'doctor.fix.confirm': 'about to repair the profile patch: {changes}',
308
+ 'doctor.fix.confirmHint': 'the previous file is kept as {path}.bak-<timestamp>; y confirms, n cancels',
309
+ 'doctor.fix.applied': 'profile patch repaired (added {added}, removed {removed}): {path}',
310
+ 'doctor.fix.backup': 'backup: {path}',
311
+ 'doctor.fix.cancelled': 'cancelled; the profile patch is unchanged',
312
+ 'doctor.fix.failed': 'repairing the profile patch failed: {error}',
313
+ 'doctor.fix.unknownRow': 'unknown row name: {row} (known: {rows})',
314
+ 'doctor.fix.restart': 'restart the TUI to pick it up: dsh --profile {profile}',
315
+ 'doctor.copyTrapHint': 'Hint: this is the module-copy trap — the plugin and the host resolved different @deepseek-ai/dsh-scope instances (usual shape: the profile links the plugin into a checkout while the CLI lives in a global install), so agent-presets refuses to compose. Fix: give both one copy by installing the plugin into that profile with npm (dsh plugin add dsh-ssh-tui@latest) instead of a symlink; see "the module-copy trap" in the README.',
316
+ 'preset.none': 'there are no presets yet',
317
+ 'preset.wizardPick': 'Pick a preset to work with ({count} available)',
318
+ 'preset.wizardAction': 'preset {id} ({name}): what should happen?',
319
+ 'preset.wizardBroken': 'unusable',
320
+ 'preset.actionShow': 'Show its rows',
321
+ 'preset.actionCopy': 'Copy it (the way the web client creates one)',
322
+ 'preset.actionRename': 'Change the display name',
323
+ 'preset.actionDescribe': 'Change the description',
324
+ 'preset.actionDelete': 'Delete it (user presets only)',
325
+ 'preset.wizardNewId': 'id for the new preset (lowercase letters, digits, hyphens; source: {from})',
326
+ 'preset.wizardNewName': 'display name (Enter alone uses the id)',
327
+ 'preset.wizardRename': 'new display name for preset {id}',
328
+ 'preset.wizardDescribe': 'new description for preset {id}',
329
+ 'preset.cancelled': 'cancelled; nothing changed',
330
+ 'preset.missingService': 'the agentPresets service is unavailable: this profile composes no preset roster',
331
+ 'preset.listTitle': 'Agent presets: {count} · default {default}',
332
+ 'preset.listRow': ' {id} · {name} · {flags}',
333
+ 'preset.listBroken': ' ✖ unusable: {reason}',
334
+ 'preset.listWritable': 'writable (user root: {root}); /preset copy|rename|describe|delete are available',
335
+ 'preset.listReadOnly': 'read-only: this deployment configures no user-writable preset root ($DSH_HOME/.agent-presets)',
336
+ 'preset.trustUser': 'user',
337
+ 'preset.trustSystem': 'shipped',
338
+ 'preset.isDefault': 'default',
339
+ 'preset.isCurrent': 'running',
340
+ 'preset.needId': 'a preset id is required. Available: {ids}',
341
+ 'preset.unknownId': 'unknown preset: {id} (available: {ids})',
342
+ 'preset.showTitle': 'preset {id}: {name}',
343
+ 'preset.showMeta': ' {trust} · order {order} · {directory}',
344
+ 'preset.showDescription': ' {description}',
345
+ 'preset.showBroken': ' ✖ unusable: {reason}',
346
+ 'preset.showNoRows': ' (no rows to show)',
347
+ 'preset.showRow': ' · {module}{entry}{state}',
348
+ 'preset.showRowId': ' (id {id})',
349
+ 'preset.rowDisabled': ' [disabled]',
350
+ 'preset.rowConditional': ' [conditional: {condition}]',
351
+ 'preset.showRawHint': '(this host has no compositionInventory; showing the first 40 lines of the document)',
352
+ 'preset.unsupported': 'this host version does not support that operation: {feature}',
353
+ 'preset.copyDone': 'copied {from} → {id}{name}\n directory: {directory}\n switch to it: /mode {id}',
354
+ 'preset.metadataDone': 'updated the {field} of {id}',
355
+ 'preset.backupLine': ' previous file backed up to: {path}',
356
+ 'preset.fieldName': 'name',
357
+ 'preset.fieldDescription': 'description',
358
+ 'preset.needValue': 'a new value is required: /preset rename {id} <name> or /preset describe {id} <description>',
359
+ 'preset.deleteConfirm': 'Delete preset {id}?',
360
+ 'preset.deleteHint': 'the whole directory goes away: {directory}\ny confirms, n cancels; only user presets can be deleted',
361
+ 'preset.deleteDone': 'deleted preset {id}',
362
+ 'preset.deleteCancelled': 'cancelled; nothing was deleted',
363
+ 'preset.failed': 'the preset operation failed: {error}',
364
+ 'preset.unknownSub': 'unknown subcommand: {sub} (available: list / show / copy / rename / describe / delete)',
365
+ 'preset.refused.invalid-id': 'invalid id: {id} (lowercase letters, digits and hyphens, starting with a letter or digit)',
366
+ 'preset.refused.exists': 'that id is taken: {id} ({name}); a copy never overwrites — pick another id or delete it first',
367
+ 'preset.refused.not-found': 'no such source preset: {id}',
368
+ 'preset.refused.read-only': 'this deployment has no user-writable preset root, so presets cannot be created or changed',
369
+ 'preset.refused.system': 'a shipped preset cannot be changed or deleted: {id}',
370
+ 'preset.refused.running': 'the running preset cannot be deleted: {id} (switch to another one first)',
371
+ 'preset.refused.empty-metadata': 'name and description cannot both be empty: {id}',
372
+ 'cmd.preset': 'Preset authoring: run it for a wizard (pick a preset, then an action); /preset list prints the roster; show <id> prints its rows; copy <from> <new-id> [name]; rename/describe edit the display name and description; delete removes a user preset',
268
373
  'cmd.unknown': 'Unknown command: /{command} (try /help)',
269
374
  'cmd.failedNamed': '/{command} failed: {error}',
270
375
  'cmd.serviceMissing': '{service} service is unavailable',
@@ -330,8 +435,11 @@ export const en = {
330
435
  'onboard.envStale': 'System already injected {env} (it may be stale). First-run wizard will overwrite your key; restart the TUI after save.',
331
436
  'onboard.needSetup': 'First launch: configure a provider and API key (/setup anytime).',
332
437
  'onboard.title': 'First-run wizard — pick a provider (same as the official Models page)',
333
- 'approval.statusAuto': 'Auto-approval on: {allowed} allowed · {denied} auto-rejected · {reviewed} AI reviews (the model is told why)',
438
+ 'approval.statusAuto': 'Auto-approval on: {allowed} allowed · {denied} auto-rejected · {reviewed} AI reviews · {cacheHits} cache hits ({cached} entries) (the model is told why)',
334
439
  'approval.statusOff': 'Auto-approval off: every approval asks',
440
+ 'approval.cacheHitRow': '⚠ auto-approval review (cache hit, {age} old): {verdict} · {command} · risk {risk} · {reason}',
441
+ 'approval.cacheStatus': 'auto-approval verdict cache: {cached} entries · {cacheHits} hits · TTL {minutes} min (/approval cache clear drops them)',
442
+ 'approval.cacheCleared': 'auto-approval verdict cache cleared: {count} entries',
335
443
  'approval.autoOn': 'Auto-approval ON: low-risk commands and workspace file tools approve; dangerous shapes (rm -rf, sudo, curl|sh, git push --force, sensitive-path reads) auto-REJECT with the reason fed back to the model; unrecognized shapes (npm publish, interpreter -c/-e) go to the subagent-model reviewer (authorization=yes required), then ask while attached and reject when detached.',
336
444
  'approval.autoOff': 'Auto-approval OFF: back to per-request prompts.',
337
445
  'approval.reviewRow': '⚠ Auto-approval review {verdict} (risk: {risk}, authorization: {authorization}): {reason}',
@@ -417,8 +525,8 @@ export const en = {
417
525
  'dialog.ask': 'ask user {index}/{total}: {question}',
418
526
  'dialog.recommended': ' (recommended)',
419
527
  'dialog.freeform': ' (freeform: type below and press Enter)',
420
- 'dialog.multiHint': ' digits/letters toggle, Enter submits, Esc cancels',
421
- 'dialog.singleHint': ' digits/letters select, Enter submits, Esc cancels',
528
+ 'dialog.multiHint': ' digits/letters toggle, Enter submits, Esc cancels (first option preselected)',
529
+ 'dialog.singleHint': ' digits/letters select, Enter submits, Esc cancels (first option preselected)',
422
530
  'dialog.scrolled': '↑ scrolled {count} lines · PgUp/PgDn/wheel · Esc to bottom',
423
531
  'reason.done': '{marker} thought · {lines} lines',
424
532
  'reason.live': '{marker} thinking {spinner} · {chars} chars',
@@ -595,6 +703,8 @@ export const en = {
595
703
  'cmd.quit': 'Exit the TUI and stop the Host (runs immediately; resume from the session log)',
596
704
  'cmd.clear': 'Clear visible transcript and search results (runs immediately, keeps session history)',
597
705
  'cmd.diag': 'Local diagnostics: versions, channel, locks, Host identity, link, log',
706
+ 'cmd.doctor': 'Deployment checkup: roster, dependencies, compatibility, routing, each with a fix; /doctor --fix repairs the profile patch',
707
+ 'cmd.fix': 'Repair the profile patch by row: insert missing rows, merge duplicates, back up first, effective after a restart',
598
708
  'cmd.status': 'Status report: show session ID, route, context occupancy, quota, network RTT, and version (runs immediately)',
599
709
  'cmd.disconnect': 'SSH drop policy: run directly to pick, or /disconnect <pause (busy pause / idle exit) | continue (busy background)>',
600
710
  'cmd.approval': 'Auto-approval: run directly to toggle, or /approval <auto (allow low-risk) | off | status>',