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,125 @@
1
+ /*
2
+ * R5a lane S — S1, the ONE status row (owner decisions Q-R5-2 and Q-R5-5; gate E1, E2; R3 Q-R3-13):
3
+ *
4
+ * Full access · No sandbox · model X · ↑1.2k ↓340 · cached 800 · ctx 3.1k/131k 2% · ~$0.004 · cmp 1 · 3 new
5
+ *
6
+ * It is the Hermes form (`☤ model │ 12.4K/200K │ [bar] 6% │ $0.06`, hermes `website/docs/user-guide/cli.md:149-180`,
7
+ * 2026-09-23; TUI `ui-tui/src/components/appChrome.tsx:197-215, 525-547`, 2026-09-19) plus the two R3 safety labels, which
8
+ * lead the row as they led the old footer. Pure: the facts come from lane R's `usageSnapshot` (runtime/usage-snapshot.ts).
9
+ *
10
+ * E1, no invented number: a window nobody knows is `ctx ?` (never a percentage); an estimate carries `~`; a cost is shown
11
+ * only from a named price source (`~$`, list price), `local` for a local engine, `cost ?` otherwise; token counts nobody
12
+ * reported leave their segment out, one side unknown is `?`.
13
+ * E2, one row: when the row is too wide the segments go in a fixed order — cost, cache, ↑↓, the compaction count, the
14
+ * "N new" count, then the window figure (`ctx 3.1k/131k 2%` → `ctx 2%`), then the model is cut in the middle and last
15
+ * dropped. The context figure (`ctx N%` or `ctx ?`), `Full access` and `No sandbox` are never dropped (Q-R3-13).
16
+ * The percentage is toned as Hermes colours it (50 / 80 / 95, appChrome.tsx:319-334); the number is always there, so a
17
+ * monochrome screen loses nothing.
18
+ */
19
+ import { t } from "../i18n/index.js";
20
+ import { shellSafeText } from "./components/terminal-shell.js";
21
+ import { displayWidth, truncateDisplay, truncateMiddle } from "./text-width.js";
22
+ const SEPARATOR = ' · ';
23
+ /* A model id cut shorter than this says nothing; it is dropped instead. */
24
+ const MODEL_MIN = 8;
25
+ /* The drop order of E2 (first dropped first). `context-window` shortens the context segment; `model` cuts, then drops. */
26
+ const DROP_ORDER = ['cost', 'cached', 'tokens', 'compactions', 'unseen', 'context-window', 'model'];
27
+ const count = (value) => typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : null;
28
+ /** 340 → `340`, 1,200 → `1.2k`, 131,072 → `131k`, 1,500,000 → `1.5m`. */
29
+ export function compactTokens(value) {
30
+ const n = Math.max(0, Math.round(value));
31
+ if (n < 1000)
32
+ return String(n);
33
+ if (n < 99_950)
34
+ return `${(n / 1000).toFixed(1).replace(/\.0$/u, '')}k`;
35
+ if (n < 999_500)
36
+ return `${Math.round(n / 1000)}k`;
37
+ return `${(n / 1_000_000).toFixed(1).replace(/\.0$/u, '')}m`;
38
+ }
39
+ /** A whole percentage; a used window under one percent reads `<1`, never `0` (that would say "empty"). */
40
+ export function percentText(percent) {
41
+ if (percent > 0 && percent < 1)
42
+ return '<1';
43
+ return String(Math.min(999, Math.round(percent)));
44
+ }
45
+ /** US dollars at list price: three decimals under a dollar (`0.004`), two above (`1.25`), `<0.001` for dust. */
46
+ export function costText(usd) {
47
+ if (usd > 0 && usd < 0.001)
48
+ return '<0.001';
49
+ return usd < 1 ? usd.toFixed(3) : usd.toFixed(2);
50
+ }
51
+ /** Hermes's thresholds for the context percentage (50 / 80 / 95). */
52
+ export function contextTone(percent) {
53
+ if (percent === null)
54
+ return 'normal';
55
+ return percent >= 95 ? 'critical' : percent >= 80 ? 'high' : percent >= 50 ? 'warn' : 'normal';
56
+ }
57
+ function contextSegment(snapshot) {
58
+ /* R5a wiring: `inputTokens` is the run's total; the context in use is lane R's `contextTokens` (the last request). */
59
+ const window = count(snapshot?.windowTokens), used = count(snapshot?.contextTokens), percent = count(snapshot?.percent);
60
+ if (window === null || window === 0 || percent === null)
61
+ return { id: 'context', text: t('screen.statusbar.contextUnknown'), tone: 'normal' };
62
+ const tilde = snapshot?.estimated ? '~' : '';
63
+ const short = t('screen.statusbar.contextShort', { percent: `${tilde}${percentText(percent)}` });
64
+ const text = used === null ? short : t('screen.statusbar.context', { used: `${tilde}${compactTokens(used)}`, window: compactTokens(window), percent: percentText(percent) });
65
+ return { id: 'context', text, short, tone: contextTone(percent) };
66
+ }
67
+ function tokensSegment(snapshot) {
68
+ const input = count(snapshot?.inputTokens), output = count(snapshot?.outputTokens);
69
+ if (input === null && output === null)
70
+ return null;
71
+ const tilde = snapshot?.estimated ? '~' : '', unknown = t('screen.statusbar.unknown');
72
+ return { id: 'tokens', text: t('screen.statusbar.tokens', { input: input === null ? unknown : `${tilde}${compactTokens(input)}`, output: output === null ? unknown : `${tilde}${compactTokens(output)}` }), tone: 'normal' };
73
+ }
74
+ function costSegment(snapshot) {
75
+ if (snapshot?.local)
76
+ return { id: 'cost', text: t('screen.statusbar.local'), tone: 'normal' };
77
+ const usd = count(snapshot?.costUsd), source = typeof snapshot?.costSource === 'string' && snapshot.costSource.trim() ? snapshot.costSource : null;
78
+ if (usd === null || source === null)
79
+ return { id: 'cost', text: t('screen.statusbar.costUnknown'), tone: 'normal' };
80
+ /* R5a wiring (Q-R5-5, E1): a cost the provider declared is reported, not estimated: no `~`. */
81
+ return { id: 'cost', text: t(source === 'provider-reported' ? 'screen.statusbar.costReported' : 'screen.statusbar.cost', { cost: costText(usd) }), tone: 'normal' };
82
+ }
83
+ function segmentsOf(input) {
84
+ const { snapshot } = input, model = shellSafeText(input.model);
85
+ const cached = count(snapshot?.cachedTokens), compactions = count(snapshot?.compactions), unseen = count(input.unseen);
86
+ const tokens = tokensSegment(snapshot);
87
+ return [
88
+ ...(input.safety.fullAccess ? [{ id: 'fullAccess', text: t('screen.footer.fullAccess'), tone: 'normal' }] : []),
89
+ ...(input.safety.noSandbox ? [{ id: 'noSandbox', text: t('screen.footer.noSandbox'), tone: 'normal' }] : []),
90
+ ...(model ? [{ id: 'model', text: t('screen.statusbar.model', { model }), tone: 'normal', model }] : []),
91
+ ...(tokens ? [tokens] : []),
92
+ ...(cached ? [{ id: 'cached', text: t('screen.statusbar.cached', { count: compactTokens(cached) }), tone: 'normal' }] : []),
93
+ contextSegment(snapshot),
94
+ costSegment(snapshot),
95
+ ...(compactions ? [{ id: 'compactions', text: t('screen.statusbar.compactions', { count: compactions }), tone: 'normal' }] : []),
96
+ ...(unseen ? [{ id: 'unseen', text: t('screen.footer.unseen', { count: unseen }), tone: 'normal' }] : []),
97
+ ];
98
+ }
99
+ const joined = (segments) => segments.map(segment => segment.text).join(SEPARATOR);
100
+ /** The status row at `width` columns: never wider, never more than one row, the protected segments always present. */
101
+ export function statusBar(input) {
102
+ const width = Math.max(0, Math.floor(Number(input.width) || 0));
103
+ let current = segmentsOf(input);
104
+ const fits = () => displayWidth(joined(current)) <= width;
105
+ for (const step of DROP_ORDER) {
106
+ if (fits())
107
+ break;
108
+ if (step === 'context-window') {
109
+ current = current.map(segment => segment.id === 'context' && segment.short ? { ...segment, text: segment.short } : segment);
110
+ continue;
111
+ }
112
+ if (step === 'model') {
113
+ const model = current.find(segment => segment.id === 'model');
114
+ if (!model?.model)
115
+ continue;
116
+ const others = current.filter(segment => segment !== model);
117
+ const room = width - displayWidth(joined(others)) - (others.length ? SEPARATOR.length : 0) - displayWidth(t('screen.statusbar.model', { model: '' }));
118
+ current = room >= MODEL_MIN ? current.map(segment => segment === model ? { ...segment, text: t('screen.statusbar.model', { model: truncateMiddle(model.model, room) }) } : segment) : others;
119
+ continue;
120
+ }
121
+ current = current.filter(segment => segment.id !== step);
122
+ }
123
+ const segments = current.map(({ id, text, tone }) => ({ id, text, tone }));
124
+ return { text: truncateDisplay(joined(segments), width), segments };
125
+ }
@@ -0,0 +1,40 @@
1
+ /*
2
+ * R5b D7 (owner decision Q-R5-17): what `/status` adds to its R4 block — the sandbox verdict, the permission rules counted
3
+ * in each scope's own file, the open tasks and the notes, and the session's usage in the status bar's own words. A fact
4
+ * that could not be read says so; nothing is shown as zero because it was not measured.
5
+ */
6
+ import { t } from "../i18n/index.js";
7
+ import { readConfigScope } from "../config/load.js";
8
+ import { statusBar } from "./status-bar.js";
9
+ const size = (value) => Array.isArray(value) ? value.length : 0;
10
+ export async function permissionRuleCounts({ paths, projectRoot }) {
11
+ try {
12
+ const count = async (scope) => { const rules = (await readConfigScope({ paths, projectRoot, scope })).permissions; return { allow: size(rules?.allow), ask: size(rules?.ask), deny: size(rules?.deny) }; };
13
+ const [user, project, projectUser] = await Promise.all([count('user'), count('project'), count('project-user')]);
14
+ return { user, project, projectUser };
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ }
20
+ /** The usage segments of the status bar (tokens, cache, context, cost, compactions), unshortened, in one line. */
21
+ export function usageLine(snapshot, model) {
22
+ if (!snapshot)
23
+ return null;
24
+ const parts = statusBar({ snapshot, model, width: 10_000, safety: { fullAccess: false, noSandbox: false } }).segments.filter(row => ['tokens', 'cached', 'context', 'cost', 'compactions'].includes(row.id)).map(row => row.text);
25
+ return parts.length ? parts.join(' · ') : null;
26
+ }
27
+ export function statusFactLines(facts) {
28
+ const lines = [t(facts.sandbox === true ? 'screen.status.sandboxVerified' : facts.sandbox === false ? 'screen.status.sandboxNone' : 'screen.status.sandboxUnknown')];
29
+ if (!facts.rules)
30
+ lines.push(t('screen.status.rulesUnknown'));
31
+ else {
32
+ const total = (row) => row.allow + row.ask + row.deny;
33
+ const { user, project, projectUser } = facts.rules;
34
+ const all = { allow: user.allow + project.allow + projectUser.allow, ask: user.ask + project.ask + projectUser.ask, deny: user.deny + project.deny + projectUser.deny };
35
+ lines.push(total(all) === 0 ? t('screen.status.rulesNone') : t('screen.status.rules', { ...all, user: total(user), project: total(project), projectUser: total(projectUser) }));
36
+ }
37
+ lines.push(facts.work ? t('screen.status.work', facts.work) : t('screen.status.workUnknown'));
38
+ lines.push(facts.usage ? t('screen.status.usage', { usage: facts.usage }) : t('screen.status.usageNone'));
39
+ return lines;
40
+ }
@@ -0,0 +1,9 @@
1
+ export function detectTerminalCapabilities({ stdinIsTTY, stdoutIsTTY, color, env }) {
2
+ const interactive = stdinIsTTY && stdoutIsTTY;
3
+ const dumb = env.TERM === 'dumb';
4
+ const noColor = typeof env.NO_COLOR === 'string' && env.NO_COLOR.length > 0;
5
+ const reduced = env.TALOS_REDUCED_MOTION === '1' || env.TALOS_REDUCED_MOTION === 'true';
6
+ const unicode = interactive && !dumb;
7
+ const effectiveColor = interactive && !dumb && color && !noColor;
8
+ return { interactive, color: effectiveColor, motion: effectiveColor && !reduced, unicode };
9
+ }
@@ -0,0 +1,11 @@
1
+ export function createTerminalSessionPlan({ capabilities, env, supportsAlternateScreen = true, }) {
2
+ if (!capabilities.interactive)
3
+ return { mode: 'plain', alternateScreen: false, paintBackground: false, fallbackReason: 'non-interactive' };
4
+ if (env.TERM === 'dumb')
5
+ return { mode: 'plain', alternateScreen: false, paintBackground: false, fallbackReason: 'term-dumb' };
6
+ if (!supportsAlternateScreen)
7
+ return { mode: 'plain', alternateScreen: false, paintBackground: false, fallbackReason: 'alternate-screen-unavailable' };
8
+ if (!capabilities.color)
9
+ return { mode: 'mono', alternateScreen: true, paintBackground: false, fallbackReason: null };
10
+ return { mode: 'full', alternateScreen: true, paintBackground: true, fallbackReason: null };
11
+ }
@@ -0,0 +1,66 @@
1
+ /* R1 gate E4/E16: TALOS measures text with the SAME function Ink 7.1.1 uses to lay it out (`string-width` 8.2.2, the
2
+ one copy in the lockfile, hoisted beside Ink). The hand-rolled table this replaces disagreed with Ink on 17 of 63
3
+ fixtures (SGR, tabs, ZWSP, flags, text-presentation symbols ☺ ⚠ © ™ ✔ ▶, combining marks, controls), and a row
4
+ count computed with one width and rendered with another is how a frame overflows (review D-02/D-04).
5
+ It is imported here, not declared in package.json, per the lane rule "no new dependency"; see the lane hand-back. */
6
+ import stringWidth from 'string-width';
7
+ const segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
8
+ export function splitGraphemes(text) { return [...segmenter.segment(text)].map(x => x.segment); }
9
+ export function displayWidth(text) { return stringWidth(String(text)); }
10
+ export function truncateDisplay(text, width) { if (displayWidth(text) <= width)
11
+ return text; if (width <= 1)
12
+ return '…'; let out = '', used = 0; for (const g of splitGraphemes(text)) {
13
+ const w = displayWidth(g);
14
+ if (used + w + 1 > width)
15
+ break;
16
+ out += g;
17
+ used += w;
18
+ } return `${out}…`; }
19
+ /* Keeps both ends of a long value (a workspace path): the tail says which folder, the head says which drive/root. */
20
+ export function truncateMiddle(text, width) {
21
+ if (displayWidth(text) <= width)
22
+ return text;
23
+ if (width <= 1)
24
+ return '…';
25
+ const graphemes = splitGraphemes(text);
26
+ const budget = width - 1;
27
+ let head = '', tail = '', used = 0, left = 0, right = graphemes.length - 1;
28
+ while (left <= right) {
29
+ const takeTail = displayWidth(tail) <= displayWidth(head);
30
+ const g = takeTail ? graphemes[right] : graphemes[left];
31
+ const w = displayWidth(g);
32
+ if (used + w > budget)
33
+ break;
34
+ used += w;
35
+ if (takeTail) {
36
+ tail = g + tail;
37
+ right--;
38
+ }
39
+ else {
40
+ head += g;
41
+ left++;
42
+ }
43
+ }
44
+ return `${head}…${tail}`;
45
+ }
46
+ /* Hard-wraps text into rows of at most `width` columns by grapheme, the way a terminal fills cells. Used where TALOS
47
+ owns the line breaks itself (the composer, chrome), so the row count is exact before render (E4). */
48
+ export function wrapDisplay(text, width) {
49
+ const limit = Math.max(1, Math.floor(width));
50
+ const rows = [];
51
+ for (const line of String(text).split('\n')) {
52
+ let row = '', used = 0;
53
+ for (const g of splitGraphemes(line)) {
54
+ const w = displayWidth(g);
55
+ if (used + w > limit && row !== '') {
56
+ rows.push(row);
57
+ row = '';
58
+ used = 0;
59
+ }
60
+ row += g;
61
+ used += w;
62
+ }
63
+ rows.push(row);
64
+ }
65
+ return rows;
66
+ }
@@ -0,0 +1,27 @@
1
+ /** `color-mix(in srgb, a amount%, b)` for #rrggbb. */
2
+ export function mixHex(a, amount, b) {
3
+ const parse = (hex) => [1, 3, 5].map(i => parseInt(hex.slice(i, i + 2), 16));
4
+ const [x, y] = [parse(a), parse(b)];
5
+ const t = Math.max(0, Math.min(100, amount)) / 100;
6
+ return `#${x.map((v, i) => Math.round(v * t + y[i] * (1 - t)).toString(16).padStart(2, '0')).join('')}`;
7
+ }
8
+ const theme = (id, label, accent, background) => ({ id, label, accent, background, muted: mixHex(accent, 62, background) });
9
+ /* P15 (owner, 2026-09-25, "vorrei mettere forge come tema principale di default"): Forge is the default from 0.2.0. A theme
10
+ the person chose stays theirs (it is in their configuration); the legacy migrations keep mapping to what they mapped to. */
11
+ export const DEFAULT_THEME_ACCENT = 'forge';
12
+ export const TALOS_THEME_ACCENTS = Object.freeze([
13
+ theme('calm', 'Calm', '#c08b3c', '#1e1f22'),
14
+ theme('forge', 'Forge', '#c98b32', '#080b11'),
15
+ theme('terminal', 'Terminal', '#63f08e', '#020403'),
16
+ theme('aurora', 'Aurora', '#42e7c7', '#071113'),
17
+ theme('ember', 'Ember', '#ff5c62', '#10090a'),
18
+ theme('atlas', 'Atlas', '#d49a52', '#07101f'),
19
+ theme('noir', 'Noir', '#f2f2f2', '#050505'),
20
+ theme('signal', 'Signal', '#ff6f61', '#091011'),
21
+ theme('violet', 'Violet', '#b794f6', '#0d0a19'),
22
+ theme('telemetry', 'Telemetry', '#6ad4d4', '#0b0f11'),
23
+ ]);
24
+ export function isThemeAccentId(id) { return TALOS_THEME_ACCENTS.some(row => row.id === id); }
25
+ export function themeAccent(id) {
26
+ return TALOS_THEME_ACCENTS.find(row => row.id === id) ?? TALOS_THEME_ACCENTS.find(row => row.id === DEFAULT_THEME_ACCENT);
27
+ }
@@ -0,0 +1,23 @@
1
+ import { createTuiTheme } from "./theme.js";
2
+ import { DEFAULT_THEME_ACCENT, TALOS_THEME_ACCENTS, isThemeAccentId } from "./theme-catalog.js";
3
+ /** What /theme offers, in the product's order, mono last. */
4
+ export const THEME_CHOICES = Object.freeze([...TALOS_THEME_ACCENTS.map(row => row.id), 'mono']);
5
+ export function parseThemeChoice(value) {
6
+ const id = typeof value === 'string' ? value.trim().toLowerCase() : '';
7
+ return THEME_CHOICES.includes(id) ? id : null;
8
+ }
9
+ export function liveTheme(base, id) {
10
+ const capabilities = id === 'mono' ? { ...base, color: false, motion: false } : base;
11
+ return { id, capabilities, theme: createTuiTheme(capabilities, isThemeAccentId(id) ? id : DEFAULT_THEME_ACCENT) };
12
+ }
13
+ export function createThemeStore(base, id = DEFAULT_THEME_ACCENT) {
14
+ let snapshot = liveTheme(base, id);
15
+ const listeners = new Set();
16
+ return {
17
+ getSnapshot: () => snapshot,
18
+ subscribe(listener) { listeners.add(listener); return () => { listeners.delete(listener); }; },
19
+ set(next) { if (next === snapshot.id)
20
+ return; snapshot = liveTheme(base, next); for (const listener of [...listeners])
21
+ listener(); },
22
+ };
23
+ }
@@ -0,0 +1,23 @@
1
+ import { DEFAULT_THEME_ACCENT, themeAccent } from "./theme-catalog.js";
2
+ export function createTuiTheme(c, accentId = DEFAULT_THEME_ACCENT) {
3
+ const accent = themeAccent(accentId);
4
+ return {
5
+ id: accent.id,
6
+ colors: c.color ? {
7
+ background: accent.background,
8
+ foreground: '#F5F5F4',
9
+ accent: accent.accent,
10
+ muted: accent.muted,
11
+ success: '#34D399',
12
+ warning: '#FBBF24',
13
+ danger: '#FB7185',
14
+ } : {},
15
+ glyphs: c.unicode
16
+ ? { spinner: ['⠋', '⠙', '⠹', '⠸'], success: '✓', error: '!', branch: '├', bullet: '•' }
17
+ : { spinner: ['-', '\\', '|', '/'], success: 'OK', error: '!', branch: '+', bullet: '*' },
18
+ };
19
+ }
20
+ const SURFACE_COLOR = {
21
+ boot: 'accent', transcript: 'accent', picker: 'accent', approval: 'warning', tool: 'success', footer: 'muted',
22
+ };
23
+ export function themeColor(theme, surface) { return theme.colors[SURFACE_COLOR[surface]]; }
@@ -0,0 +1,135 @@
1
+ /*
2
+ * R2 CONTRACT (owner: lane T). The ONE table that turns a kernel tool name into what the screen shows (Q-R2-3, gate
3
+ * E3), zipped once on the kernel name as Qwen zips `ToolNames` with `ToolDisplayNames` (`cli/src/ui/utils/
4
+ * tool-display-map.ts:12-24`, 2026-09-06). Every surface reads it: transcript rows and renderer lookup (tools/registry.ts),
5
+ * approval title and summary (overlays/approval-dialog.ts), permission mapping (security/from-approval.ts). The model
6
+ * keeps the kernel names and argument keys (gate E2): this file maps for display and never renames what it receives.
7
+ *
8
+ * The 46 rows are the kernel's own tools, measured, not remembered: `ATTREZZI` (talosHarness.mjs:1571-1741, 7 tools),
9
+ * `ATTREZZI_ESTESI` (:1829-2806, 38 tools) and `carica_skill` (:7603-7612), 53 distinct argument keys — the gate's §1.3
10
+ * count. test/i18n/tools-labels.test.ts imports those schemas and fails on a tool or key without a row here.
11
+ */
12
+ import { en } from "../i18n/en.js";
13
+ import { t } from "../i18n/index.js";
14
+ const row = (permission, renderer, ...primary) => ({ permission, renderer, primary });
15
+ /*
16
+ * `permission` is the tool the permission engine judges the call as (security/types.ts). The kernel asks for approval on
17
+ * 30 of them (`verificaPermessoConBarriera`, talosHarness.mjs:8166-9714): reads are Read, the two file writers Write (a
18
+ * write judged as Read was ALLOWED inside the project without asking, evaluate.ts:130 — review E-07), the targeted edit
19
+ * Edit, the two command runners Bash, the web tools WebFetch; TALOS's own services are TalosService with the kernel
20
+ * name as operation. `primary` lists the argument keys whose value stands beside the label, first present wins.
21
+ */
22
+ const TABLE = {
23
+ elenca: row('Read', 'list', 'percorso'),
24
+ cerca: row('Read', 'search', 'testo', 'nome'),
25
+ leggi: row('Read', 'read', 'percorso'),
26
+ scrivi: row('Write', 'write', 'percorso'),
27
+ prova: row('Bash', 'bash'),
28
+ shell: row('Bash', 'bash', 'comando'),
29
+ naviga: row('WebFetch', 'generic', 'url'),
30
+ web_search: row('WebFetch', 'generic', 'query'),
31
+ artifact_create: row('TalosService', 'generic', 'titolo'),
32
+ document_create: row('TalosService', 'generic', 'title'),
33
+ time_now: row('TalosService', 'generic'),
34
+ delega_sottotask: row('TalosService', 'generic', 'task'),
35
+ generate_image: row('TalosService', 'generic', 'prompt'),
36
+ library_list: row('TalosService', 'generic'),
37
+ library_search: row('TalosService', 'generic', 'query'),
38
+ library_read: row('TalosService', 'generic', 'id'),
39
+ library_file_origin: row('TalosService', 'generic', 'id'),
40
+ library_rename: row('TalosService', 'generic', 'name', 'id'),
41
+ library_delete: row('TalosService', 'generic', 'id'),
42
+ library_export: row('TalosService', 'generic', 'reference'),
43
+ library_context_policy_update: row('TalosService', 'generic', 'action'),
44
+ notes_list: row('TalosService', 'generic'),
45
+ notes_create: row('TalosService', 'generic', 'title'),
46
+ notes_update: row('TalosService', 'generic', 'title', 'id'),
47
+ notes_delete: row('TalosService', 'generic', 'id'),
48
+ tasks_list: row('TalosService', 'generic', 'status'),
49
+ tasks_create: row('TalosService', 'generic', 'title'),
50
+ tasks_complete: row('TalosService', 'generic', 'id'),
51
+ tasks_update: row('TalosService', 'generic', 'title', 'id'),
52
+ tasks_delete: row('TalosService', 'generic', 'id'),
53
+ memory_search: row('TalosService', 'generic', 'query'),
54
+ memory_write: row('TalosService', 'generic', 'title'),
55
+ memory_update: row('TalosService', 'generic', 'title', 'id'),
56
+ memory_delete: row('TalosService', 'generic', 'id'),
57
+ research_list: row('TalosService', 'generic', 'status'),
58
+ research_start: row('TalosService', 'generic', 'question'),
59
+ research_read: row('TalosService', 'generic', 'id'),
60
+ research_rename: row('TalosService', 'generic', 'title', 'id'),
61
+ research_pause: row('TalosService', 'generic', 'id'),
62
+ research_resume: row('TalosService', 'generic', 'id'),
63
+ research_cancel: row('TalosService', 'generic', 'id'),
64
+ research_delete: row('TalosService', 'generic', 'id'),
65
+ research_deposit: row('Write', 'generic'),
66
+ tool_create: row('TalosService', 'generic', 'title'),
67
+ file_edit: row('Edit', 'edit', 'percorso'),
68
+ carica_skill: row('TalosService', 'generic', 'nome'),
69
+ };
70
+ export const KERNEL_TOOL_NAMES = Object.freeze(Object.keys(TABLE));
71
+ const WORDS_COMPLETE = true;
72
+ void WORDS_COMPLETE;
73
+ export function isKernelTool(name) { return typeof name === 'string' && Object.hasOwn(TABLE, name); }
74
+ export function rendererKindFor(name) { return isKernelTool(name) ? TABLE[name].renderer : 'generic'; }
75
+ /* A tool the kernel did not declare is named by whoever wrote it: an MCP server (`mcp__<server>__<tool>`,
76
+ harness-ui/src/mcp-session.mjs:47), a plugin (`plugin__<plugin>__<tool>`, plugin-session.mjs:52), the Tool Forge
77
+ (`forge_<id>`, forge-contract.mjs:127), or anything else. Their parts are split by these exact prefixes. */
78
+ export function externalToolParts(name) {
79
+ for (const kind of ['mcp', 'plugin']) {
80
+ const prefix = `${kind}__`;
81
+ if (!name.startsWith(prefix))
82
+ continue;
83
+ const rest = name.slice(prefix.length), split = rest.indexOf('__');
84
+ if (split > 0 && split < rest.length - 2)
85
+ return { kind, owner: rest.slice(0, split), tool: rest.slice(split + 2) };
86
+ }
87
+ if (name.startsWith('forge_') && name.length > 6)
88
+ return { kind: 'forge', owner: null, tool: name.slice(6) };
89
+ return null;
90
+ }
91
+ /** snake_case, kebab-case and camelCase → lower-case words. */
92
+ function words(name) { return name.replace(/([a-z0-9])([A-Z])/gu, '$1 $2').replace(/[_\-.\s]+/gu, ' ').trim().toLowerCase(); }
93
+ function capitalised(text) { return text ? text[0].toUpperCase() + text.slice(1) : text; }
94
+ function permissionOfExternal(name) { const parts = externalToolParts(name); return parts?.kind === 'mcp' ? 'Mcp' : parts?.kind === 'plugin' ? 'Plugin' : 'TalosService'; }
95
+ /** The permission tool the engine judges this tool as: from the table, or from the external prefix. */
96
+ export function permissionToolFor(name) { return isKernelTool(name) ? TABLE[name].permission : permissionOfExternal(name); }
97
+ /** The English label of an argument key: the dictionary's when it has one, otherwise the key in words. */
98
+ export function argumentLabel(key) { const id = `tool.arg.${key}`; return Object.hasOwn(en, id) ? t(id) : words(key); }
99
+ /* Keys an unknown tool's primary argument is looked for under (Hermes `_PRIMARY_ARGS`, agent/display.py:353-361, 2026-09-22). */
100
+ const EXTERNAL_PRIMARY = ['path', 'file_path', 'file', 'url', 'query', 'command', 'pattern', 'name', 'title', 'id'];
101
+ function primaryValue(keys, args) {
102
+ if (!args)
103
+ return null;
104
+ for (const key of keys) {
105
+ const value = args[key];
106
+ if ((typeof value === 'string' && value.trim() !== '') || typeof value === 'number' || typeof value === 'boolean')
107
+ return String(value);
108
+ }
109
+ return null;
110
+ }
111
+ function externalLabel(name) {
112
+ const parts = externalToolParts(name);
113
+ if (parts?.kind === 'mcp')
114
+ return t('tool.mcp.label', { tool: capitalised(words(parts.tool)), server: parts.owner });
115
+ if (parts?.kind === 'plugin')
116
+ return t('tool.plugin.label', { tool: capitalised(words(parts.tool)), plugin: parts.owner });
117
+ if (parts?.kind === 'forge')
118
+ return t('tool.forge.label', { tool: capitalised(words(parts.tool)) });
119
+ return capitalised(words(name)) || t('tool.unknown.label');
120
+ }
121
+ /**
122
+ * What the screen shows for a tool call: the English label and verb, the VALUE of its primary argument when `args` is
123
+ * given (null when absent or not a plain value), the permission tool it is judged as, and the raw kernel name, which
124
+ * only an expanded detail shows (Q-R2-3).
125
+ */
126
+ export function toolDisplay(kernelName, args) {
127
+ if (isKernelTool(kernelName)) {
128
+ const entry = TABLE[kernelName];
129
+ return { label: t(`tool.${kernelName}.label`), verb: t(`tool.${kernelName}.verb`), primaryArg: primaryValue(entry.primary, args), permissionTool: entry.permission, raw: kernelName };
130
+ }
131
+ const label = externalLabel(kernelName);
132
+ return { label, verb: t('tool.unknown.verb', { tool: label }), primaryArg: primaryValue(EXTERNAL_PRIMARY, args), permissionTool: permissionOfExternal(kernelName), raw: kernelName };
133
+ }
134
+ /** The argument keys a tool's primary value is read from, in order (the table's `primary`; R3 renderers read it too). */
135
+ export function primaryArgumentKeys(kernelName) { return isKernelTool(kernelName) ? TABLE[kernelName].primary : EXTERNAL_PRIMARY; }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,32 @@
1
+ import { boundedLines, detailWidth, formatDuration, moreLines, outputTail, outputText, parseArgs, sanitizeDisplayText, withoutKernelExitLine } from "./shared.js";
2
+ import { truncateDisplay } from "../text-width.js";
3
+ import { t } from "../../i18n/index.js";
4
+ /* R2 lane T: the kernel's `shell` sends `comando` and the model's own `descrizione` ("shown to the person watching",
5
+ talosHarness.mjs:1702-1720), which leads the detail; `prova` sends no argument at all.
6
+ R3 (Q-R3-10): the output is a TAIL — the last 5 lines (errors are at the end), 40 in the expanded view — with the lines
7
+ above it counted. While the command runs, the live tail ends with `+N lines · T s`; a sandboxed command streams
8
+ nothing today (brokered-executor.ts:343-352), so its row says `running T s` and the output arrives at the end.
9
+ The kernel's `exit N [sandbox: …]` first line is hidden (shared.ts, gate E3); a person's `!` command is labelled `!`. */
10
+ const TAIL = 5, TAIL_EXPANDED = 40;
11
+ export const renderBash = (row, context) => {
12
+ const a = parseArgs(row);
13
+ const command = String(a.comando ?? a.command ?? a.cmd ?? a.raw ?? '').trim();
14
+ const description = typeof a.descrizione === 'string' ? a.descrizione.trim() : typeof a.description === 'string' ? a.description.trim() : '';
15
+ const detail = description ? boundedLines(description, context.width, context.expanded ? 4 : 1) : [];
16
+ const live = row.status === 'queued' || row.status === 'running' || row.status === 'streaming';
17
+ let liveTail = false;
18
+ if (row.status !== 'denied') {
19
+ const tail = outputTail(live ? row.liveOutput : withoutKernelExitLine(outputText(row)), context.expanded ? TAIL_EXPANDED : TAIL);
20
+ detail.push(...tail.lines.map(line => truncateDisplay(sanitizeDisplayText(line), detailWidth(context.width)) || ' '));
21
+ const summary = tail.hidden > 0 ? [moreLines(tail.hidden, tail.atLeast)] : [];
22
+ if (live && tail.lines.length) {
23
+ liveTail = true;
24
+ const elapsed = row.startedAt === null ? 0 : Math.max(0, context.now - row.startedAt);
25
+ if (elapsed >= 1000)
26
+ summary.push(formatDuration(elapsed));
27
+ }
28
+ if (summary.length)
29
+ detail.push(summary.join(' · '));
30
+ }
31
+ return { ...(row.origin === 'person' ? { label: t('tool.person.label') } : {}), target: command, result: [], detail, command: true, showsOutput: true, liveTail };
32
+ };
@@ -0,0 +1,61 @@
1
+ /*
2
+ * R3 lane RD (Q-R3-4, gate E10): a write or edit row reads its change through the ONE line diff (line-diff.ts). A row is
3
+ * drawn many times (every frame, every height estimate), so a file change is diffed once per change object and a pair
4
+ * of edit fragments once per text (bounded cache); the expanded view renders the model with components/diff.ts.
5
+ */
6
+ import { t, tn } from "../../i18n/index.js";
7
+ import { renderDiffModel } from "../components/diff.js";
8
+ import { lineDiff } from "../line-diff.js";
9
+ import { lineCount } from "./shared.js";
10
+ const DIFFS = new WeakMap();
11
+ export function changeDiff(change) {
12
+ let diff = DIFFS.get(change);
13
+ if (!diff) {
14
+ diff = lineDiff(change.before, change.after, { path: change.path });
15
+ DIFFS.set(change, diff);
16
+ }
17
+ return diff;
18
+ }
19
+ export function summarizeChange(change) {
20
+ const diff = changeDiff(change);
21
+ return { newFile: change.before === null, lines: lineCount(change.after), added: diff.approximate ? null : diff.added, removed: diff.approximate ? null : diff.removed };
22
+ }
23
+ export function changeSummaryOf(row) { return row.changeSummary ?? (row.change ? summarizeChange(row.change) : null); }
24
+ /** The result facts of a change: `new file · N lines`, `+a −r`, or `N lines` when it was too large to compare. */
25
+ export function resultOfChange(summary) {
26
+ if (summary.newFile)
27
+ return [t('tool.result.newFile'), tn('tool.result.lines', summary.lines)];
28
+ if (summary.added === null || summary.removed === null)
29
+ return [tn('tool.result.lines', summary.lines)];
30
+ return [t('tool.result.changes', { added: summary.added, removed: summary.removed })];
31
+ }
32
+ /* Edit fragments are small; the cache keeps the last few pairs so a redraw does not diff again. */
33
+ const FRAGMENTS = new Map();
34
+ const FRAGMENT_CACHE = 64, FRAGMENT_KEY_MAX = 64 * 1024;
35
+ /** The diff of an edit's two fragments: their line numbers are not the file's, so none is claimed (no numbers, no `@@`).
36
+ * A fragment is a piece of a line-ended file, so both get a final line break before diffing: `line` and `line\n` are the
37
+ * same line here (for a whole file jsdiff, like git, rightly tells them apart). */
38
+ const lineEnded = (text) => text === '' || text.endsWith('\n') ? text : text + '\n';
39
+ export function fragmentDiff(oldText, newText, path) {
40
+ const key = oldText.length + newText.length <= FRAGMENT_KEY_MAX ? `${path}\u0000${oldText}\u0000${newText}` : null;
41
+ const cached = key === null ? undefined : FRAGMENTS.get(key);
42
+ if (cached)
43
+ return cached;
44
+ const diff = lineDiff(lineEnded(oldText), lineEnded(newText), { path });
45
+ const model = { ...diff.model, files: diff.model.files.map(file => ({ ...file, rows: file.rows.filter(row => row.kind !== 'hunk').map(row => ({ ...row, oldLine: null, newLine: null })) })) };
46
+ const result = { ...diff, model };
47
+ if (key !== null) {
48
+ FRAGMENTS.set(key, result);
49
+ if (FRAGMENTS.size > FRAGMENT_CACHE)
50
+ FRAGMENTS.delete(FRAGMENTS.keys().next().value);
51
+ }
52
+ return result;
53
+ }
54
+ /* The expanded view of a change is bounded like every other detail: the first lines of the diff, then how many more. */
55
+ const MAX_DIFF_LINES = 400;
56
+ export function diffDetail(diff, width) {
57
+ const lines = renderDiffModel(diff.model, width).lines.filter(line => line.kind !== 'file').map(line => line.text);
58
+ if (lines.length <= MAX_DIFF_LINES)
59
+ return lines;
60
+ return [...lines.slice(0, MAX_DIFF_LINES), tn('tool.diff.more', lines.length - MAX_DIFF_LINES)];
61
+ }
@@ -0,0 +1,17 @@
1
+ import { parseArgs } from "./shared.js";
2
+ import { changeDiff, changeSummaryOf, diffDetail, fragmentDiff, resultOfChange } from "./change.js";
3
+ import { t } from "../../i18n/index.js";
4
+ /* R2 lane T: the kernel's `file_edit` sends `percorso`, `old_string`, `new_string` (talosHarness.mjs:2786-2806).
5
+ R3 (Q-R3-4, gate E10): `+a −r` from the ONE line diff (line-diff.ts, jsdiff) — of the whole file when the kernel reported
6
+ the change (`file.changed`), of the two fragments before that. The multiset count that stood here is gone: it saw a
7
+ moved line as no change and an edit of one of two identical lines as nothing (gate §3.1). */
8
+ export const renderEdit = (row, context) => {
9
+ const a = parseArgs(row);
10
+ const path = String(a.percorso ?? a.path ?? a.file ?? '').trim();
11
+ const oldText = String(a.oldText ?? a.old_string ?? a.before ?? ''), newText = String(a.newText ?? a.new_string ?? a.after ?? '');
12
+ const summary = changeSummaryOf(row);
13
+ const fragment = summary && summary.added !== null ? null : fragmentDiff(oldText, newText, path);
14
+ const result = fragment ? [t('tool.result.changes', { added: fragment.added, removed: fragment.removed })] : resultOfChange(summary);
15
+ const detail = !context.expanded ? [] : diffDetail(row.change ? changeDiff(row.change) : fragment ?? fragmentDiff(oldText, newText, path), context.width);
16
+ return { target: path, result, detail };
17
+ };
@@ -0,0 +1,13 @@
1
+ import { argumentLine, boundedLines, outputText, parseArgs } from "./shared.js";
2
+ import { primaryArgumentKeys, toolDisplay } from "../tool-display.js";
3
+ /* R2 lane T (review D-07, Q-R2-3): the title is the English label and the primary argument's value; every other argument
4
+ is one `label: value` line, a structure counted and never printed as JSON. R3: a refused call shows its reason, not
5
+ its output (row-format.ts). */
6
+ export const renderGeneric = (row, context) => {
7
+ const a = parseArgs(row);
8
+ const view = toolDisplay(row.name, a);
9
+ const primaryKey = view.primaryArg === null ? null : primaryArgumentKeys(row.name).find(key => a[key] !== undefined && String(a[key]) === view.primaryArg) ?? null;
10
+ const argLines = Object.entries(a).filter(([key]) => key !== primaryKey).map(([key, value]) => argumentLine(key, value));
11
+ const details = [...boundedLines(argLines.join('\n'), context.width, context.expanded ? 12 : 2), ...(row.status === 'denied' ? [] : boundedLines(outputText(row), context.width, context.expanded ? 12 : 3))];
12
+ return { target: view.primaryArg ?? '', result: [], detail: details, showsOutput: true };
13
+ };
@@ -0,0 +1,14 @@
1
+ import { boundedLines, outputText, parseArgs } from "./shared.js";
2
+ import { tn } from "../../i18n/index.js";
3
+ /* R3 (Q-R3-1, gate §2.3): `List folder <path> · N entries`. The kernel's `elenca` (elencaDaCartella,
4
+ talosHarness.mjs:3487) answers one path per line, `no files and no folders. …` for an empty folder, and a sentence for a
5
+ folder it cannot read or a refusal; those exact shapes are pinned by r3-rd-tool-rows.test.ts, anything else gets no count. */
6
+ const EMPTY = /^no files and no folders\. /u;
7
+ const NOT_COUNTED = /^REFUSED\. | is not a readable folder of this workspace\. /u;
8
+ export const renderList = (row, context) => {
9
+ const a = parseArgs(row);
10
+ const path = String(a.percorso ?? a.path ?? a.folder ?? a.raw ?? '').trim();
11
+ const text = outputText(row).trim();
12
+ const count = EMPTY.test(text) ? 0 : NOT_COUNTED.test(text) ? null : text.split(/\r?\n/u).filter(line => line.trim()).length;
13
+ return { target: path, result: count === null ? [] : [tn('tool.result.entries', count)], detail: row.status === 'denied' || count === 0 ? [] : boundedLines(text, context.width, context.expanded ? 12 : 3), showsOutput: true };
14
+ };
@@ -0,0 +1,13 @@
1
+ import { lineCount, parseArgs } from "./shared.js";
2
+ import { t, tn } from "../../i18n/index.js";
3
+ /* R2 lane T: the kernel's `leggi` sends `percorso` (talosHarness.mjs:1601-1608); the English spellings stay accepted.
4
+ R3 (Q-R3-1): the row says what was read — `N lines` of the content returned, or the range the call asked for. */
5
+ export const renderRead = row => {
6
+ const a = parseArgs(row);
7
+ const path = String(a.percorso ?? a.path ?? a.file ?? a.filename ?? a.raw ?? '').trim();
8
+ const offset = Number.isFinite(a.offset) ? Number(a.offset) : Number.isFinite(a.start) ? Number(a.start) : 1;
9
+ const limit = Number.isFinite(a.limit) ? Number(a.limit) : Number.isFinite(a.lines) ? Number(a.lines) : null;
10
+ const count = tn('tool.result.lines', lineCount(row.finalOutput));
11
+ const result = limit !== null ? [t('tool.read.lines', { from: offset, to: offset + Math.max(0, limit - 1) })] : offset > 1 ? [t('tool.read.from', { from: offset }), count] : [count];
12
+ return { target: path, result, detail: [] };
13
+ };