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,177 @@
1
+ /*
2
+ * ⛔⛔⛔ PO-12 — L'ATTREZZO DI MODIFICA. Owner, 09/09/2026: «oltre alle modifiche file da terminale,
3
+ * dare al modello un tool di edit esattamente come Claude Code da CLI, e praticamente come fanno
4
+ * tutti gli altri». Approvato il 10/09 al posto della via A di D3, per la ragione scritta più sotto.
5
+ *
6
+ * IL PROBLEMA, misurato nel nostro kernel: l'unico attrezzo di scrittura è `scrivi`, che si dichiara
7
+ * al modello così, verbatim: «Writes one file of the workspace, **replacing it entirely**. Read it
8
+ * first: the whole content is required.» Quindi per cambiare una riga in un file di 2.000 il modello
9
+ * ne rigenera 2.000, in uscita, dove i token costano di più; e il resto del file passa dalla sua
10
+ * memoria invece che dal disco.
11
+ * ⛔ E c'è la seconda metà, che è la ragione per cui questo pezzo viene PRIMA della prenotazione dei
12
+ * file (D3-A): con una riscrittura totale, due sotto-agenti che toccano lo stesso file si
13
+ * cancellano a vicenda PER COSTRUZIONE. Con una modifica ancorata al testo, la seconda fallisce da
14
+ * sola — nessuna dichiarazione da chiedere al modello, nessuna buona volontà su cui contare.
15
+ *
16
+ * RICERCA 10/09/2026, prima di scrivere:
17
+ * · Claude Code, attrezzo `Edit` (repovive.com; gist dell'implementazione interna): `old_string`
18
+ * deve comparire **esattamente una volta**; se compare più volte l'edit è respinto come ambiguo.
19
+ * La ragione, verbatim: «an ambiguous match on a common string like "return null" could corrupt
20
+ * logic in the wrong function… rather than silently picking one occurrence… the tool refuses to
21
+ * apply an ambiguous edit and surfaces the ambiguity back».
22
+ * · Hermes Agent v0.21, `tools/fuzzy_match.py` (letto nel sorgente): stessa unicità, ma il rifiuto
23
+ * ELENCA le posizioni trovate — «Found N matches… Provide more context to make it unique, or use
24
+ * replace_all=True. Matches: …» — e il matching ha strati di tolleranza sugli spazi.
25
+ * · Codex, `codex-rs/apply-patch/src/seek_sequence.rs` (letto nel sorgente): ⛔ NON ha nessun
26
+ * controllo di ambiguità — `seek_sequence` restituisce la PRIMA occorrenza e si ferma. È il
27
+ * comportamento più pericoloso dei tre, ed è quello che qui non si imita.
28
+ * · morphllm.com, «Error Editing File» e arxiv 2603.05344 («Building Effective AI Coding Agents»):
29
+ * cambiare SOLO l'attrezzo di modifica — senza toccare modello né prompt — ha migliorato 15 LLM
30
+ * di 5-14 punti percentuali sui banchi di coding, fino a 10× sui modelli più deboli, con **~20%
31
+ * di token di uscita in meno** perché smettono di bruciare giri in ritentativi. E i sistemi che
32
+ * funzionano meglio convergono su: strati di corrispondenza con ripieghi, messaggi d'errore
33
+ * AZIONABILI, e indirizzamento che tollera gli spazi — «none of which Claude Code's Edit tool
34
+ * currently implements».
35
+ *
36
+ * ⇒ Il nostro +1, che nessuno dei tre ha per intero: unicità obbligatoria (come Claude Code), il
37
+ * rifiuto che dice DOVE sono le altre occorrenze (come Hermes), i ripieghi sugli spazi (come
38
+ * Hermes) ma con la STRATEGIA DICHIARATA nell'esito — chi legge sa se ha corrisposto il testo
39
+ * esatto o una sua versione tollerata — e mai, in nessun caso, la prima occorrenza in silenzio.
40
+ */
41
+
42
+ /** Le strategie, dalla più severa alla più tollerante. Nessuna di esse indovina: tutte confrontano. */
43
+ const STRATEGIE = Object.freeze([
44
+ { nome: 'esatta', descrizione: 'il testo combacia carattere per carattere', normalizza: (t) => t },
45
+ {
46
+ nome: 'spazi-in-coda',
47
+ descrizione: 'combacia ignorando gli spazi a fine riga',
48
+ normalizza: (t) => t.split('\n').map((r) => r.replace(/[ \t]+$/u, '')).join('\n'),
49
+ },
50
+ {
51
+ nome: 'rientro',
52
+ descrizione: 'combacia ignorando il rientro a inizio riga',
53
+ normalizza: (t) => t.split('\n').map((r) => r.replace(/^[ \t]+/u, '').replace(/[ \t]+$/u, '')).join('\n'),
54
+ },
55
+ ]);
56
+
57
+ /** Riga e colonna (da 1) di un indice dentro il testo. Serve a DIRE dove, non solo quante. */
58
+ export function posizioneDi(testo, indice) {
59
+ const prima = String(testo).slice(0, indice);
60
+ const riga = prima.split('\n').length;
61
+ const colonna = indice - (prima.lastIndexOf('\n') + 1) + 1;
62
+ return { riga, colonna };
63
+ }
64
+
65
+ /** Tutte le occorrenze di `ago` in `pagliaio`, senza sovrapposizioni. */
66
+ function occorrenze(pagliaio, ago) {
67
+ const trovate = [];
68
+ if (!ago) return trovate;
69
+ let da = 0;
70
+ for (;;) {
71
+ const i = pagliaio.indexOf(ago, da);
72
+ if (i < 0) return trovate;
73
+ trovate.push(i);
74
+ da = i + ago.length;
75
+ }
76
+ }
77
+
78
+ export class ModificaError extends Error {
79
+ constructor(message, code, dettagli = {}) {
80
+ super(message);
81
+ this.name = 'ModificaError';
82
+ this.code = code;
83
+ Object.assign(this, dettagli);
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Sostituisce `vecchio` con `nuovo` dentro `contenuto`.
89
+ * @returns {{contenuto:string, strategia:string, occorrenze:number, riga:number}}
90
+ * @throws {ModificaError} e non applica NIENTE: un file si tocca solo quando si sa dove.
91
+ */
92
+ export function modificaAncorata(contenuto, vecchio, nuovo, { tutte = false } = {}) {
93
+ const testo = String(contenuto ?? '');
94
+ const cerca = String(vecchio ?? '');
95
+ const metti = String(nuovo ?? '');
96
+
97
+ if (cerca === '') {
98
+ throw new ModificaError('Il testo da sostituire è vuoto: dimmi che cosa cercare.', 'MODIFICA_VUOTA');
99
+ }
100
+ if (cerca === metti) {
101
+ throw new ModificaError('Il testo nuovo è identico a quello vecchio: non c\'è niente da cambiare.', 'MODIFICA_IDENTICA');
102
+ }
103
+ /*
104
+ * ⛔ Solo spazi: combacerebbe ovunque, e «ovunque» non è un'ancora. Hermes rifiuta lo stesso caso
105
+ * («old_string is only whitespace»), e per la stessa ragione.
106
+ */
107
+ if (cerca.trim() === '') {
108
+ throw new ModificaError('Il testo da sostituire è fatto solo di spazi: serve qualcosa che lo distingua.', 'MODIFICA_SOLO_SPAZI');
109
+ }
110
+
111
+ for (const strategia of STRATEGIE) {
112
+ /*
113
+ * ⛔ Una strategia che cambia la LUNGHEZZA del testo non può dire dove sostituire nell'originale:
114
+ * si cerca sul testo normalizzato solo per CONTARE, e si applica sull'originale solo quando la
115
+ * normalizzazione non ha spostato niente (cioè sulla strategia esatta o quando il file non ha
116
+ * spazi da normalizzare). È la stessa trappola delle citazioni elise del Context Engine.
117
+ */
118
+ const testoN = strategia.normalizza(testo);
119
+ const cercaN = strategia.normalizza(cerca);
120
+ if (cercaN === '') continue;
121
+ const trovate = occorrenze(testoN, cercaN);
122
+ if (trovate.length === 0) continue;
123
+
124
+ if (trovate.length > 1 && !tutte) {
125
+ const dove = trovate.slice(0, 5).map((i) => {
126
+ const p = posizioneDi(testoN, i);
127
+ return `riga ${p.riga}`;
128
+ });
129
+ throw new ModificaError(
130
+ `Quel testo compare ${trovate.length} volte (${dove.join(', ')}${trovate.length > 5 ? ', e altre' : ''}): `
131
+ + 'aggiungi qualche riga intorno per renderlo unico, oppure chiedi di sostituirle tutte.',
132
+ 'MODIFICA_AMBIGUA',
133
+ { occorrenze: trovate.length, righe: trovate.map((i) => posizioneDi(testoN, i).riga) },
134
+ );
135
+ }
136
+ /*
137
+ * ⛔ `tutte` vale solo sulla corrispondenza ESATTA: sostituire ovunque basandosi su una
138
+ * somiglianza è il modo più veloce di rovinare un file in molti punti insieme. Stessa guardia
139
+ * di Hermes («replace_all only applies to exact matches»).
140
+ */
141
+ if (tutte && strategia.nome !== 'esatta') {
142
+ throw new ModificaError(
143
+ 'Non trovo quel testo esatto, e «tutte le occorrenze» vale solo sul testo esatto: '
144
+ + 'rileggi il file e copia il punto com\'è.',
145
+ 'MODIFICA_TUTTE_NON_ESATTA',
146
+ );
147
+ }
148
+ if (strategia.nome !== 'esatta' && testoN.length !== testo.length) {
149
+ throw new ModificaError(
150
+ `Ho trovato quel testo ${strategia.descrizione}, ma il file ha spazi che spostano le posizioni: `
151
+ + 'rileggilo e copia il punto com\'è, spazi compresi.',
152
+ 'MODIFICA_POSIZIONE_INCERTA',
153
+ { strategia: strategia.nome },
154
+ );
155
+ }
156
+
157
+ const indice = trovate[0];
158
+ const risultato = tutte
159
+ ? testo.split(cerca).join(metti)
160
+ : testo.slice(0, indice) + metti + testo.slice(indice + cerca.length);
161
+ return {
162
+ contenuto: risultato,
163
+ strategia: strategia.nome,
164
+ occorrenze: tutte ? trovate.length : 1,
165
+ riga: posizioneDi(testo, indice).riga,
166
+ };
167
+ }
168
+
169
+ /*
170
+ * ⛔ Non trovato: il messaggio deve essere AZIONABILE (la ricerca del 10/09 dice che è ciò che fa
171
+ * smettere i cicli di ritentativo). Si dice che cosa fare, non solo che è andata male.
172
+ */
173
+ throw new ModificaError(
174
+ 'Non trovo quel testo nel file: rileggilo e copia il punto esatto da cambiare, con qualche riga intorno.',
175
+ 'MODIFICA_NON_TROVATA',
176
+ );
177
+ }
@@ -0,0 +1,205 @@
1
+ import { generateText, streamText, jsonSchema, stepCountIs } from 'ai';
2
+ import { createAnthropic } from '@ai-sdk/anthropic';
3
+ import { createGoogleGenerativeAI } from '@ai-sdk/google';
4
+ import { createOpenAI } from '@ai-sdk/openai';
5
+
6
+ import { ID_NATIVI_SDK, fornitore } from './provider-registry.mjs';
7
+ import { tokenDaCache, tokenScrittiInCache } from './usage-cache.mjs';
8
+
9
+ // Only this adapter knows the SDK message format. The kernel owns tool execution.
10
+ export function stripNativeMetadata(messages) {
11
+ return messages.map(({ talos_provider_state, ...message }) => message);
12
+ }
13
+
14
+ export function toNativeMessages(messages, { provider, model }) {
15
+ const toolNames = new Map(messages.flatMap(m => (m.tool_calls ?? []).map(t => [t.id, t.function.name])));
16
+ return messages.map(message => {
17
+ if (message.role === 'system' || message.role === 'developer') return { role: 'system', content: message.content };
18
+ if (message.role === 'tool') {
19
+ const toolName = toolNames.get(message.tool_call_id);
20
+ if (!toolName) throw new Error('Risultato di strumento senza chiamata corrispondente.');
21
+ return { role: 'tool', content: [{ type: 'tool-result', toolCallId: message.tool_call_id, toolName, output: { type: 'text', value: typeof message.content === 'string' ? message.content : JSON.stringify(message.content) } }] };
22
+ }
23
+ const state = message.talos_provider_state;
24
+ if (message.role === 'assistant' && state?.version === 1 && state.provider === provider && state.model === model && Array.isArray(state.content)) {
25
+ return { role: 'assistant', content: structuredClone(state.content) };
26
+ }
27
+ const content = [];
28
+ if (typeof message.content === 'string' && message.content) content.push({ type: 'text', text: message.content });
29
+ else if (Array.isArray(message.content)) for (const part of message.content) {
30
+ if (part.type === 'text') content.push({ type: 'text', text: part.text });
31
+ else if (part.type === 'image_url') {
32
+ // The upload resolver already verified these bytes. Never let SDK download arbitrary URLs.
33
+ if (!/^data:image\/(png|jpeg|webp);base64,[A-Za-z0-9+/]+=*$/u.test(part.image_url?.url ?? '')) throw new Error('Riferimento immagine non risolto o non consentito.');
34
+ content.push({ type: 'file', data: part.image_url.url, mediaType: part.image_url.url.slice(5, part.image_url.url.indexOf(';')) });
35
+ } else throw new Error(`Contenuto non supportato dal provider: ${part.type}`);
36
+ }
37
+ for (const call of message.tool_calls ?? []) content.push({ type: 'tool-call', toolCallId: call.id, toolName: call.function.name, input: JSON.parse(call.function.arguments) });
38
+ return { role: message.role, content };
39
+ });
40
+ }
41
+
42
+ /*
43
+ * ⛔⛔ 12/09 — P-B: QUESTO LETTORE CONOSCEVA UN NOME SOLO.
44
+ *
45
+ * `usage.inputTokenDetails?.cacheReadTokens` è il nome che l'AI SDK espone quando l'adattatore
46
+ * fissato nel lock mappa il campo nativo. Quando NON lo mappa — ed è ❓ non verificato che lo
47
+ * faccia per `cachedContentTokenCount` di Gemini (§7.8 dell'inventario) — qui usciva `undefined`,
48
+ * che a valle diventa zero: «non dichiarato» scritto come «nessuno», che è la lezione del 22/8.
49
+ *
50
+ * ⇒ Prima si chiede all'SDK, poi si chiede al fornitore con TUTTI i nomi che quel wire può usare
51
+ * (`usage-cache.mjs`, alimentato dal record). Un nome in più non fa mai danno; uno in meno fa
52
+ * sparire il 93% del costo dal pannello.
53
+ */
54
+ function canonicalUsage(usage = {}, provider) {
55
+ // P-J — l'SDK 4.0.49 trasforma campi cache assenti in zero. Per i terzi il dato
56
+ // grezzo è la prova; il totale SDK include già letture e scritture, senza risommarle.
57
+ const terzoAnthropic = provider !== 'anthropic' && fornitore(provider)?.wire === 'anthropic-messages';
58
+ const dallSdk = Number.isFinite(usage.inputTokenDetails?.cacheReadTokens) ? usage.inputTokenDetails.cacheReadTokens : null;
59
+ const letti = terzoAnthropic ? tokenDaCache(usage.raw, provider) : dallSdk ?? tokenDaCache(usage, provider);
60
+ const scritti = terzoAnthropic ? tokenScrittiInCache(usage.raw, provider) : Number.isFinite(usage.inputTokenDetails?.cacheWriteTokens)
61
+ ? usage.inputTokenDetails.cacheWriteTokens
62
+ : tokenScrittiInCache(usage, provider);
63
+ return {
64
+ prompt_tokens: usage.inputTokens,
65
+ completion_tokens: usage.outputTokens,
66
+ total_tokens: usage.totalTokens,
67
+ prompt_tokens_details: {
68
+ /* ⛔ `undefined` e non `null` quando non si sa: è la forma che questo campo ha sempre avuto,
69
+ e i lettori a valle distinguono già «assente» da «zero». */
70
+ cached_tokens: letti ?? undefined,
71
+ ...(scritti !== null && scritti !== undefined ? { cache_write_tokens: scritti } : {}),
72
+ },
73
+ completion_tokens_details: { reasoning_tokens: usage.outputTokenDetails?.reasoningTokens },
74
+ };
75
+ }
76
+
77
+ function responseMessage(response, provider, model, finishReason) {
78
+ if (!['stop', 'tool-calls'].includes(finishReason)) {
79
+ // P-J — nei nuovi profili lo schermo usa il nome umano, senza codici del protocollo.
80
+ const record = fornitore(provider);
81
+ const error = new Error(provider !== 'anthropic' && record?.wire === 'anthropic-messages'
82
+ ? `Risposta di ${record.etichetta} incompleta. Riprova: la cronologia precedente è conservata.`
83
+ : `Risposta ${provider} incompleta (${finishReason}). Riprova: la cronologia precedente è conservata.`);
84
+ error.code = 'NATIVE_RESPONSE_INCOMPLETE';
85
+ throw error;
86
+ }
87
+ const assistant = response.messages.findLast(m => m.role === 'assistant');
88
+ const content = assistant?.content ?? [];
89
+ const text = content.filter(p => p.type === 'text').map(p => p.text).join('');
90
+ const calls = content.filter(p => p.type === 'tool-call').map(p => ({ id: p.toolCallId, type: 'function', function: { name: p.toolName, arguments: JSON.stringify(p.input) } }));
91
+ const reasoning = content.filter(p => p.type === 'reasoning').map(p => p.text).join('');
92
+ return {
93
+ role: 'assistant', content: text || null,
94
+ ...(calls.length ? { tool_calls: calls } : {}),
95
+ ...(reasoning ? { reasoning_content: reasoning } : {}),
96
+ // Incomplete signatures must never become a checkpoint for the next request.
97
+ ...(['stop', 'tool-calls'].includes(finishReason) ? { talos_provider_state: { version: 1, provider, model, content } } : {}),
98
+ };
99
+ }
100
+
101
+ export async function nativeProviderResponse({ provider, model, apiKey, baseURL, body, fetchFn = fetch, signal }) {
102
+ signal?.throwIfAborted();
103
+ /* ⛔ 12/09 — P-A: la mappa resta (un pacchetto npm non si deriva da un dato), ma il registro
104
+ dichiara CHI passa di qui: se le due divergono, si ferma subito invece di costruire un client
105
+ per un fornitore che il resto del sistema instrada altrove. Il test di parità le confronta. */
106
+ // P-J — INIZIO scelta del trasporto dal registro; nessun secondo client Messages.
107
+ const record = fornitore(provider);
108
+ const wireAnthropic = record?.wire === 'anthropic-messages';
109
+ const factory = wireAnthropic ? createAnthropic : { gemini: createGoogleGenerativeAI, openai: createOpenAI }[provider];
110
+ if (!factory || !ID_NATIVI_SDK.includes(provider)) throw new Error('Provider nativo non riconosciuto.');
111
+ if (wireAnthropic && (typeof apiKey !== 'string' || !apiKey.trim())) {
112
+ throw Object.assign(new Error(`Manca la chiave per ${record.etichetta}.`), { code: 'PROVIDER_KEY_MISSING' });
113
+ }
114
+ const credenziale = wireAnthropic && record.auth.tipo === 'bearer' ? { authToken: apiKey } : { apiKey };
115
+ const client = factory({ ...credenziale, ...(wireAnthropic ? { baseURL: baseURL || record.baseUrl } : baseURL ? { baseURL } : {}), fetch: fetchFn });
116
+ // P-J — FINE scelta del trasporto.
117
+ const languageModel = provider === 'openai' ? client.responses(model) : client.chat(model);
118
+ const tools = Object.fromEntries((body.tools ?? []).map(t => [t.function.name, { description: t.function.description, inputSchema: jsonSchema(t.function.parameters) }]));
119
+ const effort = body.reasoning_effort ?? body.reasoning?.effort;
120
+ const providerOptions = provider === 'openai' ? { openai: { store: false, include: ['reasoning.encrypted_content'] } } : opzioniAnthropicTerzi(provider, model, body);
121
+ const nativeMessages = toNativeMessages(body.messages, { provider, model });
122
+ // SDK common reasoning maps support/model differences in the pinned adapters.
123
+ const common = {
124
+ model: languageModel, messages: nativeMessages.filter(m => m.role !== 'system'),
125
+ instructions: nativeMessages.filter(m => m.role === 'system'),
126
+ ...(Object.keys(tools).length ? { tools } : {}),
127
+ ...(body.tool_choice ? { toolChoice: typeof body.tool_choice === 'string' ? body.tool_choice : { type: 'tool', toolName: body.tool_choice.function.name } } : {}),
128
+ ...(body.temperature != null ? { temperature: body.temperature } : {}),
129
+ ...(body.top_p != null ? { topP: body.top_p } : {}),
130
+ ...(body.stop ? { stopSequences: Array.isArray(body.stop) ? body.stop : [body.stop] } : {}),
131
+ ...(effort && !(wireAnthropic && provider !== 'anthropic') ? { reasoning: effort } : {}), // P-J: opzioni esplicite per i terzi.
132
+ maxOutputTokens: body.max_completion_tokens ?? body.max_tokens ?? 8192,
133
+ providerOptions, maxRetries: 0, stopWhen: stepCountIs(1), abortSignal: signal,
134
+ // The caller owns retries, stop, tools and traces. No telemetry or automatic downloads.
135
+ experimental_download: async urls => { if (urls.length) throw new Error('Download implicito di immagini non consentito.'); return []; },
136
+ };
137
+ if (!body.stream) {
138
+ let usageDelloStep; // P-J — evento nominato, senza dipendere dalla posizione negli array SDK.
139
+ const result = await generateText({ ...common, onStepFinish: step => { usageDelloStep = step.usage; } });
140
+ // P-J — l'aggregato perde raw anche con un solo step; lo step mantiene la misura originale.
141
+ const usage = wireAnthropic && provider !== 'anthropic' ? usageDelloStep : result.usage;
142
+ return Response.json({ choices: [{ index: 0, message: responseMessage(result.response, provider, model, result.finishReason), finish_reason: result.finishReason === 'tool-calls' ? 'tool_calls' : result.finishReason }], usage: canonicalUsage(usage, provider) });
143
+ }
144
+ const abort = new AbortController();
145
+ const combinedSignal = signal ? AbortSignal.any([signal, abort.signal]) : abort.signal;
146
+ const result = streamText({ ...common, abortSignal: combinedSignal, onError: () => {} });
147
+ const encoder = new TextEncoder();
148
+ const iterator = result.fullStream[Symbol.asyncIterator]();
149
+ const callIndices = new Map();
150
+ let completed = false;
151
+ let usageDelloStep; // P-J — conserva raw senza consumare due volte il flusso SDK.
152
+ const stream = new ReadableStream({
153
+ async pull(controller) {
154
+ const emit = (delta, extra = {}, finishReason) => controller.enqueue(encoder.encode(`data: ${JSON.stringify({ choices: [{ index: 0, delta, ...(finishReason ? { finish_reason: finishReason === 'tool-calls' ? 'tool_calls' : finishReason } : {}) }], ...extra })}\n\n`));
155
+ try {
156
+ while (!completed) {
157
+ const { value: part, done } = await iterator.next();
158
+ if (done) throw new Error('Flusso del provider interrotto prima della conclusione.');
159
+ if (part.type === 'error') throw part.error;
160
+ if (part.type === 'abort') throw new Error('Risposta annullata.');
161
+ if (part.type === 'text-delta') { emit({ content: part.text }); return; }
162
+ if (part.type === 'reasoning-delta') { emit({ reasoning_content: part.text }); return; }
163
+ if (part.type === 'tool-input-start') {
164
+ callIndices.set(part.id, callIndices.size);
165
+ emit({ tool_calls: [{ index: callIndices.get(part.id), id: part.id, type: 'function', function: { name: part.toolName, arguments: '' } }] }); return;
166
+ }
167
+ if (part.type === 'tool-input-delta') { emit({ tool_calls: [{ index: callIndices.get(part.id), function: { arguments: part.delta } }] }); return; }
168
+ if (part.type === 'tool-call' && part.invalid) throw part.error ?? new Error('Argomenti dello strumento non validi.');
169
+ if (part.type === 'finish-step') usageDelloStep = part.usage; // P-J
170
+ if (part.type === 'finish') {
171
+ const message = responseMessage(await result.response, provider, model, part.finishReason);
172
+ // P-J — una sola chiamata/step: gli aggregati scartano raw, finish-step lo conserva.
173
+ const usage = wireAnthropic && provider !== 'anthropic' ? usageDelloStep : part.totalUsage;
174
+ emit(message.talos_provider_state ? { talos_provider_state: message.talos_provider_state } : {}, { usage: canonicalUsage(usage, provider) }, part.finishReason);
175
+ controller.enqueue(encoder.encode('data: [DONE]\n\n')); completed = true; controller.close(); return;
176
+ }
177
+ }
178
+ } catch (error) { completed = true; abort.abort(); controller.error(error); }
179
+ },
180
+ async cancel() { completed = true; abort.abort(); await iterator.return?.(); },
181
+ });
182
+ return new Response(stream, { headers: { 'content-type': 'text/event-stream' } });
183
+ }
184
+
185
+ // P-J — opzioni dei nuovi profili nel medesimo SDK; nessuna traduzione HTTP proprietaria.
186
+ function opzioniAnthropicTerzi(provider, model, body) {
187
+ const record = fornitore(provider);
188
+ if (provider === 'anthropic' || record?.wire !== 'anthropic-messages') return {};
189
+ const effort = body.reasoning_effort ?? body.reasoning?.effort;
190
+ const rifiuta = motivo => { throw Object.assign(new Error(`${record.etichetta}: ${motivo}`), { code: 'PROVIDER_REASONING_UNSUPPORTED' }); };
191
+ if (provider === 'zai-anthropic') {
192
+ if (body.reasoning?.enabled === false || (effort && !record.ragionamento.livelli.includes(effort))) rifiuta('scegli un livello di ragionamento alto o massimo.');
193
+ return effort || body.reasoning?.enabled === true ? { anthropic: { thinking: { type: 'adaptive' }, ...(effort ? { effort } : {}) } } : {};
194
+ }
195
+ if (provider === 'minimax-anthropic') {
196
+ if (body.stop) rifiuta('le sequenze di arresto non sono supportate su questa porta.');
197
+ if (effort) rifiuta('i livelli di intensità del ragionamento non sono documentati su questa porta.');
198
+ if (typeof body.reasoning?.enabled === 'boolean') {
199
+ if (model !== 'MiniMax-M3') rifiuta('questo modello non dichiara il controllo del ragionamento.');
200
+ return { anthropic: { thinking: { type: body.reasoning.enabled ? 'adaptive' : 'disabled' } } };
201
+ }
202
+ }
203
+ return {};
204
+ }
205
+ // P-J — FINE opzioni dei profili.
@@ -0,0 +1,250 @@
1
+ /**
2
+ * notes-store.mjs — FASE N, quarto sistema (30/8), piano
3
+ * `elegant-spinning-dongarra.md`. Owner: "TUTTI i 5 sistemi rimasti, uno
4
+ * dopo l'altro".
5
+ *
6
+ * ⛔⛔⛔ GLOBALE, non per-progetto — a differenza di Library/hook/MCP/skill/
7
+ * plugin (tutti dentro `.harness-ui-<cosa>/` nel workspace di UN progetto).
8
+ * Letto alla fonte (`mobile/src/lib/tools/notesWriteTools.ts`+`readTools.ts`,
9
+ * `mobile/src/persistence/chatDatabaseSchema.ts`): su mobile le note sono
10
+ * per-DISPOSITIVO, non per-conversazione — "prendi nota che il codice del
11
+ * cancello è 4471" non riguarda NESSUN progetto di codice, è un promemoria
12
+ * personale. Un desktop che le rendesse per-progetto le renderebbe invisibili
13
+ * da qualunque altra sessione — un comportamento diverso da quello mobile
14
+ * che questo porto deve preservare, non inventare. Storage accanto a
15
+ * `server.mjs`, stesso pattern REALE di `.automations/` (dati locali
16
+ * generati a runtime, non tracciati) — non `.hooks-trust/`/`.mcp-trust/`
17
+ * (quelli sono fiducia, non dati).
18
+ *
19
+ * ⛔ Stessa CONVENZIONE DI CHIAMATA di `library-store.mjs`
20
+ * (`funzione({cartella, ...}, deps={})`, non una factory con stato
21
+ * chiuso come `automation-store.mjs`) — deliberato: questo modulo va
22
+ * agganciato negli stessi punti di contatto I/O iniettabili di
23
+ * `agent-service.mjs` (`elencaVociFn`/`rinominaVoceFn`/...), che si
24
+ * aspettano funzioni STANDALONE, non un oggetto costruito una volta.
25
+ * `automation-store.mjs` ha una convenzione diversa perché è agganciato
26
+ * altrove (rotte HTTP dirette), mai dentro il ciclo tool di `talosLavora`.
27
+ *
28
+ * ⛔ Un file JSON per nota (non un unico array): una nota corrotta a metà
29
+ * scrittura non trascina giù le altre, e una cancellazione è un `rm`
30
+ * diretto invece di riscrivere un array intero — la stessa classe di bug
31
+ * (riscrittura invece di accodamento) già evitata altrove in questo
32
+ * progetto (vedi session-store.mjs).
33
+ */
34
+ import { randomUUID } from 'node:crypto';
35
+ import { promises as fsp } from 'node:fs';
36
+ import { join } from 'node:path';
37
+ import { idArchivioValido } from './id-archivio.mjs';
38
+
39
+ const TITOLO_MASSIMO = 120;
40
+ const CONTENUTO_MASSIMO = 8_000;
41
+
42
+ /** ⭐ Stesso pattern REALE di `.automations/`/`.sessions-store/`: il nome che `server.mjs` userà per il percorso di default, esportato per non duplicarlo lì. */
43
+ export const CARTELLA_NOTE = '.notes-store';
44
+
45
+ export class NoteStoreError extends Error {
46
+ constructor(message, code = 'NOTE_INVALID') {
47
+ super(message);
48
+ this.name = 'NoteStoreError';
49
+ this.code = code;
50
+ }
51
+ }
52
+
53
+ function percorsoDi(cartella, id) {
54
+ // ⛔ 14/09: l'id arriva da fuori (indirizzo HTTP, attrezzo del modello), non solo da un randomUUID nostro — un id fuori
55
+ // grammatica non nomina nessun file e torna `null`, mai un `join` che con `..` uscirebbe dalla cartella. Vedi id-archivio.mjs.
56
+ if (!idArchivioValido(id)) return null;
57
+ return join(cartella, `${id}.json`);
58
+ }
59
+
60
+ function validaTitolo(title) {
61
+ if (typeof title !== 'string' || title.trim().length === 0 || title.length > TITOLO_MASSIMO) {
62
+ throw new NoteStoreError(`title deve avere 1-${TITOLO_MASSIMO} caratteri`, 'NOTE_INVALID');
63
+ }
64
+ return title.trim();
65
+ }
66
+
67
+ function validaContenuto(content) {
68
+ if (typeof content !== 'string' || content.trim().length === 0 || content.length > CONTENUTO_MASSIMO) {
69
+ throw new NoteStoreError(`content deve avere 1-${CONTENUTO_MASSIMO} caratteri`, 'NOTE_INVALID');
70
+ }
71
+ return content.trim();
72
+ }
73
+
74
+ /*
75
+ * ⭐⭐⭐⭐ 11/09/2026, owner: «le note, se sono markdown, devono essere renderizzate in markdown».
76
+ *
77
+ * ⛔ Chi decide non è il frontend, è questo modulo: una nota nasce qui, e se ogni superficie che
78
+ * la mostra ricavasse il formato da sé avremmo tante risposte quante le superfici (la stessa
79
+ * classe di difetto di «due lettori dello stesso corpo» già scritta in http-app.mjs).
80
+ * ⛔ `formato` è DICHIARATO oppure RILEVATO, mai indovinato due volte: se chi scrive lo dichiara
81
+ * (la persona, da un interruttore nel pannello) il valore resta sul disco e vince per sempre;
82
+ * se non lo dichiara (il modello, che nei suoi attrezzi non ha quel campo) lo rileva questa
83
+ * funzione a ogni lettura — così una nota scritta ieri in testo semplice e modificata oggi con
84
+ * un titolo `#` si vede subito come markdown, senza una migrazione.
85
+ *
86
+ * I marcatori sono quelli della specifica CommonMark 0.31.2 (spec.commonmark.org, letta
87
+ * l'11/09/2026), non una lista a memoria: titoli ATX (1-6 `#` seguiti da spazio, fino a 3 spazi
88
+ * di rientro), recinti di codice (3+ backtick o tilde), citazioni (`>`), elenchi puntati
89
+ * (`-`/`+`/`*` PIÙ uno spazio — senza lo spazio non è un elenco) ed elenchi numerati (1-9 cifre
90
+ * più `.` o `)`), righe orizzontali, link `[testo](url)` e enfasi `**`/`__`.
91
+ *
92
+ * ⛔ Enfasi ed elenchi puntati sono i due marcatori che un testo normale può contenere per caso
93
+ * («3 * 4 * 5», un trattino a inizio riga): per questo richiedono la forma STRETTA — `**` o
94
+ * `__` attorno a qualcosa, e il trattino solo a inizio riga seguito da spazio. Un asterisco
95
+ * solitario non basta a chiamare markdown un promemoria della spesa.
96
+ */
97
+ const MARCATORI_MARKDOWN = Object.freeze([
98
+ /^ {0,3}#{1,6}(?:[ \t]|$)/m, // titolo ATX
99
+ /^ {0,3}(?:```|~~~)/m, // recinto di codice
100
+ /^ {0,3}>(?:[ \t]|$)/m, // citazione
101
+ /^ {0,3}[-+*][ \t]+\S/m, // elenco puntato (il marcatore VUOLE uno spazio)
102
+ /^ {0,3}\d{1,9}[.)][ \t]+\S/m, // elenco numerato
103
+ /^ {0,3}(?:(?:[-*_][ \t]*){3,})$/m, // riga orizzontale
104
+ /\[[^\]\n]+\]\([^)\s]+\)/, // link in linea
105
+ /(\*\*|__)(?!\s)[^\n]+?\1/, // enfasi forte
106
+ /^ {0,3}\|.*\|[ \t]*$/m, // riga di tabella (estensione GFM, non CommonMark: dichiarata)
107
+ ]);
108
+
109
+ /** `'markdown'` se il testo porta almeno un marcatore CommonMark, `'testo'` altrimenti. PURA: nessun I/O, si prova con una stringa letterale. */
110
+ export function rilevaFormatoNota(contenuto) {
111
+ const testo = typeof contenuto === 'string' ? contenuto : '';
112
+ return MARCATORI_MARKDOWN.some((marcatore) => marcatore.test(testo)) ? 'markdown' : 'testo';
113
+ }
114
+
115
+ const FORMATI = Object.freeze(['markdown', 'testo']);
116
+ /*
117
+ * ⛔ 11/09 — CHI ha scritto questa nota. Due soli valori possibili perché due sole porte
118
+ * esistono: gli attrezzi `notes_*` del modello (agent-service.mjs) e le rotte HTTP della
119
+ * persona (http-app.mjs). Il default è `'modello'` e non `'ignoto'` di proposito: fino a
120
+ * oggi la persona NON aveva una porta per scrivere — ogni nota già sul disco viene di lì, e
121
+ * un terzo valore inventerebbe un'incertezza che non c'è.
122
+ */
123
+ const ORIGINI = Object.freeze(['persona', 'modello']);
124
+
125
+ function validaFormato(formato) {
126
+ if (!FORMATI.includes(formato)) {
127
+ throw new NoteStoreError(`formato deve essere uno fra ${FORMATI.join('/')}`, 'NOTE_INVALID');
128
+ }
129
+ return formato;
130
+ }
131
+
132
+ function validaOrigine(origine) {
133
+ if (!ORIGINI.includes(origine)) {
134
+ throw new NoteStoreError(`origine deve essere una fra ${ORIGINI.join('/')}`, 'NOTE_INVALID');
135
+ }
136
+ return origine;
137
+ }
138
+
139
+ /**
140
+ * La forma PUBBLICA di una nota — l'unica che esce da questo prodotto, uguale per la rotta
141
+ * HTTP della persona e per chiunque altro la mostri. `formato` dichiarato vince, altrimenti
142
+ * si rileva dal contenuto; `origine` assente su disco vuol dire `'modello'` (vedi ORIGINI).
143
+ */
144
+ export function formaPubblicaNota(voce) {
145
+ return {
146
+ id: voce.id,
147
+ titolo: voce.titolo,
148
+ contenuto: voce.contenuto,
149
+ formato: FORMATI.includes(voce.formato) ? voce.formato : rilevaFormatoNota(voce.contenuto),
150
+ creataAlle: voce.creataAlle ?? null,
151
+ aggiornataAlle: voce.aggiornataAlle ?? null,
152
+ origine: ORIGINI.includes(voce.origine) ? voce.origine : 'modello',
153
+ };
154
+ }
155
+
156
+ /** Più recentemente aggiornate per prime — stesso ordine di `notes_list` mobile (`chatDatabaseSchema.ts`: `ON talos_notes(updated_at DESC, id)`). Cartella assente ⇒ `[]`, mai un errore (primo avvio, nessuna nota ancora). */
157
+ export async function elencaNote({ cartella }, deps = {}) {
158
+ const readdirFn = deps.readdirFn ?? fsp.readdir;
159
+ const readFileFn = deps.readFileFn ?? fsp.readFile;
160
+ let nomi;
161
+ try {
162
+ nomi = await readdirFn(cartella);
163
+ } catch {
164
+ return [];
165
+ }
166
+ const voci = [];
167
+ for (const nome of nomi) {
168
+ if (!nome.endsWith('.json')) continue;
169
+ try {
170
+ voci.push(JSON.parse(await readFileFn(join(cartella, nome), 'utf8')));
171
+ } catch { /* una voce corrotta non deve nascondere le altre */ }
172
+ }
173
+ return voci.sort((a, b) => b.aggiornataAlle.localeCompare(a.aggiornataAlle) || a.id.localeCompare(b.id));
174
+ }
175
+
176
+ /** Un id assente torna `null`, mai un'eccezione — stesso principio di `library-store.mjs#leggiVoce`. */
177
+ export async function leggiNota({ cartella, id }, deps = {}) {
178
+ const readFileFn = deps.readFileFn ?? fsp.readFile;
179
+ const percorso = percorsoDi(cartella, id);
180
+ if (!percorso) return null; // ⛔ 14/09: id fuori grammatica = «non c'è», mai una lettura fuori dalla cartella
181
+ try {
182
+ return JSON.parse(await readFileFn(percorso, 'utf8'));
183
+ } catch {
184
+ return null;
185
+ }
186
+ }
187
+
188
+ /**
189
+ * @returns la nota creata: `{id, titolo, contenuto, formato?, origine, creataAlle, aggiornataAlle}`.
190
+ * @throws {NoteStoreError} NOTE_INVALID su title/content/formato/origine fuori dai tetti — PRIMA di ogni I/O, mai una scrittura parziale.
191
+ * ⛔ 11/09 — `formato` si scrive sul disco SOLO se dichiarato: assente vuol dire «rilevalo a ogni
192
+ * lettura» (vedi formaPubblicaNota), e scriverci dentro il risultato del rilevamento
193
+ * congelerebbe per sempre una risposta che deve poter cambiare col contenuto.
194
+ */
195
+ export async function creaNota({ cartella, title, content, formato, origine = 'modello' }, deps = {}) {
196
+ const titolo = validaTitolo(title);
197
+ const contenuto = validaContenuto(content);
198
+ const formatoDichiarato = formato === undefined ? undefined : validaFormato(formato);
199
+ const daChi = validaOrigine(origine);
200
+ const mkdirFn = deps.mkdirFn ?? fsp.mkdir;
201
+ const writeFileFn = deps.writeFileFn ?? fsp.writeFile;
202
+ const clockFn = deps.clockFn ?? (() => new Date());
203
+ const ora = clockFn().toISOString();
204
+ const voce = {
205
+ id: randomUUID(),
206
+ titolo,
207
+ contenuto,
208
+ ...(formatoDichiarato ? { formato: formatoDichiarato } : {}),
209
+ origine: daChi,
210
+ creataAlle: ora,
211
+ aggiornataAlle: ora,
212
+ };
213
+ await mkdirFn(cartella, { recursive: true });
214
+ await writeFileFn(percorsoDi(cartella, voce.id), JSON.stringify(voce, null, 2), 'utf8');
215
+ return voce;
216
+ }
217
+
218
+ /**
219
+ * Solo i campi passati cambiano — `undefined` lascia il campo intatto (mai
220
+ * una cancellazione implicita), stesso contratto ESATTO del tool mobile
221
+ * ("Send ONLY the fields you are changing").
222
+ * @throws {NoteStoreError} NOTE_NOT_FOUND se l'id non esiste, NOTE_INVALID su un campo passato ma fuori dai tetti.
223
+ */
224
+ export async function aggiornaNota({ cartella, id, title, content, formato }, deps = {}) {
225
+ const readFileFn = deps.readFileFn ?? fsp.readFile;
226
+ const mkdirFn = deps.mkdirFn ?? fsp.mkdir;
227
+ const writeFileFn = deps.writeFileFn ?? fsp.writeFile;
228
+ const clockFn = deps.clockFn ?? (() => new Date());
229
+ const voce = await leggiNota({ cartella, id }, { readFileFn });
230
+ if (!voce) throw new NoteStoreError(`nessuna nota con id ${id}`, 'NOTE_NOT_FOUND');
231
+ if (title !== undefined) voce.titolo = validaTitolo(title);
232
+ if (content !== undefined) voce.contenuto = validaContenuto(content);
233
+ /* ⛔ `formato: null` NON è «lascia stare» come `undefined`: è «torna a rilevarlo dal contenuto»,
234
+ cioè l'unico modo di disfare una dichiarazione sbagliata. Senza questa riga un interruttore
235
+ acceso una volta non si sarebbe più potuto spegnere. */
236
+ if (formato === null) delete voce.formato;
237
+ else if (formato !== undefined) voce.formato = validaFormato(formato);
238
+ voce.aggiornataAlle = clockFn().toISOString();
239
+ await mkdirFn(cartella, { recursive: true });
240
+ await writeFileFn(percorsoDi(cartella, id), JSON.stringify(voce, null, 2), 'utf8');
241
+ return voce;
242
+ }
243
+
244
+ /** Idempotente — un id già assente non è un errore, è l'esito voluto ottenuto da qualcun altro (stesso principio del tool mobile: "It may already be gone"). */
245
+ export async function eliminaNota({ cartella, id }, deps = {}) {
246
+ const rmFn = deps.rmFn ?? fsp.rm;
247
+ const percorso = percorsoDi(cartella, id);
248
+ if (!percorso) return; // ⛔ 14/09: un id che non può nominare un file è già «assente» — no-op idempotente, mai un rm fuori dalla cartella
249
+ await rmFn(percorso, { force: true });
250
+ }