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,385 @@
1
+ /*
2
+ * ⛔⛔⛔ IL PREAMBOLO — quello che il modello legge PRIMA della consegna, e che si paga a ogni invio.
3
+ *
4
+ * ════ COS'ERA, MISURATO L'11/09/2026 ═════════════════════════════════════════════════════════
5
+ *
6
+ * Questo modulo mandava al modello **l'elenco dei file** dello spazio di lavoro. Misurato con lo
7
+ * stimatore del prodotto (`costo-elenco.mjs`, metodo «stimato», 3,5 byte/token — la taratura del
8
+ * 09/09 su `z-ai/glm-5.3-flash`):
9
+ *
10
+ * spazio di lavoro elenco file percorsi troncato
11
+ * ───────────────── ─────────── ────────── ─────────────────────────────────────
12
+ * AVM/mobile 17.149 token 1.500 ⚠ SÌ — l'albero ne ha 1.842 (il 30%…)
13
+ * harness-ui/ 7.267 token 693 no
14
+ * TALOS-PAROLA (piccolo) 85 token 10 no
15
+ *
16
+ * ⇒ Su `AVM/mobile` pagavamo 17.000 token per mostrare **il 30% dei file** e per dire al modello,
17
+ * nel testo stesso, di non fidarsi dell'elenco. Sulla mediana misurata in BC-07 il primo
18
+ * messaggio pesa **29.148 token**: l'elenco ne era la parte più grossa.
19
+ *
20
+ * ⛔ E NESSUNO DEI QUATTRO CONCORRENTI FA COSÌ. Letti nel codice l'11/09
21
+ * (`.claude/RAPPORTO-PREAMBOLO-CONCORRENTI-2026-09-11.md`): Codex manda 35 token di ambiente +
22
+ * `AGENTS.md` (32 KiB) e cerca con `rg`; Claude Code 2.1.268 manda quattro chiavi di sessione e
23
+ * `gitStatus` tagliato a 2.000 caratteri; Hermes v0.21 manda 100-130 token di «workspace
24
+ * snapshot»; DeepSeek `dsh` manda **una frase**. Tutti e quattro mandano le ISTRUZIONI di
25
+ * progetto. **TALOS era l'unico che mandava l'inventario e non le istruzioni.**
26
+ *
27
+ * ════ COS'È ADESSO — QUATTRO BLOCCHI, IN ORDINE DI STABILITÀ ═════════════════════════════════
28
+ *
29
+ * 1. Istruzioni del kernel .... in `talosHarness.mjs` (`ISTRUZIONI`), 97 token, non si tocca
30
+ * 2. Istruzioni di progetto ... `istruzioni-di-progetto.mjs` — AGENTS.md/CLAUDE.md, tetto in byte
31
+ * 3. Mappa delle CARTELLE ..... `mappa-cartelle.mjs` — stabile nella finestra SWR
32
+ * 4. Scheda di lavoro ......... `scheda-di-lavoro.mjs` — stato git, permesso, modello, verifica
33
+ *
34
+ * I blocchi 2-4 li compone questo file, in quest'ordine, e il kernel li mette **subito dopo il
35
+ * blocco 1 e PRIMA della consegna**. L'ordine non è una preferenza: è il vincolo della cache.
36
+ *
37
+ * ════ PERCHÉ IL PREFISSO NON SI RISCRIVE MAI ════════════════════════════════════════════════
38
+ *
39
+ * RICERCA WEB, letta l'11/09/2026 PRIMA di toccare una riga — Claude Platform Docs, «Prompt
40
+ * caching» <https://platform.claude.com/docs/en/docs/build-with-claude/prompt-caching>, verbatim:
41
+ * · *«Cache hits require 100% identical prompt segments»*;
42
+ * · *«Prompt caching references the entire prompt — tools, system, and messages (in that order)
43
+ * up to and including the block designated with cache_control»*: la lookup lavora sul
44
+ * **prefisso intero**, non sul singolo blocco;
45
+ * · i minimi per modello sono **512 / 1.024 / 2.048 / 4.096 token** a seconda del modello, e
46
+ * valgono sul prefisso, non sull'ultimo blocco.
47
+ * E OpenRouter, «Prompt caching» (letto 11/09/2026): i minimi sono 4.096 token per Opus 4.5-4.8 e
48
+ * Haiku 4.5, 1.024 per Sonnet 4.5/4.6 e per OpenAI; Z.AI, DeepSeek, Grok, Moonshot e Groq
49
+ * cacheggiano **in automatico senza marcatori**, Anthropic e Qwen li vogliono espliciti.
50
+ *
51
+ * ⇒ Da qui la regola che i tre harness che gestiscono contesti mutevoli applicano tutti:
52
+ * **il prefisso si costruisce UNA VOLTA e non si tocca più; ciò che cambia si APPENDE in coda,
53
+ * dichiarando che sostituisce.** Codex lo fa con `WorldState::render_diff` +
54
+ * `REPLACEMENT_NOTICE`; Claude Code con *«The session context has changed; these values replace
55
+ * the earlier ones»*; dsh con *«This complete workspace instruction baseline replaces all earlier
56
+ * workspace instruction baselines»*.
57
+ * Qui: `contestoDelProgetto()` costruisce il prefisso, `aggiornamentoInCoda()` costruisce il
58
+ * messaggio da appendere quando qualcosa è cambiato davvero.
59
+ *
60
+ * ⛔ E VALE ANCHE SE LA CACHE NON PRENDE. L'A/B dell'11/09 su `z-ai/glm-5.3-flash` ha dato **0
61
+ * token da cache su due invii consecutivi** anche col `cache_control` per blocco. Un prefisso che
62
+ * non cambia resta comunque **meno byte** e **meno rumore** — e il rumore ha una misura: Chroma,
63
+ * «Context Rot» (14/07/2025, 18 modelli): *«a single distractor reduces performance relative to
64
+ * the baseline»*, e l'effetto cresce con l'input.
65
+ *
66
+ * ════ LA CHIAVE DELLA CACHE — TRE COSE, DICHIARATE ══════════════════════════════════════════
67
+ *
68
+ * Il preambolo dipende da **cartella**, **permesso del giro** e **modello**: sono le tre cose che
69
+ * compaiono nel testo e che possono cambiare senza che il disco cambi. La cache è indicizzata su
70
+ * quelle tre, quindi:
71
+ * · due giri di fila con gli stessi tre valori ⇒ **la STESSA stringa, byte per byte**;
72
+ * · cambia uno dei tre ⇒ stringa nuova, perché il testo dice davvero una cosa diversa.
73
+ * ⛔ La prova sta in `tests/preambolo-quattro-blocchi.test.mjs`, ed è la prova che conta più di
74
+ * tutte le altre di questo modulo.
75
+ */
76
+
77
+ import { costruisciMappaCartelle, mappaEntroIlTetto, TETTO_TOKEN_MAPPA_PREDEFINITO } from './mappa-cartelle.mjs';
78
+ import { istruzioniDiProgetto, trovaRadiceProgetto, TETTO_BYTE_PREDEFINITO } from './istruzioni-di-progetto.mjs';
79
+ import { schedaDiLavoro } from './scheda-di-lavoro.mjs';
80
+ import { costoElenco } from './costo-elenco.mjs';
81
+
82
+ /**
83
+ * Quanto a lungo un preambolo resta buono senza che nessuno dica che i file sono cambiati.
84
+ * ⛔ Non è pigrizia: è la difesa contro il caso in cui il segnale di cambiamento si perda (un file
85
+ * creato da un processo esterno, un `git checkout` fuori da TALOS). Cinque minuti è il compromesso
86
+ * fra «non ricostruire per niente» e «non mentire troppo a lungo» — dichiarato, non misurato.
87
+ */
88
+ export const VALIDITA_MS = 5 * 60 * 1000;
89
+
90
+ /**
91
+ * ⛔⛔⛔ 12/09/2026 — LA CACHE SERVE SUBITO E SI RINNOVA DOPO (stale-while-revalidate).
92
+ * Owner: «i modelli OpenRouter sono estremamente lenti al primo messaggio, quasi un minuto».
93
+ * Misurato: su `Desktop` il preambolo costa 34.356 ms da costruire, e con una validità di cinque
94
+ * minuti OGNI messaggio mandato dopo una pausa lo ripagava per intero (record `tempi-giro` della
95
+ * sessione 78247740: 41,8 s · 34,3 s · 39,9 s al primo token, tre invii di fila). Una persona che
96
+ * legge la risposta, pensa, e riscrive dopo sei minuti non deve aspettare che il disco venga
97
+ * ricamminato: riceve la mappa di prima — che è anche il prefisso IDENTICO su cui prende la cache
98
+ * del fornitore — e la mappa nuova si costruisce in sottofondo per il messaggio dopo.
99
+ * ⛔ Non è «cache per sempre»: `segnalaFileCambiati` continua a buttarla quando la cartella cambia
100
+ * (WorkspaceChanged), e in quel caso la ricostruzione è sincrona ma ora ha il tetto in tempo
101
+ * di `mappa-cartelle.mjs`. Ciò che cambia è solo il caso «scaduta per età»: prima faceva
102
+ * aspettare, ora no. È la forma di HTTP `stale-while-revalidate` (RFC 5861, §3).
103
+ * ⭐ Il rinnovo in sottofondo è UNO per chiave (`rinnovo` sulla voce): dieci messaggi in fila su
104
+ * una cache scaduta fanno partire una sola camminata, non dieci.
105
+ */
106
+ export const RINNOVA_IN_SOTTOFONDO = true;
107
+
108
+ /** La memoria dei preamboli già costruiti, per `cartella|permesso|modello`. */
109
+ const cache = new Map();
110
+
111
+ const chiaveDi = (cartella, permesso, modello) => `${cartella}|${permesso ?? ''}|${modello ?? ''}`;
112
+
113
+ /**
114
+ * Le frasi della scheda e dell'aggiornamento. Servono a RITROVARLO dentro una
115
+ * conversazione già iniziata — cioè a rispondere alla domanda «che cosa ha già visto questo
116
+ * modello?» **senza tenere nessuno stato in memoria**.
117
+ *
118
+ * ⛔ Perché senza stato: una mappa `sessione → ultimo preambolo` sopravvive al riavvio del server
119
+ * come `null`, e la sessione ripresa dopo un riavvio riceverebbe un «aggiornamento» che non
120
+ * aggiorna niente, oppure niente quando invece qualcosa era cambiato. La conversazione salvata è
121
+ * l'unica fonte che non mente su cosa il modello ha letto. È la stessa scelta di Claude Code
122
+ * 2.1.268, che confronta il contesto di sessione per uguaglianza secca
123
+ * (`function N$t(e,n){return soe.every((r)=>e[r]===n[r])}`) invece di ricordarselo.
124
+ * ⛔ E non sono sentinelle invisibili (`<!--TALOS-PREAMBOLO-->`): sono le prime parole che il
125
+ * modello legge davvero. Una sentinella tecnica costerebbe token per non dire niente a chi legge.
126
+ */
127
+ export const INIZIO_SCHEDA = 'Scheda di lavoro — ';
128
+ export const INIZIO_AGGIORNAMENTO = 'Aggiornamento del contesto del progetto:';
129
+
130
+ /**
131
+ * Costruisce (o riusa) il PREAMBOLO di una cartella: blocchi 2, 3 e 4 in un testo solo.
132
+ *
133
+ * @param {object} input
134
+ * @param {string} input.cartella
135
+ * @param {(radice: string) => Promise<Function|null>} [input.creaFiltro] — il filtro `.gitignore`,
136
+ * iniettato: questo modulo non deve sapere come si leggono quelle regole.
137
+ * @param {string|null} [input.permesso] — l'etichetta del permesso del giro (entra nella scheda finale)
138
+ * @param {string|null} [input.modello] — il modello del giro (entra nella scheda finale)
139
+ * @param {string|null} [input.piattaforma]
140
+ * @param {number} [input.tettoIstruzioni] — il tetto in byte delle istruzioni
141
+ * @param {boolean} [input.statoVolatile=true] — se falso, la scheda non porta lo stato di git
142
+ * @param {object} [input.contatore] — il contatore di token, se ce n'è uno vero
143
+ * @param {number} [input.finestra] — la finestra del modello, per dire quanto pesa
144
+ * @param {object} [input.deps] — `{fs, adesso, eseguiGit}` per le prove
145
+ * @returns {Promise<{testo:string, blocchi:object, costo:object, riusato:boolean}|null>}
146
+ */
147
+ export async function contestoDelProgetto({
148
+ cartella, creaFiltro, permesso = null, modello = null, piattaforma = null,
149
+ tettoIstruzioni = TETTO_BYTE_PREDEFINITO, tettoTokenMappa = TETTO_TOKEN_MAPPA_PREDEFINITO,
150
+ statoVolatile = true,
151
+ contatore, finestra, deps = {},
152
+ } = {}) {
153
+ if (typeof cartella !== 'string' || cartella.trim() === '') return null;
154
+ const adesso = deps.adesso ?? (() => Date.now());
155
+ const ora = adesso();
156
+ const chiave = chiaveDi(cartella, permesso, modello);
157
+
158
+ const voce = cache.get(chiave);
159
+ if (voce && ora - voce.quando < VALIDITA_MS) {
160
+ /* ⛔ `riusato` non è un dettaglio da registro: è la prova che il prefisso mandato al fornitore
161
+ è lo STESSO di prima. Se fosse sempre `false`, questo modulo starebbe ricostruendo il
162
+ preambolo a ogni giro e nessuno se ne accorgerebbe. */
163
+ return { ...voce.esito, riusato: true };
164
+ }
165
+ if (voce && RINNOVA_IN_SOTTOFONDO) {
166
+ /* Scaduta per età: si serve quella di prima SUBITO e si rinnova dopo (vedi la nota in testa).
167
+ `stantio` lo dice a chi legge il registro; il testo è byte-identico al precedente. */
168
+ if (!voce.rinnovo) {
169
+ voce.rinnovo = costruisciPreambolo({ cartella, creaFiltro, permesso, modello, piattaforma, tettoIstruzioni, tettoTokenMappa, statoVolatile, contatore, finestra, deps, chiave, rinnovo: true })
170
+ .catch(() => null)
171
+ .finally(() => { const attuale = cache.get(chiave); if (attuale) attuale.rinnovo = null; });
172
+ }
173
+ return { ...voce.esito, riusato: true, stantio: true };
174
+ }
175
+
176
+ return costruisciPreambolo({ cartella, creaFiltro, permesso, modello, piattaforma, tettoIstruzioni, tettoTokenMappa, statoVolatile, contatore, finestra, deps, chiave });
177
+ }
178
+
179
+ /** La costruzione vera, separata dalla lettura della cache perché il rinnovo in sottofondo la chiama da solo. */
180
+ async function costruisciPreambolo({ cartella, creaFiltro, permesso, modello, piattaforma, tettoIstruzioni, tettoTokenMappa, statoVolatile, contatore, finestra, deps, chiave, rinnovo = false }) {
181
+ const adesso = deps.adesso ?? (() => Date.now());
182
+ const ora = adesso();
183
+ const filtro = await filtroGitignore(creaFiltro, cartella);
184
+
185
+ /*
186
+ * I tre blocchi si costruiscono IN PARALLELO: la mappa è la parte lenta (404 ms su `AVM/mobile`,
187
+ * 20 ms su `harness-ui/`) e le altre due sono `stat` e `spawn` di git. In serie il preambolo
188
+ * costerebbe la somma; qui costa il massimo.
189
+ * ⛔ Nessuno dei tre può far cadere l'avvio di una sessione: ognuno degrada al proprio vuoto.
190
+ * Ma i due modi di degradare NON sono lo stesso, e la differenza è quella che il 10/09 è
191
+ * costata 25.163 token invece di 6.518 — vedi `filtroGitignore()` qui sotto.
192
+ */
193
+ const [mappa, istruzioni, scheda, nomeProgetto] = await Promise.all([
194
+ costruisciMappaCartelle({ radice: cartella, filtro, fs: deps.fs }).catch(() => null),
195
+ istruzioniDiProgetto({ cartella, tetto: tettoIstruzioni, fs: deps.fs }),
196
+ schedaDiLavoro({ cartella, permesso, modello, piattaforma, statoVolatile, fs: deps.fs, eseguiGit: deps.eseguiGit }).catch(() => null),
197
+ trovaRadiceProgetto(cartella, { fs: deps.fs }).catch(() => null),
198
+ ]);
199
+
200
+ /*
201
+ * ⛔ ZERO CARTELLE E ZERO FILE NON È UN CONTESTO, È UNA BUGIA. Il camminatore non lancia quando
202
+ * una cartella non si legge: la salta con onestà. Ma se l'albero INTERO è vuoto, dire al
203
+ * modello «in questo progetto non c'è niente» sarebbe peggio che non dirgli niente — gli farebbe
204
+ * concludere che i file non esistono, che è esattamente la conclusione sbagliata che tutto
205
+ * questo esiste per impedire ([[un-modello-che-non-vede-non-tace-spiega]]: alla domanda «quanti
206
+ * file .mjs ci sono in harness-ui/src?» TALOS rispose «0 — la cartella non esiste». Sono 104).
207
+ * ⭐ La scheda di lavoro da sola NON basta a far esistere il preambolo: senza mappa e senza
208
+ * istruzioni, ciò che resta («sei in una cartella») non vale i suoi token.
209
+ */
210
+ const mappaHaSostanza = Boolean(mappa && (mappa.cartelle.length > 0 || mappa.fileTotali > 0));
211
+ if (!mappaHaSostanza && !istruzioni) return null;
212
+
213
+ /*
214
+ * BC-48 C — istruzioni e mappa precedono la scheda: un cambiamento di git non sposta
215
+ * il primo byte diverso davanti ai blocchi stabili. Il marcatore resta al kernel;
216
+ * il riordino da solo non garantisce un hit sui fornitori che cercano confini di blocco.
217
+ * La scheda conserva un ripiego riconoscibile anche quando non si riesce a costruirla.
218
+ */
219
+ const pezzi = [];
220
+ if (istruzioni?.testo) pezzi.push(istruzioni.testo);
221
+ /*
222
+ * ⛔ IL TETTO DELLA MAPPA E' IN TOKEN, non in cartelle — misurato l'11/09 e non negoziabile:
223
+ * col solo tetto sulle cartelle, lo spazio di lavoro «repo intero» produceva una mappa da
224
+ * 17.966 token e il preambolo nuovo costava +8,4% del vecchio. Cioe' la cura peggiorava il
225
+ * caso peggiore, che e' l'unico che conta. Qui si taglia in PROFONDITA' finche' non entra, e
226
+ * il testo lo dichiara.
227
+ */
228
+ const resaMappa = mappaHaSostanza ? mappaEntroIlTetto(mappa, { radice: cartella, tettoToken: tettoTokenMappa }) : null;
229
+ if (resaMappa) pezzi.push(resaMappa.testo);
230
+ pezzi.push(scheda?.testo ?? `${INIZIO_SCHEDA}non sono riuscito a leggere lo stato di questa cartella; quello che precede e' comunque vero.`);
231
+ /* Doppio a-capo fra i blocchi: sono tre cose diverse, e un modello che legge un muro di testo
232
+ senza confini le mescola. Costa 2 byte per blocco. */
233
+ const testo = pezzi.join('\n\n');
234
+
235
+ const costo = costoElenco(testo, { finestra, contatore });
236
+ const esito = {
237
+ testo,
238
+ blocchi: {
239
+ scheda: scheda ? { byte: Buffer.byteLength(scheda.testo, 'utf8') } : null,
240
+ istruzioni: istruzioni ? { byte: istruzioni.byte, usati: istruzioni.usati, omessi: istruzioni.omessi, tagliati: istruzioni.tagliati, indicizzati: istruzioni.indicizzati, sezioniSempre: istruzioni.sezioniSempre } : null,
241
+ mappa: resaMappa
242
+ ? {
243
+ cartelle: mappa.cartelle.filter((c) => c.livello <= resaMappa.profonditaUsata).length,
244
+ cartelleTotali: mappa.cartelle.length,
245
+ file: mappa.fileTotali,
246
+ /* ⛔ Due modi diversi di essere incompleta, e si dicono per nome: il camminatore si e'
247
+ fermato (`troncata`), oppure e' entrata solo fino a una certa profondita' per stare
248
+ nel tetto di token (`tagliataInProfondita`). Un booleano solo li confonderebbe. */
249
+ troncata: mappa.troncato,
250
+ tagliataInProfondita: resaMappa.tagliataInProfondita,
251
+ /* ⛔ BC-40 (12/09) — TERZO modo, ed è quello NORMALE da oggi: la mappa si ferma alla
252
+ profondità predefinita (2) perché così è stata disegnata, non perché un tetto abbia
253
+ morso. Campo AGGIUNTO, mai sostituito: chi leggeva `troncata`/`tagliataInProfondita`
254
+ continua a leggere esattamente quello che leggeva prima. */
255
+ ridottaPerDisegno: Boolean(mappa.fermatoInProfondita),
256
+ profondita: resaMappa.profonditaUsata,
257
+ profonditaPiena: mappa.profonditaRaggiunta,
258
+ token: resaMappa.token,
259
+ }
260
+ : null,
261
+ },
262
+ nomeProgetto,
263
+ costo,
264
+ riusato: false,
265
+ };
266
+ /* ⛔ Un rinnovo in sottofondo che finisce DOPO un `segnalaFileCambiati` non deve resuscitare
267
+ una voce buttata: si scrive solo se la chiave è ancora quella attesa o se non c'è niente. */
268
+ const precedente = cache.get(chiave);
269
+ if (rinnovo && !precedente) return esito; // buttata da segnalaFileCambiati mentre si ricostruiva: la cartella e' cambiata, questa mappa e' gia' vecchia
270
+ cache.set(chiave, { quando: ora, esito, rinnovo: precedente?.rinnovo ?? null });
271
+ return esito;
272
+ }
273
+
274
+ /**
275
+ * Il filtro `.gitignore`, con i DUE MODI DI DEGRADARE tenuti distinti.
276
+ *
277
+ * ⛔⛔ QUESTO CATCH HA GIÀ NASCOSTO UN BUG, il 10/09: il chiamante passava la stringa nuda a
278
+ * `creaFiltroGitignore`, che vuole `{radice}`; Node lanciava `ERR_INVALID_ARG_TYPE` e qui veniva
279
+ * scambiato per un file di regole illeggibile — elenco senza filtro, 1500 percorsi troncati e
280
+ * **25.163 token al posto di ~6.500**, e nessun errore da nessuna parte.
281
+ * ⇒ Un `.gitignore` illeggibile si degrada in silenzio (giusto: il modello vede qualche cartella in
282
+ * più, e il contrario — nessun contesto per colpa di un file di regole — sarebbe rifare il difetto
283
+ * che stiamo curando). Un errore di **CONTRATTO** no: quello è un bug di chi chiama, e deve farsi
284
+ * sentire. Un catch che degrada dice QUALE guasto copre e rilancia gli altri.
285
+ */
286
+ async function filtroGitignore(creaFiltro, cartella) {
287
+ if (typeof creaFiltro !== 'function') return undefined;
288
+ let regole;
289
+ try {
290
+ regole = await creaFiltro(cartella);
291
+ } catch (errore) {
292
+ if (errore?.code === 'ERR_INVALID_ARG_TYPE' || errore instanceof TypeError) throw errore;
293
+ return undefined;
294
+ }
295
+ if (typeof regole !== 'function') return undefined;
296
+ /*
297
+ * L'ADATTATORE FRA I DUE CONTRATTI. Il camminatore chiama `filtro(percorso, { cartella })` — un
298
+ * OGGETTO; il filtro delle regole si aspetta `(percorso, eDirectory)` — un BOOLEANO
299
+ * (`gitignore-elenco.mjs:281`). Un oggetto è sempre vero: senza questa conversione ogni file
300
+ * verrebbe giudicato come se fosse una cartella, e le regole non morderebbero.
301
+ * ⛔ MISURATO il 10/09: la conversione NON cambia il risultato sull'albero vero (1.629 file in
302
+ * entrambi i casi) — l'avevo scritta credendo fosse la causa di un elenco troncato, e la misura
303
+ * mi ha smentito. Resta perché rende esplicito un contratto che altrimenti regge per caso.
304
+ */
305
+ return (percorso, forma) => regole(percorso, typeof forma === 'object' && forma !== null ? Boolean(forma.cartella) : Boolean(forma));
306
+ }
307
+
308
+ /**
309
+ * IL CONTESTO CHE SI APPENDE — il messaggio da mettere IN CODA quando il preambolo e' cambiato
310
+ * dopo che il modello l'ha gia' ricevuto.
311
+ *
312
+ * ⛔ Non rigenera il prefisso: lo lascia esattamente dov'e' e dice al modello che cio' che segue
313
+ * SOSTITUISCE. E' la forma che usano tutti e tre gli harness che gestiscono contesti mutevoli:
314
+ * · Codex, `world_state/agents_md.rs:9-11` — «These AGENTS.md instructions replace all
315
+ * previously provided AGENTS.md instructions.»
316
+ * · Claude Code 2.1.268 — «The session context has changed; these values replace the earlier
317
+ * ones», con confronto per uguaglianza secca e un elenco chiuso di cause;
318
+ * · dsh, `src/render.ts:12-19` — «This complete workspace instruction baseline replaces all
319
+ * earlier workspace instruction baselines.»
320
+ *
321
+ * @param {object} input
322
+ * @param {Array<object>} input.storia — i messaggi che il modello ha gia' davanti (`messaggiIniziali`)
323
+ * @param {string} input.testo — il preambolo corrente
324
+ * @returns {string|null} il messaggio da appendere, oppure `null` se non e' cambiato NIENTE — e
325
+ * allora non si appende niente: zero token, come Hermes, che della sua sonda d'ambiente scrive
326
+ * «Emits a single line; emits NOTHING when the environment is clean (no token cost)».
327
+ */
328
+ export function aggiornamentoInCoda({ storia, testo } = {}) {
329
+ if (typeof testo !== 'string' || testo === '') return null;
330
+ const visto = preamboloVistoDa(storia);
331
+ /* ⛔ Nessun preambolo nella storia: o e' una sessione fresca (e il preambolo sta gia' in testa,
332
+ ripeterlo in coda sarebbe pagarlo due volte) o e' una conversazione nata prima di questa cura.
333
+ In entrambi i casi non si appende: non c'e' niente da SOSTITUIRE. */
334
+ if (visto === null) return null;
335
+ if (visto === testo) return null;
336
+ return INIZIO_AGGIORNAMENTO + ' quanto segue SOSTITUISCE la scheda di lavoro, le istruzioni di '
337
+ + 'progetto e la mappa delle cartelle che hai ricevuto prima in questa conversazione. Quelle '
338
+ + 'non valgono piu\u0027.\n\n' + testo;
339
+ }
340
+
341
+ /**
342
+ * L'ultimo preambolo che il modello ha davvero letto, ricavato dalla conversazione salvata.
343
+ * Si cammina dalla FINE: l'ultimo che parla e' quello che vale.
344
+ */
345
+ export function preamboloVistoDa(storia) {
346
+ if (!Array.isArray(storia)) return null;
347
+ for (let i = storia.length - 1; i >= 0; i -= 1) {
348
+ const m = storia[i];
349
+ if (m?.role !== 'system' || typeof m.content !== 'string') continue;
350
+ if (m.content.startsWith(INIZIO_AGGIORNAMENTO)) {
351
+ const taglio = m.content.indexOf('\n\n');
352
+ return taglio >= 0 ? m.content.slice(taglio + 2) : null;
353
+ }
354
+ if (m.content.startsWith(INIZIO_SCHEDA)) return m.content;
355
+ // BC-48 C: i preamboli nuovi iniziano col blocco stabile; quelli salvati prima restano validi.
356
+ const inizioStabile = m.content.startsWith('Istruzioni di questo progetto — ')
357
+ || m.content.startsWith('Struttura di «');
358
+ if (inizioStabile && m.content.includes(`\n\n${INIZIO_SCHEDA}`)) return m.content;
359
+ }
360
+ return null;
361
+ }
362
+
363
+ /**
364
+ * Dice che i file di una cartella sono cambiati: il prossimo giro ricostruira' il preambolo.
365
+ * ⛔ Si chiama da `WorkspaceChanged`, cioe' quando il disco cambia DAVVERO. Chiamarla a ogni evento
366
+ * annullerebbe la cache e con essa tutto il vantaggio.
367
+ * ⛔ Cancella TUTTE le chiavi di quella cartella, qualunque permesso e qualunque modello: i file
368
+ * sono cambiati per tutte.
369
+ */
370
+ export function segnalaFileCambiati(cartella) {
371
+ if (typeof cartella !== 'string') return false;
372
+ const prefisso = cartella + '|';
373
+ let tolte = 0;
374
+ for (const chiave of [...cache.keys()]) {
375
+ if (chiave.startsWith(prefisso)) { cache.delete(chiave); tolte += 1; }
376
+ }
377
+ return tolte > 0;
378
+ }
379
+
380
+ /** Svuota tutto. Serve alle prove, e a un riavvio pulito. */
381
+ export function dimenticaTuttiGliElenchi() {
382
+ const quanti = cache.size;
383
+ cache.clear();
384
+ return quanti;
385
+ }
@@ -0,0 +1,72 @@
1
+ import { createHash } from 'node:crypto';
2
+
3
+ const MAX_BYTES = 10 * 1024 * 1024;
4
+ const IMAGE_MAX_BYTES = 5 * 1024 * 1024;
5
+ const MIMES = new Set(['image/png', 'image/jpeg', 'image/webp', 'application/pdf', 'text/plain', 'text/markdown', 'text/csv', 'application/json', 'application/octet-stream']);
6
+ const fail = (message, code = 'CTX_ASSET_INVALID') => { throw Object.assign(new Error(message), { code }); };
7
+
8
+ function identifiers(sessionId, id) {
9
+ if (typeof sessionId !== 'string' || !sessionId.trim() || sessionId.length > 256
10
+ || typeof id !== 'string' || !id.trim() || id.length > 256 || /[\u0000-\u001f]/u.test(sessionId)
11
+ || /[\u0000-\u001f/\\:]/u.test(id) || id === '.' || id === '..') fail('Invalid session or asset identifier');
12
+ }
13
+
14
+ function validateBytes(bytes, mimeType, expectedHash) {
15
+ if (!(bytes instanceof Uint8Array) || bytes.length === 0 || bytes.length > MAX_BYTES) fail('Asset byte count is invalid', 'CTX_ASSET_LIMIT');
16
+ if (!MIMES.has(mimeType)) fail('Asset MIME is unsupported', 'CTX_ASSET_MIME');
17
+ if (mimeType.startsWith('image/') && bytes.length > IMAGE_MAX_BYTES) fail('Image exceeds the 5 MiB limit', 'CTX_ASSET_LIMIT');
18
+ const copy = Buffer.from(bytes);
19
+ const signature = mimeType === 'image/png' ? copy.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))
20
+ : mimeType === 'image/jpeg' ? copy[0] === 255 && copy[1] === 216 && copy[2] === 255
21
+ : mimeType === 'image/webp' ? copy.toString('ascii', 0, 4) === 'RIFF' && copy.toString('ascii', 8, 12) === 'WEBP'
22
+ : mimeType === 'application/pdf' ? copy.toString('ascii', 0, 5) === '%PDF-' : true;
23
+ if (!signature) fail('Asset bytes do not match declared MIME', 'CTX_ASSET_MIME');
24
+ if (mimeType.startsWith('text/') || mimeType === 'application/json') {
25
+ try { new TextDecoder('utf-8', { fatal: true }).decode(copy); } catch { fail('Text asset is not valid UTF-8', 'CTX_ASSET_MIME'); }
26
+ }
27
+ const sha256 = createHash('sha256').update(copy).digest('hex');
28
+ if (expectedHash !== undefined && (typeof expectedHash !== 'string' || !/^[a-f0-9]{64}$/iu.test(expectedHash) || sha256 !== expectedHash.toLowerCase())) fail('Asset hash does not match its original bytes', 'CTX_ASSET_HASH');
29
+ return { bytes: Uint8Array.from(copy), sha256, mimeType, byteLength: copy.length };
30
+ }
31
+
32
+ export function createContextAssetAdapter({ store, readAsset } = {}) {
33
+ if (!store || typeof store.putBlob !== 'function' || typeof store.readBlob !== 'function' || (readAsset !== undefined && typeof readAsset !== 'function')) fail('Asset store dependencies are invalid');
34
+
35
+ async function archiveContextAsset({ sessionId, id, mimeType, bytes, sha256 } = {}) {
36
+ identifiers(sessionId, id);
37
+ if (sha256 !== undefined && (typeof sha256 !== 'string' || !/^[a-f0-9]{64}$/iu.test(sha256))) fail('Asset reference hash is invalid', 'CTX_ASSET_HASH');
38
+ if (bytes === undefined) {
39
+ if (!readAsset) fail('Original asset is unavailable', 'CTX_ASSET_MISSING');
40
+ const source = await readAsset({ sessionId, id });
41
+ if (!source) fail('Original asset is unavailable', 'CTX_ASSET_MISSING');
42
+ if (source.sessionId !== sessionId || source.id !== id) fail('Asset belongs to another session', 'CTX_ASSET_OWNERSHIP');
43
+ if (source.mimeType !== mimeType) fail('Original MIME does not match asset reference', 'CTX_ASSET_MIME');
44
+ bytes = source.bytes;
45
+ const verified = validateBytes(bytes, mimeType, source.sha256);
46
+ if (sha256 !== undefined && verified.sha256 !== sha256.toLowerCase()) fail('Reference hash does not match original asset', 'CTX_ASSET_HASH');
47
+ sha256 = verified.sha256;
48
+ }
49
+ const checked = validateBytes(bytes, mimeType, sha256);
50
+ const manifest = await store.putBlob({ sessionId, id, bytes: checked.bytes, mimeType, sha256: checked.sha256 });
51
+ if (!manifest || manifest.id !== id || manifest.sha256 !== checked.sha256 || manifest.mimeType !== mimeType || manifest.byteLength !== checked.byteLength) fail('Stored asset manifest differs from original', 'CTX_ASSET_HASH');
52
+ return structuredClone(manifest);
53
+ }
54
+
55
+ async function resolveContextAsset({ sessionId, id, modelCapabilities } = {}) {
56
+ identifiers(sessionId, id);
57
+ const source = await store.readBlob({ sessionId, id });
58
+ if (!source) fail('Archived asset is unavailable', 'CTX_ASSET_MISSING');
59
+ if (source.id !== id || (source.sessionId !== undefined && source.sessionId !== sessionId)) fail('Asset belongs to another session', 'CTX_ASSET_OWNERSHIP');
60
+ if (typeof source.sha256 !== 'string') fail('Archived asset hash is missing', 'CTX_ASSET_HASH');
61
+ const checked = validateBytes(source.bytes, source.mimeType, source.sha256);
62
+ const capabilities = modelCapabilities ?? {};
63
+ const supported = capabilities.supportedMimeTypes;
64
+ if ((checked.mimeType.startsWith('image/') && capabilities.vision !== true)
65
+ || (!checked.mimeType.startsWith('image/') && !Array.isArray(supported))
66
+ || (supported !== undefined && (!Array.isArray(supported) || !supported.includes(checked.mimeType)))
67
+ || (capabilities.maxAssetBytes !== undefined && (!Number.isSafeInteger(capabilities.maxAssetBytes) || capabilities.maxAssetBytes < checked.byteLength))) fail('Selected model cannot receive this asset type or size', 'CTX_ASSET_CAPABILITY');
68
+ return { id, ...checked };
69
+ }
70
+
71
+ return Object.freeze({ archiveContextAsset, resolveContextAsset });
72
+ }