dsh-llm-fallbacks 0.7.0 → 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.
@@ -37,21 +37,26 @@ export declare const zh: {
37
37
  'chains.selector.modelPlaceholder': string;
38
38
  'chains.selector.wildcardLegacy': string;
39
39
  'chains.selector.noModelsStrict': string;
40
- 'mainAgent.label': string;
41
40
  'subagents.label': string;
42
- 'subagents.policy.label': string;
43
- 'subagents.policy.allowlist': string;
44
- 'subagents.policy.head': string;
45
- 'subagents.policy.source.authorized': string;
46
- 'subagents.policy.source.injected': string;
47
- 'subagents.policy.blocked': string;
48
- 'subagents.policy.unprovable': string;
49
- 'subagents.policy.offAllowlist': string;
50
- 'subagents.policy.recommend': string;
51
- 'subagents.policy.sync': string;
52
- 'subagents.policy.sync.done': string;
53
- 'subagents.policy.sync.failed': string;
54
- '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;
55
60
  'timeSlots.label': string;
56
61
  'timeSlots.hint': string;
57
62
  'timeSlots.tz.label': string;
@@ -99,8 +104,6 @@ export declare const zh: {
99
104
  'allDay.pro': string;
100
105
  'allDay.nonconforming': string;
101
106
  'roles.list.label': string;
102
- 'roles.list.hint': string;
103
- 'roles.list.tooltip': string;
104
107
  'roles.id': string;
105
108
  'roles.id.hint': string;
106
109
  'roles.idPlaceholder': string;
@@ -112,35 +115,24 @@ export declare const zh: {
112
115
  'roles.seedSource.bundled': string;
113
116
  'roles.seedSource.external': string;
114
117
  'roles.seedSource.user': string;
115
- 'roles.seedChainOptional': string;
116
- 'roles.fallback': string;
117
- 'roles.fallback.inherit-root': string;
118
- '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;
119
124
  'roles.add': string;
120
125
  'roles.remove': string;
121
126
  'roles.expand': string;
122
127
  'roles.collapse': string;
123
- 'roles.selector.add': string;
124
- 'roles.rules': string;
125
- 'roles.rules.hint': string;
126
- 'roles.rules.tooltip': string;
127
- 'roles.rule.provider': string;
128
- 'roles.rule.provider.any': string;
129
- 'roles.rule.model': string;
130
- 'roles.rule.model.any': string;
131
- 'roles.rule.role': string;
132
- 'roles.rule.role.inherit': string;
133
- 'roles.rule.roleSelectPlaceholder': string;
134
- 'roles.rule.roleUndeclared.short': string;
135
- 'roles.addRule': string;
136
- 'roles.removeRule': string;
137
128
  'validation.blocked': string;
138
129
  'validation.roleIdFormat': string;
139
130
  'validation.roleIdReserved': string;
140
131
  'validation.roleIdDuplicate': string;
141
- 'validation.ruleRoleUndeclared': string;
142
- 'validation.ruleRoleRequired': string;
143
- 'validation.roleChainRequired': string;
132
+ 'validation.chainIdFormat': string;
133
+ 'validation.chainIdDuplicate': string;
134
+ 'validation.chainLabelRequired': string;
135
+ 'validation.chainEntriesRequired': string;
144
136
  'validation.allDayRequired': string;
145
137
  'validation.slotChainRequired': string;
146
138
  'validation.slotWindow': string;
@@ -158,24 +150,9 @@ export declare const zh: {
158
150
  'catalog.outside.tooltip': string;
159
151
  'catalog.outside.short': string;
160
152
  'catalog.unconfigured.short': string;
161
- 'status.title': string;
162
- 'status.switches.label': string;
163
- 'status.switches.empty': string;
164
- 'status.switches.error': string;
165
- 'status.switches.compact': string;
166
- 'status.switches.compact.roleInject': string;
167
153
  'status.switches.reason.trigger-code': string;
168
154
  'status.switches.reason.always-cap': string;
169
155
  'status.switches.reason.role-inject': string;
170
- 'general.title': string;
171
- 'general.enabled': string;
172
- 'general.disabled': string;
173
- 'general.unknown': string;
174
- 'general.unavailable': string;
175
- 'general.switch': string;
176
- 'general.switch.roleInject': string;
177
- 'general.switch.empty': string;
178
- 'general.error': string;
179
156
  'chat.switch.title': string;
180
157
  'chat.switch.summary': string;
181
158
  'chat.switch.summary.roleInject': string;
@@ -230,21 +207,26 @@ export declare const en: {
230
207
  'chains.selector.modelPlaceholder': string;
231
208
  'chains.selector.wildcardLegacy': string;
232
209
  'chains.selector.noModelsStrict': string;
233
- 'mainAgent.label': string;
234
210
  'subagents.label': string;
235
- 'subagents.policy.label': string;
236
- 'subagents.policy.allowlist': string;
237
- 'subagents.policy.head': string;
238
- 'subagents.policy.source.authorized': string;
239
- 'subagents.policy.source.injected': string;
240
- 'subagents.policy.blocked': string;
241
- 'subagents.policy.unprovable': string;
242
- 'subagents.policy.offAllowlist': string;
243
- 'subagents.policy.recommend': string;
244
- 'subagents.policy.sync': string;
245
- 'subagents.policy.sync.done': string;
246
- 'subagents.policy.sync.failed': string;
247
- '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;
248
230
  'timeSlots.label': string;
249
231
  'timeSlots.hint': string;
250
232
  'timeSlots.tz.label': string;
@@ -293,7 +275,6 @@ export declare const en: {
293
275
  'allDay.nonconforming': string;
294
276
  'roles.list.label': string;
295
277
  'roles.list.hint': string;
296
- 'roles.list.tooltip': string;
297
278
  'roles.id': string;
298
279
  'roles.id.hint': string;
299
280
  'roles.idPlaceholder': string;
@@ -305,35 +286,23 @@ export declare const en: {
305
286
  'roles.seedSource.bundled': string;
306
287
  'roles.seedSource.external': string;
307
288
  'roles.seedSource.user': string;
308
- 'roles.seedChainOptional': string;
309
- 'roles.fallback': string;
310
- 'roles.fallback.inherit-root': string;
311
- '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;
312
294
  'roles.add': string;
313
295
  'roles.remove': string;
314
296
  'roles.expand': string;
315
297
  'roles.collapse': string;
316
- 'roles.selector.add': string;
317
- 'roles.rules': string;
318
- 'roles.rules.hint': string;
319
- 'roles.rules.tooltip': string;
320
- 'roles.rule.provider': string;
321
- 'roles.rule.provider.any': string;
322
- 'roles.rule.model': string;
323
- 'roles.rule.model.any': string;
324
- 'roles.rule.role': string;
325
- 'roles.rule.role.inherit': string;
326
- 'roles.rule.roleSelectPlaceholder': string;
327
- 'roles.rule.roleUndeclared.short': string;
328
- 'roles.addRule': string;
329
- 'roles.removeRule': string;
330
298
  'validation.blocked': string;
331
299
  'validation.roleIdFormat': string;
332
300
  'validation.roleIdReserved': string;
333
301
  'validation.roleIdDuplicate': string;
334
- 'validation.ruleRoleUndeclared': string;
335
- 'validation.ruleRoleRequired': string;
336
- 'validation.roleChainRequired': string;
302
+ 'validation.chainIdFormat': string;
303
+ 'validation.chainIdDuplicate': string;
304
+ 'validation.chainLabelRequired': string;
305
+ 'validation.chainEntriesRequired': string;
337
306
  'validation.allDayRequired': string;
338
307
  'validation.slotChainRequired': string;
339
308
  'validation.slotWindow': string;
@@ -351,24 +320,9 @@ export declare const en: {
351
320
  'catalog.outside.tooltip': string;
352
321
  'catalog.outside.short': string;
353
322
  'catalog.unconfigured.short': string;
354
- 'status.title': string;
355
- 'status.switches.label': string;
356
- 'status.switches.empty': string;
357
- 'status.switches.error': string;
358
- 'status.switches.compact': string;
359
- 'status.switches.compact.roleInject': string;
360
323
  'status.switches.reason.trigger-code': string;
361
324
  'status.switches.reason.always-cap': string;
362
325
  'status.switches.reason.role-inject': string;
363
- 'general.title': string;
364
- 'general.enabled': string;
365
- 'general.disabled': string;
366
- 'general.unknown': string;
367
- 'general.unavailable': string;
368
- 'general.switch': string;
369
- 'general.switch.roleInject': string;
370
- 'general.switch.empty': string;
371
- 'general.error': string;
372
326
  'chat.switch.title': string;
373
327
  'chat.switch.summary': string;
374
328
  'chat.switch.summary.roleInject': string;
@@ -392,8 +346,8 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
392
346
  }
393
347
  }
394
348
  /**
395
- * Reason → locale key map for switch summaries (S-c; shared by the card's
396
- * 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
397
351
  * reasons resolve from ONE key family (`status.switches.reason.*`) — the
398
352
  * shared reason vocabulary must not mix dictionary families (qc1 F-004). The
399
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,51 +85,45 @@ 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;
@@ -145,8 +133,8 @@ export interface FallbacksConfigSummary {
145
133
  /**
146
134
  * The session-scoped read-only operations the `/fallbacks` handler drives.
147
135
  * Implemented by the wiring (`src/index.ts`) against the live config source
148
- * (`roles.list` / `rootChain` — no chain map anymore) and the per-agent
149
- * 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.
150
138
  */
151
139
  export interface FallbacksCommandController {
152
140
  /** Snapshot the session's fallback diagnostics. Never mutates state. */
@@ -186,7 +174,6 @@ export declare const FALLBACKS_COMMAND_LOCALES: {
186
174
  readonly origin: "会话来源";
187
175
  readonly role: "角色";
188
176
  readonly chain: "链";
189
- readonly inheritRoot: "(inherit-root)";
190
177
  readonly chainNone: "未配置";
191
178
  readonly slot: "分时";
192
179
  readonly switches: "最近降级切换";
@@ -205,16 +192,16 @@ export declare const FALLBACKS_COMMAND_LOCALES: {
205
192
  readonly configEnabled: "已启用";
206
193
  readonly configDisabled: "未启用";
207
194
  readonly configTriggerCodes: "触发码";
208
- readonly configRootChain: "根链";
195
+ readonly configChains: "虚拟链";
209
196
  readonly configEmpty: "(空)";
210
- readonly configTimeSlots: "分时槽";
197
+ readonly configChainItem: "{id}({label}): {entries}|分时槽: {slots}";
211
198
  readonly configSlotPresetItem: "{preset}(chain: {n}, window {window})";
212
199
  readonly configSlotPresetBare: "{preset}(chain: {n})";
213
200
  readonly configSlotCustomItem: "custom {start}-{end}(chain: {n})";
214
201
  readonly configTz: "时区";
215
202
  readonly configRoles: "角色";
216
- readonly configRoleItem: "{id}(chain: {n})";
217
- readonly configRules: "角色规则";
203
+ readonly configRoleItem: "{id}(指定降级链: {chain})";
204
+ readonly configRoleUnspecified: "未指定(沿用 dsh 默认)";
218
205
  readonly configCooldown: "冷却";
219
206
  readonly configRevert: "回主策略";
220
207
  readonly configMaxSwitches: "单次请求行走最大切换";
@@ -239,7 +226,6 @@ export declare const FALLBACKS_COMMAND_LOCALES: {
239
226
  readonly origin: "Session origin";
240
227
  readonly role: "Role";
241
228
  readonly chain: "Chain";
242
- readonly inheritRoot: " (inherit-root)";
243
229
  readonly chainNone: "not configured";
244
230
  readonly slot: "Time slot";
245
231
  readonly switches: "Recent fallback switches";
@@ -258,16 +244,16 @@ export declare const FALLBACKS_COMMAND_LOCALES: {
258
244
  readonly configEnabled: "enabled";
259
245
  readonly configDisabled: "disabled";
260
246
  readonly configTriggerCodes: "Trigger codes";
261
- readonly configRootChain: "Root chain";
247
+ readonly configChains: "Chains";
262
248
  readonly configEmpty: "(empty)";
263
- readonly configTimeSlots: "Time slots";
249
+ readonly configChainItem: "{id} ({label}): {entries} | slots: {slots}";
264
250
  readonly configSlotPresetItem: "{preset} (chain: {n}, window {window})";
265
251
  readonly configSlotPresetBare: "{preset} (chain: {n})";
266
252
  readonly configSlotCustomItem: "custom {start}-{end} (chain: {n})";
267
253
  readonly configTz: "TZ";
268
254
  readonly configRoles: "Roles";
269
- readonly configRoleItem: "{id} (chain: {n})";
270
- readonly configRules: "Rules";
255
+ readonly configRoleItem: "{id} (specified chain: {chain})";
256
+ readonly configRoleUnspecified: "not specified (dsh default)";
271
257
  readonly configCooldown: "Cooldown";
272
258
  readonly configRevert: "Revert";
273
259
  readonly configMaxSwitches: "Max switches per request walk";
@@ -312,31 +298,6 @@ export declare function parseFallbacksSubcommand(rawInput: string): FallbacksSub
312
298
  * `SessionEventMap` type, and the durable log can outlive schema versions).
313
299
  */
314
300
  export declare function recentFallbacksSwitches(events: readonly unknown[], limit: number): FallbacksSwitchEventData[];
315
- /**
316
- * The chain entries `/fallbacks` shows for a role (spec §7.4): the declared
317
- * role's own chain when non-empty (`chainRole: true`); an empty own chain
318
- * defers to `rootChain` unless `fallback: 'none'` — then nothing is appended
319
- * and the display chain is empty, mirroring `resolveChainViews`'s
320
- * `[...[], ...[]]` exactly; undeclared ids and the built-in `'inherit'`
321
- * role resolve to `rootChain`. `inherit: true` marks the append-not-replace
322
- * tail — the role's `fallback` is `'inherit-root'` (the default) or the role
323
- * is unknown/built-in `'inherit'`, and `rootChain` is non-empty. Mirrors
324
- * `resolveChainViews`'s concatenation (see {@link roleChainEntries} —
325
- * `src/chains.ts`; the diagnostic keeps its display semantics: the role's
326
- * own chain renders in full, `rootChain` only when the role has no own
327
- * chain, with the inherit tail as an annotation) without a failing model to
328
- * resolve against (the diagnostic is model-independent).
329
- *
330
- * `warn` mirrors {@link resolveChainViews}' defensive unknown-role warn
331
- * (qc2 F-002 — routed through the injected logger; the `/fallbacks` path
332
- * never reaches here unsanitized, as {@link resolveRole} resolves to a
333
- * declared id or `'inherit'` first, so this is direct-caller parity).
334
- */
335
- export declare function resolveChainForDiagnostic(roles: readonly FallbacksRole[], rootChain: readonly string[], role: string, warn?: (message: string) => void): {
336
- readonly chainRole: boolean;
337
- readonly chain: readonly string[];
338
- readonly inherit: boolean;
339
- };
340
301
  /**
341
302
  * Cap for the composed-config readback's LIST lines — Trigger codes, Root
342
303
  * chain, Time slots, Roles, and Rules (qc2 Task-2 Minor): beyond this many
@@ -345,12 +306,13 @@ export declare function resolveChainForDiagnostic(roles: readonly FallbacksRole[
345
306
  */
346
307
  export declare const FALLBACKS_CONFIG_LIST_CAP = 5;
347
308
  /**
348
- * Render the `/fallbacks config` surface (plan fallbacks-tui-client T2,
349
- * AC-2 + fallbacks-tui-settings Task 2 AC-4): the composed `fallbacks`
350
- * namespace as the runtime reads it — enriched with the time-slot rows
351
- * (preset rows resolve their frozen window from {@link PRESETS}), the
352
- * config timezone, and the role rules — plus edit hints pointing at the
353
- * `/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.
354
316
  * The FIRST LINE marks the composed-config readback — distinct from the
355
317
  * diagnostic title and never merged into {@link fallbacksCommandText} (two
356
318
  * operator surfaces, product lock). Locale defaults to `zh` (the command
@@ -359,8 +321,10 @@ export declare const FALLBACKS_CONFIG_LIST_CAP = 5;
359
321
  export declare function fallbacksConfigText(summary: FallbacksConfigSummary, locale?: FallbacksCommandLocale): string;
360
322
  /**
361
323
  * Render the `/fallbacks` status surface for one snapshot. Kept minimal and
362
- * truthful: origin → role → chain (+ inherit tail) → current slot (分时) →
363
- * 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.
364
328
  */
365
329
  export declare function fallbacksCommandText(snapshot: FallbacksCommandSnapshot, locale?: FallbacksCommandLocale): string;
366
330
  /**
@@ -371,3 +335,4 @@ export declare function fallbacksCommandText(snapshot: FallbacksCommandSnapshot,
371
335
  * @returns the registry disposer (the inject child owns its lifetime).
372
336
  */
373
337
  export declare function registerFallbacksCommands(registry: FallbacksCommandRegistry, controller: FallbacksCommandController, locale?: FallbacksCommandLocale): () => void;
338
+ export {};