talos-code 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (401) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +111 -3
  3. package/THIRD_PARTY_NOTICES.md +40 -0
  4. package/dist/archive/zip.js +73 -0
  5. package/dist/args.js +97 -0
  6. package/dist/automations/history-store.js +34 -0
  7. package/dist/automations/policy-store.js +43 -0
  8. package/dist/automations/runner.js +107 -0
  9. package/dist/automations/schedule.js +85 -0
  10. package/dist/automations/windows-task.js +53 -0
  11. package/dist/commands/advanced-cli.js +233 -0
  12. package/dist/commands/checkpoint-cli.js +45 -0
  13. package/dist/commands/config-cli.js +107 -0
  14. package/dist/commands/context.js +17 -0
  15. package/dist/commands/extensions-cli.js +207 -0
  16. package/dist/commands/project-cli.js +74 -0
  17. package/dist/commands/project-commands.js +143 -0
  18. package/dist/commands/provider-cli.js +185 -0
  19. package/dist/commands/services-cli.js +248 -0
  20. package/dist/commands/session-cli.js +171 -0
  21. package/dist/commands/system-cli.js +405 -0
  22. package/dist/config/commands.js +60 -0
  23. package/dist/config/load.js +382 -0
  24. package/dist/config/migrations.js +48 -0
  25. package/dist/config/types.js +11 -0
  26. package/dist/diagnostics/development-log.js +154 -0
  27. package/dist/diagnostics/doctor.js +104 -0
  28. package/dist/diagnostics/redact.js +80 -0
  29. package/dist/diagnostics/zip.js +52 -0
  30. package/dist/errors.js +156 -0
  31. package/dist/events/bridge.js +130 -0
  32. package/dist/extensions/installer.js +178 -0
  33. package/dist/extensions/package-schema.js +24 -0
  34. package/dist/headless/result.js +84 -0
  35. package/dist/headless/run.js +230 -0
  36. package/dist/i18n/en/approval.js +43 -0
  37. package/dist/i18n/en/common.js +9 -0
  38. package/dist/i18n/en/credentials.js +82 -0
  39. package/dist/i18n/en/errors.js +246 -0
  40. package/dist/i18n/en/firstrun.js +89 -0
  41. package/dist/i18n/en/providers.js +37 -0
  42. package/dist/i18n/en/screen.js +736 -0
  43. package/dist/i18n/en/tools.js +127 -0
  44. package/dist/i18n/en.js +14 -0
  45. package/dist/i18n/error-view.js +307 -0
  46. package/dist/i18n/index.js +19 -0
  47. package/dist/i18n/kernel-map.js +139 -0
  48. package/dist/io.js +45 -0
  49. package/dist/main.js +330 -0
  50. package/dist/paths.js +41 -0
  51. package/dist/protocol/v2/codec.js +9 -0
  52. package/dist/protocol/v2/events.js +555 -0
  53. package/dist/protocol/v2/index.js +4 -0
  54. package/dist/protocol/v2/replay.js +28 -0
  55. package/dist/protocol/v2/types.js +1 -0
  56. package/dist/provider/control-plane.js +135 -0
  57. package/dist/provider/environment-keys.js +275 -0
  58. package/dist/provider/health.js +110 -0
  59. package/dist/provider/missing-key.js +48 -0
  60. package/dist/provider/model-catalog.js +168 -0
  61. package/dist/provider/provider-text.js +13 -0
  62. package/dist/provider/store.js +95 -0
  63. package/dist/provider/system-keyring.js +214 -0
  64. package/dist/runtime/active-run.js +63 -0
  65. package/dist/runtime/agent-tree.js +74 -0
  66. package/dist/runtime/attachments.js +84 -0
  67. package/dist/runtime/brokered-executor.js +395 -0
  68. package/dist/runtime/context-status.js +76 -0
  69. package/dist/runtime/create-runtime.js +111 -0
  70. package/dist/runtime/model-profile.js +361 -0
  71. package/dist/runtime/output-store.js +137 -0
  72. package/dist/runtime/provider-attempts.js +185 -0
  73. package/dist/runtime/replay-buffer.js +153 -0
  74. package/dist/runtime/repo.js +95 -0
  75. package/dist/runtime/session-facade.js +135 -0
  76. package/dist/runtime/session-summary.js +125 -0
  77. package/dist/runtime/supervisor.js +262 -0
  78. package/dist/runtime/talos-composition.js +1006 -0
  79. package/dist/runtime/types.js +5 -0
  80. package/dist/runtime/usage-snapshot.js +82 -0
  81. package/dist/security/auto-classifier.js +38 -0
  82. package/dist/security/credential-free-environment.js +54 -0
  83. package/dist/security/evaluate.js +243 -0
  84. package/dist/security/execution-backends.js +236 -0
  85. package/dist/security/execution-broker.js +102 -0
  86. package/dist/security/forge-scan.js +74 -0
  87. package/dist/security/from-approval.js +39 -0
  88. package/dist/security/mxc-execution-backend.js +281 -0
  89. package/dist/security/permission-engine.js +138 -0
  90. package/dist/security/permission-explanation.js +54 -0
  91. package/dist/security/persist.js +179 -0
  92. package/dist/security/plugin-guard.js +230 -0
  93. package/dist/security/process-tree-evidence-store.js +74 -0
  94. package/dist/security/process-tree-probe.js +554 -0
  95. package/dist/security/project-resource-inventory.js +186 -0
  96. package/dist/security/project-trust-gate.js +38 -0
  97. package/dist/security/project-trust.js +367 -0
  98. package/dist/security/rule-parser.js +201 -0
  99. package/dist/security/shell-segmentation.js +68 -0
  100. package/dist/security/trust-authority.js +324 -0
  101. package/dist/security/types.js +1 -0
  102. package/dist/security/workspace-identity.js +102 -0
  103. package/dist/services/automation-facade.js +59 -0
  104. package/dist/services/forge-facade.js +77 -0
  105. package/dist/services/hook-facade.js +240 -0
  106. package/dist/services/index.js +16 -0
  107. package/dist/services/library-facade.js +174 -0
  108. package/dist/services/mcp-facade.js +348 -0
  109. package/dist/services/memory-facade.js +126 -0
  110. package/dist/services/notes-facade.js +157 -0
  111. package/dist/services/plugin-facade.js +308 -0
  112. package/dist/services/research-facade.js +110 -0
  113. package/dist/services/task-board-facade.js +236 -0
  114. package/dist/services/workflow-catalog.js +246 -0
  115. package/dist/sessions/export-format.js +98 -0
  116. package/dist/sessions/metadata-store.js +160 -0
  117. package/dist/sessions/share.js +122 -0
  118. package/dist/sessions/transfer.js +16 -0
  119. package/dist/subcommands.js +62 -0
  120. package/dist/tui/agent-roster.js +36 -0
  121. package/dist/tui/app.js +3761 -0
  122. package/dist/tui/approval.js +36 -0
  123. package/dist/tui/boot/boot-sequence.js +76 -0
  124. package/dist/tui/boot/cinematic.js +243 -0
  125. package/dist/tui/boot/desktop-logo.js +82 -0
  126. package/dist/tui/boot.js +3 -0
  127. package/dist/tui/busy-input.js +58 -0
  128. package/dist/tui/catalog-service.js +559 -0
  129. package/dist/tui/components/assistant-stream.js +1 -0
  130. package/dist/tui/components/command-menu.js +68 -0
  131. package/dist/tui/components/composer.js +219 -0
  132. package/dist/tui/components/diff.js +35 -0
  133. package/dist/tui/components/footer.js +48 -0
  134. package/dist/tui/components/header.js +6 -0
  135. package/dist/tui/components/markdown.js +305 -0
  136. package/dist/tui/components/status-indicator.js +32 -0
  137. package/dist/tui/components/terminal-shell.js +205 -0
  138. package/dist/tui/components/thinking-row.js +19 -0
  139. package/dist/tui/components/tool-row.js +97 -0
  140. package/dist/tui/components/transcript-virtualizer.js +165 -0
  141. package/dist/tui/components/transcript.js +43 -0
  142. package/dist/tui/diff-model.js +77 -0
  143. package/dist/tui/editor-history.js +21 -0
  144. package/dist/tui/editor.js +210 -0
  145. package/dist/tui/event-adapter.js +436 -0
  146. package/dist/tui/exit-output.js +58 -0
  147. package/dist/tui/external-editor.js +53 -0
  148. package/dist/tui/file-completion.js +89 -0
  149. package/dist/tui/focus-manager.js +5 -0
  150. package/dist/tui/highlight.js +30 -0
  151. package/dist/tui/input-router.js +18 -0
  152. package/dist/tui/interrupt.js +99 -0
  153. package/dist/tui/keybindings.js +194 -0
  154. package/dist/tui/keymap-resolver.js +91 -0
  155. package/dist/tui/launch-state.js +139 -0
  156. package/dist/tui/line-diff.js +57 -0
  157. package/dist/tui/live-activity.js +45 -0
  158. package/dist/tui/metrics.js +123 -0
  159. package/dist/tui/onboarding.js +36 -0
  160. package/dist/tui/overlays/agent-tree.js +39 -0
  161. package/dist/tui/overlays/approval-dialog.js +640 -0
  162. package/dist/tui/overlays/automation-center.js +51 -0
  163. package/dist/tui/overlays/checkpoint-picker.js +47 -0
  164. package/dist/tui/overlays/context-inspector.js +36 -0
  165. package/dist/tui/overlays/effort-line.js +110 -0
  166. package/dist/tui/overlays/forge-center.js +46 -0
  167. package/dist/tui/overlays/help-dialog.js +16 -0
  168. package/dist/tui/overlays/history-picker.js +37 -0
  169. package/dist/tui/overlays/hook-center.js +70 -0
  170. package/dist/tui/overlays/library-center.js +55 -0
  171. package/dist/tui/overlays/mcp-center.js +60 -0
  172. package/dist/tui/overlays/memory-center.js +63 -0
  173. package/dist/tui/overlays/model-picker.js +72 -0
  174. package/dist/tui/overlays/notes-center.js +53 -0
  175. package/dist/tui/overlays/overlay-host.js +8 -0
  176. package/dist/tui/overlays/plugin-center.js +76 -0
  177. package/dist/tui/overlays/provider-picker.js +145 -0
  178. package/dist/tui/overlays/queue-editor.js +32 -0
  179. package/dist/tui/overlays/research-center.js +59 -0
  180. package/dist/tui/overlays/scroll-window.js +234 -0
  181. package/dist/tui/overlays/session-picker.js +115 -0
  182. package/dist/tui/overlays/tasks-center.js +83 -0
  183. package/dist/tui/overlays/theme-picker.js +21 -0
  184. package/dist/tui/overlays/transcript-search.js +58 -0
  185. package/dist/tui/overlays/trust-center.js +29 -0
  186. package/dist/tui/overlays/workflow-center.js +46 -0
  187. package/dist/tui/project-file-index.js +214 -0
  188. package/dist/tui/project-references.js +85 -0
  189. package/dist/tui/project-trust-prompt.js +287 -0
  190. package/dist/tui/prompt-history-store.js +116 -0
  191. package/dist/tui/queue-store.js +110 -0
  192. package/dist/tui/regions/budget.js +59 -0
  193. package/dist/tui/regions/views.js +96 -0
  194. package/dist/tui/render-coordinator.js +148 -0
  195. package/dist/tui/render-scheduler.js +4 -0
  196. package/dist/tui/run.js +69 -0
  197. package/dist/tui/selection-list.js +29 -0
  198. package/dist/tui/session-controller.js +778 -0
  199. package/dist/tui/session-export.js +54 -0
  200. package/dist/tui/shell-input.js +35 -0
  201. package/dist/tui/shell-layout.js +48 -0
  202. package/dist/tui/shell-model.js +98 -0
  203. package/dist/tui/slash-commands.js +80 -0
  204. package/dist/tui/state.js +151 -0
  205. package/dist/tui/status-bar.js +125 -0
  206. package/dist/tui/status-view.js +40 -0
  207. package/dist/tui/terminal-capabilities.js +9 -0
  208. package/dist/tui/terminal-session.js +11 -0
  209. package/dist/tui/text-width.js +66 -0
  210. package/dist/tui/theme-catalog.js +25 -0
  211. package/dist/tui/theme-store.js +23 -0
  212. package/dist/tui/theme.js +23 -0
  213. package/dist/tui/tool-display.js +135 -0
  214. package/dist/tui/tool-facts.js +1 -0
  215. package/dist/tui/tools/bash-renderer.js +32 -0
  216. package/dist/tui/tools/change.js +61 -0
  217. package/dist/tui/tools/edit-renderer.js +17 -0
  218. package/dist/tui/tools/generic-renderer.js +13 -0
  219. package/dist/tui/tools/list-renderer.js +14 -0
  220. package/dist/tui/tools/read-renderer.js +13 -0
  221. package/dist/tui/tools/registry.js +20 -0
  222. package/dist/tui/tools/row-format.js +187 -0
  223. package/dist/tui/tools/search-renderer.js +38 -0
  224. package/dist/tui/tools/shared.js +97 -0
  225. package/dist/tui/tools/write-renderer.js +15 -0
  226. package/dist/tui/transcript-model.js +441 -0
  227. package/dist/tui/ui-preferences.js +79 -0
  228. package/dist/tui/usage-view.js +77 -0
  229. package/dist/tui/vim-mode.js +99 -0
  230. package/dist/update/check.js +15 -0
  231. package/dist/update/npm.js +51 -0
  232. package/dist/update/run.js +129 -0
  233. package/dist/version.js +2 -0
  234. package/dist/workspace/checkpoint-store.js +210 -0
  235. package/dist/workspace/checkpoint.js +413 -0
  236. package/dist/workspace/restore.js +232 -0
  237. package/package.json +63 -5
  238. package/vendor/context-engine/package.json +11 -0
  239. package/vendor/context-engine/src/compaction-planner.mjs +57 -0
  240. package/vendor/context-engine/src/contracts.mjs +48 -0
  241. package/vendor/context-engine/src/engine.mjs +445 -0
  242. package/vendor/context-engine/src/node/context-export.mjs +164 -0
  243. package/vendor/context-engine/src/node/legacy-import.mjs +92 -0
  244. package/vendor/context-engine/src/node/migrations/001-context.sql +126 -0
  245. package/vendor/context-engine/src/node/sqlite-store.mjs +85 -0
  246. package/vendor/context-engine/src/node/sqlite-worker.mjs +559 -0
  247. package/vendor/context-engine/src/profiles.mjs +10 -0
  248. package/vendor/context-engine/src/retrieval.mjs +104 -0
  249. package/vendor/context-engine/src/summary.mjs +97 -0
  250. package/vendor/context-engine/src/usage.mjs +34 -0
  251. package/vendor/harness-ui/package.json +38 -0
  252. package/vendor/harness-ui/src/acp-agent.mjs +350 -0
  253. package/vendor/harness-ui/src/agent-service.mjs +2188 -0
  254. package/vendor/harness-ui/src/agui-events.mjs +452 -0
  255. package/vendor/harness-ui/src/ambiente-solo-server.mjs +121 -0
  256. package/vendor/harness-ui/src/artifact-store.mjs +39 -0
  257. package/vendor/harness-ui/src/assistenza.mjs +123 -0
  258. package/vendor/harness-ui/src/automation-scheduler.mjs +69 -0
  259. package/vendor/harness-ui/src/automation-store.mjs +145 -0
  260. package/vendor/harness-ui/src/browser-annota.mjs +639 -0
  261. package/vendor/harness-ui/src/browser-frame.mjs +211 -0
  262. package/vendor/harness-ui/src/browser-proxy-universale.mjs +519 -0
  263. package/vendor/harness-ui/src/browser-proxy.mjs +87 -0
  264. package/vendor/harness-ui/src/browser-sessione-viva.mjs +329 -0
  265. package/vendor/harness-ui/src/browser-stream.mjs +445 -0
  266. package/vendor/harness-ui/src/browser-vivo.mjs +694 -0
  267. package/vendor/harness-ui/src/chat-image-attachments.mjs +72 -0
  268. package/vendor/harness-ui/src/config.mjs +697 -0
  269. package/vendor/harness-ui/src/contesto-del-progetto.mjs +385 -0
  270. package/vendor/harness-ui/src/context-asset-adapter.mjs +72 -0
  271. package/vendor/harness-ui/src/context-desktop-service.mjs +253 -0
  272. package/vendor/harness-ui/src/context-embedding-runtime.mjs +252 -0
  273. package/vendor/harness-ui/src/context-inference-scheduler.mjs +81 -0
  274. package/vendor/harness-ui/src/context-native-compaction.mjs +75 -0
  275. package/vendor/harness-ui/src/context-provider-adapter.mjs +141 -0
  276. package/vendor/harness-ui/src/context-runtime.mjs +118 -0
  277. package/vendor/harness-ui/src/context-token-counters.mjs +184 -0
  278. package/vendor/harness-ui/src/context-tool-catalog.mjs +86 -0
  279. package/vendor/harness-ui/src/context-tool-output.mjs +72 -0
  280. package/vendor/harness-ui/src/costo-elenco.mjs +252 -0
  281. package/vendor/harness-ui/src/custom-task.mjs +171 -0
  282. package/vendor/harness-ui/src/doctor.mjs +142 -0
  283. package/vendor/harness-ui/src/document-filename.mjs +97 -0
  284. package/vendor/harness-ui/src/document-generator.mjs +493 -0
  285. package/vendor/harness-ui/src/document-report.mjs +331 -0
  286. package/vendor/harness-ui/src/duckduckgo-search.mjs +155 -0
  287. package/vendor/harness-ui/src/elenco-profondo.mjs +337 -0
  288. package/vendor/harness-ui/src/favicon-proxy.mjs +113 -0
  289. package/vendor/harness-ui/src/forge-contract.mjs +221 -0
  290. package/vendor/harness-ui/src/frequent-dirs.mjs +134 -0
  291. package/vendor/harness-ui/src/generated-image-store.mjs +147 -0
  292. package/vendor/harness-ui/src/generation-idle.mjs +332 -0
  293. package/vendor/harness-ui/src/gguf-header.mjs +207 -0
  294. package/vendor/harness-ui/src/git-service.mjs +626 -0
  295. package/vendor/harness-ui/src/gitignore-elenco.mjs +604 -0
  296. package/vendor/harness-ui/src/harness-receipt-keypair.mjs +207 -0
  297. package/vendor/harness-ui/src/hf-direct-transfer.mjs +170 -0
  298. package/vendor/harness-ui/src/hf-hub-client.mjs +106 -0
  299. package/vendor/harness-ui/src/hf-image-proxy.mjs +105 -0
  300. package/vendor/harness-ui/src/hf-model-transfer.mjs +245 -0
  301. package/vendor/harness-ui/src/hook-registry.mjs +186 -0
  302. package/vendor/harness-ui/src/http-app.mjs +6259 -0
  303. package/vendor/harness-ui/src/http-lifecycle.mjs +132 -0
  304. package/vendor/harness-ui/src/id-archivio.mjs +27 -0
  305. package/vendor/harness-ui/src/image-generator.mjs +143 -0
  306. package/vendor/harness-ui/src/istruzioni-di-progetto.mjs +234 -0
  307. package/vendor/harness-ui/src/kernel/dist/kernelPerIlBanco.js +518 -0
  308. package/vendor/harness-ui/src/kernel/talosHarness.mjs +10437 -0
  309. package/vendor/harness-ui/src/library-policy-store.mjs +175 -0
  310. package/vendor/harness-ui/src/library-store.mjs +652 -0
  311. package/vendor/harness-ui/src/llama-server-supervisor.mjs +629 -0
  312. package/vendor/harness-ui/src/local-model-store.mjs +339 -0
  313. package/vendor/harness-ui/src/local-runtime-contract.mjs +66 -0
  314. package/vendor/harness-ui/src/local-runtime-events.mjs +44 -0
  315. package/vendor/harness-ui/src/local-runtime-llama-server.mjs +244 -0
  316. package/vendor/harness-ui/src/local-runtime-probe.mjs +401 -0
  317. package/vendor/harness-ui/src/machine-capacity.mjs +66 -0
  318. package/vendor/harness-ui/src/mappa-cartelle.mjs +491 -0
  319. package/vendor/harness-ui/src/mcp-client.mjs +98 -0
  320. package/vendor/harness-ui/src/mcp-registry.mjs +157 -0
  321. package/vendor/harness-ui/src/mcp-session.mjs +177 -0
  322. package/vendor/harness-ui/src/memory-store.mjs +227 -0
  323. package/vendor/harness-ui/src/model-catalog-models-dev.mjs +276 -0
  324. package/vendor/harness-ui/src/model-catalog.mjs +129 -0
  325. package/vendor/harness-ui/src/model-destination.mjs +189 -0
  326. package/vendor/harness-ui/src/modifica-ancorata.mjs +177 -0
  327. package/vendor/harness-ui/src/native-provider-adapter.mjs +205 -0
  328. package/vendor/harness-ui/src/notes-store.mjs +250 -0
  329. package/vendor/harness-ui/src/openai-compatible-runtime.mjs +428 -0
  330. package/vendor/harness-ui/src/openrouter-oauth.mjs +339 -0
  331. package/vendor/harness-ui/src/path-policy.mjs +442 -0
  332. package/vendor/harness-ui/src/plugin-registry.mjs +780 -0
  333. package/vendor/harness-ui/src/plugin-session.mjs +180 -0
  334. package/vendor/harness-ui/src/process-policy.mjs +345 -0
  335. package/vendor/harness-ui/src/prompt-enhancer-provider.mjs +94 -0
  336. package/vendor/harness-ui/src/provider-auth-cloud.mjs +95 -0
  337. package/vendor/harness-ui/src/provider-credential-store.mjs +541 -0
  338. package/vendor/harness-ui/src/provider-probe.mjs +582 -0
  339. package/vendor/harness-ui/src/provider-registry.mjs +1633 -0
  340. package/vendor/harness-ui/src/pty-terminal.mjs +312 -0
  341. package/vendor/harness-ui/src/public-problem.mjs +109 -0
  342. package/vendor/harness-ui/src/research/card.mjs +235 -0
  343. package/vendor/harness-ui/src/research/citations.mjs +142 -0
  344. package/vendor/harness-ui/src/research/collector.mjs +275 -0
  345. package/vendor/harness-ui/src/research/deposito-a-pezzi.mjs +139 -0
  346. package/vendor/harness-ui/src/research/dossier.mjs +114 -0
  347. package/vendor/harness-ui/src/research/esportazioni.mjs +560 -0
  348. package/vendor/harness-ui/src/research/fetch-cache.mjs +465 -0
  349. package/vendor/harness-ui/src/research/fidelity.mjs +122 -0
  350. package/vendor/harness-ui/src/research/independence.mjs +159 -0
  351. package/vendor/harness-ui/src/research/ledger.mjs +166 -0
  352. package/vendor/harness-ui/src/research/markdown-server.mjs +565 -0
  353. package/vendor/harness-ui/src/research/narration.mjs +181 -0
  354. package/vendor/harness-ui/src/research/open-cards.mjs +131 -0
  355. package/vendor/harness-ui/src/research/opposing.mjs +305 -0
  356. package/vendor/harness-ui/src/research/outline.mjs +111 -0
  357. package/vendor/harness-ui/src/research/page-budget.mjs +209 -0
  358. package/vendor/harness-ui/src/research/pdf.mjs +291 -0
  359. package/vendor/harness-ui/src/research/plan.mjs +301 -0
  360. package/vendor/harness-ui/src/research/raccolta-viva.mjs +452 -0
  361. package/vendor/harness-ui/src/research/recheck-document.mjs +69 -0
  362. package/vendor/harness-ui/src/research/recheck-history.mjs +192 -0
  363. package/vendor/harness-ui/src/research/recheck.mjs +194 -0
  364. package/vendor/harness-ui/src/research/report.mjs +203 -0
  365. package/vendor/harness-ui/src/research/run.mjs +527 -0
  366. package/vendor/harness-ui/src/research/synthesis.mjs +318 -0
  367. package/vendor/harness-ui/src/research/verification.mjs +572 -0
  368. package/vendor/harness-ui/src/research-orchestrator.mjs +2679 -0
  369. package/vendor/harness-ui/src/research-store.mjs +1133 -0
  370. package/vendor/harness-ui/src/runtime-build-manifest.mjs +26 -0
  371. package/vendor/harness-ui/src/runtime-contract.mjs +59 -0
  372. package/vendor/harness-ui/src/runtime-owner-adapter.mjs +1348 -0
  373. package/vendor/harness-ui/src/runtime-owner-contract.mjs +32 -0
  374. package/vendor/harness-ui/src/scheda-di-lavoro.mjs +249 -0
  375. package/vendor/harness-ui/src/search-source-store.mjs +172 -0
  376. package/vendor/harness-ui/src/session-registry.mjs +6095 -0
  377. package/vendor/harness-ui/src/session-store.mjs +220 -0
  378. package/vendor/harness-ui/src/sessione-pronta.mjs +73 -0
  379. package/vendor/harness-ui/src/setup-stato.mjs +31 -0
  380. package/vendor/harness-ui/src/sezioni-istruzioni.mjs +204 -0
  381. package/vendor/harness-ui/src/skill-registry.mjs +120 -0
  382. package/vendor/harness-ui/src/sse-replay-coalescente.mjs +0 -0
  383. package/vendor/harness-ui/src/static-files.mjs +96 -0
  384. package/vendor/harness-ui/src/stream-partition.mjs +123 -0
  385. package/vendor/harness-ui/src/subagent-orchestrator.mjs +453 -0
  386. package/vendor/harness-ui/src/task-catalog.mjs +65 -0
  387. package/vendor/harness-ui/src/tasks-store.mjs +220 -0
  388. package/vendor/harness-ui/src/terminal-registry.mjs +312 -0
  389. package/vendor/harness-ui/src/terminal-ws.mjs +170 -0
  390. package/vendor/harness-ui/src/tool-forge-store.mjs +299 -0
  391. package/vendor/harness-ui/src/tool-schema-normalize.mjs +100 -0
  392. package/vendor/harness-ui/src/usage-cache.mjs +315 -0
  393. package/vendor/harness-ui/src/workspace-browser.mjs +213 -0
  394. package/vendor/harness-ui/src/workspace-context.mjs +124 -0
  395. package/vendor/harness-ui/src/workspace-disk.mjs +62 -0
  396. package/vendor/harness-ui/src/workspace-files.mjs +589 -0
  397. package/vendor/harness-ui/src/workspace-info.mjs +189 -0
  398. package/vendor/harness-ui/src/workspace-launch-store.mjs +150 -0
  399. package/vendor/harness-ui/src/workspace-tree.mjs +67 -0
  400. package/vendor/harness-ui/src/workspace-watcher.mjs +161 -0
  401. package/vendor/manifest.json +170 -0
@@ -0,0 +1,32 @@
1
+ /** Versioned, provider-neutral readiness envelope for the optional owner runtime. */
2
+ export class RuntimeOwnerContractError extends Error {
3
+ constructor(message, code = 'RUNTIME_SNAPSHOT_INVALID') {
4
+ super(message);
5
+ this.name = 'RuntimeOwnerContractError';
6
+ this.code = code;
7
+ }
8
+ }
9
+
10
+ function isIsoDate(value) {
11
+ return value === null || (typeof value === 'string' && Number.isFinite(Date.parse(value)));
12
+ }
13
+
14
+ /**
15
+ * Normalizes the only snapshot shape exposed to the HTTP/UI layer.
16
+ * `unavailable` intentionally carries `items:null`; an empty array is
17
+ * reserved for a successfully consulted runtime that has no entries.
18
+ */
19
+ export function parseRuntimeOwnerSnapshot(value) {
20
+ if (value === null || value === undefined) {
21
+ return { status: 'unavailable', items: null, reason: 'runtime_not_configured', observedAt: null };
22
+ }
23
+ if (!value || typeof value !== 'object' || Array.isArray(value)) throw new RuntimeOwnerContractError('Stato runtime non valido.');
24
+ const { status, items, reason = null, observedAt = null } = value;
25
+ if (status !== 'available' && status !== 'unavailable') throw new RuntimeOwnerContractError('Stato runtime sconosciuto.');
26
+ if (status === 'available' && !Array.isArray(items)) throw new RuntimeOwnerContractError('Un runtime disponibile deve fornire un elenco.');
27
+ if (status === 'unavailable' && items !== null) throw new RuntimeOwnerContractError('Un runtime non disponibile non può fornire elementi.');
28
+ if (reason !== null && (typeof reason !== 'string' || reason.length === 0)) throw new RuntimeOwnerContractError('Motivo runtime non valido.');
29
+ if (!isIsoDate(observedAt)) throw new RuntimeOwnerContractError('Data di osservazione runtime non valida.');
30
+ return Object.freeze({ status, items, reason, observedAt });
31
+ }
32
+
@@ -0,0 +1,249 @@
1
+ /**
2
+ * scheda-di-lavoro.mjs — BLOCCO 2 del preambolo: dove sei, con che permesso, con che modello, e
3
+ * con quali comandi si verifica il lavoro. Dieci-quindici righe, mai un file nominato.
4
+ *
5
+ * ── DA CHI LO PRENDIAMO, e perché ────────────────────────────────────────────────────────────
6
+ *
7
+ * È il «workspace snapshot» di Hermes v0.21 (`agent/coding_context.py:836-932`), che fra i quattro
8
+ * concorrenti letti nel codice l'11/09/2026 è il più ricco al costo più basso (~100-130 token), più
9
+ * il blocco `Environment` di Claude Code 2.1.268 (otto righe, zero file) e il suo `gitStatus`
10
+ * tagliato a 2.000 caratteri. La cosa da rubare per intero è il commento di Hermes sui
11
+ * «project facts», verbatim:
12
+ *
13
+ * *«Hands the model its verify loop up front — which manifest, which package manager, and the
14
+ * exact test/lint/build commands — instead of making it rediscover them every session. Built once
15
+ * at prompt-build time; the string output must stay byte-stable to preserve the prompt cache.»*
16
+ *
17
+ * ⛔ E il vincolo di cache, dichiarato da loro e valido per noi (`coding_context.py:31-38`):
18
+ * *«The workspace snapshot is built once at prompt-build time and baked into the stable
19
+ * system-prompt tier — never re-probed per turn (that would shatter the prompt cache). Branch and
20
+ * dirty state drift mid-session, so the brief tells the model to re-check with git before acting
21
+ * on the snapshot.»*
22
+ * ⇒ Qui si fa lo stesso: si costruisce UNA VOLTA e si DICHIARA che invecchia. Chi chiama non deve
23
+ * rifarlo a ogni giro — `contesto-del-progetto.mjs` tiene la cache che lo garantisce.
24
+ *
25
+ * ⛔⛔ IL RITRATTO DELLA CARTELLA CE L'AVEVAMO GIÀ, E NON LO MANDAVAMO AL MODELLO.
26
+ * `workspace-info.mjs` calcola da mesi ramo, file non salvati, repo annidati (`:105-113`) e
27
+ * quali `CLAUDE.md`/`AGENTS.md`/`TALOS.md`/`.talos` esistono (`:132-140`). Tutto questo finiva
28
+ * **nella modale «Nuova sessione»**, cioè davanti alla persona, e mai dentro il prompt. È la
29
+ * lezione [[chi-guarda-da-fuori-inventa-quello-che-dentro-aveva-gia]], di nuovo: prima di
30
+ * scrivere codice nuovo si cerca nel PROPRIO codebase. Questo modulo RIUSA quelle funzioni, non
31
+ * ne scrive di nuove.
32
+ *
33
+ * RICERCA WEB, letta l'11/09/2026 PRIMA di scrivere:
34
+ * · Anthropic, «Effective context engineering for AI agents», 29/09/2025 — il principio guida è
35
+ * *«find the smallest set of high-signal tokens that maximize the likelihood of your desired
36
+ * outcome»*. Il comando di verifica è il token a segnale più alto che esista in un progetto di
37
+ * codice: risponde in una riga alla domanda che l'agente si pone a ogni giro («ho finito?»).
38
+ * · Claude Platform Docs, «Prompt caching» (letto 11/09/2026) — *«Cache hits require 100%
39
+ * identical prompt segments»*. ⇒ In questa scheda NON entra niente che cambi da una chiamata
40
+ * all'altra senza una ragione: nessun orario, nessuna durata, nessun percorso assoluto.
41
+ * ⛔ L'unica cosa volatile che resta di proposito è lo stato di git (file non salvati), perché
42
+ * vale più di quanto costa — ed è dietro l'argomento `statoVolatile`, così l'A/B può misurare
43
+ * la differenza invece di discuterne.
44
+ */
45
+ import { readFile, stat } from 'node:fs/promises';
46
+ import { basename, join } from 'node:path';
47
+ import { numeroItaliano, statoGit, istruzioniPresenti } from './workspace-info.mjs';
48
+
49
+ /** Hermes `_MAX_VERIFY_COMMANDS = 8`: oltre, la scheda smette di essere una scheda. */
50
+ export const MASSIMO_COMANDI_VERIFICA = 8;
51
+
52
+ /**
53
+ * I manifesti che si riconoscono, e il gestore di pacchetti che si deduce dal lockfile.
54
+ * ⛔ È una lista, e una lista invecchia: quando non riconosce niente la scheda TACE su questa
55
+ * riga invece di indovinare. Un «Progetto: sconosciuto» costerebbe token per non dire niente.
56
+ */
57
+ export const MANIFESTI = Object.freeze([
58
+ 'package.json', 'deno.json', 'deno.jsonc', 'pyproject.toml', 'requirements.txt', 'setup.py',
59
+ 'Cargo.toml', 'go.mod', 'pom.xml', 'build.gradle', 'build.gradle.kts', 'composer.json',
60
+ 'Gemfile', 'CMakeLists.txt', 'Makefile', 'pubspec.yaml', 'Package.swift', 'mix.exs',
61
+ ]);
62
+
63
+ const LOCKFILE = Object.freeze([
64
+ ['pnpm-lock.yaml', 'pnpm'], ['yarn.lock', 'yarn'], ['bun.lockb', 'bun'], ['bun.lock', 'bun'],
65
+ ['package-lock.json', 'npm'], ['poetry.lock', 'poetry'], ['uv.lock', 'uv'],
66
+ ['Cargo.lock', 'cargo'], ['Gemfile.lock', 'bundler'],
67
+ ]);
68
+
69
+ /** Gli script che valgono come «verifica», nell'ordine in cui servono. */
70
+ const SCRIPT_DI_VERIFICA = Object.freeze(['test', 'typecheck', 'lint', 'build', 'check', 'verify']);
71
+
72
+ /**
73
+ * Quali manifesti ci sono, quale gestore di pacchetti, e i comandi con cui si verifica.
74
+ * Non lancia mai: una cartella illeggibile produce una scheda più povera, non un errore.
75
+ */
76
+ export async function fattiDelProgetto(cartella, { fs } = {}) {
77
+ const disco = { readFile, stat, ...(fs ?? {}) };
78
+ const manifesti = [];
79
+ for (const nome of MANIFESTI) {
80
+ try { await disco.stat(join(cartella, nome)); manifesti.push(nome); } catch { /* non c'è */ }
81
+ }
82
+ let gestore = null;
83
+ for (const [lock, quale] of LOCKFILE) {
84
+ try { await disco.stat(join(cartella, lock)); gestore = quale; break; } catch { /* non c'è */ }
85
+ }
86
+
87
+ const comandi = [];
88
+ if (manifesti.includes('package.json')) {
89
+ try {
90
+ const pacchetto = JSON.parse(await disco.readFile(join(cartella, 'package.json'), 'utf8'));
91
+ const script = pacchetto?.scripts && typeof pacchetto.scripts === 'object' ? pacchetto.scripts : {};
92
+ const eseguibile = gestore === 'yarn' || gestore === 'bun' || gestore === 'pnpm' ? gestore : 'npm';
93
+ const prefisso = eseguibile === 'npm' ? 'npm run' : `${eseguibile} run`;
94
+ /*
95
+ * ⛔⛔ SI GUARDA ANCHE IL PREFISSO, non solo il nome esatto — trovato GUARDANDO IL TESTO
96
+ * VERO l'11/09, non da un test: su `harness-ui/` la riga «Verifica» NON USCIVA, perché
97
+ * gli script di questo repo si chiamano `verify:all`, `verify:ui`, `test:kernel`, e
98
+ * nessuno di quei nomi è `test` o `verify` esatti. Era il difetto peggiore possibile in
99
+ * questo blocco: la riga a segnale più alto della scheda — quella che risponde da sola a
100
+ * «ho finito?», e che Hermes cita come la ragione d'essere dei suoi «project facts» —
101
+ * spariva in silenzio proprio sul progetto su cui stavo misurando la cura.
102
+ * ⭐ L'ordine è deterministico due volte: prima la priorità della parola (`test` prima di
103
+ * `build`), poi il nome per unità di codice. La chiave della cache è il TESTO, e un ordine
104
+ * che dipende da come è scritto il `package.json` lo farebbe cambiare senza motivo.
105
+ */
106
+ const nomiScript = Object.keys(script).filter((k) => typeof script[k] === 'string');
107
+ const candidati = [];
108
+ for (const parola of SCRIPT_DI_VERIFICA) {
109
+ const uguale = nomiScript.filter((k) => k === parola);
110
+ const conPrefisso = nomiScript.filter((k) => k.startsWith(`${parola}:`)).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
111
+ candidati.push(...uguale, ...conPrefisso);
112
+ }
113
+ for (const nome of candidati) {
114
+ comandi.push(nome === 'test' && eseguibile === 'npm' ? 'npm test' : `${prefisso} ${nome}`);
115
+ if (comandi.length >= MASSIMO_COMANDI_VERIFICA) break;
116
+ }
117
+ } catch { /* package.json rotto o illeggibile: nessun comando inventato */ }
118
+ }
119
+ if (comandi.length === 0 && manifesti.includes('Cargo.toml')) comandi.push('cargo test');
120
+ if (comandi.length === 0 && manifesti.includes('go.mod')) comandi.push('go test ./...');
121
+ if (comandi.length === 0 && manifesti.includes('Makefile')) comandi.push('make test');
122
+
123
+ return { manifesti, gestore, comandi };
124
+ }
125
+
126
+ /**
127
+ * Il testo del blocco 2.
128
+ *
129
+ * @param {object} input
130
+ * @param {string} input.cartella — usata SOLO per ricavarne il NOME (vedi sotto)
131
+ * @param {string} [input.nomeProgetto] — il nome della radice del progetto, se diversa dal cwd
132
+ * @param {object|null} [input.git] — l'esito di `statoGit`
133
+ * @param {string[]} [input.commit] — le righe «hash oggetto» degli ultimi commit
134
+ * @param {object} [input.fatti] — l'esito di `fattiDelProgetto`
135
+ * @param {string[]} [input.istruzioni] — i nomi dei file di istruzioni trovati
136
+ * @param {string|null} [input.permesso] — l'etichetta del permesso del giro
137
+ * @param {string|null} [input.modello]
138
+ * @param {string|null} [input.piattaforma]
139
+ */
140
+ export function testoSchedaDiLavoro({
141
+ cartella, nomeProgetto = null, git = null, commit = [], fatti = null,
142
+ istruzioni = [], permesso = null, modello = null, piattaforma = null,
143
+ } = {}) {
144
+ /* ⛔ Il NOME della cartella, mai il percorso: contiene il nome della persona e questo testo esce
145
+ dalla macchina dentro un prompt — [[cancello-4-non-guardava-tutto-mobile]]. Ed è anche ciò che
146
+ rende il prefisso identico fra due macchine diverse sullo stesso progetto. */
147
+ const nome = basename(String(cartella ?? '').replace(/[\\/]+$/, '')) || 'la cartella di lavoro';
148
+ const righe = [];
149
+ righe.push('Scheda di lavoro — fotografia scattata all\'inizio della sessione. Lo stato di git INVECCHIA mentre lavori: prima di fidartene, ricontrollalo.');
150
+ righe.push(nomeProgetto && nomeProgetto !== nome
151
+ ? `Cartella di lavoro: «${nome}», dentro il progetto «${nomeProgetto}».`
152
+ : `Cartella di lavoro: «${nome}».`);
153
+
154
+ if (git) {
155
+ const pezzi = [];
156
+ if (git.ramo) pezzi.push(`ramo ${git.ramo}`);
157
+ if (Number.isFinite(git.nonSalvate)) pezzi.push(git.nonSalvate === 0 ? 'niente da salvare' : `${numeroItaliano(git.nonSalvate)} file non salvati`);
158
+ if (git.repoAnnidati?.length) pezzi.push(`${git.repoAnnidati.length} repo annidati`);
159
+ if (pezzi.length) righe.push(`Git: ${pezzi.join(' · ')}.`);
160
+ } else {
161
+ /* ⛔ «Non è un repo git» è un FATTO, e cambia cosa ha senso fare: niente `git diff`, niente
162
+ «guarda l'ultimo commit». Tacere lo farebbe scoprire con un giro sprecato. */
163
+ righe.push('Git: questa cartella non è un repository.');
164
+ }
165
+ if (Array.isArray(commit) && commit.length > 0) {
166
+ righe.push(`Ultimi commit: ${commit.slice(0, 3).join(' | ')}`);
167
+ }
168
+
169
+ if (fatti?.manifesti?.length) {
170
+ righe.push(`Progetto: ${fatti.manifesti.slice(0, 6).join(', ')}${fatti.gestore ? ` (gestore: ${fatti.gestore})` : ''}.`);
171
+ }
172
+ if (fatti?.comandi?.length) {
173
+ /* La riga a segnale più alto della scheda: risponde a «ho finito?» senza un giro di scoperta. */
174
+ righe.push(`Verifica: ${fatti.comandi.join(' ; ')}`);
175
+ }
176
+
177
+ if (permesso) righe.push(`Permesso di questo giro: ${permesso}.`);
178
+ if (modello) righe.push(`Modello che stai usando: ${modello}.`);
179
+ if (piattaforma) righe.push(`Piattaforma: ${piattaforma}.`);
180
+ /*
181
+ * ⛔ TOLTA l'11/09 la riga «Istruzioni di progetto presenti: …». Guardava SOLO il cwd, mentre il
182
+ * blocco 3 raccoglie la catena dalla RADICE DEL PROGETTO in giù: su `harness-ui/` la scheda
183
+ * avrebbe detto «nessuna» mentre due righe sotto c'era l'`AGENTS.md` della radice, per intero.
184
+ * Due verità diverse sulla stessa cosa nello stesso testo sono peggio di una sola incompleta.
185
+ * Chi ha bisogno del dato lo trova in `istruzioni`, che `schedaDiLavoro()` restituisce lo stesso.
186
+ */
187
+ return righe.join('\n');
188
+ }
189
+
190
+ /**
191
+ * Costruisce la scheda leggendo davvero il disco. Non lancia mai.
192
+ * ⛔ Le tre sonde girano IN PARALLELO: sono tre `spawn` di git più una manciata di `stat`, e in
193
+ * serie sarebbero la parte lenta di un preambolo che deve costare niente. Misurato su questo
194
+ * repo: 60-90 ms in parallelo.
195
+ */
196
+ export async function schedaDiLavoro({
197
+ cartella, permesso = null, modello = null, piattaforma = null, nomeProgetto = null,
198
+ statoVolatile = true, fs, eseguiGit,
199
+ } = {}) {
200
+ if (typeof cartella !== 'string' || cartella.trim() === '') return null;
201
+ const opzioniGit = eseguiGit ? { eseguiGit } : {};
202
+
203
+ const [git, commit, fatti, istruzioni] = await Promise.all([
204
+ /* ⛔ `statoVolatile:false` toglie la riga che cambia più spesso (i file non salvati), per l'A/B
205
+ sulla cache fra sessioni consecutive: è l'unica cosa in tutto il preambolo che si muove senza
206
+ che nessuno abbia cambiato cartella, permesso o modello. Si misura, non si discute. */
207
+ statoVolatile ? statoGit(cartella, opzioniGit).catch(() => null) : Promise.resolve(null),
208
+ statoVolatile ? ultimiCommit(cartella, opzioniGit).catch(() => []) : Promise.resolve([]),
209
+ fattiDelProgetto(cartella, { fs }).catch(() => null),
210
+ istruzioniPresenti(cartella).catch(() => []),
211
+ ]);
212
+
213
+ return {
214
+ testo: testoSchedaDiLavoro({ cartella, nomeProgetto, git, commit, fatti, istruzioni, permesso, modello, piattaforma }),
215
+ git, commit, fatti, istruzioni,
216
+ };
217
+ }
218
+
219
+ /**
220
+ * Gli ultimi tre commit, in una riga ciascuno. Stessa forma di Hermes
221
+ * (`coding_context.py:354`: `_git(root, "log", "-3", "--pretty=%h %s")`).
222
+ * ⛔ Il soggetto si taglia a 72 caratteri: i nostri messaggi di commit sono lunghi apposta, e tre
223
+ * righe da 200 caratteri sono un terzo della scheda.
224
+ */
225
+ export async function ultimiCommit(cartella, { eseguiGit } = {}) {
226
+ if (typeof eseguiGit !== 'function') {
227
+ /* Nessun esecutore iniettato: si usa quello di `workspace-info.mjs` passando da `statoGit`?
228
+ No — quello non espone `git log`. Si fa qui, con lo stesso stile: spawn, timeout, mai throw. */
229
+ const { spawn } = await import('node:child_process');
230
+ return await new Promise((risolvi) => {
231
+ let uscita = '';
232
+ let processo;
233
+ try { processo = spawn('git', ['log', '-3', '--pretty=%h %s'], { cwd: cartella, windowsHide: true }); }
234
+ catch { risolvi([]); return; }
235
+ const timer = setTimeout(() => { try { processo.kill(); } catch { /* già morto */ } risolvi([]); }, 4000);
236
+ processo.stdout?.on('data', (pezzo) => { uscita += String(pezzo); });
237
+ processo.on('error', () => { clearTimeout(timer); risolvi([]); });
238
+ processo.on('close', (codice) => { clearTimeout(timer); risolvi(codice === 0 ? tagliaCommit(uscita) : []); });
239
+ });
240
+ }
241
+ const uscita = await eseguiGit(['log', '-3', '--pretty=%h %s'], cartella);
242
+ return uscita ? tagliaCommit(uscita) : [];
243
+ }
244
+
245
+ function tagliaCommit(uscita) {
246
+ return String(uscita).split('\n').map((r) => r.trim()).filter(Boolean)
247
+ .map((r) => (r.length > 72 ? `${r.slice(0, 71)}…` : r))
248
+ .slice(0, 3);
249
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * ⭐⭐⭐ 04/9 — R-03, LA FONTE DELLA RICERCA WEB si sceglie dalle Impostazioni
3
+ * (parità col mobile, `TalosMobileSearchSourcePanel.vue` / `searchSources.ts`),
4
+ * non più solo dalle variabili d'ambiente all'avvio.
5
+ *
6
+ * Cinque fonti: le quattro del mobile (Tavily, Brave, SearXNG, endpoint
7
+ * custom) più una che il mobile non ha, **DuckDuckGo senza chiave** — il +1 del
8
+ * desktop: la ricerca funziona anche a chiave zero, dichiarando che è una
9
+ * pagina pubblica letta senza accordo (vedi `duckduckgo-search.mjs`).
10
+ *
11
+ * Dove vivono le cose:
12
+ * - la scelta (fonte, indirizzo) in un file JSON accanto al server, come
13
+ * `.provider-runtime.json`; mai nel browser;
14
+ * - la chiave nel portachiavi del sistema (`@napi-rs/keyring`, servizio
15
+ * `talos-harness-search`), un account per fonte; mai su disco in chiaro;
16
+ * - le variabili `TALOS_HARNESS_SEARCH_*` restano il SEME quando il file non
17
+ * esiste ancora (chi le usa oggi non perde niente); appena si sceglie dalla
18
+ * UI, comanda il file.
19
+ *
20
+ * Senza niente di configurato la fonte è DuckDuckGo: il modello può cercare
21
+ * subito. Chi non vuole nessuna ricerca la spegne («off») ed è una scelta
22
+ * registrata, non un'assenza.
23
+ */
24
+ import { existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
25
+
26
+ export const KEYRING_SERVICE_RICERCA = 'talos-harness-search';
27
+ const MAX_KEY_LENGTH = 4096;
28
+ const FONTI = Object.freeze({
29
+ duckduckgo: Object.freeze({ id: 'duckduckgo', label: 'DuckDuckGo (senza chiave)', needsKey: false, needsEndpoint: false, keyless: true,
30
+ nota: 'Nessuna chiave e nessun account: TALOS legge la pagina dei risultati pubblica di DuckDuckGo. Non è un\'API ufficiale: sotto uso intenso può rispondere con un blocco, e allora l\'esito lo dice. Solo la query lascia questo computer.' }),
31
+ tavily: Object.freeze({ id: 'tavily', label: 'Tavily', needsKey: true, needsEndpoint: false, keyless: false,
32
+ nota: '1.000 ricerche al mese senza costi e senza carta. È progettato per gli agenti, quindi restituisce risultati puliti.', link: 'https://app.tavily.com' }),
33
+ brave: Object.freeze({ id: 'brave', label: 'Brave Search', needsKey: true, needsEndpoint: false, keyless: false,
34
+ nota: 'Un indice indipendente. È richiesta una carta di credito e Brave offre limiti di spesa. Brave non consente di conservare i risultati senza un accordo separato: TALOS apre le fonti con naviga prima di salvarle.', link: 'https://api-dashboard.search.brave.com' }),
35
+ searxng: Object.freeze({ id: 'searxng', label: 'SearXNG (istanza tua)', needsKey: false, needsEndpoint: true, keyless: false,
36
+ nota: 'La tua istanza SearXNG: nessuna terza parte vede la query. Basta un container Docker. L\'output JSON è disattivato all\'inizio: attivalo nelle impostazioni dell\'istanza, o TALOS riceverà una pagina HTML.' }),
37
+ custom: Object.freeze({ id: 'custom', label: 'Endpoint personalizzato', needsKey: false, needsEndpoint: true, keyless: false,
38
+ nota: 'Qualsiasi altra API di ricerca che restituisca un array «results» al primo livello (chiave opzionale, inviata come Bearer).' }),
39
+ });
40
+ export const FONTI_RICERCA_IDS = Object.freeze(Object.keys(FONTI));
41
+
42
+ export class SearchSourceError extends Error {
43
+ constructor(code, message) { super(message || code); this.name = 'SearchSourceError'; this.code = code; }
44
+ }
45
+
46
+ function normalizzaEndpoint(valore) {
47
+ const testo = typeof valore === 'string' ? valore.trim().replace(/\/+$/, '') : '';
48
+ if (!testo) return '';
49
+ let u;
50
+ try { u = new URL(testo); } catch { throw new SearchSourceError('SEARCH_ENDPOINT_INVALID', 'Indirizzo non valido: serve un URL http(s) completo.'); }
51
+ if (u.protocol !== 'http:' && u.protocol !== 'https:') throw new SearchSourceError('SEARCH_ENDPOINT_INVALID', 'Indirizzo non valido: solo http o https.');
52
+ return u.toString().replace(/\/+$/, '');
53
+ }
54
+
55
+ function leggiFile(percorso) {
56
+ if (!percorso || !existsSync(percorso)) return null;
57
+ try {
58
+ const dati = JSON.parse(readFileSync(percorso, 'utf8'));
59
+ return dati && typeof dati === 'object' ? dati : null;
60
+ } catch { return null; }
61
+ }
62
+ function scriviFile(percorso, dati) {
63
+ if (!percorso) return;
64
+ const tmp = `${percorso}.tmp-${process.pid}`;
65
+ writeFileSync(tmp, `${JSON.stringify(dati, null, 2)}\n`);
66
+ renameSync(tmp, percorso);
67
+ }
68
+
69
+ /**
70
+ * @param {object} deps
71
+ * @param {NodeJS.ProcessEnv} [deps.env] seme: TALOS_HARNESS_SEARCH_PROVIDER / _API_KEY / _ENDPOINT
72
+ * @param {{get,set,remove}|null} [deps.keyring] stesso contratto del portachiavi provider (server.mjs)
73
+ * @param {string|null} [deps.file] percorso del JSON di scelta (fonte, endpoint)
74
+ */
75
+ export function createSearchSourceStore({ env = process.env, keyring = null, file = null } = {}) {
76
+ const chiavi = new Map();
77
+ let scelta = { source: 'duckduckgo', endpoint: '' };
78
+
79
+ const salvato = leggiFile(file);
80
+ if (salvato && typeof salvato.source === 'string' && (FONTI[salvato.source] || salvato.source === 'off')) {
81
+ scelta = { source: salvato.source, endpoint: typeof salvato.endpoint === 'string' ? salvato.endpoint : '' };
82
+ } else {
83
+ const provider = typeof env.TALOS_HARNESS_SEARCH_PROVIDER === 'string' ? env.TALOS_HARNESS_SEARCH_PROVIDER.trim().toLowerCase() : '';
84
+ const chiaveEnv = typeof env.TALOS_HARNESS_SEARCH_API_KEY === 'string' ? env.TALOS_HARNESS_SEARCH_API_KEY.trim() : '';
85
+ const endpointEnv = typeof env.TALOS_HARNESS_SEARCH_ENDPOINT === 'string' ? env.TALOS_HARNESS_SEARCH_ENDPOINT.trim() : '';
86
+ if ((chiaveEnv || endpointEnv) && FONTI[provider || 'tavily']) {
87
+ scelta = { source: provider || 'tavily', endpoint: endpointEnv };
88
+ if (chiaveEnv) chiavi.set(scelta.source, chiaveEnv);
89
+ }
90
+ }
91
+ if (keyring && typeof keyring.get === 'function') {
92
+ for (const id of FONTI_RICERCA_IDS) {
93
+ try {
94
+ const v = keyring.get(KEYRING_SERVICE_RICERCA, id);
95
+ if (typeof v === 'string' && v.trim() && v.length <= MAX_KEY_LENGTH) chiavi.set(id, v.trim());
96
+ } catch { /* il portachiavi che non risponde non è una chiave */ }
97
+ }
98
+ }
99
+
100
+ function definizione(id) {
101
+ if (id === 'off') return null;
102
+ const d = FONTI[id];
103
+ if (!d) throw new SearchSourceError('SEARCH_SOURCE_INVALID', `Fonte sconosciuta: ${id}`);
104
+ return d;
105
+ }
106
+ function prontezza() {
107
+ if (scelta.source === 'off') return 'spenta';
108
+ const d = FONTI[scelta.source];
109
+ if (d.needsKey && !chiavi.has(scelta.source)) return 'chiave-mancante';
110
+ if (d.needsEndpoint && !scelta.endpoint) return 'indirizzo-mancante';
111
+ return 'pronta';
112
+ }
113
+ function keyringOp(op, id, valore) {
114
+ if (!keyring || typeof keyring[op] !== 'function') throw new SearchSourceError('SEARCH_STORE_UNAVAILABLE', 'Portachiavi del sistema non disponibile.');
115
+ try { return op === 'set' ? keyring.set(KEYRING_SERVICE_RICERCA, id, valore) : keyring.remove(KEYRING_SERVICE_RICERCA, id); }
116
+ catch { throw new SearchSourceError('SEARCH_STORE_UNAVAILABLE', 'Portachiavi del sistema non disponibile.'); }
117
+ }
118
+
119
+ /** Vista pubblica: mai una chiave, solo se c'è. */
120
+ function listPublic() {
121
+ return {
122
+ source: scelta.source,
123
+ endpoint: scelta.endpoint || '',
124
+ readiness: prontezza(),
125
+ fonti: FONTI_RICERCA_IDS.map((id) => ({ ...FONTI[id], keyConfigured: chiavi.has(id) })),
126
+ };
127
+ }
128
+ function setSource({ source, endpoint } = {}) {
129
+ if (source !== 'off') definizione(source);
130
+ const endpointNorm = source === 'off' ? '' : normalizzaEndpoint(endpoint ?? (source === scelta.source ? scelta.endpoint : ''));
131
+ const precedente = scelta;
132
+ scelta = { source, endpoint: endpointNorm };
133
+ try { scriviFile(file, scelta); } catch (errore) { scelta = precedente; throw new SearchSourceError('SEARCH_STORE_UNAVAILABLE', `Scelta non salvata: ${errore.message}`); }
134
+ return listPublic();
135
+ }
136
+ function setKey(source, valore) {
137
+ const d = definizione(source);
138
+ if (!d) throw new SearchSourceError('SEARCH_SOURCE_INVALID', 'Nessuna fonte scelta.');
139
+ if (typeof valore !== 'string' || valore.trim() === '') throw new SearchSourceError('SEARCH_KEY_REQUIRED', 'Incolla prima una chiave.');
140
+ const chiave = valore.trim();
141
+ if (chiave.length > MAX_KEY_LENGTH) throw new SearchSourceError('SEARCH_KEY_INVALID', 'Chiave troppo lunga.');
142
+ keyringOp('set', source, chiave);
143
+ chiavi.set(source, chiave);
144
+ return listPublic();
145
+ }
146
+ function clearKey(source) {
147
+ definizione(source);
148
+ keyringOp('remove', source);
149
+ chiavi.delete(source);
150
+ return listPublic();
151
+ }
152
+ /**
153
+ * Ciò che il kernel riceve. `ricercaWeb` è la config di `talosLavora`;
154
+ * `richiediRicercaFn` è il trasporto iniettato SOLO per la fonte senza
155
+ * chiave (per le fonti con chiave il kernel usa il proprio, con la sua
156
+ * guardia DNS pubblica). `undefined` quando spenta o non pronta: il kernel
157
+ * dichiara «not configured», mai un tentativo senza credenziali.
158
+ */
159
+ function perKernel({ trasportoSenzaChiave = null, sentinellaDuckDuckGo = 'https://ricerca-senza-chiave.talos.invalid/duckduckgo' } = {}) {
160
+ if (prontezza() !== 'pronta') return { ricercaWeb: undefined, richiediRicercaFn: undefined };
161
+ if (scelta.source === 'duckduckgo') {
162
+ return { ricercaWeb: Object.freeze({ provider: 'custom', endpoint: sentinellaDuckDuckGo }), richiediRicercaFn: trasportoSenzaChiave ?? undefined };
163
+ }
164
+ const chiave = chiavi.get(scelta.source);
165
+ return {
166
+ ricercaWeb: Object.freeze({ provider: scelta.source, ...(chiave ? { apiKey: chiave } : {}), ...(scelta.endpoint ? { endpoint: scelta.endpoint } : {}) }),
167
+ richiediRicercaFn: undefined,
168
+ };
169
+ }
170
+
171
+ return Object.freeze({ listPublic, setSource, setKey, clearKey, perKernel, prontezza, fonte: () => scelta.source });
172
+ }