dsh-llm-fallbacks 0.6.13 → 0.8.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.
@@ -22,15 +22,10 @@ export declare const zh: {
22
22
  'maxSwitchesPerStep.label': string;
23
23
  'maxSwitchesPerStep.hint': string;
24
24
  'maxSwitchesPerStep.tooltip': string;
25
- 'alwaysModeRetryCap.label': string;
26
- 'alwaysModeRetryCap.hint': string;
27
- 'alwaysModeRetryCap.tooltip': string;
25
+ 'virtualOnly.rule': string;
28
26
  'advanced.label': string;
29
27
  'advanced.expand': string;
30
28
  'advanced.collapse': string;
31
- 'roleAutoMatch.label': string;
32
- 'roleAutoMatch.hint': string;
33
- 'roleAutoMatch.tooltip': string;
34
29
  'rootChain.label': string;
35
30
  'rootChain.tooltip': string;
36
31
  'defaultModel.label': string;
@@ -42,21 +37,26 @@ export declare const zh: {
42
37
  'chains.selector.modelPlaceholder': string;
43
38
  'chains.selector.wildcardLegacy': string;
44
39
  'chains.selector.noModelsStrict': string;
45
- 'mainAgent.label': string;
46
40
  'subagents.label': string;
47
- 'subagents.policy.label': string;
48
- 'subagents.policy.allowlist': string;
49
- 'subagents.policy.head': string;
50
- 'subagents.policy.source.authorized': string;
51
- 'subagents.policy.source.injected': string;
52
- 'subagents.policy.blocked': string;
53
- 'subagents.policy.unprovable': string;
54
- 'subagents.policy.offAllowlist': string;
55
- 'subagents.policy.recommend': string;
56
- 'subagents.policy.sync': string;
57
- 'subagents.policy.sync.done': string;
58
- 'subagents.policy.sync.failed': string;
59
- 'subagents.policy.sync.dirty': string;
41
+ 'virtualChain.label': string;
42
+ 'virtualChain.hint': string;
43
+ 'chains.tab.add': string;
44
+ 'chains.tab.menu': string;
45
+ 'chains.name.label': string;
46
+ 'chains.name.hint': string;
47
+ 'chains.name.tooltip': string;
48
+ 'chains.tab.renameLabel': string;
49
+ 'chains.tab.renameDone': string;
50
+ 'chains.tab.delete': string;
51
+ 'chains.tab.deleteDisabled': string;
52
+ 'chains.tab.dirty': string;
53
+ 'chains.tab.error': string;
54
+ 'chains.empty.title': string;
55
+ 'chains.empty.body': string;
56
+ 'chains.empty.create': string;
57
+ 'chains.chainFoot.hint': string;
58
+ 'chains.chainFoot.discard': string;
59
+ 'chains.chainFoot.save': string;
60
60
  'timeSlots.label': string;
61
61
  'timeSlots.hint': string;
62
62
  'timeSlots.tz.label': string;
@@ -104,8 +104,6 @@ export declare const zh: {
104
104
  'allDay.pro': string;
105
105
  'allDay.nonconforming': string;
106
106
  'roles.list.label': string;
107
- 'roles.list.hint': string;
108
- 'roles.list.tooltip': string;
109
107
  'roles.id': string;
110
108
  'roles.id.hint': string;
111
109
  'roles.idPlaceholder': string;
@@ -117,35 +115,24 @@ export declare const zh: {
117
115
  'roles.seedSource.bundled': string;
118
116
  'roles.seedSource.external': string;
119
117
  'roles.seedSource.user': string;
120
- 'roles.seedChainOptional': string;
121
- 'roles.fallback': string;
122
- 'roles.fallback.inherit-root': string;
123
- 'roles.fallback.none': string;
118
+ 'roles.list.hint': string;
119
+ 'roles.chain.label': string;
120
+ 'roles.chain.unspecified': string;
121
+ 'roles.chain.hint': string;
122
+ 'roles.chain.tooltip': string;
123
+ 'roles.chainMeta.unspecified': string;
124
124
  'roles.add': string;
125
125
  'roles.remove': string;
126
126
  'roles.expand': string;
127
127
  'roles.collapse': string;
128
- 'roles.selector.add': string;
129
- 'roles.rules': string;
130
- 'roles.rules.hint': string;
131
- 'roles.rules.tooltip': string;
132
- 'roles.rule.provider': string;
133
- 'roles.rule.provider.any': string;
134
- 'roles.rule.model': string;
135
- 'roles.rule.model.any': string;
136
- 'roles.rule.role': string;
137
- 'roles.rule.role.inherit': string;
138
- 'roles.rule.roleSelectPlaceholder': string;
139
- 'roles.rule.roleUndeclared.short': string;
140
- 'roles.addRule': string;
141
- 'roles.removeRule': string;
142
128
  'validation.blocked': string;
143
129
  'validation.roleIdFormat': string;
144
130
  'validation.roleIdReserved': string;
145
131
  'validation.roleIdDuplicate': string;
146
- 'validation.ruleRoleUndeclared': string;
147
- 'validation.ruleRoleRequired': string;
148
- 'validation.roleChainRequired': string;
132
+ 'validation.chainIdFormat': string;
133
+ 'validation.chainIdDuplicate': string;
134
+ 'validation.chainLabelRequired': string;
135
+ 'validation.chainEntriesRequired': string;
149
136
  'validation.allDayRequired': string;
150
137
  'validation.slotChainRequired': string;
151
138
  'validation.slotWindow': string;
@@ -163,24 +150,9 @@ export declare const zh: {
163
150
  'catalog.outside.tooltip': string;
164
151
  'catalog.outside.short': string;
165
152
  'catalog.unconfigured.short': string;
166
- 'status.title': string;
167
- 'status.switches.label': string;
168
- 'status.switches.empty': string;
169
- 'status.switches.error': string;
170
- 'status.switches.compact': string;
171
- 'status.switches.compact.roleInject': string;
172
153
  'status.switches.reason.trigger-code': string;
173
154
  'status.switches.reason.always-cap': string;
174
155
  'status.switches.reason.role-inject': string;
175
- 'general.title': string;
176
- 'general.enabled': string;
177
- 'general.disabled': string;
178
- 'general.unknown': string;
179
- 'general.unavailable': string;
180
- 'general.switch': string;
181
- 'general.switch.roleInject': string;
182
- 'general.switch.empty': string;
183
- 'general.error': string;
184
156
  'chat.switch.title': string;
185
157
  'chat.switch.summary': string;
186
158
  'chat.switch.summary.roleInject': string;
@@ -220,15 +192,10 @@ export declare const en: {
220
192
  'maxSwitchesPerStep.label': string;
221
193
  'maxSwitchesPerStep.hint': string;
222
194
  'maxSwitchesPerStep.tooltip': string;
223
- 'alwaysModeRetryCap.label': string;
224
- 'alwaysModeRetryCap.hint': string;
225
- 'alwaysModeRetryCap.tooltip': string;
195
+ 'virtualOnly.rule': string;
226
196
  'advanced.label': string;
227
197
  'advanced.expand': string;
228
198
  'advanced.collapse': string;
229
- 'roleAutoMatch.label': string;
230
- 'roleAutoMatch.hint': string;
231
- 'roleAutoMatch.tooltip': string;
232
199
  'rootChain.label': string;
233
200
  'rootChain.tooltip': string;
234
201
  'defaultModel.label': string;
@@ -240,21 +207,26 @@ export declare const en: {
240
207
  'chains.selector.modelPlaceholder': string;
241
208
  'chains.selector.wildcardLegacy': string;
242
209
  'chains.selector.noModelsStrict': string;
243
- 'mainAgent.label': string;
244
210
  'subagents.label': string;
245
- 'subagents.policy.label': string;
246
- 'subagents.policy.allowlist': string;
247
- 'subagents.policy.head': string;
248
- 'subagents.policy.source.authorized': string;
249
- 'subagents.policy.source.injected': string;
250
- 'subagents.policy.blocked': string;
251
- 'subagents.policy.unprovable': string;
252
- 'subagents.policy.offAllowlist': string;
253
- 'subagents.policy.recommend': string;
254
- 'subagents.policy.sync': string;
255
- 'subagents.policy.sync.done': string;
256
- 'subagents.policy.sync.failed': string;
257
- 'subagents.policy.sync.dirty': string;
211
+ 'virtualChain.label': string;
212
+ 'virtualChain.hint': string;
213
+ 'chains.tab.add': string;
214
+ 'chains.tab.menu': string;
215
+ 'chains.name.label': string;
216
+ 'chains.name.hint': string;
217
+ 'chains.name.tooltip': string;
218
+ 'chains.tab.renameLabel': string;
219
+ 'chains.tab.renameDone': string;
220
+ 'chains.tab.delete': string;
221
+ 'chains.tab.deleteDisabled': string;
222
+ 'chains.tab.dirty': string;
223
+ 'chains.tab.error': string;
224
+ 'chains.empty.title': string;
225
+ 'chains.empty.body': string;
226
+ 'chains.empty.create': string;
227
+ 'chains.chainFoot.hint': string;
228
+ 'chains.chainFoot.discard': string;
229
+ 'chains.chainFoot.save': string;
258
230
  'timeSlots.label': string;
259
231
  'timeSlots.hint': string;
260
232
  'timeSlots.tz.label': string;
@@ -303,7 +275,6 @@ export declare const en: {
303
275
  'allDay.nonconforming': string;
304
276
  'roles.list.label': string;
305
277
  'roles.list.hint': string;
306
- 'roles.list.tooltip': string;
307
278
  'roles.id': string;
308
279
  'roles.id.hint': string;
309
280
  'roles.idPlaceholder': string;
@@ -315,35 +286,23 @@ export declare const en: {
315
286
  'roles.seedSource.bundled': string;
316
287
  'roles.seedSource.external': string;
317
288
  'roles.seedSource.user': string;
318
- 'roles.seedChainOptional': string;
319
- 'roles.fallback': string;
320
- 'roles.fallback.inherit-root': string;
321
- 'roles.fallback.none': string;
289
+ 'roles.chain.label': string;
290
+ 'roles.chain.unspecified': string;
291
+ 'roles.chain.hint': string;
292
+ 'roles.chain.tooltip': string;
293
+ 'roles.chainMeta.unspecified': string;
322
294
  'roles.add': string;
323
295
  'roles.remove': string;
324
296
  'roles.expand': string;
325
297
  'roles.collapse': string;
326
- 'roles.selector.add': string;
327
- 'roles.rules': string;
328
- 'roles.rules.hint': string;
329
- 'roles.rules.tooltip': string;
330
- 'roles.rule.provider': string;
331
- 'roles.rule.provider.any': string;
332
- 'roles.rule.model': string;
333
- 'roles.rule.model.any': string;
334
- 'roles.rule.role': string;
335
- 'roles.rule.role.inherit': string;
336
- 'roles.rule.roleSelectPlaceholder': string;
337
- 'roles.rule.roleUndeclared.short': string;
338
- 'roles.addRule': string;
339
- 'roles.removeRule': string;
340
298
  'validation.blocked': string;
341
299
  'validation.roleIdFormat': string;
342
300
  'validation.roleIdReserved': string;
343
301
  'validation.roleIdDuplicate': string;
344
- 'validation.ruleRoleUndeclared': string;
345
- 'validation.ruleRoleRequired': string;
346
- 'validation.roleChainRequired': string;
302
+ 'validation.chainIdFormat': string;
303
+ 'validation.chainIdDuplicate': string;
304
+ 'validation.chainLabelRequired': string;
305
+ 'validation.chainEntriesRequired': string;
347
306
  'validation.allDayRequired': string;
348
307
  'validation.slotChainRequired': string;
349
308
  'validation.slotWindow': string;
@@ -361,24 +320,9 @@ export declare const en: {
361
320
  'catalog.outside.tooltip': string;
362
321
  'catalog.outside.short': string;
363
322
  'catalog.unconfigured.short': string;
364
- 'status.title': string;
365
- 'status.switches.label': string;
366
- 'status.switches.empty': string;
367
- 'status.switches.error': string;
368
- 'status.switches.compact': string;
369
- 'status.switches.compact.roleInject': string;
370
323
  'status.switches.reason.trigger-code': string;
371
324
  'status.switches.reason.always-cap': string;
372
325
  'status.switches.reason.role-inject': string;
373
- 'general.title': string;
374
- 'general.enabled': string;
375
- 'general.disabled': string;
376
- 'general.unknown': string;
377
- 'general.unavailable': string;
378
- 'general.switch': string;
379
- 'general.switch.roleInject': string;
380
- 'general.switch.empty': string;
381
- 'general.error': string;
382
326
  'chat.switch.title': string;
383
327
  'chat.switch.summary': string;
384
328
  'chat.switch.summary.roleInject': string;
@@ -402,8 +346,8 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
402
346
  }
403
347
  }
404
348
  /**
405
- * Reason → locale key map for switch summaries (S-c; shared by the card's
406
- * status block, the General page status row, and the conversation node). All
349
+ * Reason → locale key map for switch summaries (shared by the conversation
350
+ * node). All
407
351
  * reasons resolve from ONE key family (`status.switches.reason.*`) — the
408
352
  * shared reason vocabulary must not mix dictionary families (qc1 F-004). The
409
353
  * session log is durable and forward-compatible: a reason value outside the
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * `/fallbacks` slash command (plan fallbacks-role-runtime T3, AC-5).
3
3
  *
4
- * Session-scoped, read-only diagnostic: current session origin → resolved
5
- * role → resolved chain (role chain, else rootChain — an `inherit: true`
6
- * tail is annotated 「(inherit-root)」) → recent `fallbacks/switch` events
7
- * (newest first, capped) → cooldown status. Mirrors dsh-advisor's
4
+ * Session-scoped, read-only diagnostic: current session origin → the resolved
5
+ * dispatch role (+ its specified chain pointer) → every configured named chain
6
+ * with its tail and current slot label, the calling agent's selection marked →
7
+ * recent `fallbacks/switch` events (newest first, capped) → cooldown status.
8
+ * Mirrors dsh-advisor's
8
9
  * `/advisor` command pattern: a conditional `ctx.inject(['commands'])` child
9
10
  * in `src/index.ts` calls {@link registerFallbacksCommands} with a
10
11
  * factory-bound handler; `commands` never joins the top-level inject list, so
@@ -26,11 +27,9 @@
26
27
  * @module dsh-llm-fallbacks/commands
27
28
  */
28
29
  import type { CommandDefinition } from '@deepseek-ai/dsh-commands';
29
- import { type FallbacksRole } from './config.ts';
30
- import type { Origin } from './roles.ts';
30
+ type Origin = 'root' | 'subagent';
31
31
  import type { FallbacksSwitchEventData } from './events.ts';
32
32
  import type { SeedRevertFailReason } from './seeds.ts';
33
- import { type SlotRowConfig } from './time-slots.ts';
34
33
  /** How many recent `fallbacks/switch` events `/fallbacks` shows (newest first). */
35
34
  export declare const RECENT_SWITCHES_LIMIT = 5;
36
35
  /** Minimal command registry surface (satisfied by the dsh `CommandService`). */
@@ -64,26 +63,21 @@ export interface FallbacksCooldownEntry {
64
63
  export interface FallbacksCommandSnapshot {
65
64
  /** Session origin: `'root'` when the agent carries no header origin. */
66
65
  readonly origin: Origin;
67
- /** Resolved role (first matching `roles.rules` entry → built-in `'inherit'`, spec §7.1). */
66
+ /** Resolved dispatch role (the seam record), `''` when none resolved. */
68
67
  readonly role: string;
69
- /** True when the role's own chain is non-empty and shown; false when rootChain (or none) is shown. */
70
- readonly chainRole: boolean;
71
- /** The displayed chain entries: the role's own chain when non-empty, else
72
- * rootChain — except `fallback: 'none'` with an empty own chain, which
73
- * yields `[]` even when rootChain is non-empty (nothing appended, mirroring
74
- * resolveChainViews' `[...[], ...[]]`); empty = not configured. */
75
- readonly chain: readonly string[];
76
- /** True when rootChain is appended as the inherit fallback tail (role's
77
- * `fallback` is `'inherit-root'` — or the role is unknown — and rootChain
78
- * is non-empty; the diagnostic annotation source, spec §7.4). */
79
- readonly inherit: boolean;
80
- /** Current time-slot winner + display label (P5/P7): the 分时切换 side of
81
- * the status strip. The switches section below is the 降级切换 side —
82
- * the copy never mixes. */
83
- readonly slot: {
84
- readonly winner: SlotRowConfig | 'all-day';
68
+ /** The resolved role's declared chain POINTER (「指定降级链」), `undefined`
69
+ * when the role is unresolved or specifies nothing (NOT SPECIFIED). */
70
+ readonly roleChain?: string;
71
+ /** Every configured named chain with its slot state; `selected` marks the
72
+ * calling agent's chain (its route names the chain id). */
73
+ readonly chains: readonly {
74
+ readonly id: string;
85
75
  readonly label: string;
86
- };
76
+ readonly entries: readonly string[];
77
+ /** Current slot label for the chain (`'all-day'` when no row matches). */
78
+ readonly slotLabel: string;
79
+ readonly selected: boolean;
80
+ }[];
87
81
  /** Recent `fallbacks/switch` events (failure walks — 降级切换), newest
88
82
  * first, capped at {@link RECENT_SWITCHES_LIMIT}. */
89
83
  readonly switches: readonly FallbacksSwitchEventData[];
@@ -91,65 +85,56 @@ export interface FallbacksCommandSnapshot {
91
85
  readonly cooldown: readonly FallbacksCooldownEntry[];
92
86
  }
93
87
  /**
94
- * The composed-config surface `/fallbacks config` renders (plan
95
- * fallbacks-tui-client T2, AC-2): the composed `fallbacks` namespace as the
96
- * runtime sees it (settings user layer included). Roles are summarized from
97
- * `roles.list` as `{ id, chainCount }` — the two-block model: `roles.list`
98
- * entities carry id/persona/chain/fallback (NO per-role `model`;
99
- * `provider`/`model` live on `roles.rules`), so the readback line is id +
100
- * chain count, never a rules dump.
88
+ * The composed-config surface `/fallbacks config` renders: the composed
89
+ * `fallbacks` namespace as the runtime sees it (settings user layer included).
90
+ * It carries every named chain (`{ id, label, entries, timeSlots }`) and the
91
+ * declared roles as `{ id, chain? }` — the role's optional POINTER into
92
+ * `chains[].id` (「指定降级链」), rendered as its `FallbacksChain/<id>` route or
93
+ * as NOT SPECIFIED. There is no rules dump (rules are gone).
101
94
  *
102
- * Enriched readback (plan fallbacks-tui-settings Task 2, AC-4): timeSlots /
103
- * tz / roles.rules join the summary so TUI operators can verify `/settings`
104
- * edits. One summarized time-slot row: preset rows carry `{ preset,
105
- * chainCount }` (windows are frozen code constants in {@link PRESETS} and
106
- * never stored on the row — the render resolves the window text from
107
- * PRESETS); custom rows carry `{ start, end, chainCount }`. Rules rows carry
108
- * `{ provider, model, role }` — an omitted provider/model (wildcard match at
109
- * runtime) is summarized as `''` and rendered as `*`.
95
+ * The config-level `tz` joins the summary so TUI operators can verify
96
+ * `/settings` edits. One summarized time-slot row: preset rows carry
97
+ * `{ preset, chainCount }` (windows are frozen code constants in
98
+ * {@link PRESETS} and never stored on the row — the render resolves the window
99
+ * text from PRESETS); custom rows carry `{ start, end, chainCount }`.
110
100
  */
111
101
  export interface FallbacksConfigSummary {
112
102
  /**
113
- * Content-presence gate (`isFallbackActive`, plan fallbacks-web-ux-alignment
114
- * T2 — the removed config-level `enabled` switch re-keyed): the plugin
115
- * intervenes exactly when a chain/time-slot/role is configured.
103
+ * Content-presence gate (`isFallbackActive`): the plugin intervenes exactly
104
+ * when the named-chain list is non-empty (`chains.length > 0`). Slot rows and
105
+ * declared roles alone do NOT activate it — they are per-chain / optional.
116
106
  */
117
107
  readonly active: boolean;
118
108
  readonly triggerCodes: readonly string[];
119
- readonly rootChain: readonly string[];
120
- /** Summarized time-slot rows (preset rows carry `preset`, custom rows carry `start`/`end`; both may carry a day mask). */
121
- readonly timeSlots: readonly {
122
- preset?: string;
123
- start?: string;
124
- end?: string;
125
- days?: readonly number[];
126
- chainCount: number;
109
+ /** Named chains (v2): id/label/entries + summarized per-chain slot rows. */
110
+ readonly chains: readonly {
111
+ id: string;
112
+ label: string;
113
+ entries: readonly string[];
114
+ timeSlots: readonly {
115
+ preset?: string;
116
+ start?: string;
117
+ end?: string;
118
+ days?: readonly number[];
119
+ chainCount: number;
120
+ }[];
127
121
  }[];
128
122
  /** Config-level timezone for slot matching (default `Asia/Shanghai`). */
129
123
  readonly tz: string;
130
124
  readonly roles: readonly {
131
125
  id: string;
132
- chainCount: number;
133
- }[];
134
- /** Summarized role rules: provider/model patterns → declared role (or the built-in `'inherit'`). */
135
- readonly rules: readonly {
136
- provider: string;
137
- model: string;
138
- role: string;
126
+ chain?: string;
139
127
  }[];
140
128
  readonly cooldownMs: number;
141
129
  readonly revertPolicy: string;
142
130
  readonly maxSwitchesPerStep: number;
143
- readonly alwaysModeRetryCap: number;
144
131
  readonly presets: 'bundled' | 'none';
145
- /** Dispatch-time LLM role auto-match switch (default true). */
146
- readonly roleAutoMatch: boolean;
147
132
  }
148
133
  /**
149
134
  * The session-scoped read-only operations the `/fallbacks` handler drives.
150
135
  * Implemented by the wiring (`src/index.ts`) against the live config source
151
- * (`roles.list` / `rootChain` — no chain map anymore) and the per-agent
152
- * state store; faked in unit tests.
136
+ * (`chains` / `roles.list`), the dispatch seam's per-child record and the
137
+ * per-agent state store; faked in unit tests.
153
138
  */
154
139
  export interface FallbacksCommandController {
155
140
  /** Snapshot the session's fallback diagnostics. Never mutates state. */
@@ -189,7 +174,6 @@ export declare const FALLBACKS_COMMAND_LOCALES: {
189
174
  readonly origin: "会话来源";
190
175
  readonly role: "角色";
191
176
  readonly chain: "链";
192
- readonly inheritRoot: "(inherit-root)";
193
177
  readonly chainNone: "未配置";
194
178
  readonly slot: "分时";
195
179
  readonly switches: "最近降级切换";
@@ -208,22 +192,20 @@ export declare const FALLBACKS_COMMAND_LOCALES: {
208
192
  readonly configEnabled: "已启用";
209
193
  readonly configDisabled: "未启用";
210
194
  readonly configTriggerCodes: "触发码";
211
- readonly configRootChain: "根链";
195
+ readonly configChains: "虚拟链";
212
196
  readonly configEmpty: "(空)";
213
- readonly configTimeSlots: "分时槽";
197
+ readonly configChainItem: "{id}({label}): {entries}|分时槽: {slots}";
214
198
  readonly configSlotPresetItem: "{preset}(chain: {n}, window {window})";
215
199
  readonly configSlotPresetBare: "{preset}(chain: {n})";
216
200
  readonly configSlotCustomItem: "custom {start}-{end}(chain: {n})";
217
201
  readonly configTz: "时区";
218
202
  readonly configRoles: "角色";
219
- readonly configRoleItem: "{id}(chain: {n})";
220
- readonly configRules: "角色规则";
203
+ readonly configRoleItem: "{id}(指定降级链: {chain})";
204
+ readonly configRoleUnspecified: "未指定(沿用 dsh 默认)";
221
205
  readonly configCooldown: "冷却";
222
206
  readonly configRevert: "回主策略";
223
- readonly configMaxSwitches: "单步最大切换";
224
- readonly configAlwaysCap: "always 上限";
207
+ readonly configMaxSwitches: "单次请求行走最大切换";
225
208
  readonly configPresets: "预置";
226
- readonly configRoleAutoMatch: "角色自动匹配";
227
209
  readonly configEdit: "编辑:/settings(TUI 设置界面)或 ~/.dsh/profiles/<profile>/cordis.patch.yml(插件行)/ $DSH_HOME/settings.yaml(fallbacks: 分节)";
228
210
  readonly configEditHint: "TUI 通过 /settings 修改配置;文件编辑仍然可用";
229
211
  readonly revertSeedOk: "角色 {id} 已还原为 Seed 默认";
@@ -244,7 +226,6 @@ export declare const FALLBACKS_COMMAND_LOCALES: {
244
226
  readonly origin: "Session origin";
245
227
  readonly role: "Role";
246
228
  readonly chain: "Chain";
247
- readonly inheritRoot: " (inherit-root)";
248
229
  readonly chainNone: "not configured";
249
230
  readonly slot: "Time slot";
250
231
  readonly switches: "Recent fallback switches";
@@ -263,22 +244,20 @@ export declare const FALLBACKS_COMMAND_LOCALES: {
263
244
  readonly configEnabled: "enabled";
264
245
  readonly configDisabled: "disabled";
265
246
  readonly configTriggerCodes: "Trigger codes";
266
- readonly configRootChain: "Root chain";
247
+ readonly configChains: "Chains";
267
248
  readonly configEmpty: "(empty)";
268
- readonly configTimeSlots: "Time slots";
249
+ readonly configChainItem: "{id} ({label}): {entries} | slots: {slots}";
269
250
  readonly configSlotPresetItem: "{preset} (chain: {n}, window {window})";
270
251
  readonly configSlotPresetBare: "{preset} (chain: {n})";
271
252
  readonly configSlotCustomItem: "custom {start}-{end} (chain: {n})";
272
253
  readonly configTz: "TZ";
273
254
  readonly configRoles: "Roles";
274
- readonly configRoleItem: "{id} (chain: {n})";
275
- readonly configRules: "Rules";
255
+ readonly configRoleItem: "{id} (specified chain: {chain})";
256
+ readonly configRoleUnspecified: "not specified (dsh default)";
276
257
  readonly configCooldown: "Cooldown";
277
258
  readonly configRevert: "Revert";
278
- readonly configMaxSwitches: "Max switches/step";
279
- readonly configAlwaysCap: "Always-mode cap";
259
+ readonly configMaxSwitches: "Max switches per request walk";
280
260
  readonly configPresets: "Presets";
281
- readonly configRoleAutoMatch: "Auto-match";
282
261
  readonly configEdit: "Edit: /settings (TUI settings screen) or ~/.dsh/profiles/<profile>/cordis.patch.yml (plugin row) / $DSH_HOME/settings.yaml (fallbacks: section)";
283
262
  readonly configEditHint: "TUI edits config via /settings; file editing still works";
284
263
  readonly revertSeedOk: "role {id} reverted to its seed default";
@@ -319,31 +298,6 @@ export declare function parseFallbacksSubcommand(rawInput: string): FallbacksSub
319
298
  * `SessionEventMap` type, and the durable log can outlive schema versions).
320
299
  */
321
300
  export declare function recentFallbacksSwitches(events: readonly unknown[], limit: number): FallbacksSwitchEventData[];
322
- /**
323
- * The chain entries `/fallbacks` shows for a role (spec §7.4): the declared
324
- * role's own chain when non-empty (`chainRole: true`); an empty own chain
325
- * defers to `rootChain` unless `fallback: 'none'` — then nothing is appended
326
- * and the display chain is empty, mirroring `resolveChainViews`'s
327
- * `[...[], ...[]]` exactly; undeclared ids and the built-in `'inherit'`
328
- * role resolve to `rootChain`. `inherit: true` marks the append-not-replace
329
- * tail — the role's `fallback` is `'inherit-root'` (the default) or the role
330
- * is unknown/built-in `'inherit'`, and `rootChain` is non-empty. Mirrors
331
- * `resolveChainViews`'s concatenation (see {@link buildRoleEntries} —
332
- * `src/chains.ts`; the diagnostic keeps its display semantics: the role's
333
- * own chain renders in full, `rootChain` only when the role has no own
334
- * chain, with the inherit tail as an annotation) without a failing model to
335
- * resolve against (the diagnostic is model-independent).
336
- *
337
- * `warn` mirrors {@link resolveChainViews}' defensive unknown-role warn
338
- * (qc2 F-002 — routed through the injected logger; the `/fallbacks` path
339
- * never reaches here unsanitized, as {@link resolveRole} resolves to a
340
- * declared id or `'inherit'` first, so this is direct-caller parity).
341
- */
342
- export declare function resolveChainForDiagnostic(roles: readonly FallbacksRole[], rootChain: readonly string[], role: string, warn?: (message: string) => void): {
343
- readonly chainRole: boolean;
344
- readonly chain: readonly string[];
345
- readonly inherit: boolean;
346
- };
347
301
  /**
348
302
  * Cap for the composed-config readback's LIST lines — Trigger codes, Root
349
303
  * chain, Time slots, Roles, and Rules (qc2 Task-2 Minor): beyond this many
@@ -352,12 +306,13 @@ export declare function resolveChainForDiagnostic(roles: readonly FallbacksRole[
352
306
  */
353
307
  export declare const FALLBACKS_CONFIG_LIST_CAP = 5;
354
308
  /**
355
- * Render the `/fallbacks config` surface (plan fallbacks-tui-client T2,
356
- * AC-2 + fallbacks-tui-settings Task 2 AC-4): the composed `fallbacks`
357
- * namespace as the runtime reads it — enriched with the time-slot rows
358
- * (preset rows resolve their frozen window from {@link PRESETS}), the
359
- * config timezone, and the role rules — plus edit hints pointing at the
360
- * `/settings` TUI edit surface while keeping the file-edit documentation.
309
+ * Render the `/fallbacks config` surface: the composed `fallbacks` namespace
310
+ * as the runtime reads it — every named chain with its label, entries and
311
+ * time-slot rows (preset rows resolve their frozen window from
312
+ * {@link PRESETS}), the config timezone, and each role with its `chain`
313
+ * POINTER (the `FallbacksChain/<id>` it specifies, or NOT SPECIFIED) — plus
314
+ * edit hints pointing at the `/settings` TUI edit surface while keeping the
315
+ * file-edit documentation.
361
316
  * The FIRST LINE marks the composed-config readback — distinct from the
362
317
  * diagnostic title and never merged into {@link fallbacksCommandText} (two
363
318
  * operator surfaces, product lock). Locale defaults to `zh` (the command
@@ -366,8 +321,10 @@ export declare const FALLBACKS_CONFIG_LIST_CAP = 5;
366
321
  export declare function fallbacksConfigText(summary: FallbacksConfigSummary, locale?: FallbacksCommandLocale): string;
367
322
  /**
368
323
  * Render the `/fallbacks` status surface for one snapshot. Kept minimal and
369
- * truthful: origin → role → chain (+ inherit tail) → current slot (分时) →
370
- * recent switches (降级切换) → cooldown.
324
+ * truthful: origin → role (+ its specified chain pointer) → every configured
325
+ * chain with tail + slot state, the calling agent's selection marked →
326
+ * recent switches (降级切换) → cooldown. No chain-id argument (named virtual
327
+ * chains §1): the snapshot lists every chain.
371
328
  */
372
329
  export declare function fallbacksCommandText(snapshot: FallbacksCommandSnapshot, locale?: FallbacksCommandLocale): string;
373
330
  /**
@@ -378,3 +335,4 @@ export declare function fallbacksCommandText(snapshot: FallbacksCommandSnapshot,
378
335
  * @returns the registry disposer (the inject child owns its lifetime).
379
336
  */
380
337
  export declare function registerFallbacksCommands(registry: FallbacksCommandRegistry, controller: FallbacksCommandController, locale?: FallbacksCommandLocale): () => void;
338
+ export {};