talos-code 0.0.1 → 0.2.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 (407) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/LICENSE +661 -0
  3. package/README.md +116 -3
  4. package/THIRD_PARTY_NOTICES.md +40 -0
  5. package/dist/archive/zip.js +73 -0
  6. package/dist/args.js +100 -0
  7. package/dist/automations/history-store.js +34 -0
  8. package/dist/automations/policy-store.js +43 -0
  9. package/dist/automations/runner.js +107 -0
  10. package/dist/automations/schedule.js +85 -0
  11. package/dist/automations/windows-task.js +53 -0
  12. package/dist/commands/advanced-cli.js +233 -0
  13. package/dist/commands/checkpoint-cli.js +45 -0
  14. package/dist/commands/config-cli.js +107 -0
  15. package/dist/commands/context.js +17 -0
  16. package/dist/commands/extensions-cli.js +207 -0
  17. package/dist/commands/project-cli.js +74 -0
  18. package/dist/commands/project-commands.js +143 -0
  19. package/dist/commands/provider-cli.js +244 -0
  20. package/dist/commands/services-cli.js +248 -0
  21. package/dist/commands/session-cli.js +171 -0
  22. package/dist/commands/system-cli.js +405 -0
  23. package/dist/config/commands.js +60 -0
  24. package/dist/config/load.js +382 -0
  25. package/dist/config/migrations.js +48 -0
  26. package/dist/config/types.js +11 -0
  27. package/dist/diagnostics/development-log.js +154 -0
  28. package/dist/diagnostics/doctor.js +104 -0
  29. package/dist/diagnostics/redact.js +80 -0
  30. package/dist/diagnostics/zip.js +52 -0
  31. package/dist/errors.js +156 -0
  32. package/dist/events/bridge.js +130 -0
  33. package/dist/extensions/installer.js +178 -0
  34. package/dist/extensions/package-schema.js +24 -0
  35. package/dist/headless/result.js +84 -0
  36. package/dist/headless/run.js +230 -0
  37. package/dist/i18n/en/approval.js +46 -0
  38. package/dist/i18n/en/common.js +9 -0
  39. package/dist/i18n/en/credentials.js +92 -0
  40. package/dist/i18n/en/errors.js +267 -0
  41. package/dist/i18n/en/firstrun.js +101 -0
  42. package/dist/i18n/en/providers.js +37 -0
  43. package/dist/i18n/en/screen.js +774 -0
  44. package/dist/i18n/en/tools.js +127 -0
  45. package/dist/i18n/en.js +14 -0
  46. package/dist/i18n/error-view.js +307 -0
  47. package/dist/i18n/index.js +19 -0
  48. package/dist/i18n/kernel-map.js +139 -0
  49. package/dist/io.js +45 -0
  50. package/dist/main.js +331 -0
  51. package/dist/paths.js +41 -0
  52. package/dist/protocol/v2/codec.js +9 -0
  53. package/dist/protocol/v2/events.js +555 -0
  54. package/dist/protocol/v2/index.js +4 -0
  55. package/dist/protocol/v2/replay.js +28 -0
  56. package/dist/protocol/v2/types.js +1 -0
  57. package/dist/provider/control-plane.js +135 -0
  58. package/dist/provider/environment-keys.js +275 -0
  59. package/dist/provider/health.js +110 -0
  60. package/dist/provider/missing-key.js +48 -0
  61. package/dist/provider/model-catalog.js +168 -0
  62. package/dist/provider/openrouter-login.js +172 -0
  63. package/dist/provider/provider-text.js +13 -0
  64. package/dist/provider/store.js +95 -0
  65. package/dist/provider/system-keyring.js +214 -0
  66. package/dist/runtime/active-run.js +63 -0
  67. package/dist/runtime/agent-tree.js +74 -0
  68. package/dist/runtime/attachments.js +84 -0
  69. package/dist/runtime/brokered-executor.js +395 -0
  70. package/dist/runtime/context-archive.js +69 -0
  71. package/dist/runtime/context-status.js +76 -0
  72. package/dist/runtime/create-runtime.js +111 -0
  73. package/dist/runtime/model-profile.js +361 -0
  74. package/dist/runtime/output-store.js +137 -0
  75. package/dist/runtime/provider-attempts.js +185 -0
  76. package/dist/runtime/replay-buffer.js +153 -0
  77. package/dist/runtime/repo.js +95 -0
  78. package/dist/runtime/session-facade.js +135 -0
  79. package/dist/runtime/session-summary.js +125 -0
  80. package/dist/runtime/supervisor.js +265 -0
  81. package/dist/runtime/talos-composition.js +1011 -0
  82. package/dist/runtime/types.js +5 -0
  83. package/dist/runtime/usage-snapshot.js +82 -0
  84. package/dist/security/auto-classifier.js +38 -0
  85. package/dist/security/credential-free-environment.js +54 -0
  86. package/dist/security/evaluate.js +243 -0
  87. package/dist/security/execution-backends.js +236 -0
  88. package/dist/security/execution-broker.js +102 -0
  89. package/dist/security/forge-scan.js +74 -0
  90. package/dist/security/from-approval.js +39 -0
  91. package/dist/security/mxc-execution-backend.js +281 -0
  92. package/dist/security/permission-engine.js +138 -0
  93. package/dist/security/permission-explanation.js +54 -0
  94. package/dist/security/persist.js +179 -0
  95. package/dist/security/plugin-guard.js +230 -0
  96. package/dist/security/process-tree-evidence-store.js +74 -0
  97. package/dist/security/process-tree-probe.js +554 -0
  98. package/dist/security/project-resource-inventory.js +186 -0
  99. package/dist/security/project-trust-gate.js +38 -0
  100. package/dist/security/project-trust.js +367 -0
  101. package/dist/security/rule-parser.js +201 -0
  102. package/dist/security/shell-segmentation.js +68 -0
  103. package/dist/security/trust-authority.js +324 -0
  104. package/dist/security/types.js +1 -0
  105. package/dist/security/workspace-identity.js +102 -0
  106. package/dist/services/automation-facade.js +59 -0
  107. package/dist/services/forge-facade.js +77 -0
  108. package/dist/services/hook-facade.js +240 -0
  109. package/dist/services/index.js +16 -0
  110. package/dist/services/library-facade.js +174 -0
  111. package/dist/services/mcp-facade.js +348 -0
  112. package/dist/services/memory-facade.js +126 -0
  113. package/dist/services/notes-facade.js +157 -0
  114. package/dist/services/plugin-facade.js +308 -0
  115. package/dist/services/research-facade.js +110 -0
  116. package/dist/services/task-board-facade.js +236 -0
  117. package/dist/services/workflow-catalog.js +246 -0
  118. package/dist/sessions/export-format.js +98 -0
  119. package/dist/sessions/metadata-store.js +160 -0
  120. package/dist/sessions/share.js +122 -0
  121. package/dist/sessions/transfer.js +16 -0
  122. package/dist/subcommands.js +62 -0
  123. package/dist/tui/agent-roster.js +36 -0
  124. package/dist/tui/agent-view.js +51 -0
  125. package/dist/tui/app.js +4098 -0
  126. package/dist/tui/approval.js +36 -0
  127. package/dist/tui/boot/boot-sequence.js +76 -0
  128. package/dist/tui/boot/cinematic.js +243 -0
  129. package/dist/tui/boot/desktop-logo.js +82 -0
  130. package/dist/tui/boot.js +3 -0
  131. package/dist/tui/busy-input.js +58 -0
  132. package/dist/tui/catalog-service.js +560 -0
  133. package/dist/tui/components/assistant-stream.js +1 -0
  134. package/dist/tui/components/command-menu.js +68 -0
  135. package/dist/tui/components/composer.js +219 -0
  136. package/dist/tui/components/diff.js +35 -0
  137. package/dist/tui/components/footer.js +48 -0
  138. package/dist/tui/components/header.js +6 -0
  139. package/dist/tui/components/markdown.js +305 -0
  140. package/dist/tui/components/status-indicator.js +38 -0
  141. package/dist/tui/components/terminal-shell.js +214 -0
  142. package/dist/tui/components/thinking-row.js +19 -0
  143. package/dist/tui/components/tool-row.js +97 -0
  144. package/dist/tui/components/transcript-virtualizer.js +165 -0
  145. package/dist/tui/components/transcript.js +43 -0
  146. package/dist/tui/descendant-approvals.js +104 -0
  147. package/dist/tui/diff-model.js +77 -0
  148. package/dist/tui/editor-history.js +21 -0
  149. package/dist/tui/editor.js +210 -0
  150. package/dist/tui/event-adapter.js +436 -0
  151. package/dist/tui/exit-output.js +58 -0
  152. package/dist/tui/external-editor.js +53 -0
  153. package/dist/tui/file-completion.js +89 -0
  154. package/dist/tui/focus-manager.js +5 -0
  155. package/dist/tui/highlight.js +30 -0
  156. package/dist/tui/input-router.js +18 -0
  157. package/dist/tui/interrupt.js +99 -0
  158. package/dist/tui/keybindings.js +194 -0
  159. package/dist/tui/keymap-resolver.js +91 -0
  160. package/dist/tui/launch-state.js +148 -0
  161. package/dist/tui/line-diff.js +57 -0
  162. package/dist/tui/live-activity.js +56 -0
  163. package/dist/tui/metrics.js +123 -0
  164. package/dist/tui/onboarding.js +36 -0
  165. package/dist/tui/overlays/agent-tree.js +43 -0
  166. package/dist/tui/overlays/approval-dialog.js +642 -0
  167. package/dist/tui/overlays/automation-center.js +51 -0
  168. package/dist/tui/overlays/checkpoint-picker.js +47 -0
  169. package/dist/tui/overlays/context-inspector.js +36 -0
  170. package/dist/tui/overlays/effort-line.js +110 -0
  171. package/dist/tui/overlays/forge-center.js +46 -0
  172. package/dist/tui/overlays/help-dialog.js +16 -0
  173. package/dist/tui/overlays/history-picker.js +37 -0
  174. package/dist/tui/overlays/hook-center.js +70 -0
  175. package/dist/tui/overlays/library-center.js +55 -0
  176. package/dist/tui/overlays/mcp-center.js +60 -0
  177. package/dist/tui/overlays/memory-center.js +63 -0
  178. package/dist/tui/overlays/model-picker.js +77 -0
  179. package/dist/tui/overlays/notes-center.js +53 -0
  180. package/dist/tui/overlays/overlay-host.js +8 -0
  181. package/dist/tui/overlays/plugin-center.js +76 -0
  182. package/dist/tui/overlays/provider-picker.js +171 -0
  183. package/dist/tui/overlays/queue-editor.js +32 -0
  184. package/dist/tui/overlays/research-center.js +59 -0
  185. package/dist/tui/overlays/scroll-window.js +234 -0
  186. package/dist/tui/overlays/session-picker.js +115 -0
  187. package/dist/tui/overlays/tasks-center.js +83 -0
  188. package/dist/tui/overlays/theme-picker.js +21 -0
  189. package/dist/tui/overlays/transcript-search.js +58 -0
  190. package/dist/tui/overlays/trust-center.js +29 -0
  191. package/dist/tui/overlays/workflow-center.js +46 -0
  192. package/dist/tui/project-file-index.js +214 -0
  193. package/dist/tui/project-references.js +85 -0
  194. package/dist/tui/project-trust-prompt.js +289 -0
  195. package/dist/tui/prompt-history-store.js +116 -0
  196. package/dist/tui/queue-store.js +110 -0
  197. package/dist/tui/regions/budget.js +59 -0
  198. package/dist/tui/regions/views.js +96 -0
  199. package/dist/tui/render-coordinator.js +148 -0
  200. package/dist/tui/render-scheduler.js +4 -0
  201. package/dist/tui/run.js +69 -0
  202. package/dist/tui/selection-list.js +29 -0
  203. package/dist/tui/session-controller.js +791 -0
  204. package/dist/tui/session-export.js +54 -0
  205. package/dist/tui/setup-wizard.js +46 -0
  206. package/dist/tui/shell-input.js +35 -0
  207. package/dist/tui/shell-layout.js +48 -0
  208. package/dist/tui/shell-model.js +98 -0
  209. package/dist/tui/slash-commands.js +82 -0
  210. package/dist/tui/state.js +151 -0
  211. package/dist/tui/status-bar.js +125 -0
  212. package/dist/tui/status-view.js +40 -0
  213. package/dist/tui/terminal-capabilities.js +9 -0
  214. package/dist/tui/terminal-session.js +11 -0
  215. package/dist/tui/text-width.js +66 -0
  216. package/dist/tui/theme-catalog.js +27 -0
  217. package/dist/tui/theme-store.js +23 -0
  218. package/dist/tui/theme.js +23 -0
  219. package/dist/tui/tool-display.js +135 -0
  220. package/dist/tui/tool-facts.js +1 -0
  221. package/dist/tui/tools/bash-renderer.js +32 -0
  222. package/dist/tui/tools/change.js +61 -0
  223. package/dist/tui/tools/edit-renderer.js +17 -0
  224. package/dist/tui/tools/generic-renderer.js +13 -0
  225. package/dist/tui/tools/list-renderer.js +14 -0
  226. package/dist/tui/tools/read-renderer.js +13 -0
  227. package/dist/tui/tools/registry.js +20 -0
  228. package/dist/tui/tools/row-format.js +187 -0
  229. package/dist/tui/tools/search-renderer.js +38 -0
  230. package/dist/tui/tools/shared.js +97 -0
  231. package/dist/tui/tools/write-renderer.js +15 -0
  232. package/dist/tui/transcript-model.js +441 -0
  233. package/dist/tui/ui-preferences.js +79 -0
  234. package/dist/tui/usage-view.js +77 -0
  235. package/dist/tui/vim-mode.js +99 -0
  236. package/dist/update/check.js +15 -0
  237. package/dist/update/npm.js +51 -0
  238. package/dist/update/run.js +129 -0
  239. package/dist/version.js +2 -0
  240. package/dist/workspace/checkpoint-store.js +210 -0
  241. package/dist/workspace/checkpoint.js +413 -0
  242. package/dist/workspace/restore.js +232 -0
  243. package/package.json +64 -5
  244. package/vendor/context-engine/package.json +11 -0
  245. package/vendor/context-engine/src/compaction-planner.mjs +57 -0
  246. package/vendor/context-engine/src/contracts.mjs +48 -0
  247. package/vendor/context-engine/src/engine.mjs +445 -0
  248. package/vendor/context-engine/src/node/context-export.mjs +164 -0
  249. package/vendor/context-engine/src/node/legacy-import.mjs +92 -0
  250. package/vendor/context-engine/src/node/migrations/001-context.sql +126 -0
  251. package/vendor/context-engine/src/node/sqlite-store.mjs +85 -0
  252. package/vendor/context-engine/src/node/sqlite-worker.mjs +559 -0
  253. package/vendor/context-engine/src/profiles.mjs +10 -0
  254. package/vendor/context-engine/src/retrieval.mjs +104 -0
  255. package/vendor/context-engine/src/summary.mjs +97 -0
  256. package/vendor/context-engine/src/usage.mjs +34 -0
  257. package/vendor/harness-ui/package.json +38 -0
  258. package/vendor/harness-ui/src/acp-agent.mjs +350 -0
  259. package/vendor/harness-ui/src/agent-service.mjs +2188 -0
  260. package/vendor/harness-ui/src/agui-events.mjs +452 -0
  261. package/vendor/harness-ui/src/ambiente-solo-server.mjs +121 -0
  262. package/vendor/harness-ui/src/artifact-store.mjs +39 -0
  263. package/vendor/harness-ui/src/assistenza.mjs +123 -0
  264. package/vendor/harness-ui/src/automation-scheduler.mjs +69 -0
  265. package/vendor/harness-ui/src/automation-store.mjs +145 -0
  266. package/vendor/harness-ui/src/browser-annota.mjs +639 -0
  267. package/vendor/harness-ui/src/browser-frame.mjs +211 -0
  268. package/vendor/harness-ui/src/browser-proxy-universale.mjs +519 -0
  269. package/vendor/harness-ui/src/browser-proxy.mjs +87 -0
  270. package/vendor/harness-ui/src/browser-sessione-viva.mjs +329 -0
  271. package/vendor/harness-ui/src/browser-stream.mjs +445 -0
  272. package/vendor/harness-ui/src/browser-vivo.mjs +694 -0
  273. package/vendor/harness-ui/src/chat-image-attachments.mjs +72 -0
  274. package/vendor/harness-ui/src/config.mjs +697 -0
  275. package/vendor/harness-ui/src/contesto-del-progetto.mjs +385 -0
  276. package/vendor/harness-ui/src/context-asset-adapter.mjs +72 -0
  277. package/vendor/harness-ui/src/context-desktop-service.mjs +253 -0
  278. package/vendor/harness-ui/src/context-embedding-runtime.mjs +252 -0
  279. package/vendor/harness-ui/src/context-inference-scheduler.mjs +81 -0
  280. package/vendor/harness-ui/src/context-native-compaction.mjs +75 -0
  281. package/vendor/harness-ui/src/context-provider-adapter.mjs +141 -0
  282. package/vendor/harness-ui/src/context-runtime.mjs +118 -0
  283. package/vendor/harness-ui/src/context-token-counters.mjs +184 -0
  284. package/vendor/harness-ui/src/context-tool-catalog.mjs +86 -0
  285. package/vendor/harness-ui/src/context-tool-output.mjs +72 -0
  286. package/vendor/harness-ui/src/costo-elenco.mjs +252 -0
  287. package/vendor/harness-ui/src/custom-task.mjs +171 -0
  288. package/vendor/harness-ui/src/doctor.mjs +142 -0
  289. package/vendor/harness-ui/src/document-filename.mjs +97 -0
  290. package/vendor/harness-ui/src/document-generator.mjs +493 -0
  291. package/vendor/harness-ui/src/document-report.mjs +331 -0
  292. package/vendor/harness-ui/src/duckduckgo-search.mjs +155 -0
  293. package/vendor/harness-ui/src/elenco-profondo.mjs +337 -0
  294. package/vendor/harness-ui/src/favicon-proxy.mjs +113 -0
  295. package/vendor/harness-ui/src/forge-contract.mjs +221 -0
  296. package/vendor/harness-ui/src/frequent-dirs.mjs +134 -0
  297. package/vendor/harness-ui/src/generated-image-store.mjs +147 -0
  298. package/vendor/harness-ui/src/generation-idle.mjs +332 -0
  299. package/vendor/harness-ui/src/gguf-header.mjs +207 -0
  300. package/vendor/harness-ui/src/git-service.mjs +626 -0
  301. package/vendor/harness-ui/src/gitignore-elenco.mjs +604 -0
  302. package/vendor/harness-ui/src/harness-receipt-keypair.mjs +207 -0
  303. package/vendor/harness-ui/src/hf-direct-transfer.mjs +170 -0
  304. package/vendor/harness-ui/src/hf-hub-client.mjs +106 -0
  305. package/vendor/harness-ui/src/hf-image-proxy.mjs +105 -0
  306. package/vendor/harness-ui/src/hf-model-transfer.mjs +245 -0
  307. package/vendor/harness-ui/src/hook-registry.mjs +186 -0
  308. package/vendor/harness-ui/src/http-app.mjs +6259 -0
  309. package/vendor/harness-ui/src/http-lifecycle.mjs +132 -0
  310. package/vendor/harness-ui/src/id-archivio.mjs +27 -0
  311. package/vendor/harness-ui/src/image-generator.mjs +143 -0
  312. package/vendor/harness-ui/src/istruzioni-di-progetto.mjs +234 -0
  313. package/vendor/harness-ui/src/kernel/dist/kernelPerIlBanco.js +518 -0
  314. package/vendor/harness-ui/src/kernel/talosHarness.mjs +10437 -0
  315. package/vendor/harness-ui/src/library-policy-store.mjs +175 -0
  316. package/vendor/harness-ui/src/library-store.mjs +652 -0
  317. package/vendor/harness-ui/src/llama-server-supervisor.mjs +629 -0
  318. package/vendor/harness-ui/src/local-model-store.mjs +339 -0
  319. package/vendor/harness-ui/src/local-runtime-contract.mjs +66 -0
  320. package/vendor/harness-ui/src/local-runtime-events.mjs +44 -0
  321. package/vendor/harness-ui/src/local-runtime-llama-server.mjs +244 -0
  322. package/vendor/harness-ui/src/local-runtime-probe.mjs +401 -0
  323. package/vendor/harness-ui/src/machine-capacity.mjs +66 -0
  324. package/vendor/harness-ui/src/mappa-cartelle.mjs +491 -0
  325. package/vendor/harness-ui/src/mcp-client.mjs +98 -0
  326. package/vendor/harness-ui/src/mcp-registry.mjs +157 -0
  327. package/vendor/harness-ui/src/mcp-session.mjs +177 -0
  328. package/vendor/harness-ui/src/memory-store.mjs +227 -0
  329. package/vendor/harness-ui/src/model-catalog-models-dev.mjs +276 -0
  330. package/vendor/harness-ui/src/model-catalog.mjs +129 -0
  331. package/vendor/harness-ui/src/model-destination.mjs +189 -0
  332. package/vendor/harness-ui/src/modifica-ancorata.mjs +177 -0
  333. package/vendor/harness-ui/src/native-provider-adapter.mjs +205 -0
  334. package/vendor/harness-ui/src/notes-store.mjs +250 -0
  335. package/vendor/harness-ui/src/openai-compatible-runtime.mjs +428 -0
  336. package/vendor/harness-ui/src/openrouter-oauth.mjs +339 -0
  337. package/vendor/harness-ui/src/path-policy.mjs +442 -0
  338. package/vendor/harness-ui/src/plugin-registry.mjs +780 -0
  339. package/vendor/harness-ui/src/plugin-session.mjs +180 -0
  340. package/vendor/harness-ui/src/process-policy.mjs +345 -0
  341. package/vendor/harness-ui/src/prompt-enhancer-provider.mjs +94 -0
  342. package/vendor/harness-ui/src/provider-auth-cloud.mjs +95 -0
  343. package/vendor/harness-ui/src/provider-credential-store.mjs +541 -0
  344. package/vendor/harness-ui/src/provider-probe.mjs +582 -0
  345. package/vendor/harness-ui/src/provider-registry.mjs +1633 -0
  346. package/vendor/harness-ui/src/pty-terminal.mjs +312 -0
  347. package/vendor/harness-ui/src/public-problem.mjs +109 -0
  348. package/vendor/harness-ui/src/research/card.mjs +235 -0
  349. package/vendor/harness-ui/src/research/citations.mjs +142 -0
  350. package/vendor/harness-ui/src/research/collector.mjs +275 -0
  351. package/vendor/harness-ui/src/research/deposito-a-pezzi.mjs +139 -0
  352. package/vendor/harness-ui/src/research/dossier.mjs +114 -0
  353. package/vendor/harness-ui/src/research/esportazioni.mjs +560 -0
  354. package/vendor/harness-ui/src/research/fetch-cache.mjs +465 -0
  355. package/vendor/harness-ui/src/research/fidelity.mjs +122 -0
  356. package/vendor/harness-ui/src/research/independence.mjs +159 -0
  357. package/vendor/harness-ui/src/research/ledger.mjs +166 -0
  358. package/vendor/harness-ui/src/research/markdown-server.mjs +565 -0
  359. package/vendor/harness-ui/src/research/narration.mjs +181 -0
  360. package/vendor/harness-ui/src/research/open-cards.mjs +131 -0
  361. package/vendor/harness-ui/src/research/opposing.mjs +305 -0
  362. package/vendor/harness-ui/src/research/outline.mjs +111 -0
  363. package/vendor/harness-ui/src/research/page-budget.mjs +209 -0
  364. package/vendor/harness-ui/src/research/pdf.mjs +291 -0
  365. package/vendor/harness-ui/src/research/plan.mjs +301 -0
  366. package/vendor/harness-ui/src/research/raccolta-viva.mjs +452 -0
  367. package/vendor/harness-ui/src/research/recheck-document.mjs +69 -0
  368. package/vendor/harness-ui/src/research/recheck-history.mjs +192 -0
  369. package/vendor/harness-ui/src/research/recheck.mjs +194 -0
  370. package/vendor/harness-ui/src/research/report.mjs +203 -0
  371. package/vendor/harness-ui/src/research/run.mjs +527 -0
  372. package/vendor/harness-ui/src/research/synthesis.mjs +318 -0
  373. package/vendor/harness-ui/src/research/verification.mjs +572 -0
  374. package/vendor/harness-ui/src/research-orchestrator.mjs +2679 -0
  375. package/vendor/harness-ui/src/research-store.mjs +1133 -0
  376. package/vendor/harness-ui/src/runtime-build-manifest.mjs +26 -0
  377. package/vendor/harness-ui/src/runtime-contract.mjs +59 -0
  378. package/vendor/harness-ui/src/runtime-owner-adapter.mjs +1348 -0
  379. package/vendor/harness-ui/src/runtime-owner-contract.mjs +32 -0
  380. package/vendor/harness-ui/src/scheda-di-lavoro.mjs +249 -0
  381. package/vendor/harness-ui/src/search-source-store.mjs +172 -0
  382. package/vendor/harness-ui/src/session-registry.mjs +6095 -0
  383. package/vendor/harness-ui/src/session-store.mjs +220 -0
  384. package/vendor/harness-ui/src/sessione-pronta.mjs +73 -0
  385. package/vendor/harness-ui/src/setup-stato.mjs +31 -0
  386. package/vendor/harness-ui/src/sezioni-istruzioni.mjs +204 -0
  387. package/vendor/harness-ui/src/skill-registry.mjs +120 -0
  388. package/vendor/harness-ui/src/sse-replay-coalescente.mjs +0 -0
  389. package/vendor/harness-ui/src/static-files.mjs +96 -0
  390. package/vendor/harness-ui/src/stream-partition.mjs +123 -0
  391. package/vendor/harness-ui/src/subagent-orchestrator.mjs +453 -0
  392. package/vendor/harness-ui/src/task-catalog.mjs +65 -0
  393. package/vendor/harness-ui/src/tasks-store.mjs +220 -0
  394. package/vendor/harness-ui/src/terminal-registry.mjs +312 -0
  395. package/vendor/harness-ui/src/terminal-ws.mjs +170 -0
  396. package/vendor/harness-ui/src/tool-forge-store.mjs +299 -0
  397. package/vendor/harness-ui/src/tool-schema-normalize.mjs +100 -0
  398. package/vendor/harness-ui/src/usage-cache.mjs +315 -0
  399. package/vendor/harness-ui/src/workspace-browser.mjs +213 -0
  400. package/vendor/harness-ui/src/workspace-context.mjs +124 -0
  401. package/vendor/harness-ui/src/workspace-disk.mjs +62 -0
  402. package/vendor/harness-ui/src/workspace-files.mjs +589 -0
  403. package/vendor/harness-ui/src/workspace-info.mjs +189 -0
  404. package/vendor/harness-ui/src/workspace-launch-store.mjs +150 -0
  405. package/vendor/harness-ui/src/workspace-tree.mjs +67 -0
  406. package/vendor/harness-ui/src/workspace-watcher.mjs +161 -0
  407. package/vendor/manifest.json +170 -0
@@ -0,0 +1,436 @@
1
+ import { createRedactor } from "../diagnostics/redact.js";
2
+ import { createV2EventBridge } from "../protocol/v2/events.js";
3
+ import { describeError, describeKernelNotice, describeKernelRefusalReason, describeKernelToolText, errorViewLines } from "../i18n/error-view.js";
4
+ import { t } from "../i18n/index.js";
5
+ import { REFUSAL_VIA, looksItalian } from "../i18n/kernel-map.js";
6
+ import { toolDisplay } from "./tool-display.js";
7
+ function objectValue(value) {
8
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : null;
9
+ }
10
+ function stringValue(value) {
11
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
12
+ }
13
+ function booleanValue(value) {
14
+ return typeof value === 'boolean' ? value : undefined;
15
+ }
16
+ function isCanonicalEvent(value) {
17
+ if (!value || typeof value !== 'object')
18
+ return false;
19
+ const row = value;
20
+ return row.schema === 'talos.cli.event.v2' && row.version === 2 && typeof row.sessionId === 'string'
21
+ && typeof row.eventId === 'string' && typeof row.type === 'string' && Boolean(row.data && typeof row.data === 'object');
22
+ }
23
+ function asToolResult(data) {
24
+ const receipt = objectValue(data.receipt);
25
+ const status = data.status;
26
+ if (typeof data.toolCallId !== 'string' || typeof data.content !== 'string' || typeof status !== 'string' || !receipt)
27
+ return null;
28
+ return data;
29
+ }
30
+ function compactToolOutcome(result) {
31
+ const structured = result.status !== 'completed' || result.receipt.status !== null || result.receipt.allowed !== null
32
+ || result.receipt.via !== null || result.receipt.reason !== null || result.receipt.risk !== null || result.enforcement !== null;
33
+ if (!structured)
34
+ return undefined;
35
+ return {
36
+ toolCallId: result.toolCallId,
37
+ status: result.status,
38
+ content: result.content,
39
+ receiptStatus: result.receipt.status,
40
+ exitCode: result.enforcement?.exitCode ?? null,
41
+ enforcement: result.enforcement?.sandbox ?? null,
42
+ allowed: result.receipt.allowed,
43
+ permissionVia: result.receipt.via,
44
+ permissionReason: result.receipt.reason,
45
+ risk: result.receipt.risk,
46
+ };
47
+ }
48
+ function canonicalError(data) {
49
+ const row = objectValue(data.error);
50
+ const envelope = objectValue(row?.envelope);
51
+ return row && typeof row.message === 'string' && envelope ? row : undefined;
52
+ }
53
+ function identity(event) { return { eventId: event.eventId }; }
54
+ /*
55
+ * R1 lane R (D-04, gate E9): the kernel records the person's prompt ONLY as `RunStarted.input.consegna` (measured through the
56
+ * real composition, r1-resume-history.test.ts); no `TextMessageStart role:user` exists, so a replay rebuilt no user message.
57
+ * The prompt is shown as it was typed: the project-reference blocks `renderPromptWithAttachments` appends
58
+ * (runtime/attachments.ts:65-70) are cut, the `@path` the person wrote stays. The local runtime passes chat messages instead.
59
+ */
60
+ const REFERENCE_BLOCKS = '\n\n[TALOS project reference: ', REFERENCE_END = '[End TALOS project reference]';
61
+ function typedPrompt(value) { const cut = value.indexOf(REFERENCE_BLOCKS); return cut >= 0 && value.endsWith(REFERENCE_END) ? value.slice(0, cut) : value; }
62
+ function messageText(content) {
63
+ if (typeof content === 'string')
64
+ return content;
65
+ if (!Array.isArray(content))
66
+ return undefined;
67
+ const parts = content.map(part => objectValue(part)).filter(part => part?.type === 'text' && typeof part.text === 'string').map(part => String(part.text));
68
+ return parts.length ? parts.join('\n') : undefined;
69
+ }
70
+ export function runPrompt(input) {
71
+ if (Array.isArray(input)) {
72
+ for (let i = input.length - 1; i >= 0; i--) {
73
+ const row = objectValue(input[i]);
74
+ if (row?.role === 'user')
75
+ return stringValue(messageText(row.content));
76
+ }
77
+ return undefined;
78
+ }
79
+ /* R2 lane J (E11): protocol v2 renames `consegna` to `prompt`; the TUI reads both. */
80
+ const text = stringValue(objectValue(input)?.prompt) ?? stringValue(objectValue(input)?.consegna);
81
+ return text === undefined ? undefined : stringValue(typedPrompt(text));
82
+ }
83
+ function role(value) { return value === 'user' ? 'user' : 'assistant'; }
84
+ function countOrNull(value) { return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? Math.round(value) : null; }
85
+ /* R5a lane R (S10): a kernel tool id in the screen's words, for the English refusal reasons. */
86
+ const toolLabel = (id) => { try {
87
+ return toolDisplay(id).label;
88
+ }
89
+ catch {
90
+ return id;
91
+ } };
92
+ /** The screen's copy of a tool result: the kernel's Italian refusal reason in English (display only; v2 keeps the kernel's). */
93
+ function displayReceipt(result) {
94
+ const reason = result.receipt.reason;
95
+ if (!reason)
96
+ return result;
97
+ const english = describeKernelRefusalReason(reason, { toolLabel });
98
+ return english && english !== reason ? { ...result, receipt: { ...result.receipt, reason: english } } : result;
99
+ }
100
+ function projectCanonical(event) {
101
+ const id = identity(event);
102
+ const data = event.data;
103
+ switch (event.type) {
104
+ case 'run.started': {
105
+ const runId = stringValue(data.runId), prompt = runPrompt(data.input);
106
+ return { type: 'run.started', sessionId: event.sessionId, ...(runId ? { runId } : {}), ...(prompt ? { prompt } : {}), ...id };
107
+ }
108
+ case 'message.started':
109
+ return { type: 'message.started', messageId: String(data.messageId ?? 'assistant'), role: role(data.role), ...id };
110
+ case 'message.delta': {
111
+ /* R2 lane E (gate E4): a kernel notice arrives as one whole assistant message (no code); only its exact template is
112
+ replaced, so the model's own words are never touched. */
113
+ const delta = String(data.delta ?? '');
114
+ return { type: 'message.delta', messageId: String(data.messageId ?? 'assistant'), delta: describeKernelNotice(delta) ?? delta, ...id };
115
+ }
116
+ case 'message.completed':
117
+ return { type: 'message.end', messageId: String(data.messageId ?? 'assistant'), ...id };
118
+ case 'reasoning.started':
119
+ return { type: 'reasoning.started', messageId: String(data.messageId ?? 'reasoning'), ...id };
120
+ case 'reasoning.delta':
121
+ return { type: 'reasoning.delta', messageId: String(data.messageId ?? 'reasoning'), delta: String(data.delta ?? ''), ...id };
122
+ case 'reasoning.completed':
123
+ return { type: 'reasoning.end', messageId: String(data.messageId ?? 'reasoning'), ...id };
124
+ case 'tool.started':
125
+ return { type: 'tool.started', toolCallId: String(data.toolCallId ?? ''), toolName: String(data.toolName ?? 'tool'), ...id };
126
+ case 'tool.args':
127
+ return { type: 'tool.args', toolCallId: String(data.toolCallId ?? ''), delta: String(data.delta ?? ''), ...id };
128
+ case 'tool.output':
129
+ return { type: 'tool.output', toolCallId: String(data.toolCallId ?? ''), delta: String(data.delta ?? ''), ...id };
130
+ case 'tool.completed': {
131
+ const canonical = asToolResult(data);
132
+ if (!canonical)
133
+ return null;
134
+ /* R3 Q-R3-8 (R3-INT): the kernel's stop sentences in English, on the display copy only; a tool the person stopped is
135
+ `cancelled` (shown as interrupted), never `failed`. The canonical v2 result is untouched. */
136
+ const shown = describeKernelToolText(canonical.content);
137
+ const result = displayReceipt(shown.text === canonical.content && !shown.stopped ? canonical : { ...canonical, content: shown.text, ...(shown.stopped ? { status: 'cancelled' } : {}) });
138
+ const outcome = compactToolOutcome(result);
139
+ return {
140
+ type: 'tool.completed', toolCallId: result.toolCallId, content: result.content, result,
141
+ ...(outcome ? { outcome } : {}), ...id
142
+ };
143
+ }
144
+ case 'file.changed':
145
+ return { type: 'file.changed', data: { ...data }, ...id };
146
+ case 'approval.required': {
147
+ const payload = objectValue(data.azione ?? data.action) ?? {};
148
+ const toolCallId = stringValue(payload.toolCallId);
149
+ return {
150
+ type: 'approval.required',
151
+ requestId: String(data.requestId ?? ''),
152
+ payload: { ...payload },
153
+ ...(toolCallId ? { toolCallId } : {}),
154
+ ...id
155
+ };
156
+ }
157
+ case 'approval.resolved': {
158
+ const approved = booleanValue(data.approvato) ?? booleanValue(data.approved);
159
+ return { type: 'approval.resolved', requestId: String(data.requestId ?? ''), ...(approved !== undefined ? { approved } : {}), ...id };
160
+ }
161
+ case 'usage.updated': {
162
+ /* R5a lane R (S1): the last request's own usage and the run's declared cost ride inside the value (additive keys), so the
163
+ state keeps one usage object and `usageSnapshot` reads them there. */
164
+ const value = objectValue(data.value);
165
+ const lastRequest = objectValue(data.lastRequest);
166
+ const declared = countOrNull(data.declaredCostUsd) === null ? null : Number(data.declaredCostUsd);
167
+ if (!value || (!lastRequest && declared === null))
168
+ return { type: 'usage.updated', value: data.value, ...id };
169
+ return { type: 'usage.updated', value: { ...value, ...(lastRequest ? { lastRequest: { ...lastRequest } } : {}), ...(declared !== null ? { declaredCostUsd: declared } : {}) }, ...id };
170
+ }
171
+ case 'provider.attempt': {
172
+ const attempt = countOrNull(data.attempt), maxAttempts = countOrNull(data.maxAttempts);
173
+ if (attempt === null || maxAttempts === null)
174
+ return null;
175
+ return { type: 'provider.attempt', attempt, maxAttempts, status: countOrNull(data.status), retryAfterMs: countOrNull(data.retryAfterMs), waitMs: countOrNull(data.waitMs), ...id };
176
+ }
177
+ case 'context.summary.requested': return { type: 'context.summary.requested', ...id };
178
+ case 'context.compaction.paused': {
179
+ const code = typeof data.code === 'string' ? data.code : '', retryAfter = typeof data.retryAfter === 'string' ? data.retryAfter : '';
180
+ if (!code || !Number.isFinite(Date.parse(retryAfter)))
181
+ return null;
182
+ return { type: 'context.compaction.paused', noticeId: typeof data.noticeId === 'string' ? data.noticeId : null, code, attempts: countOrNull(data.attempts), waitSeconds: countOrNull(data.waitSeconds), retryAfter, ...id };
183
+ }
184
+ case 'context.compacted': {
185
+ const trigger = data.trigger === 'manual' || data.trigger === 'automatic' ? data.trigger : null;
186
+ return { type: 'context.compacted', engine: data.engine === 'context-engine' ? 'context-engine' : 'kernel', messagesSummarized: countOrNull(data.messagesSummarized),
187
+ tokensBefore: countOrNull(data.tokensBefore), tokensAfter: countOrNull(data.tokensAfter), ...(trigger ? { trigger } : {}), ...id };
188
+ }
189
+ case 'warning': {
190
+ /* R2 lane E (Q-R2-2): a kernel notice has no code (`onAvviso`, RuntimeFallback): Italian text is replaced by one English
191
+ sentence and kept as `raw` for the expanded view and the log; the CLI's own English notices pass unchanged. */
192
+ const message = String(data.message ?? 'warning');
193
+ return looksItalian(message) ? { type: 'warning', message: t('error.warning.untranslated'), raw: message, ...id } : { type: 'warning', message, ...id };
194
+ }
195
+ case 'session.snapshot':
196
+ return { type: 'session.snapshot', data: { ...data }, ...id };
197
+ case 'run.completed': {
198
+ const runId = stringValue(data.runId);
199
+ return { type: 'run.completed', ...(runId ? { runId } : {}), ...id };
200
+ }
201
+ case 'run.failed': {
202
+ const error = canonicalError(data);
203
+ const runId = stringValue(data.runId);
204
+ /* R2 lane E (gate E4, Q-R2-4): the message is the English three-part view of the CODE; the kernel's text rides along
205
+ only inside `error` (the transcript keeps it as the row's raw detail). */
206
+ const view = describeError(error ?? { message: String(data.message ?? 'run failed'), code: data.code });
207
+ return {
208
+ type: 'run.failed',
209
+ message: errorViewLines(view).join('\n'),
210
+ ...(error ? { error } : {}),
211
+ ...(runId ? { runId } : {}),
212
+ ...id
213
+ };
214
+ }
215
+ case 'run.cancelled': {
216
+ const runId = stringValue(data.runId);
217
+ const reason = stringValue(data.reason);
218
+ return { type: 'run.cancelled', ...(runId ? { runId } : {}), ...(reason ? { reason } : {}), ...id };
219
+ }
220
+ default:
221
+ return null;
222
+ }
223
+ }
224
+ /*
225
+ * R3 gate E3 (Q-R3-1/2): the facts of a finished tool, from structured fields only: the receipt's exit code, the kernel's
226
+ * measured `durataMs` (v2 `details.durationMs`, talosHarness.mjs:8661), and the isolation named by the glyph the CLI's own
227
+ * executor puts first in its annotation (`EXECUTION_TEXT.isolation`: ⛉ sandbox, ⛶ host). An absent fact stays absent: a
228
+ * zero would say "instant" or "exit 0" where the truth is unknown (agui-events.mjs OSS-1).
229
+ */
230
+ const SANDBOX_GLYPH = '⛉', HOST_GLYPH = '⛶';
231
+ export function isolationOf(enforcement) {
232
+ if (typeof enforcement !== 'string')
233
+ return null;
234
+ const head = enforcement.trimStart();
235
+ return head.startsWith(SANDBOX_GLYPH) ? 'sandbox' : head.startsWith(HOST_GLYPH) ? 'host' : null;
236
+ }
237
+ function toolFacts(result, noted = null) {
238
+ const exitCode = result.enforcement?.exitCode, durationMs = objectValue(result.details)?.durationMs, isolation = isolationOf(result.enforcement?.sandbox);
239
+ const denial = noted ?? kernelDenial(result);
240
+ const facts = {
241
+ ...(typeof exitCode === 'number' && Number.isInteger(exitCode) ? { exitCode } : {}),
242
+ ...(typeof durationMs === 'number' && Number.isFinite(durationMs) && durationMs >= 0 ? { durationMs: Math.round(durationMs) } : {}),
243
+ ...(isolation ? { isolation } : {}),
244
+ ...(denial ? { denial } : {}),
245
+ };
246
+ return Object.keys(facts).length ? facts : null;
247
+ }
248
+ /*
249
+ * R5a lane R (S10, gate finding 15). Why a refused tool did not run, from the receipt alone, only when the receipt can say
250
+ * it: the session's own level (read-only, research, workspace writes, a tool turned off) is `mode`; the kernel's floors (a
251
+ * command that cannot be undone, the checkpoint guard) are `policy`. An "asked" via is NOT decided here: the kernel writes
252
+ * the same via and the same sentence whether the person said no or the permission engine answered alone (finding 15), so
253
+ * only the session controller, which asked, can say which (`noteDenial`). A stop is not a denial.
254
+ */
255
+ const MODE_VIAS = new Set(['toolOff', 'readOnly', 'research', 'workspaceWrite']);
256
+ const POLICY_VIAS = new Set(['noRecovery', 'checkpoint']);
257
+ function kernelDenial(result) {
258
+ if (result.receipt.allowed !== false && result.receipt.status !== 'denied')
259
+ return null;
260
+ const key = result.receipt.via ? REFUSAL_VIA[result.receipt.via] : undefined;
261
+ if (!key || (!MODE_VIAS.has(key) && !POLICY_VIAS.has(key)))
262
+ return null;
263
+ const english = result.receipt.reason ? describeKernelRefusalReason(result.receipt.reason, { toolLabel }) : null;
264
+ const reason = english ?? (result.receipt.reason && !looksItalian(result.receipt.reason) ? result.receipt.reason : null);
265
+ return { by: MODE_VIAS.has(key) ? 'mode' : 'policy', ...(reason ? { reason } : {}) };
266
+ }
267
+ /**
268
+ * R5a lane R (S10): the denial fact for a decision the permission engine made ALONE (`ApprovalDecision` deny,
269
+ * security/permission-engine.ts:36-44), in English. A matched deny rule is `rule` with its text (`explain.rule`, e.g. the
270
+ * rule `simulatePermission` names) and scope; a command the policy cannot split (`unsupported shell composition`,
271
+ * security/evaluate.ts:134-140) or a path outside the project is `policy`; plan mode, a mode that never asks and the automatic
272
+ * classifier are `mode`. The person's own "no" is `{by:'person'}`, and nothing else is.
273
+ */
274
+ export function denialFromEngine(decision, explain = {}) {
275
+ const code = String(decision?.code ?? '');
276
+ const message = String(decision?.message ?? '');
277
+ const because = (id) => ({ by: code === 'PATH_NOT_ALLOWED' || id === 'error.denial.reason.unsupportedShell' || id === 'error.denial.reason.pathOutside' ? 'policy' : 'mode', reason: t(id) });
278
+ if (code === 'PLAN_MODE_READ_ONLY')
279
+ return because('error.denial.reason.planMode');
280
+ if (code === 'PERMISSION_REQUIRED')
281
+ return because('error.denial.reason.noAsking');
282
+ if (code === 'PERMISSION_AUTO_DENIED')
283
+ return because('error.denial.reason.autoDenied');
284
+ if (code === 'PATH_NOT_ALLOWED')
285
+ return because('error.denial.reason.pathOutside');
286
+ if (/(?:^|: )matched deny rule$/u.test(message)) {
287
+ let rule = null;
288
+ try {
289
+ rule = explain.rule?.() ?? null;
290
+ }
291
+ catch {
292
+ rule = null;
293
+ }
294
+ let scope = null;
295
+ try {
296
+ scope = rule ? explain.scope?.(rule) ?? null : null;
297
+ }
298
+ catch {
299
+ scope = null;
300
+ }
301
+ return { by: 'rule', ...(rule ? { rule } : {}), ...(scope ? { scope } : {}) };
302
+ }
303
+ if (/unsupported shell composition$/u.test(message))
304
+ return because('error.denial.reason.unsupportedShell');
305
+ if (/write path is outside the authorized project$/u.test(message))
306
+ return because('error.denial.reason.pathOutside');
307
+ return { by: 'policy', ...(message && !looksItalian(message) ? { reason: message } : {}) };
308
+ }
309
+ /*
310
+ * R3 gate E10 (Q-R3-4): a file the kernel wrote arrives as `StateDelta` rows `/file/<path>` with the text after and, for a
311
+ * file that existed, the text before (`prima`) (agui-events.mjs:427-436); the v2 bridge keeps only `/usage`, so the TUI
312
+ * reads the rows here, through the same redactor as every v2 string. A replaced file whose before is unknown is skipped
313
+ * (it must not look new); texts over MAX_FILE_CHANGE_CHARS are skipped (the diff of a huge file is not a screen). The change
314
+ * belongs to the open tool call whose arguments name the same path, or else to the only open call.
315
+ */
316
+ const MAX_FILE_CHANGE_CHARS = 1_000_000, MAX_OPEN_ARGS_CHARS = 65_536;
317
+ function samePath(value) { return value.replace(/\\/gu, '/').replace(/^\.\//u, ''); }
318
+ function argsPath(args) {
319
+ try {
320
+ const parsed = objectValue(JSON.parse(args));
321
+ const value = parsed?.percorso ?? parsed?.path ?? parsed?.file_path;
322
+ return typeof value === 'string' && value ? samePath(value) : null;
323
+ }
324
+ catch {
325
+ return null;
326
+ }
327
+ }
328
+ export function createTuiEventAdapter(secretValues = []) {
329
+ let currentSessionId = null;
330
+ let bridge = null;
331
+ const redactor = createRedactor(secretValues);
332
+ const openTools = new Map();
333
+ /* R5a lane R (S10): the denial facts the session controller noted, by tool call, until the tool's result arrives. */
334
+ const noted = new Map();
335
+ /* R5a lane R (S3): the kernel compactions seen live in this run (the fetch observer's event). */
336
+ let liveKernelCompactions = 0;
337
+ function bindSession(sessionId) {
338
+ if (typeof sessionId !== 'string' || sessionId.length === 0)
339
+ throw new Error('SESSION_ID_REQUIRED');
340
+ if (sessionId === currentSessionId && bridge)
341
+ return;
342
+ currentSessionId = sessionId;
343
+ openTools.clear();
344
+ noted.clear();
345
+ liveKernelCompactions = 0;
346
+ bridge = createV2EventBridge(sessionId, undefined, secretValues);
347
+ }
348
+ function canonicalOf(raw) {
349
+ if (isCanonicalEvent(raw))
350
+ return raw;
351
+ if (!raw || typeof raw !== 'object' || !bridge)
352
+ return null;
353
+ return bridge.translate(raw);
354
+ }
355
+ function translate(raw) {
356
+ const canonical = canonicalOf(raw);
357
+ return canonical ? projectCanonical(canonical) : null;
358
+ }
359
+ /**
360
+ * R5a lane R (S10): the session controller tells the adapter who refused a tool BEFORE its result arrives — the person
361
+ * (`{by:'person'}`, only after asking) or the engine alone (`denialFromEngine`). The next `tool.facts` of that call carries it.
362
+ */
363
+ function noteDenial(toolCallId, denial) {
364
+ if (typeof toolCallId !== 'string' || !toolCallId || !denial)
365
+ return;
366
+ noted.set(toolCallId, denial);
367
+ if (noted.size > 256)
368
+ noted.delete(noted.keys().next().value);
369
+ }
370
+ function fileChanges(raw) {
371
+ if (raw.type !== 'StateDelta' || !Array.isArray(raw.delta))
372
+ return [];
373
+ const out = [];
374
+ for (const entry of raw.delta) {
375
+ const row = objectValue(entry);
376
+ const where = stringValue(row?.path);
377
+ if (!row || !where?.startsWith('/file/') || typeof row.value !== 'string' || (row.op !== 'add' && row.op !== 'replace'))
378
+ continue;
379
+ const before = row.op === 'add' ? null : typeof row.prima === 'string' ? row.prima : undefined;
380
+ if (before === undefined || row.value.length > MAX_FILE_CHANGE_CHARS || (before?.length ?? 0) > MAX_FILE_CHANGE_CHARS)
381
+ continue;
382
+ const path = where.slice('/file/'.length);
383
+ const owners = [...openTools].filter(([, args]) => argsPath(args) === samePath(path)).map(([id]) => id);
384
+ /* The call whose arguments name the path; failing that, the only open call (lane RD matches by path otherwise). */
385
+ const owner = owners.length === 1 ? owners[0] : owners.length === 0 && openTools.size === 1 ? [...openTools.keys()][0] : undefined;
386
+ const change = { path: redactor.text(path), before: before === null ? null : redactor.text(before), after: redactor.text(row.value), ...(owner ? { toolCallId: owner } : {}) };
387
+ out.push({ type: 'file.changed', change });
388
+ }
389
+ return out;
390
+ }
391
+ function translateAll(raw) {
392
+ const canonical = canonicalOf(raw);
393
+ const event = canonical ? projectCanonical(canonical) : null;
394
+ const out = event ? [event] : [];
395
+ if (event?.type === 'run.started')
396
+ liveKernelCompactions = 0;
397
+ else if (event?.type === 'context.compacted' && event.engine === 'kernel' && event.trigger !== 'manual')
398
+ liveKernelCompactions++;
399
+ if (event?.type === 'run.completed') {
400
+ /* R5a lane R (S3): the kernel counts its own compactions in the run's result (`compattazioni` → v2 `compactions`,
401
+ agent-service.mjs:182). A compaction the live observer did not report — every one, in a replay, where live events do
402
+ not exist — is named here, before the run ends, with what is known: nothing but that it happened. */
403
+ const total = countOrNull(objectValue(objectValue(canonical?.data)?.result)?.compactions) ?? 0;
404
+ const missing = Math.max(0, total - liveKernelCompactions);
405
+ for (let i = 0; i < missing; i++)
406
+ out.unshift({ type: 'context.compacted', engine: 'kernel', messagesSummarized: null, tokensBefore: null, tokensAfter: null, trigger: 'automatic' });
407
+ liveKernelCompactions = 0;
408
+ }
409
+ if (event?.type === 'tool.started')
410
+ openTools.set(event.toolCallId, '');
411
+ else if (event?.type === 'run.completed' || event?.type === 'run.failed' || event?.type === 'run.cancelled')
412
+ openTools.clear();
413
+ else if (event?.type === 'tool.args' && openTools.has(event.toolCallId))
414
+ openTools.set(event.toolCallId, (openTools.get(event.toolCallId) + event.delta).slice(0, MAX_OPEN_ARGS_CHARS));
415
+ else if (event?.type === 'tool.completed') {
416
+ openTools.delete(event.toolCallId);
417
+ const denial = noted.get(event.toolCallId) ?? null;
418
+ noted.delete(event.toolCallId);
419
+ const facts = event.result ? toolFacts(event.result, denial) : null;
420
+ if (facts)
421
+ out.push({ type: 'tool.facts', toolCallId: event.toolCallId, facts });
422
+ /* R5a lane R (Q-R5-10/11): the cut the model read, as facts the row states (the v2 result carries them). */
423
+ const saved = event.result?.outputSaved;
424
+ if (saved?.path)
425
+ out.push({ type: 'tool.output.saved', toolCallId: event.toolCallId, path: saved.path, keptChars: saved.keptChars, totalChars: saved.totalChars });
426
+ const cut = event.result?.readCut;
427
+ if (cut)
428
+ out.push({ type: 'tool.read.cut', toolCallId: event.toolCallId, shownLines: cut.shownLines, totalLines: cut.totalLines, limitChars: cut.limitChars });
429
+ }
430
+ const row = objectValue(raw);
431
+ if (row && !isCanonicalEvent(raw))
432
+ out.push(...fileChanges(row));
433
+ return out;
434
+ }
435
+ return { bindSession, translate, translateAll, noteDenial };
436
+ }
@@ -0,0 +1,58 @@
1
+ import { sanitizeTranscriptText } from "./transcript-model.js";
2
+ import { toolRowView } from "./components/tool-row.js";
3
+ /* The resume line is pasted into a shell, so the id must be one shell word: the pattern `talos session import`
4
+ already enforces for archive ids (session-cli.ts), no leading dash, no `..`. */
5
+ const SESSION_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u;
6
+ const TOOL_ARGS_MAX = 72;
7
+ /* R3 gate E1: a tool row is the ONE row formatter's line, fitted to this width (the target is cut in the middle first). */
8
+ export const EXIT_TOOL_WIDTH = 120;
9
+ const hasText = (item) => item.kind === 'message' && item.text.trim().length > 0;
10
+ /** The id worth printing as `talos --resume <id>`: valid, and only for a session that holds a message (Qwen gating,
11
+ * startInteractiveUI.tsx:421-449 @2026-09-15, gate C10). */
12
+ export function resumableSessionId(snapshot) {
13
+ const id = snapshot?.sessionId;
14
+ if (!id || !SESSION_ID.test(id) || id.includes('..'))
15
+ return null;
16
+ return snapshot.items.some(hasText) ? id : null;
17
+ }
18
+ const oneLine = (value, max) => { const text = sanitizeTranscriptText(value).replace(/\s+/gu, ' ').trim(); return text.length > max ? text.slice(0, max - 1) + '…' : text; };
19
+ export function formatExitOutput(snapshot, { mode = 'transcript', color = false } = {}) {
20
+ if (!snapshot || !snapshot.items.some(hasText))
21
+ return '';
22
+ const bold = (text) => color ? `\u001b[1m${text}\u001b[22m` : text;
23
+ const dim = (text) => color ? `\u001b[2m${text}\u001b[22m` : text;
24
+ const id = resumableSessionId(snapshot);
25
+ const resume = id ? `${dim('To resume this session:')} talos --resume ${id}\n` : '';
26
+ if (mode === 'resume')
27
+ return resume;
28
+ /* Blocks are separated by one blank line; consecutive one-line rows (tools, run outcomes) stay together. Reasoning
29
+ and local notices (help, /status, warnings) are screen chrome, not the conversation, so they are left out. */
30
+ const blocks = [];
31
+ let rows = null;
32
+ const row = (text) => { if (!rows) {
33
+ rows = [];
34
+ blocks.push(rows);
35
+ } rows.push(dim(text)); };
36
+ for (const item of snapshot.items) {
37
+ if (item.kind === 'message') {
38
+ if (!hasText(item))
39
+ continue;
40
+ rows = null;
41
+ blocks.push([bold(item.role === 'user' ? 'You' : 'TALOS'), ...sanitizeTranscriptText(item.text).replace(/\s+$/u, '').split('\n')]);
42
+ }
43
+ else if (item.kind === 'tool') {
44
+ /* R3 gate E1 (R2 Q-R2-3 kept): the same header row as the screen — English label, primary argument, facts; never the
45
+ kernel name, raw JSON or the enum. The detail lines stay on the screen. */
46
+ row(toolRowView(item, EXIT_TOOL_WIDTH, false).line);
47
+ }
48
+ else if (item.kind === 'warning' && item.outcome) {
49
+ /* R3 Q-R3-8/9: a turn that did not end normally leaves its one line (its first line: the headline). */
50
+ row(oneLine(item.text.split(/\r?\n/u)[0] ?? '', EXIT_TOOL_WIDTH));
51
+ }
52
+ else if (item.kind === 'run' && (item.status === 'failed' || item.status === 'cancelled')) {
53
+ const message = oneLine(item.message.split(/\r?\n/u)[0] ?? '', TOOL_ARGS_MAX);
54
+ row(`Run ${item.status}${message ? ` · ${message}` : ''}`);
55
+ }
56
+ }
57
+ return blocks.map(block => block.join('\n') + '\n').join('\n') + (resume ? `\n${resume}` : '');
58
+ }
@@ -0,0 +1,53 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { readFile, rm, writeFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ export function parseEditorCommand(value) { const out = []; let token = '', quote = ''; for (let i = 0; i < value.length; i++) {
5
+ const ch = value[i];
6
+ if (quote) {
7
+ if (ch === quote) {
8
+ quote = '';
9
+ continue;
10
+ }
11
+ if (ch === '\\' && quote === '"' && i + 1 < value.length) {
12
+ token += value[++i];
13
+ continue;
14
+ }
15
+ token += ch;
16
+ continue;
17
+ }
18
+ if (ch === '"' || ch === "'") {
19
+ quote = ch;
20
+ continue;
21
+ }
22
+ if (/\s/u.test(ch)) {
23
+ if (token) {
24
+ out.push(token);
25
+ token = '';
26
+ }
27
+ continue;
28
+ }
29
+ if (ch === '\\' && i + 1 < value.length) {
30
+ token += value[++i];
31
+ continue;
32
+ }
33
+ token += ch;
34
+ } if (quote)
35
+ throw Object.assign(new Error('EXTERNAL_EDITOR_PARSE_FAILED'), { code: 'EXTERNAL_EDITOR_PARSE_FAILED' }); if (token)
36
+ out.push(token); if (out.length === 0)
37
+ throw Object.assign(new Error('EXTERNAL_EDITOR_NOT_CONFIGURED'), { code: 'EXTERNAL_EDITOR_NOT_CONFIGURED' }); return out; }
38
+ export async function editExternally({ text, editor, tmpRoot, spawn = spawnSync }) {
39
+ if (!editor?.trim())
40
+ throw Object.assign(new Error('EXTERNAL_EDITOR_NOT_CONFIGURED'), { code: 'EXTERNAL_EDITOR_NOT_CONFIGURED' });
41
+ const [command, ...args] = parseEditorCommand(editor);
42
+ const file = join(tmpRoot, `talos-editor-${process.pid}-${Date.now()}.txt`);
43
+ await writeFile(file, text, { encoding: 'utf8', mode: 0o600 });
44
+ try {
45
+ const result = spawn(command, [...args, file], { stdio: 'inherit', shell: false, windowsHide: false });
46
+ if (result.status !== 0)
47
+ throw Object.assign(new Error('EXTERNAL_EDITOR_FAILED'), { code: 'EXTERNAL_EDITOR_FAILED' });
48
+ return await readFile(file, 'utf8');
49
+ }
50
+ finally {
51
+ await rm(file, { force: true });
52
+ }
53
+ }
@@ -0,0 +1,89 @@
1
+ import { readdir, stat } from 'node:fs/promises';
2
+ import { isAbsolute, resolve } from 'node:path';
3
+ import { t } from "../i18n/index.js";
4
+ import { isPathInsideWorkspace, resolvePathInsideWorkspace, resolveWorkspaceIdentity } from "../security/workspace-identity.js";
5
+ import { pickerSection } from "./overlays/scroll-window.js";
6
+ import { buildProjectFileIndex, rankProjectFiles } from "./project-file-index.js";
7
+ /** The most rows the list takes, border and title included (E13: inside the R1 budget, which may give it fewer). */
8
+ export const FILE_COMPLETION_MAX_ROWS = 10;
9
+ const UNSAFE_NAME = /[\x00-\x1f\x7f\p{Zl}\p{Zp}\p{Bidi_Control}]/u;
10
+ /** The typed path after `@`: quotes removed, `\` read as `/`, repeated slashes collapsed; `folder` keeps its final `/`. */
11
+ export function projectPathQuery(token) {
12
+ const raw = (token.startsWith('@') ? token.slice(1) : token).replace(/^['"]|['"]$/gu, '').replace(/\\/gu, '/').replace(/\/{2,}/gu, '/');
13
+ const slash = raw.lastIndexOf('/');
14
+ return { path: raw, folder: slash >= 0 ? raw.slice(0, slash + 1) : '', prefix: raw.slice(slash + 1) };
15
+ }
16
+ function displayValue(path, directory) { const value = path + (directory ? '/' : ''); return /\s/u.test(value) ? `@"${value}"` : `@${value}`; }
17
+ export async function completeProjectPath(projectRoot, token) {
18
+ const workspace = await resolveWorkspaceIdentity({ projectRoot });
19
+ const { path: raw, folder, prefix } = projectPathQuery(token);
20
+ if (isAbsolute(raw) || /^[A-Za-z]:/u.test(raw))
21
+ return [];
22
+ const logicalParent = resolve(workspace.requestedRoot, folder || '.');
23
+ if (!isPathInsideWorkspace(workspace, logicalParent))
24
+ return [];
25
+ const parent = await resolvePathInsideWorkspace(workspace, logicalParent);
26
+ if (!parent)
27
+ return [];
28
+ let entries;
29
+ try {
30
+ entries = await readdir(parent, { withFileTypes: true });
31
+ }
32
+ catch {
33
+ return [];
34
+ }
35
+ const rows = [];
36
+ for (const entry of entries) {
37
+ if (!entry.name.startsWith(prefix) || UNSAFE_NAME.test(entry.name))
38
+ continue;
39
+ const canonical = await resolvePathInsideWorkspace(workspace, resolve(parent, entry.name));
40
+ if (!canonical)
41
+ continue;
42
+ let info;
43
+ try {
44
+ info = await stat(canonical);
45
+ }
46
+ catch {
47
+ continue;
48
+ }
49
+ if (!info.isDirectory() && !info.isFile())
50
+ continue;
51
+ rows.push({ name: entry.name, directory: info.isDirectory() });
52
+ }
53
+ return rows.sort((a, b) => Number(a.directory) - Number(b.directory) || a.name.localeCompare(b.name)).map(entry => ({ value: displayValue(folder + entry.name, entry.directory), directory: entry.directory }));
54
+ }
55
+ /*
56
+ * R5b D6 (Q-R5-16; plan Part III items 2 and 5): `@` with part of a name searches the whole project (project-file-index.ts);
57
+ * `@` alone and `@folder/` still browse one folder (R4). The list says where its rows come from and how many it found, and
58
+ * shows at most PROJECT_COMPLETION_SHOWN of them, saying so when there are more.
59
+ */
60
+ export const PROJECT_COMPLETION_SHOWN = 50;
61
+ export async function completeProjectFiles(projectRoot, token, { index } = {}) {
62
+ const query = projectPathQuery(token);
63
+ if (!query.path || query.path.endsWith('/'))
64
+ return { rows: await completeProjectPath(projectRoot, token), source: { kind: 'folder', folder: query.folder } };
65
+ if (isAbsolute(query.path) || /^[A-Za-z]:/u.test(query.path) || query.path.split('/').includes('..'))
66
+ return { rows: [], source: { kind: 'project', found: 0, shown: 0, capped: false, max: 0 } };
67
+ const built = await (index ? index() : buildProjectFileIndex(projectRoot));
68
+ const ranked = rankProjectFiles(built, query.path);
69
+ const shown = ranked.slice(0, PROJECT_COMPLETION_SHOWN);
70
+ return { rows: shown.map(entry => ({ value: displayValue(entry.path, entry.directory), directory: entry.directory })), source: { kind: 'project', found: ranked.length, shown: shown.length, capped: built.capped, max: built.max } };
71
+ }
72
+ function sourceLine(source) {
73
+ if (source.kind === 'folder')
74
+ return { text: t('screen.completion.sourceFolder', { folder: source.folder || t('screen.completion.thisFolder') }), tone: 'dim' };
75
+ const base = source.shown < source.found ? t('screen.completion.sourceProjectMore', { shown: source.shown, found: source.found }) : t('screen.completion.sourceProject', { found: source.found });
76
+ return { text: base + (source.capped ? t('screen.completion.sourceCapped', { max: source.max.toLocaleString('en-US') }) : ''), tone: 'dim' };
77
+ }
78
+ /* The list as app.ts draws it (single border, like the command menu), fitted by overlays/scroll-window.ts to at most
79
+ FILE_COMPLETION_MAX_ROWS and the R1 budget, the highlight kept in view; with nothing to offer, one dim line says so
80
+ (Q-R4-13: `No files match src/x`, gate §5). */
81
+ export function fileCompletionOverlay({ token, rows, selected, source }) {
82
+ const head = [{ text: t('screen.completion.title'), tone: 'strong' }, ...(source ? [sourceLine(source)] : [])];
83
+ if (!rows.length) {
84
+ const query = projectPathQuery(token);
85
+ const text = query.prefix ? t('screen.completion.none', { path: query.path }) : t('screen.completion.emptyFolder', { folder: query.folder || t('screen.completion.thisFolder') });
86
+ return { head, sections: [{ lines: [{ text, tone: 'dim' }] }], borderStyle: 'single' };
87
+ }
88
+ return { head, sections: [pickerSection(rows, selected, row => row.value)], borderStyle: 'single' };
89
+ }
@@ -0,0 +1,5 @@
1
+ export function focusForOverlay(overlay) { return overlay === 'model' ? 'model-picker' : overlay === 'provider' ? 'provider-picker' : overlay === 'session' ? 'session-picker' : overlay; }
2
+ export function createFocusState(initial) { return { current: initial, stack: [] }; }
3
+ export function openFocus(state, next) { return next === state.current ? state : { current: next, stack: [...state.stack, state.current] }; }
4
+ export function closeFocus(state) { const previous = state.stack.at(-1); if (!previous)
5
+ return state; return { current: previous, stack: state.stack.slice(0, -1) }; }