@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
@@ -28,6 +28,11 @@ export type TerminalQuery<T extends TerminalResponse = TerminalResponse> = {
28
28
  request: string;
29
29
  /** Recognizes the expected response in the inbound stream */
30
30
  match: (r: TerminalResponse) => r is T;
31
+ /** The response type this query can be answered by, declared separately
32
+ * from `match` (a predicate cannot be introspected). The input parser
33
+ * reads it through {@link TerminalQuerier.pendingResponseTypes} to bind
34
+ * an ambiguous reply tail to the queries actually awaiting an answer. */
35
+ responseType: TerminalResponse['type'];
31
36
  };
32
37
  type DecrpmResponse = Extract<TerminalResponse, {
33
38
  type: 'decrpm';
@@ -139,6 +144,26 @@ export declare class TerminalQuerier {
139
144
  constructor(stdout: NodeJS.WriteStream, setRawMode?: ((enabled: boolean) => void) | undefined);
140
145
  /** Whether terminal query I/O is paused for an external process handoff. */
141
146
  get isSuspended(): boolean;
147
+ /**
148
+ * In-flight evidence for the input parser (read-only observation): true
149
+ * while at least one query or flush sentinel is still waiting for its
150
+ * reply. Purely observational — queue semantics are untouched.
151
+ */
152
+ get hasPending(): boolean;
153
+ /**
154
+ * In-flight evidence for the input parser (read-only observation): the
155
+ * response types of the queries still awaiting a reply, plus `da1` when a
156
+ * flush() sentinel is still open (DA1 is the reply that resolves it).
157
+ *
158
+ * This is bound to the query lifecycle on purpose. A boolean "something
159
+ * was sent recently" lets any recent query authorize a claim for bytes
160
+ * that may belong to no query at all, so the parser receives the expected
161
+ * types instead: a reply tail is only claimed when its shape can complete
162
+ * into one of them, and a query resolved by a sentinel stops counting the
163
+ * moment its promise settles. Purely observational — queue semantics are
164
+ * untouched.
165
+ */
166
+ get pendingResponseTypes(): ReadonlySet<TerminalResponse['type']>;
142
167
  private holdRawMode;
143
168
  /**
144
169
  * Send a query and wait for its response.
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-querier.d.ts","sourceRoot":"","sources":["../../../src/ink/terminal-querier.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"terminal-querier.d.ts","sourceRoot":"","sources":["../../../src/ink/terminal-querier.ts"],"names":[],"mappings":"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"}
@@ -32,6 +32,7 @@ export function decrqm(mode) {
32
32
  return {
33
33
  request: csi(`?${mode}$p`),
34
34
  match: (r) => r.type === 'decrpm' && r.mode === mode,
35
+ responseType: 'decrpm',
35
36
  };
36
37
  }
37
38
  /**
@@ -44,6 +45,7 @@ export function da1() {
44
45
  return {
45
46
  request: csi('c'),
46
47
  match: (r) => r.type === 'da1',
48
+ responseType: 'da1',
47
49
  };
48
50
  }
49
51
  /**
@@ -54,6 +56,7 @@ export function da2() {
54
56
  return {
55
57
  request: csi('>c'),
56
58
  match: (r) => r.type === 'da2',
59
+ responseType: 'da2',
57
60
  };
58
61
  }
59
62
  /**
@@ -65,6 +68,7 @@ export function kittyKeyboard() {
65
68
  return {
66
69
  request: csi('?u'),
67
70
  match: (r) => r.type === 'kittyKeyboard',
71
+ responseType: 'kittyKeyboard',
68
72
  };
69
73
  }
70
74
  /**
@@ -78,6 +82,7 @@ export function kittyGraphics(imageId) {
78
82
  // same direct-data + compression path used by real renderer uploads.
79
83
  request: `\u001b_Gi=${id},s=1,v=1,a=q,t=d,f=32,o=z;eAFjYGBgAAAABAAB\u001b\\`,
80
84
  match: (r) => r.type === 'kittyGraphics' && r.imageId === id,
85
+ responseType: 'kittyGraphics',
81
86
  };
82
87
  }
83
88
  /** XTWINOPS: query the physical pixel dimensions of one terminal cell. */
@@ -85,6 +90,7 @@ export function terminalCellSizePixels() {
85
90
  return {
86
91
  request: csi('16t'),
87
92
  match: (r) => r.type === 'terminalPixelSize' && r.scope === 'cell',
93
+ responseType: 'terminalPixelSize',
88
94
  };
89
95
  }
90
96
  /** XTWINOPS: query the terminal text area's physical pixel dimensions. */
@@ -92,6 +98,7 @@ export function terminalWindowSizePixels() {
92
98
  return {
93
99
  request: csi('14t'),
94
100
  match: (r) => r.type === 'terminalPixelSize' && r.scope === 'window',
101
+ responseType: 'terminalPixelSize',
95
102
  };
96
103
  }
97
104
  /**
@@ -105,6 +112,7 @@ export function cursorPosition() {
105
112
  return {
106
113
  request: csi('?6n'),
107
114
  match: (r) => r.type === 'cursorPosition',
115
+ responseType: 'cursorPosition',
108
116
  };
109
117
  }
110
118
  /**
@@ -117,6 +125,7 @@ export function oscColor(code) {
117
125
  return {
118
126
  request: osc(code, '?'),
119
127
  match: (r) => r.type === 'osc' && r.code === code,
128
+ responseType: 'osc',
120
129
  };
121
130
  }
122
131
  /**
@@ -131,6 +140,7 @@ export function xtversion() {
131
140
  return {
132
141
  request: csi('>0q'),
133
142
  match: (r) => r.type === 'xtversion',
143
+ responseType: 'xtversion',
134
144
  };
135
145
  }
136
146
  // -- Querier --
@@ -166,6 +176,37 @@ export class TerminalQuerier {
166
176
  get isSuspended() {
167
177
  return this.suspended;
168
178
  }
179
+ /**
180
+ * In-flight evidence for the input parser (read-only observation): true
181
+ * while at least one query or flush sentinel is still waiting for its
182
+ * reply. Purely observational — queue semantics are untouched.
183
+ */
184
+ get hasPending() {
185
+ return this.queue.length > 0;
186
+ }
187
+ /**
188
+ * In-flight evidence for the input parser (read-only observation): the
189
+ * response types of the queries still awaiting a reply, plus `da1` when a
190
+ * flush() sentinel is still open (DA1 is the reply that resolves it).
191
+ *
192
+ * This is bound to the query lifecycle on purpose. A boolean "something
193
+ * was sent recently" lets any recent query authorize a claim for bytes
194
+ * that may belong to no query at all, so the parser receives the expected
195
+ * types instead: a reply tail is only claimed when its shape can complete
196
+ * into one of them, and a query resolved by a sentinel stops counting the
197
+ * moment its promise settles. Purely observational — queue semantics are
198
+ * untouched.
199
+ */
200
+ get pendingResponseTypes() {
201
+ const types = new Set();
202
+ for (const pending of this.queue) {
203
+ if (pending.kind === 'query')
204
+ types.add(pending.responseType);
205
+ else
206
+ types.add('da1');
207
+ }
208
+ return types;
209
+ }
169
210
  holdRawMode() {
170
211
  this.setRawMode?.(true);
171
212
  return () => this.setRawMode?.(false);
@@ -190,6 +231,7 @@ export class TerminalQuerier {
190
231
  this.queue.push({
191
232
  kind: 'query',
192
233
  match: query.match,
234
+ responseType: query.responseType,
193
235
  resolve: r => resolve(r),
194
236
  releaseRawMode: this.holdRawMode(),
195
237
  });
@@ -58,5 +58,29 @@ export declare function swallowNestedUpdateOverflow(error: unknown, source: stri
58
58
  * @param onChange - The subscriber callback about to run.
59
59
  */
60
60
  export declare function callWithUpdateOverflowGuard(source: string, onChange: () => void): void;
61
+ /**
62
+ * Origin of a process-level fatal error, as reported to the sink.
63
+ */
64
+ export type ProcessGuardOrigin = 'uncaughtException' | 'unhandledRejection';
65
+ /**
66
+ * Fatal-error sink installed by the process owner (the dsh-tui runtime, which
67
+ * routes it into the TUI's single exit funnel). Returning true means the sink
68
+ * took ownership of the process — it runs the teardown (resume marker,
69
+ * terminal restore, `dsh-tui crashed: …`) and exits non-zero. Returning false
70
+ * leaves the error to Node's default crash, which keeps "fail loud, non-zero"
71
+ * true when no sink is registered or the tree is being torn down.
72
+ */
73
+ export type ProcessGuardFatalSink = (error: unknown, origin: ProcessGuardOrigin) => boolean;
74
+ /** Register (or clear, with undefined) the fatal-error sink. */
75
+ export declare function registerProcessGuardFatalSink(sink: ProcessGuardFatalSink | undefined): void;
76
+ /**
77
+ * Normalize the reason handed to a fatal sink so the exit funnel can never
78
+ * mistake a fatal error for a clean user exit. `Promise.reject()` and
79
+ * `throw undefined` deliver `undefined`, and the funnel selects its crash path
80
+ * with `error !== undefined` — passing the raw reason through would run the
81
+ * zero-exit path while the sink reported that it owned the process. Defined
82
+ * reasons (including non-Error values) are returned unchanged.
83
+ */
84
+ export declare function fatalReasonForExit(error: unknown, origin: ProcessGuardOrigin): unknown;
61
85
  export declare function installNestedUpdateOverflowProcessGuard(): void;
62
86
  //# sourceMappingURL=update-overflow-guard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"update-overflow-guard.d.ts","sourceRoot":"","sources":["../../../src/ink/update-overflow-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAoBH,2EAA2E;AAC3E,MAAM,MAAM,cAAc,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;AAOjD,+CAA+C;AAC/C,wBAAgB,+BAA+B,IAAI,IAAI,CAEtD;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,CAEnF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAG9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAmDnF;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAOtF;AAeD,wBAAgB,uCAAuC,IAAI,IAAI,CAc9D"}
1
+ {"version":3,"file":"update-overflow-guard.d.ts","sourceRoot":"","sources":["../../../src/ink/update-overflow-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAoBH,2EAA2E;AAC3E,MAAM,MAAM,cAAc,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;AAOjD,+CAA+C;AAC/C,wBAAgB,+BAA+B,IAAI,IAAI,CAEtD;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,CAEnF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAG9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAmDnF;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAOtF;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,GAAG,oBAAoB,CAAA;AAE3E;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,kBAAkB,KAAK,OAAO,CAAA;AAG3F,gEAAgE;AAChE,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,qBAAqB,GAAG,SAAS,GAAG,IAAI,CAE3F;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAEtF;AAiBD,wBAAgB,uCAAuC,IAAI,IAAI,CAgB9D"}
@@ -130,6 +130,22 @@ export function callWithUpdateOverflowGuard(source, onChange) {
130
130
  throw error;
131
131
  }
132
132
  }
133
+ let fatalSink;
134
+ /** Register (or clear, with undefined) the fatal-error sink. */
135
+ export function registerProcessGuardFatalSink(sink) {
136
+ fatalSink = sink;
137
+ }
138
+ /**
139
+ * Normalize the reason handed to a fatal sink so the exit funnel can never
140
+ * mistake a fatal error for a clean user exit. `Promise.reject()` and
141
+ * `throw undefined` deliver `undefined`, and the funnel selects its crash path
142
+ * with `error !== undefined` — passing the raw reason through would run the
143
+ * zero-exit path while the sink reported that it owned the process. Defined
144
+ * reasons (including non-Error values) are returned unchanged.
145
+ */
146
+ export function fatalReasonForExit(error, origin) {
147
+ return error === undefined ? new Error(`${origin} with undefined reason`) : error;
148
+ }
133
149
  /**
134
150
  * Process-level backstop for the overflow error. The hotspot guards above
135
151
  * cover the known enqueue sites (clock tick, reveal tick, channel emit,
@@ -138,9 +154,11 @@ export function callWithUpdateOverflowGuard(source, onChange) {
138
154
  * feeder, a future timer, a plugin's store) would still kill the process.
139
155
  * This installs uncaughtException/unhandledRejection handlers that absorb
140
156
  * exactly the overflow error class (same self-healing contract: React
141
- * already reset the counter before throwing) and rethrow everything else
142
- * unchanged. Idempotent; opt out with DSH_TUI_NO_185_PROCESS_GUARD=1 when a
143
- * host owns process error policy.
157
+ * already reset the counter before throwing) and hand everything else to the
158
+ * registered fatal sink — or rethrow it unchanged when there is none, so the
159
+ * process still fails loud with a non-zero exit rather than continuing in an
160
+ * unknown state. Idempotent; opt out with DSH_TUI_NO_185_PROCESS_GUARD=1 when
161
+ * a host owns process error policy.
144
162
  */
145
163
  let processGuardInstalled = false;
146
164
  export function installNestedUpdateOverflowProcessGuard() {
@@ -152,6 +170,8 @@ export function installNestedUpdateOverflowProcessGuard() {
152
170
  process.on('uncaughtException', error => {
153
171
  if (swallowNestedUpdateOverflow(error, 'process.uncaught'))
154
172
  return;
173
+ if (fatalSink?.(error, 'uncaughtException') === true)
174
+ return;
155
175
  // Unknown errors keep Node's default semantics: rethrowing from a
156
176
  // listener crashes the process with the original error.
157
177
  throw error;
@@ -159,6 +179,8 @@ export function installNestedUpdateOverflowProcessGuard() {
159
179
  process.on('unhandledRejection', error => {
160
180
  if (swallowNestedUpdateOverflow(error, 'process.rejection'))
161
181
  return;
182
+ if (fatalSink?.(error, 'unhandledRejection') === true)
183
+ return;
162
184
  throw error;
163
185
  });
164
186
  }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Minimal UI: one process-wide flag gating decorative UI (header splash,
3
+ * emoji status glyphs, non-tool text colors, status-bar extras). The flag is
4
+ * owned by the channel (settings key `dsh-tui.minimal`, applied live through
5
+ * scope.watch); leaf components read it here instead of threading a prop
6
+ * through four render layers. Code highlighting and tool-name colors are
7
+ * deliberately NOT gated — the minimal UI keeps those.
8
+ *
9
+ * This is the INTERFACE switch only. It is unrelated to the kernel's agent
10
+ * preset `minimal` (极简模式 / "Minimal"), which changes the model-facing
11
+ * world (a single persistent-shell tool — bash on POSIX, pwsh on Windows —
12
+ * with no compaction, no plan mode and no runtime context). Renamed from
13
+ * `minimalMode` so the two concepts cannot be read as one.
14
+ */
15
+ /** True when the minimal UI is active (settings key `dsh-tui.minimal`). */
16
+ export declare function isMinimalUiMode(): boolean;
17
+ /** @internal channel-owned setter; also called once at boot. */
18
+ export declare function setMinimalUiMode(enabled: boolean): void;
19
+ //# sourceMappingURL=minimalUiMode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"minimalUiMode.d.ts","sourceRoot":"","sources":["../../src/minimalUiMode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,2EAA2E;AAC3E,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEvD"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Minimal UI: one process-wide flag gating decorative UI (header splash,
3
+ * emoji status glyphs, non-tool text colors, status-bar extras). The flag is
4
+ * owned by the channel (settings key `dsh-tui.minimal`, applied live through
5
+ * scope.watch); leaf components read it here instead of threading a prop
6
+ * through four render layers. Code highlighting and tool-name colors are
7
+ * deliberately NOT gated — the minimal UI keeps those.
8
+ *
9
+ * This is the INTERFACE switch only. It is unrelated to the kernel's agent
10
+ * preset `minimal` (极简模式 / "Minimal"), which changes the model-facing
11
+ * world (a single persistent-shell tool — bash on POSIX, pwsh on Windows —
12
+ * with no compaction, no plan mode and no runtime context). Renamed from
13
+ * `minimalMode` so the two concepts cannot be read as one.
14
+ */
15
+ let minimalUi = false;
16
+ /** True when the minimal UI is active (settings key `dsh-tui.minimal`). */
17
+ export function isMinimalUiMode() {
18
+ return minimalUi;
19
+ }
20
+ /** @internal channel-owned setter; also called once at boot. */
21
+ export function setMinimalUiMode(enabled) {
22
+ minimalUi = enabled;
23
+ }
@@ -1,15 +1,10 @@
1
1
  /**
2
- * Re-export of the `@deepseek-harness-tui/dsh-auth` plugin under this
3
- * package's own name, so the bundle patch layer can mount the OAuth row as
4
- * `@deepseek-harness-tui/dsh-tui/oauth` instead of the bare package name —
5
- * the same anchor the working-activity row uses (#60): the dsh Loader
6
- * resolves row names from the *profile* directory, where only the profile's
7
- * direct dependencies are linked, and pnpm's isolated layout never hoists a
8
- * transitive dependency there. Mounting through this subpath keeps plugin
9
- * resolution anchored at @deepseek-harness-tui/dsh-tui itself, always a
10
- * direct profile dependency, under every package-manager layout.
2
+ * Public entry for the built-in OAuth Cordis module. The bundle patch keeps
3
+ * mounting this subpath so existing profile overrides and loader ordering
4
+ * remain compatible after the former dsh-auth package was folded into the
5
+ * TUI's adapter tree.
11
6
  *
12
7
  * @module @deepseek-harness-tui/dsh-tui/oauth
13
8
  */
14
- export * from '@deepseek-harness-tui/dsh-auth';
9
+ export * from './dsh-adapter/oauth/index.js';
15
10
  //# sourceMappingURL=oauth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,cAAc,gCAAgC,CAAA"}
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,cAAc,8BAA8B,CAAA"}
@@ -1,14 +1,9 @@
1
1
  /**
2
- * Re-export of the `@deepseek-harness-tui/dsh-auth` plugin under this
3
- * package's own name, so the bundle patch layer can mount the OAuth row as
4
- * `@deepseek-harness-tui/dsh-tui/oauth` instead of the bare package name —
5
- * the same anchor the working-activity row uses (#60): the dsh Loader
6
- * resolves row names from the *profile* directory, where only the profile's
7
- * direct dependencies are linked, and pnpm's isolated layout never hoists a
8
- * transitive dependency there. Mounting through this subpath keeps plugin
9
- * resolution anchored at @deepseek-harness-tui/dsh-tui itself, always a
10
- * direct profile dependency, under every package-manager layout.
2
+ * Public entry for the built-in OAuth Cordis module. The bundle patch keeps
3
+ * mounting this subpath so existing profile overrides and loader ordering
4
+ * remain compatible after the former dsh-auth package was folded into the
5
+ * TUI's adapter tree.
11
6
  *
12
7
  * @module @deepseek-harness-tui/dsh-tui/oauth
13
8
  */
14
- export * from '@deepseek-harness-tui/dsh-auth';
9
+ export * from './dsh-adapter/oauth/index.js';
@@ -8,9 +8,10 @@ import type { TuiShortcutHost } from '../dsh-adapter/shortcuts.js';
8
8
  import type { TuiThemeHost } from '../dsh-adapter/themes.js';
9
9
  import { ApprovalStore } from '../dsh-adapter/approvals.js';
10
10
  import { type StarAttempt } from '../components/StarPrompt.js';
11
+ import type { WhaleCouponStore } from '../dsh-adapter/oauth/bonus.js';
11
12
  import { type PromptController } from '../components/PromptInput.js';
12
13
  import type { InjectController } from '../dsh-adapter/inject-channel.js';
13
- export declare function Chat({ channel, questionStore, approvalStore, extensionDialogs, extensionStatus, activityStore, extensionShortcuts, themeHost, onExit, onUpdate, onRestart, fullscreen, trajectorySeen: trajectorySeenProp, injectControllerRef, promptControllerRef: promptControllerRefProp, renderScene, openHomeOnBoot, starPrompt, }: {
14
+ export declare function Chat({ channel, questionStore, approvalStore, extensionDialogs, bonusNotices, extensionStatus, activityStore, extensionShortcuts, themeHost, onExit, onUpdate, onRestart, fullscreen, trajectorySeen: trajectorySeenProp, injectControllerRef, promptControllerRef: promptControllerRefProp, renderScene, openHomeOnBoot, starPrompt, }: {
14
15
  channel: Channel;
15
16
  renderScene?: (id: string, channel: Channel) => React.ReactNode;
16
17
  questionStore: QuestionStore;
@@ -26,6 +27,8 @@ export declare function Chat({ channel, questionStore, approvalStore, extensionD
26
27
  * park unanswered (their `timeoutMs` is the plugin's guard).
27
28
  */
28
29
  extensionDialogs?: TuiDialogStore;
30
+ /** Server-confirmed login bonuses awaiting presentation in the TUI. */
31
+ bonusNotices?: WhaleCouponStore;
29
32
  /** Plugin text and bounded rich status contributions. */
30
33
  extensionStatus?: TuiStatusStore;
31
34
  /** Session-scoped activity values published by the working-activity plugin. */
@@ -1 +1 @@
1
- {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/screens/Chat.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AA2BzB,OAAO,KAAK,EAAE,SAAS,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAA;AAE3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAwB,MAAM,0BAA0B,CAAA;AAC/E,OAAO,EAAE,aAAa,EAAe,MAAM,kCAAkC,CAAA;AAW7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAG5D,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAa3D,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAQ1E,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAEjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AA4NxE,wBAAgB,IAAI,CAAC,EACnB,OAAO,EACP,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,kBAAkB,EAClB,SAAS,EACT,MAAM,EACN,QAAQ,EACR,SAAS,EACT,UAAkB,EAClB,cAAc,EAAE,kBAAkB,EAClC,mBAAmB,EACnB,mBAAmB,EAAE,uBAAuB,EAC5C,WAAW,EACX,cAAc,EACd,UAAU,GACX,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,KAAK,CAAC,SAAS,CAAA;IAC/D,aAAa,EAAE,aAAa,CAAA;IAC5B;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,cAAc,CAAA;IACjC,yDAAyD;IACzD,eAAe,CAAC,EAAE,cAAc,CAAA;IAChC,+EAA+E;IAC/E,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,iDAAiD;IACjD,kBAAkB,CAAC,EAAE,eAAe,CAAA;IACpC,uEAAuE;IACvE,SAAS,CAAC,EAAE,YAAY,CAAA;IACxB,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;IAC9D;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,GAAG,IAAI,CAAA;IAC5G;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;CAC/D,4BAkvJA"}
1
+ {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/screens/Chat.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AA2BzB,OAAO,KAAK,EAAE,SAAS,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAA;AAE3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAwB,MAAM,0BAA0B,CAAA;AAC/E,OAAO,EAAE,aAAa,EAAe,MAAM,kCAAkC,CAAA;AAW7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAG5D,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAa3D,OAAO,EAAiC,KAAK,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAC7F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAQrE,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAEjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AA8NxE,wBAAgB,IAAI,CAAC,EACnB,OAAO,EACP,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,aAAa,EACb,kBAAkB,EAClB,SAAS,EACT,MAAM,EACN,QAAQ,EACR,SAAS,EACT,UAAkB,EAClB,cAAc,EAAE,kBAAkB,EAClC,mBAAmB,EACnB,mBAAmB,EAAE,uBAAuB,EAC5C,WAAW,EACX,cAAc,EACd,UAAU,GACX,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,KAAK,CAAC,SAAS,CAAA;IAC/D,aAAa,EAAE,aAAa,CAAA;IAC5B;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,cAAc,CAAA;IACjC,uEAAuE;IACvE,YAAY,CAAC,EAAE,gBAAgB,CAAA;IAC/B,yDAAyD;IACzD,eAAe,CAAC,EAAE,cAAc,CAAA;IAChC,+EAA+E;IAC/E,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,iDAAiD;IACjD,kBAAkB,CAAC,EAAE,eAAe,CAAA;IACpC,uEAAuE;IACvE,SAAS,CAAC,EAAE,YAAY,CAAA;IACxB,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;IAC9D;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,GAAG,IAAI,CAAA;IAC5G;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;CAC/D,4BAywJA"}
@@ -43,7 +43,7 @@ import { useSelection } from '../ink/hooks/use-selection.js';
43
43
  import { NoSelect } from '../ink/components/NoSelect.js';
44
44
  import { LogoHeader, MessageList } from '../components/MessageList.js';
45
45
  import { splashFontIdOf } from '../components/splashFonts.js';
46
- import { StarPrompt } from '../components/StarPrompt.js';
46
+ import { StarPrompt, WhaleCouponPrompt } from '../components/StarPrompt.js';
47
47
  import { dueStarModal, markStarAsked, STAR_MILESTONES } from '../usageStats.js';
48
48
  import { TimelineRail } from '../components/TimelineRail.js';
49
49
  import { ScrollbarGutter } from '../components/ScrollbarGutter.js';
@@ -223,12 +223,14 @@ let fallbackDialogStore;
223
223
  let fallbackStatusStore;
224
224
  /** Standalone mounts (tests, bare embeds) without the composition root's store. */
225
225
  let fallbackActivityStore;
226
+ const noCouponSubscription = () => () => undefined;
227
+ const noCouponSnapshot = () => null;
226
228
  /** Identity of one caret-preview dismissal: the token (its title) on the
227
229
  * image, so the same image staged twice is dismissed per token. */
228
230
  function peekKey(image, title) {
229
231
  return `${title ?? ''} ${image.id}`;
230
232
  }
231
- export function Chat({ channel, questionStore, approvalStore, extensionDialogs, extensionStatus, activityStore, extensionShortcuts, themeHost, onExit, onUpdate, onRestart, fullscreen = false, trajectorySeen: trajectorySeenProp, injectControllerRef, promptControllerRef: promptControllerRefProp, renderScene, openHomeOnBoot, starPrompt, }) {
233
+ export function Chat({ channel, questionStore, approvalStore, extensionDialogs, bonusNotices, extensionStatus, activityStore, extensionShortcuts, themeHost, onExit, onUpdate, onRestart, fullscreen = false, trajectorySeen: trajectorySeenProp, injectControllerRef, promptControllerRef: promptControllerRefProp, renderScene, openHomeOnBoot, starPrompt, }) {
232
234
  const writeRaw = React.useContext(TerminalWriteContext);
233
235
  // Re-render whenever the channel mutates; rows/status are read fresh below.
234
236
  // DEFAULT lane on purpose (useExternalVersion): the channel version bumps
@@ -258,6 +260,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
258
260
  // extensions row share one inert store that never holds a dialog.
259
261
  const dialogs = extensionDialogs ?? (fallbackDialogStore ??= new TuiDialogStore());
260
262
  const dialogSnapshot = React.useSyncExternalStore(listener => dialogs.subscribe(listener), () => dialogs.getSnapshot());
263
+ const coupon = React.useSyncExternalStore(bonusNotices?.subscribe ?? noCouponSubscription, bonusNotices?.getSnapshot ?? noCouponSnapshot);
261
264
  // Plugin status contributions: text keys join into one line; bounded rich
262
265
  // views keep their own rows immediately above the prompt.
263
266
  const statusContributions = extensionStatus ?? (fallbackStatusStore ??= new TuiStatusStore());
@@ -2415,7 +2418,9 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2415
2418
  ...oauth.map(row => t('login-oauth-row', {
2416
2419
  provider: row.provider,
2417
2420
  state: row.signedIn
2418
- ? t('login-oauth-in', { time: new Date(row.expiresAt ?? 0).toISOString() })
2421
+ ? row.expiresAt === undefined
2422
+ ? t('login-oauth-in-no-expiry')
2423
+ : t('login-oauth-in', { time: new Date(row.expiresAt).toISOString() })
2419
2424
  : row.expired
2420
2425
  ? t('login-oauth-expired')
2421
2426
  : t('login-oauth-signed-out'),
@@ -3014,11 +3019,23 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3014
3019
  }, []);
3015
3020
  /** Deduplicate terminals that report one Enter as parsed Return then raw CR/LF. */
3016
3021
  const lastModalEnterAtRef = React.useRef(0);
3022
+ const couponVisible = coupon !== null && starModal === null
3023
+ && approvalSnapshot === null && dialogSnapshot === null && questionSnapshot === null
3024
+ && overlay.kind === 'none' && btw === null && recap === null
3025
+ && !supervisorOpen && !treeOpen && !settingsOpen && !jobsPanelOpen
3026
+ && !sceneOpen && !subagentDashboardOpen && subagentDetailId === null;
3027
+ const markCouponShown = React.useCallback((orderId) => {
3028
+ bonusNotices?.shown(orderId);
3029
+ }, [bonusNotices]);
3030
+ const closeCoupon = React.useCallback(() => {
3031
+ if (coupon !== null)
3032
+ bonusNotices?.dismiss(coupon.orderId);
3033
+ }, [bonusNotices, coupon]);
3017
3034
  useInput((input, key, event) => {
3018
3035
  // 开屏"求 star"弹窗开着时键盘全归它(↑/↓/Enter/Esc 由它自己的
3019
3036
  // useInput 处理),滚轮也不许滚动它身后的转录——和下面的整屏界面
3020
3037
  // 同一套让位规则。
3021
- if (starModal !== null)
3038
+ if (starModal !== null || couponVisible)
3022
3039
  return;
3023
3040
  // Prompt-slot panels own the keyboard while visible. Their own useInput
3024
3041
  // handles the relevant keys; Chat registered first, so yielding here
@@ -4030,7 +4047,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4030
4047
  // Who owns the spinner slot: with the working-activity line on, that slot
4031
4048
  // draws the user's `/activity` preset, so the compaction row borrows the same
4032
4049
  // indicator instead of answering with the classic dot.
4033
- const activitySlot = channel.activityEnabled && !channel.minimal;
4050
+ const activitySlot = channel.activityEnabled && !channel.minimalUi;
4034
4051
  // An automatic compaction runs INSIDE the turn, so it rides whichever spinner
4035
4052
  // the slot shows as a badge instead of a second row (the spinner's timer is
4036
4053
  // the turn's, not the compaction's).
@@ -4235,7 +4252,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4235
4252
  || (recap !== null && (!recap.auto || recap.expanded))
4236
4253
  || btw !== null
4237
4254
  || questionPanelNode !== null
4238
- || starModal !== null;
4255
+ || starModal !== null
4256
+ || couponVisible;
4239
4257
  // The trajectory scene replaces the conversation for as long as it is open.
4240
4258
  // Rendering it INSTEAD of (not above) the transcript is what makes it a
4241
4259
  // screen rather than an overlay: it owns the full viewport, and the
@@ -4392,6 +4410,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4392
4410
  band: wakeBand,
4393
4411
  hint: trajectorySeen ? undefined : primaryComboString('trajectory'),
4394
4412
  tick: Math.floor(wakeTime / 120),
4413
+ onOpen: openScene,
4414
+ hoverHint: primaryComboString('trajectory'),
4395
4415
  } }), dialogOverlayOpen && (_jsxs(OverlayAbove, { maxHeight: Math.max(terminalRows - 8, 1), children: [overlay.kind === 'thinking' && (_jsx(ThinkingToggle, { currentValue: thinkingVisible, focusIndex: overlay.focus, onPick: (index) => {
4396
4416
  // 点击行 = 设焦点 + 应用(与 Enter 同一条路径)
4397
4417
  const visible = index === 0;
@@ -4534,7 +4554,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4534
4554
  const path = overlay.path;
4535
4555
  dispatchOverlay({ type: 'close' });
4536
4556
  runFileAction(index, path);
4537
- } }) })), overlay.kind === 'search' && _jsx(TranscriptSearch, { query: searchQuery, cursorOffset: searchCursor, count: searchCount, current: searchCurrent })] }))] })] }), _jsx(TooltipLayer, { invalidationKey: `${overlay.kind}:${dialogOverlayOpen}:${btw !== null}`, subscribeInvalidation: subscribeTooltipInvalidation }), _jsx(PromptEditorLayer, {}), promptEditorOpen && imagePreviewNode, starModal !== null && STAR_MILESTONES[starModal.index] !== undefined && (_jsx(StarPrompt, { milestone: STAR_MILESTONES[starModal.index], actions: starModalActions, onClose: closeStarModal, initialPhase: starModal.phase }))] }));
4557
+ } }) })), overlay.kind === 'search' && _jsx(TranscriptSearch, { query: searchQuery, cursorOffset: searchCursor, count: searchCount, current: searchCurrent })] }))] })] }), _jsx(TooltipLayer, { invalidationKey: `${overlay.kind}:${dialogOverlayOpen}:${btw !== null}`, subscribeInvalidation: subscribeTooltipInvalidation }), _jsx(PromptEditorLayer, {}), promptEditorOpen && imagePreviewNode, starModal !== null && STAR_MILESTONES[starModal.index] !== undefined && (_jsx(StarPrompt, { milestone: STAR_MILESTONES[starModal.index], actions: starModalActions, onClose: closeStarModal, initialPhase: starModal.phase })), couponVisible && coupon !== null && (_jsx(WhaleCouponPrompt, { notice: coupon, onShown: markCouponShown, onClose: closeCoupon }))] }));
4538
4558
  }
4539
4559
  /**
4540
4560
  * The pinned prompt header shown above the ScrollBox while the user has
@@ -22,6 +22,10 @@ export declare function StatusLine({ channel, selectionActive, helpOpen, wake, a
22
22
  band: WaveBand;
23
23
  hint?: string;
24
24
  tick: number;
25
+ /** Click target for the strip: opens the trajectory scene. */
26
+ onOpen?: () => void;
27
+ /** Chord revealed while the pointer rests on the strip. */
28
+ hoverHint?: string;
25
29
  };
26
30
  }): React.JSX.Element;
27
31
  type UsageSnapshot = {
@@ -1 +1 @@
1
- {"version":3,"file":"StatusLine.d.ts","sourceRoot":"","sources":["../../../src/screens/StatusLine.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,OAAO,EAAoC,KAAK,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AAOxG,OAAO,KAAK,EAAE,SAAS,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAA;AAqB3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAqHvD,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,eAAuB,EACvB,QAAgB,EAChB,IAAI,EACJ,QAAQ,EAAE,iBAAiB,GAC5B,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;kFAC8E;IAC9E,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CACvD,qBA+aA;AAED,KAAK,aAAa,GAAG;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AA0LD,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAKvF;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EACL;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GACzD,SAAS,GACZ,MAAM,GAAG,SAAS,CAIpB"}
1
+ {"version":3,"file":"StatusLine.d.ts","sourceRoot":"","sources":["../../../src/screens/StatusLine.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,OAAO,EAAoC,KAAK,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AAOxG,OAAO,KAAK,EAAE,SAAS,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAA;AAqB3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAqHvD,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,eAAuB,EACvB,QAAgB,EAChB,IAAI,EACJ,QAAQ,EAAE,iBAAiB,GAC5B,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;kFAC8E;IAC9E,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE;QACL,IAAI,EAAE,QAAQ,CAAA;QACd,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,8DAA8D;QAC9D,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;QACnB,2DAA2D;QAC3D,SAAS,CAAC,EAAE,MAAM,CAAA;KACnB,CAAA;CACF,qBA+aA;AAED,KAAK,aAAa,GAAG;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AA0LD,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAKvF;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EACL;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GACzD,SAAS,GACZ,MAAM,GAAG,SAAS,CAIpB"}
@@ -38,20 +38,20 @@ import { FREE_SEGMENT_FILL, USED_SEGMENTS, contextBarBreakdown, renderMiniContex
38
38
  * own, so hovering it is how its colors get their names and numbers.
39
39
  */
40
40
  /**
41
- * Minimal mode's footer config. It ignores every SAVED preference (built from
41
+ * The minimal UI's footer config. It ignores every SAVED preference (built from
42
42
  * scratch rather than `normalizeStatusBar(channel.statusBar)`) and pins the
43
43
  * DECORATION switches OFF — the shared defaults are free to change
44
- * (`contextBar` became default-on in 2026-09) and minimal mode must not follow
44
+ * (`contextBar` became default-on in 2026-09) and the minimal UI must not follow
45
45
  * them into the footer.
46
46
  *
47
- * The metric fields keep their `DEFAULT_STATUS_BAR` values on purpose: minimal
48
- * mode has ALWAYS shown the default-on metrics (thinking / contextUsage /
47
+ * The metric fields keep their `DEFAULT_STATUS_BAR` values on purpose: the
48
+ * minimal UI has ALWAYS shown the default-on metrics (thinking / contextUsage /
49
49
  * cache / cost / goal) next to model + cwd — that predates the long-line fold
50
50
  * and the context-bar flip, and trimming them further is a product decision,
51
51
  * not a regression fix. Module scope: one frozen object, no per-render
52
52
  * allocation.
53
53
  */
54
- const MINIMAL_STATUS_BAR = Object.freeze({
54
+ const MINIMAL_UI_STATUS_BAR = Object.freeze({
55
55
  ...DEFAULT_STATUS_BAR,
56
56
  compact: true,
57
57
  model: true,
@@ -82,10 +82,10 @@ export function StatusLine({ channel, selectionActive = false, helpOpen = false,
82
82
  // not clobber the field it entered.
83
83
  onMouseLeave: () => setHover(current => (current === id ? null : current)),
84
84
  }), []);
85
- const statusBar = channel.minimal
86
- // Minimal mode overrides every field switch: model + cwd only, so the
85
+ const statusBar = channel.minimalUi
86
+ // The minimal UI overrides every field switch: model + cwd only, so the
87
87
  // footer can never grow decorations regardless of saved preferences.
88
- ? MINIMAL_STATUS_BAR
88
+ ? MINIMAL_UI_STATUS_BAR
89
89
  : normalizeStatusBar(channel.statusBar);
90
90
  // Provider workspaces expose a remote display path alongside a host alias;
91
91
  // only the local target has identical cwd/displayCwd values to fold.
@@ -259,7 +259,7 @@ export function StatusLine({ channel, selectionActive = false, helpOpen = false,
259
259
  ? [{
260
260
  key: 'goal',
261
261
  id: 'goal',
262
- node: _jsx(GoalStatusChip, { goal: channel.goal, minimal: channel.minimal }),
262
+ node: _jsx(GoalStatusChip, { goal: channel.goal, minimal: channel.minimalUi }),
263
263
  }]
264
264
  : []),
265
265
  ...(statusBar.gitBranch && channel.gitBranch
@@ -345,13 +345,13 @@ export function StatusLine({ channel, selectionActive = false, helpOpen = false,
345
345
  // on hover is what made the footer grow mid-gesture and shoved the
346
346
  // transcript up (user feedback). Idle it may sit blank: a stable footer
347
347
  // outranks a reclaimable row, and hovering only ever swaps this line's
348
- // content. Minimal mode keeps the old contract — no hover details, the
348
+ // content. The minimal UI keeps the old contract — no hover details, the
349
349
  // row appears only for real content (which its defaults never produce).
350
- const showSupplementalRow = (!channel.minimal && (hasStatusFields || barVisible)) ||
350
+ const showSupplementalRow = (!channel.minimalUi && (hasStatusFields || barVisible)) ||
351
351
  showActivity ||
352
352
  showTrajectory ||
353
353
  hint !== '';
354
- return (_jsx(Box, { paddingX: 1, width: columns, flexShrink: 0, children: _jsxs(Box, { flexDirection: "column", width: "100%", children: [barVisible ? (_jsx(ContextBarView, { segments: channel.contextSegments, usedTokens: contextUsed ?? 0, contextWindow: channel.contextWindow ?? 0, width: barWidth, colors: barColors, onHover: hovered => setHover(current => hovered ? 'bar' : current === 'bar' ? null : current) })) : null, hasStatusFields ? statusBar.compact ? (_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", gap: 2, children: [_jsx(Box, { flexGrow: 1, flexShrink: 1, flexDirection: "row", overflow: "hidden", children: _jsx(FieldLine, { parts: compactFields, hoverProps: hoverProps }) }), ctxNode !== undefined ? (_jsx(Box, { flexShrink: 0, ...hoverProps('ctx'), children: _jsx(Text, { wrap: "truncate", children: ctxNode }) })) : null] })) : (_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", gap: 2, children: [_jsx(Box, { flexGrow: 1, flexShrink: 1, flexDirection: "row", overflow: "hidden", children: _jsx(FieldLine, { parts: fullLeftFields, hoverProps: hoverProps }) }), _jsx(Box, { justifyContent: "flex-end", flexShrink: 2, flexDirection: "row", overflow: "hidden", children: _jsx(FieldLine, { parts: rightFields, hoverProps: hoverProps }) })] })) : null, showSupplementalRow ? _jsxs(Box, { height: 1, overflow: "hidden", flexDirection: "row", justifyContent: "space-between", gap: 2, children: [_jsxs(Box, { flexDirection: "row", flexGrow: 1, justifyContent: showActivity && trailer !== null ? 'space-between' : 'flex-start', gap: 2, children: [showActivity && activity !== undefined ? (_jsx(ActivityLine, { activity: activity, activityFrames: channel.activityFrames, warnPct: contextPressurePct(usage, channel.contextWindow), warnDanger: (contextPressurePct(usage, channel.contextWindow) ?? 0) >= 95 })) : trailer, showActivity ? trailer : null] }), showTrajectory && wake !== undefined ? (_jsx(MiniWake, { band: wake.band, hint: wake.hint, tick: wake.tick })) : null] }) : null] }) }));
354
+ return (_jsx(Box, { paddingX: 1, width: columns, flexShrink: 0, children: _jsxs(Box, { flexDirection: "column", width: "100%", children: [barVisible ? (_jsx(ContextBarView, { segments: channel.contextSegments, usedTokens: contextUsed ?? 0, contextWindow: channel.contextWindow ?? 0, width: barWidth, colors: barColors, onHover: hovered => setHover(current => hovered ? 'bar' : current === 'bar' ? null : current) })) : null, hasStatusFields ? statusBar.compact ? (_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", gap: 2, children: [_jsx(Box, { flexGrow: 1, flexShrink: 1, flexDirection: "row", overflow: "hidden", children: _jsx(FieldLine, { parts: compactFields, hoverProps: hoverProps }) }), ctxNode !== undefined ? (_jsx(Box, { flexShrink: 0, ...hoverProps('ctx'), children: _jsx(Text, { wrap: "truncate", children: ctxNode }) })) : null] })) : (_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", gap: 2, children: [_jsx(Box, { flexGrow: 1, flexShrink: 1, flexDirection: "row", overflow: "hidden", children: _jsx(FieldLine, { parts: fullLeftFields, hoverProps: hoverProps }) }), _jsx(Box, { justifyContent: "flex-end", flexShrink: 2, flexDirection: "row", overflow: "hidden", children: _jsx(FieldLine, { parts: rightFields, hoverProps: hoverProps }) })] })) : null, showSupplementalRow ? _jsxs(Box, { height: 1, overflow: "hidden", flexDirection: "row", justifyContent: "space-between", gap: 2, children: [_jsxs(Box, { flexDirection: "row", flexGrow: 1, justifyContent: showActivity && trailer !== null ? 'space-between' : 'flex-start', gap: 2, children: [showActivity && activity !== undefined ? (_jsx(ActivityLine, { activity: activity, activityFrames: channel.activityFrames, warnPct: contextPressurePct(usage, channel.contextWindow), warnDanger: (contextPressurePct(usage, channel.contextWindow) ?? 0) >= 95 })) : trailer, showActivity ? trailer : null] }), showTrajectory && wake !== undefined ? (_jsx(MiniWake, { band: wake.band, hint: wake.hint, tick: wake.tick, onOpen: wake.onOpen, hoverHint: wake.hoverHint })) : null] }) : null] }) }));
355
355
  }
356
356
  /**
357
357
  * The supplemental-row readout for a hovered footer field. Technical label
@@ -124,11 +124,11 @@ export const SETTING_DEFINITIONS = {
124
124
  kind: 'boolean',
125
125
  },
126
126
  'minimal': {
127
- label: 'Minimal mode',
128
- descriptions: { zh: '极简模式' },
127
+ label: 'Minimal UI',
128
+ descriptions: { zh: '极简界面' },
129
129
  group: 'appearance',
130
- hint: 'Hide the header splash, emoji glyphs, and decorative colors; code highlight and tool colors stay. Trims the status bar to model + cwd.',
131
- hintDescriptions: { zh: '隐藏开屏头部、emoji 状态符与装饰性配色;代码高亮与工具配色保留,底栏只留模型与目录。' },
130
+ hint: 'Interface only: hide the header splash, emoji glyphs and decorative colors, and trim the status bar to model + cwd; code highlight and tool colors stay. NOT the agent preset — the kernel\'s own `minimal` preset is a separate, model-facing choice that decides which tools the model can use (see /preset).',
131
+ hintDescriptions: { zh: '只精简界面:隐藏开屏头部、emoji 状态符与装饰性配色,底栏只留模型与目录;代码高亮与工具配色保留。这是界面开关,不是 Agent 预设——模型能用哪些工具由内核预设决定(见 /preset)。' },
132
132
  kind: 'boolean',
133
133
  },
134
134
  'pageMargin': {