talos-code 0.0.1 → 0.1.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 (401) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +111 -3
  3. package/THIRD_PARTY_NOTICES.md +40 -0
  4. package/dist/archive/zip.js +73 -0
  5. package/dist/args.js +97 -0
  6. package/dist/automations/history-store.js +34 -0
  7. package/dist/automations/policy-store.js +43 -0
  8. package/dist/automations/runner.js +107 -0
  9. package/dist/automations/schedule.js +85 -0
  10. package/dist/automations/windows-task.js +53 -0
  11. package/dist/commands/advanced-cli.js +233 -0
  12. package/dist/commands/checkpoint-cli.js +45 -0
  13. package/dist/commands/config-cli.js +107 -0
  14. package/dist/commands/context.js +17 -0
  15. package/dist/commands/extensions-cli.js +207 -0
  16. package/dist/commands/project-cli.js +74 -0
  17. package/dist/commands/project-commands.js +143 -0
  18. package/dist/commands/provider-cli.js +185 -0
  19. package/dist/commands/services-cli.js +248 -0
  20. package/dist/commands/session-cli.js +171 -0
  21. package/dist/commands/system-cli.js +405 -0
  22. package/dist/config/commands.js +60 -0
  23. package/dist/config/load.js +382 -0
  24. package/dist/config/migrations.js +48 -0
  25. package/dist/config/types.js +11 -0
  26. package/dist/diagnostics/development-log.js +154 -0
  27. package/dist/diagnostics/doctor.js +104 -0
  28. package/dist/diagnostics/redact.js +80 -0
  29. package/dist/diagnostics/zip.js +52 -0
  30. package/dist/errors.js +156 -0
  31. package/dist/events/bridge.js +130 -0
  32. package/dist/extensions/installer.js +178 -0
  33. package/dist/extensions/package-schema.js +24 -0
  34. package/dist/headless/result.js +84 -0
  35. package/dist/headless/run.js +230 -0
  36. package/dist/i18n/en/approval.js +43 -0
  37. package/dist/i18n/en/common.js +9 -0
  38. package/dist/i18n/en/credentials.js +82 -0
  39. package/dist/i18n/en/errors.js +246 -0
  40. package/dist/i18n/en/firstrun.js +89 -0
  41. package/dist/i18n/en/providers.js +37 -0
  42. package/dist/i18n/en/screen.js +736 -0
  43. package/dist/i18n/en/tools.js +127 -0
  44. package/dist/i18n/en.js +14 -0
  45. package/dist/i18n/error-view.js +307 -0
  46. package/dist/i18n/index.js +19 -0
  47. package/dist/i18n/kernel-map.js +139 -0
  48. package/dist/io.js +45 -0
  49. package/dist/main.js +330 -0
  50. package/dist/paths.js +41 -0
  51. package/dist/protocol/v2/codec.js +9 -0
  52. package/dist/protocol/v2/events.js +555 -0
  53. package/dist/protocol/v2/index.js +4 -0
  54. package/dist/protocol/v2/replay.js +28 -0
  55. package/dist/protocol/v2/types.js +1 -0
  56. package/dist/provider/control-plane.js +135 -0
  57. package/dist/provider/environment-keys.js +275 -0
  58. package/dist/provider/health.js +110 -0
  59. package/dist/provider/missing-key.js +48 -0
  60. package/dist/provider/model-catalog.js +168 -0
  61. package/dist/provider/provider-text.js +13 -0
  62. package/dist/provider/store.js +95 -0
  63. package/dist/provider/system-keyring.js +214 -0
  64. package/dist/runtime/active-run.js +63 -0
  65. package/dist/runtime/agent-tree.js +74 -0
  66. package/dist/runtime/attachments.js +84 -0
  67. package/dist/runtime/brokered-executor.js +395 -0
  68. package/dist/runtime/context-status.js +76 -0
  69. package/dist/runtime/create-runtime.js +111 -0
  70. package/dist/runtime/model-profile.js +361 -0
  71. package/dist/runtime/output-store.js +137 -0
  72. package/dist/runtime/provider-attempts.js +185 -0
  73. package/dist/runtime/replay-buffer.js +153 -0
  74. package/dist/runtime/repo.js +95 -0
  75. package/dist/runtime/session-facade.js +135 -0
  76. package/dist/runtime/session-summary.js +125 -0
  77. package/dist/runtime/supervisor.js +262 -0
  78. package/dist/runtime/talos-composition.js +1006 -0
  79. package/dist/runtime/types.js +5 -0
  80. package/dist/runtime/usage-snapshot.js +82 -0
  81. package/dist/security/auto-classifier.js +38 -0
  82. package/dist/security/credential-free-environment.js +54 -0
  83. package/dist/security/evaluate.js +243 -0
  84. package/dist/security/execution-backends.js +236 -0
  85. package/dist/security/execution-broker.js +102 -0
  86. package/dist/security/forge-scan.js +74 -0
  87. package/dist/security/from-approval.js +39 -0
  88. package/dist/security/mxc-execution-backend.js +281 -0
  89. package/dist/security/permission-engine.js +138 -0
  90. package/dist/security/permission-explanation.js +54 -0
  91. package/dist/security/persist.js +179 -0
  92. package/dist/security/plugin-guard.js +230 -0
  93. package/dist/security/process-tree-evidence-store.js +74 -0
  94. package/dist/security/process-tree-probe.js +554 -0
  95. package/dist/security/project-resource-inventory.js +186 -0
  96. package/dist/security/project-trust-gate.js +38 -0
  97. package/dist/security/project-trust.js +367 -0
  98. package/dist/security/rule-parser.js +201 -0
  99. package/dist/security/shell-segmentation.js +68 -0
  100. package/dist/security/trust-authority.js +324 -0
  101. package/dist/security/types.js +1 -0
  102. package/dist/security/workspace-identity.js +102 -0
  103. package/dist/services/automation-facade.js +59 -0
  104. package/dist/services/forge-facade.js +77 -0
  105. package/dist/services/hook-facade.js +240 -0
  106. package/dist/services/index.js +16 -0
  107. package/dist/services/library-facade.js +174 -0
  108. package/dist/services/mcp-facade.js +348 -0
  109. package/dist/services/memory-facade.js +126 -0
  110. package/dist/services/notes-facade.js +157 -0
  111. package/dist/services/plugin-facade.js +308 -0
  112. package/dist/services/research-facade.js +110 -0
  113. package/dist/services/task-board-facade.js +236 -0
  114. package/dist/services/workflow-catalog.js +246 -0
  115. package/dist/sessions/export-format.js +98 -0
  116. package/dist/sessions/metadata-store.js +160 -0
  117. package/dist/sessions/share.js +122 -0
  118. package/dist/sessions/transfer.js +16 -0
  119. package/dist/subcommands.js +62 -0
  120. package/dist/tui/agent-roster.js +36 -0
  121. package/dist/tui/app.js +3761 -0
  122. package/dist/tui/approval.js +36 -0
  123. package/dist/tui/boot/boot-sequence.js +76 -0
  124. package/dist/tui/boot/cinematic.js +243 -0
  125. package/dist/tui/boot/desktop-logo.js +82 -0
  126. package/dist/tui/boot.js +3 -0
  127. package/dist/tui/busy-input.js +58 -0
  128. package/dist/tui/catalog-service.js +559 -0
  129. package/dist/tui/components/assistant-stream.js +1 -0
  130. package/dist/tui/components/command-menu.js +68 -0
  131. package/dist/tui/components/composer.js +219 -0
  132. package/dist/tui/components/diff.js +35 -0
  133. package/dist/tui/components/footer.js +48 -0
  134. package/dist/tui/components/header.js +6 -0
  135. package/dist/tui/components/markdown.js +305 -0
  136. package/dist/tui/components/status-indicator.js +32 -0
  137. package/dist/tui/components/terminal-shell.js +205 -0
  138. package/dist/tui/components/thinking-row.js +19 -0
  139. package/dist/tui/components/tool-row.js +97 -0
  140. package/dist/tui/components/transcript-virtualizer.js +165 -0
  141. package/dist/tui/components/transcript.js +43 -0
  142. package/dist/tui/diff-model.js +77 -0
  143. package/dist/tui/editor-history.js +21 -0
  144. package/dist/tui/editor.js +210 -0
  145. package/dist/tui/event-adapter.js +436 -0
  146. package/dist/tui/exit-output.js +58 -0
  147. package/dist/tui/external-editor.js +53 -0
  148. package/dist/tui/file-completion.js +89 -0
  149. package/dist/tui/focus-manager.js +5 -0
  150. package/dist/tui/highlight.js +30 -0
  151. package/dist/tui/input-router.js +18 -0
  152. package/dist/tui/interrupt.js +99 -0
  153. package/dist/tui/keybindings.js +194 -0
  154. package/dist/tui/keymap-resolver.js +91 -0
  155. package/dist/tui/launch-state.js +139 -0
  156. package/dist/tui/line-diff.js +57 -0
  157. package/dist/tui/live-activity.js +45 -0
  158. package/dist/tui/metrics.js +123 -0
  159. package/dist/tui/onboarding.js +36 -0
  160. package/dist/tui/overlays/agent-tree.js +39 -0
  161. package/dist/tui/overlays/approval-dialog.js +640 -0
  162. package/dist/tui/overlays/automation-center.js +51 -0
  163. package/dist/tui/overlays/checkpoint-picker.js +47 -0
  164. package/dist/tui/overlays/context-inspector.js +36 -0
  165. package/dist/tui/overlays/effort-line.js +110 -0
  166. package/dist/tui/overlays/forge-center.js +46 -0
  167. package/dist/tui/overlays/help-dialog.js +16 -0
  168. package/dist/tui/overlays/history-picker.js +37 -0
  169. package/dist/tui/overlays/hook-center.js +70 -0
  170. package/dist/tui/overlays/library-center.js +55 -0
  171. package/dist/tui/overlays/mcp-center.js +60 -0
  172. package/dist/tui/overlays/memory-center.js +63 -0
  173. package/dist/tui/overlays/model-picker.js +72 -0
  174. package/dist/tui/overlays/notes-center.js +53 -0
  175. package/dist/tui/overlays/overlay-host.js +8 -0
  176. package/dist/tui/overlays/plugin-center.js +76 -0
  177. package/dist/tui/overlays/provider-picker.js +145 -0
  178. package/dist/tui/overlays/queue-editor.js +32 -0
  179. package/dist/tui/overlays/research-center.js +59 -0
  180. package/dist/tui/overlays/scroll-window.js +234 -0
  181. package/dist/tui/overlays/session-picker.js +115 -0
  182. package/dist/tui/overlays/tasks-center.js +83 -0
  183. package/dist/tui/overlays/theme-picker.js +21 -0
  184. package/dist/tui/overlays/transcript-search.js +58 -0
  185. package/dist/tui/overlays/trust-center.js +29 -0
  186. package/dist/tui/overlays/workflow-center.js +46 -0
  187. package/dist/tui/project-file-index.js +214 -0
  188. package/dist/tui/project-references.js +85 -0
  189. package/dist/tui/project-trust-prompt.js +287 -0
  190. package/dist/tui/prompt-history-store.js +116 -0
  191. package/dist/tui/queue-store.js +110 -0
  192. package/dist/tui/regions/budget.js +59 -0
  193. package/dist/tui/regions/views.js +96 -0
  194. package/dist/tui/render-coordinator.js +148 -0
  195. package/dist/tui/render-scheduler.js +4 -0
  196. package/dist/tui/run.js +69 -0
  197. package/dist/tui/selection-list.js +29 -0
  198. package/dist/tui/session-controller.js +778 -0
  199. package/dist/tui/session-export.js +54 -0
  200. package/dist/tui/shell-input.js +35 -0
  201. package/dist/tui/shell-layout.js +48 -0
  202. package/dist/tui/shell-model.js +98 -0
  203. package/dist/tui/slash-commands.js +80 -0
  204. package/dist/tui/state.js +151 -0
  205. package/dist/tui/status-bar.js +125 -0
  206. package/dist/tui/status-view.js +40 -0
  207. package/dist/tui/terminal-capabilities.js +9 -0
  208. package/dist/tui/terminal-session.js +11 -0
  209. package/dist/tui/text-width.js +66 -0
  210. package/dist/tui/theme-catalog.js +25 -0
  211. package/dist/tui/theme-store.js +23 -0
  212. package/dist/tui/theme.js +23 -0
  213. package/dist/tui/tool-display.js +135 -0
  214. package/dist/tui/tool-facts.js +1 -0
  215. package/dist/tui/tools/bash-renderer.js +32 -0
  216. package/dist/tui/tools/change.js +61 -0
  217. package/dist/tui/tools/edit-renderer.js +17 -0
  218. package/dist/tui/tools/generic-renderer.js +13 -0
  219. package/dist/tui/tools/list-renderer.js +14 -0
  220. package/dist/tui/tools/read-renderer.js +13 -0
  221. package/dist/tui/tools/registry.js +20 -0
  222. package/dist/tui/tools/row-format.js +187 -0
  223. package/dist/tui/tools/search-renderer.js +38 -0
  224. package/dist/tui/tools/shared.js +97 -0
  225. package/dist/tui/tools/write-renderer.js +15 -0
  226. package/dist/tui/transcript-model.js +441 -0
  227. package/dist/tui/ui-preferences.js +79 -0
  228. package/dist/tui/usage-view.js +77 -0
  229. package/dist/tui/vim-mode.js +99 -0
  230. package/dist/update/check.js +15 -0
  231. package/dist/update/npm.js +51 -0
  232. package/dist/update/run.js +129 -0
  233. package/dist/version.js +2 -0
  234. package/dist/workspace/checkpoint-store.js +210 -0
  235. package/dist/workspace/checkpoint.js +413 -0
  236. package/dist/workspace/restore.js +232 -0
  237. package/package.json +63 -5
  238. package/vendor/context-engine/package.json +11 -0
  239. package/vendor/context-engine/src/compaction-planner.mjs +57 -0
  240. package/vendor/context-engine/src/contracts.mjs +48 -0
  241. package/vendor/context-engine/src/engine.mjs +445 -0
  242. package/vendor/context-engine/src/node/context-export.mjs +164 -0
  243. package/vendor/context-engine/src/node/legacy-import.mjs +92 -0
  244. package/vendor/context-engine/src/node/migrations/001-context.sql +126 -0
  245. package/vendor/context-engine/src/node/sqlite-store.mjs +85 -0
  246. package/vendor/context-engine/src/node/sqlite-worker.mjs +559 -0
  247. package/vendor/context-engine/src/profiles.mjs +10 -0
  248. package/vendor/context-engine/src/retrieval.mjs +104 -0
  249. package/vendor/context-engine/src/summary.mjs +97 -0
  250. package/vendor/context-engine/src/usage.mjs +34 -0
  251. package/vendor/harness-ui/package.json +38 -0
  252. package/vendor/harness-ui/src/acp-agent.mjs +350 -0
  253. package/vendor/harness-ui/src/agent-service.mjs +2188 -0
  254. package/vendor/harness-ui/src/agui-events.mjs +452 -0
  255. package/vendor/harness-ui/src/ambiente-solo-server.mjs +121 -0
  256. package/vendor/harness-ui/src/artifact-store.mjs +39 -0
  257. package/vendor/harness-ui/src/assistenza.mjs +123 -0
  258. package/vendor/harness-ui/src/automation-scheduler.mjs +69 -0
  259. package/vendor/harness-ui/src/automation-store.mjs +145 -0
  260. package/vendor/harness-ui/src/browser-annota.mjs +639 -0
  261. package/vendor/harness-ui/src/browser-frame.mjs +211 -0
  262. package/vendor/harness-ui/src/browser-proxy-universale.mjs +519 -0
  263. package/vendor/harness-ui/src/browser-proxy.mjs +87 -0
  264. package/vendor/harness-ui/src/browser-sessione-viva.mjs +329 -0
  265. package/vendor/harness-ui/src/browser-stream.mjs +445 -0
  266. package/vendor/harness-ui/src/browser-vivo.mjs +694 -0
  267. package/vendor/harness-ui/src/chat-image-attachments.mjs +72 -0
  268. package/vendor/harness-ui/src/config.mjs +697 -0
  269. package/vendor/harness-ui/src/contesto-del-progetto.mjs +385 -0
  270. package/vendor/harness-ui/src/context-asset-adapter.mjs +72 -0
  271. package/vendor/harness-ui/src/context-desktop-service.mjs +253 -0
  272. package/vendor/harness-ui/src/context-embedding-runtime.mjs +252 -0
  273. package/vendor/harness-ui/src/context-inference-scheduler.mjs +81 -0
  274. package/vendor/harness-ui/src/context-native-compaction.mjs +75 -0
  275. package/vendor/harness-ui/src/context-provider-adapter.mjs +141 -0
  276. package/vendor/harness-ui/src/context-runtime.mjs +118 -0
  277. package/vendor/harness-ui/src/context-token-counters.mjs +184 -0
  278. package/vendor/harness-ui/src/context-tool-catalog.mjs +86 -0
  279. package/vendor/harness-ui/src/context-tool-output.mjs +72 -0
  280. package/vendor/harness-ui/src/costo-elenco.mjs +252 -0
  281. package/vendor/harness-ui/src/custom-task.mjs +171 -0
  282. package/vendor/harness-ui/src/doctor.mjs +142 -0
  283. package/vendor/harness-ui/src/document-filename.mjs +97 -0
  284. package/vendor/harness-ui/src/document-generator.mjs +493 -0
  285. package/vendor/harness-ui/src/document-report.mjs +331 -0
  286. package/vendor/harness-ui/src/duckduckgo-search.mjs +155 -0
  287. package/vendor/harness-ui/src/elenco-profondo.mjs +337 -0
  288. package/vendor/harness-ui/src/favicon-proxy.mjs +113 -0
  289. package/vendor/harness-ui/src/forge-contract.mjs +221 -0
  290. package/vendor/harness-ui/src/frequent-dirs.mjs +134 -0
  291. package/vendor/harness-ui/src/generated-image-store.mjs +147 -0
  292. package/vendor/harness-ui/src/generation-idle.mjs +332 -0
  293. package/vendor/harness-ui/src/gguf-header.mjs +207 -0
  294. package/vendor/harness-ui/src/git-service.mjs +626 -0
  295. package/vendor/harness-ui/src/gitignore-elenco.mjs +604 -0
  296. package/vendor/harness-ui/src/harness-receipt-keypair.mjs +207 -0
  297. package/vendor/harness-ui/src/hf-direct-transfer.mjs +170 -0
  298. package/vendor/harness-ui/src/hf-hub-client.mjs +106 -0
  299. package/vendor/harness-ui/src/hf-image-proxy.mjs +105 -0
  300. package/vendor/harness-ui/src/hf-model-transfer.mjs +245 -0
  301. package/vendor/harness-ui/src/hook-registry.mjs +186 -0
  302. package/vendor/harness-ui/src/http-app.mjs +6259 -0
  303. package/vendor/harness-ui/src/http-lifecycle.mjs +132 -0
  304. package/vendor/harness-ui/src/id-archivio.mjs +27 -0
  305. package/vendor/harness-ui/src/image-generator.mjs +143 -0
  306. package/vendor/harness-ui/src/istruzioni-di-progetto.mjs +234 -0
  307. package/vendor/harness-ui/src/kernel/dist/kernelPerIlBanco.js +518 -0
  308. package/vendor/harness-ui/src/kernel/talosHarness.mjs +10437 -0
  309. package/vendor/harness-ui/src/library-policy-store.mjs +175 -0
  310. package/vendor/harness-ui/src/library-store.mjs +652 -0
  311. package/vendor/harness-ui/src/llama-server-supervisor.mjs +629 -0
  312. package/vendor/harness-ui/src/local-model-store.mjs +339 -0
  313. package/vendor/harness-ui/src/local-runtime-contract.mjs +66 -0
  314. package/vendor/harness-ui/src/local-runtime-events.mjs +44 -0
  315. package/vendor/harness-ui/src/local-runtime-llama-server.mjs +244 -0
  316. package/vendor/harness-ui/src/local-runtime-probe.mjs +401 -0
  317. package/vendor/harness-ui/src/machine-capacity.mjs +66 -0
  318. package/vendor/harness-ui/src/mappa-cartelle.mjs +491 -0
  319. package/vendor/harness-ui/src/mcp-client.mjs +98 -0
  320. package/vendor/harness-ui/src/mcp-registry.mjs +157 -0
  321. package/vendor/harness-ui/src/mcp-session.mjs +177 -0
  322. package/vendor/harness-ui/src/memory-store.mjs +227 -0
  323. package/vendor/harness-ui/src/model-catalog-models-dev.mjs +276 -0
  324. package/vendor/harness-ui/src/model-catalog.mjs +129 -0
  325. package/vendor/harness-ui/src/model-destination.mjs +189 -0
  326. package/vendor/harness-ui/src/modifica-ancorata.mjs +177 -0
  327. package/vendor/harness-ui/src/native-provider-adapter.mjs +205 -0
  328. package/vendor/harness-ui/src/notes-store.mjs +250 -0
  329. package/vendor/harness-ui/src/openai-compatible-runtime.mjs +428 -0
  330. package/vendor/harness-ui/src/openrouter-oauth.mjs +339 -0
  331. package/vendor/harness-ui/src/path-policy.mjs +442 -0
  332. package/vendor/harness-ui/src/plugin-registry.mjs +780 -0
  333. package/vendor/harness-ui/src/plugin-session.mjs +180 -0
  334. package/vendor/harness-ui/src/process-policy.mjs +345 -0
  335. package/vendor/harness-ui/src/prompt-enhancer-provider.mjs +94 -0
  336. package/vendor/harness-ui/src/provider-auth-cloud.mjs +95 -0
  337. package/vendor/harness-ui/src/provider-credential-store.mjs +541 -0
  338. package/vendor/harness-ui/src/provider-probe.mjs +582 -0
  339. package/vendor/harness-ui/src/provider-registry.mjs +1633 -0
  340. package/vendor/harness-ui/src/pty-terminal.mjs +312 -0
  341. package/vendor/harness-ui/src/public-problem.mjs +109 -0
  342. package/vendor/harness-ui/src/research/card.mjs +235 -0
  343. package/vendor/harness-ui/src/research/citations.mjs +142 -0
  344. package/vendor/harness-ui/src/research/collector.mjs +275 -0
  345. package/vendor/harness-ui/src/research/deposito-a-pezzi.mjs +139 -0
  346. package/vendor/harness-ui/src/research/dossier.mjs +114 -0
  347. package/vendor/harness-ui/src/research/esportazioni.mjs +560 -0
  348. package/vendor/harness-ui/src/research/fetch-cache.mjs +465 -0
  349. package/vendor/harness-ui/src/research/fidelity.mjs +122 -0
  350. package/vendor/harness-ui/src/research/independence.mjs +159 -0
  351. package/vendor/harness-ui/src/research/ledger.mjs +166 -0
  352. package/vendor/harness-ui/src/research/markdown-server.mjs +565 -0
  353. package/vendor/harness-ui/src/research/narration.mjs +181 -0
  354. package/vendor/harness-ui/src/research/open-cards.mjs +131 -0
  355. package/vendor/harness-ui/src/research/opposing.mjs +305 -0
  356. package/vendor/harness-ui/src/research/outline.mjs +111 -0
  357. package/vendor/harness-ui/src/research/page-budget.mjs +209 -0
  358. package/vendor/harness-ui/src/research/pdf.mjs +291 -0
  359. package/vendor/harness-ui/src/research/plan.mjs +301 -0
  360. package/vendor/harness-ui/src/research/raccolta-viva.mjs +452 -0
  361. package/vendor/harness-ui/src/research/recheck-document.mjs +69 -0
  362. package/vendor/harness-ui/src/research/recheck-history.mjs +192 -0
  363. package/vendor/harness-ui/src/research/recheck.mjs +194 -0
  364. package/vendor/harness-ui/src/research/report.mjs +203 -0
  365. package/vendor/harness-ui/src/research/run.mjs +527 -0
  366. package/vendor/harness-ui/src/research/synthesis.mjs +318 -0
  367. package/vendor/harness-ui/src/research/verification.mjs +572 -0
  368. package/vendor/harness-ui/src/research-orchestrator.mjs +2679 -0
  369. package/vendor/harness-ui/src/research-store.mjs +1133 -0
  370. package/vendor/harness-ui/src/runtime-build-manifest.mjs +26 -0
  371. package/vendor/harness-ui/src/runtime-contract.mjs +59 -0
  372. package/vendor/harness-ui/src/runtime-owner-adapter.mjs +1348 -0
  373. package/vendor/harness-ui/src/runtime-owner-contract.mjs +32 -0
  374. package/vendor/harness-ui/src/scheda-di-lavoro.mjs +249 -0
  375. package/vendor/harness-ui/src/search-source-store.mjs +172 -0
  376. package/vendor/harness-ui/src/session-registry.mjs +6095 -0
  377. package/vendor/harness-ui/src/session-store.mjs +220 -0
  378. package/vendor/harness-ui/src/sessione-pronta.mjs +73 -0
  379. package/vendor/harness-ui/src/setup-stato.mjs +31 -0
  380. package/vendor/harness-ui/src/sezioni-istruzioni.mjs +204 -0
  381. package/vendor/harness-ui/src/skill-registry.mjs +120 -0
  382. package/vendor/harness-ui/src/sse-replay-coalescente.mjs +0 -0
  383. package/vendor/harness-ui/src/static-files.mjs +96 -0
  384. package/vendor/harness-ui/src/stream-partition.mjs +123 -0
  385. package/vendor/harness-ui/src/subagent-orchestrator.mjs +453 -0
  386. package/vendor/harness-ui/src/task-catalog.mjs +65 -0
  387. package/vendor/harness-ui/src/tasks-store.mjs +220 -0
  388. package/vendor/harness-ui/src/terminal-registry.mjs +312 -0
  389. package/vendor/harness-ui/src/terminal-ws.mjs +170 -0
  390. package/vendor/harness-ui/src/tool-forge-store.mjs +299 -0
  391. package/vendor/harness-ui/src/tool-schema-normalize.mjs +100 -0
  392. package/vendor/harness-ui/src/usage-cache.mjs +315 -0
  393. package/vendor/harness-ui/src/workspace-browser.mjs +213 -0
  394. package/vendor/harness-ui/src/workspace-context.mjs +124 -0
  395. package/vendor/harness-ui/src/workspace-disk.mjs +62 -0
  396. package/vendor/harness-ui/src/workspace-files.mjs +589 -0
  397. package/vendor/harness-ui/src/workspace-info.mjs +189 -0
  398. package/vendor/harness-ui/src/workspace-launch-store.mjs +150 -0
  399. package/vendor/harness-ui/src/workspace-tree.mjs +67 -0
  400. package/vendor/harness-ui/src/workspace-watcher.mjs +161 -0
  401. package/vendor/manifest.json +170 -0
@@ -0,0 +1,312 @@
1
+ /**
2
+ * pty-terminal.mjs — Terminale REALE, ledger in
3
+ * `.claude/LEDGER-TERMINALE-REALE.md`. Owner, 28/8: *"deve essere un
4
+ * terminale vero e proprio bash [...] che non ha limiti [...] usabile
5
+ * dall'utente con le sue dita umane"* — non il log a righe dei comandi
6
+ * dell'agente (quello resta, invariato, nel tool-call della chat).
7
+ *
8
+ * Ricerca fatta prima di scrivere: su Windows (dove non esiste
9
+ * un primitivo PTY POSIX nativo), lo stato dell'arte monta Git Bash dentro
10
+ * una PTY vera — la stessa strategia adottata da altri strumenti dello
11
+ * stesso tipo.
12
+ * Verificato empiricamente su QUESTA macchina (non presunto): `node-pty`
13
+ * include il prebuild `win32-x64` DENTRO il pacchetto npm (zero
14
+ * compilazione), Git Bash è installato
15
+ * (`C:\Program Files\Git\bin\bash.exe`, lo stesso binario che questa
16
+ * sessione usa per il proprio tool Bash), e una sonda reale
17
+ * (`pty.spawn` + un comando scritto come keystroke) ha prodotto un
18
+ * prompt MINGW64 vero con sequenze ANSI vere.
19
+ *
20
+ * ⛔ Questo modulo NON impone timeout, non tronca l'output, non ha una
21
+ * allowlist di comandi — a differenza di `eseguiComandoSandboxato`
22
+ * (l'attrezzo `shell` dato in mano a un MODELLO): qui la shell è in
23
+ * mano al proprietario della macchina, "non ha limiti" per richiesta
24
+ * esplicita.
25
+ */
26
+ import { spawn as spawnPty } from 'node-pty';
27
+ import { existsSync } from 'node:fs';
28
+
29
+ import { ambienteSenzaVariabiliDelServer } from './ambiente-solo-server.mjs';
30
+
31
+ /** ⛔ Solo win32: `existsFn` iniettabile per i test, mai una vera ricerca su disco lì. */
32
+ const PERCORSI_GIT_BASH_WINDOWS = [
33
+ 'C:\\Program Files\\Git\\bin\\bash.exe',
34
+ 'C:\\Program Files (x86)\\Git\\bin\\bash.exe',
35
+ ];
36
+
37
+ /**
38
+ * Tetto del backlog **PER SCHEDA** — un replay alla riconnessione, non uno
39
+ * storico infinito.
40
+ *
41
+ * ⛔⛔ W1-01 (05/9): verificato che il tetto è per voce del registro e non
42
+ * globale (`voce.byteBacklog` vive dentro la singola voce), perché con più
43
+ * schede per sessione un tetto globale farebbe sparire il backlog di una
44
+ * scheda quando ne parla un'altra. Il numero è **200.000 byte per scheda**:
45
+ * dichiarato, non infinito. Stessa disciplina di VS Code, che limita lo
46
+ * scrollback ripristinato di una sessione persistente con
47
+ * `terminal.integrated.persistentSessionScrollback` (default **100 righe**,
48
+ * code.visualstudio.com/docs/terminal/advanced, letto il 05/09/2026) invece di
49
+ * rigiocare tutto. ⛔ E il backlog DEVE stare qui: `node-pty` non tiene
50
+ * scrollback proprio — lo scrollback vive in xterm, lato client, e un F5 lo
51
+ * azzera (ricerca 05/09/2026).
52
+ */
53
+ export const BACKLOG_MASSIMO_BYTE = 200_000;
54
+
55
+ /*
56
+ * ⛔ 14/09 (F04 della review, riprodotto): il tetto NON si rispettava con un solo pezzo — il vecchio ciclo si fermava a
57
+ * `backlog.length > 1`, quindi un `cat` di un file grosso lasciava in memoria un elemento da megabyte PER SCHEDA, e
58
+ * il numero dichiarato qui sopra («200.000 byte per scheda, dichiarato, non infinito») era falso proprio nel caso che
59
+ * conta. Adesso l'ultimo pezzo si TAGLIA, e si tiene la CODA: è quella che la scheda deve rivedere al rientro.
60
+ * ⛔ Il taglio è sui byte UTF-8, mai sui caratteri: si entra da destra e si scavalcano i byte di continuazione
61
+ * (`10xxxxxx`), perché una sequenza multi-byte spezzata arriverebbe a xterm come `�` — cioè il backlog
62
+ * consegnerebbe caratteri che la shell non ha mai scritto.
63
+ */
64
+ function limitaBacklog(voce) {
65
+ while (voce.byteBacklog > BACKLOG_MASSIMO_BYTE && voce.backlog.length > 1) {
66
+ voce.byteBacklog -= Buffer.byteLength(voce.backlog.shift(), 'utf8');
67
+ }
68
+ if (voce.byteBacklog <= BACKLOG_MASSIMO_BYTE || voce.backlog.length === 0) return;
69
+ const ultimo = Buffer.from(voce.backlog[0], 'utf8');
70
+ let taglio = ultimo.length - BACKLOG_MASSIMO_BYTE;
71
+ while (taglio < ultimo.length && (ultimo[taglio] & 0xc0) === 0x80) taglio += 1;
72
+ const coda = ultimo.subarray(taglio).toString('utf8');
73
+ voce.backlog[0] = coda;
74
+ voce.byteBacklog = Buffer.byteLength(coda, 'utf8');
75
+ }
76
+
77
+ /** Una PTY disconnessa da più di così viene chiusa dal reaper — pulizia di schede mai più tornate, non un limite sulla shell viva. */
78
+ export const MINUTI_PRIMA_DI_CHIUDERE_PTY_ORFANA = 10;
79
+
80
+ /*
81
+ * ⛔⛔⛔ CLI-REQ-04 (17/09/2026) — L'AMBIENTE DELLA SHELL DELLA PERSONA.
82
+ *
83
+ * Fino a oggi `apri` passava `env: process.env`, cioè l'ambiente INTERO del server. Dentro ci
84
+ * sono il token di loopback a 64 esadecimali che protegge TUTTA la nostra API locale e la chiave
85
+ * privata che firma le ricevute (`desktop/runtime.mjs:47-60`, `src/config.mjs:601` e `:625-627`).
86
+ * Un `npm install` con i suoi script di installazione, o un attrezzo scaricato, lanciato dalla
87
+ * persona in questa scheda poteva leggerli e usarli.
88
+ *
89
+ * ⛔ Ricerca prima di scrivere, 17/09/2026: la documentazione di `node:child_process`
90
+ * (nodejs.org/api/child_process.html) dichiara `env` con default `process.env`, cioè l'eredità
91
+ * INTERA è il comportamento predefinito e va disfatta a mano; lo stato dell'arte sui segreti in
92
+ * Node (nodejs-security.com/blog/do-not-use-secrets-in-environment-variables-and-here-is-how-to
93
+ * -do-it-better) chiama l'eredità automatica una violazione del minimo privilegio.
94
+ *
95
+ * ⛔ L'elenco e la funzione NON vivono più qui: stanno in `ambiente-solo-server.mjs`, perché dal
96
+ * secondo giro il browser di sistema (`browser-vivo.mjs`) ha lo stesso bisogno e due copie
97
+ * divergerebbero al primo segreto nuovo. Lì stanno anche il perché dell'elenco CHIUSO e la
98
+ * misura che mostra che D-10E NON copre già questi nomi.
99
+ *
100
+ * ⛔ L'ELENCO DEI PUNTI CHE AVVIANO PROCESSI CON L'AMBIENTE INTERO — cioè chi altri ha questo
101
+ * stesso difetto, quanto è coperto e quanto no — sta in
102
+ * `.claude/ELENCO-SPAWN-AMBIENTE-2026-09-17.md`, misurato il 17/09/2026. Chi tocca questa riga
103
+ * lo rilegga: una cura su una sola strada non chiude la classe.
104
+ */
105
+ export { VARIABILI_DEL_SERVER_DICHIARATE_INNOCUE, VARIABILI_SOLO_DEL_SERVER } from './ambiente-solo-server.mjs';
106
+
107
+ /** Il nome con cui questo modulo ha sempre esposto la funzione: una sola implementazione, due nomi. */
108
+ export const ambienteDelTerminale = ambienteSenzaVariabiliDelServer;
109
+
110
+ /**
111
+ * Sceglie la shell reale da lanciare. Su Windows: Git Bash se esiste
112
+ * — altrimenti `cmd.exe`, ma
113
+ * DICHIARATO (`enforcement:'cmd-fallback'`), mai un fallback silenzioso
114
+ * spacciato per bash (stesso principio "onestà sull'enforcement" già
115
+ * in uso per l'attrezzo `shell` dell'agente). Su POSIX: `$SHELL` o
116
+ * `/bin/bash`.
117
+ */
118
+ export function sceltaShell(deps = {}) {
119
+ const platform = deps.platform ?? process.platform;
120
+ const existsFn = deps.existsFn ?? existsSync;
121
+ const env = deps.env ?? process.env;
122
+ if (platform === 'win32') {
123
+ const percorsi = deps.percorsiGitBash ?? PERCORSI_GIT_BASH_WINDOWS;
124
+ const gitBash = percorsi.find((percorso) => existsFn(percorso));
125
+ if (gitBash) return { comando: gitBash, argomenti: ['--login', '-i'], enforcement: 'git-bash' };
126
+ return { comando: 'cmd.exe', argomenti: [], enforcement: 'cmd-fallback' };
127
+ }
128
+ return { comando: env.SHELL || '/bin/bash', argomenti: ['-l'], enforcement: 'posix-shell' };
129
+ }
130
+
131
+ /**
132
+ * Codifica/decodifica del framing binario sulla WebSocket — un byte di
133
+ * comando in testa, mai lo stream incapsulato in JSON (corromperebbe le
134
+ * sequenze ANSI/di controllo — guardia raccolta in ricerca:
135
+ * xtermjs.org/docs/guides/flowcontrol). `0` = dati grezzi (tastiera
136
+ * umana → PTY, o PTY → schermo). `1` = controllo JSON (resize, o
137
+ * l'evento di uscita della shell).
138
+ */
139
+ export const TIPO_FRAME_DATI = 0;
140
+ export const TIPO_FRAME_CONTROLLO = 1;
141
+
142
+ export function codificaFrame(tipo, payload) {
143
+ const corpo = typeof payload === 'string' ? Buffer.from(payload, 'utf8') : payload;
144
+ return Buffer.concat([Buffer.from([tipo]), corpo]);
145
+ }
146
+
147
+ /** AL CONTRARIO — un frame vuoto o con un tipo ignoto torna `null`, mai un crash. */
148
+ export function decodificaFrame(dati) {
149
+ const buf = Buffer.isBuffer(dati) ? dati : Buffer.from(dati);
150
+ if (buf.length === 0) return null;
151
+ const tipo = buf[0];
152
+ if (tipo !== TIPO_FRAME_DATI && tipo !== TIPO_FRAME_CONTROLLO) return null;
153
+ return { tipo, payload: buf.subarray(1) };
154
+ }
155
+
156
+ /**
157
+ * Registro delle PTY vive, per id. Una riconnessione sullo STESSO id
158
+ * riaggancia la PTY viva invece di aprirne una seconda (un F5 non perde la
159
+ * shell) — stesso principio del `Last-Event-ID` già in uso per SSE, qui
160
+ * applicato a una PTY invece che a un run dell'agente.
161
+ *
162
+ * ⛔⛔ W1-01 (05/9) — l'id NON è più il `sessionId`: è il **`terminalId`**, e
163
+ * una sessione può averne più d'uno. Chi decide quali id esistono, a quale
164
+ * sessione appartengono e in quale cartella si aprono è
165
+ * `terminal-registry.mjs`; questo file non autorizza niente, tiene solo in
166
+ * vita le PTY. ⇒ Ogni id ha la sua voce, quindi la sua PTY, il suo backlog e
167
+ * i suoi ascoltatori: due schede della stessa sessione **non condividono
168
+ * I/O**, ed è il criterio della riga (provato in `pty-terminal.test.mjs`).
169
+ */
170
+ export function creaRegistroTerminali(deps = {}) {
171
+ const spawnPtyFn = deps.spawnPtyFn ?? spawnPty;
172
+ const sceltaShellFn = deps.sceltaShellFn ?? sceltaShell;
173
+ const ambienteFn = deps.ambienteFn ?? ambienteDelTerminale; // ⛔ CLI-REQ-04: iniettabile per i test.
174
+ const clock = deps.clock ?? (() => Date.now());
175
+ /** @type {Map<string, any>} */
176
+ const terminali = new Map();
177
+
178
+ function apri({ id, cartella, cols = 80, rows = 24 }) {
179
+ const esistente = terminali.get(id);
180
+ if (esistente && !esistente.chiusa) {
181
+ esistente.ultimaDisconnessioneMs = null;
182
+ return esistente;
183
+ }
184
+ const scelta = sceltaShellFn();
185
+ const handle = spawnPtyFn(scelta.comando, scelta.argomenti, {
186
+ name: 'xterm-256color',
187
+ cols,
188
+ rows,
189
+ cwd: cartella,
190
+ env: ambienteFn(), // ⛔ CLI-REQ-04 (17/09/2026): mai `process.env` intero — vedi VARIABILI_SOLO_DEL_SERVER.
191
+ });
192
+ const voce = {
193
+ id,
194
+ handle,
195
+ enforcement: scelta.enforcement,
196
+ comando: scelta.comando, // 06/9 B1: il nome della shell arriva alla scheda
197
+ backlog: [],
198
+ byteBacklog: 0,
199
+ ultimaDisconnessioneMs: null,
200
+ chiusa: false,
201
+ ascoltatori: new Set(),
202
+ };
203
+ handle.onData((dati) => {
204
+ voce.backlog.push(dati);
205
+ voce.byteBacklog += Buffer.byteLength(dati, 'utf8');
206
+ limitaBacklog(voce);
207
+ for (const ascolta of voce.ascoltatori) ascolta({ tipo: 'dati', dati });
208
+ });
209
+ handle.onExit(({ exitCode, signal }) => {
210
+ voce.chiusa = true;
211
+ for (const ascolta of voce.ascoltatori) ascolta({ tipo: 'uscita', exitCode, signal });
212
+ });
213
+ terminali.set(id, voce);
214
+ return voce;
215
+ }
216
+
217
+ function scrivi(id, dati) {
218
+ terminali.get(id)?.handle.write(dati);
219
+ }
220
+
221
+ function ridimensiona(id, cols, rows) {
222
+ const voce = terminali.get(id);
223
+ if (voce && !voce.chiusa && cols > 0 && rows > 0) voce.handle.resize(cols, rows);
224
+ }
225
+
226
+ /*
227
+ * ⛔ 14/09 (F05 della review, riprodotto): una scheda che si stacca NON rende orfana una PTY che un'ALTRA finestra sta
228
+ * ancora guardando. Prima il timbro si metteva comunque, e dieci minuti dopo il reaper uccideva un terminale vivo
229
+ * sotto gli occhi di chi lo stava usando — difetto che il lavoro a due finestre di oggi rende tutt'altro che teorico.
230
+ * Il timbro lo mette solo l'ULTIMO che se ne va; se resta qualcuno, si azzera.
231
+ */
232
+ function segnaDisconnesso(id) {
233
+ const voce = terminali.get(id);
234
+ if (voce) voce.ultimaDisconnessioneMs = voce.ascoltatori.size === 0 ? clock() : null;
235
+ }
236
+
237
+ /** Chiusura esplicita (mai implicita): l'owner chiude la scheda del terminale dalla UI. */
238
+ function chiudiForzato(id) {
239
+ const voce = terminali.get(id);
240
+ if (!voce) return;
241
+ try { voce.handle.kill(); } catch { /* già morta, nulla da fare */ }
242
+ terminali.delete(id);
243
+ }
244
+
245
+ /**
246
+ * Chiude solo le PTY orfane da più di `MINUTI_PRIMA_DI_CHIUDERE_PTY_ORFANA`
247
+ * — mai quelle ancora attaccate a un client (`ultimaDisconnessioneMs`
248
+ * nullo finché una WS resta aperta), mai per un tetto di tempo sulla
249
+ * shell VIVA.
250
+ */
251
+ function reap() {
252
+ const ora = clock();
253
+ for (const [id, voce] of terminali) {
254
+ // ⛔ 14/09 (F05): «orfana» vuol dire che NESSUNO la guarda — il timbro da solo non basta, perché un'altra finestra
255
+ // può essersi riagganciata nel frattempo. Due condizioni, non una.
256
+ const orfanaScaduta = voce.ascoltatori.size === 0
257
+ && voce.ultimaDisconnessioneMs !== null
258
+ && ora - voce.ultimaDisconnessioneMs > MINUTI_PRIMA_DI_CHIUDERE_PTY_ORFANA * 60_000;
259
+ if (voce.chiusa || orfanaScaduta) {
260
+ try { voce.handle.kill(); } catch { /* già morta */ }
261
+ terminali.delete(id);
262
+ }
263
+ }
264
+ }
265
+
266
+ /**
267
+ * ⭐ W1-01 (05/9) — lo stato di UNA PTY, senza esporre la voce mutabile del
268
+ * registro fuori da qui (stesso principio di `cartellaDi` in
269
+ * `session-registry.mjs`). Serve all'elenco delle schede per dire «shell
270
+ * viva» / «shell già uscita»: `null` significa «nessuna PTY per questo id»,
271
+ * che è un terzo fatto e non si confonde con `{viva:false}`.
272
+ */
273
+ function stato(id) {
274
+ const voce = terminali.get(id);
275
+ if (!voce) return null;
276
+ return { viva: !voce.chiusa, enforcement: voce.enforcement, byteBacklog: voce.byteBacklog };
277
+ }
278
+
279
+ /**
280
+ * ⭐⭐⭐ Come `apri`, ma DICE se ha ripreso una PTY viva o ne ha aperta una
281
+ * nuova.
282
+ *
283
+ * ⛔ Serve perché da fuori le due cose sono indistinguibili: il ponte
284
+ * rigioca il backlog in entrambi i casi, e una PTY appena creata ha backlog
285
+ * vuoto — che è anche l'aspetto di una shell viva che non ha ancora
286
+ * stampato niente. Dedurlo dall'assenza di backlog è un indovinello, non una
287
+ * misura, e l'interfaccia finiva per dire «riconnesso» senza poter sapere se
288
+ * la shell della persona fosse sopravvissuta. Lo stato dell'arte separa
289
+ * l'identità della CONNESSIONE da quella della SESSIONE e fa dichiarare al
290
+ * server se ha davvero ripreso (un pattern noto come "connection state
291
+ * recovery", ricerca del 05/09/2026: websocket.org/guides/reconnection/).
292
+ *
293
+ * ⛔ La risposta viene dallo STESSO controllo che fa `apri` («la voce esiste
294
+ * e non è chiusa»), letto un attimo prima: non è una seconda verità che può
295
+ * divergere dalla prima. Fra la lettura e la chiamata non c'è `await`.
296
+ *
297
+ * @returns {{voce:object, ripresa:boolean}} `ripresa:false` significa shell
298
+ * NUOVA — la prima volta in assoluto, oppure dopo che il reaper ha chiuso
299
+ * quella di prima.
300
+ */
301
+ function apriDichiarando({ id, cartella, cols, rows }) {
302
+ const esistente = terminali.get(id);
303
+ const ripresa = Boolean(esistente && !esistente.chiusa);
304
+ return { voce: apri({ id, cartella, cols, rows }), ripresa };
305
+ }
306
+
307
+ return {
308
+ apri, apriDichiarando, scrivi, ridimensiona, segnaDisconnesso, chiudiForzato, reap, stato,
309
+ /** ⛔ Solo per i test — mai usato dal codice di produzione. */
310
+ _terminali: terminali,
311
+ };
312
+ }
@@ -0,0 +1,109 @@
1
+ import { createHash } from 'node:crypto';
2
+
3
+ const diagnostics = new Map();
4
+ const MESSAGES = Object.freeze({
5
+ CONFIG_INVALID: { title: 'Configurazione non pronta', explanation: 'Manca una parte della configurazione necessaria per completare questa operazione.', action: 'Apri Doctor e segui i controlli indicati, poi riprova.' },
6
+ TASK_CATALOG_UNAVAILABLE: { title: 'Elenco attività non disponibile', explanation: 'Il servizio che fornisce le attività non è ancora collegato.', action: 'Controlla Doctor o configura il servizio delle attività, poi riprova.' },
7
+ RUNTIME_NOT_AVAILABLE: { title: 'Servizio locale non disponibile', explanation: 'Non è stato possibile trovare un servizio locale pronto.', action: 'Apri Doctor per vedere cosa manca oppure scegli un servizio online.' },
8
+ RUNTIME_UNREACHABLE: { title: 'Servizio locale non raggiungibile', explanation: 'Il servizio locale non ha risposto.', action: 'Controlla che sia avviato in Doctor e riprova.' },
9
+ PATH_NOT_ALLOWED: { title: 'Percorso non consentito', explanation: 'Il percorso scelto è fuori dall’area autorizzata.', action: 'Scegli una cartella dentro il progetto aperto.' },
10
+ PROCESS_POLICY_REJECTED: { title: 'Operazione bloccata per sicurezza', explanation: 'Il comando richiesto non rientra nelle autorizzazioni correnti.', action: 'Controlla il permesso della sessione e riprova solo se riconosci il comando.' },
11
+ /*
12
+ * ⛔ 07/9, O-49 — senza una voce qui la busta portava la copia di INTERNAL_ERROR:
13
+ * «Si è verificato un problema imprevisto» e «Apri Doctor». Falso due volte: non è
14
+ * imprevisto, ed è l’unica cosa che Doctor non può spiegare. La scheda del permesso
15
+ * è semplicemente vecchia — si ricarica la sessione e si guarda cosa chiede adesso.
16
+ */
17
+ APPROVAL_NOT_PENDING: { title: 'Richiesta di permesso scaduta', explanation: 'La sessione è andata avanti: quella domanda non aspetta più una risposta.', action: 'Ricarica la sessione e rispondi alla richiesta che vedi adesso, se ce n’è una.' },
18
+ /*
19
+ * ⛔⛔ 07/9, owner bloccato: «la sessione e ancora bloccata, non riesco a inviare messaggi e
20
+ * spunta errore toast». `SESSION_NOT_READY` NON era in questa mappa, quindi cadeva su
21
+ * INTERNAL_ERROR e a schermo arrivava «Si e verificato un problema imprevisto» — mentre il
22
+ * registro aveva gia scritto la frase giusta e AZIONABILE: «Questa sessione e stata interrotta
23
+ * da un riavvio del server e non puo essere ripresa: avvia una sessione nuova».
24
+ * ⇒ Il codice piu utile della mappa e quello che dice COSA FARE. Qui la spiegazione generica
25
+ * resta come rete, ma il motivo VERO del registro passa in `explanation` (vedi `problemFor`):
26
+ * una porta chiusa senza indicazione di dove sia quella aperta e il modo migliore per bloccare
27
+ * una persona su una schermata.
28
+ */
29
+ SESSION_NOT_READY: { title: 'Sessione non pronta', explanation: 'Questa sessione non puo accettare l’azione richiesta nello stato in cui si trova.', action: 'Se e stata interrotta da un riavvio, avvia una sessione nuova: la conversazione resta leggibile qui.' },
30
+ /*
31
+ * ⛔⛔ 12/09, L5 — LA STESSA VORAGINE DI O-49, e per questo sono qui il giorno stesso in cui
32
+ * nascono i codici. Senza una voce in questa mappa una risposta cade sulla copia di
33
+ * INTERNAL_ERROR, e a schermo una ricerca cancellata dieci secondi fa diventa «Si è verificato
34
+ * un problema imprevisto · Apri Doctor, copia il riferimento»: falso due volte — non è
35
+ * imprevisto, ed è l'unica cosa che Doctor non può spiegare. Misurato interrogando la rotta
36
+ * vera prima di scrivere queste righe, non dedotto.
37
+ * ⛔ Nessuna di queste è un guasto: sono tre no diversi, e ognuna dice COSA FARE.
38
+ */
39
+ RESEARCH_NOT_FOUND: { title: 'Ricerca non trovata', explanation: 'Questa ricerca approfondita non è più nel progetto: può essere stata eliminata.', action: 'Torna all’elenco delle ricerche: mostra quelle che ci sono adesso.' },
40
+ RESEARCH_CONFLICT: { title: 'Azione non possibile adesso', explanation: 'Questa ricerca non è nello stato che l’azione richiede — per esempio è già ferma, o è già finita.', action: 'Riapri la scheda della ricerca: dice come sta in questo momento.' },
41
+ RESEARCH_RECHECK_UNAVAILABLE: { title: 'Controllo delle fonti non possibile', explanation: 'Per ricontrollare le fonti serve un rapporto con i passaggi citati, e questa ricerca non ne ha.', action: 'Le ricerche nuove lo portano: questa si può rifare, oppure lasciarla com’è.' },
42
+ RESEARCH_INVALID: { title: 'Richiesta non valida', explanation: 'L’identificativo della ricerca non ha una forma ammessa.', action: 'Apri la ricerca dall’elenco invece di comporre l’indirizzo a mano.' },
43
+ INTERNAL_ERROR: { title: 'Operazione non riuscita', explanation: 'Si è verificato un problema imprevisto durante l’operazione.', action: 'Apri Doctor, copia il riferimento e riprova.' },
44
+ });
45
+
46
+ function safeCode(error) {
47
+ return typeof error?.code === 'string' && /^[A-Z0-9_]+$/u.test(error.code) ? error.code : 'INTERNAL_ERROR';
48
+ }
49
+
50
+ function referenceFor(code, requestId, operation) {
51
+ return `doctor-${createHash('sha256').update(`${code}|${requestId || ''}|${operation || ''}`).digest('hex').slice(0, 12)}`;
52
+ }
53
+
54
+ function safeDiagnosticDetail(error) {
55
+ if (typeof error?.message !== 'string') return '';
56
+ return error.message
57
+ .replace(/\b(?:sk|pk)-[A-Za-z0-9_-]+\b/giu, '[redacted]')
58
+ .replace(/\bsecret\b/giu, '[redacted]')
59
+ .replace(/\bTALOS_[A-Z0-9_]+\b/gu, '[setting]')
60
+ .replace(/\b[A-Za-z]:\\[^\r\n;]+/gu, '[path]')
61
+ .replace(/\/(?:Users|home|tmp|var|data)\/[^\r\n; ]+/giu, '[path]')
62
+ .replace(/\s+/gu, ' ')
63
+ .trim()
64
+ .slice(0, 240);
65
+ }
66
+
67
+ /*
68
+ * ⛔⛔ 07/9 — I codici il cui `message` e GIA scritto per una persona, e non per un log.
69
+ * Il registro, per una sessione che non puo ripartire, dice: «Questa sessione e stata interrotta da
70
+ * un riavvio del server e non puo essere ripresa: avvia una sessione nuova» — una frase che dice
71
+ * cosa e successo E cosa fare. Quella frase veniva BUTTATA e sostituita con «Si e verificato un
72
+ * problema imprevisto», e l'owner e rimasto bloccato su una schermata senza sapere dove fosse
73
+ * l'uscita.
74
+ * ⛔ La sostituzione generica esiste per una ragione buona — un messaggio d'errore grezzo puo
75
+ * portare percorsi, id, dettagli interni — e resta il comportamento predefinito. Qui si dichiara
76
+ * la sola eccezione: i codici dove chi ha scritto il messaggio lo ha scritto PER lo schermo.
77
+ * Aggiungerne uno vuol dire prendersi la responsabilita che quel testo sia leggibile e privo di
78
+ * dettagli interni: si guarda ogni `erroreAvvio` di quel codice prima di metterlo qui.
79
+ */
80
+ const MESSAGGIO_GIA_PER_LA_PERSONA = new Set(['SESSION_NOT_READY']);
81
+
82
+ /** Un testo del registro e pubblicabile solo se e corto e non porta percorsi o identificatori. */
83
+ function messaggioPubblicabile(testo) {
84
+ const t = String(testo || '').trim();
85
+ if (t.length < 12 || t.length > 240) return '';
86
+ if (/[\/]{1}[\w.-]+[\/]|[0-9a-f]{8}-[0-9a-f]{4}/i.test(t)) return ''; // percorsi o id: restano nel log
87
+ return t;
88
+ }
89
+
90
+ export function toPublicProblem(error, { requestId = '', operation = '' } = {}) {
91
+ const code = safeCode(error);
92
+ const copy = MESSAGES[code] ?? MESSAGES.INTERNAL_ERROR;
93
+ const doctorReference = referenceFor(code, requestId, operation);
94
+ diagnostics.set(doctorReference, Object.freeze({ code, operation: String(operation || 'operation'), requestId: String(requestId || ''), detail: safeDiagnosticDetail(error) }));
95
+ const vero = MESSAGGIO_GIA_PER_LA_PERSONA.has(code) ? messaggioPubblicabile(error?.message) : '';
96
+ return { title: copy.title, explanation: vero || copy.explanation, action: copy.action, doctorReference };
97
+ }
98
+
99
+ export function logDiagnosticProblem(error, { requestId = '', operation = '', logger = console } = {}) {
100
+ const publicProblem = toPublicProblem(error, { requestId, operation });
101
+ const code = safeCode(error);
102
+ try { logger?.warn?.(`[${publicProblem.doctorReference}] ${operation || 'operation'} (${code})`); } catch { /* un logger guasto non cambia l’esito dell’operazione */ }
103
+ return publicProblem.doctorReference;
104
+ }
105
+
106
+ export function getDiagnosticProblem(reference) {
107
+ const detail = diagnostics.get(reference);
108
+ return detail ? { ...detail } : null;
109
+ }
@@ -0,0 +1,235 @@
1
+ import { talosResearchIsResting, talosResearchIsTerminal, talosResearchProgressOf } from './run.mjs'
2
+
3
+ /*
4
+ * PORTO FEDELE di AVM/mobile/src/lib/research/researchCard.ts (211 righe, 11/09/2026).
5
+ *
6
+ * ⛔ `run.mjs` è il porto di `researchRun.ts` e lo cura un'altra sessione, in
7
+ * parallelo: qui se ne importa solo il nome concordato.
8
+ *
9
+ * Che aspetto ha una ricerca da fuori, prima di aprirla.
10
+ *
11
+ * La stazione era un modulo con sotto un elenco di righe espandibili, e le
12
+ * righe dicevano `3/3 · done`. Quella è la vista della macchina. Questa è
13
+ * quella del lettore: che cosa ho chiesto, quando, com'è finita e — quando è
14
+ * finita — **quanto regge**.
15
+ *
16
+ * L'ultima parte è tutto l'argomento. La ricerca sui concorrenti (2026-08-03)
17
+ * ha trovato che tutti e cinque i prodotti guidano col volume — «56 siti»,
18
+ * «hundreds of sources» — e nessuno dice se le affermazioni hanno retto. La sua
19
+ * conclusione è che la vittoria non sono più citazioni, è un resoconto migliore
20
+ * della relazione fra affermazione e prova. Quindi una scheda qui guida col
21
+ * bilancio e mai col conteggio delle fonti.
22
+ *
23
+ * Pura apposta: una scheda è un riassunto, e un riassunto che ha bisogno di un
24
+ * database è un riassunto che non si può provare.
25
+ */
26
+
27
+ /**
28
+ * @import { TalosResearchRun, TalosResearchStatus } from './run.mjs'
29
+ */
30
+
31
+ /**
32
+ * I secchi che il filtro offre. Una corsa sta in esattamente uno.
33
+ * @typedef {'running' | 'paused' | 'unfinished' | 'cancelled' | 'done' | 'failed'} TalosResearchBucket
34
+ */
35
+
36
+ /**
37
+ * @typedef {object} TalosResearchStanding
38
+ * @property {number} total
39
+ * @property {number} supported
40
+ * @property {number} partial
41
+ * @property {number} unsupported
42
+ * @property {number} unchecked
43
+ * @property {number} [contested] ⛔ CONTESA-01 — le affermazioni su cui le fonti
44
+ * non concordano. Opzionale, e non per pigrizia: i rapporti scritti prima del
45
+ * 2026-08-20 non hanno questo conto, e leggerlo come zero su un rapporto
46
+ * vecchio direbbe «nessun disaccordo» dove la verità è «non guardato». Chi lo
47
+ * mostra usa `?? 0` sapendo cosa sta facendo.
48
+ */
49
+
50
+ /**
51
+ * @typedef {object} TalosResearchCard
52
+ * @property {string} id
53
+ * @property {string} question Quello che l'elenco MOSTRA: l'etichetta scelta, o la domanda quando non ce n'è.
54
+ * @property {string} originalQuestion La domanda come è stata posta, tenuta accanto all'etichetta perché la provenienza sopravviva a una rinomina.
55
+ * @property {boolean} renamed Vero quando qualcuno ha dato un nome suo a questa ricerca.
56
+ * @property {string} startedAt
57
+ * @property {string} updatedAt
58
+ * @property {TalosResearchBucket} bucket
59
+ * @property {TalosResearchStatus} status La parola del giornale, che il secchio apposta sfuma.
60
+ * @property {number} done
61
+ * @property {number} total
62
+ * @property {number} failedSteps Rami falliti, così una scheda può ammettere un risultato parziale invece di nasconderlo.
63
+ * @property {TalosResearchStanding | null} standing Presente solo una volta letto il rapporto; l'elenco non lo aspetta.
64
+ */
65
+
66
+ /**
67
+ * In quale secchio sta una corsa.
68
+ *
69
+ * `running` lo decide il registro VIVO, non il giornale: una corsa che il
70
+ * giornale chiama incompiuta può essere in volo proprio adesso, e chiamarla
71
+ * interrotta mentre lavora è esattamente la bugia che questo rifacimento è
72
+ * nato per togliere. Il giornale risponde a «che cosa è stato scritto», mai a
73
+ * «che cosa sta succedendo».
74
+ *
75
+ * @param {TalosResearchRun} run
76
+ * @param {boolean} isRunning
77
+ * @returns {TalosResearchBucket}
78
+ */
79
+ export function talosResearchBucketOf(run, isRunning) {
80
+ if (isRunning) return 'running'
81
+ if (run.status === 'failed') return 'failed'
82
+ if (run.status === 'done') return 'done'
83
+ // Annullata è una DECISIONE, come la pausa, e per la stessa ragione non sta
84
+ // con le corse che il telefono ha ucciso. Peggio che disordinato: quelle
85
+ // sono archiviate come «interrotte», il che promette che si possano
86
+ // riprendere — e una ricerca annullata è l'unica cosa qui che non riparte mai.
87
+ if (run.status === 'cancelled') return 'cancelled'
88
+ // In pausa ha un secchio SUO, ed è il punto stesso della pausa: la persona
89
+ // ha fermato apposta e conta di tornarci. Archiviarla accanto alle corse che
90
+ // il telefono ha ucciso le direbbe che la sua decisione è stata un incidente.
91
+ // `pause_requested` sta qui anche lui — è una pausa che non ha finito di
92
+ // atterrare, non una situazione diversa per chi legge.
93
+ if (talosResearchIsResting(run.status)) return 'paused'
94
+ // Tutto il resto — planning, collecting, synthesising, verifying — è lavoro
95
+ // che si è fermato senza finire. Un secchio solo, perché dal lato del
96
+ // lettore sono la stessa situazione: deve qualcosa e non sta succedendo niente.
97
+ return 'unfinished'
98
+ }
99
+
100
+ /**
101
+ * @param {TalosResearchRun} run
102
+ * @param {{ isRunning: boolean, standing?: TalosResearchStanding | null }} options
103
+ * @returns {TalosResearchCard}
104
+ */
105
+ export function talosResearchCardOf(run, options) {
106
+ const progress = talosResearchProgressOf(run)
107
+ return {
108
+ id: run.id,
109
+ question: run.title ?? run.question,
110
+ originalQuestion: run.question,
111
+ renamed: run.title !== null,
112
+ startedAt: run.startedAt,
113
+ updatedAt: run.updatedAt,
114
+ bucket: talosResearchBucketOf(run, options.isRunning),
115
+ status: run.status,
116
+ done: progress.done,
117
+ total: progress.total,
118
+ failedSteps: run.steps.filter((step) => step.state === 'failed').length,
119
+ standing: options.standing ?? null,
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Quanto regge un rapporto finito, come un numero solo fra 0 e 1.
125
+ *
126
+ * Il sostegno parziale conta metà. Non è una furbizia: un'affermazione che la
127
+ * fonte sostiene in parte sta davvero in mezzo, e arrotondarla a «sostenuta» è
128
+ * il modo in cui un rapporto finisce per sembrare più solido di quanto sia —
129
+ * che è il guasto che tutta la verifica esiste per impedire. Il non verificato
130
+ * conta zero per la stessa ragione: «non siamo riusciti a controllare» non è
131
+ * una promozione.
132
+ *
133
+ * ⛔ Una CONTESA vale zero, come una smentita, e la ragione è la stessa che
134
+ * regge tutta questa funzione: se le fonti si contraddicono, quell'affermazione
135
+ * non è una prova. Contarla anche solo per metà rifarebbe esattamente il
136
+ * difetto che la verifica esiste per impedire — un rapporto che sembra più
137
+ * solido di quanto sia.
138
+ *
139
+ * @param {TalosResearchStanding | null} standing
140
+ * @returns {number | null}
141
+ */
142
+ export function talosResearchSolidity(standing) {
143
+ if (!standing || standing.total === 0) return null
144
+ return (standing.supported + (standing.partial * 0.5)) / standing.total
145
+ }
146
+
147
+ /**
148
+ * Se un rapporto finito merita un secondo sguardo.
149
+ *
150
+ * Qualsiasi cosa non sostenuta, o una solidità sotto due terzi. La soglia è un
151
+ * giudizio, ed è scritta qui invece che sparsa in un modello di pagina, così la
152
+ * si può contestare in un posto solo.
153
+ *
154
+ * @param {TalosResearchCard} card
155
+ * @returns {boolean}
156
+ */
157
+ export function talosResearchNeedsAttention(card) {
158
+ if (card.failedSteps > 0) return true
159
+ if (!card.standing) return false
160
+ if (card.standing.unsupported > 0) return true
161
+ // ⛔ Anche UNA contesa merita un secondo sguardo: vuol dire che su quel
162
+ // punto il mondo non concorda, ed è precisamente il caso in cui una
163
+ // persona vuole leggere le fonti invece di fidarsi del riassunto.
164
+ if ((card.standing.contested ?? 0) > 0) return true
165
+ const solidity = talosResearchSolidity(card.standing)
166
+ return solidity !== null && solidity < 2 / 3
167
+ }
168
+
169
+ /**
170
+ * Il file del rapporto che la sintesi ha scritto, quando ce n'è uno da leggere.
171
+ *
172
+ * Vive qui invece che in ogni schermata: l'elenco, la pagina del rapporto, la
173
+ * pagina dell'affermazione e quella della fonte ne hanno tutte bisogno, e
174
+ * quattro copie dello stesso `find` è il modo in cui cominciano a non essere
175
+ * più d'accordo su che cosa conti come finito.
176
+ *
177
+ * @param {TalosResearchRun} run
178
+ * @returns {string | null}
179
+ */
180
+ export function talosResearchReportRefOf(run) {
181
+ const synthesis = run.steps.find((step) => step.kind === 'synthesise' && step.state === 'done')
182
+ return synthesis?.resultRef ?? null
183
+ }
184
+
185
+ /**
186
+ * Il filtro, applicato. `all` è un secchio che la UI offre e che i dati non hanno mai.
187
+ *
188
+ * @param {readonly TalosResearchCard[]} cards
189
+ * @param {TalosResearchBucket | 'all'} bucket
190
+ * @param {string} query
191
+ * @returns {readonly TalosResearchCard[]}
192
+ */
193
+ export function talosResearchFilterCards(cards, bucket, query) {
194
+ const needle = query.trim().toLowerCase()
195
+ return cards.filter((card) => {
196
+ if (bucket !== 'all' && card.bucket !== bucket) return false
197
+ if (needle.length === 0) return true
198
+ return card.question.toLowerCase().includes(needle)
199
+ })
200
+ }
201
+
202
+ /**
203
+ * Che cosa si può fare a questa ricerca, adesso.
204
+ *
205
+ * Un elenco invece di un insieme di voci disabilitate: quali azioni esistono è
206
+ * un fatto sulla cosa, e un menu di opzioni morte fa lavorare il lettore per
207
+ * capire perché siano morte. Una ricerca viva offre Pausa e Annulla; una in
208
+ * pausa offre Riprendi; una annullata nessuna delle due, perché il motore si
209
+ * rifiuta di guidare una corsa finita e far finta di sì sarebbe un pulsante che
210
+ * mente.
211
+ *
212
+ * Elimina manca mentre gira, e non è schizzinosità: togliere il giornale da
213
+ * sotto all'unico scrittore distruggerebbe l'unica prova che un passo già
214
+ * mandato a un fornitore era stato pagato. Prima si ferma.
215
+ *
216
+ * @typedef {'open' | 'rename' | 'pause' | 'resume' | 'cancel' | 'delete'} TalosResearchAction
217
+ */
218
+
219
+ /**
220
+ * @param {TalosResearchCard} card
221
+ * @returns {readonly TalosResearchAction[]}
222
+ */
223
+ export function talosResearchActionsFor(card) {
224
+ /** @type {TalosResearchAction[]} */
225
+ const actions = ['open', 'rename']
226
+ if (card.bucket === 'running') {
227
+ actions.push('pause', 'cancel')
228
+ // Niente elimina: vedi sopra.
229
+ return actions
230
+ }
231
+ // In riposo o solo interrotta — entrambe devono ancora lavoro ed entrambe riprendono.
232
+ if (!talosResearchIsTerminal(card.status)) actions.push('resume', 'cancel')
233
+ actions.push('delete')
234
+ return actions
235
+ }