@deepseek-harness-tui/dsh-tui 0.11.2 → 0.12.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 (168) hide show
  1. package/README.md +21 -5
  2. package/bin/dsh-tui.js +30 -3
  3. package/cordis.patch.yml +24 -5
  4. package/guide/dsh-tui-guide/SKILL.md +37 -0
  5. package/guide/dsh-tui-guide/configuration.en.md +410 -0
  6. package/guide/dsh-tui-guide/configuration.md +349 -0
  7. package/guide/dsh-tui-guide/getting-started.en.md +398 -0
  8. package/guide/dsh-tui-guide/getting-started.md +397 -0
  9. package/guide/dsh-tui-guide/interaction.en.md +674 -0
  10. package/guide/dsh-tui-guide/interaction.md +747 -0
  11. package/guide/dsh-tui-guide/migrate.en.md +166 -0
  12. package/guide/dsh-tui-guide/migrate.md +132 -0
  13. package/guide/dsh-tui-guide/plugins.en.md +68 -0
  14. package/guide/dsh-tui-guide/plugins.md +56 -0
  15. package/guide/dsh-tui-guide/themes.en.md +192 -0
  16. package/guide/dsh-tui-guide/themes.md +185 -0
  17. package/guide/dsh-tui-guide/user-guide.en.md +608 -0
  18. package/guide/dsh-tui-guide/user-guide.md +586 -0
  19. package/guide/dsh-tui-guide/vscode.en.md +301 -0
  20. package/guide/dsh-tui-guide/vscode.md +272 -0
  21. package/lib/settings.json +5 -5
  22. package/lib/types/adapter/channel/ui-policy.d.ts +3 -2
  23. package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
  24. package/lib/types/adapter/channel/ui-policy.js +4 -0
  25. package/lib/types/adapter/ports/channel-settings.d.ts +2 -1
  26. package/lib/types/adapter/ports/channel-settings.d.ts.map +1 -1
  27. package/lib/types/adapter/ports/channel-ui.d.ts +29 -2
  28. package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
  29. package/lib/types/adapter/ports/channel-view.d.ts +43 -9
  30. package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
  31. package/lib/types/components/Chat/JobCard.d.ts +9 -0
  32. package/lib/types/components/Chat/JobCard.d.ts.map +1 -1
  33. package/lib/types/components/Chat/JobCard.js +42 -15
  34. package/lib/types/components/Chat/SubagentMessage.js +6 -6
  35. package/lib/types/components/JobsPanel.d.ts.map +1 -1
  36. package/lib/types/components/JobsPanel.js +80 -33
  37. package/lib/types/components/MessageList.js +3 -3
  38. package/lib/types/components/PresetPicker.d.ts +4 -0
  39. package/lib/types/components/PresetPicker.d.ts.map +1 -1
  40. package/lib/types/components/PresetPicker.js +5 -1
  41. package/lib/types/components/PromptInput.d.ts.map +1 -1
  42. package/lib/types/components/PromptInput.js +12 -1
  43. package/lib/types/components/StarPrompt.d.ts +6 -0
  44. package/lib/types/components/StarPrompt.d.ts.map +1 -1
  45. package/lib/types/components/StarPrompt.js +45 -0
  46. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  47. package/lib/types/components/SubagentCard.js +8 -8
  48. package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
  49. package/lib/types/components/SubagentDetailScene.js +108 -10
  50. package/lib/types/components/WhaleGirl.d.ts +6 -0
  51. package/lib/types/components/WhaleGirl.d.ts.map +1 -1
  52. package/lib/types/components/WhaleGirl.js +18 -0
  53. package/lib/types/components/messages/AssistantThinkingMessage.js +4 -4
  54. package/lib/types/components/trajectory/MiniWake.d.ts +11 -1
  55. package/lib/types/components/trajectory/MiniWake.d.ts.map +1 -1
  56. package/lib/types/components/trajectory/MiniWake.js +9 -3
  57. package/lib/types/dsh-adapter/channel/external-commands.d.ts.map +1 -1
  58. package/lib/types/dsh-adapter/channel/external-commands.js +8 -2
  59. package/lib/types/dsh-adapter/channel/job-projection.d.ts +1 -0
  60. package/lib/types/dsh-adapter/channel/job-projection.d.ts.map +1 -1
  61. package/lib/types/dsh-adapter/channel/job-projection.js +88 -3
  62. package/lib/types/dsh-adapter/channel/mode-actions.d.ts +13 -0
  63. package/lib/types/dsh-adapter/channel/mode-actions.d.ts.map +1 -1
  64. package/lib/types/dsh-adapter/channel/mode-actions.js +48 -7
  65. package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts.map +1 -1
  66. package/lib/types/dsh-adapter/channel/mode-permission-actions.js +25 -9
  67. package/lib/types/dsh-adapter/channel/preferences.d.ts +1 -1
  68. package/lib/types/dsh-adapter/channel/preferences.d.ts.map +1 -1
  69. package/lib/types/dsh-adapter/channel/preferences.js +17 -7
  70. package/lib/types/dsh-adapter/channel/state.d.ts +4 -2
  71. package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
  72. package/lib/types/dsh-adapter/channel/state.js +1 -1
  73. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
  74. package/lib/types/dsh-adapter/channel/subagent-projection.js +5 -0
  75. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  76. package/lib/types/dsh-adapter/channel.js +16 -1
  77. package/lib/types/dsh-adapter/contract.d.ts +5 -4
  78. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  79. package/lib/types/dsh-adapter/contract.js +9 -3
  80. package/lib/types/dsh-adapter/jobs.d.ts +82 -16
  81. package/lib/types/dsh-adapter/jobs.d.ts.map +1 -1
  82. package/lib/types/dsh-adapter/jobs.js +104 -9
  83. package/lib/types/dsh-adapter/oauth/bonus.d.ts +27 -0
  84. package/lib/types/dsh-adapter/oauth/bonus.d.ts.map +1 -0
  85. package/lib/types/dsh-adapter/oauth/bonus.js +69 -0
  86. package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/command.d.ts +2 -1
  87. package/lib/types/dsh-adapter/oauth/command.d.ts.map +1 -0
  88. package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/command.js +7 -4
  89. package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/credentials.d.ts +13 -10
  90. package/lib/types/dsh-adapter/oauth/credentials.d.ts.map +1 -0
  91. package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/credentials.js +61 -23
  92. package/lib/types/dsh-adapter/oauth/deepseek.d.ts +39 -0
  93. package/lib/types/dsh-adapter/oauth/deepseek.d.ts.map +1 -0
  94. package/lib/types/dsh-adapter/oauth/deepseek.js +189 -0
  95. package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/index.d.ts +24 -16
  96. package/lib/types/dsh-adapter/oauth/index.d.ts.map +1 -0
  97. package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/index.js +34 -20
  98. package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/interaction.d.ts +14 -12
  99. package/lib/types/dsh-adapter/oauth/interaction.d.ts.map +1 -0
  100. package/lib/types/dsh-adapter/oauth/interaction.js +283 -0
  101. package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/opener.d.ts +2 -1
  102. package/lib/types/dsh-adapter/oauth/opener.d.ts.map +1 -0
  103. package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/opener.js +1 -1
  104. package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/pi-ai.d.ts +10 -3
  105. package/lib/types/dsh-adapter/oauth/pi-ai.d.ts.map +1 -0
  106. package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/pi-ai.js +8 -3
  107. package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/profiles.d.ts +6 -3
  108. package/lib/types/dsh-adapter/oauth/profiles.d.ts.map +1 -0
  109. package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/profiles.js +11 -3
  110. package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/service.d.ts +14 -7
  111. package/lib/types/dsh-adapter/oauth/service.d.ts.map +1 -0
  112. package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/service.js +82 -17
  113. package/lib/types/dsh-adapter/plugin.d.ts +8 -1
  114. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  115. package/lib/types/dsh-adapter/plugin.js +72 -12
  116. package/lib/types/dsh-adapter/presets.d.ts +6 -4
  117. package/lib/types/dsh-adapter/presets.d.ts.map +1 -1
  118. package/lib/types/dsh-adapter/presets.js +6 -4
  119. package/lib/types/dsh-adapter/providerWizard.d.ts.map +1 -1
  120. package/lib/types/dsh-adapter/providerWizard.js +6 -2
  121. package/lib/types/dsh-adapter/subagents.d.ts +1 -0
  122. package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
  123. package/lib/types/dsh-adapter/subagents.js +10 -1
  124. package/lib/types/i18n.d.ts +174 -18
  125. package/lib/types/i18n.d.ts.map +1 -1
  126. package/lib/types/i18n.js +53 -11
  127. package/lib/types/ink/components/App.d.ts.map +1 -1
  128. package/lib/types/ink/components/App.js +10 -1
  129. package/lib/types/ink/parse-keypress.d.ts +35 -0
  130. package/lib/types/ink/parse-keypress.d.ts.map +1 -1
  131. package/lib/types/ink/parse-keypress.js +611 -83
  132. package/lib/types/ink/terminal-querier.d.ts +25 -0
  133. package/lib/types/ink/terminal-querier.d.ts.map +1 -1
  134. package/lib/types/ink/terminal-querier.js +42 -0
  135. package/lib/types/ink/update-overflow-guard.d.ts +24 -0
  136. package/lib/types/ink/update-overflow-guard.d.ts.map +1 -1
  137. package/lib/types/ink/update-overflow-guard.js +25 -3
  138. package/lib/types/minimalUiMode.d.ts +19 -0
  139. package/lib/types/minimalUiMode.d.ts.map +1 -0
  140. package/lib/types/minimalUiMode.js +23 -0
  141. package/lib/types/oauth.d.ts +5 -10
  142. package/lib/types/oauth.d.ts.map +1 -1
  143. package/lib/types/oauth.js +5 -10
  144. package/lib/types/screens/Chat.d.ts +4 -1
  145. package/lib/types/screens/Chat.d.ts.map +1 -1
  146. package/lib/types/screens/Chat.js +27 -7
  147. package/lib/types/screens/StatusLine.d.ts +4 -0
  148. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  149. package/lib/types/screens/StatusLine.js +12 -12
  150. package/lib/types/settings/definitions.js +4 -4
  151. package/lib/types/tips.d.ts.map +1 -1
  152. package/lib/types/tips.js +10 -4
  153. package/lib/types/update.js +2 -2
  154. package/lib/types/utils/pastedImagePath.d.ts +8 -0
  155. package/lib/types/utils/pastedImagePath.d.ts.map +1 -1
  156. package/lib/types/utils/pastedImagePath.js +29 -5
  157. package/package.json +111 -100
  158. package/presets/liangshen/agent.cordis.yml +4 -1
  159. package/presets/liangshen/preset.yml +1 -1
  160. package/lib/types/minimalMode.d.ts +0 -13
  161. package/lib/types/minimalMode.d.ts.map +0 -1
  162. package/lib/types/minimalMode.js +0 -17
  163. package/node_modules/@deepseek-harness-tui/dsh-auth/LICENSE +0 -21
  164. package/node_modules/@deepseek-harness-tui/dsh-auth/README.md +0 -143
  165. package/node_modules/@deepseek-harness-tui/dsh-auth/cordis.patch.yml +0 -11
  166. package/node_modules/@deepseek-harness-tui/dsh-auth/dsh-plugin.json +0 -44
  167. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/interaction.js +0 -193
  168. package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +0 -69
@@ -1,16 +1,19 @@
1
1
  /**
2
- * The `ctx.dshAuth` service: the programmatic surface over this plugin's
2
+ * The `ctx.dshAuth` service: the programmatic surface over this module's
3
3
  * mounted OAuth routes. UIs (the dsh-tui /provider wizard, a web settings
4
4
  * page) enumerate providers with masked sign-in state and drive login/logout
5
5
  * without touching the credential file or the pi-ai flow objects; the `/auth`
6
6
  * command in `command.ts` is a thin textual veneer over the same api.
7
7
  *
8
- * @module dsh-auth/service
8
+ * @module @deepseek-harness-tui/dsh-tui/oauth/service
9
9
  */
10
10
  import { Service } from '@deepseek-ai/cordis';
11
11
  import { asStoredCredential } from './credentials.js';
12
12
  import { oauthOf } from './profiles.js';
13
13
  import { QuestionBridge } from './interaction.js';
14
+ import { loginOAuth } from './pi-ai.js';
15
+ import { DEEPSEEK_ACCOUNT_PROVIDER, deepSeekClientMetadata, loginDeepSeekAccount, } from './deepseek.js';
16
+ import { WhaleCouponStore } from './bonus.js';
14
17
  /**
15
18
  * The constructed catalog provider one mounted route carries. 0.1.5 made
16
19
  * `ResolvedPiAiProviderProfile.piProvider` optional (a stored route that
@@ -27,6 +30,7 @@ function mountedProvider(profile) {
27
30
  /** Cordis service holder; `api` is set by the plugin's apply. */
28
31
  export class DshAuthService extends Service {
29
32
  api;
33
+ coupons = new WhaleCouponStore();
30
34
  constructor(ctx) {
31
35
  super(ctx, 'dshAuth');
32
36
  }
@@ -56,9 +60,13 @@ async function chooseProvider(ask, candidates, signal) {
56
60
  */
57
61
  export function createDshAuthApi(deps) {
58
62
  const inflight = new Map();
63
+ const mountedIds = () => [
64
+ ...deps.profiles.keys(),
65
+ ...(deps.resolveDeepSeekAccount?.() === undefined ? [] : [DEEPSEEK_ACCOUNT_PROVIDER]),
66
+ ];
59
67
  const statusOf = async () => {
60
68
  const described = new Map((await deps.store.describe()).map(row => [row.provider, row]));
61
- return [...deps.profiles.entries()].map(([id, profile]) => {
69
+ const piAi = [...deps.profiles.entries()].map(([id, profile]) => {
62
70
  const oauth = oauthOf(mountedProvider(profile));
63
71
  const row = described.get(id);
64
72
  return {
@@ -71,32 +79,55 @@ export function createDshAuthApi(deps) {
71
79
  expired: row?.expired ?? false,
72
80
  };
73
81
  });
82
+ const account = deps.resolveDeepSeekAccount?.();
83
+ if (account === undefined)
84
+ return piAi;
85
+ const state = await account.getState();
86
+ return [{
87
+ provider: DEEPSEEK_ACCOUNT_PROVIDER,
88
+ label: 'DeepSeek Account',
89
+ oauthLabel: 'DeepSeek',
90
+ loginLabel: 'Sign in with DeepSeek',
91
+ signedIn: state.status === 'credential-stored',
92
+ expiresAt: undefined,
93
+ expired: false,
94
+ }, ...piAi];
74
95
  };
75
96
  const loginOne = async (provider, ask, signal) => {
76
97
  const profile = deps.profiles.get(provider);
77
98
  if (profile === undefined) {
78
- throw new Error(`dsh-auth: unknown provider "${provider}" (mounted: ${[...deps.profiles.keys()].join(', ')})`);
99
+ throw new Error(`dsh-auth: unknown provider "${provider}" (mounted: ${mountedIds().join(', ')})`);
79
100
  }
80
101
  const oauth = oauthOf(mountedProvider(profile));
81
102
  const runAbort = new AbortController();
103
+ const forwardAbort = () => runAbort.abort(signal?.reason);
82
104
  if (signal !== undefined) {
83
105
  if (signal.aborted)
84
- runAbort.abort(signal.reason);
106
+ forwardAbort();
85
107
  else
86
- signal.addEventListener('abort', () => runAbort.abort(signal.reason), { once: true });
108
+ signal.addEventListener('abort', forwardAbort, { once: true });
87
109
  }
88
110
  const bridge = new QuestionBridge(ask, runAbort);
89
111
  try {
90
- const returned = await oauth.login(bridge);
112
+ runAbort.signal.throwIfAborted();
113
+ const returned = await loginOAuth(oauth, bridge, {
114
+ // pi-ai 0.87.1's `openai` flow needs this on login. Older flows
115
+ // ignore the optional context, so the ID is created only on demand.
116
+ getDeviceId: () => deps.store.getOrCreateDeviceId(),
117
+ });
91
118
  const normalized = asStoredCredential(returned);
92
119
  if (normalized === undefined) {
93
120
  throw new Error(`dsh-auth: the ${oauth.name} flow returned an unusable credential; nothing was stored`);
94
121
  }
95
- const stored = normalized;
96
- await deps.store.modify(provider, async () => stored);
97
- return { provider, oauthLabel: oauth.name, expiresAt: stored.expires };
122
+ await deps.store.modify(provider, async () => {
123
+ // Logout may have cancelled the flow while this write waited for the file lock.
124
+ runAbort.signal.throwIfAborted();
125
+ return normalized;
126
+ });
127
+ return { provider, oauthLabel: oauth.name, expiresAt: normalized.expires };
98
128
  }
99
129
  finally {
130
+ signal?.removeEventListener('abort', forwardAbort);
100
131
  await bridge.settle();
101
132
  }
102
133
  };
@@ -115,24 +146,58 @@ export function createDshAuthApi(deps) {
115
146
  throw new Error('dsh-auth: every mounted provider is already signed in');
116
147
  target = await chooseProvider(ask, candidates, signal);
117
148
  }
118
- else if (!deps.profiles.has(target)) {
119
- throw new Error(`dsh-auth: unknown provider "${target}" (mounted: ${[...deps.profiles.keys()].join(', ')})`);
149
+ else if (!mountedIds().includes(target)) {
150
+ throw new Error(`dsh-auth: unknown provider "${target}" (mounted: ${mountedIds().join(', ')})`);
120
151
  }
121
152
  if (ask === undefined) {
122
153
  throw new Error(`dsh-auth: signing in to "${target}" needs an interactive surface (run inside dsh-tui or the web client); `
123
154
  + 'this plugin refuses to assume a browser on this machine');
124
155
  }
125
- const existing = inflight.get(target);
126
- if (existing !== undefined) {
156
+ if (inflight.has(target)) {
127
157
  throw new Error(`dsh-auth: a login for "${target}" is already running`);
128
158
  }
129
- const run = loginOne(target, ask, signal).finally(() => { inflight.delete(target); });
130
- inflight.set(target, run);
159
+ const account = target === DEEPSEEK_ACCOUNT_PROVIDER ? deps.resolveDeepSeekAccount?.() : undefined;
160
+ if (target === DEEPSEEK_ACCOUNT_PROVIDER && account === undefined) {
161
+ throw new Error(`dsh-auth: provider "${target}" is no longer mounted`);
162
+ }
163
+ const cancellation = new AbortController();
164
+ const runSignal = signal === undefined ? cancellation.signal : AbortSignal.any([signal, cancellation.signal]);
165
+ inflight.set(target, cancellation);
166
+ const run = (account === undefined
167
+ ? loginOne(target, ask, runSignal)
168
+ : (async () => {
169
+ runSignal.throwIfAborted();
170
+ const callbackOrigin = await deps.resolveCallbackOrigin?.();
171
+ runSignal.throwIfAborted();
172
+ if (callbackOrigin === undefined) {
173
+ throw new Error('DeepSeek sign-in needs an active Host webServer for the browser callback');
174
+ }
175
+ await loginDeepSeekAccount(account, callbackOrigin, ask, runSignal);
176
+ deps.coupons?.clear();
177
+ const getUnnotifiedBonuses = account.getUnnotifiedBonuses?.bind(account);
178
+ const ackBonusNotified = account.ackBonusNotified?.bind(account);
179
+ if (getUnnotifiedBonuses !== undefined && ackBonusNotified !== undefined) {
180
+ void deps.coupons?.refresh({ getUnnotifiedBonuses, ackBonusNotified });
181
+ }
182
+ return { provider: target, oauthLabel: 'DeepSeek', expiresAt: undefined };
183
+ })()).finally(() => { inflight.delete(target); });
131
184
  return run;
132
185
  },
133
186
  logout: async (provider) => {
187
+ // A DeepSeek login may still be awaiting its callback listener, before
188
+ // the Host has an attempt to cancel. Abort it before Host sign-out.
189
+ inflight.get(provider)?.abort(new Error('Login cancelled'));
190
+ if (provider === DEEPSEEK_ACCOUNT_PROVIDER) {
191
+ const account = deps.resolveDeepSeekAccount?.();
192
+ if (account !== undefined) {
193
+ const existed = (await account.getState()).status === 'credential-stored';
194
+ await account.signOut(deepSeekClientMetadata());
195
+ deps.coupons?.clear();
196
+ return existed;
197
+ }
198
+ }
134
199
  if (!deps.profiles.has(provider)) {
135
- throw new Error(`dsh-auth: unknown provider "${provider}" (mounted: ${[...deps.profiles.keys()].join(', ')})`);
200
+ throw new Error(`dsh-auth: unknown provider "${provider}" (mounted: ${mountedIds().join(', ')})`);
136
201
  }
137
202
  const existed = (await deps.store.read(provider)) !== undefined;
138
203
  await deps.store.delete(provider);
@@ -43,7 +43,14 @@ export declare function apply(ctx: Context, runtimeConfig: RuntimeConfig<Config>
43
43
  export declare function createExitFunnel(deps: {
44
44
  onUserExit: (error?: unknown) => void;
45
45
  }): {
46
- handleExit: (error?: unknown) => void;
46
+ /**
47
+ * Settle the exit once.
48
+ * @returns true when this call ran the user-exit path (the funnel now owns
49
+ * the process), false when it was already settled or the tree is being
50
+ * torn down. A process-level crash backstop must fall back to Node's
51
+ * default crash on false instead of swallowing the error.
52
+ */
53
+ handleExit: (error?: unknown) => boolean;
47
54
  markTeardown: () => void;
48
55
  };
49
56
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,wBAAwB,CAAA;AAGhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACnC,OAAO,EAA+D,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAwDtH,OAAO,EAAE,MAAM,EAAkC,MAAM,UAAU,CAAA;AAkCjE;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,CAsBxF;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,yBAAyB,GAAG,eAAe,CAAA;AAErF,wBAAgB,kBAAkB,CAChC,WAAW,UAAgC,EAC3C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,WAAW,CASb;AAED,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,WAAW,GAAE,OAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA84CzH;AAmMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GAAG;IACjF,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB,CAcA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,KAAK,GAAG,SAAS,CAAA;IAC5B,YAAY,EAAE,KAAK,CAAA;CACpB,GAAG,OAAO,CAQV;AAgBD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,GAAG,SAAS,EACxD,UAAU,EAAE,OAAO,EACnB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,IAAI,EAAE,MAAM,IAAI,GACf,OAAO,CAAC,IAAI,CAAC,CAmFf;AA4HD,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAIrE"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,wBAAwB,CAAA;AAGhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACnC,OAAO,EAA+D,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAyDtH,OAAO,EAAE,MAAM,EAAkC,MAAM,UAAU,CAAA;AAmCjE;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,CAsBxF;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,yBAAyB,GAAG,eAAe,CAAA;AAErF,wBAAgB,kBAAkB,CAChC,WAAW,UAAgC,EAC3C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,WAAW,CASb;AAED,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,WAAW,GAAE,OAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAw8CzH;AAmMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GAAG;IACjF;;;;;;OAMG;IACH,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,OAAO,CAAA;IACxC,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB,CAeA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,KAAK,GAAG,SAAS,CAAA;IAC5B,YAAY,EAAE,KAAK,CAAA;CACpB,GAAG,OAAO,CAQV;AAgBD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,GAAG,SAAS,EACxD,UAAU,EAAE,OAAO,EACnB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,IAAI,EAAE,MAAM,IAAI,GACf,OAAO,CAAC,IAAI,CAAC,CAmFf;AA4HD,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAIrE"}
@@ -61,6 +61,7 @@ import instances from '../ink/instances.js';
61
61
  import { cursorMove, DISABLE_KITTY_KEYBOARD, DISABLE_MODIFY_OTHER_KEYS, DISABLE_WIN32_INPUT_MODE } from '../ink/termio/csi.js';
62
62
  import { DBP, DFE, DISABLE_MOUSE_TRACKING, EXIT_ALT_SCREEN, SHOW_CURSOR } from '../ink/termio/dec.js';
63
63
  import { CLEAR_ITERM2_PROGRESS, CLEAR_TAB_STATUS, supportsTabStatus, wrapForMultiplexer } from '../ink/termio/osc.js';
64
+ import { fatalReasonForExit, registerProcessGuardFatalSink } from '../ink/update-overflow-guard.js';
64
65
  /**
65
66
  * Interactive TUI front door for DeepSeek Harness agents.
66
67
  *
@@ -274,10 +275,10 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
274
275
  const userQuestions = ctx.get('userQuestions') ?? new UserQuestionService(ctx);
275
276
  ctx.plugin(toolAskUser);
276
277
  // The host-level tool mount above is intentional for the TUI and for user
277
- // presets, but the official Minimal preset is a strict two-tool trajectory
278
- // (persistent bash + str_replace_editor). Filter only that preset at the
279
- // final assembly boundary. Reading the session on every assembly also makes
280
- // blank-session /preset switches and resumed sessions behave correctly.
278
+ // presets, but the official Minimal preset is a single-tool trajectory (one
279
+ // persistent shell: bash on POSIX, pwsh on Windows). Filter only that preset
280
+ // at the final assembly boundary. Reading the session on every assembly also
281
+ // makes blank-session /preset switches and resumed sessions behave correctly.
281
282
  ctx.on('system-prompt/assemble', async (_assembly, context, next) => {
282
283
  const assembled = await next();
283
284
  const presetId = context.agent === undefined ? undefined : runningPresetOf(context.agent.session);
@@ -431,7 +432,20 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
431
432
  // reads the same records. There is deliberately no rail-side "add a
432
433
  // workspace" control any more: a terminal's launch directory is the whole
433
434
  // registration story.
434
- const attached = await attachSessionToWorkspace(ctx, meta.cwd, agent.session.id);
435
+ //
436
+ // A RESUMED session is accounted where its OWN header cwd lives, never
437
+ // where this terminal was launched. The launch directory can be an
438
+ // ANCESTOR of the resumed session's: launching in `~/projects` and
439
+ // resuming a session recorded in `~/projects/app` accounts the same
440
+ // session in both workspaces, and the next boot dies inside
441
+ // `validateStoredState` ("session ... is accounted by both workspace
442
+ // ..."), which leaves `workspaceRegistry` unactivated and the whole TUI
443
+ // pending forever. Ownership must therefore agree with the `cwd:` handed
444
+ // to `createChannel` below, which already prefers the persisted header.
445
+ // Fresh sessions record `meta.cwd` at creation, so the launch directory
446
+ // still registers through them.
447
+ const ownershipCwd = agent.session.header.cwd ?? meta.cwd;
448
+ const attached = await attachSessionToWorkspace(ctx, ownershipCwd, agent.session.id);
435
449
  if (!attached) {
436
450
  ctx.logger.warn(`dsh-tui: session "${agent.session.id}" has no workspace ownership because workspaceRegistry is not mounted`);
437
451
  }
@@ -670,8 +684,9 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
670
684
  // (undefined → daily), so cordis.yml stays decisive and junk lands on
671
685
  // daily.
672
686
  splashFont: Schema.string(),
673
- // Minimal mode: strips the header splash, emoji glyphs, and
674
- // decorative colors; code highlight and tool colors stay.
687
+ // Minimal UI (极简界面, settings key `minimal` — never renamed): strips
688
+ // the header splash, emoji glyphs, and decorative colors; code highlight
689
+ // and tool colors stay. Unrelated to the kernel agent preset `minimal`.
675
690
  minimal: Schema.boolean().default(false),
676
691
  // No default on purpose: an unset `lang` keeps the field showing
677
692
  // the effective language (see the section's format below) and lets
@@ -714,10 +729,12 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
714
729
  return;
715
730
  channel.setSplashFont(normalizeSplashFont(value.splashFont ?? config.splashFont));
716
731
  };
717
- const applyMinimal = (value) => {
732
+ const applyMinimalUi = (value) => {
718
733
  if (shadow)
719
734
  return;
720
- channel.setMinimal(value.minimal ?? false);
735
+ // `value.minimal` is the persisted settings key (never renamed); the
736
+ // channel member is the minimal-UI flag, NOT the kernel preset.
737
+ channel.setMinimalUi(value.minimal ?? false);
721
738
  };
722
739
  // Renderer settings are resolved before mount; later edits wait for restart.
723
740
  const applyRendererSettings = (value) => {
@@ -802,7 +819,7 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
802
819
  applyWhaleIdle(next);
803
820
  applyWhaleGirl(next);
804
821
  applySplashFont(next);
805
- applyMinimal(next);
822
+ applyMinimalUi(next);
806
823
  applyLang(next);
807
824
  applyDisplay(next);
808
825
  applyEffortDefault(next);
@@ -1190,6 +1207,24 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
1190
1207
  if (error !== undefined) {
1191
1208
  const message = error instanceof Error ? error.message : String(error);
1192
1209
  ctx.logger.error(`dsh-tui: exit after error: ${message}`);
1210
+ // A crash must leave the resume marker a clean exit would leave: the
1211
+ // launcher's next start (and its safe-mode retry) then reopens the
1212
+ // session the user was actually in instead of a blank one. Only the
1213
+ // resumable case writes — unlike the clean-exit branch below, a crash
1214
+ // never CLEARS a marker, so a session the user still has cannot be
1215
+ // dropped by a failure that happened before the first message landed.
1216
+ try {
1217
+ if (isExitResumable({
1218
+ pendingCount: channel.pending.length,
1219
+ liveAgent: ctx.agents.get(SessionId(channel.agentId)),
1220
+ startupAgent: agent,
1221
+ })) {
1222
+ writeResumeTarget(channel.agentId);
1223
+ }
1224
+ }
1225
+ catch {
1226
+ // Resume persistence is best effort and must never block the exit.
1227
+ }
1193
1228
  void finishExit(ctx, instance, bootedFullscreen, undefined, `dsh-tui crashed: ${message}`, () => disposeRootAndExit(ctx, 1));
1194
1229
  return;
1195
1230
  }
@@ -1250,6 +1285,25 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
1250
1285
  },
1251
1286
  });
1252
1287
  const handleExit = funnel.handleExit;
1288
+ // Process-level crash backstop (see installNestedUpdateOverflowProcessGuard):
1289
+ // an uncaught exception or unhandled rejection that is NOT the React #185
1290
+ // overflow would otherwise take Node's default path and kill the process
1291
+ // before this funnel runs — no resume marker, no terminal restore, and the
1292
+ // launcher's "entered safe mode" prompt on what looks like a lost session.
1293
+ // Route it through the same teardown a fatal RENDER error uses: unmount,
1294
+ // `dsh-tui crashed: …`, dispose, exit 1. Fail loud stays intact — the funnel
1295
+ // returns false when it has already settled or the tree is being torn down
1296
+ // (host recompose), and the guard then rethrows to Node's default crash.
1297
+ // DSH_TUI_NO_185_PROCESS_GUARD=1 skips the guard entirely, leaving process
1298
+ // error policy to the host exactly as before.
1299
+ registerProcessGuardFatalSink((error, origin) => {
1300
+ // An undefined reason (`Promise.reject()`, `throw undefined`) must not reach
1301
+ // the funnel as-is: `error !== undefined` is what selects the crash path, so
1302
+ // a bare undefined would exit 0 while this sink claims the process.
1303
+ const fatal = fatalReasonForExit(error, origin);
1304
+ ctx.logger.error(`dsh-tui: fatal ${origin}: ${fatal instanceof Error ? fatal.message : String(fatal)}`);
1305
+ return handleExit(fatal);
1306
+ });
1253
1307
  // External injection controller: Chat fills it with `{ append, submit }`
1254
1308
  // every render; the injection socket (opened below) drives it. A ref rather
1255
1309
  // than a prop callback so the socket handler always reaches the live Chat.
@@ -1289,6 +1343,7 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
1289
1343
  // shortcuts). Soft-consumed: absent the row (stale patch, bare embed),
1290
1344
  // Chat falls back to inert stores and no shortcut registry.
1291
1345
  extensionDialogs: getHostDialogStore(ctx.get('tuiDialogs')),
1346
+ bonusNotices: ctx.get('dshAuth')?.coupons,
1292
1347
  extensionStatus: getHostStatusStore(ctx.get('tuiStatus')),
1293
1348
  // The working line's semantics belong to the dsh-working-activity plugin's
1294
1349
  // session projection; this store is the read side of that seam, so the TUI
@@ -1445,6 +1500,10 @@ export async function apply(ctx, runtimeConfig, configOwner = ctx) {
1445
1500
  ctx.effect(() => () => {
1446
1501
  logMouseDebug('apply teardown');
1447
1502
  funnel.markTeardown();
1503
+ // Drop the crash backstop with this mount: a torn-down funnel cannot own
1504
+ // the process, so a later fatal error falls back to Node's default crash
1505
+ // instead of reaching a disposed ctx.
1506
+ registerProcessGuardFatalSink(undefined);
1448
1507
  rawChannel.releaseContributions();
1449
1508
  instance?.unmount();
1450
1509
  });
@@ -1648,11 +1707,12 @@ export function createExitFunnel(deps) {
1648
1707
  },
1649
1708
  handleExit: (error) => {
1650
1709
  if (teardown)
1651
- return;
1710
+ return false;
1652
1711
  if (exited)
1653
- return;
1712
+ return false;
1654
1713
  exited = true;
1655
1714
  deps.onUserExit(error);
1715
+ return true;
1656
1716
  },
1657
1717
  };
1658
1718
  }
@@ -79,10 +79,12 @@ export declare function runningPresetOf(session: unknown): string | undefined;
79
79
  */
80
80
  export declare function resolvePersistedRoute(ctx: Context, sessionId: SessionId): Promise<ModelRoute | undefined>;
81
81
  /**
82
- * Keep the official Minimal preset's model-facing contract at exactly two
83
- * tools. The TUI mounts ask_user_question at the host layer so every other
84
- * preset (including user presets) can use its questionnaire UI; host-layer
85
- * tools otherwise merge into Minimal's scoped catalog as a third tool.
82
+ * Keep the official Minimal preset's model-facing catalog minimal. The preset
83
+ * itself declares exactly one persistent shell tool (bash on POSIX, pwsh on
84
+ * Windows), while the TUI mounts ask_user_question at the host layer so every
85
+ * other preset (including user presets) can use its questionnaire UI —
86
+ * that host-layer tool otherwise merges into Minimal's scoped catalog as an
87
+ * extra tool.
86
88
  *
87
89
  * This is a per-assembly filter rather than a startup-time decision because
88
90
  * one TUI process can resume, create, or recompose sessions under different
@@ -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;;;;;;;;;;;;;;;;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;;;;;;;;;;;;;;;GAeG;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"}
@@ -120,10 +120,12 @@ export async function resolvePersistedRoute(ctx, sessionId) {
120
120
  }
121
121
  }
122
122
  /**
123
- * Keep the official Minimal preset's model-facing contract at exactly two
124
- * tools. The TUI mounts ask_user_question at the host layer so every other
125
- * preset (including user presets) can use its questionnaire UI; host-layer
126
- * tools otherwise merge into Minimal's scoped catalog as a third tool.
123
+ * Keep the official Minimal preset's model-facing catalog minimal. The preset
124
+ * itself declares exactly one persistent shell tool (bash on POSIX, pwsh on
125
+ * Windows), while the TUI mounts ask_user_question at the host layer so every
126
+ * other preset (including user presets) can use its questionnaire UI —
127
+ * that host-layer tool otherwise merges into Minimal's scoped catalog as an
128
+ * extra tool.
127
129
  *
128
130
  * This is a per-assembly filter rather than a startup-time decision because
129
131
  * one TUI process can resume, create, or recompose sessions under different
@@ -1 +1 @@
1
- {"version":3,"file":"providerWizard.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/providerWizard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAsH,MAAM,sCAAsC,CAAA;AACjM,YAAY,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,aAAa,EAAE,cAAc,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAA;AAsBjM,OAAO,EAEL,KAAK,qBAAqB,EAE1B,KAAK,sBAAsB,EAC5B,MAAM,iCAAiC,CAAA;AACxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAE9D,iFAAiF;AACjF,eAAO,MAAM,iBAAiB,QAAoC,CAAA;AAElE,2EAA2E;AAC3E,eAAO,MAAM,kBAAkB,2EAIrB,CAAA;AAEV;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAA;IAChC,QAAQ,CAAC,GAAG,EAAE,CACZ,OAAO,EAAE,sBAAsB,EAC/B,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAC3B,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACnC,QAAQ,CAAC,MAAM,EAAE,CACf,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KACtE,IAAI,CAAA;IACT,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAA;IACrE,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAA;IAC/B,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CAC5E;AAED,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAA;AA4D3G;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,qBAAqB,CAAC,CA8BhC;AAo3BD,8DAA8D;AAC9D,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,QAAQ,GAAG,aAAa,CAAA;AACrE,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,QAAQ,GAAG,aAAa,CAAA;AACxE,MAAM,MAAM,oBAAoB,GAC5B,aAAa,GACb,qBAAqB,GACrB,gBAAgB,CAAA;AAEpB,qEAAqE;AACrE,MAAM,WAAW,cAAc;IAC7B;uEACmE;IACnE,QAAQ,CAAC,IAAI,EAAE,SAAS,kBAAkB,EAAE,CAAA;IAC5C,6EAA6E;IAC7E,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACxC,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAA;IACvC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAA;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAA;CACvC"}
1
+ {"version":3,"file":"providerWizard.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/providerWizard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAsH,MAAM,sCAAsC,CAAA;AACjM,YAAY,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,aAAa,EAAE,cAAc,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAA;AAsBjM,OAAO,EAEL,KAAK,qBAAqB,EAE1B,KAAK,sBAAsB,EAC5B,MAAM,iCAAiC,CAAA;AACxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAE9D,iFAAiF;AACjF,eAAO,MAAM,iBAAiB,QAAoC,CAAA;AAElE,2EAA2E;AAC3E,eAAO,MAAM,kBAAkB,2EAIrB,CAAA;AAEV;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAA;IAChC,QAAQ,CAAC,GAAG,EAAE,CACZ,OAAO,EAAE,sBAAsB,EAC/B,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAC3B,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACnC,QAAQ,CAAC,MAAM,EAAE,CACf,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KACtE,IAAI,CAAA;IACT,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAA;IACrE,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAA;IAC/B,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CAC5E;AAED,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAA;AA4D3G;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,qBAAqB,CAAC,CA8BhC;AAw3BD,8DAA8D;AAC9D,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,QAAQ,GAAG,aAAa,CAAA;AACrE,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,QAAQ,GAAG,aAAa,CAAA;AACxE,MAAM,MAAM,oBAAoB,GAC5B,aAAa,GACb,qBAAqB,GACrB,gBAAgB,CAAA;AAEpB,qEAAqE;AACrE,MAAM,WAAW,cAAc;IAC7B;uEACmE;IACnE,QAAQ,CAAC,IAAI,EAAE,SAAS,kBAAkB,EAAE,CAAA;IAC5C,6EAA6E;IAC7E,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACxC,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAA;IACvC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAA;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAA;CACvC"}
@@ -817,7 +817,9 @@ function buildDeleteSummary(provider) {
817
817
  /** Masked state line for one provider row in the OAuth pick question. */
818
818
  function oauthStateDescription(status) {
819
819
  if (status.signedIn) {
820
- return t('provider-oauth-state-in', { time: new Date(status.expiresAt ?? 0).toISOString() });
820
+ return status.expiresAt === undefined
821
+ ? t('provider-oauth-state-in-no-expiry')
822
+ : t('provider-oauth-state-in', { time: new Date(status.expiresAt).toISOString() });
821
823
  }
822
824
  return status.expired
823
825
  ? t('provider-oauth-state-expired')
@@ -872,7 +874,9 @@ async function runOAuthWizard(deps, oauth) {
872
874
  pushLocal('/provider', [
873
875
  t('provider-line-oauth-provider', { provider: result.provider }),
874
876
  t('provider-line-oauth-flow', { flow: result.oauthLabel }),
875
- t('provider-line-oauth-expires', { time: new Date(result.expiresAt).toISOString() }),
877
+ ...(result.expiresAt === undefined
878
+ ? []
879
+ : [t('provider-line-oauth-expires', { time: new Date(result.expiresAt).toISOString() })]),
876
880
  t('provider-switch-hint'),
877
881
  ]);
878
882
  notify(t('provider-oauth-login-ok', { provider: result.provider }), { color: 'success' });
@@ -32,6 +32,7 @@ export declare class SubagentActivityStore {
32
32
  live?: boolean;
33
33
  provider?: string;
34
34
  model?: string;
35
+ mode?: 'one-shot' | 'continuable' | 'unknown';
35
36
  }): void;
36
37
  linkSession(agentId: string, session: unknown): void;
37
38
  getSubagentIdBySession(session: unknown): string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"subagents.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/subagents.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"subagents.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/subagents.ts"],"names":[],"mappings":"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"}
@@ -89,8 +89,16 @@ export class SubagentActivityStore {
89
89
  * row running; an idle historical child shows as `unknown` (the parent log
90
90
  * alone cannot prove how its last epoch ended). */
91
91
  onDiscovered(agentId, info = {}) {
92
- if (this.states.has(agentId))
92
+ const existing = this.states.get(agentId);
93
+ if (existing !== undefined) {
94
+ // A bus edge usually created the row first; the durable catalog fact
95
+ // still carries the one thing the edge never knows — the mode.
96
+ if (info.mode !== undefined && existing.mode === undefined) {
97
+ existing.mode = info.mode;
98
+ this.notify();
99
+ }
93
100
  return;
101
+ }
94
102
  this.states.set(agentId, {
95
103
  agentId,
96
104
  description: info.label ?? `${info.provider ?? 'subagent'} task`,
@@ -99,6 +107,7 @@ export class SubagentActivityStore {
99
107
  status: info.live ? 'running' : 'unknown',
100
108
  startedAt: info.childCreatedAt ?? Date.now(),
101
109
  sessionId: agentId,
110
+ ...(info.mode === undefined ? {} : { mode: info.mode }),
102
111
  output: [],
103
112
  outputEvents: [],
104
113
  toolCalls: [],