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,180 @@
1
+ /**
2
+ * plugin-session.mjs — FASE G del piano `elegant-spinning-dongarra.md`,
3
+ * esecuzione (29/8): il punto che UNISCE `plugin-registry.mjs` (quali
4
+ * plugin sono dichiarati e fidati) in quello che una sessione REALE
5
+ * offre al kernel — `toolPlugin` + `eseguiToolPluginFn`, esattamente
6
+ * la forma che `talosLavora` accetta (vedi
7
+ * `AVM-harness/.../talosHarness.mjs`, commit `b9065891`) — più
8
+ * `hookPlugin`, gli hook dei plugin fidati pronti per fondersi
9
+ * nell'elenco che `hook-registry.mjs` già produce (vedi la doc su
10
+ * `costruisciHookFn` in `session-registry.mjs`).
11
+ *
12
+ * Mirror di `mcp-session.mjs`, con differenze deliberate:
13
+ * - EAGER come MCP (i tool devono essere noti PRIMA della prima
14
+ * chiamata al modello), ma senza connessione persistente: un tool
15
+ * di plugin non è un processo che resta vivo, è un comando lanciato
16
+ * ON-DEMAND ad ogni chiamata (spawn, non connect+call) — più vicino
17
+ * a come l'attrezzo `shell` del kernel gira un comando, che al
18
+ * protocollo MCP.
19
+ * - Nome esposto SEMPRE prefissato `plugin__<pluginId>__<toolName>`
20
+ * (stessa convenzione di `mcp__<serverId>__<toolName>` in
21
+ * `mcp-session.mjs`) — due plugin indipendenti possono dichiarare
22
+ * un tool con lo stesso nome, e non sanno l'uno dell'altro.
23
+ * - Solo i plugin FIDATI (`verificaTrustPlugin`, hash sull'INTERO
24
+ * manifesto — non per componente, vedi `plugin-registry.mjs`)
25
+ * contribuiscono tool E hook. Un plugin mai fidato, o il cui
26
+ * manifesto è cambiato da quando è stato fidato, resta interamente
27
+ * inerte: zero tool offerti, zero hook nella lista tornata.
28
+ * - `hookPlugin` porta id GIÀ QUALIFICATI (`plugin:<pluginId>:<hookId>`)
29
+ * per non collidere con un hook scritto a mano in
30
+ * `.harness-ui-hooks.json` o con l'omonimo di un altro plugin, e
31
+ * NON porta un hash da verificare di nuovo altrove: la fiducia è già
32
+ * stata accertata QUI (sul plugin intero) — chi fonde questo elenco
33
+ * (`costruisciHookFn`) tratta ogni voce di `hookPlugin` come
34
+ * già-fidata, mai una seconda verifica nella cartella di trust degli
35
+ * hook singoli (namespace di trust diverso, per costruzione: un
36
+ * hook standalone è fidato per HASH DEL SUO COMANDO, un hook di
37
+ * plugin per HASH DELL'INTERO MANIFESTO — mischiare i due namespace
38
+ * sarebbe un bug di sicurezza, non una semplificazione).
39
+ */
40
+ import {
41
+ caricaPlugin as caricaPluginReale,
42
+ verificaTrustPlugin as verificaTrustPluginReale,
43
+ } from './plugin-registry.mjs';
44
+ import { createProcessPolicy, parseProcessCommand } from './process-policy.mjs';
45
+
46
+ const SEPARATORE = '__';
47
+ const PREFISSO = `plugin${SEPARATORE}`;
48
+ // ⭐ un tool di plugin è un comando singolo, non un giro di test — più di un hook (10s, hook-registry.mjs) ma meno di eseguiProva nel kernel (120s): non è né un controllo rapido né un'intera suite.
49
+ const TIMEOUT_MS = 60_000;
50
+
51
+ /** Pura: costruisce il nome esposto al modello. Un test la esercita senza spawnare nulla. */
52
+ export function nomeEspostoPlugin(pluginId, nomeTool) {
53
+ return `${PREFISSO}${pluginId}${SEPARATORE}${nomeTool}`;
54
+ }
55
+
56
+ /** Pura: l'id qualificato di un hook di plugin, per non collidere con hook standalone o di un altro plugin. */
57
+ export function hookIdQualificato(pluginId, hookId) {
58
+ return `plugin:${pluginId}:${hookId}`;
59
+ }
60
+
61
+ /**
62
+ * Esegue `comando` come sottoprocesso locale (shell, cwd della
63
+ * sessione), passando gli argomenti della tool-call via una variabile
64
+ * d'ambiente (`TALOS_PLUGIN_TOOL_ARGS`, JSON — stesso principio già
65
+ * in uso in `eseguiHook` per `TALOS_HOOK_EVENT`: mai un templating
66
+ * della stringa comando, che aprirebbe a injection).
67
+ *
68
+ * ⭐ Un codice di uscita non-zero è un ESITO del comando, non un
69
+ * guasto del canale — risolve comunque, con l'output annotato, stesso
70
+ * principio già in uso per `shell`/`prova` nel kernel: il modello lo
71
+ * vede e si adatta. Solo un vero guasto di spawn (comando introvabile,
72
+ * permessi) rigetta la Promise — diventa "plugin tool call failed:
73
+ * ..." nel kernel, la stessa distinzione già presa per
74
+ * `chiamaToolMcpFn`.
75
+ */
76
+ export async function eseguiComandoPlugin({ comando, argomenti, cartella }, deps = {}) {
77
+ const [executable, ...args] = parseProcessCommand(comando);
78
+ const envKeys = ['PATH', 'Path', 'PATHEXT', 'SystemRoot', 'WINDIR', 'COMSPEC', 'TALOS_PLUGIN_TOOL_ARGS'];
79
+ const allowedExecutables = deps.allowedExecutables ?? ['node', 'node.exe', 'echo', 'echo.exe'];
80
+ const policy = createProcessPolicy({
81
+ allowedExecutables,
82
+ capabilities: { plugin: cartella },
83
+ envAllowlist: envKeys,
84
+ spawnFn: deps.spawnFn,
85
+ });
86
+ const result = await policy.runApprovedProcess({
87
+ executable,
88
+ args,
89
+ cwd: cartella,
90
+ capability: 'plugin',
91
+ timeoutMs: TIMEOUT_MS,
92
+ envKeys,
93
+ env: { TALOS_PLUGIN_TOOL_ARGS: JSON.stringify(argomenti ?? {}) },
94
+ captureLimitBytes: 64 * 1024,
95
+ });
96
+ const testoFuori = result.stdout.trim();
97
+ const testoErrori = result.stderr.trim();
98
+ if (result.code === 0) return testoFuori || '(nessun output)';
99
+ return [`comando terminato con codice ${result.code}`, testoErrori, testoFuori].filter(Boolean).join('\n');
100
+ }
101
+
102
+ /**
103
+ * Carica i plugin del workspace, li filtra a quelli FIDATI, e torna
104
+ * `{toolPlugin, eseguiToolPluginFn, hookPlugin, falliti}` pronto per
105
+ * `talosLavora`/`costruisciHookFn`.
106
+ *
107
+ * `falliti`: `{pluginId, errore}[]` — mai usata oggi (un plugin fidato
108
+ * non ha un passo di "connessione" che possa fallire, a differenza di
109
+ * MCP) ma tornata per SIMMETRIA con `preparaToolMcpPerSessione` e per
110
+ * non chiudere la porta a un fallimento futuro (es. un `parametri`
111
+ * malformato scoperto solo qui) — un array vuoto oggi è un fatto
112
+ * onesto, non un placeholder.
113
+ */
114
+ export async function preparaToolPluginPerSessione({ cartella, cartellaTrust }, deps = {}) {
115
+ const caricaPluginFn = deps.caricaPluginFn ?? caricaPluginReale;
116
+ const verificaTrustPluginFn = deps.verificaTrustPluginFn ?? verificaTrustPluginReale;
117
+ const eseguiComandoPluginFn = deps.eseguiComandoPluginFn ?? eseguiComandoPlugin;
118
+
119
+ let plugin = [];
120
+ /*
121
+ * ⛔⛔ A-4 (17/09/2026) — `falliti` MORIVA QUI. Questa funzione dichiara di tornare `falliti` e
122
+ * tornava sempre `[]`, perché scartava quello che `caricaPlugin` le dava. Dal secondo giro
123
+ * `caricaPlugin` raccoglie i guasti PER PLUGIN (un collegamento, troppi file, un comando che
124
+ * esce dalla cartella): buttarli qui significa che un pacchetto guasto sparisce dalla sessione
125
+ * senza che niente dica perché — cioè il difetto che quei `falliti` esistono per chiudere.
126
+ * ⛔ Il commento storico qui sotto («mai usata oggi») non vale più: adesso è piena.
127
+ */
128
+ let falliti = [];
129
+ try {
130
+ ({ plugin, falliti = [] } = await caricaPluginFn({ cartella }));
131
+ } catch {
132
+ // ⭐ stesso principio di hook/MCP: un manifesto malformato non blocca la sessione, degrada a "nessun plugin".
133
+ return { toolPlugin: [], eseguiToolPluginFn: null, hookPlugin: [], falliti: [] };
134
+ }
135
+
136
+ const toolPlugin = [];
137
+ const hookPlugin = [];
138
+ const instradamento = new Map(); // nomeEsposto -> { comando }
139
+
140
+ for (const p of plugin) {
141
+ let fidato = false;
142
+ try {
143
+ fidato = await verificaTrustPluginFn({ cartellaTrust, pluginId: p.id, hash: p.hash });
144
+ } catch {
145
+ fidato = false; // un registro di trust che non si legge non autorizza in silenzio
146
+ }
147
+ if (!fidato) continue; // un plugin non fidato è come se non esistesse — zero tool, zero hook
148
+
149
+ for (const t of p.tools) {
150
+ const nomeEsposto = nomeEspostoPlugin(p.id, t.nome);
151
+ toolPlugin.push({ nome: nomeEsposto, descrizione: t.descrizione, parametri: t.parametri });
152
+ /*
153
+ * ⛔⛔⛔ A-3 (17/09/2026): nella mappa ci va l'id VERO, non lo si ricava dal nome esposto.
154
+ * Chi deve riverificare la fiducia prima di eseguire (`agent-service.mjs`) tagliava il
155
+ * nome su `__` e ricostruiva l'id: due verità sulla stessa cosa, che il terzo controllo ha
156
+ * fatto divergere in due modi (un id `a__b` faceva controllare `a`; un id `_sano` non si
157
+ * riconosceva affatto). Qui l'id lo abbiamo in mano: si porta, non si indovina.
158
+ */
159
+ instradamento.set(nomeEsposto, { comando: t.comando, pluginId: p.id });
160
+ }
161
+ for (const h of p.hooks) {
162
+ hookPlugin.push({ id: hookIdQualificato(p.id, h.id), eventi: h.eventi, comando: h.comando });
163
+ }
164
+ }
165
+
166
+ const eseguiToolPluginFn = toolPlugin.length > 0
167
+ ? async (nomeEsposto, argomenti) => {
168
+ const voce = instradamento.get(nomeEsposto);
169
+ if (!voce) throw new Error(`tool di plugin "${nomeEsposto}" non è fra quelli offerti in questa sessione`);
170
+ return eseguiComandoPluginFn({ comando: voce.comando, argomenti, cartella });
171
+ }
172
+ : null;
173
+
174
+ /*
175
+ * ⛔ A-3: `pluginIdDiTool` è la sola strada per sapere DI CHI è un attrezzo. Chi riverifica la
176
+ * fiducia prima di eseguirlo (`agent-service.mjs`) la usa al posto di tagliare il nome
177
+ * esposto: se l'attrezzo non è in questa mappa, non è di questa sessione e non si esegue.
178
+ */
179
+ return { toolPlugin, eseguiToolPluginFn, hookPlugin, falliti, pluginIdDiTool: (n) => instradamento.get(n)?.pluginId ?? null };
180
+ }
@@ -0,0 +1,345 @@
1
+ /**
2
+ * Policy boundary for every host process started by the desktop harness.
3
+ *
4
+ * The adapter deliberately keeps the Node child_process API behind a small,
5
+ * typed surface: callers must name an allowed executable and an explicit
6
+ * working directory; shell execution is never accepted; environment values
7
+ * are allowlisted. The underlying spawn/exec implementation remains
8
+ * injectable so tests never need to start a real process.
9
+ */
10
+ import { createHash } from 'node:crypto';
11
+ import { execFile, execFileSync, spawn } from 'node:child_process';
12
+ import { existsSync } from 'node:fs';
13
+ import { readFile, stat } from 'node:fs/promises';
14
+ import { isAbsolute, relative, resolve, sep } from 'node:path';
15
+
16
+ const DEFAULT_ENV_ALLOWLIST = Object.freeze([
17
+ 'PATH', 'Path', 'PATHEXT', 'SystemRoot', 'WINDIR', 'COMSPEC',
18
+ 'HOME', 'USERPROFILE', 'TMP', 'TEMP', 'LANG', 'LC_ALL',
19
+ ]);
20
+ const DEFAULT_CAPTURE_LIMIT_BYTES = 64 * 1024;
21
+
22
+ export class ProcessPolicyError extends Error {
23
+ constructor(message, code = 'PROCESS_POLICY_REJECTED') {
24
+ super(message);
25
+ this.name = 'ProcessPolicyError';
26
+ this.code = code;
27
+ }
28
+ }
29
+
30
+ function isInside(root, candidate) {
31
+ const difference = relative(resolve(root), resolve(candidate));
32
+ return difference === ''
33
+ || (difference !== '..' && !difference.startsWith(`..${sep}`) && !isAbsolute(difference));
34
+ }
35
+
36
+ function executableKey(command) {
37
+ if (typeof command !== 'string' || command.trim().length === 0 || command.includes('\0')) {
38
+ throw new ProcessPolicyError('Eseguibile non valido', 'EXECUTABLE_INVALID');
39
+ }
40
+ return command.trim().toLowerCase();
41
+ }
42
+
43
+ function validateArgs(args) {
44
+ if (!Array.isArray(args) || args.some((arg) => typeof arg !== 'string' || arg.includes('\0'))) {
45
+ throw new ProcessPolicyError('Argomenti del comando non validi', 'ARGS_INVALID');
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Tokenizza una dichiarazione di comando senza passare da una shell. Le
51
+ * virgolette servono solo a conservare un argomento (ad esempio il codice di
52
+ * `node -e`); metacaratteri di shell fuori dalle virgolette sono rifiutati.
53
+ */
54
+ export function parseProcessCommand(command) {
55
+ if (typeof command !== 'string' || command.trim() === '' || command.includes('\0')) {
56
+ throw new ProcessPolicyError('Comando non valido', 'COMMAND_INVALID');
57
+ }
58
+ const tokens = [];
59
+ let token = '';
60
+ let quoted = false;
61
+ let escaping = false;
62
+ for (const char of command.trim()) {
63
+ if (escaping) { token += char; escaping = false; continue; }
64
+ if (char === '\\' && quoted) { escaping = true; continue; }
65
+ if (char === '"') { quoted = !quoted; continue; }
66
+ if (!quoted && /[&|;<>()]/u.test(char)) {
67
+ throw new ProcessPolicyError('Il comando non può contenere operatori di shell', 'SHELL_SYNTAX_NOT_ALLOWED');
68
+ }
69
+ if (!quoted && /\s/u.test(char)) {
70
+ if (token) { tokens.push(token); token = ''; }
71
+ continue;
72
+ }
73
+ token += char;
74
+ }
75
+ if (escaping) token += '\\';
76
+ if (quoted) throw new ProcessPolicyError('Virgolette non bilanciate', 'COMMAND_INVALID');
77
+ if (token) tokens.push(token);
78
+ if (tokens.length === 0) throw new ProcessPolicyError('Comando non valido', 'COMMAND_INVALID');
79
+ return tokens;
80
+ }
81
+
82
+ function validateTimeout(timeout) {
83
+ if (timeout === undefined) return;
84
+ if (!Number.isInteger(timeout) || timeout <= 0) {
85
+ throw new ProcessPolicyError('Durata massima del comando non valida', 'TIMEOUT_INVALID');
86
+ }
87
+ }
88
+
89
+ function buildEnvironment(env, allowlist) {
90
+ if (env !== undefined && (env === null || typeof env !== 'object' || Array.isArray(env))) {
91
+ throw new ProcessPolicyError('Ambiente del comando non valido', 'ENV_INVALID');
92
+ }
93
+ const allowed = new Set(allowlist);
94
+ const source = { ...process.env, ...(env ?? {}) };
95
+ return Object.fromEntries(Object.entries(source).filter(([key]) => allowed.has(key)));
96
+ }
97
+
98
+ function validateCwd(cwd, cwdRoot) {
99
+ if (typeof cwd !== 'string' || cwd.length === 0 || cwd.includes('\0') || !isAbsolute(cwd)) {
100
+ throw new ProcessPolicyError('Cartella di lavoro esplicita richiesta', 'CWD_REQUIRED');
101
+ }
102
+ const resolved = resolve(cwd);
103
+ if (cwdRoot && !isInside(cwdRoot, resolved)) {
104
+ throw new ProcessPolicyError('Cartella di lavoro fuori dall’area autorizzata', 'CWD_NOT_ALLOWED');
105
+ }
106
+ return resolved;
107
+ }
108
+
109
+ function validateCaptureLimit(value) {
110
+ if (value === undefined) return DEFAULT_CAPTURE_LIMIT_BYTES;
111
+ if (!Number.isSafeInteger(value) || value <= 0) {
112
+ throw new ProcessPolicyError('Limite output non valida', 'CAPTURE_LIMIT_INVALID');
113
+ }
114
+ return value;
115
+ }
116
+
117
+ function appendBounded(current, chunk, limit) {
118
+ const text = Buffer.isBuffer(chunk) ? chunk.toString('utf8') : String(chunk);
119
+ const remaining = limit - Buffer.byteLength(current, 'utf8');
120
+ if (remaining <= 0) return { value: current, truncated: true };
121
+ const bytes = Buffer.from(text, 'utf8');
122
+ if (bytes.byteLength <= remaining) return { value: current + text, truncated: false };
123
+ return { value: current + bytes.subarray(0, remaining).toString('utf8'), truncated: true };
124
+ }
125
+
126
+ function terminateChild(child) {
127
+ if (!child || typeof child.kill !== 'function') return;
128
+ try { child.kill('SIGTERM'); } catch { /* il processo può essersi chiuso tra controllo e kill */ }
129
+ }
130
+
131
+ /**
132
+ * Risolve un binario configurato soltanto se è un file assoluto realmente
133
+ * presente. Il digest opzionale rende il pin verificabile senza esporre il
134
+ * contenuto del file al chiamante.
135
+ */
136
+ export async function resolveApprovedExecutable({ id, configuredPath, expectedSha256 } = {}, deps = {}) {
137
+ if (typeof id !== 'string' || id.trim() === '' || typeof configuredPath !== 'string'
138
+ || !configuredPath.trim() || !isAbsolute(configuredPath) || configuredPath.includes('\0')) {
139
+ throw new ProcessPolicyError('Percorso dell’eseguibile non valido', 'EXECUTABLE_PATH_INVALID');
140
+ }
141
+ if (expectedSha256 !== undefined && !/^[a-f0-9]{64}$/iu.test(expectedSha256)) {
142
+ throw new ProcessPolicyError('Digest dell’eseguibile non valido', 'EXECUTABLE_DIGEST_INVALID');
143
+ }
144
+ const statFn = deps.statFn ?? stat;
145
+ const readFileFn = deps.readFileFn ?? readFile;
146
+ const path = resolve(configuredPath);
147
+ let info;
148
+ try { info = await statFn(path); } catch { throw new ProcessPolicyError('Eseguibile configurato non trovato', 'EXECUTABLE_NOT_FOUND'); }
149
+ if (!info?.isFile?.()) throw new ProcessPolicyError('Il percorso configurato non è un file', 'EXECUTABLE_NOT_FILE');
150
+ let sha256 = null;
151
+ if (expectedSha256 !== undefined) {
152
+ const contents = await readFileFn(path);
153
+ sha256 = createHash('sha256').update(contents).digest('hex');
154
+ if (sha256.toLowerCase() !== expectedSha256.toLowerCase()) {
155
+ throw new ProcessPolicyError('Digest dell’eseguibile non corrisponde', 'EXECUTABLE_DIGEST_MISMATCH');
156
+ }
157
+ }
158
+ return Object.freeze({ id: id.trim(), path, sha256 });
159
+ }
160
+
161
+ /**
162
+ * @param {{allowedExecutables?:string[], cwdRoot?:string|null, capabilities?:Record<string,string>, envAllowlist?:string[], spawnFn?:typeof spawn, execFileFn?:typeof execFile, execFileSyncFn?:typeof execFileSync}} [options]
163
+ */
164
+ export function createProcessPolicy({
165
+ allowedExecutables = [],
166
+ cwdRoot = null,
167
+ capabilities = {},
168
+ envAllowlist = DEFAULT_ENV_ALLOWLIST,
169
+ spawnFn = spawn,
170
+ execFileFn = execFile,
171
+ execFileSyncFn = execFileSync,
172
+ /*
173
+ * ⛔ BC-64 (17/09/2026) — `windowsHide: true` NON nasconde solo la console: libuv lo traduce in
174
+ * STARTF_USESHOWWINDOW + SW_HIDE, e un programma con finestra che onora quell'avvio nasce INVISIBILE.
175
+ * Misurato su questa macchina nei due versi con `explorer.exe /select,<file>`: con `true` la finestra di
176
+ * Esplora esiste ma `Visible=False` (l'owner: «non apre nessuna finestra»), con `false` `Visible=True`.
177
+ * È lo stesso motivo per cui Node ha revocato il default a `true` (nodejs/node PR #24034, letta il 17/09/2026).
178
+ * ⇒ Il default resta `true` — un processo di servizio non deve far lampeggiare una console — e chi lancia
179
+ * apposta un programma CHE LA PERSONA DEVE VEDERE lo dichiara qui, per nome, alla nascita della politica.
180
+ */
181
+ finestreVisibili = false,
182
+ } = {}) {
183
+ if (typeof finestreVisibili !== 'boolean') throw new ProcessPolicyError('finestreVisibili deve essere un booleano', 'POLICY_INVALID');
184
+ const approved = new Set(allowedExecutables.map((value) => executableKey(value)));
185
+ if (cwdRoot !== null && (typeof cwdRoot !== 'string' || !isAbsolute(cwdRoot))) {
186
+ throw new ProcessPolicyError('Radice delle cartelle di lavoro non valida', 'CWD_ROOT_INVALID');
187
+ }
188
+ const environmentKeys = [...new Set(envAllowlist)];
189
+ if (!capabilities || typeof capabilities !== 'object' || Array.isArray(capabilities)) {
190
+ throw new ProcessPolicyError('Capability di processo non valide', 'CAPABILITIES_INVALID');
191
+ }
192
+ const capabilityRoots = new Map(Object.entries(capabilities).map(([name, root]) => {
193
+ if (typeof name !== 'string' || !name || typeof root !== 'string' || !isAbsolute(root)) {
194
+ throw new ProcessPolicyError('Capability di processo non valida', 'CAPABILITIES_INVALID');
195
+ }
196
+ return [name, resolve(root)];
197
+ }));
198
+
199
+ function prepare(command, args, options = {}) {
200
+ const key = executableKey(command);
201
+ if (!approved.has(key)) throw new ProcessPolicyError('Eseguibile non autorizzato', 'EXECUTABLE_NOT_ALLOWED');
202
+ validateArgs(args);
203
+ if (options.shell === true) throw new ProcessPolicyError('I comandi tramite shell non sono consentiti', 'SHELL_NOT_ALLOWED');
204
+ const cwd = validateCwd(options.cwd, cwdRoot);
205
+ validateTimeout(options.timeout);
206
+ return {
207
+ command,
208
+ args,
209
+ options: {
210
+ ...options,
211
+ cwd,
212
+ shell: false,
213
+ env: buildEnvironment(options.env, environmentKeys),
214
+ windowsHide: !finestreVisibili,
215
+ },
216
+ };
217
+ }
218
+
219
+ function prepareApprovedProcess({ executable, args = [], cwd, envKeys, timeoutMs, signal, capability, captureLimitBytes, env } = {}) {
220
+ if (typeof capability !== 'string' || capability.trim() === '') {
221
+ throw new ProcessPolicyError('Capability esplicita richiesta', 'CAPABILITY_REQUIRED');
222
+ }
223
+ const capabilityRoot = capabilityRoots.get(capability);
224
+ if (!capabilityRoot) throw new ProcessPolicyError('Capability non autorizzata', 'CAPABILITY_NOT_ALLOWED');
225
+ const requestedCwd = validateCwd(cwd, capabilityRoot);
226
+ if (!existsSync(requestedCwd)) {
227
+ throw new ProcessPolicyError('Cartella di lavoro non trovata', 'CWD_NOT_FOUND');
228
+ }
229
+ const keys = envKeys === undefined ? environmentKeys : envKeys;
230
+ if (!Array.isArray(keys) || keys.some((key) => typeof key !== 'string')) {
231
+ throw new ProcessPolicyError('Elenco ambiente non valido', 'ENV_KEYS_INVALID');
232
+ }
233
+ const allowedKeys = keys.filter((key) => environmentKeys.includes(key));
234
+ const options = {
235
+ cwd: requestedCwd,
236
+ env: buildEnvironment(env, allowedKeys),
237
+ timeout: timeoutMs,
238
+ signal,
239
+ captureLimitBytes: validateCaptureLimit(captureLimitBytes),
240
+ shell: false,
241
+ windowsHide: true,
242
+ stdio: ['ignore', 'pipe', 'pipe'],
243
+ };
244
+ const prepared = prepare(executable, args, options);
245
+ return { ...prepared, capability };
246
+ }
247
+
248
+ async function runApprovedProcess(request = {}) {
249
+ const prepared = prepareApprovedProcess(request);
250
+ const limit = prepared.options.captureLimitBytes;
251
+ let child;
252
+ try {
253
+ child = spawnFn(prepared.command, prepared.args, prepared.options);
254
+ } catch (error) {
255
+ throw new ProcessPolicyError(`Impossibile avviare il comando: ${error?.message || 'errore sconosciuto'}`, 'PROCESS_START_FAILED');
256
+ }
257
+ if (!child || typeof child.once !== 'function') {
258
+ throw new ProcessPolicyError('Il processo non ha restituito un canale valido', 'PROCESS_START_FAILED');
259
+ }
260
+ return new Promise((resolveResult, rejectResult) => {
261
+ let stdout = '';
262
+ let stderr = '';
263
+ let outputTruncated = false;
264
+ let timedOut = false;
265
+ let aborted = false;
266
+ let settled = false;
267
+ let spawnError = null;
268
+ let timer;
269
+ let onAbort;
270
+ const cleanup = () => {
271
+ if (timer) clearTimeout(timer);
272
+ if (prepared.options.signal && onAbort) prepared.options.signal.removeEventListener('abort', onAbort);
273
+ child.stdout?.destroy?.();
274
+ child.stderr?.destroy?.();
275
+ };
276
+ const finish = (code = null, signalValue = null) => {
277
+ if (settled) return;
278
+ settled = true;
279
+ cleanup();
280
+ resolveResult({ code, signal: signalValue, stdout, stderr, outputTruncated, timedOut, aborted });
281
+ };
282
+ const capture = (stream, chunk) => {
283
+ const next = appendBounded(stream === 'stdout' ? stdout : stderr, chunk, limit);
284
+ if (stream === 'stdout') stdout = next.value; else stderr = next.value;
285
+ if (next.truncated) {
286
+ outputTruncated = true;
287
+ terminateChild(child);
288
+ }
289
+ };
290
+ child.stdout?.on('data', (chunk) => capture('stdout', chunk));
291
+ child.stderr?.on('data', (chunk) => capture('stderr', chunk));
292
+ child.once('close', (code, signalValue) => {
293
+ if (spawnError && spawnError.code !== 'ENOENT') {
294
+ if (settled) return;
295
+ settled = true;
296
+ cleanup();
297
+ rejectResult(new ProcessPolicyError(`Processo non disponibile: ${spawnError?.message || 'errore sconosciuto'}`, 'PROCESS_FAILED'));
298
+ return;
299
+ }
300
+ finish(spawnError?.code === 'ENOENT' ? -1 : code, spawnError?.code === 'ENOENT' ? 'ENOENT' : signalValue);
301
+ });
302
+ child.once('error', (error) => {
303
+ if (settled) return;
304
+ spawnError = error;
305
+ // Su Windows un avvio fallito può lasciare un handle del job anche
306
+ // dopo l'evento error; il processo non deve restare orfano mentre
307
+ // attendiamo il close definitivo.
308
+ child.unref?.();
309
+ });
310
+ if (Number.isInteger(prepared.options.timeout) && prepared.options.timeout > 0) {
311
+ timer = setTimeout(() => { timedOut = true; terminateChild(child); }, prepared.options.timeout);
312
+ timer.unref?.();
313
+ }
314
+ if (prepared.options.signal) {
315
+ onAbort = () => { aborted = true; terminateChild(child); };
316
+ if (prepared.options.signal.aborted) onAbort();
317
+ else prepared.options.signal.addEventListener('abort', onAbort, { once: true });
318
+ }
319
+ });
320
+ }
321
+
322
+ return Object.freeze({
323
+ spawn(command, args = [], options = {}) {
324
+ const prepared = prepare(command, args, options);
325
+ return spawnFn(prepared.command, prepared.args, prepared.options);
326
+ },
327
+ execFile(command, args = [], options = {}, callback) {
328
+ const prepared = prepare(command, args, options);
329
+ return execFileFn(prepared.command, prepared.args, prepared.options, callback);
330
+ },
331
+ execFileSync(command, args = [], options = {}) {
332
+ const prepared = prepare(command, args, options);
333
+ return execFileSyncFn(prepared.command, prepared.args, prepared.options);
334
+ },
335
+ runApprovedProcess,
336
+ });
337
+ }
338
+
339
+ /** Convenience entry point for callers that already own a configured policy. */
340
+ export function runApprovedProcess(request, { policy } = {}) {
341
+ if (!policy || typeof policy.runApprovedProcess !== 'function') {
342
+ throw new ProcessPolicyError('Policy di processo richiesta', 'POLICY_REQUIRED');
343
+ }
344
+ return policy.runApprovedProcess(request);
345
+ }
@@ -0,0 +1,94 @@
1
+ import { risolviDestinazioneModello } from './model-destination.mjs';
2
+ import { nativeProviderResponse } from './native-provider-adapter.mjs';
3
+
4
+ function erroreApi(message, code) {
5
+ return Object.assign(new Error(message), { code });
6
+ }
7
+
8
+ function mappaErroreDestinazione(errore) {
9
+ if (errore?.code === 'PROVIDER_KEY_MISSING') {
10
+ return erroreApi('Manca la credenziale del provider usato da questa chat. Collegala in Impostazioni → Provider, poi riprova.', 'PROVIDER_KEY_REQUIRED');
11
+ }
12
+ if (errore?.code === 'MODEL_DESTINATION_INVALID' || errore?.code === 'MODEL_DESTINATION_MISCONFIGURED') {
13
+ return erroreApi('Il modello di questa chat non ha una destinazione valida.', 'PROVIDER_RUNTIME_UNAVAILABLE');
14
+ }
15
+ if (typeof errore?.code === 'string' && errore.code.startsWith('PROVIDER_')) {
16
+ return erroreApi('Il provider di questa chat non è disponibile per la riscrittura.', 'PROVIDER_RUNTIME_UNAVAILABLE');
17
+ }
18
+ return errore;
19
+ }
20
+
21
+ /**
22
+ * Invia Prompt Enhance allo stesso provider scelto dalla sessione.
23
+ *
24
+ * La rotta HTTP possiede sessione e contratto API; questo modulo possiede solo
25
+ * l'instradamento del trasporto, riusando la stessa fonte di verità della chat.
26
+ */
27
+ export async function chiediMiglioramentoAlProvider({ modello, messaggi, providerStore, fetchFn = globalThis.fetch } = {}) {
28
+ if (typeof modello !== 'string' || modello.trim() === '') {
29
+ throw erroreApi('Questa sessione non dichiara un modello.', 'SESSION_NOT_READY');
30
+ }
31
+ if (!providerStore || typeof providerStore.getKey !== 'function' || typeof providerStore.getRuntime !== 'function') {
32
+ throw erroreApi('Il portachiavi dei provider non è configurato.', 'PROVIDER_STORE_UNAVAILABLE');
33
+ }
34
+ if (typeof fetchFn !== 'function') {
35
+ throw erroreApi('Il trasporto del provider non è configurato.', 'PROVIDER_RUNTIME_UNAVAILABLE');
36
+ }
37
+
38
+ let destinazione;
39
+ try {
40
+ destinazione = risolviDestinazioneModello(modello, {
41
+ leggiChiave: (provider) => providerStore.getKey(provider),
42
+ leggiRuntime: (provider) => providerStore.getRuntime(provider),
43
+ localePronto: () => false,
44
+ });
45
+ } catch (errore) {
46
+ throw mappaErroreDestinazione(errore);
47
+ }
48
+
49
+ if (destinazione.locale || destinazione.esterno) {
50
+ throw erroreApi('Il provider di questa chat non è disponibile per la riscrittura.', 'PROVIDER_RUNTIME_UNAVAILABLE');
51
+ }
52
+
53
+ const body = {
54
+ model: destinazione.modelloRemoto,
55
+ messages: messaggi,
56
+ stream: false,
57
+ max_tokens: 2048,
58
+ };
59
+
60
+ let risposta;
61
+ try {
62
+ if (destinazione.native) {
63
+ risposta = await nativeProviderResponse({
64
+ provider: destinazione.fonte,
65
+ model: destinazione.modelloRemoto,
66
+ apiKey: destinazione.apiKey,
67
+ baseURL: destinazione.baseURL,
68
+ body,
69
+ fetchFn,
70
+ });
71
+ } else {
72
+ risposta = await fetchFn(destinazione.url, {
73
+ method: 'POST',
74
+ headers: { Accept: 'application/json', ...destinazione.headers },
75
+ body: JSON.stringify(body),
76
+ });
77
+ }
78
+ } catch {
79
+ throw erroreApi('Il provider di questa chat non ha risposto.', 'PROVIDER_RUNTIME_UNAVAILABLE');
80
+ }
81
+
82
+ if (!risposta?.ok) {
83
+ throw erroreApi(`Il provider di questa chat ha risposto ${risposta?.status ?? '?'}.`, 'PROVIDER_RUNTIME_UNAVAILABLE');
84
+ }
85
+
86
+ let letto;
87
+ try { letto = await risposta.json(); } catch { letto = null; }
88
+ const contenuto = typeof letto?.choices?.[0]?.message?.content === 'string' ? letto.choices[0].message.content : '';
89
+ return {
90
+ contenuto,
91
+ modelloUsato: modello,
92
+ fornitoreUsato: destinazione.fonte,
93
+ };
94
+ }