open-multi-agent-kit 0.95.1 → 0.96.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 (306) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +16 -1
  3. package/dist/approvals/approval-receipt-store.d.ts +18 -0
  4. package/dist/approvals/approval-receipt-store.d.ts.map +1 -0
  5. package/dist/approvals/approval-receipt-store.js +194 -0
  6. package/dist/approvals/approval-receipt-store.js.map +1 -0
  7. package/dist/approvals/approval-receipt.d.ts +43 -0
  8. package/dist/approvals/approval-receipt.d.ts.map +1 -0
  9. package/dist/approvals/approval-receipt.js +208 -0
  10. package/dist/approvals/approval-receipt.js.map +1 -0
  11. package/dist/approvals/approval-verifier.d.ts +17 -0
  12. package/dist/approvals/approval-verifier.d.ts.map +1 -0
  13. package/dist/approvals/approval-verifier.js +23 -0
  14. package/dist/approvals/approval-verifier.js.map +1 -0
  15. package/dist/approvals/plannotator-approval-bridge.d.ts +58 -0
  16. package/dist/approvals/plannotator-approval-bridge.d.ts.map +1 -0
  17. package/dist/approvals/plannotator-approval-bridge.js +169 -0
  18. package/dist/approvals/plannotator-approval-bridge.js.map +1 -0
  19. package/dist/cli/args.d.ts.map +1 -1
  20. package/dist/cli/args.js +2 -0
  21. package/dist/cli/args.js.map +1 -1
  22. package/dist/commands/package-doctor-cli.d.ts +13 -0
  23. package/dist/commands/package-doctor-cli.d.ts.map +1 -0
  24. package/dist/commands/package-doctor-cli.js +80 -0
  25. package/dist/commands/package-doctor-cli.js.map +1 -0
  26. package/dist/commands/router-feedback-cli.d.ts +11 -0
  27. package/dist/commands/router-feedback-cli.d.ts.map +1 -0
  28. package/dist/commands/router-feedback-cli.js +99 -0
  29. package/dist/commands/router-feedback-cli.js.map +1 -0
  30. package/dist/commands/stats-cli.d.ts +20 -0
  31. package/dist/commands/stats-cli.d.ts.map +1 -0
  32. package/dist/commands/stats-cli.js +99 -0
  33. package/dist/commands/stats-cli.js.map +1 -0
  34. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  35. package/dist/core/agent-session-runtime.js +4 -1
  36. package/dist/core/agent-session-runtime.js.map +1 -1
  37. package/dist/core/agent-session.d.ts +99 -31
  38. package/dist/core/agent-session.d.ts.map +1 -1
  39. package/dist/core/agent-session.js +624 -216
  40. package/dist/core/agent-session.js.map +1 -1
  41. package/dist/core/bash-executor.d.ts.map +1 -1
  42. package/dist/core/bash-executor.js +8 -2
  43. package/dist/core/bash-executor.js.map +1 -1
  44. package/dist/core/compaction/transaction.d.ts +9 -0
  45. package/dist/core/compaction/transaction.d.ts.map +1 -1
  46. package/dist/core/compaction/transaction.js +17 -2
  47. package/dist/core/compaction/transaction.js.map +1 -1
  48. package/dist/core/context-budget-governor-v2.d.ts +1 -1
  49. package/dist/core/context-budget-governor-v2.d.ts.map +1 -1
  50. package/dist/core/context-budget-governor-v2.js +1 -1
  51. package/dist/core/context-budget-governor-v2.js.map +1 -1
  52. package/dist/core/context-budget-system-prompt.d.ts.map +1 -1
  53. package/dist/core/context-budget-system-prompt.js +18 -2
  54. package/dist/core/context-budget-system-prompt.js.map +1 -1
  55. package/dist/core/context-budget-v2-cache-disk.d.ts +109 -0
  56. package/dist/core/context-budget-v2-cache-disk.d.ts.map +1 -0
  57. package/dist/core/context-budget-v2-cache-disk.js +343 -0
  58. package/dist/core/context-budget-v2-cache-disk.js.map +1 -0
  59. package/dist/core/context-budget-v2-cache-keys.d.ts +22 -0
  60. package/dist/core/context-budget-v2-cache-keys.d.ts.map +1 -1
  61. package/dist/core/context-budget-v2-cache-keys.js +4 -4
  62. package/dist/core/context-budget-v2-cache-keys.js.map +1 -1
  63. package/dist/core/context-budget-v2-cache.d.ts +1 -0
  64. package/dist/core/context-budget-v2-cache.d.ts.map +1 -1
  65. package/dist/core/context-budget-v2-cache.js +1 -0
  66. package/dist/core/context-budget-v2-cache.js.map +1 -1
  67. package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
  68. package/dist/core/context-budget-v2-planner.js +17 -14
  69. package/dist/core/context-budget-v2-planner.js.map +1 -1
  70. package/dist/core/context-budget-v2-types.d.ts +1 -0
  71. package/dist/core/context-budget-v2-types.d.ts.map +1 -1
  72. package/dist/core/context-budget-v2-types.js.map +1 -1
  73. package/dist/core/extensions/loader.d.ts.map +1 -1
  74. package/dist/core/extensions/loader.js +45 -22
  75. package/dist/core/extensions/loader.js.map +1 -1
  76. package/dist/core/extensions/types.d.ts +4 -0
  77. package/dist/core/extensions/types.d.ts.map +1 -1
  78. package/dist/core/extensions/types.js.map +1 -1
  79. package/dist/core/mcp/client.d.ts +105 -0
  80. package/dist/core/mcp/client.d.ts.map +1 -0
  81. package/dist/core/mcp/client.js +198 -0
  82. package/dist/core/mcp/client.js.map +1 -0
  83. package/dist/core/mcp/config.d.ts +23 -0
  84. package/dist/core/mcp/config.d.ts.map +1 -0
  85. package/dist/core/mcp/config.js +89 -0
  86. package/dist/core/mcp/config.js.map +1 -0
  87. package/dist/core/mcp/index.d.ts +15 -0
  88. package/dist/core/mcp/index.d.ts.map +1 -0
  89. package/dist/core/mcp/index.js +15 -0
  90. package/dist/core/mcp/index.js.map +1 -0
  91. package/dist/core/mcp/manager.d.ts +84 -0
  92. package/dist/core/mcp/manager.d.ts.map +1 -0
  93. package/dist/core/mcp/manager.js +173 -0
  94. package/dist/core/mcp/manager.js.map +1 -0
  95. package/dist/core/mcp/protocol.d.ts +59 -0
  96. package/dist/core/mcp/protocol.d.ts.map +1 -0
  97. package/dist/core/mcp/protocol.js +103 -0
  98. package/dist/core/mcp/protocol.js.map +1 -0
  99. package/dist/core/mcp/stdio-transport.d.ts +63 -0
  100. package/dist/core/mcp/stdio-transport.d.ts.map +1 -0
  101. package/dist/core/mcp/stdio-transport.js +132 -0
  102. package/dist/core/mcp/stdio-transport.js.map +1 -0
  103. package/dist/core/mcp/tools.d.ts +47 -0
  104. package/dist/core/mcp/tools.d.ts.map +1 -0
  105. package/dist/core/mcp/tools.js +102 -0
  106. package/dist/core/mcp/tools.js.map +1 -0
  107. package/dist/core/package-archive.d.ts +3 -0
  108. package/dist/core/package-archive.d.ts.map +1 -0
  109. package/dist/core/package-archive.js +161 -0
  110. package/dist/core/package-archive.js.map +1 -0
  111. package/dist/core/package-doctor-source-scan.d.ts +13 -0
  112. package/dist/core/package-doctor-source-scan.d.ts.map +1 -0
  113. package/dist/core/package-doctor-source-scan.js +124 -0
  114. package/dist/core/package-doctor-source-scan.js.map +1 -0
  115. package/dist/core/package-doctor.d.ts +41 -0
  116. package/dist/core/package-doctor.d.ts.map +1 -0
  117. package/dist/core/package-doctor.js +145 -0
  118. package/dist/core/package-doctor.js.map +1 -0
  119. package/dist/core/package-manager.d.ts +10 -1
  120. package/dist/core/package-manager.d.ts.map +1 -1
  121. package/dist/core/package-manager.js +175 -42
  122. package/dist/core/package-manager.js.map +1 -1
  123. package/dist/core/package-manifest.d.ts +26 -0
  124. package/dist/core/package-manifest.d.ts.map +1 -0
  125. package/dist/core/package-manifest.js +85 -0
  126. package/dist/core/package-manifest.js.map +1 -0
  127. package/dist/core/pi-compat.d.ts +5 -0
  128. package/dist/core/pi-compat.d.ts.map +1 -0
  129. package/dist/core/pi-compat.js +18 -0
  130. package/dist/core/pi-compat.js.map +1 -0
  131. package/dist/core/provider-resilience.d.ts +7 -0
  132. package/dist/core/provider-resilience.d.ts.map +1 -1
  133. package/dist/core/provider-resilience.js +11 -0
  134. package/dist/core/provider-resilience.js.map +1 -1
  135. package/dist/core/reasoning-router-bias.d.ts +10 -14
  136. package/dist/core/reasoning-router-bias.d.ts.map +1 -1
  137. package/dist/core/reasoning-router-bias.js +22 -15
  138. package/dist/core/reasoning-router-bias.js.map +1 -1
  139. package/dist/core/reasoning-router-v4.d.ts +9 -1
  140. package/dist/core/reasoning-router-v4.d.ts.map +1 -1
  141. package/dist/core/reasoning-router-v4.js +20 -5
  142. package/dist/core/reasoning-router-v4.js.map +1 -1
  143. package/dist/core/redaction.d.ts +2 -5
  144. package/dist/core/redaction.d.ts.map +1 -1
  145. package/dist/core/redaction.js +14 -1
  146. package/dist/core/redaction.js.map +1 -1
  147. package/dist/core/repository-learning-scope.d.ts +10 -0
  148. package/dist/core/repository-learning-scope.d.ts.map +1 -0
  149. package/dist/core/repository-learning-scope.js +42 -0
  150. package/dist/core/repository-learning-scope.js.map +1 -0
  151. package/dist/core/resource-loader.d.ts.map +1 -1
  152. package/dist/core/resource-loader.js +16 -1
  153. package/dist/core/resource-loader.js.map +1 -1
  154. package/dist/core/router-feedback-collector.d.ts +2 -1
  155. package/dist/core/router-feedback-collector.d.ts.map +1 -1
  156. package/dist/core/router-feedback-collector.js +2 -2
  157. package/dist/core/router-feedback-collector.js.map +1 -1
  158. package/dist/core/runtime-provenance.d.ts +54 -0
  159. package/dist/core/runtime-provenance.d.ts.map +1 -0
  160. package/dist/core/runtime-provenance.js +115 -0
  161. package/dist/core/runtime-provenance.js.map +1 -0
  162. package/dist/core/sandbox/backend.d.ts.map +1 -1
  163. package/dist/core/sandbox/backend.js +39 -21
  164. package/dist/core/sandbox/backend.js.map +1 -1
  165. package/dist/core/sandbox/default-policy.d.ts +4 -5
  166. package/dist/core/sandbox/default-policy.d.ts.map +1 -1
  167. package/dist/core/sandbox/default-policy.js +9 -11
  168. package/dist/core/sandbox/default-policy.js.map +1 -1
  169. package/dist/core/session-bash-runtime.d.ts +4 -4
  170. package/dist/core/session-bash-runtime.d.ts.map +1 -1
  171. package/dist/core/session-bash-runtime.js +6 -5
  172. package/dist/core/session-bash-runtime.js.map +1 -1
  173. package/dist/core/session-compaction-service.d.ts.map +1 -1
  174. package/dist/core/session-compaction-service.js +7 -7
  175. package/dist/core/session-compaction-service.js.map +1 -1
  176. package/dist/core/session-manager.d.ts +4 -1
  177. package/dist/core/session-manager.d.ts.map +1 -1
  178. package/dist/core/session-manager.js +47 -7
  179. package/dist/core/session-manager.js.map +1 -1
  180. package/dist/core/settings-manager.d.ts +7 -4
  181. package/dist/core/settings-manager.d.ts.map +1 -1
  182. package/dist/core/settings-manager.js +11 -3
  183. package/dist/core/settings-manager.js.map +1 -1
  184. package/dist/core/subagent-orchestration.d.ts.map +1 -1
  185. package/dist/core/subagent-orchestration.js +4 -2
  186. package/dist/core/subagent-orchestration.js.map +1 -1
  187. package/dist/core/system-prompt.d.ts +9 -1
  188. package/dist/core/system-prompt.d.ts.map +1 -1
  189. package/dist/core/system-prompt.js +10 -4
  190. package/dist/core/system-prompt.js.map +1 -1
  191. package/dist/core/tools/bash.d.ts +2 -2
  192. package/dist/core/tools/bash.d.ts.map +1 -1
  193. package/dist/core/tools/bash.js +2 -1
  194. package/dist/core/tools/bash.js.map +1 -1
  195. package/dist/core/tools/diagnostics.d.ts.map +1 -1
  196. package/dist/core/tools/diagnostics.js +8 -2
  197. package/dist/core/tools/diagnostics.js.map +1 -1
  198. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  199. package/dist/core/tools/tool-definition-wrapper.js +15 -0
  200. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  201. package/dist/core/turn-metrics.d.ts +135 -0
  202. package/dist/core/turn-metrics.d.ts.map +1 -0
  203. package/dist/core/turn-metrics.js +261 -0
  204. package/dist/core/turn-metrics.js.map +1 -0
  205. package/dist/core/verified-bash-runtime.d.ts.map +1 -1
  206. package/dist/core/verified-bash-runtime.js +10 -4
  207. package/dist/core/verified-bash-runtime.js.map +1 -1
  208. package/dist/guardrails/evidence-protocol.d.ts +10 -0
  209. package/dist/guardrails/evidence-protocol.d.ts.map +1 -0
  210. package/dist/guardrails/evidence-protocol.js +34 -0
  211. package/dist/guardrails/evidence-protocol.js.map +1 -0
  212. package/dist/guardrails/evidence-system.d.ts +3 -1
  213. package/dist/guardrails/evidence-system.d.ts.map +1 -1
  214. package/dist/guardrails/evidence-system.js +22 -14
  215. package/dist/guardrails/evidence-system.js.map +1 -1
  216. package/dist/guardrails/replay-ledger-lock-owner.d.ts +7 -0
  217. package/dist/guardrails/replay-ledger-lock-owner.d.ts.map +1 -1
  218. package/dist/guardrails/replay-ledger-lock-owner.js +42 -1
  219. package/dist/guardrails/replay-ledger-lock-owner.js.map +1 -1
  220. package/dist/guardrails/replay-payload-hash.d.ts +6 -0
  221. package/dist/guardrails/replay-payload-hash.d.ts.map +1 -0
  222. package/dist/guardrails/replay-payload-hash.js +24 -0
  223. package/dist/guardrails/replay-payload-hash.js.map +1 -0
  224. package/dist/index.d.ts +8 -2
  225. package/dist/index.d.ts.map +1 -1
  226. package/dist/index.js +7 -1
  227. package/dist/index.js.map +1 -1
  228. package/dist/main.d.ts.map +1 -1
  229. package/dist/main.js +18 -0
  230. package/dist/main.js.map +1 -1
  231. package/dist/modes/interactive/components/control-panel-layout.d.ts.map +1 -1
  232. package/dist/modes/interactive/components/control-panel-layout.js +2 -2
  233. package/dist/modes/interactive/components/control-panel-layout.js.map +1 -1
  234. package/dist/modes/interactive/components/footer.d.ts +3 -0
  235. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  236. package/dist/modes/interactive/components/footer.js +40 -12
  237. package/dist/modes/interactive/components/footer.js.map +1 -1
  238. package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  239. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  240. package/dist/modes/interactive/components/settings-selector.js +10 -0
  241. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  242. package/dist/modes/interactive/components/status-sidebar.d.ts +14 -2
  243. package/dist/modes/interactive/components/status-sidebar.d.ts.map +1 -1
  244. package/dist/modes/interactive/components/status-sidebar.js +106 -19
  245. package/dist/modes/interactive/components/status-sidebar.js.map +1 -1
  246. package/dist/modes/interactive/interactive-mode.d.ts +10 -1
  247. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  248. package/dist/modes/interactive/interactive-mode.js +104 -17
  249. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  250. package/dist/modes/interactive/theme/dark.json +1 -1
  251. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  252. package/dist/modes/interactive/theme/theme.js +1 -0
  253. package/dist/modes/interactive/theme/theme.js.map +1 -1
  254. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  255. package/dist/modes/rpc/rpc-mode.js +1 -1
  256. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  257. package/dist/types/evidence.d.ts +11 -3
  258. package/dist/types/evidence.d.ts.map +1 -1
  259. package/dist/types/evidence.js.map +1 -1
  260. package/docs/book-to-skill.md +79 -0
  261. package/docs/compaction.md +35 -3
  262. package/docs/containerization.md +14 -2
  263. package/docs/docs.json +16 -0
  264. package/docs/environment-variables.md +1 -1
  265. package/docs/extensions.md +75 -16
  266. package/docs/index.md +3 -0
  267. package/docs/mcp.md +97 -0
  268. package/docs/metrics.md +87 -0
  269. package/docs/models.md +12 -0
  270. package/docs/packages.md +25 -4
  271. package/docs/provider-resilience.md +37 -56
  272. package/docs/providers.md +5 -1
  273. package/docs/run-protocol.md +72 -0
  274. package/docs/sdk.md +40 -6
  275. package/docs/sessions.md +6 -0
  276. package/docs/settings.md +10 -7
  277. package/docs/skills.md +9 -1
  278. package/docs/usage.md +14 -4
  279. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  280. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  281. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  282. package/examples/extensions/gondolin/package-lock.json +2 -2
  283. package/examples/extensions/gondolin/package.json +1 -1
  284. package/examples/extensions/plannotator-approval-bridge.ts +83 -0
  285. package/examples/extensions/sandbox/package-lock.json +2 -2
  286. package/examples/extensions/sandbox/package.json +1 -1
  287. package/examples/extensions/subagent/README.md +21 -11
  288. package/examples/extensions/subagent/adaptive-agent-runtime.ts +9 -3
  289. package/examples/extensions/subagent/agents/planner.md +0 -2
  290. package/examples/extensions/subagent/agents/reviewer.md +0 -2
  291. package/examples/extensions/subagent/agents/scout.md +0 -2
  292. package/examples/extensions/subagent/agents/worker.md +0 -1
  293. package/examples/extensions/subagent/agents.test.ts +9 -0
  294. package/examples/extensions/subagent/agents.ts +11 -4
  295. package/examples/extensions/subagent/deadline-budget.test.ts +32 -0
  296. package/examples/extensions/subagent/deadline-budget.ts +25 -1
  297. package/examples/extensions/subagent/fixtures/fake-omk-json.mjs +10 -0
  298. package/examples/extensions/subagent/index.ts +234 -55
  299. package/examples/extensions/subagent/subagent-execution-policy.test.ts +27 -0
  300. package/examples/extensions/subagent/subagent-extension-smoke.test.ts +167 -2
  301. package/examples/extensions/subagent/workflow-graph.test.ts +80 -0
  302. package/examples/extensions/subagent/workflow-graph.ts +89 -0
  303. package/examples/extensions/with-deps/package-lock.json +2 -2
  304. package/examples/extensions/with-deps/package.json +1 -1
  305. package/npm-shrinkwrap.json +275 -439
  306. package/package.json +11 -8
@@ -7,7 +7,6 @@ import * as crypto from "node:crypto";
7
7
  import * as fs from "node:fs";
8
8
  import * as os from "node:os";
9
9
  import * as path from "node:path";
10
- import chalk from "chalk";
11
10
  import { spawn, spawnSync } from "child_process";
12
11
  import { getProviders, } from "omk-ai";
13
12
  import { CombinedAutocompleteProvider, Container, fuzzyFilter, getCapabilities, hyperlink, Loader, Markdown, matchesKey, ProcessTerminal, Spacer, setKeybindings, Text, TruncatedText, TUI, visibleWidth, } from "omk-tui";
@@ -185,6 +184,10 @@ export function isApiKeyLoginProvider(providerId, oauthProviderIds, builtInProvi
185
184
  }
186
185
  return !oauthProviderIds.has(providerId);
187
186
  }
187
+ /** Placeholder shown in the empty editor to make core affordances discoverable. */
188
+ const EDITOR_PLACEHOLDER = "Ask anything · / for commands · ! for skills/bash";
189
+ /** How long transient info notices stay visible below the editor. */
190
+ const TRANSIENT_NOTICE_MS = 6000;
188
191
  export function buildWorkingLoaderMessage(base, reasoning, level) {
189
192
  if (!reasoning || level === undefined || level === "off") {
190
193
  return base;
@@ -214,6 +217,11 @@ export class InteractiveMode {
214
217
  onInputCallback;
215
218
  pendingUserInputs = [];
216
219
  loadingAnimation = undefined;
220
+ // Wall-clock start of the current agent turn, for the working loader elapsed suffix
221
+ workingStartedAt = undefined;
222
+ // Transient (auto-dismissing) notice shown below the editor for info-level notifications
223
+ noticeContainer;
224
+ noticeTimer = undefined;
217
225
  workingMessage = undefined;
218
226
  workingVisible = true;
219
227
  workingIndicatorOptions = undefined;
@@ -332,12 +340,15 @@ export class InteractiveMode {
332
340
  paddingX: editorPaddingX,
333
341
  autocompleteMaxVisible,
334
342
  });
343
+ this.defaultEditor.setPlaceholder(EDITOR_PLACEHOLDER);
335
344
  this.editor = this.defaultEditor;
336
345
  this.editorContainer = new Container();
337
346
  this.editorContainer.addChild(this.editor);
338
347
  this.footerDataProvider = new FooterDataProvider(this.sessionManager.getCwd());
339
348
  this.footer = new FooterComponent(this.session, this.footerDataProvider);
340
349
  this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
350
+ this.footer.setShowSystemMetrics(this.settingsManager.getFooterSystemMetrics());
351
+ this.noticeContainer = new Container();
341
352
  // Load hide thinking block setting
342
353
  this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
343
354
  // Register themes from resource loader and initialize
@@ -639,6 +650,7 @@ export class InteractiveMode {
639
650
  this.ui.addChild(this.widgetContainerAbove);
640
651
  this.ui.addChild(this.editorContainer);
641
652
  this.ui.addChild(this.widgetContainerBelow);
653
+ this.ui.addChild(this.noticeContainer);
642
654
  // Pinned status sidebar: renders footer data as a fixed right rail (Ctrl+Q).
643
655
  // Pinned by default via the pinStatusSidebar setting / OMK_PIN_STATUS_SIDEBAR=1.
644
656
  // The footer slot below stays mounted and yields to the rail only while the
@@ -1541,7 +1553,17 @@ export class InteractiveMode {
1541
1553
  return buildWorkingLoaderMessage(this.workingMessage ?? this.defaultWorkingMessage, !!this.session.model?.reasoning, this.session.thinkingLevel);
1542
1554
  }
1543
1555
  createWorkingLoader() {
1544
- return new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), this.getWorkingLoaderMessage(), this.workingIndicatorOptions);
1556
+ const loader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), this.getWorkingLoaderMessage(), this.workingIndicatorOptions);
1557
+ const startedAt = this.workingStartedAt ?? Date.now();
1558
+ loader.setDynamicSuffix(() => {
1559
+ const seconds = Math.max(0, Math.floor((Date.now() - startedAt) / 1000));
1560
+ const parts = [`${seconds}s`, `${keyText("app.interrupt")} interrupt`];
1561
+ if (!this.toolOutputExpanded && this.pendingTools.size > 0) {
1562
+ parts.push(`${keyText("app.tools.expand")} expand tools`);
1563
+ }
1564
+ return theme.fg("dim", ` (${parts.join(" · ")})`);
1565
+ });
1566
+ return loader;
1545
1567
  }
1546
1568
  stopWorkingLoader() {
1547
1569
  if (this.loadingAnimation) {
@@ -1657,8 +1679,10 @@ export class InteractiveMode {
1657
1679
  this.workingVisible = true;
1658
1680
  this.setWorkingIndicator();
1659
1681
  if (this.loadingAnimation) {
1660
- this.loadingAnimation.setMessage(`${this.defaultWorkingMessage} (${keyText("app.interrupt")} to interrupt)`);
1682
+ // Interrupt hint now lives in the loader's dynamic suffix
1683
+ this.loadingAnimation.setMessage(this.getWorkingLoaderMessage());
1661
1684
  }
1685
+ this.clearTransientNotice();
1662
1686
  this.setHiddenThinkingLabel();
1663
1687
  }
1664
1688
  // Maximum total widget lines to prevent viewport overflow
@@ -2018,7 +2042,8 @@ export class InteractiveMode {
2018
2042
  this.showWarning(message);
2019
2043
  }
2020
2044
  else {
2021
- this.showStatus(message);
2045
+ // Info notifications are transient - they do not pollute the chat history
2046
+ this.showTransientNotice(message);
2022
2047
  }
2023
2048
  }
2024
2049
  /** Show a custom component with keyboard focus. Overlay mode renders on top of existing content. */
@@ -2034,13 +2059,14 @@ export class InteractiveMode {
2034
2059
  };
2035
2060
  return new Promise((resolve, reject) => {
2036
2061
  let component;
2062
+ let overlayHandle;
2037
2063
  let closed = false;
2038
2064
  const close = (result) => {
2039
2065
  if (closed)
2040
2066
  return;
2041
2067
  closed = true;
2042
2068
  if (isOverlay)
2043
- this.ui.hideOverlay();
2069
+ overlayHandle?.hide();
2044
2070
  else
2045
2071
  restoreEditor();
2046
2072
  // Note: both branches above already call requestRender
@@ -2070,9 +2096,9 @@ export class InteractiveMode {
2070
2096
  const w = component.width;
2071
2097
  return w ? { width: w } : undefined;
2072
2098
  };
2073
- const handle = this.ui.showOverlay(component, resolveOptions());
2099
+ overlayHandle = this.ui.showOverlay(component, resolveOptions());
2074
2100
  // Expose handle to caller for visibility control
2075
- options?.onHandle?.(handle);
2101
+ options?.onHandle?.(overlayHandle);
2076
2102
  }
2077
2103
  else {
2078
2104
  this.editorContainer.clear();
@@ -2420,6 +2446,7 @@ export class InteractiveMode {
2420
2446
  this.footer.invalidate();
2421
2447
  switch (event.type) {
2422
2448
  case "agent_start":
2449
+ this.workingStartedAt = Date.now();
2423
2450
  this.pendingTools.clear();
2424
2451
  if (this.settingsManager.getShowTerminalProgress()) {
2425
2452
  this.ui.terminal.setProgress(true);
@@ -2579,6 +2606,7 @@ export class InteractiveMode {
2579
2606
  this.showSessionTermination(event.termination);
2580
2607
  break;
2581
2608
  case "agent_end":
2609
+ this.workingStartedAt = undefined;
2582
2610
  if (this.settingsManager.getShowTerminalProgress()) {
2583
2611
  this.ui.terminal.setProgress(false);
2584
2612
  }
@@ -2950,6 +2978,16 @@ export class InteractiveMode {
2950
2978
  const context = this.sessionManager.buildSessionContext();
2951
2979
  this.renderSessionContext(context);
2952
2980
  }
2981
+ buildFinalSessionLog() {
2982
+ this.chatContainer.clear();
2983
+ const context = this.sessionManager.buildSessionContext();
2984
+ const messages = context.messages.filter((message) => message.role === "user" ||
2985
+ message.role === "assistant" ||
2986
+ message.role === "toolResult" ||
2987
+ message.role === "bashExecution");
2988
+ this.renderSessionContext({ ...context, messages });
2989
+ return this.chatContainer.render(this.ui.terminal.columns);
2990
+ }
2953
2991
  // =========================================================================
2954
2992
  // Key handlers
2955
2993
  // =========================================================================
@@ -2997,12 +3035,8 @@ export class InteractiveMode {
2997
3035
  // Drain any in-flight Kitty key release events before stopping.
2998
3036
  // This prevents escape sequences from leaking to the parent shell over slow SSH.
2999
3037
  await this.ui.terminal.drainInput(1000);
3000
- this.stop();
3038
+ this.stop({ finalSessionLog: true });
3001
3039
  await this.runtimeHost.dispose();
3002
- const resumeCommand = formatResumeCommand(this.sessionManager);
3003
- if (resumeCommand) {
3004
- process.stdout.write(`${chalk.dim("To resume this session:")} ${resumeCommand}\n`);
3005
- }
3006
3040
  process.exit(0);
3007
3041
  }
3008
3042
  emergencyTerminalExit() {
@@ -3312,6 +3346,27 @@ export class InteractiveMode {
3312
3346
  this.chatContainer.addChild(new Text(theme.fg("warning", `Warning: ${warningMessage}`), 1, 0));
3313
3347
  this.ui.requestRender();
3314
3348
  }
3349
+ /** Show an auto-dismissing notice below the editor (single slot, replaces previous). */
3350
+ showTransientNotice(message) {
3351
+ this.clearTransientNotice();
3352
+ this.noticeContainer.addChild(new Text(theme.fg("dim", message), 1, 0));
3353
+ this.noticeTimer = setTimeout(() => {
3354
+ this.noticeTimer = undefined;
3355
+ this.noticeContainer.clear();
3356
+ this.ui.requestRender();
3357
+ }, TRANSIENT_NOTICE_MS);
3358
+ if (this.noticeTimer && typeof this.noticeTimer === "object" && "unref" in this.noticeTimer) {
3359
+ this.noticeTimer.unref();
3360
+ }
3361
+ this.ui.requestRender();
3362
+ }
3363
+ clearTransientNotice() {
3364
+ if (this.noticeTimer) {
3365
+ clearTimeout(this.noticeTimer);
3366
+ this.noticeTimer = undefined;
3367
+ }
3368
+ this.noticeContainer.clear();
3369
+ }
3315
3370
  showNewVersionNotification(release) {
3316
3371
  const action = theme.fg("accent", `${APP_NAME} update`);
3317
3372
  const updateInstruction = theme.fg("muted", `New version ${release.version} is available. Run `) + action;
@@ -3554,6 +3609,7 @@ export class InteractiveMode {
3554
3609
  editorPaddingX: this.settingsManager.getEditorPaddingX(),
3555
3610
  autocompleteMaxVisible: this.settingsManager.getAutocompleteMaxVisible(),
3556
3611
  quietStartup: this.settingsManager.getQuietStartup(),
3612
+ footerSystemMetrics: this.settingsManager.getFooterSystemMetrics(),
3557
3613
  clearOnShrink: this.settingsManager.getClearOnShrink(),
3558
3614
  showTerminalProgress: this.settingsManager.getShowTerminalProgress(),
3559
3615
  warnings: this.settingsManager.getWarnings(),
@@ -3641,6 +3697,11 @@ export class InteractiveMode {
3641
3697
  onQuietStartupChange: (enabled) => {
3642
3698
  this.settingsManager.setQuietStartup(enabled);
3643
3699
  },
3700
+ onFooterSystemMetricsChange: (enabled) => {
3701
+ this.settingsManager.setFooterSystemMetrics(enabled);
3702
+ this.footer.setShowSystemMetrics(enabled);
3703
+ this.ui.requestRender();
3704
+ },
3644
3705
  onDoubleEscapeActionChange: (action) => {
3645
3706
  this.settingsManager.setDoubleEscapeAction(action);
3646
3707
  },
@@ -3714,9 +3775,7 @@ export class InteractiveMode {
3714
3775
  this.showStatus("Thinking: auto (v4 router, level routed per task)");
3715
3776
  }
3716
3777
  applyThinkingLevel(level) {
3717
- // A concrete level is an explicit user override: always return to manual mode.
3718
- this.session.setThinkingMode("manual");
3719
- this.session.setThinkingLevel(level);
3778
+ this.session.setUserThinkingLevel(level);
3720
3779
  this.footer.invalidate();
3721
3780
  this.updateEditorBorderColor();
3722
3781
  this.showStatus(`Thinking: ${this.session.thinkingLevel}`);
@@ -4818,7 +4877,21 @@ export class InteractiveMode {
4818
4877
  if (stats.tokens.cacheWrite > 0) {
4819
4878
  info += `${theme.fg("dim", "Cache Write:")} ${stats.tokens.cacheWrite.toLocaleString()}\n`;
4820
4879
  }
4880
+ if (stats.promptCache.providerEligibleInputTokens > 0) {
4881
+ info += `${theme.fg("dim", "Cache Hit Rate:")} ${(stats.promptCache.providerHitRate * 100).toFixed(1)}%\n`;
4882
+ }
4821
4883
  info += `${theme.fg("dim", "Total:")} ${stats.tokens.total.toLocaleString()}\n`;
4884
+ if (stats.promptCache.stablePrefixCharacters > 0 ||
4885
+ stats.promptCache.keyChanges > 0 ||
4886
+ stats.promptCache.boundaryBypasses > 0) {
4887
+ info += `\n${theme.bold("Prompt Cache Diagnostics")}\n`;
4888
+ info += `${theme.fg("dim", "Stable Prefix:")} ${stats.promptCache.stablePrefixCharacters.toLocaleString()} chars\n`;
4889
+ info += `${theme.fg("dim", "Key Changes:")} ${stats.promptCache.keyChanges.toLocaleString()}\n`;
4890
+ info += `${theme.fg("dim", "Boundary Bypasses:")} ${stats.promptCache.boundaryBypasses.toLocaleString()}\n`;
4891
+ if (stats.promptCache.lastBreakReason) {
4892
+ info += `${theme.fg("dim", "Last Break:")} ${stats.promptCache.lastBreakReason}\n`;
4893
+ }
4894
+ }
4822
4895
  if (stats.cost > 0) {
4823
4896
  info += `\n${theme.bold("Cost")}\n`;
4824
4897
  info += `${theme.fg("dim", "Total:")} ${stats.cost.toFixed(4)}`;
@@ -5131,7 +5204,7 @@ export class InteractiveMode {
5131
5204
  // Ignore, will be emitted as an event
5132
5205
  }
5133
5206
  }
5134
- stop() {
5207
+ stop(options = {}) {
5135
5208
  this.unregisterSignalHandlers();
5136
5209
  if (this.settingsManager.getShowTerminalProgress()) {
5137
5210
  this.ui.terminal.setProgress(false);
@@ -5141,6 +5214,15 @@ export class InteractiveMode {
5141
5214
  this.loadingAnimation = undefined;
5142
5215
  }
5143
5216
  this.clearExtensionTerminalInputListeners();
5217
+ let finalLines;
5218
+ if (options.finalSessionLog) {
5219
+ try {
5220
+ finalLines = this.buildFinalSessionLog();
5221
+ }
5222
+ catch {
5223
+ // Preserve terminal cleanup if transcript reconstruction fails.
5224
+ }
5225
+ }
5144
5226
  disposeComponent(this.builtInHeader);
5145
5227
  disposeComponent(this.customHeader);
5146
5228
  this.footer.dispose();
@@ -5153,7 +5235,12 @@ export class InteractiveMode {
5153
5235
  this.unsubscribe();
5154
5236
  }
5155
5237
  if (this.isInitialized) {
5156
- this.ui.stop();
5238
+ if (finalLines === undefined) {
5239
+ this.ui.stop();
5240
+ }
5241
+ else {
5242
+ this.ui.stop({ finalLines });
5243
+ }
5157
5244
  this.isInitialized = false;
5158
5245
  }
5159
5246
  }