talos-code 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (407) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/LICENSE +661 -0
  3. package/README.md +116 -3
  4. package/THIRD_PARTY_NOTICES.md +40 -0
  5. package/dist/archive/zip.js +73 -0
  6. package/dist/args.js +100 -0
  7. package/dist/automations/history-store.js +34 -0
  8. package/dist/automations/policy-store.js +43 -0
  9. package/dist/automations/runner.js +107 -0
  10. package/dist/automations/schedule.js +85 -0
  11. package/dist/automations/windows-task.js +53 -0
  12. package/dist/commands/advanced-cli.js +233 -0
  13. package/dist/commands/checkpoint-cli.js +45 -0
  14. package/dist/commands/config-cli.js +107 -0
  15. package/dist/commands/context.js +17 -0
  16. package/dist/commands/extensions-cli.js +207 -0
  17. package/dist/commands/project-cli.js +74 -0
  18. package/dist/commands/project-commands.js +143 -0
  19. package/dist/commands/provider-cli.js +244 -0
  20. package/dist/commands/services-cli.js +248 -0
  21. package/dist/commands/session-cli.js +171 -0
  22. package/dist/commands/system-cli.js +405 -0
  23. package/dist/config/commands.js +60 -0
  24. package/dist/config/load.js +382 -0
  25. package/dist/config/migrations.js +48 -0
  26. package/dist/config/types.js +11 -0
  27. package/dist/diagnostics/development-log.js +154 -0
  28. package/dist/diagnostics/doctor.js +104 -0
  29. package/dist/diagnostics/redact.js +80 -0
  30. package/dist/diagnostics/zip.js +52 -0
  31. package/dist/errors.js +156 -0
  32. package/dist/events/bridge.js +130 -0
  33. package/dist/extensions/installer.js +178 -0
  34. package/dist/extensions/package-schema.js +24 -0
  35. package/dist/headless/result.js +84 -0
  36. package/dist/headless/run.js +230 -0
  37. package/dist/i18n/en/approval.js +46 -0
  38. package/dist/i18n/en/common.js +9 -0
  39. package/dist/i18n/en/credentials.js +92 -0
  40. package/dist/i18n/en/errors.js +267 -0
  41. package/dist/i18n/en/firstrun.js +101 -0
  42. package/dist/i18n/en/providers.js +37 -0
  43. package/dist/i18n/en/screen.js +774 -0
  44. package/dist/i18n/en/tools.js +127 -0
  45. package/dist/i18n/en.js +14 -0
  46. package/dist/i18n/error-view.js +307 -0
  47. package/dist/i18n/index.js +19 -0
  48. package/dist/i18n/kernel-map.js +139 -0
  49. package/dist/io.js +45 -0
  50. package/dist/main.js +331 -0
  51. package/dist/paths.js +41 -0
  52. package/dist/protocol/v2/codec.js +9 -0
  53. package/dist/protocol/v2/events.js +555 -0
  54. package/dist/protocol/v2/index.js +4 -0
  55. package/dist/protocol/v2/replay.js +28 -0
  56. package/dist/protocol/v2/types.js +1 -0
  57. package/dist/provider/control-plane.js +135 -0
  58. package/dist/provider/environment-keys.js +275 -0
  59. package/dist/provider/health.js +110 -0
  60. package/dist/provider/missing-key.js +48 -0
  61. package/dist/provider/model-catalog.js +168 -0
  62. package/dist/provider/openrouter-login.js +172 -0
  63. package/dist/provider/provider-text.js +13 -0
  64. package/dist/provider/store.js +95 -0
  65. package/dist/provider/system-keyring.js +214 -0
  66. package/dist/runtime/active-run.js +63 -0
  67. package/dist/runtime/agent-tree.js +74 -0
  68. package/dist/runtime/attachments.js +84 -0
  69. package/dist/runtime/brokered-executor.js +395 -0
  70. package/dist/runtime/context-archive.js +69 -0
  71. package/dist/runtime/context-status.js +76 -0
  72. package/dist/runtime/create-runtime.js +111 -0
  73. package/dist/runtime/model-profile.js +361 -0
  74. package/dist/runtime/output-store.js +137 -0
  75. package/dist/runtime/provider-attempts.js +185 -0
  76. package/dist/runtime/replay-buffer.js +153 -0
  77. package/dist/runtime/repo.js +95 -0
  78. package/dist/runtime/session-facade.js +135 -0
  79. package/dist/runtime/session-summary.js +125 -0
  80. package/dist/runtime/supervisor.js +265 -0
  81. package/dist/runtime/talos-composition.js +1011 -0
  82. package/dist/runtime/types.js +5 -0
  83. package/dist/runtime/usage-snapshot.js +82 -0
  84. package/dist/security/auto-classifier.js +38 -0
  85. package/dist/security/credential-free-environment.js +54 -0
  86. package/dist/security/evaluate.js +243 -0
  87. package/dist/security/execution-backends.js +236 -0
  88. package/dist/security/execution-broker.js +102 -0
  89. package/dist/security/forge-scan.js +74 -0
  90. package/dist/security/from-approval.js +39 -0
  91. package/dist/security/mxc-execution-backend.js +281 -0
  92. package/dist/security/permission-engine.js +138 -0
  93. package/dist/security/permission-explanation.js +54 -0
  94. package/dist/security/persist.js +179 -0
  95. package/dist/security/plugin-guard.js +230 -0
  96. package/dist/security/process-tree-evidence-store.js +74 -0
  97. package/dist/security/process-tree-probe.js +554 -0
  98. package/dist/security/project-resource-inventory.js +186 -0
  99. package/dist/security/project-trust-gate.js +38 -0
  100. package/dist/security/project-trust.js +367 -0
  101. package/dist/security/rule-parser.js +201 -0
  102. package/dist/security/shell-segmentation.js +68 -0
  103. package/dist/security/trust-authority.js +324 -0
  104. package/dist/security/types.js +1 -0
  105. package/dist/security/workspace-identity.js +102 -0
  106. package/dist/services/automation-facade.js +59 -0
  107. package/dist/services/forge-facade.js +77 -0
  108. package/dist/services/hook-facade.js +240 -0
  109. package/dist/services/index.js +16 -0
  110. package/dist/services/library-facade.js +174 -0
  111. package/dist/services/mcp-facade.js +348 -0
  112. package/dist/services/memory-facade.js +126 -0
  113. package/dist/services/notes-facade.js +157 -0
  114. package/dist/services/plugin-facade.js +308 -0
  115. package/dist/services/research-facade.js +110 -0
  116. package/dist/services/task-board-facade.js +236 -0
  117. package/dist/services/workflow-catalog.js +246 -0
  118. package/dist/sessions/export-format.js +98 -0
  119. package/dist/sessions/metadata-store.js +160 -0
  120. package/dist/sessions/share.js +122 -0
  121. package/dist/sessions/transfer.js +16 -0
  122. package/dist/subcommands.js +62 -0
  123. package/dist/tui/agent-roster.js +36 -0
  124. package/dist/tui/agent-view.js +51 -0
  125. package/dist/tui/app.js +4098 -0
  126. package/dist/tui/approval.js +36 -0
  127. package/dist/tui/boot/boot-sequence.js +76 -0
  128. package/dist/tui/boot/cinematic.js +243 -0
  129. package/dist/tui/boot/desktop-logo.js +82 -0
  130. package/dist/tui/boot.js +3 -0
  131. package/dist/tui/busy-input.js +58 -0
  132. package/dist/tui/catalog-service.js +560 -0
  133. package/dist/tui/components/assistant-stream.js +1 -0
  134. package/dist/tui/components/command-menu.js +68 -0
  135. package/dist/tui/components/composer.js +219 -0
  136. package/dist/tui/components/diff.js +35 -0
  137. package/dist/tui/components/footer.js +48 -0
  138. package/dist/tui/components/header.js +6 -0
  139. package/dist/tui/components/markdown.js +305 -0
  140. package/dist/tui/components/status-indicator.js +38 -0
  141. package/dist/tui/components/terminal-shell.js +214 -0
  142. package/dist/tui/components/thinking-row.js +19 -0
  143. package/dist/tui/components/tool-row.js +97 -0
  144. package/dist/tui/components/transcript-virtualizer.js +165 -0
  145. package/dist/tui/components/transcript.js +43 -0
  146. package/dist/tui/descendant-approvals.js +104 -0
  147. package/dist/tui/diff-model.js +77 -0
  148. package/dist/tui/editor-history.js +21 -0
  149. package/dist/tui/editor.js +210 -0
  150. package/dist/tui/event-adapter.js +436 -0
  151. package/dist/tui/exit-output.js +58 -0
  152. package/dist/tui/external-editor.js +53 -0
  153. package/dist/tui/file-completion.js +89 -0
  154. package/dist/tui/focus-manager.js +5 -0
  155. package/dist/tui/highlight.js +30 -0
  156. package/dist/tui/input-router.js +18 -0
  157. package/dist/tui/interrupt.js +99 -0
  158. package/dist/tui/keybindings.js +194 -0
  159. package/dist/tui/keymap-resolver.js +91 -0
  160. package/dist/tui/launch-state.js +148 -0
  161. package/dist/tui/line-diff.js +57 -0
  162. package/dist/tui/live-activity.js +56 -0
  163. package/dist/tui/metrics.js +123 -0
  164. package/dist/tui/onboarding.js +36 -0
  165. package/dist/tui/overlays/agent-tree.js +43 -0
  166. package/dist/tui/overlays/approval-dialog.js +642 -0
  167. package/dist/tui/overlays/automation-center.js +51 -0
  168. package/dist/tui/overlays/checkpoint-picker.js +47 -0
  169. package/dist/tui/overlays/context-inspector.js +36 -0
  170. package/dist/tui/overlays/effort-line.js +110 -0
  171. package/dist/tui/overlays/forge-center.js +46 -0
  172. package/dist/tui/overlays/help-dialog.js +16 -0
  173. package/dist/tui/overlays/history-picker.js +37 -0
  174. package/dist/tui/overlays/hook-center.js +70 -0
  175. package/dist/tui/overlays/library-center.js +55 -0
  176. package/dist/tui/overlays/mcp-center.js +60 -0
  177. package/dist/tui/overlays/memory-center.js +63 -0
  178. package/dist/tui/overlays/model-picker.js +77 -0
  179. package/dist/tui/overlays/notes-center.js +53 -0
  180. package/dist/tui/overlays/overlay-host.js +8 -0
  181. package/dist/tui/overlays/plugin-center.js +76 -0
  182. package/dist/tui/overlays/provider-picker.js +171 -0
  183. package/dist/tui/overlays/queue-editor.js +32 -0
  184. package/dist/tui/overlays/research-center.js +59 -0
  185. package/dist/tui/overlays/scroll-window.js +234 -0
  186. package/dist/tui/overlays/session-picker.js +115 -0
  187. package/dist/tui/overlays/tasks-center.js +83 -0
  188. package/dist/tui/overlays/theme-picker.js +21 -0
  189. package/dist/tui/overlays/transcript-search.js +58 -0
  190. package/dist/tui/overlays/trust-center.js +29 -0
  191. package/dist/tui/overlays/workflow-center.js +46 -0
  192. package/dist/tui/project-file-index.js +214 -0
  193. package/dist/tui/project-references.js +85 -0
  194. package/dist/tui/project-trust-prompt.js +289 -0
  195. package/dist/tui/prompt-history-store.js +116 -0
  196. package/dist/tui/queue-store.js +110 -0
  197. package/dist/tui/regions/budget.js +59 -0
  198. package/dist/tui/regions/views.js +96 -0
  199. package/dist/tui/render-coordinator.js +148 -0
  200. package/dist/tui/render-scheduler.js +4 -0
  201. package/dist/tui/run.js +69 -0
  202. package/dist/tui/selection-list.js +29 -0
  203. package/dist/tui/session-controller.js +791 -0
  204. package/dist/tui/session-export.js +54 -0
  205. package/dist/tui/setup-wizard.js +46 -0
  206. package/dist/tui/shell-input.js +35 -0
  207. package/dist/tui/shell-layout.js +48 -0
  208. package/dist/tui/shell-model.js +98 -0
  209. package/dist/tui/slash-commands.js +82 -0
  210. package/dist/tui/state.js +151 -0
  211. package/dist/tui/status-bar.js +125 -0
  212. package/dist/tui/status-view.js +40 -0
  213. package/dist/tui/terminal-capabilities.js +9 -0
  214. package/dist/tui/terminal-session.js +11 -0
  215. package/dist/tui/text-width.js +66 -0
  216. package/dist/tui/theme-catalog.js +27 -0
  217. package/dist/tui/theme-store.js +23 -0
  218. package/dist/tui/theme.js +23 -0
  219. package/dist/tui/tool-display.js +135 -0
  220. package/dist/tui/tool-facts.js +1 -0
  221. package/dist/tui/tools/bash-renderer.js +32 -0
  222. package/dist/tui/tools/change.js +61 -0
  223. package/dist/tui/tools/edit-renderer.js +17 -0
  224. package/dist/tui/tools/generic-renderer.js +13 -0
  225. package/dist/tui/tools/list-renderer.js +14 -0
  226. package/dist/tui/tools/read-renderer.js +13 -0
  227. package/dist/tui/tools/registry.js +20 -0
  228. package/dist/tui/tools/row-format.js +187 -0
  229. package/dist/tui/tools/search-renderer.js +38 -0
  230. package/dist/tui/tools/shared.js +97 -0
  231. package/dist/tui/tools/write-renderer.js +15 -0
  232. package/dist/tui/transcript-model.js +441 -0
  233. package/dist/tui/ui-preferences.js +79 -0
  234. package/dist/tui/usage-view.js +77 -0
  235. package/dist/tui/vim-mode.js +99 -0
  236. package/dist/update/check.js +15 -0
  237. package/dist/update/npm.js +51 -0
  238. package/dist/update/run.js +129 -0
  239. package/dist/version.js +2 -0
  240. package/dist/workspace/checkpoint-store.js +210 -0
  241. package/dist/workspace/checkpoint.js +413 -0
  242. package/dist/workspace/restore.js +232 -0
  243. package/package.json +64 -5
  244. package/vendor/context-engine/package.json +11 -0
  245. package/vendor/context-engine/src/compaction-planner.mjs +57 -0
  246. package/vendor/context-engine/src/contracts.mjs +48 -0
  247. package/vendor/context-engine/src/engine.mjs +445 -0
  248. package/vendor/context-engine/src/node/context-export.mjs +164 -0
  249. package/vendor/context-engine/src/node/legacy-import.mjs +92 -0
  250. package/vendor/context-engine/src/node/migrations/001-context.sql +126 -0
  251. package/vendor/context-engine/src/node/sqlite-store.mjs +85 -0
  252. package/vendor/context-engine/src/node/sqlite-worker.mjs +559 -0
  253. package/vendor/context-engine/src/profiles.mjs +10 -0
  254. package/vendor/context-engine/src/retrieval.mjs +104 -0
  255. package/vendor/context-engine/src/summary.mjs +97 -0
  256. package/vendor/context-engine/src/usage.mjs +34 -0
  257. package/vendor/harness-ui/package.json +38 -0
  258. package/vendor/harness-ui/src/acp-agent.mjs +350 -0
  259. package/vendor/harness-ui/src/agent-service.mjs +2188 -0
  260. package/vendor/harness-ui/src/agui-events.mjs +452 -0
  261. package/vendor/harness-ui/src/ambiente-solo-server.mjs +121 -0
  262. package/vendor/harness-ui/src/artifact-store.mjs +39 -0
  263. package/vendor/harness-ui/src/assistenza.mjs +123 -0
  264. package/vendor/harness-ui/src/automation-scheduler.mjs +69 -0
  265. package/vendor/harness-ui/src/automation-store.mjs +145 -0
  266. package/vendor/harness-ui/src/browser-annota.mjs +639 -0
  267. package/vendor/harness-ui/src/browser-frame.mjs +211 -0
  268. package/vendor/harness-ui/src/browser-proxy-universale.mjs +519 -0
  269. package/vendor/harness-ui/src/browser-proxy.mjs +87 -0
  270. package/vendor/harness-ui/src/browser-sessione-viva.mjs +329 -0
  271. package/vendor/harness-ui/src/browser-stream.mjs +445 -0
  272. package/vendor/harness-ui/src/browser-vivo.mjs +694 -0
  273. package/vendor/harness-ui/src/chat-image-attachments.mjs +72 -0
  274. package/vendor/harness-ui/src/config.mjs +697 -0
  275. package/vendor/harness-ui/src/contesto-del-progetto.mjs +385 -0
  276. package/vendor/harness-ui/src/context-asset-adapter.mjs +72 -0
  277. package/vendor/harness-ui/src/context-desktop-service.mjs +253 -0
  278. package/vendor/harness-ui/src/context-embedding-runtime.mjs +252 -0
  279. package/vendor/harness-ui/src/context-inference-scheduler.mjs +81 -0
  280. package/vendor/harness-ui/src/context-native-compaction.mjs +75 -0
  281. package/vendor/harness-ui/src/context-provider-adapter.mjs +141 -0
  282. package/vendor/harness-ui/src/context-runtime.mjs +118 -0
  283. package/vendor/harness-ui/src/context-token-counters.mjs +184 -0
  284. package/vendor/harness-ui/src/context-tool-catalog.mjs +86 -0
  285. package/vendor/harness-ui/src/context-tool-output.mjs +72 -0
  286. package/vendor/harness-ui/src/costo-elenco.mjs +252 -0
  287. package/vendor/harness-ui/src/custom-task.mjs +171 -0
  288. package/vendor/harness-ui/src/doctor.mjs +142 -0
  289. package/vendor/harness-ui/src/document-filename.mjs +97 -0
  290. package/vendor/harness-ui/src/document-generator.mjs +493 -0
  291. package/vendor/harness-ui/src/document-report.mjs +331 -0
  292. package/vendor/harness-ui/src/duckduckgo-search.mjs +155 -0
  293. package/vendor/harness-ui/src/elenco-profondo.mjs +337 -0
  294. package/vendor/harness-ui/src/favicon-proxy.mjs +113 -0
  295. package/vendor/harness-ui/src/forge-contract.mjs +221 -0
  296. package/vendor/harness-ui/src/frequent-dirs.mjs +134 -0
  297. package/vendor/harness-ui/src/generated-image-store.mjs +147 -0
  298. package/vendor/harness-ui/src/generation-idle.mjs +332 -0
  299. package/vendor/harness-ui/src/gguf-header.mjs +207 -0
  300. package/vendor/harness-ui/src/git-service.mjs +626 -0
  301. package/vendor/harness-ui/src/gitignore-elenco.mjs +604 -0
  302. package/vendor/harness-ui/src/harness-receipt-keypair.mjs +207 -0
  303. package/vendor/harness-ui/src/hf-direct-transfer.mjs +170 -0
  304. package/vendor/harness-ui/src/hf-hub-client.mjs +106 -0
  305. package/vendor/harness-ui/src/hf-image-proxy.mjs +105 -0
  306. package/vendor/harness-ui/src/hf-model-transfer.mjs +245 -0
  307. package/vendor/harness-ui/src/hook-registry.mjs +186 -0
  308. package/vendor/harness-ui/src/http-app.mjs +6259 -0
  309. package/vendor/harness-ui/src/http-lifecycle.mjs +132 -0
  310. package/vendor/harness-ui/src/id-archivio.mjs +27 -0
  311. package/vendor/harness-ui/src/image-generator.mjs +143 -0
  312. package/vendor/harness-ui/src/istruzioni-di-progetto.mjs +234 -0
  313. package/vendor/harness-ui/src/kernel/dist/kernelPerIlBanco.js +518 -0
  314. package/vendor/harness-ui/src/kernel/talosHarness.mjs +10437 -0
  315. package/vendor/harness-ui/src/library-policy-store.mjs +175 -0
  316. package/vendor/harness-ui/src/library-store.mjs +652 -0
  317. package/vendor/harness-ui/src/llama-server-supervisor.mjs +629 -0
  318. package/vendor/harness-ui/src/local-model-store.mjs +339 -0
  319. package/vendor/harness-ui/src/local-runtime-contract.mjs +66 -0
  320. package/vendor/harness-ui/src/local-runtime-events.mjs +44 -0
  321. package/vendor/harness-ui/src/local-runtime-llama-server.mjs +244 -0
  322. package/vendor/harness-ui/src/local-runtime-probe.mjs +401 -0
  323. package/vendor/harness-ui/src/machine-capacity.mjs +66 -0
  324. package/vendor/harness-ui/src/mappa-cartelle.mjs +491 -0
  325. package/vendor/harness-ui/src/mcp-client.mjs +98 -0
  326. package/vendor/harness-ui/src/mcp-registry.mjs +157 -0
  327. package/vendor/harness-ui/src/mcp-session.mjs +177 -0
  328. package/vendor/harness-ui/src/memory-store.mjs +227 -0
  329. package/vendor/harness-ui/src/model-catalog-models-dev.mjs +276 -0
  330. package/vendor/harness-ui/src/model-catalog.mjs +129 -0
  331. package/vendor/harness-ui/src/model-destination.mjs +189 -0
  332. package/vendor/harness-ui/src/modifica-ancorata.mjs +177 -0
  333. package/vendor/harness-ui/src/native-provider-adapter.mjs +205 -0
  334. package/vendor/harness-ui/src/notes-store.mjs +250 -0
  335. package/vendor/harness-ui/src/openai-compatible-runtime.mjs +428 -0
  336. package/vendor/harness-ui/src/openrouter-oauth.mjs +339 -0
  337. package/vendor/harness-ui/src/path-policy.mjs +442 -0
  338. package/vendor/harness-ui/src/plugin-registry.mjs +780 -0
  339. package/vendor/harness-ui/src/plugin-session.mjs +180 -0
  340. package/vendor/harness-ui/src/process-policy.mjs +345 -0
  341. package/vendor/harness-ui/src/prompt-enhancer-provider.mjs +94 -0
  342. package/vendor/harness-ui/src/provider-auth-cloud.mjs +95 -0
  343. package/vendor/harness-ui/src/provider-credential-store.mjs +541 -0
  344. package/vendor/harness-ui/src/provider-probe.mjs +582 -0
  345. package/vendor/harness-ui/src/provider-registry.mjs +1633 -0
  346. package/vendor/harness-ui/src/pty-terminal.mjs +312 -0
  347. package/vendor/harness-ui/src/public-problem.mjs +109 -0
  348. package/vendor/harness-ui/src/research/card.mjs +235 -0
  349. package/vendor/harness-ui/src/research/citations.mjs +142 -0
  350. package/vendor/harness-ui/src/research/collector.mjs +275 -0
  351. package/vendor/harness-ui/src/research/deposito-a-pezzi.mjs +139 -0
  352. package/vendor/harness-ui/src/research/dossier.mjs +114 -0
  353. package/vendor/harness-ui/src/research/esportazioni.mjs +560 -0
  354. package/vendor/harness-ui/src/research/fetch-cache.mjs +465 -0
  355. package/vendor/harness-ui/src/research/fidelity.mjs +122 -0
  356. package/vendor/harness-ui/src/research/independence.mjs +159 -0
  357. package/vendor/harness-ui/src/research/ledger.mjs +166 -0
  358. package/vendor/harness-ui/src/research/markdown-server.mjs +565 -0
  359. package/vendor/harness-ui/src/research/narration.mjs +181 -0
  360. package/vendor/harness-ui/src/research/open-cards.mjs +131 -0
  361. package/vendor/harness-ui/src/research/opposing.mjs +305 -0
  362. package/vendor/harness-ui/src/research/outline.mjs +111 -0
  363. package/vendor/harness-ui/src/research/page-budget.mjs +209 -0
  364. package/vendor/harness-ui/src/research/pdf.mjs +291 -0
  365. package/vendor/harness-ui/src/research/plan.mjs +301 -0
  366. package/vendor/harness-ui/src/research/raccolta-viva.mjs +452 -0
  367. package/vendor/harness-ui/src/research/recheck-document.mjs +69 -0
  368. package/vendor/harness-ui/src/research/recheck-history.mjs +192 -0
  369. package/vendor/harness-ui/src/research/recheck.mjs +194 -0
  370. package/vendor/harness-ui/src/research/report.mjs +203 -0
  371. package/vendor/harness-ui/src/research/run.mjs +527 -0
  372. package/vendor/harness-ui/src/research/synthesis.mjs +318 -0
  373. package/vendor/harness-ui/src/research/verification.mjs +572 -0
  374. package/vendor/harness-ui/src/research-orchestrator.mjs +2679 -0
  375. package/vendor/harness-ui/src/research-store.mjs +1133 -0
  376. package/vendor/harness-ui/src/runtime-build-manifest.mjs +26 -0
  377. package/vendor/harness-ui/src/runtime-contract.mjs +59 -0
  378. package/vendor/harness-ui/src/runtime-owner-adapter.mjs +1348 -0
  379. package/vendor/harness-ui/src/runtime-owner-contract.mjs +32 -0
  380. package/vendor/harness-ui/src/scheda-di-lavoro.mjs +249 -0
  381. package/vendor/harness-ui/src/search-source-store.mjs +172 -0
  382. package/vendor/harness-ui/src/session-registry.mjs +6095 -0
  383. package/vendor/harness-ui/src/session-store.mjs +220 -0
  384. package/vendor/harness-ui/src/sessione-pronta.mjs +73 -0
  385. package/vendor/harness-ui/src/setup-stato.mjs +31 -0
  386. package/vendor/harness-ui/src/sezioni-istruzioni.mjs +204 -0
  387. package/vendor/harness-ui/src/skill-registry.mjs +120 -0
  388. package/vendor/harness-ui/src/sse-replay-coalescente.mjs +0 -0
  389. package/vendor/harness-ui/src/static-files.mjs +96 -0
  390. package/vendor/harness-ui/src/stream-partition.mjs +123 -0
  391. package/vendor/harness-ui/src/subagent-orchestrator.mjs +453 -0
  392. package/vendor/harness-ui/src/task-catalog.mjs +65 -0
  393. package/vendor/harness-ui/src/tasks-store.mjs +220 -0
  394. package/vendor/harness-ui/src/terminal-registry.mjs +312 -0
  395. package/vendor/harness-ui/src/terminal-ws.mjs +170 -0
  396. package/vendor/harness-ui/src/tool-forge-store.mjs +299 -0
  397. package/vendor/harness-ui/src/tool-schema-normalize.mjs +100 -0
  398. package/vendor/harness-ui/src/usage-cache.mjs +315 -0
  399. package/vendor/harness-ui/src/workspace-browser.mjs +213 -0
  400. package/vendor/harness-ui/src/workspace-context.mjs +124 -0
  401. package/vendor/harness-ui/src/workspace-disk.mjs +62 -0
  402. package/vendor/harness-ui/src/workspace-files.mjs +589 -0
  403. package/vendor/harness-ui/src/workspace-info.mjs +189 -0
  404. package/vendor/harness-ui/src/workspace-launch-store.mjs +150 -0
  405. package/vendor/harness-ui/src/workspace-tree.mjs +67 -0
  406. package/vendor/harness-ui/src/workspace-watcher.mjs +161 -0
  407. package/vendor/manifest.json +170 -0
@@ -0,0 +1,66 @@
1
+ import os from 'node:os';
2
+ import { statfs } from 'node:fs/promises';
3
+
4
+ export const MACHINE_CAPACITY_SCHEMA = 'talos.model-lab.capacity/1';
5
+ export const MODEL_RESERVE_BYTES = 1024 * 1024 * 1024;
6
+
7
+ export class MachineCapacityError extends Error {
8
+ constructor(message, code = 'MACHINE_CAPACITY_UNAVAILABLE') {
9
+ super(message);
10
+ this.name = 'MachineCapacityError';
11
+ this.code = code;
12
+ }
13
+ }
14
+
15
+ function numero(value) {
16
+ return typeof value === 'bigint' ? Number(value) : value;
17
+ }
18
+
19
+ function interoPositivo(value) {
20
+ const result = numero(value);
21
+ return Number.isFinite(result) && result >= 0 ? Math.floor(result) : null;
22
+ }
23
+
24
+ /**
25
+ * Measures only the host resources that are safe to expose to the desktop UI.
26
+ * No process, GPU probe, path listing or model execution is performed.
27
+ */
28
+ export async function misuraCapacitaMacchina({
29
+ totalmemFn = os.totalmem,
30
+ freememFn = os.freemem,
31
+ statfsFn = statfs,
32
+ platformFn = os.platform,
33
+ archFn = os.arch,
34
+ storagePath = process.cwd(),
35
+ reserveBytes = MODEL_RESERVE_BYTES,
36
+ } = {}) {
37
+ let totalMemoryBytes;
38
+ let freeMemoryBytes;
39
+ let filesystem;
40
+ try {
41
+ totalMemoryBytes = interoPositivo(totalmemFn());
42
+ freeMemoryBytes = interoPositivo(freememFn());
43
+ filesystem = await statfsFn(storagePath, { bigint: true });
44
+ } catch (error) {
45
+ throw new MachineCapacityError(`Misura capacità macchina non disponibile: ${error?.message || 'errore sconosciuto'}`);
46
+ }
47
+ const blockSize = interoPositivo(filesystem?.bsize);
48
+ const availableBlocks = interoPositivo(filesystem?.bavail);
49
+ const totalBlocks = interoPositivo(filesystem?.blocks);
50
+ const availableStorageBytes = blockSize !== null && availableBlocks !== null ? blockSize * availableBlocks : null;
51
+ const totalStorageBytes = blockSize !== null && totalBlocks !== null ? blockSize * totalBlocks : null;
52
+ const reserve = interoPositivo(reserveBytes) ?? MODEL_RESERVE_BYTES;
53
+ const allocatableStorageBytes = availableStorageBytes === null ? null : Math.max(0, availableStorageBytes - reserve);
54
+ if (totalMemoryBytes === null || freeMemoryBytes === null || availableStorageBytes === null || totalStorageBytes === null) {
55
+ throw new MachineCapacityError('Il sistema ha restituito una misura incompleta', 'MACHINE_CAPACITY_INVALID');
56
+ }
57
+ return {
58
+ schema: MACHINE_CAPACITY_SCHEMA,
59
+ platform: String(platformFn()),
60
+ arch: String(archFn()),
61
+ measuredAt: new Date().toISOString(),
62
+ memory: { totalBytes: totalMemoryBytes, freeBytes: freeMemoryBytes },
63
+ storage: { totalBytes: totalStorageBytes, availableBytes: availableStorageBytes, reserveBytes: reserve, allocatableBytes: allocatableStorageBytes },
64
+ runtime: { status: 'unconfigured', reason: 'Runtime locale desktop non scelto' },
65
+ };
66
+ }
@@ -0,0 +1,491 @@
1
+ /**
2
+ * mappa-cartelle.mjs — BLOCCO 4 del preambolo: la forma del progetto, senza l'inventario dei file.
3
+ *
4
+ * ── PERCHÉ ESISTE, e perché NON è l'elenco dei file ──────────────────────────────────────────
5
+ *
6
+ * Misurato l'11/09/2026 con `elenco-profondo.mjs` + `gitignore-elenco.mjs` (stesso stimatore del
7
+ * prodotto, `costo-elenco.mjs` metodo «stimato», 3,5 byte/token):
8
+ * · `AVM/mobile` .... elenco dei file = 17.149 token, 1.500 percorsi, **TRONCATO** (l'albero ne
9
+ * ha 1.842: paghiamo 17k token per mostrarne il 30% e per dire al modello di non fidarsi);
10
+ * · `harness-ui/` ... elenco dei file = 7.267 token, 693 percorsi.
11
+ * La mappa delle sole cartelle degli stessi due alberi sta fra i 1.400 e i 1.700 token ed è
12
+ * **COMPLETA**: non mente mai, perché non c'è niente da troncare.
13
+ *
14
+ * ⛔ Nessuno dei quattro concorrenti letti nel codice l'11/09 (Codex, Claude Code 2.1.268, Hermes
15
+ * v0.21, DeepSeek harness) manda al modello un elenco di file: mandano `AGENTS.md`/`CLAUDE.md`
16
+ * e lasciano cercare. Loro possono: hanno ripgrep, glob, regex, paginazione e giri di fatto
17
+ * illimitati. Noi abbiamo `GIRI_MASSIMI = 24`, e il banco ha già misurato che **TALOS esaurisce
18
+ * i giri, non le capacità** ([[talos-esaurisce-i-giri-non-le-capacita]]: fallisce in 80 s
19
+ * mentre gli altri ne usano 332-630). La mappa delle cartelle è il nostro +1: toglie i giri di
20
+ * orientamento senza pagare l'inventario.
21
+ *
22
+ * RICERCA WEB, letta l'11/09/2026 PRIMA di scrivere (fonte + data + misura):
23
+ * 1. Anthropic, «Effective context engineering for AI agents», 29/09/2025
24
+ * <https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents> —
25
+ * verbatim: *«Folder hierarchies, naming conventions, and timestamps all provide important
26
+ * signals that help both humans and agents understand how and when to utilize information.»*
27
+ * La stessa pagina difende il «just in time» (identificatori leggeri + ricerca a runtime) MA
28
+ * ne dichiara il prezzo: *«there's a trade-off: runtime exploration is slower than retrieving
29
+ * pre-computed data»*, e indica come migliore una strategia IBRIDA — *«retrieving some data up
30
+ * front for speed, and pursuing further autonomous exploration at its discretion»*. Questo
31
+ * modulo è esattamente la metà «up front» di quell'ibrido, tenuta al minimo: la FORMA, non il
32
+ * contenuto.
33
+ * 2. Chroma, «Context Rot: How Increasing Input Tokens Impacts LLM Performance», 14/07/2025
34
+ * <https://www.trychroma.com/research/context-rot> — 18 modelli di frontiera: *«a single
35
+ * distractor reduces performance relative to the baseline»*, e il degrado cresce con
36
+ * l'input. ⇒ 17.000 token di elenco troncato non sono solo un costo: sono **distrattori**.
37
+ *
38
+ * ── LE CINQUE DECISIONI ──────────────────────────────────────────────────────────────────────
39
+ *
40
+ * (1) SOLO CARTELLE, e il conteggio dei file per cartella. `src/ (104)` dice al modello dove sta
41
+ * il codice senza nominare un file. Il conteggio costa ~6 caratteri e risponde da solo alla
42
+ * domanda «dove guardo per prima»; senza, la mappa è un elenco di nomi tutti uguali.
43
+ *
44
+ * (2) COMPLETA, e se un tetto morde si taglia IN PROFONDITÀ e LO SI DICHIARA. Un tetto che taglia
45
+ * «le prime N cartelle in ordine alfabetico» produce una mappa che sembra intera e non lo è —
46
+ * la bugia che `elenco-profondo.mjs` esiste per non dire, rifatta in forma nuova. Tagliare in
47
+ * profondità ha una proprietà che il taglio alfabetico non ha: ciò che resta è **vero e
48
+ * chiuso** («fin qui l'albero è tutto, sotto non l'ho guardato»), non «vero a metà».
49
+ *
50
+ * (3) ORDINE DETERMINISTICO, imposto durante la camminata. Identica ragione di
51
+ * `elenco-profondo.mjs` decisione (3), e ora con la fonte primaria: Claude Platform Docs,
52
+ * «Prompt caching» (letto 11/09/2026, <https://platform.claude.com/docs/en/docs/build-with-claude/prompt-caching>)
53
+ * — *«Cache hits require 100% identical prompt segments»* e la lookup lavora sul **prefisso
54
+ * intero** fino al breakpoint, non sul singolo blocco. Un byte diverso alla posizione N
55
+ * invalida tutto da lì in poi. ⛔ Mai `localeCompare`: dipende dai dati ICU compilati in Node.
56
+ *
57
+ * (4) IL `.gitignore` SI RISPETTA, con lo STESSO filtro del camminatore dei file — e il filtro si
58
+ * INIETTA già costruito. ⛔ Non si accetta una `creaFiltro(radice)` da chiamare qui dentro:
59
+ * è esattamente il contratto che il 10/09 ha prodotto 25.163 token invece di 6.518, perché
60
+ * `creaFiltroGitignore` vuole `{radice}` e riceveva la stringa nuda, Node lanciava
61
+ * `ERR_INVALID_ARG_TYPE` e un `catch` messo lì per il «.gitignore illeggibile» lo scambiava per
62
+ * quello. Qui il filtro arriva già pronto: non c'è nessun contratto da sbagliare.
63
+ *
64
+ * (5) UNA CARTELLA VUOTA RESTA NELLA MAPPA. Esiste sul disco; nasconderla perché non ha file
65
+ * dentro farebbe concludere al modello che non c'è. Costa una riga.
66
+ */
67
+ import { readdir, realpath, stat } from 'node:fs/promises';
68
+ import { basename, join } from 'node:path';
69
+ /* ⛔ UN SOLO contatore in tutto il repo: e' la regola scritta in testa a `costo-elenco.mjs`.
70
+ Due stime diverse per la stessa cosa sono peggio di nessuna stima. */
71
+ import { costoDelTesto } from './costo-elenco.mjs';
72
+
73
+ export class MappaCartelleError extends Error {
74
+ constructor(message) {
75
+ super(message);
76
+ this.name = 'MappaCartelleError';
77
+ this.code = 'MAPPA_INVALIDA';
78
+ }
79
+ }
80
+
81
+ /* ⛔ La stessa lista di `elenco-profondo.mjs`: due potature diverse per lo stesso albero
82
+ darebbero al modello una mappa che non combacia con ciò che l'elenco/la ricerca trovano. */
83
+ export { CARTELLE_ESCLUSE_PREDEFINITE } from './elenco-profondo.mjs';
84
+ import { CARTELLE_ESCLUSE_PREDEFINITE } from './elenco-profondo.mjs';
85
+
86
+ /**
87
+ * Profondità massima della mappa.
88
+ *
89
+ * ⛔⛔⛔ BC-40, 12/09/2026 — ERA 8, ED ERA UN CONTO CHE NON TORNAVA. Owner, dopo la lentezza del
90
+ * primo messaggio: «ci deve essere un metodo migliore, magari mettere il preambolo come tool o
91
+ * qualcosa del genere». Il TEMPO era già stato curato il 12/09 (`TEMPO_MASSIMO_MAPPA_MS`); qui si
92
+ * curano i TOKEN e la FORMA. Misurato lo stesso giorno con lo stimatore del prodotto
93
+ * (`costo-elenco.mjs`, metodo «stimato»), filtro `.gitignore` vero, sui tre spazi reali:
94
+ *
95
+ * spazio OGGI (camminata 8) → resa NATIVA a 2 camminata token
96
+ * ────────────────── ───────────────────────────── ─────────── ─────────── ────────────
97
+ * harness-ui/ 55 cart., resa a prof 5, 374 29 cart., 229 22 → 5 ms −39%
98
+ * AVM-harness-desktop 2.000 cart. (TETTO), resa 4, 3.689 124, 825 507 → 19 ms −78%
99
+ * Desktop 2.000 cart. (TETTO), resa 2, 911 84, 841 434 → 12 ms −8%
100
+ *
101
+ * ⇒ Tre fatti, e nessuno è un'opinione:
102
+ * (a) sui due spazi grandi la camminata a 8 leggeva **2.000 cartelle** e il tetto di token ne
103
+ * rendeva 571 e 84: si pagava il disco per buttare via il risultato;
104
+ * (b) la profondità che il tetto di token SCEGLIEVA DA SOLA era già 2 su `Desktop` e 4 sul repo
105
+ * — cioè 2 non è una perdita inventata a tavolino, è dove il tetto arrivava comunque;
106
+ * (c) il costo scende di 25-36× in tempo di camminata e di 4,5× in token sul caso peggiore.
107
+ *
108
+ * ⛔ E la profondità 2 NON è una legge: `profonditaMax` resta un parametro. Il corpus `storia` ha
109
+ * i file a 4-6 ([[talos-non-vede-i-file-del-corpus-storia]]) e una mappa a 2 non li nomina —
110
+ * ma una mappa a 8 **nemmeno**, perché il tetto di token la tagliava a 4 prima di partire. La
111
+ * differenza non la fa la profondità: la fanno `elenca` (che da BC-40 scende in una cartella
112
+ * PRECISA) e `cerca`. Questa è la metà «up front» dell'ibrido che Anthropic raccomanda
113
+ * («Effective context engineering for AI agents», 29/09/2025: *«retrieving some data up front
114
+ * for speed, and pursuing further autonomous exploration at its discretion»*), tenuta al
115
+ * minimo — ed è la stessa forma della *progressive disclosure* delle Agent Skills (Anthropic,
116
+ * 16/10/2025: *«Like a well-organized manual that starts with a table of contents, then
117
+ * specific chapters, and finally a detailed appendix»*). La mappa è l'indice; `elenca` è il
118
+ * capitolo; `leggi` è la pagina.
119
+ *
120
+ * ⛔⛔ IL RISCHIO, dichiarato e non minimizzato: un modello che vede meno può concludere che una
121
+ * cartella NON ESISTA — è successo, con questa frase esatta: «0 — la cartella `harness-ui/src`
122
+ * non esiste» quando ne conteneva 104 ([[un-modello-che-non-vede-non-tace-spiega]]). ⇒ Per
123
+ * questo una mappa ridotta DEVE dirlo (`fermatoInProfondita` → `testoMappaCartelle`) e DEVE
124
+ * dire come scendere. Una mappa corta che si spaccia per intera sarebbe peggio di una lunga.
125
+ */
126
+ export const PROFONDITA_MAPPA_PREDEFINITA = 2;
127
+
128
+ /**
129
+ * Tetto sulle CARTELLE, non sui file. 2.000: misurato l'11/09, `AVM-harness-desktop` intero ne ha
130
+ * 559 e `AVM/mobile` 215, cioè il tetto non morde su nessuno spazio reale che abbiamo. Esiste per
131
+ * la cartella patologica (la scrivania dell'owner, un disco intero), dove morde e lo DICHIARA.
132
+ */
133
+ export const TETTO_CARTELLE_PREDEFINITO = 2000;
134
+
135
+ /**
136
+ * ⛔⛔⛔ 12/09/2026 — IL TETTO CHE MANCAVA ERA IL TEMPO. Owner: «i modelli OpenRouter sono
137
+ * estremamente lenti al primo messaggio, quasi un minuto». Misurato sui record `tempi-giro`: lo
138
+ * stesso `glm-5.3-flash` risponde in 2,4 s sulla cartella `harness-ui`, in 4,2 s su
139
+ * `AVM-harness-desktop`, in **34-42 s** sulla cartella `Desktop` — a OGNI invio distanziato più
140
+ * di cinque minuti. E `contestoDelProgetto` da sola, su `Desktop`, costa **34.356 ms** per una
141
+ * mappa che poi il tetto di token riduce a 998 token: trentaquattro secondi NOSTRI, spesi a
142
+ * camminare `projects/` (decine di repo) prima ancora di chiamare il fornitore. Il tetto sulle
143
+ * cartelle (2.000) non mordeva in tempo: su Windows ogni `readdir` costa millisecondi, e duemila
144
+ * cartelle sono decine di secondi.
145
+ * ⇒ Un tetto in TEMPO, dichiarato nel testo come gli altri due: ciò che si è letto entro il
146
+ * budget è vero e completo per quelle cartelle (camminata in ampiezza: sopravvive ciò che sta
147
+ * vicino alla radice); il resto «non l'ho guardato», e il modello ha `cerca`/`elenca` per
148
+ * scendere dove serve — è la forma «just in time» che Anthropic raccomanda («maintain
149
+ * lightweight identifiers… load data at runtime», Effective context engineering for AI agents,
150
+ * 29/09/2025) e che Claude Code applica (il suo `/doctor` TOGLIE dal contesto «directory
151
+ * layouts» perché il modello li ricava con gli strumenti — docs «How Claude remembers your
152
+ * project», letta il 12/09/2026).
153
+ * ⛔ 2.000 ms: sopra i 258 ms di `harness-ui/`, sotto i 3.438 ms di `AVM-harness-desktop` (che
154
+ * viene quindi tagliato in tempo: è il repo intero con worktree e `scratchpad/`, il caso
155
+ * patologico dichiarato l'11/09), e un ordine di grandezza sotto il primo token del modello.
156
+ */
157
+ export const TEMPO_MASSIMO_MAPPA_MS = 2000;
158
+
159
+ const insiemeMinuscolo = (valore, predefinito) => {
160
+ const grezzo = valore === undefined || valore === null ? predefinito : valore;
161
+ const voci = grezzo instanceof Set ? [...grezzo] : Array.isArray(grezzo) ? grezzo : [grezzo];
162
+ return new Set(voci.filter((v) => typeof v === 'string').map((v) => v.toLowerCase()));
163
+ };
164
+
165
+ const ordinaVoci = (voci) => [...voci].sort((a, b) => {
166
+ const na = typeof a === 'string' ? a : a.name;
167
+ const nb = typeof b === 'string' ? b : b.name;
168
+ return na === nb ? 0 : na < nb ? -1 : 1;
169
+ });
170
+
171
+ /**
172
+ * Cammina l'albero e restituisce SOLO le cartelle, con quanti file contengono (i propri, non
173
+ * quelli dei figli) e a che livello stanno.
174
+ *
175
+ * @param {object} input
176
+ * @param {string} input.radice
177
+ * @param {number} [input.profonditaMax=8] — livello di una cartella: `src` è 1, `src/kernel` è 2
178
+ * @param {number} [input.tettoCartelle=2000]
179
+ * @param {string[]|Set<string>} [input.escludiCartelle]
180
+ * @param {object} [input.fs] — `{readdir, realpath, stat}`, iniettabile come negli altri moduli
181
+ * @param {(percorsoRelativo: string, info?: {cartella: boolean}) => boolean} [input.filtro]
182
+ * GIÀ COSTRUITO (vedi decisione 4). true = tieni.
183
+ * @param {number} [input.tempoMassimoMs=2000] — il tetto in TEMPO (12/09): oltre, si smette di
184
+ * accodare e lo si dichiara. `Infinity` per le prove che vogliono l'albero intero.
185
+ * @param {() => number} [input.orologio] — iniettabile per le prove (default `performance.now`)
186
+ * @returns {Promise<{cartelle: {percorso:string, livello:number, file:number}[], fileTotali:number,
187
+ * troncato:boolean, motivoTroncamento:'cartelle'|'tempo'|null, msImpiegati:number,
188
+ * profonditaRaggiunta:number, illeggibili:number, fermatoInProfondita:boolean}>}
189
+ *
190
+ * ⛔⛔ BC-40 — `fermatoInProfondita` è il campo che rende ONESTA la profondità ridotta, ed è nato
191
+ * da un difetto che la cura stava per introdurre: con `profonditaMax` a 2 il camminatore finisce
192
+ * senza `troncato`, e `testoMappaCartelle` scriveva **«albero COMPLETO»** su un albero che
193
+ * continuava sotto. Cioè la riduzione avrebbe prodotto esattamente la bugia che questo modulo
194
+ * esiste per non dire (decisione 2). Qui invece si REGISTRA che c'erano figli e non sono stati
195
+ * guardati — `troncato` resta quello che è sempre stato (mi sono FERMATO), questo è un'altra
196
+ * cosa (ho SCELTO di non scendere), e il testo le dice separate.
197
+ */
198
+ export async function costruisciMappaCartelle({
199
+ radice,
200
+ profonditaMax = PROFONDITA_MAPPA_PREDEFINITA,
201
+ tettoCartelle = TETTO_CARTELLE_PREDEFINITO,
202
+ tempoMassimoMs = TEMPO_MASSIMO_MAPPA_MS,
203
+ orologio = () => performance.now(),
204
+ escludiCartelle,
205
+ fs,
206
+ filtro,
207
+ } = {}) {
208
+ if (typeof radice !== 'string' || radice.length === 0 || radice.includes('\0')) {
209
+ throw new MappaCartelleError('La cartella di partenza non è valida');
210
+ }
211
+ if (filtro !== undefined && typeof filtro !== 'function') {
212
+ throw new MappaCartelleError('Il filtro deve essere una funzione');
213
+ }
214
+
215
+ const disco = { readdir, realpath, stat, ...(fs ?? {}) };
216
+ const escluse = insiemeMinuscolo(escludiCartelle, CARTELLE_ESCLUSE_PREDEFINITE);
217
+ const profondita = Number.isFinite(profonditaMax) ? Math.trunc(profonditaMax) : PROFONDITA_MAPPA_PREDEFINITA;
218
+ const tetto = Number.isFinite(tettoCartelle) ? Math.max(0, Math.trunc(tettoCartelle)) : TETTO_CARTELLE_PREDEFINITO;
219
+ const tieni = (percorso, cartella) => (filtro ? filtro(percorso, { cartella }) !== false : true);
220
+
221
+ const cartelle = [];
222
+ let radiceFile = 0;
223
+ let fileTotali = 0;
224
+ let troncato = false;
225
+ let motivoTroncamento = null;
226
+ let profonditaRaggiunta = 0;
227
+ let illeggibili = 0;
228
+ /* BC-40: true appena una cartella TENUTA resta fuori perche' `profonditaMax` non la copre. */
229
+ let fermatoInProfondita = false;
230
+ const budgetMs = Number.isFinite(tempoMassimoMs) ? Math.max(0, tempoMassimoMs) : Infinity;
231
+ const partenza = orologio();
232
+
233
+ const radiceReale = await disco.realpath(radice).catch(() => radice);
234
+ /* Ampiezza, come `elenco-profondo.mjs`: se il tetto morde, ciò che sopravvive è la roba vicina
235
+ alla radice — `src/`, `tests/` — non il primo sottoalbero seguito fino in fondo. */
236
+ const coda = [{ assoluto: radice, relativo: '', livello: 0, antenati: [radiceReale] }];
237
+
238
+ while (coda.length > 0) {
239
+ /* ⛔ Il tetto in tempo si guarda PRIMA di leggere la prossima cartella, non dopo: una lettura
240
+ già iniziata si finisce (i suoi file vanno contati e la sua riga scritta), quella dopo no.
241
+ Stessa disciplina del tetto sulle cartelle: si smette di camminare, non si butta il fatto. */
242
+ if (orologio() - partenza > budgetMs) { troncato = true; motivoTroncamento = 'tempo'; break; }
243
+ const corrente = coda.shift();
244
+ let voci;
245
+ try {
246
+ voci = await disco.readdir(corrente.assoluto, { withFileTypes: true });
247
+ } catch {
248
+ /* Una cartella illeggibile si salta e si CONTA: tacere dichiarerebbe completa una mappa
249
+ che non lo è — lo stesso principio di `elenco-profondo.mjs`. */
250
+ illeggibili += 1;
251
+ continue;
252
+ }
253
+
254
+ let fileQui = 0;
255
+ const figli = [];
256
+ let contate = 0;
257
+ for (const voce of ordinaVoci(voci)) {
258
+ /* ⛔ 12/09: una cartella sola puo' avere migliaia di voci (la radice di `Desktop`), e ognuna
259
+ passa dal filtro: il tetto in tempo si guarda anche QUI, ogni 256 voci, o una cartella
260
+ enorme lo scavalca da sola. Le voci gia' contate restano; il testo dichiara il taglio. */
261
+ if ((contate++ & 255) === 255 && orologio() - partenza > budgetMs) { troncato = true; motivoTroncamento = 'tempo'; break; }
262
+ const nome = typeof voce === 'string' ? voce : voce.name;
263
+ const relativo = corrente.relativo ? `${corrente.relativo}/${nome}` : nome;
264
+ const assoluto = join(corrente.assoluto, nome);
265
+
266
+ let eCartella = Boolean(voce.isDirectory?.());
267
+ let eFile = Boolean(voce.isFile?.());
268
+ if (voce.isSymbolicLink?.()) {
269
+ const informazioni = await disco.stat(assoluto).catch(() => null);
270
+ if (!informazioni) { illeggibili += 1; continue; } // link rotto: onesto, non fatale
271
+ eCartella = Boolean(informazioni.isDirectory?.());
272
+ eFile = Boolean(informazioni.isFile?.());
273
+ }
274
+
275
+ if (eCartella) {
276
+ if (escluse.has(nome.toLowerCase())) continue;
277
+ if (!tieni(relativo, true)) continue;
278
+ figli.push({ nome, relativo, assoluto, collegamento: Boolean(voce.isSymbolicLink?.()) });
279
+ continue;
280
+ }
281
+ /* ⛔ Il conteggio passa dallo STESSO filtro dei file: se non lo facesse, `src/ (104)`
282
+ conterebbe anche ciò che `git` ignora e il numero non combacerebbe con quello che il
283
+ modello trova cercando. Un conteggio che non combacia è peggio di nessun conteggio. */
284
+ if (!eFile) continue;
285
+ if (!tieni(relativo, false)) continue;
286
+ fileQui += 1;
287
+ }
288
+
289
+ fileTotali += fileQui;
290
+ if (corrente.relativo !== '') {
291
+ cartelle.push({ percorso: corrente.relativo, livello: corrente.livello, file: fileQui });
292
+ if (corrente.livello > profonditaRaggiunta) profonditaRaggiunta = corrente.livello;
293
+ } else {
294
+ /* La radice non è una voce della mappa (si chiama come lo spazio di lavoro, già detto
295
+ nell'intestazione), ma i suoi file contano nel totale e si dichiarano a parte. */
296
+ radiceFile = fileQui;
297
+ }
298
+
299
+ if (corrente.livello + 1 > profondita) {
300
+ /* ⛔ BC-40 — NON un `continue` muto. Se questa cartella ha figli TENUTI (gia' passati dalle
301
+ esclusioni e dal filtro `.gitignore`) e la profondita' chiesta non li copre, l'albero
302
+ continua sotto e la mappa NON e' completa: si segna, e il testo lo dichiara. Senza questa
303
+ riga una mappa a profondita' 2 direbbe «albero COMPLETO» di un albero profondo sei. */
304
+ if (figli.length > 0) fermatoInProfondita = true;
305
+ continue;
306
+ }
307
+ for (const figlio of figli) {
308
+ /*
309
+ * ⛔⛔ IL TETTO SMETTE DI ACCODARE, NON DI CAMMINARE — trovato da una prova al verso
310
+ * contrario l'11/09. La prima versione faceva `break` anche sul ciclo esterno: con un
311
+ * tetto raggiunto alla RADICE usciva una mappa **vuota**, che `testoMappaCartelle` poi
312
+ * dichiarava «nessuna sottocartella». Cioè, per colpa della guardia contro l'eccesso, la
313
+ * bugia esatta che questo modulo esiste per non dire — la stessa forma dell'errore che
314
+ * `elenco-profondo.mjs` racconta nella sua nota sugli anelli simbolici.
315
+ * ⇒ Chi è già in coda si finisce di visitare (i suoi file vanno contati, e la sua riga
316
+ * scritta); ciò che non entra non entra, e il testo lo DICHIARA.
317
+ */
318
+ if (cartelle.length + coda.length >= tetto) { troncato = true; motivoTroncamento = 'cartelle'; break; }
319
+ /* ⛔ 12/09: `realpath` era una chiamata di sistema PER OGNI cartella, e serve solo a chi può
320
+ girare in tondo — un collegamento simbolico o una giunzione. Una cartella vera ha come
321
+ percorso reale il suo percorso: si prende senza chiedere al disco. Su `Desktop` erano
322
+ migliaia di chiamate in più per non scoprire niente. */
323
+ const reale = figlio.collegamento ? await disco.realpath(figlio.assoluto).catch(() => figlio.assoluto) : figlio.assoluto;
324
+ if (corrente.antenati.includes(reale)) continue; // ciclo: si torna su un ANTENATO del cammino
325
+ coda.push({ assoluto: figlio.assoluto, relativo: figlio.relativo, livello: corrente.livello + 1, antenati: [...corrente.antenati, reale] });
326
+ }
327
+ }
328
+
329
+ /* ⛔ La camminata è in AMPIEZZA (decisione 3: se il tetto morde sopravvive la roba vicina alla
330
+ radice), ma il TESTO è un albero indentato: in ordine di ampiezza i figli non seguirebbero il
331
+ loro genitore e l'indentazione mentirebbe. Si riordina qui, in profondità e per nome, con lo
332
+ stesso confronto per unità di codice di `elenco-profondo.mjs` — mai `localeCompare`. */
333
+ cartelle.sort(confrontaCartelle);
334
+
335
+ return { cartelle, radiceFile, fileTotali, troncato, motivoTroncamento, msImpiegati: Math.round(orologio() - partenza), profonditaRaggiunta, illeggibili, fermatoInProfondita };
336
+ }
337
+
338
+ /**
339
+ * Ordine totale, stabile e indipendente dall'ambiente: segmento per segmento, e un genitore
340
+ * viene sempre prima dei propri figli. ⛔ Mai `localeCompare` (dipende dai dati ICU compilati in
341
+ * Node: un ordine che cambia da una macchina all'altra rompe il prefisso della cache).
342
+ */
343
+ export function confrontaCartelle(a, b) {
344
+ const sa = String(a?.percorso ?? a).split('/');
345
+ const sb = String(b?.percorso ?? b).split('/');
346
+ const comuni = Math.min(sa.length, sb.length);
347
+ for (let i = 0; i < comuni; i += 1) {
348
+ if (sa[i] === sb[i]) continue;
349
+ return sa[i] < sb[i] ? -1 : 1;
350
+ }
351
+ return sa.length - sb.length;
352
+ }
353
+
354
+ /**
355
+ * Il testo del blocco 4.
356
+ *
357
+ * FORMA: nomi INDENTATI, non percorsi interi. Misurato l'11/09 sui due spazi veri: il percorso
358
+ * intero ripete il prefisso del genitore su ogni riga e costa il 35-45% in più della sola
359
+ * indentazione a due spazi, per la stessa informazione. Un `/` finale distingue a colpo d'occhio
360
+ * una cartella da un file, e il conteggio fra parentesi dice dove sta il lavoro.
361
+ *
362
+ * ⛔ Nell'intestazione va il NOME della cartella, MAI il percorso assoluto: contiene il nome della
363
+ * persona e questo testo esce dalla macchina dentro un prompt. È la lezione
364
+ * [[cancello-4-non-guardava-tutto-mobile]] — un percorso personale pubblicato in chiaro perché
365
+ * nessuno aveva guardato dove finiva. Stessa regola di `testoElenco()`.
366
+ */
367
+ export function testoMappaCartelle(mappa, { radice = '' } = {}) {
368
+ const nome = basename(String(radice ?? '').replace(/[\\/]+$/, '')) || 'la cartella di lavoro';
369
+ const voci = Array.isArray(mappa?.cartelle) ? mappa.cartelle : [];
370
+
371
+ if (voci.length === 0) {
372
+ /* ⛔ «nessuna sottocartella» è un fatto VERO e utile (un progetto piatto esiste); «nessun
373
+ file» invece si dice solo se davvero non ce ne sono, e in quel caso chi compone il preambolo
374
+ decide di non mandare niente — vedi `contesto-del-progetto.mjs`. */
375
+ return `Struttura di «${nome}»: nessuna sottocartella, ${mappa?.radiceFile ?? 0} file nella cartella principale.`;
376
+ }
377
+
378
+ /* ⛔⛔ BC-40 — DUE modi di NON essere completa, e non sono la stessa cosa:
379
+ · `troncato` .............. mi sono FERMATO (tetto sulle cartelle, o tetto in tempo): non
380
+ so nemmeno io che cosa mi sia rimasto fuori;
381
+ · `fermatoInProfondita` ... ho SCELTO di non scendere sotto la profondità dichiarata: so
382
+ per certo che sotto c'è altro, e so esattamente dove.
383
+ Un booleano solo li confonderebbe, e la seconda è l'unica che il modello può RIPARARE da sé,
384
+ con `elenca`. ⛔ «albero COMPLETO» si dice solo quando nessuna delle due è vera. */
385
+ const ridotta = Boolean(mappa?.fermatoInProfondita);
386
+ const righe = [];
387
+ /*
388
+ * ⛔⛔⛔ BC-40 — LA DICHIARAZIONE STA NELL'INTESTAZIONE, NON IN UN BLOCCO A PARTE, e non è
389
+ * una scelta di stile: MISURATA. La prima stesura metteva un paragrafo di avviso in testa
390
+ * («ti do i primi N livelli… non concludere mai che…»): **167 token**, cioè PIÙ dei 145 che
391
+ * la riduzione da profondità 5 a 2 risparmiava su `harness-ui/`. Il preambolo passava da
392
+ * 3.963 a 3.985 token: la cura peggiorava il caso normale per curare quello patologico,
393
+ * che è esattamente il difetto che l'11/09 aveva fatto nascere il tetto in token.
394
+ * ⇒ La dichiarazione costa mezza riga qui, e il promemoria VERO — «non dire che non esiste» —
395
+ * sta in fondo, dopo l'elenco, che è dove il modello guarda per ultimo prima di rispondere
396
+ * ([[il-promemoria-dove-guarda-per-ultimo]]: non riscrivere la regola, SPOSTARLA).
397
+ */
398
+ const coda = ridotta
399
+ ? `, primi ${mappa.profonditaRaggiunta} livelli soltanto (⚠ MAPPA INCOMPLETA PER SCELTA: fin qui è tutto vero, sotto ci sono altre cartelle che non ho elencato)`
400
+ : mappa.troncato ? '' : ', albero COMPLETO';
401
+ righe.push(`Struttura di «${nome}» — ${voci.length} cartelle${coda}. Fra parentesi quanti file contiene ognuna (i propri, non quelli delle sottocartelle).`);
402
+ righe.push('I singoli file non sono elencati: usa `cerca` per trovarli per nome o per contenuto, e `elenca` con `percorso` per aprire una cartella precisa (es. `elenca {"percorso":"src"}`).');
403
+ if (mappa.troncato && mappa.motivoTroncamento === 'tempo') {
404
+ righe.push(`⚠ MAPPA INCOMPLETA — questa cartella è grande e leggerla tutta avrebbe fatto aspettare: mi sono fermato dopo ${voci.length} cartelle (profondità ${mappa.profonditaRaggiunta}). Quelle elencate sono vere; le altre non le ho guardate: cercale con \`cerca\` o \`elenca\` prima di dire che mancano.`);
405
+ } else if (mappa.troncato) {
406
+ righe.push(`⚠ MAPPA INCOMPLETA — mi sono fermato a ${voci.length} cartelle (profondità ${mappa.profonditaRaggiunta}): più in basso l'albero continua e non l'ho guardato.`);
407
+ }
408
+ if (mappa.illeggibili > 0) {
409
+ righe.push(`(${mappa.illeggibili} cartelle non si sono lasciate leggere: quello che contengono non compare qui.)`);
410
+ }
411
+ righe.push('');
412
+ righe.push(`${nome}/ (${mappa.radiceFile ?? 0})`);
413
+ for (const voce of voci) {
414
+ const foglia = voce.percorso.slice(voce.percorso.lastIndexOf('/') + 1);
415
+ righe.push(`${' '.repeat(voce.livello)}${foglia}/ (${voce.file})`);
416
+ }
417
+ if (mappa.troncato || ridotta) {
418
+ righe.push('');
419
+ righe.push('⚠ Fine di una mappa INCOMPLETA. ⛔ Se una cartella non compare qui sopra NON vuol dire che non esista: aprila con `elenca {"percorso":"…"}` o cercala con `cerca` prima di dire che manca.');
420
+ }
421
+ return righe.join('\n');
422
+ }
423
+
424
+ /**
425
+ * Il TETTO DELLA MAPPA, in TOKEN — perche' un tetto sulle cartelle non e' un tetto sul costo.
426
+ *
427
+ * ⛔ MISURATO L'11/09/2026, ed e' il numero che ha fatto nascere questa funzione: col solo tetto
428
+ * sulle cartelle (2.000), lo spazio di lavoro «repo intero» (`AVM-harness-desktop`, 12.715 file
429
+ * e oltre 2.000 cartelle, worktree e `scratchpad/prove` compresi) produceva una mappa da
430
+ * **17.966 token** — cioe' il preambolo nuovo costava **+8,4% del vecchio** invece di meno.
431
+ * Una cura che peggiora il caso peggiore non e' una cura.
432
+ * ⇒ 4.000 token: sotto, tutti gli spazi di lavoro veri misurati quel giorno (`harness-ui/` 358,
433
+ * `AVM/mobile` 3.937); sopra, solo gli alberi patologici, che e' esattamente dove deve mordere.
434
+ *
435
+ * ⛔ E si taglia IN PROFONDITA', non in ordine alfabetico. La differenza e' fra «fin qui l'albero
436
+ * e' TUTTO, sotto non l'ho guardato» — una verita' chiusa, su cui il modello puo' ragionare — e
437
+ * «ne ho mostrate le prime N», che sembra intero e non lo e'. E si DICHIARA.
438
+ */
439
+ /*
440
+ * ⛔⛔ BC-40, 12/09/2026 — ERA 4.000, e con la profondità predefinita a 8 era il numero giusto:
441
+ * serviva a non far esplodere l'albero patologico. Con la profondità predefinita a 2 quel tetto
442
+ * non morde più su NIENTE — misurato il 12/09 sui tre spazi veri, camminata nativa a 2:
443
+ * `harness-ui/` 229 token, `AVM-harness-desktop` 825, `Desktop` 841. Un tetto che non morde mai
444
+ * non è una guardia: è una riga morta, ed è il difetto che il 27/8 ha lasciato il cancello
445
+ * semantico inerte per mesi ([[il-cancello-semantico-era-spento-da-sempre]]).
446
+ * ⇒ 1.200: sopra tutti e tre (il più grosso misurato è 841, quindi c'è il 43% di margine per una
447
+ * cartella più larga di qualunque cosa abbiamo), e sotto l'albero patologico — dove morde e
448
+ * scende a profondità 1, dichiarandolo.
449
+ * ⛔ SCARTATO 800 (la proposta di partenza), e si scrive perché: a 800 token il tetto taglia a
450
+ * profondità 1 sia `AVM-harness-desktop` (825) sia `Desktop` (841), e a profondità 1 sul repo
451
+ * **`harness-ui/src` non compare** — cioè proprio la cartella su cui il modello aveva detto
452
+ * «non esiste». Risparmiare 640 token riaprendo quel buco non è un affare.
453
+ * ⛔ E il confronto esterno dice lo stesso ordine di grandezza: aider, «Repository map» (letto
454
+ * 12/09/2026, <https://aider.chat/docs/repomap.html>), *«The token budget is influenced by the
455
+ * --map-tokens switch, which defaults to 1k tokens»*.
456
+ */
457
+ export const TETTO_TOKEN_MAPPA_PREDEFINITO = 1200;
458
+
459
+ /**
460
+ * Rende la mappa dentro un tetto di token, togliendo un livello di profondita' alla volta.
461
+ *
462
+ * ⭐ NON ricammina l'albero: filtra le cartelle gia' raccolte. Sul repo intero la camminata costa
463
+ * 3,5 s, e rifarla quattro volte per trovare la profondita' giusta sarebbe 14 s prima del primo
464
+ * token — il contrario di cio' che BC-07 sta cercando di ottenere.
465
+ *
466
+ * @returns {{testo:string, profonditaUsata:number, tagliataInProfondita:boolean, token:number}}
467
+ */
468
+ export function mappaEntroIlTetto(mappa, { radice = '', tettoToken = TETTO_TOKEN_MAPPA_PREDEFINITO, stima } = {}) {
469
+ const conta = typeof stima === 'function' ? stima : (t) => costoDelTesto(t, { metodo: 'stimato' }).token;
470
+ const profonditaPiena = mappa?.profonditaRaggiunta ?? 0;
471
+
472
+ for (let profondita = profonditaPiena; profondita >= 1; profondita -= 1) {
473
+ const tagliata = profondita < profonditaPiena;
474
+ const voci = tagliata ? mappa.cartelle.filter((c) => c.livello <= profondita) : mappa.cartelle;
475
+ /* ⛔ BC-40 — un taglio in profondita' deciso dal TETTO e' la stessa cosa, per chi legge, di
476
+ una profondita' scelta in partenza: sotto c'e' altro e non l'ho guardato. Va nello stesso
477
+ campo (`fermatoInProfondita`), non in `troncato`: `troncato` vuol dire «mi sono fermato e
478
+ non so cosa mi manca», e qui invece si sa esattamente. */
479
+ const testo = testoMappaCartelle(
480
+ { ...mappa, cartelle: voci, troncato: Boolean(mappa.troncato), fermatoInProfondita: Boolean(mappa.fermatoInProfondita) || tagliata, profonditaRaggiunta: profondita },
481
+ { radice },
482
+ );
483
+ const token = conta(testo);
484
+ if (token <= tettoToken || profondita === 1) {
485
+ return { testo, profonditaUsata: profondita, tagliataInProfondita: tagliata, token };
486
+ }
487
+ }
488
+ /* Nessuna cartella affatto: la mappa e' una riga sola, e non c'e' niente da tagliare. */
489
+ const testo = testoMappaCartelle(mappa, { radice });
490
+ return { testo, profonditaUsata: 0, tagliataInProfondita: false, token: conta(testo) };
491
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * FASE E — MCP client. Prima fetta: connessione stdio a UN server MCP
3
+ * reale, elenco dei suoi tool, chiamata di un tool. Il server (FASE
4
+ * successiva) resta fuori da questo file.
5
+ *
6
+ * ⛔ `@modelcontextprotocol/client` (v2), NON `@modelcontextprotocol/sdk`
7
+ * (v1) — verificato con ctx7 il 29/8 PRIMA di scrivere una riga: l'SDK
8
+ * si è diviso in pacchetti scoped a metà 2026, e il pacchetto v1 resta
9
+ * pubblicato ma è esplicitamente "legacy support... should not be
10
+ * included in new projects" (doc ufficiale). Il primo ledger di questa
11
+ * fase (piano, sezione FASE E) nominava `@modelcontextprotocol/sdk` —
12
+ * scritto A MEMORIA prima che questa fase si aprisse per davvero, mai
13
+ * verificato alla fonte. Corretto qui, non lì: il piano resta la
14
+ * cronaca di quando è stato scritto, questo file è quello che conta.
15
+ *
16
+ * Filtro di sicurezza per-server (già ricercato,
17
+ * `elegant-spinning-dongarra.md` §2.2): un server MCP collegato non
18
+ * espone MAI i suoi tool al modello senza una allowlist esplicita —
19
+ * vedi `filtraToolMcp`.
20
+ */
21
+ import { Client } from '@modelcontextprotocol/client'
22
+ import { StdioClientTransport } from '@modelcontextprotocol/client/stdio'
23
+
24
+ /**
25
+ * Apre una connessione stdio verso un server MCP e ne fa l'handshake.
26
+ *
27
+ * `config`: `{ comando, argomenti?, nome?, versione? }` — `comando` è
28
+ * l'eseguibile del server (es. `npx`), `argomenti` i suoi parametri
29
+ * (es. `['-y', '@modelcontextprotocol/server-filesystem', cartella]`).
30
+ *
31
+ * `deps.ClientCls`/`deps.TransportCls` — stesso pattern DI già in uso
32
+ * per `spawnPtyFn` in `pty-terminal.mjs`: default alle classi vere
33
+ * dell'SDK, iniettabili nei test per non spawnare mai un processo reale
34
+ * a unità (la verifica CON un processo reale vive in uno script a parte,
35
+ * non nella suite `node --test`).
36
+ *
37
+ * Torna `{ client, chiudi }` — `chiudi()` chiude il transport e il
38
+ * processo figlio che lo serviva. Non cattura errori di connect: un
39
+ * server che non parte deve fallire in modo visibile a chi chiama, non
40
+ * sparire in un `null`.
41
+ */
42
+ export async function connettiServerMcp(config, deps = {}) {
43
+ const ClientCls = deps.ClientCls ?? Client
44
+ const TransportCls = deps.TransportCls ?? StdioClientTransport
45
+ const client = new ClientCls({
46
+ name: config.nome ?? 'talos-harness-desktop',
47
+ version: config.versione ?? '1.0.0',
48
+ })
49
+ const transport = new TransportCls({
50
+ command: config.comando,
51
+ args: config.argomenti ?? [],
52
+ })
53
+ await client.connect(transport)
54
+ return {
55
+ client,
56
+ chiudi: () => client.close(),
57
+ }
58
+ }
59
+
60
+ /**
61
+ * L'elenco dei tool che il server offre, con paginazione automatica
62
+ * (il client la fa da solo — vedi doc ufficiale `listTools()`).
63
+ * Torna l'array grezzo `{name, description, inputSchema}[]`: la
64
+ * traduzione verso lo schema attrezzi di `talosHarness.mjs` è compito
65
+ * di chi chiama, non di questo modulo (stesso confine già usato per
66
+ * `document-generator.mjs`: qui solo il protocollo, mai la policy).
67
+ */
68
+ export async function elencaToolMcp({ client }) {
69
+ const { tools } = await client.listTools()
70
+ return tools
71
+ }
72
+
73
+ /**
74
+ * ⛔⛔⛔ IL FILTRO DI SICUREZZA — mai un tool MCP remoto esposto al
75
+ * modello senza revisione esplicita. Lo stato dell'arte lo fa per-server
76
+ * prima di esporre i tool remoti (ricerca già fatta); stesso principio qui, più
77
+ * semplice: un'allowlist di nomi. Un nome non nell'allowlist non
78
+ * compare mai nell'elenco filtrato — non un "nascosto ma chiamabile",
79
+ * proprio assente.
80
+ */
81
+ export function filtraToolMcp(tool, allowlist) {
82
+ return tool.filter((t) => allowlist.includes(t.name))
83
+ }
84
+
85
+ /**
86
+ * Chiama un tool del server. `argomenti` è l'oggetto già validato
87
+ * contro `inputSchema` da chi chiama (questo modulo non valida: non
88
+ * conosce lo schema di un tool arbitrario meglio del server stesso).
89
+ *
90
+ * Torna il risultato grezzo del protocollo — `content` (blocchi
91
+ * testo/immagine) e `isError` se il tool stesso ha fallito (un
92
+ * `isError:true` NON lancia: è un esito del tool, non un guasto del
93
+ * trasporto — stessa distinzione già in uso in `corsaDiCoding.mjs` fra
94
+ * "fallito" e "erroreDellHarness").
95
+ */
96
+ export async function chiamaToolMcp({ client }, nome, argomenti) {
97
+ return client.callTool({ name: nome, arguments: argomenti })
98
+ }