@askdkc/dsh-cli 0.12.3 → 0.13.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.
Files changed (162) hide show
  1. package/cordis.patch.yml +12 -131
  2. package/lib/types/adapter/channel/session-projection.d.ts.map +1 -1
  3. package/lib/types/adapter/channel/session-projection.js +0 -7
  4. package/lib/types/adapter/ports/channel-view.d.ts +1 -1
  5. package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
  6. package/lib/types/dsh-adapter/bundled-presets.d.ts +3 -8
  7. package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -1
  8. package/lib/types/dsh-adapter/bundled-presets.js +5 -20
  9. package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
  10. package/lib/types/dsh-adapter/channel/binding-events.js +2 -9
  11. package/lib/types/dsh-adapter/channel/external-commands.d.ts.map +1 -1
  12. package/lib/types/dsh-adapter/channel/external-commands.js +9 -33
  13. package/lib/types/dsh-adapter/channel/local-actions.d.ts +2 -1
  14. package/lib/types/dsh-adapter/channel/local-actions.d.ts.map +1 -1
  15. package/lib/types/dsh-adapter/channel/local-actions.js +6 -2
  16. package/lib/types/dsh-adapter/channel/model-actions.js +3 -3
  17. package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
  18. package/lib/types/dsh-adapter/channel/model-switch.js +0 -1
  19. package/lib/types/dsh-adapter/channel/permissions.d.ts +1 -6
  20. package/lib/types/dsh-adapter/channel/permissions.d.ts.map +1 -1
  21. package/lib/types/dsh-adapter/channel/permissions.js +2 -54
  22. package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
  23. package/lib/types/dsh-adapter/channel/projection.js +15 -70
  24. package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
  25. package/lib/types/dsh-adapter/channel/session-fork.js +0 -1
  26. package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
  27. package/lib/types/dsh-adapter/channel/session-metadata.js +1 -4
  28. package/lib/types/dsh-adapter/channel/session-resume.js +2 -2
  29. package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
  30. package/lib/types/dsh-adapter/channel/session-rewind.js +0 -1
  31. package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
  32. package/lib/types/dsh-adapter/channel/session-tree-actions.js +1 -2
  33. package/lib/types/dsh-adapter/channel/session-tree.d.ts.map +1 -1
  34. package/lib/types/dsh-adapter/channel/session-tree.js +9 -62
  35. package/lib/types/dsh-adapter/channel/skill-catalog.js +1 -1
  36. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
  37. package/lib/types/dsh-adapter/channel/subagent-projection.js +2 -8
  38. package/lib/types/dsh-adapter/channel/transcript.d.ts +0 -16
  39. package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
  40. package/lib/types/dsh-adapter/channel/transcript.js +0 -43
  41. package/lib/types/dsh-adapter/channel.js +2 -2
  42. package/lib/types/dsh-adapter/compat/index.d.ts +5 -25
  43. package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -1
  44. package/lib/types/dsh-adapter/compat/index.js +5 -25
  45. package/lib/types/dsh-adapter/compat/liveSession.d.ts +12 -23
  46. package/lib/types/dsh-adapter/compat/liveSession.d.ts.map +1 -1
  47. package/lib/types/dsh-adapter/compat/liveSession.js +15 -68
  48. package/lib/types/dsh-adapter/compat/messages.d.ts +1 -3
  49. package/lib/types/dsh-adapter/compat/messages.d.ts.map +1 -1
  50. package/lib/types/dsh-adapter/compat/messages.js +2 -10
  51. package/lib/types/dsh-adapter/compat/persistence.d.ts +2 -3
  52. package/lib/types/dsh-adapter/compat/persistence.d.ts.map +1 -1
  53. package/lib/types/dsh-adapter/compat/persistence.js +9 -14
  54. package/lib/types/dsh-adapter/compat/sessionLog.d.ts +10 -144
  55. package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -1
  56. package/lib/types/dsh-adapter/compat/sessionLog.js +45 -275
  57. package/lib/types/dsh-adapter/compat/settings.d.ts +4 -10
  58. package/lib/types/dsh-adapter/compat/settings.d.ts.map +1 -1
  59. package/lib/types/dsh-adapter/compat/settings.js +6 -23
  60. package/lib/types/dsh-adapter/compat/shell.d.ts +2 -3
  61. package/lib/types/dsh-adapter/compat/shell.d.ts.map +1 -1
  62. package/lib/types/dsh-adapter/compat/shell.js +2 -7
  63. package/lib/types/dsh-adapter/contract.d.ts +4 -34
  64. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  65. package/lib/types/dsh-adapter/contract.js +8 -83
  66. package/lib/types/dsh-adapter/packaged-presets.d.ts +0 -19
  67. package/lib/types/dsh-adapter/packaged-presets.d.ts.map +1 -1
  68. package/lib/types/dsh-adapter/packaged-presets.js +1 -83
  69. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  70. package/lib/types/dsh-adapter/plugin.js +25 -168
  71. package/lib/types/dsh-adapter/preset-resolution.d.ts +1 -22
  72. package/lib/types/dsh-adapter/preset-resolution.d.ts.map +1 -1
  73. package/lib/types/dsh-adapter/preset-resolution.js +0 -34
  74. package/lib/types/dsh-adapter/presets.d.ts +1 -4
  75. package/lib/types/dsh-adapter/presets.d.ts.map +1 -1
  76. package/lib/types/dsh-adapter/presets.js +3 -6
  77. package/lib/types/dsh-adapter/questions-answerer.d.ts +5 -43
  78. package/lib/types/dsh-adapter/questions-answerer.d.ts.map +1 -1
  79. package/lib/types/dsh-adapter/questions-answerer.js +7 -63
  80. package/lib/types/dsh-adapter/sessionTree.d.ts +0 -19
  81. package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -1
  82. package/lib/types/dsh-adapter/sessionTree.js +2 -112
  83. package/lib/types/dsh-adapter/sessions/header.d.ts +2 -2
  84. package/lib/types/dsh-adapter/sessions/header.d.ts.map +1 -1
  85. package/lib/types/dsh-adapter/sessions/header.js +2 -8
  86. package/lib/types/dsh-adapter/sessions/list.d.ts +7 -28
  87. package/lib/types/dsh-adapter/sessions/list.d.ts.map +1 -1
  88. package/lib/types/dsh-adapter/sessions/list.js +48 -103
  89. package/lib/types/dsh-adapter/sessions/store.d.ts +1 -2
  90. package/lib/types/dsh-adapter/sessions/store.d.ts.map +1 -1
  91. package/lib/types/dsh-adapter/sessions/store.js +7 -10
  92. package/lib/types/dsh-adapter/sharp.d.ts.map +1 -1
  93. package/lib/types/dsh-adapter/sharp.js +0 -1
  94. package/lib/types/dsh-adapter/subagents.d.ts +1 -2
  95. package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
  96. package/lib/types/dsh-adapter/subagents.js +1 -12
  97. package/lib/types/dsh-adapter/trajectory/aggregate.d.ts +1 -1
  98. package/lib/types/dsh-adapter/trajectory/aggregate.js +1 -1
  99. package/lib/types/dsh-adapter/trajectory/guards.d.ts +5 -22
  100. package/lib/types/dsh-adapter/trajectory/guards.d.ts.map +1 -1
  101. package/lib/types/dsh-adapter/trajectory/guards.js +5 -23
  102. package/lib/types/dsh-adapter/trajectory/projection.d.ts +5 -21
  103. package/lib/types/dsh-adapter/trajectory/projection.d.ts.map +1 -1
  104. package/lib/types/dsh-adapter/trajectory/projection.js +4 -38
  105. package/lib/types/dsh-adapter/trajectory/types.d.ts +1 -1
  106. package/lib/types/dsh-adapter/trajectory/types.d.ts.map +1 -1
  107. package/lib/types/i18n.d.ts +2 -22
  108. package/lib/types/i18n.d.ts.map +1 -1
  109. package/lib/types/i18n.js +2 -10
  110. package/lib/types/presetPrefs.d.ts +1 -3
  111. package/lib/types/presetPrefs.d.ts.map +1 -1
  112. package/lib/types/presetPrefs.js +2 -4
  113. package/node_modules/@askdkc/dsh-auth/README.ja.md +28 -9
  114. package/node_modules/@askdkc/dsh-auth/README.md +19 -8
  115. package/node_modules/@askdkc/dsh-auth/dsh-plugin.json +3 -3
  116. package/node_modules/@askdkc/dsh-auth/lib/THIRD_PARTY_NOTICES.txt +168 -0
  117. package/node_modules/@askdkc/dsh-auth/lib/abortable.d.ts +2 -0
  118. package/node_modules/@askdkc/dsh-auth/lib/abortable.js +9 -0
  119. package/node_modules/@askdkc/dsh-auth/lib/auth-contract.d.ts +66 -0
  120. package/node_modules/@askdkc/dsh-auth/lib/auth-contract.js +1 -0
  121. package/node_modules/@askdkc/dsh-auth/lib/command.js +15 -1
  122. package/node_modules/@askdkc/dsh-auth/lib/credentials.d.ts +8 -14
  123. package/node_modules/@askdkc/dsh-auth/lib/credentials.js +1 -1
  124. package/node_modules/@askdkc/dsh-auth/lib/index.d.ts +8 -28
  125. package/node_modules/@askdkc/dsh-auth/lib/index.js +67 -65
  126. package/node_modules/@askdkc/dsh-auth/lib/interaction.d.ts +5 -5
  127. package/node_modules/@askdkc/dsh-auth/lib/opencode-adapter.d.ts +37 -0
  128. package/node_modules/@askdkc/dsh-auth/lib/opencode-adapter.js +197 -0
  129. package/node_modules/@askdkc/dsh-auth/lib/opencode-catalog.d.ts +72 -0
  130. package/node_modules/@askdkc/dsh-auth/lib/opencode-catalog.js +252 -0
  131. package/node_modules/@askdkc/dsh-auth/lib/opencode-codec.d.ts +6 -0
  132. package/node_modules/@askdkc/dsh-auth/lib/opencode-codec.js +93 -0
  133. package/node_modules/@askdkc/dsh-auth/lib/opencode-owned.generated.d.ts +113 -0
  134. package/node_modules/@askdkc/dsh-auth/lib/opencode-owned.generated.js +2866 -0
  135. package/node_modules/@askdkc/dsh-auth/lib/opencode-replay.d.ts +15 -0
  136. package/node_modules/@askdkc/dsh-auth/lib/opencode-replay.js +141 -0
  137. package/node_modules/@askdkc/dsh-auth/lib/opencode-sdk.d.ts +5 -0
  138. package/node_modules/@askdkc/dsh-auth/lib/opencode-sdk.js +43465 -0
  139. package/node_modules/@askdkc/dsh-auth/lib/opencode-sdk.js.map +7 -0
  140. package/node_modules/@askdkc/dsh-auth/lib/opencode-transport.d.ts +5 -0
  141. package/node_modules/@askdkc/dsh-auth/lib/opencode-transport.js +69 -0
  142. package/node_modules/@askdkc/dsh-auth/lib/pi-routes.d.ts +32 -0
  143. package/node_modules/@askdkc/dsh-auth/lib/pi-routes.js +45 -0
  144. package/node_modules/@askdkc/dsh-auth/lib/profiles.d.ts +2 -20
  145. package/node_modules/@askdkc/dsh-auth/lib/profiles.js +6 -41
  146. package/node_modules/@askdkc/dsh-auth/lib/routes.d.ts +20 -0
  147. package/node_modules/@askdkc/dsh-auth/lib/routes.js +13 -0
  148. package/node_modules/@askdkc/dsh-auth/lib/service.d.ts +11 -2
  149. package/node_modules/@askdkc/dsh-auth/lib/service.js +26 -16
  150. package/node_modules/@askdkc/dsh-auth/package.json +26 -15
  151. package/package.json +100 -96
  152. package/lib/types/dsh-adapter/providerGuard.d.ts +0 -75
  153. package/lib/types/dsh-adapter/providerGuard.d.ts.map +0 -1
  154. package/lib/types/dsh-adapter/providerGuard.js +0 -104
  155. package/lib/types/migrationPrefs.d.ts +0 -60
  156. package/lib/types/migrationPrefs.d.ts.map +0 -1
  157. package/lib/types/migrationPrefs.js +0 -97
  158. package/node_modules/@askdkc/dsh-auth/lib/fresh-models.d.ts +0 -59
  159. package/node_modules/@askdkc/dsh-auth/lib/fresh-models.js +0 -246
  160. package/node_modules/@askdkc/dsh-auth/lib/opencode-snapshot.generated.d.ts +0 -321
  161. package/node_modules/@askdkc/dsh-auth/lib/opencode-snapshot.generated.js +0 -528
  162. package/presets/liangshen/.dsh-tui-managed.json +0 -5
@@ -3,7 +3,6 @@ import React from 'react';
3
3
  import { SessionId } from '@deepseek-ai/dsh-session';
4
4
  import UserQuestionService from '@deepseek-ai/dsh-user-questions';
5
5
  import * as toolAskUser from '@deepseek-ai/dsh-tool-ask-user';
6
- import Schema from '@deepseek-ai/schemastery';
7
6
  import { Config } from './index.js';
8
7
  import { configValues, createSettingsScope, resolveSettingsNamespace } from './compat/settings.js';
9
8
  import { createChannel } from './channel.js';
@@ -16,26 +15,24 @@ import { removeClipboardImageDir } from '../utils/clipboard.js';
16
15
  import { logForDebugging } from '../utils/debug.js';
17
16
  import { isEnvTruthy } from '../utils/envUtils.js';
18
17
  import { QuestionStore, bindQuestionStore } from './questions.js';
19
- import { prepareQuestionAnswerer } from './questions-answerer.js';
18
+ import { registerQuestionAnswerer } from './questions-answerer.js';
20
19
  import { adapterRuntimeFor } from '../adapter/kernel/runtime-context.js';
21
20
  import { ApprovalStore, bindApprovalStore } from './approvals.js';
22
21
  import { registerPromptDebug } from './promptDebug.js';
23
22
  import { readActivityFrames } from '../activityPrefs.js';
24
- import { commitFullscreenFactoryMigration, planFullscreenFactoryMigration, readAppliedMigrations } from '../migrationPrefs.js';
25
23
  import { readModelPref } from '../modelPrefs.js';
26
24
  import { explicitModelRoute, recordedModelRoute, resolveModelRoute, validateModelRoute } from '../modelRoute.js';
27
25
  import { migratePresetPref, readPresetPref } from '../presetPrefs.js';
28
26
  import { readEffortPref } from '../effortPrefs.js';
29
27
  import { composePreset, filterMinimalPresetTools, resolvePersistedPreset, resolvePersistedRoute, runningPresetOf } from './presets.js';
30
- import { ensurePackagedPresets } from './packaged-presets.js';
31
28
  import { registerBundledPresets } from './bundled-presets.js';
32
- import { ensureLegacySessionEventTypes, snapshotLiveSessionEvents } from './compat/index.js';
29
+ import { registerTuiSessionEventTypes, snapshotLiveSessionEvents } from './compat/index.js';
33
30
  import { clearResumeTarget, resumeTargetFromArgv, writeResumeTarget } from '../sessionHistory.js';
34
31
  import { readHomePrefs } from '../homePrefs.js';
35
32
  import { resolveSessionCwd } from '../utils/workspaceRoot.js';
36
33
  import { beginRestartAttempt, checkForTuiUpdate, installedTuiVersion, isBootDeadlockTarget, isStandaloneRuntime, isVersionNewer, logRestartEvent, resolveDshProfileName, resolveTuiUpdateTarget, restartTui, updateTuiAndRestart, writeHandoffNotice } from '../update.js';
37
34
  import { getLang, isLang, resolveStartupLang, setLang, t, writeLangPref } from '../i18n.js';
38
- import { DEFAULT_PAGE_MARGIN, DEFAULT_STATUS_BAR, applyMermaidDiagrams, applyPageMargin, isPageMarginMode, normalizePageMargin, normalizeScrollGutter, normalizeStatusBar, normalizeToolBackground, parsePageMarginSpec } from '../tuiDisplayPrefs.js';
35
+ import { DEFAULT_PAGE_MARGIN, applyMermaidDiagrams, applyPageMargin, isPageMarginMode, normalizePageMargin, normalizeScrollGutter, normalizeStatusBar, normalizeToolBackground, parsePageMarginSpec } from '../tuiDisplayPrefs.js';
39
36
  import { draftComboConflicts, effectiveComboString, parseComboDraft, setKeymapOverrides, SHORTCUT_ACTIONS, } from '../utils/keymap.js';
40
37
  import { attachHerdrIntegration } from '../herdr.js';
41
38
  import { logMouseDebug } from '../utils/debug.js';
@@ -73,7 +70,7 @@ import { CLEAR_ITERM2_PROGRESS, CLEAR_TAB_STATUS, supportsTabStatus, wrapForMult
73
70
  * Fullscreen decision latched across host recomposes. The launcher disposes
74
71
  * and re-mounts the plugin tree (teardown → apply() runs again) — a fresh
75
72
  * apply() re-resolves `bootedFullscreen` from cordis config, and the
76
- * settings user layer (settings.yaml) can arrive after the 300ms
73
+ * profile configuration can arrive after the 300ms
77
74
  * `settingsReady` bound when the recompose is also re-mounting the settings
78
75
  * service. The tree would then mount INLINE and `rendererSettingsFrozen` would
79
76
  * swallow the late application — the app lands on the main screen
@@ -189,23 +186,9 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
189
186
  }
190
187
  // Validate settings before creating an agent or taking over the terminal.
191
188
  const tuiSettingsNs = resolveSettingsNamespace(configOwner, Config);
192
- // Modern hosts own a declarative registry; old hosts discover directories.
193
- // A modern bundle failure must not silently fall back to obsolete files.
194
- if (!await registerBundledPresets(ctx))
195
- try {
196
- for (const result of ensurePackagedPresets()) {
197
- if (result.status === 'conflict') {
198
- ctx.logger.warn(`dsh-tui: packaged preset "${result.id}" was not installed because an unmanaged preset already uses that id`);
199
- }
200
- }
201
- }
202
- catch (error) {
203
- // A read-only home must not make the whole terminal unusable; the other
204
- // official and user presets remain available.
205
- ctx.logger.warn(`dsh-tui: unable to install packaged presets (${error instanceof Error ? error.message : String(error)})`);
206
- }
189
+ await registerBundledPresets(ctx);
207
190
  // UI language resolution: DSH_TUI_LANG env var wins, then the
208
- // settings.yaml `dsh-tui.lang` user layer (applied once the settings
191
+ // active profile `dsh-tui.lang` configuration (applied once the settings
209
192
  // namespace registers below), then cordis.yml `lang`, then the
210
193
  // persisted `/lang` choice, then `zh`. Must settle before the first
211
194
  // render so every module resolves strings in the same language.
@@ -269,10 +252,8 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
269
252
  // service when the composition doesn't (the official dsh-base
270
253
  // user-interaction config row does; a bare plugin mount creates it on
271
254
  // this context), then expose the model-facing tool before resolving the
272
- // agent so per-step assembly includes ask_user_question. rc.2's provider
273
- // seat is registered below; the 0.1.2 line's agent-aware waterfall needs the
274
- // channel owner and is therefore registered immediately after the channel
275
- // is created. Optional-service access goes through `ctx.get`, not the
255
+ // agent so per-step assembly includes ask_user_question. The answerer needs
256
+ // the channel owner and registers immediately after channel creation. Optional-service access goes through `ctx.get`, not the
276
257
  // inject proxy.
277
258
  const userQuestions = ctx.get('userQuestions') ?? new UserQuestionService(ctx);
278
259
  ctx.plugin(toolAskUser);
@@ -288,31 +269,11 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
288
269
  });
289
270
  const questionStore = new QuestionStore(adapterRuntimeFor(ctx));
290
271
  bindQuestionStore(ctx, questionStore);
291
- // One store, one teardown effect on both API lines. The compatibility
292
- // adapter binds either registration to this Cordis fiber; this separate
293
- // effect rejects asks still parked in the UI during teardown.
272
+ // Reject questions still parked in the UI when its fiber is disposed.
294
273
  ctx.effect(() => () => questionStore.rejectAll());
295
274
  // `/debug-prompt` snapshots the final provider-neutral request at the
296
275
  // llm/stream boundary, after every prompt and tool contributor has run.
297
276
  registerPromptDebug(ctx);
298
- // API selection and registration live behind one adapter boundary. The UI
299
- // bootstrap only translates a legacy seat conflict into its visible notice.
300
- const questionAnswererRegistration = prepareQuestionAnswerer(ctx, userQuestions, questionStore);
301
- const questionSeatDecision = questionAnswererRegistration.kind === 'legacy'
302
- ? questionAnswererRegistration.yieldDecision
303
- : undefined;
304
- let questionSeatNotice;
305
- if (questionSeatDecision?.action === 'alert-unverified') {
306
- ctx.logger.error(`dsh-tui: user-questions provider seat is held by a component self-reporting as ${questionSeatDecision.incumbentId} ` +
307
- '(identity not host-verified); this TUI will not register its questionnaire and model questions may be answered by it');
308
- questionSeatNotice = t('question-provider-occupied-unverified', { id: questionSeatDecision.incumbentId ?? '' });
309
- }
310
- else if (questionSeatDecision?.action === 'alert') {
311
- const displayId = questionSeatDecision.incumbentId ?? t('question-provider-occupied-unknown');
312
- ctx.logger.error(`dsh-tui: user-questions provider seat is held by a non-host component (${displayId}); ` +
313
- 'this TUI will not register its questionnaire and model questions may be answered by it');
314
- questionSeatNotice = t('question-provider-occupied', { id: displayId });
315
- }
316
277
  // Child-process stderr guard (issue #17): MCP servers spawned with an
317
278
  // inherited stderr (the MCP SDK's stdio default) write straight to the
318
279
  // terminal device from the child process, bypassing the renderer's own
@@ -550,11 +511,7 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
550
511
  toastStore?.setSink(delivery => {
551
512
  notifyChannel(delivery.text, { color: delivery.color, timeoutMs: delivery.timeoutMs });
552
513
  });
553
- if (questionAnswererRegistration.kind === 'waterfall') {
554
- // Ownership follows the mutable channel; registration cleanup belongs to
555
- // this Cordis fiber.
556
- questionAnswererRegistration.register(channel);
557
- }
514
+ registerQuestionAnswerer(ctx, channel, questionStore);
558
515
  // Fullscreen layout decision: the settings user layer (edited through the
559
516
  // /settings screen) overrides cordis.yml when set. The settings injection
560
517
  // below resolves it synchronously when the host settings service is up —
@@ -578,81 +535,10 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
578
535
  resolveSettingsReady = () => resolve();
579
536
  setTimeout(resolve, 300);
580
537
  });
581
- // Old hosts register a settings.yaml scope. 0.1.7 projects the plugin's
582
- // volatile Config fields instead; both paths apply edits without remounting.
538
+ // Apply volatile Config edits without remounting the agent.
583
539
  ctx.inject(['settings'], (settingsCtx) => {
584
540
  // Loader targets the Config owner's fiber, not the injected child fiber.
585
- const scope = createSettingsScope(configOwner, settingsCtx.settings, tuiSettingsNs, Schema.object({
586
- diffLayout: Schema.union(['auto', 'split', 'unified']).default('auto'),
587
- thinkingFold: Schema.union(['preview', 'full']).default('preview'),
588
- toolBackground: Schema.union(['none', 'subtle', 'strong']).default('none'),
589
- scrollGutter: Schema.union(['timeline', 'scrollbar', 'hidden']).default('timeline'),
590
- // Preset names AND custom `NxM` specs (the settings field's parse
591
- // gate keeps junk out of the user layer; the transform normalizes
592
- // whatever survives — cordis.yml junk included).
593
- pageMargin: Schema.transform(Schema.string().default('normal'), value => normalizePageMargin(value)),
594
- // No default on purpose (same rule as `fullscreen` below): a schema
595
- // default here would come back from scope.get()/watch() and shadow
596
- // an explicit cordis.yml `foldTerminalCommand: true` while the
597
- // settings user layer is unset — applyDisplay's
598
- // `?? config.foldTerminalCommand ?? false` already supplies the
599
- // default and keeps cordis.yml decisive.
600
- foldTerminalCommand: Schema.boolean(),
601
- promptSessionLabel: Schema.boolean().default(false),
602
- // No schema default (same rule as foldTerminalCommand): applyDisplay
603
- // resolves `?? config.expandEditor ?? true` so cordis.yml stays
604
- // decisive while the user layer is unset.
605
- expandEditor: Schema.boolean(),
606
- // Same no-default rule: applyDisplay resolves `?? config.smoothStreaming ?? true`.
607
- smoothStreaming: Schema.boolean(),
608
- // Same no-default rule: applyDisplay resolves `?? config.mermaidDiagrams ?? true`.
609
- mermaidDiagrams: Schema.boolean(),
610
- // No default on purpose: unset keeps the boot chain decisive
611
- // (applyEffortDefault hands `undefined` to channel.setDefaultEffort,
612
- // which resolves cordis.yml `effort` → effort.json → adapter default).
613
- effortDefault: Schema.string(),
614
- statusBar: Schema.object({
615
- compact: Schema.boolean().default(DEFAULT_STATUS_BAR.compact),
616
- model: Schema.boolean().default(DEFAULT_STATUS_BAR.model),
617
- thinking: Schema.boolean().default(DEFAULT_STATUS_BAR.thinking),
618
- cwd: Schema.boolean().default(DEFAULT_STATUS_BAR.cwd),
619
- contextUsage: Schema.boolean().default(DEFAULT_STATUS_BAR.contextUsage),
620
- cache: Schema.boolean().default(DEFAULT_STATUS_BAR.cache),
621
- tokens: Schema.boolean().default(DEFAULT_STATUS_BAR.tokens),
622
- tps: Schema.boolean().default(DEFAULT_STATUS_BAR.tps),
623
- gitBranch: Schema.boolean().default(DEFAULT_STATUS_BAR.gitBranch),
624
- sessionTitle: Schema.boolean().default(DEFAULT_STATUS_BAR.sessionTitle),
625
- sessionId: Schema.boolean().default(DEFAULT_STATUS_BAR.sessionId),
626
- goal: Schema.boolean().default(DEFAULT_STATUS_BAR.goal),
627
- mode: Schema.boolean().default(DEFAULT_STATUS_BAR.mode),
628
- contextBar: Schema.boolean().default(DEFAULT_STATUS_BAR.contextBar),
629
- activity: Schema.boolean().default(DEFAULT_STATUS_BAR.activity),
630
- trajectory: Schema.boolean().default(DEFAULT_STATUS_BAR.trajectory),
631
- shortcutHint: Schema.boolean().default(DEFAULT_STATUS_BAR.shortcutHint),
632
- }).default({ ...DEFAULT_STATUS_BAR }),
633
- // Header pixel whale art; on unless settings.yaml says otherwise.
634
- whale: Schema.boolean().default(true),
635
- // Idle whale behaviors after the intro settles; on by default —
636
- // the idle-wakeup gate stays: an explicit `false` keeps the settled
637
- // header timer-free.
638
- whaleIdle: Schema.boolean().default(true),
639
- // Minimal mode: strips the header splash, emoji glyphs, and
640
- // decorative colors; code highlight and tool colors stay.
641
- minimal: Schema.boolean().default(false),
642
- // No default on purpose: an unset `lang` keeps the field showing
643
- // the effective language (see the section's format below) and lets
644
- // cordis.yml / lang.json keep their precedence.
645
- lang: Schema.union(['zh', 'en']),
646
- // Same no-default rule: unset keeps cordis.yml's `fullscreen`
647
- // decisive; set overrides it from the next boot on.
648
- fullscreen: Schema.boolean(),
649
- // Unset inherits cordis.yml; a saved choice takes effect after restart.
650
- terminalImages: Schema.boolean(),
651
- // Built-in action-shortcut overrides, one optional combo string per
652
- // action (see the keymap utility). Unset keeps the default binding
653
- // and the section's format() shows the effective combos.
654
- shortcuts: Schema.object(Object.fromEntries(SHORTCUT_ACTIONS.map(action => [action.id, Schema.string().required(false)]))).required(false),
655
- }), () => {
541
+ const scope = createSettingsScope(configOwner, () => {
656
542
  const current = configValues(runtimeConfig);
657
543
  return { ...current, lang: isLang(current.lang) ? current.lang : undefined };
658
544
  });
@@ -715,19 +601,16 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
715
601
  applyMermaidDiagrams(value.mermaidDiagrams ?? config.mermaidDiagrams);
716
602
  channel.setStatusBar(normalizeStatusBar(value.statusBar ?? config.statusBar));
717
603
  };
718
- // Legacy user scopes layer over cordis.yml. Modern Config is already
719
- // resolved: an unset action must not revive its startup override.
604
+ // Config is already resolved: an unset action must not revive its startup override.
720
605
  // Applied live so the very next keypress matches the new combos.
721
606
  const applyShortcuts = (value) => {
722
607
  const userLayer = value.shortcuts ?? {};
723
- const configLayer = scope.legacy ? config.shortcuts ?? {} : {};
724
608
  const merged = {};
725
609
  for (const action of SHORTCUT_ACTIONS) {
726
610
  const user = userLayer[action.id];
727
- const pinned = configLayer[action.id];
728
611
  const chosen = typeof user === 'string' && user.trim() !== ''
729
612
  ? user
730
- : (typeof pinned === 'string' && pinned.trim() !== '' ? pinned : undefined);
613
+ : undefined;
731
614
  if (chosen !== undefined)
732
615
  merged[action.id] = chosen;
733
616
  }
@@ -758,30 +641,8 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
758
641
  applyShortcuts(next);
759
642
  applyRendererSettings(next);
760
643
  };
761
- // One-time fullscreen factory-default migration (companion to the
762
- // schema + cordis.patch.yml flip false→true): a `fullscreen: false`
763
- // pinned in the settings user layer BEFORE the flip keeps overriding
764
- // the new default on every boot. The first boot past this code clears
765
- // that stale explicit choice; the migrations.json marker makes it
766
- // strictly once, so a `false` re-pinned afterwards always stands. The
767
- // boot decision cannot wait for the async doc write — the stale value
768
- // is shadowed out of the first apply below (destructuring omission,
769
- // not an explicit undefined), and the later watch commit (fullscreen
770
- // back to undefined) leaves the fullscreen decision unchanged.
771
644
  const bootSettings = scope.get();
772
- // The old migration applies only to the separate user layer. A modern
773
- // profile's explicit inline Config must never be mistaken for that layer.
774
- const fullscreenMigration = scope.legacy
775
- ? planFullscreenFactoryMigration(bootSettings.fullscreen, readAppliedMigrations())
776
- : 'done';
777
- void commitFullscreenFactoryMigration(fullscreenMigration, {
778
- unset: () => settingsCtx.settings.mutate(tuiSettingsNs, [{ op: 'unset', path: ['fullscreen'] }]),
779
- });
780
- if (fullscreenMigration === 'unset') {
781
- notifyChannel(t('settings-fullscreen-migrated'), { color: 'warning' });
782
- }
783
- const { fullscreen: staleFullscreen, ...migratedSettings } = bootSettings;
784
- apply(fullscreenMigration === 'unset' ? migratedSettings : bootSettings);
645
+ apply(bootSettings);
785
646
  let lastTerminalImages = bootSettings.terminalImages ?? config.terminalImages ?? true;
786
647
  settingsCtx.effect(() => scope.watch(next => {
787
648
  apply(next);
@@ -934,7 +795,7 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
934
795
  { value: 'en', label: 'English', descriptions: { zh: '英文' } },
935
796
  ],
936
797
  format(value) {
937
- // Unset in settings.yaml: show the effective UI language
798
+ // Unset in profile configuration: show the effective UI language
938
799
  // (env / cordis.yml / lang.json resolution) instead of a
939
800
  // blank "unset" that hides the current choice.
940
801
  return value === undefined || value === null ? getLang() : String(value);
@@ -951,7 +812,7 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
951
812
  hintDescriptions: { zh: '开启:接管整个终端(同 vim/less),应用内鼠标;关闭:终端原生滚动选择;整屏页两种模式都有鼠标。重启生效。' },
952
813
  kind: 'boolean',
953
814
  format(value) {
954
- // Unset in settings.yaml: show what THIS session booted with
815
+ // Unset in profile configuration: show what THIS session booted with
955
816
  // (the cordis.yml resolution) instead of a misleading false.
956
817
  return value === undefined || value === null ? String(bootedFullscreen) : String(value);
957
818
  },
@@ -1060,7 +921,7 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
1060
921
  hintDescriptions: { zh: '终端卡(Bash/PowerShell):多行命令头部折叠为首行 + 计数;Ctrl+O 或点击卡片展开。' },
1061
922
  kind: 'boolean',
1062
923
  format(value) {
1063
- // Unset in settings.yaml: show the effective resolution (cordis.yml
924
+ // Unset in profile configuration: show the effective resolution (cordis.yml
1064
925
  // → off) instead of a blank — same rule as `fullscreen`'s field.
1065
926
  return String(typeof value === 'boolean' ? value : config.foldTerminalCommand === true);
1066
927
  },
@@ -1081,7 +942,7 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
1081
942
  hintDescriptions: { zh: '开启:输入行尾 ⛶ 按钮与全屏编辑快捷键(默认 Ctrl+Shift+E)把草稿展开成整屏编辑器(Enter 换行、Ctrl+Enter 发送)。关闭:两个入口都不显示。默认开启。' },
1082
943
  kind: 'boolean',
1083
944
  format(value) {
1084
- // Unset in settings.yaml: the effective default is on.
945
+ // Unset in profile configuration: the effective default is on.
1085
946
  return String(typeof value === 'boolean' ? value : config.expandEditor !== false);
1086
947
  },
1087
948
  },
@@ -1093,7 +954,7 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
1093
954
  hintDescriptions: { zh: '把实时回复、展开的思考与工具卡正文按 ~30fps 匀速揭示,不再随供应商突发一跳一跳;一次性到达的非流式回复也会平滑打出。回放/历史内容始终完整直出。默认开启。' },
1094
955
  kind: 'boolean',
1095
956
  format(value) {
1096
- // Unset in settings.yaml: the effective default is on.
957
+ // Unset in profile configuration: the effective default is on.
1097
958
  return String(typeof value === 'boolean' ? value : config.smoothStreaming !== false);
1098
959
  },
1099
960
  },
@@ -1105,7 +966,7 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
1105
966
  hintDescriptions: { zh: '把回复中的 ```mermaid 代码块画成字符图(flowchart、sequence、state、class、ER、pie、mindmap、timeline、gitGraph)。比终端宽或类型不支持的图保留源码。立即生效。默认开启。' },
1106
967
  kind: 'boolean',
1107
968
  format(value) {
1108
- // Unset in settings.yaml: the effective default is on.
969
+ // Unset in profile configuration: the effective default is on.
1109
970
  return String(typeof value === 'boolean' ? value : config.mermaidDiagrams !== false);
1110
971
  },
1111
972
  },
@@ -1117,7 +978,7 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
1117
978
  hintDescriptions: { zh: '开启:打开/恢复会话时自动把最近活动总结成一行灰字显示在会话底部(可悬停/点击查看或应用建议标题);关闭:手动使用 /recap。' },
1118
979
  kind: 'boolean',
1119
980
  format(value) {
1120
- // Unset in settings.yaml: the default is on.
981
+ // Unset in profile configuration: the default is on.
1121
982
  return value === undefined || value === null ? 'true' : String(value);
1122
983
  },
1123
984
  },
@@ -1136,7 +997,7 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
1136
997
  { value: 'max', label: 'Max', descriptions: { zh: '最高' } },
1137
998
  ],
1138
999
  format(value) {
1139
- // Unset in settings.yaml: show what a boot would actually start
1000
+ // Unset in profile configuration: show what a boot would actually start
1140
1001
  // on (the cordis effort pin → the persisted /effort choice)
1141
1002
  // instead of a misleading blank.
1142
1003
  if (value === undefined || value === null || value === 'auto') {
@@ -1386,10 +1247,6 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
1386
1247
  notifyStderr = (text, options) => notifyChannel(text, options);
1387
1248
  // The question-seat alert was raised before the channel existed; flush it
1388
1249
  // now so it lands as an in-UI notice, not only in the log file.
1389
- if (questionSeatNotice !== undefined) {
1390
- notifyChannel(questionSeatNotice, { color: 'error' });
1391
- questionSeatNotice = undefined;
1392
- }
1393
1250
  for (const [text, options] of stderrBacklog.splice(0)) {
1394
1251
  notifyStderr(text, options);
1395
1252
  }
@@ -1762,10 +1619,10 @@ async function resolveAgent(ctx, requestedSessionId, configuredRoute, startupRou
1762
1619
  // between would otherwise drop the claim this boot just committed.
1763
1620
  const reservation = reserved.reservation;
1764
1621
  try {
1765
- // Compat boundary: register vouched-for legacy event types before the
1622
+ // Register current TUI-owned event types before the
1766
1623
  // strict read path (issue #153) — same seam as the /resume picker,
1767
1624
  // here for the launch-time --resume flow. In-process only.
1768
- ensureLegacySessionEventTypes();
1625
+ registerTuiSessionEventTypes();
1769
1626
  // The resumed session keeps the preset its log records (last
1770
1627
  // `agent-preset/selected` wins over the creation header), never the
1771
1628
  // caller's current preference.
@@ -1,11 +1,4 @@
1
- /**
2
- * Agent-preset resolution across upstream prerelease lines.
3
- *
4
- * Legacy rc.2 exports `resolveSessionPreset` and ships `code`; the 0.1.2 line
5
- * replaces the helper with a projection definition and renames that preset to `ptc`.
6
- * Keeping both compatibility decisions here prevents composition and channel
7
- * code from acquiring prerelease-specific branches.
8
- */
1
+ /** Current DSH agent-preset roster and durable selection. */
9
2
  import type { Context } from '@deepseek-ai/cordis';
10
3
  /** One roster entry, as returned by `agentPresets.list()`/`resolve()`. */
11
4
  export interface AgentPresetInfo {
@@ -40,18 +33,4 @@ export declare function resolveRecordedPreset(session: {
40
33
  data: unknown;
41
34
  }[];
42
35
  }): string | undefined;
43
- /**
44
- * Resolve an exact roster id first, then bridge the official rename in either
45
- * direction. A successful list is required before aliasing so roster I/O or
46
- * a broken exact preset can never be mistaken for an unknown id.
47
- */
48
- export declare function resolveCompatiblePreset(presets: AgentPresetsLike, requested?: string): Promise<AgentPresetInfo>;
49
- /**
50
- * The i18n dictionary id a roster preset's localized display text resolves
51
- * under. The 0.1.2 line renamed the official PTC preset `code` → `ptc`, but
52
- * the dictionary keys still use the legacy `code` id (`preset-name-code` /
53
- * `preset-desc-code`), so the `/preset` picker's display lookup must bridge
54
- * the roster id back. User-authored ids pass through untouched.
55
- */
56
- export declare function presetDisplayId(id: string): string;
57
36
  //# sourceMappingURL=preset-resolution.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"preset-resolution.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/preset-resolution.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAAA;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,+DAA+D;AAC/D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,IAAI,IAAI,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC,CAAA;IAC3C,OAAO,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAC9C,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAC/D,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAClE,yEAAyE;IACzE,UAAU,CAAC,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,OAAO,CAAA;KAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAC3D;AAED,2EAA2E;AAC3E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAEnE;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE;IAC7C,MAAM,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAChC,MAAM,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;CACnD,GAAG,MAAM,GAAG,SAAS,CASrB;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,gBAAgB,EACzB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,CAAC,CAQ1B;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAElD"}
1
+ {"version":3,"file":"preset-resolution.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/preset-resolution.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAAA;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,+DAA+D;AAC/D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,IAAI,IAAI,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC,CAAA;IAC3C,OAAO,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAC9C,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAC/D,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAClE,yEAAyE;IACzE,UAAU,CAAC,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,OAAO,CAAA;KAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAC3D;AAED,2EAA2E;AAC3E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAEnE;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE;IAC7C,MAAM,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAChC,MAAM,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;CACnD,GAAG,MAAM,GAAG,SAAS,CASrB"}
@@ -1,11 +1,3 @@
1
- /**
2
- * Agent-preset resolution across upstream prerelease lines.
3
- *
4
- * Legacy rc.2 exports `resolveSessionPreset` and ships `code`; the 0.1.2 line
5
- * replaces the helper with a projection definition and renames that preset to `ptc`.
6
- * Keeping both compatibility decisions here prevents composition and channel
7
- * code from acquiring prerelease-specific branches.
8
- */
9
1
  /** The mounted preset roster, or undefined in a rosterless composition. */
10
2
  export function rosterOf(ctx) {
11
3
  return ctx.get('agentPresets');
@@ -24,29 +16,3 @@ export function resolveRecordedPreset(session) {
24
16
  }
25
17
  return session.header.agentPreset;
26
18
  }
27
- /**
28
- * Resolve an exact roster id first, then bridge the official rename in either
29
- * direction. A successful list is required before aliasing so roster I/O or
30
- * a broken exact preset can never be mistaken for an unknown id.
31
- */
32
- export async function resolveCompatiblePreset(presets, requested) {
33
- const fallback = requested === 'code' ? 'ptc' : requested === 'ptc' ? 'code' : undefined;
34
- if (fallback === undefined)
35
- return presets.resolve(requested);
36
- const roster = await presets.list();
37
- if (roster.some(preset => preset.id === requested))
38
- return presets.resolve(requested);
39
- if (roster.some(preset => preset.id === fallback))
40
- return presets.resolve(fallback);
41
- return presets.resolve(requested);
42
- }
43
- /**
44
- * The i18n dictionary id a roster preset's localized display text resolves
45
- * under. The 0.1.2 line renamed the official PTC preset `code` → `ptc`, but
46
- * the dictionary keys still use the legacy `code` id (`preset-name-code` /
47
- * `preset-desc-code`), so the `/preset` picker's display lookup must bridge
48
- * the roster id back. User-authored ids pass through untouched.
49
- */
50
- export function presetDisplayId(id) {
51
- return id === 'ptc' ? 'code' : id;
52
- }
@@ -10,10 +10,7 @@
10
10
  * factory's `setup(agentCtx)` hook, where a composition failure rolls the
11
11
  * whole creation back instead of publishing a half-configured agent.
12
12
  *
13
- * A deployment without the roster (bare `dsh --config cordis.yml` boots,
14
- * older CLI without the shipped preset root) composes nothing: callers get
15
- * no `setup` and every session shares the host composition — the behavior
16
- * before presets existed.
13
+ * A composition without a preset registry supplies no preset setup.
17
14
  */
18
15
  import type { Context } from '@deepseek-ai/cordis';
19
16
  import type { AgentSetup } from '@deepseek-ai/dsh-agent';
@@ -1 +1 @@
1
- {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/presets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAWtE,kEAAkE;AAClE,MAAM,WAAW,iBAAiB;IAChC,kFAAkF;IAClF,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAA;CAC5B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAmBhG;AAED;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAW5G;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAGpE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAW/G;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,CAM/G;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE;IAAE,GAAG,EAAE,OAAO,CAAA;CAAE,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAKpG"}
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/presets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAUtE,kEAAkE;AAClE,MAAM,WAAW,iBAAiB;IAChC,kFAAkF;IAClF,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAA;CAC5B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAmBhG;AAED;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAW5G;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAGpE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAW/G;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,CAM/G;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE;IAAE,GAAG,EAAE,OAAO,CAAA;CAAE,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAKpG"}
@@ -10,15 +10,12 @@
10
10
  * factory's `setup(agentCtx)` hook, where a composition failure rolls the
11
11
  * whole creation back instead of publishing a half-configured agent.
12
12
  *
13
- * A deployment without the roster (bare `dsh --config cordis.yml` boots,
14
- * older CLI without the shipped preset root) composes nothing: callers get
15
- * no `setup` and every session shares the host composition — the behavior
16
- * before presets existed.
13
+ * A composition without a preset registry supplies no preset setup.
17
14
  */
18
15
  import { recordedModelRoute } from '../modelRoute.js';
19
16
  import { snapshotLiveSessionEvents } from './compat/liveSession.js';
20
17
  import { readPersistedSession } from './compat/persistence.js';
21
- import { resolveCompatiblePreset, resolveRecordedPreset, rosterOf, } from './preset-resolution.js';
18
+ import { resolveRecordedPreset, rosterOf, } from './preset-resolution.js';
22
19
  const ASK_USER_TOOL = 'ask_user_question';
23
20
  /**
24
21
  * Resolve the preset one new/resumed session will run under and the setup
@@ -39,7 +36,7 @@ export async function composePreset(ctx, requested) {
39
36
  return {};
40
37
  let resolvedId;
41
38
  try {
42
- resolvedId = (await resolveCompatiblePreset(presets, requested)).id;
39
+ resolvedId = (await presets.resolve(requested)).id;
43
40
  }
44
41
  catch (error) {
45
42
  ctx.logger.warn(`dsh-tui: agent preset ${requested === undefined ? '(default)' : `"${requested}"`} unavailable ` +
@@ -1,51 +1,13 @@
1
- /**
2
- * User-question answerer compatibility.
3
- *
4
- * Legacy rc.2 exposes one global `registerProvider` seat. The 0.1.2 line removed that
5
- * API in favour of a scope-aware `user-questions/request` waterfall. Keep the
6
- * capability probe and both registration paths here so the TUI bootstrap only
7
- * consumes a small prepared-registration result.
8
- */
1
+ /** Scope-aware question routing. Registration belongs to the TUI fiber. */
9
2
  import type { Context } from '@deepseek-ai/cordis';
10
3
  import type { AskUserQuestionAnswer, AskUserQuestionRequest } from '@deepseek-ai/dsh-user-questions';
11
- import { type QuestionProviderYieldDecision } from './providerGuard.js';
12
4
  export interface QuestionAnswerer {
13
5
  ask(request: AskUserQuestionRequest, options?: {
14
6
  redact?: boolean;
15
7
  }): Promise<AskUserQuestionAnswer>;
16
8
  }
17
- export type PreparedQuestionAnswerer = {
18
- readonly kind: 'legacy';
19
- /** Present only when another component already owns the provider seat. */
20
- readonly yieldDecision?: QuestionProviderYieldDecision;
21
- } | {
22
- readonly kind: 'waterfall';
23
- /** Bind ownership after the mutable channel has been created. */
24
- register(owner: {
25
- readonly agentId: string;
26
- }): () => void;
27
- };
28
- /**
29
- * Prepare the answerer against whichever upstream API the active package
30
- * exposes. The legacy path registers immediately and binds the returned
31
- * disposer to this TUI fiber. The waterfall path returns a late binder because
32
- * channel.agentId changes across `/new`, `/resume`, and rewind.
33
- *
34
- * Agentless waterfall requests are claimed deliberately: dsh-auth's `/auth`
35
- * wizard asks through the same service without an agent. Foreign-agent
36
- * requests continue to the next answerer.
37
- *
38
- * Security scope (#586): the provider-seat guard (DUPLICATE_PROVIDER probe +
39
- * private symbol check) exists ONLY on the legacy path. The waterfall has no
40
- * seat. Agent-bearing requests are scope-filtered; agentless requests such as
41
- * dsh-auth `/auth` are dispatched without a scope carrier. Under the answerer
42
- * contract, the first eligible listener that returns instead of delegating
43
- * with `next()` claims the request. Cordis waterfall is around middleware,
44
- * however: an outer listener can call `next()` and then observe, replace, or
45
- * reject the downstream result, while `{ prepend: true }` inserts a listener
46
- * at the front. Upstream exposes no supported way to discover or reserve an
47
- * exclusive claimant, so the legacy guard and its warning cannot be
48
- * reproduced here.
49
- */
50
- export declare function prepareQuestionAnswerer(ctx: Context, service: unknown, answerer: QuestionAnswerer): PreparedQuestionAnswerer;
9
+ /** Read the mutable channel identity for every request, including after resume. */
10
+ export declare function registerQuestionAnswerer(ctx: Context, owner: {
11
+ readonly agentId: string;
12
+ }, answerer: QuestionAnswerer): () => void;
51
13
  //# sourceMappingURL=questions-answerer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"questions-answerer.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/questions-answerer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EACV,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,iCAAiC,CAAA;AACxC,OAAO,EAIL,KAAK,6BAA6B,EACnC,MAAM,oBAAoB,CAAA;AAE3B,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,OAAO,EAAE,sBAAsB,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;CACrG;AAoBD,MAAM,MAAM,wBAAwB,GAChC;IACE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;IACvB,0EAA0E;IAC1E,QAAQ,CAAC,aAAa,CAAC,EAAE,6BAA6B,CAAA;CACvD,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,IAAI,CAAA;CAC1D,CAAA;AAML;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,gBAAgB,GACzB,wBAAwB,CA2B1B"}
1
+ {"version":3,"file":"questions-answerer.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/questions-answerer.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAA;AAEpG,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,OAAO,EAAE,sBAAsB,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;CACrG;AAED,mFAAmF;AACnF,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EACnC,QAAQ,EAAE,gBAAgB,GACzB,MAAM,IAAI,CAKZ"}
@@ -1,64 +1,8 @@
1
- /**
2
- * User-question answerer compatibility.
3
- *
4
- * Legacy rc.2 exposes one global `registerProvider` seat. The 0.1.2 line removed that
5
- * API in favour of a scope-aware `user-questions/request` waterfall. Keep the
6
- * capability probe and both registration paths here so the TUI bootstrap only
7
- * consumes a small prepared-registration result.
8
- */
9
- import { decideQuestionProviderYield, incumbentQuestionProviderId, tagTuiQuestionProvider, } from './providerGuard.js';
10
- function secretRequest(request) {
11
- return request.questions.some(question => question.id === 'dsh-auth-secret');
12
- }
13
- function hasLegacyProvider(service) {
14
- return typeof service.registerProvider === 'function';
15
- }
16
- /**
17
- * Prepare the answerer against whichever upstream API the active package
18
- * exposes. The legacy path registers immediately and binds the returned
19
- * disposer to this TUI fiber. The waterfall path returns a late binder because
20
- * channel.agentId changes across `/new`, `/resume`, and rewind.
21
- *
22
- * Agentless waterfall requests are claimed deliberately: dsh-auth's `/auth`
23
- * wizard asks through the same service without an agent. Foreign-agent
24
- * requests continue to the next answerer.
25
- *
26
- * Security scope (#586): the provider-seat guard (DUPLICATE_PROVIDER probe +
27
- * private symbol check) exists ONLY on the legacy path. The waterfall has no
28
- * seat. Agent-bearing requests are scope-filtered; agentless requests such as
29
- * dsh-auth `/auth` are dispatched without a scope carrier. Under the answerer
30
- * contract, the first eligible listener that returns instead of delegating
31
- * with `next()` claims the request. Cordis waterfall is around middleware,
32
- * however: an outer listener can call `next()` and then observe, replace, or
33
- * reject the downstream result, while `{ prepend: true }` inserts a listener
34
- * at the front. Upstream exposes no supported way to discover or reserve an
35
- * exclusive claimant, so the legacy guard and its warning cannot be
36
- * reproduced here.
37
- */
38
- export function prepareQuestionAnswerer(ctx, service, answerer) {
39
- if (!hasLegacyProvider(service)) {
40
- const events = ctx;
41
- return {
42
- kind: 'waterfall',
43
- register: owner => events.on('user-questions/request', (request, next) => {
44
- if (request.agent !== undefined && String(request.agent.id) !== owner.agentId)
45
- return next();
46
- return answerer.ask(request, { redact: secretRequest(request) });
47
- }),
48
- };
49
- }
50
- const provider = { ask: request => answerer.ask(request, { redact: secretRequest(request) }) };
51
- tagTuiQuestionProvider(provider);
52
- try {
53
- ctx.effect(() => service.registerProvider(provider), 'dsh-tui.questions.legacy-provider');
54
- return { kind: 'legacy' };
55
- }
56
- catch (error) {
57
- if (error.code !== 'DUPLICATE_PROVIDER')
58
- throw error;
59
- return {
60
- kind: 'legacy',
61
- yieldDecision: decideQuestionProviderYield(incumbentQuestionProviderId(service)),
62
- };
63
- }
1
+ /** Read the mutable channel identity for every request, including after resume. */
2
+ export function registerQuestionAnswerer(ctx, owner, answerer) {
3
+ return ctx.on('user-questions/request', (request, next) => {
4
+ if (request.agent !== undefined && String(request.agent.id) !== owner.agentId)
5
+ return next();
6
+ return answerer.ask(request, { redact: request.questions.some(question => question.id === 'dsh-auth-secret') });
7
+ });
64
8
  }