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,234 @@
1
+ import { displayWidth, splitGraphemes } from "../text-width.js";
2
+ const BORDER_ROWS = 2, BORDER_COLUMNS = 2;
3
+ // Below this a border costs more than it shows: 4 rows keep top, bottom and two rows of content.
4
+ const MIN_BORDERED_ROWS = 4;
5
+ /** Lossless word wrap by display width: the rows join back to the text; a word longer than a row is broken inside it. */
6
+ export function wrapDisplay(text, width) {
7
+ const limit = Math.max(1, Math.floor(width));
8
+ const rows = [];
9
+ let row = '', used = 0;
10
+ const push = () => { rows.push(row); row = ''; used = 0; };
11
+ const breakInside = (token) => { for (const grapheme of splitGraphemes(token)) {
12
+ const cells = displayWidth(grapheme);
13
+ if (row !== '' && used + cells > limit)
14
+ push();
15
+ row += grapheme;
16
+ used += cells;
17
+ } };
18
+ for (const token of text.split(/( +)/u)) {
19
+ if (token === '')
20
+ continue;
21
+ const cells = displayWidth(token);
22
+ if (used + cells <= limit) {
23
+ row += token;
24
+ used += cells;
25
+ continue;
26
+ }
27
+ if (token.startsWith(' ') || cells > limit) {
28
+ breakInside(token);
29
+ continue;
30
+ }
31
+ if (row !== '')
32
+ push();
33
+ row = token;
34
+ used = cells;
35
+ }
36
+ if (row !== '' || !rows.length)
37
+ rows.push(row);
38
+ return rows;
39
+ }
40
+ /** A line may carry its own line breaks (help text, previews): each is wrapped on its own. */
41
+ function wrapLine(text, width) { return String(text).split(/\r?\n/u).flatMap(part => wrapDisplay(part, width)); }
42
+ export function moreIndicator(above, below) {
43
+ return [above > 0 ? `↑ ${above} more` : '', below > 0 ? `↓ ${below} more` : ''].filter(Boolean).join(' · ');
44
+ }
45
+ /*
46
+ * The window over items of known heights. `budget` counts every row, the marker included: when anything is cut one
47
+ * row is the "↑/↓ N more" marker (if the budget has room for it next to the selected item). `clip` is set only when the
48
+ * one item in the window is taller than the window by itself.
49
+ */
50
+ export function sliceByHeights(heights, { budget, selected, offset }) {
51
+ const count = heights.length, total = heights.reduce((sum, value) => sum + value, 0), rows = Math.max(0, Math.floor(budget));
52
+ if (total <= rows)
53
+ return { start: 0, end: count, above: 0, below: 0, maxOffset: 0, clip: null };
54
+ const room = rows >= 2 ? rows - 1 : rows;
55
+ // The last start whose tail fits the window: scrolling past it would only show blank rows.
56
+ let maxOffset = count, used = 0;
57
+ for (let index = count - 1; index >= 0; index--) {
58
+ if (used + heights[index] > room)
59
+ break;
60
+ used += heights[index];
61
+ maxOffset = index;
62
+ }
63
+ if (maxOffset === count)
64
+ maxOffset = Math.max(0, count - 1);
65
+ let start, end;
66
+ if (selected !== undefined && count > 0) {
67
+ const anchor = Math.max(0, Math.min(count - 1, Math.trunc(selected) || 0));
68
+ start = anchor;
69
+ end = anchor + 1;
70
+ used = heights[anchor];
71
+ // Alternate above/below, above first: uniform rows give `pickerWindow`'s floor(size/2) rows above the selection.
72
+ let turn = 'above', blocked = { above: false, below: false };
73
+ while (!(blocked.above && blocked.below)) {
74
+ const side = blocked[turn] ? (turn === 'above' ? 'below' : 'above') : turn;
75
+ const index = side === 'above' ? start - 1 : end;
76
+ if (index < 0 || index >= count || used + heights[index] > room)
77
+ blocked[side] = true;
78
+ else {
79
+ used += heights[index];
80
+ if (side === 'above')
81
+ start = index;
82
+ else
83
+ end = index + 1;
84
+ }
85
+ turn = turn === 'above' ? 'below' : 'above';
86
+ }
87
+ }
88
+ else {
89
+ start = Math.max(0, Math.min(maxOffset, Math.trunc(offset ?? 0) || 0));
90
+ end = start;
91
+ used = 0;
92
+ while (end < count && used + heights[end] <= room) {
93
+ used += heights[end];
94
+ end++;
95
+ }
96
+ if (end === start && count > 0)
97
+ end = start + 1;
98
+ }
99
+ const clip = end - start === 1 && heights[start] > room ? room : null;
100
+ return { start, end, above: start, below: count - end, maxOffset, clip };
101
+ }
102
+ /*
103
+ * Chrome that does not fit is dropped in a fixed order and counted in `dropped`: the title (head[0]) is the last to
104
+ * go after the first foot line (the key hints), and the other lines go before either. Sections share what is left:
105
+ * each gets what it needs if the sum fits; otherwise a selected section is served first, then the rest is shared.
106
+ */
107
+ export function fitOverlay(content, { maxRows, columns }) {
108
+ const limit = maxRows === undefined || !Number.isFinite(maxRows) ? Number.POSITIVE_INFINITY : Math.max(0, Math.floor(maxRows));
109
+ const border = limit >= MIN_BORDERED_ROWS;
110
+ const inner = Math.max(1, Math.floor(columns) - (border ? BORDER_COLUMNS : 0));
111
+ const available = Math.max(0, limit - (border ? BORDER_ROWS : 0));
112
+ const head = (content.head ?? []).map(line => wrapLine(line.text, inner));
113
+ const foot = (content.foot ?? []).map(line => wrapLine(line.text, inner));
114
+ const sections = content.sections.map(section => section.lines.map(line => wrapLine(line.text, inner)));
115
+ const need = sections.map(blocks => blocks.reduce((sum, rows) => sum + rows.length, 0));
116
+ const chromeRows = [...head, ...foot].reduce((sum, rows) => sum + rows.length, 0);
117
+ const bodyNeed = need.reduce((sum, value) => sum + value, 0);
118
+ let keepHead = head.map(rows => rows.length), keepFoot = foot.map(rows => rows.length), dropped = 0;
119
+ if (chromeRows + bodyNeed > available) {
120
+ // Every section keeps at least one row plus its marker (or less, if it needs less).
121
+ const reserve = need.reduce((sum, value) => sum + Math.min(value, 2), 0);
122
+ let left = Math.max(0, available - reserve);
123
+ keepHead = head.map(() => 0);
124
+ keepFoot = foot.map(() => 0);
125
+ const order = [...(head.length ? [['head', 0]] : []), ...foot.map((_, index) => ['foot', index]), ...head.slice(1).map((_, index) => ['head', index + 1])];
126
+ for (const [where, index] of order) {
127
+ const rows = (where === 'head' ? head : foot)[index].length, take = Math.min(rows, left);
128
+ if (where === 'head')
129
+ keepHead[index] = take;
130
+ else
131
+ keepFoot[index] = take;
132
+ left -= take;
133
+ }
134
+ dropped = [...head, ...foot].reduce((sum, rows) => sum + rows.length, 0) - [...keepHead, ...keepFoot].reduce((sum, value) => sum + value, 0);
135
+ }
136
+ let bodyLeft = Math.max(0, available - [...keepHead, ...keepFoot].reduce((sum, value) => sum + value, 0));
137
+ const budgets = need.map(() => 0);
138
+ if (need.reduce((sum, value) => sum + value, 0) <= bodyLeft)
139
+ need.forEach((value, index) => { budgets[index] = value; });
140
+ else {
141
+ const order = need.map((_, index) => index).sort((a, b) => Number(content.sections[b].selected !== undefined) - Number(content.sections[a].selected !== undefined));
142
+ for (const index of order) {
143
+ const take = Math.min(need[index], 2, bodyLeft);
144
+ budgets[index] = take;
145
+ bodyLeft -= take;
146
+ }
147
+ for (let active = order.filter(index => budgets[index] < need[index]); active.length && bodyLeft > 0; active = active.filter(index => budgets[index] < need[index])) {
148
+ const share = Math.max(1, Math.floor(bodyLeft / active.length));
149
+ for (const index of active) {
150
+ const take = Math.min(need[index] - budgets[index], share, bodyLeft);
151
+ budgets[index] = budgets[index] + take;
152
+ bodyLeft -= take;
153
+ }
154
+ }
155
+ }
156
+ const rows = [];
157
+ const views = [];
158
+ let cut = false;
159
+ const chrome = (lines, wrapped, keep, role) => wrapped.forEach((pieces, index) => {
160
+ for (const text of pieces.slice(0, keep[index]))
161
+ rows.push({ text, tone: lines[index].tone ?? (role === 'head' && index === 0 ? 'title' : 'dim'), role, selected: false });
162
+ });
163
+ chrome(content.head ?? [], head, keepHead, 'head');
164
+ sections.forEach((blocks, index) => {
165
+ const section = content.sections[index], budget = budgets[index];
166
+ if (budget <= 0) {
167
+ views.push({ start: 0, end: 0, above: 0, below: blocks.length, maxOffset: 0 });
168
+ if (blocks.length)
169
+ cut = true;
170
+ return;
171
+ }
172
+ const view = sliceByHeights(blocks.map(pieces => pieces.length), { budget, selected: section.selected, offset: section.offset });
173
+ views.push({ start: view.start, end: view.end, above: view.above, below: view.below, maxOffset: view.maxOffset });
174
+ let used = 0;
175
+ for (let line = view.start; line < view.end; line++) {
176
+ const pieces = view.clip !== null ? blocks[line].slice(0, view.clip) : blocks[line];
177
+ const selected = section.selected !== undefined && line === Math.max(0, Math.min(blocks.length - 1, Math.trunc(section.selected) || 0));
178
+ const { accentTo, accentColor } = section.lines[line];
179
+ pieces.forEach((text, piece) => rows.push({ text, tone: section.lines[line].tone ?? 'plain', role: 'body', selected, ...(piece === 0 && typeof accentTo === 'number' && accentTo > 0 ? { accentTo, ...(accentColor ? { accentColor } : {}) } : {}) }));
180
+ used += pieces.length;
181
+ }
182
+ if (view.above || view.below || view.clip !== null) {
183
+ cut = true;
184
+ if (used < budget)
185
+ rows.push({ text: moreIndicator(view.above, view.below) || `↓ ${blocks[view.start].length - (view.clip ?? 0)} more`, tone: 'dim', role: 'more', selected: false });
186
+ }
187
+ });
188
+ chrome(content.foot ?? [], foot, keepFoot, 'foot');
189
+ return { border, borderStyle: content.borderStyle ?? 'round', rows, sections: views, cut, dropped };
190
+ }
191
+ function toneStyle(tone, accentColor) {
192
+ if (tone === 'title')
193
+ return { bold: true, color: accentColor };
194
+ if (tone === 'accent')
195
+ return { color: accentColor };
196
+ if (tone === 'selected')
197
+ return { inverse: true, color: accentColor };
198
+ if (tone === 'strong')
199
+ return { bold: true };
200
+ if (tone === 'dim')
201
+ return { dimColor: true };
202
+ return {};
203
+ }
204
+ /** The fitted overlay as Ink elements: one `Text` per row, cut rather than wrapped by Ink, so its height is exact. */
205
+ export function renderFittedOverlay(h, Ink, fitted, { accentColor } = {}) {
206
+ // `flexShrink:0`: inside lane L's fixed-height root a shrinking box is exactly how a border ends up under content.
207
+ const box = fitted.border ? { borderStyle: fitted.borderStyle, flexDirection: 'column', flexShrink: 0 } : { flexDirection: 'column', flexShrink: 0 };
208
+ return h(Ink.Box, box, ...fitted.rows.map((row, index) => typeof row.accentTo === 'number' && row.accentTo > 0 && row.text
209
+ ? h(Ink.Text, { key: index, wrap: 'truncate-end' }, h(Ink.Text, toneStyle('accent', row.accentColor ?? accentColor), row.text.slice(0, row.accentTo)), h(Ink.Text, toneStyle(row.tone, accentColor), row.text.slice(row.accentTo)))
210
+ : h(Ink.Text, { key: index, wrap: 'truncate-end', ...toneStyle(row.tone, accentColor) }, row.text || ' ')));
211
+ }
212
+ /** `maxRows` absent: the whole overlay, as tall as its wrapped content (today's behaviour until lane L passes the budget). */
213
+ export function renderOverlay(h, Ink, content, { maxRows, columns, accentColor }) {
214
+ return renderFittedOverlay(h, Ink, fitOverlay(content, { maxRows, columns }), { accentColor });
215
+ }
216
+ /** Splits an overlay's own line list into chrome and one selectable list (+ an optional detail section after it). */
217
+ export function listOverlay(lines, { head, list, selected, foot, tones }) {
218
+ const toned = lines.map((text, index) => ({ text, tone: tones?.(text, index) }));
219
+ const headLines = toned.slice(0, head), listLines = toned.slice(head, head + list);
220
+ const footLines = foot ? toned.slice(Math.max(head + list, toned.length - foot)) : [];
221
+ const detail = toned.slice(head + list, toned.length - footLines.length);
222
+ const sections = [];
223
+ if (listLines.length)
224
+ sections.push({ lines: listLines, selected: Math.max(0, Math.min(listLines.length - 1, selected)) });
225
+ if (detail.length)
226
+ sections.push({ lines: detail, offset: 0 });
227
+ return { head: headLines, sections, foot: footLines };
228
+ }
229
+ /** The control centers' look: the title in the accent colour, every other line dim (as app.ts draws them today). */
230
+ export const centerTones = (_line, index) => index === 0 ? 'accent' : 'dim';
231
+ /** A picker's rows as app.ts draws them: `›` and inverse on the selected row, the accent colour on the others. */
232
+ export function pickerSection(rows, selected, label) {
233
+ return { lines: rows.map((row, index) => ({ text: `${index === selected ? '›' : ' '} ${label(row)}`, tone: index === selected ? 'selected' : 'accent' })), selected };
234
+ }
@@ -0,0 +1,115 @@
1
+ import { t, tn } from "../../i18n/index.js";
2
+ import { normalizeSessionSummary } from "../../runtime/session-summary.js";
3
+ import { createSessionMetadataStore } from "../../sessions/metadata-store.js";
4
+ import { moveSelection } from "../selection-list.js";
5
+ import { pickerSection } from "./scroll-window.js";
6
+ function isTyped(row) { return Boolean(row && typeof row.id === 'string' && typeof row.sessionId === 'string' && typeof row.depth === 'number' && typeof row.outcome === 'string' && Array.isArray(row.collisions)); }
7
+ export function normalizeSessions(rows) {
8
+ return rows.map((row) => {
9
+ const summary = isTyped(row) ? row : normalizeSessionSummary(row);
10
+ const tags = Array.isArray(row?.tags) ? row.tags.filter((value) => typeof value === 'string') : [];
11
+ /* R5b D2: the person's own name (/rename, kept in the metadata) wins over the kernel's short name. */
12
+ const named = typeof row?.metadataName === 'string' && row.metadataName ? row.metadataName : null;
13
+ return { ...summary, title: named ?? summary.name ?? summary.id, tags, pinned: row?.pinned === true };
14
+ }).filter(row => row.id).sort((a, b) => {
15
+ if (a.pinned !== b.pinned)
16
+ return a.pinned ? -1 : 1;
17
+ const aTime = a.updatedAt ?? a.startedAt, bTime = b.updatedAt ?? b.startedAt;
18
+ if (aTime === bTime)
19
+ return 0;
20
+ if (aTime === null)
21
+ return 1;
22
+ if (bTime === null)
23
+ return -1;
24
+ return bTime.localeCompare(aTime);
25
+ });
26
+ }
27
+ export function filterSessions(rows, query) { const q = query.trim().toLowerCase(); return q ? rows.filter(row => [row.id, row.title, row.project ?? '', row.path ?? '', ...(Array.isArray(row.tags) ? row.tags : [])].some(value => String(value ?? '').toLowerCase().includes(q))) : [...rows]; }
28
+ export function createSessionPickerModel(controller, action, options = {}) {
29
+ let all = [];
30
+ let visible = [];
31
+ let state = { query: '', selected: 0, pageSize: 10 };
32
+ let cancelled = false;
33
+ return {
34
+ async open() { cancelled = false; const source = await controller.listSessions(); if (options.metadataRoot) {
35
+ const rows = normalizeSessions(source);
36
+ const store = createSessionMetadataStore({ rootDir: options.metadataRoot });
37
+ all = normalizeSessions(await Promise.all(rows.map(async (row) => { const metadata = await store.get(row.id); return { ...row, tags: metadata?.tags ?? [], pinned: metadata?.pinned ?? false, ...(metadata?.name ? { metadataName: metadata.name } : {}) }; })));
38
+ all = sessionTree(all);
39
+ }
40
+ else
41
+ all = source.map(row => ({ ...row, tags: Array.isArray(row.tags) ? row.tags : [], pinned: row.pinned === true })); visible = all; state = { query: '', selected: 0, pageSize: 10 }; },
42
+ move(next) { state = moveSelection(state, visible.length, next); },
43
+ select(index) { state = { ...state, selected: Math.max(0, Math.min(Math.max(0, visible.length - 1), Math.trunc(index))) }; },
44
+ /* R5b: the session it attached (the fork's new id), so the screen can say where a fork came from. */
45
+ async confirm() { if (cancelled)
46
+ return null; const row = visible[state.selected]; if (!row)
47
+ return null; return action === 'resume' ? await controller.resumeSession(row.id) : await controller.forkSession(row.id); },
48
+ action: () => action,
49
+ cancel() { cancelled = true; }, rows: () => visible, selected: () => state.selected,
50
+ setQuery(query) { visible = filterSessions(all, query); state = { ...state, query, selected: 0 }; },
51
+ };
52
+ }
53
+ /* R5b D2 (Q-R5-12): how long ago, as a person says it; a date after a month. */
54
+ export function sessionAge(iso, now = Date.now()) {
55
+ const at = typeof iso === 'string' ? Date.parse(iso) : Number.NaN;
56
+ if (Number.isNaN(at))
57
+ return '';
58
+ const minutes = Math.floor(Math.max(0, now - at) / 60_000);
59
+ if (minutes < 1)
60
+ return t('screen.session.ageNow');
61
+ if (minutes < 60)
62
+ return t('screen.session.ageMinutes', { count: minutes });
63
+ const hours = Math.floor(minutes / 60);
64
+ if (hours < 24)
65
+ return t('screen.session.ageHours', { count: hours });
66
+ const days = Math.floor(hours / 24);
67
+ if (days < 31)
68
+ return t('screen.session.ageDays', { count: days });
69
+ return new Date(at).toISOString().slice(0, 10);
70
+ }
71
+ /* R5b D2 (Q-R5-12, "the branch tree"): each fork right under the conversation it came from (depth +1), in the list's own
72
+ order; a fork whose origin is not listed stays where it was. */
73
+ export function sessionTree(rows) {
74
+ const ids = new Set(rows.map(row => row.id));
75
+ const children = new Map();
76
+ const roots = [];
77
+ for (const row of rows) {
78
+ const from = row.forkedFrom;
79
+ if (from && from !== row.id && ids.has(from)) {
80
+ const list = children.get(from) ?? [];
81
+ list.push(row);
82
+ children.set(from, list);
83
+ }
84
+ else
85
+ roots.push(row);
86
+ }
87
+ const out = [];
88
+ const seen = new Set();
89
+ const visit = (row, depth) => { if (seen.has(row.id))
90
+ return; seen.add(row.id); out.push({ ...row, forkDepth: depth }); for (const child of children.get(row.id) ?? [])
91
+ visit(child, Math.min(depth + 1, 4)); };
92
+ for (const row of roots)
93
+ visit(row, 0);
94
+ for (const row of rows)
95
+ if (!seen.has(row.id))
96
+ visit(row, 0);
97
+ return out;
98
+ }
99
+ function sessionRowText(row, now) {
100
+ const depth = row.forkDepth ?? 0;
101
+ const parts = [`${row.title || row.id}`, sessionAge(row.updatedAt ?? row.startedAt, now), row.usage?.turns ? tn('screen.session.turns', row.usage.turns) : '', row.model ?? ''].filter(Boolean);
102
+ return `${row.pinned ? '★ ' : ''}${' '.repeat(depth)}${depth || row.forkedFrom ? '⑂ ' : ''}${parts.join(' · ')}${row.tags?.length ? ` · ${row.tags.map((tag) => `#${tag}`).join(' ')}` : ''}`;
103
+ }
104
+ // R1 Q-R1-3: the picker as app.ts draws it, capped and scrolled by overlays/scroll-window.ts.
105
+ // R4 Q-R4-13: with nothing to list it says so and how to start one (review D-10 s09: the empty picker had no text; Claude
106
+ // Code "No conversations found in this project.", Codex "No sessions yet", Pi "No sessions in current folder", gate §5.2).
107
+ export function sessionPickerOverlay({ action, query, rows, selected, now = Date.now() }) {
108
+ const empty = query.trim() ? t('screen.session.noMatch', { query: query.trim() }) : t('screen.session.empty');
109
+ return {
110
+ head: [{ text: t(action === 'resume' ? 'screen.session.resumeTitle' : 'screen.session.forkTitle'), tone: 'title' }, { text: t('screen.picker.search', { query: query || t('screen.none') }), tone: 'dim' }],
111
+ sections: [rows.length
112
+ ? pickerSection(rows, selected, row => sessionRowText(row, now))
113
+ : { lines: [{ text: empty, tone: 'dim' }] }],
114
+ };
115
+ }
@@ -0,0 +1,83 @@
1
+ import { en, t } from "../../i18n/index.js";
2
+ import { centerTones, listOverlay } from "./scroll-window.js";
3
+ const UNSAFE = /[\\\x00-\x1f\x7f-\x9f\u2028\u2029\p{Bidi_Control}\p{Default_Ignorable_Code_Point}]/gu;
4
+ function inert(value) { return String(value ?? '').replace(UNSAFE, ch => { if (ch === '\\')
5
+ return '\\\\'; const cp = ch.codePointAt(0) ?? 0; return cp <= 0xffff ? '\\u' + cp.toString(16).padStart(4, '0') : '\\u{' + cp.toString(16) + '}'; }); }
6
+ /* R2 (gate §1.5, E4): the kernel's `origine` value (modello|persona) is mapped by value, never printed raw. */
7
+ function writerLabel(value) { const id = `screen.writer.${String(value)}`; return Object.hasOwn(en, id) ? t(id) : inert(value); }
8
+ function clamp(value, count) { return count ? Math.max(0, Math.min(count - 1, value)) : 0; }
9
+ export function createTasksCenterModel(snapshot, selected = 0) { return { snapshot, selected: clamp(selected, snapshot.rows.length) }; }
10
+ export function moveTasksCenterSelection(model, delta) { return { ...model, selected: clamp(model.selected + delta, model.snapshot.rows.length) }; }
11
+ export function selectedTask(model) { return model.snapshot.rows[model.selected] ?? null; }
12
+ function evidenceLabel(row) {
13
+ if (row.state === 'dangling' || !row.measurement)
14
+ return 'evidence ' + inert(row.sessionId) + ' · dangling';
15
+ const m = row.measurement;
16
+ return 'evidence ' + inert(row.sessionId) + ' · available · writes ' + m.scritture + ' · artifacts ' + m.artefatti + ' · tools ' + m.toolCalls + ' · ok ' + m.toolCallsOk + ' · failed ' + m.toolCallsFalliti + ' · verifiable ' + (m.verificabile ? 'yes' : 'no');
17
+ }
18
+ function scheduleLabel(row) {
19
+ if (row.state === 'dangling')
20
+ return 'schedule ' + inert(row.automationId) + ' · dangling';
21
+ return 'schedule ' + inert(row.automationId) + ' · available · executes ' + inert(row.executionTaskId ?? 'unavailable') + ' · interval ' + inert(row.intervalMinutes ?? 'unavailable') + 'm · ' + (row.active ? 'active' : 'inactive') + ' · next ' + inert(row.nextExecution ?? 'unavailable');
22
+ }
23
+ export function renderTasksCenterLines(model) {
24
+ const lines = [t('screen.tasks.title')];
25
+ if (model.snapshot.state === 'invalid') {
26
+ lines.push('Store: invalid · ' + inert(model.snapshot.error?.code ?? 'TASK_BOARD_INVALID') + ' · ' + inert(model.snapshot.error?.message ?? 'unavailable'));
27
+ lines.push(t('screen.center.closeRefresh'));
28
+ return lines;
29
+ }
30
+ if (!model.snapshot.rows.length) {
31
+ lines.push(t('screen.tasks.empty'));
32
+ lines.push(t('screen.center.closeRefresh'));
33
+ return lines;
34
+ }
35
+ lines.push(...model.snapshot.rows.map((row, index) => (index === model.selected ? '› ' : ' ') + '[' + inert(row.status) + '] ' + inert(row.priority) + ' · ' + inert(row.title) + ' · ' + inert(row.id)));
36
+ const row = selectedTask(model);
37
+ if (row) {
38
+ lines.push('ID: ' + inert(row.id) + ' · writer ' + writerLabel(row.writer) + ' (' + inert(row.writerEvidence) + ')');
39
+ if (row.description)
40
+ lines.push('Description: ' + inert(row.description));
41
+ if (row.dependencies.length) {
42
+ lines.push('Dependencies:');
43
+ for (const dep of row.dependencies)
44
+ lines.push('- depends ' + inert(dep.targetTaskId) + ' · ' + inert(dep.state) + (dep.label ? ' · ' + inert(dep.label) : ''));
45
+ }
46
+ else
47
+ lines.push('Dependencies: none');
48
+ if (row.evidence.length) {
49
+ lines.push('Evidence:');
50
+ for (const evidence of row.evidence)
51
+ lines.push('- ' + evidenceLabel(evidence));
52
+ }
53
+ else
54
+ lines.push('Evidence: none');
55
+ if (row.agents.length) {
56
+ lines.push('Agents:');
57
+ for (const agent of row.agents)
58
+ lines.push('- agent ' + inert(agent.sessionId) + ' · ' + inert(agent.state) + ' · parent ' + inert(agent.parentSessionId ?? 'unavailable') + ' · depth ' + inert(agent.depth ?? 'unavailable') + ' · ' + inert(agent.task ?? 'unavailable') + ' · ' + inert(agent.outcome));
59
+ }
60
+ else
61
+ lines.push('Agents: none');
62
+ if (row.schedules.length) {
63
+ lines.push('Schedules:');
64
+ for (const schedule of row.schedules)
65
+ lines.push('- ' + scheduleLabel(schedule));
66
+ }
67
+ else
68
+ lines.push('Schedules: none');
69
+ }
70
+ lines.push(t('screen.center.selectRefresh'));
71
+ lines.push(t('screen.tasks.edges'));
72
+ lines.push(t('screen.tasks.edgesEvidence'));
73
+ lines.push(t('screen.tasks.edgesAssign'));
74
+ lines.push(t('screen.tasks.edgesSchedule'));
75
+ return lines;
76
+ }
77
+ // R1 Q-R1-3: the same lines as a capped, scrolling overlay — the list keeps the selection visible, the detail scrolls.
78
+ // The four /tasks edge reference lines follow the key hint: they scroll with the detail, the hint stays.
79
+ export function tasksCenterOverlay(model) {
80
+ const lines = renderTasksCenterLines(model), list = model.snapshot.state === 'invalid' ? 0 : model.snapshot.rows.length;
81
+ const reference = list ? 4 : 0, hint = lines.length - 1 - reference;
82
+ return listOverlay([...lines.slice(0, hint), ...lines.slice(hint + 1), lines[hint]], { head: 1, list, selected: model.selected, foot: 1, tones: centerTones });
83
+ }
@@ -0,0 +1,21 @@
1
+ /*
2
+ * R5b D4 (owner decision Q-R5-14): the /theme picker — the ten product themes and mono, each with a swatch drawn in its
3
+ * own accent, the one in use marked. The arrows preview a theme on the whole screen (theme-store.ts); Enter keeps it, Esc
4
+ * puts back the one in use.
5
+ */
6
+ import { t } from "../../i18n/index.js";
7
+ import { TALOS_THEME_ACCENTS } from "../theme-catalog.js";
8
+ import { THEME_CHOICES } from "../theme-store.js";
9
+ export function themeLabel(id) { return TALOS_THEME_ACCENTS.find(row => row.id === id)?.label ?? t('screen.theme.mono'); }
10
+ export function themePickerOverlay({ selected, current, colors }) {
11
+ const lines = THEME_CHOICES.map((id, index) => {
12
+ const row = TALOS_THEME_ACCENTS.find(entry => entry.id === id);
13
+ const text = `${row ? '■' : ' '} ${themeLabel(id)}${id === 'mono' ? ' · ' + t('screen.theme.noColour') : ''}${id === current ? ' · ' + t('screen.theme.inUse') : ''}`;
14
+ return { text, tone: index === selected ? 'selected' : 'plain', ...(row && colors ? { accentTo: 1, accentColor: row.accent } : {}) };
15
+ });
16
+ return {
17
+ head: [{ text: t('screen.theme.title'), tone: 'title' }],
18
+ sections: [{ lines, selected }],
19
+ foot: [{ text: t('screen.theme.keys', { current: themeLabel(current) }), tone: 'dim' }],
20
+ };
21
+ }
@@ -0,0 +1,58 @@
1
+ import { t } from "../../i18n/index.js";
2
+ import { transcriptItemRaw, transcriptItemText } from "../transcript-model.js";
3
+ import { listOverlay } from "./scroll-window.js";
4
+ export function createTranscriptSearchState(selectedId = null) { return { query: '', mode: 'literal', selectedId, raw: false, notice: null }; }
5
+ function haystack(item) { return (item.id + '\n' + item.kind + '\n' + transcriptItemText(item)).toLocaleLowerCase(); }
6
+ function fuzzyIncludes(text, query) {
7
+ let at = 0;
8
+ for (const character of query) {
9
+ at = text.indexOf(character, at);
10
+ if (at < 0)
11
+ return false;
12
+ at++;
13
+ }
14
+ return true;
15
+ }
16
+ export function transcriptSearchMatches(items, query, mode) {
17
+ const needle = String(query ?? '').trim().toLocaleLowerCase();
18
+ const matches = [];
19
+ for (let index = 0; index < items.length; index++) {
20
+ const item = items[index], text = haystack(item);
21
+ if (!needle || (mode === 'literal' ? text.includes(needle) : fuzzyIncludes(text, needle)))
22
+ matches.push({ itemId: item.id, index });
23
+ }
24
+ return matches;
25
+ }
26
+ export function selectedTranscriptMatch(matches, selectedId) {
27
+ if (matches.length === 0)
28
+ return null;
29
+ return matches.find(row => row.itemId === selectedId) ?? matches[0] ?? null;
30
+ }
31
+ export function moveTranscriptSearchSelection(matches, selectedId, delta) {
32
+ if (matches.length === 0)
33
+ return null;
34
+ const index = matches.findIndex(row => row.itemId === selectedId);
35
+ if (index < 0)
36
+ return matches[0].itemId;
37
+ const next = Math.max(0, Math.min(matches.length - 1, index + delta));
38
+ return matches[next].itemId;
39
+ }
40
+ export function transcriptSearchLines({ items, state, raw = state.raw }) {
41
+ const matches = transcriptSearchMatches(items, state.query, state.mode);
42
+ const selected = selectedTranscriptMatch(matches, state.selectedId);
43
+ const position = selected ? matches.findIndex(row => row.itemId === selected.itemId) + 1 : 0;
44
+ const header = t('screen.search.header', { mode: state.mode, position, total: matches.length, view: t(raw ? 'screen.search.viewRaw' : 'screen.search.viewSemantic') });
45
+ const query = t('screen.search.query', { query: state.query || t('screen.none') });
46
+ if (!selected)
47
+ return [header, query, state.notice ?? t('screen.search.none')];
48
+ const item = items[selected.index];
49
+ const preview = (raw ? transcriptItemRaw(item) : transcriptItemText(item)).split(/\r?\n/u).slice(0, 10);
50
+ return [header, query, ...(state.notice ? [state.notice] : []), t('screen.search.selected', { id: item.id }), ...preview];
51
+ }
52
+ // R1 Q-R1-3: the preview scrolls under the header and the query. The `selected:` row heads the scrolling part as its
53
+ // selected line, so a short budget drops the query before it drops the name of the item Enter would jump to.
54
+ export function transcriptSearchOverlay(input) {
55
+ const lines = transcriptSearchLines(input), marker = t('screen.search.selected', { id: '' }), selected = lines.findIndex(line => line.startsWith(marker));
56
+ const head = selected < 0 ? 2 : selected;
57
+ return listOverlay(lines, { head, list: selected < 0 ? 0 : lines.length - head, selected: 0, foot: 0, tones: (_line, index) => index === 0 ? 'accent' : 'dim' });
58
+ }
@@ -0,0 +1,29 @@
1
+ import { t, tn } from "../../i18n/index.js";
2
+ import { listOverlay } from "./scroll-window.js";
3
+ const UNSAFE = /[\\\x00-\x1f\x7f-\x9f\u2028\u2029\p{Bidi_Control}\p{Default_Ignorable_Code_Point}]/gu;
4
+ const BACKSLASH = String.fromCharCode(92);
5
+ export function inertTrustCenterText(value) { return String(value).replace(UNSAFE, character => { if (character === BACKSLASH)
6
+ return BACKSLASH + BACKSLASH; const code = character.codePointAt(0); return code > 0xffff ? `${BACKSLASH}u{${code.toString(16)}}` : `${BACKSLASH}u${code.toString(16).padStart(4, '0')}`; }); }
7
+ function shown(value) { return inertTrustCenterText(value); }
8
+ function statusLabel(snapshot) { return snapshot.trusted ? t('screen.trust.trusted') : t('screen.trust.notTrusted', { reason: snapshot.reason }); }
9
+ export function trustCenterModel(snapshot, { permissionMode }) {
10
+ const projectSection = [
11
+ t('screen.trust.project', { root: shown(snapshot.workspace.canonicalRoot) }),
12
+ t('screen.trust.projectTrust', { status: statusLabel(snapshot) }),
13
+ `Store: ${snapshot.storeSchema ? snapshot.storeSchema === 'v1' ? 'legacy v1' : 'v2' : 'none'}${snapshot.migrationRequired ? ' · migration available' : ''}${snapshot.rollbackAvailable ? ' · rollback available' : ''}`
14
+ ];
15
+ const permissionSection = [t('screen.trust.permissionMode', { mode: shown(permissionMode) }), t('screen.trust.policy')];
16
+ const resourceSection = snapshot.resources.length ? snapshot.resources.map(row => `${row.kind} · ${shown(row.id)} · ${row.state} · ${shown(row.relativePath)}`) : [t('screen.trust.noResources')];
17
+ const nestedSection = snapshot.nestedRepositories.length ? snapshot.nestedRepositories.map(row => tn('screen.trust.nested', row.resources.length, { path: shown(row.relativePath) })) : [t('screen.trust.noNested')];
18
+ const actions = [t('screen.trust.review'), t('screen.trust.accept'), t('screen.trust.revoke')];
19
+ if (snapshot.migrationRequired)
20
+ actions.push(t(snapshot.nestedRepositories.length ? 'screen.trust.migrateNested' : 'screen.trust.migrate'));
21
+ if (snapshot.rollbackAvailable)
22
+ actions.push(t('screen.trust.rollback'));
23
+ return { title: t('screen.trust.title'), projectSection, permissionSection, resourceSection, nestedSection, actions };
24
+ }
25
+ export function renderTrustCenterLines(model) { return [model.title, '', ...model.projectSection, '', ...model.permissionSection, '', t('screen.trust.resources'), ...model.resourceSection, '', ...model.nestedSection, '', t('screen.trust.actions'), ...model.actions]; }
26
+ // R1 Q-R1-3: the same lines as a capped, scrolling overlay (overlays/scroll-window.ts).
27
+ export function trustCenterOverlay(model) {
28
+ return listOverlay([...renderTrustCenterLines(model), t('screen.center.closes')], { head: 1, list: 0, selected: 0, foot: 1, tones: (_line, index) => index === 0 ? 'plain' : 'dim' });
29
+ }
@@ -0,0 +1,46 @@
1
+ import { t } from "../../i18n/index.js";
2
+ import { centerTones, listOverlay } from "./scroll-window.js";
3
+ const UNSAFE = /[\\\x00-\x1f\x7f-\x9f\u2028\u2029\p{Bidi_Control}\p{Default_Ignorable_Code_Point}]/gu;
4
+ const BACKSLASH = String.fromCharCode(92);
5
+ function inert(value) {
6
+ return String(value).replace(UNSAFE, character => {
7
+ if (character === BACKSLASH)
8
+ return BACKSLASH + BACKSLASH;
9
+ const code = character.codePointAt(0);
10
+ return code > 0xffff ? BACKSLASH + 'u{' + code.toString(16) + '}' : BACKSLASH + 'u' + code.toString(16).padStart(4, '0');
11
+ });
12
+ }
13
+ function shown(value) { return inert(String(value ?? '—')); }
14
+ export function createWorkflowCenterModel(rows, selected = 0) {
15
+ const copy = rows.map(row => ({ ...row, references: [...row.references] }));
16
+ return { title: t('screen.workflow.title'), rows: copy, selected: copy.length ? Math.max(0, Math.min(copy.length - 1, selected)) : 0 };
17
+ }
18
+ export function moveWorkflowCenterSelection(model, delta) {
19
+ if (!model.rows.length)
20
+ return model;
21
+ return { ...model, selected: Math.max(0, Math.min(model.rows.length - 1, model.selected + delta)) };
22
+ }
23
+ export function selectedWorkflow(model) { return model.rows[model.selected] ?? null; }
24
+ export function renderWorkflowCenterLines(model) {
25
+ const lines = [model.title, ''];
26
+ if (!model.rows.length)
27
+ return [...lines, t('screen.workflow.empty')];
28
+ for (const [index, row] of model.rows.entries()) {
29
+ const state = row.validation.valid ? (row.trust.required ? (row.trust.trusted ? 'trusted' : row.trust.state) : row.trust.state) : 'invalid';
30
+ lines.push((index === model.selected ? '›' : ' ') + ' ' + shown(row.id) + ' · ' + row.kind + ' · ' + row.provenance.scope + ' · ' + state);
31
+ }
32
+ const row = selectedWorkflow(model);
33
+ if (!row)
34
+ return lines;
35
+ lines.push('', 'Selected: ' + shown(row.name) + ' · ' + row.kind, 'Provenance: ' + row.provenance.scope + ' · ' + shown(row.provenance.path), 'Validation: ' + (row.validation.valid ? 'valid' : 'INVALID ' + shown(row.validation.code)) + (row.validation.message ? ' · ' + shown(row.validation.message) : ''), 'Trust: ' + (row.trust.required ? (row.trust.trusted ? 'trusted' : row.trust.state) : row.trust.state), 'Current fingerprint: ' + shown(row.trust.currentFingerprint), 'Trusted fingerprint: ' + shown(row.trust.trustedFingerprint), 'Executable steps: ' + row.executableSteps);
36
+ if (row.references.length) {
37
+ lines.push('References');
38
+ for (const reference of row.references)
39
+ lines.push(' ' + reference.type + ' · ' + shown(reference.name) + ' · ' + shown(reference.id));
40
+ }
41
+ return lines;
42
+ }
43
+ // R1 Q-R1-3: the same lines as a capped, scrolling overlay — the list keeps the selection visible, the detail scrolls.
44
+ export function workflowCenterOverlay(model) {
45
+ return listOverlay(renderWorkflowCenterLines(model), { head: 2, list: model.rows.length, selected: model.selected, foot: 0, tones: centerTones });
46
+ }