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,111 @@
1
+ import { talosResearchIsTerminal, talosResearchStepIdFor } from './run.mjs'
2
+
3
+ /*
4
+ * PORTO FEDELE di AVM/mobile/src/lib/research/researchOutline.ts (85 righe, 11/09/2026).
5
+ *
6
+ * ⛔ `run.mjs` è il porto di `researchRun.ts` e lo cura un'altra sessione, in
7
+ * parallelo: qui se ne importa solo il nome concordato, senza duplicarne una riga.
8
+ *
9
+ * Il documento, prima che esista.
10
+ *
11
+ * La ricerca visiva del 2026-08-03 fa una domanda a cui nessun concorrente
12
+ * risponde: che cosa si disegna nel primo mezzo secondo, quando ancora non si
13
+ * sa niente? Di quel momento non ha trovato uno screenshot in nessuno dei
14
+ * cinque prodotti — le recensioni saltano dal piano allo stato popolato e il
15
+ * marketing taglia la transizione. Il che fa comodo, perché vuol dire che la
16
+ * risposta qui è nostra.
17
+ *
18
+ * E la risposta è che qualcosa lo sappiamo. Il piano è stato approvato prima
19
+ * che si spendesse un centesimo: i suoi rami SONO le sezioni che il rapporto
20
+ * avrà. Quindi la pagina si apre sulla forma del documento, con ogni sezione
21
+ * che dice dov'è — invece che su una rotella, o, come faceva fino a oggi, su
22
+ * niente del tutto.
23
+ *
24
+ * Tutto qui dentro è aritmetica sulla corsa. Niente disco, niente rete: il
25
+ * primo fotogramma non può essere in ritardo perché non c'è niente da aspettare.
26
+ */
27
+
28
+ /**
29
+ * @import { TalosResearchRun, TalosResearchStepState } from './run.mjs'
30
+ */
31
+
32
+ /**
33
+ * @typedef {object} TalosResearchSection
34
+ * @property {string} id
35
+ * @property {string} question
36
+ * @property {TalosResearchStepState} state
37
+ */
38
+
39
+ /**
40
+ * Una sezione per ramo, nell'ordine del piano.
41
+ *
42
+ * Un ramo senza ancora un passo è `pending` invece che assente: al lettore si
43
+ * sta mostrando che cosa SUCCEDERÀ, e nascondere le parti non ancora partite
44
+ * farebbe sembrare che il documento cresca dal nulla.
45
+ *
46
+ * @param {TalosResearchRun} run
47
+ * @returns {readonly TalosResearchSection[]}
48
+ */
49
+ export function talosResearchOutline(run) {
50
+ return run.plan.map((branch) => {
51
+ const step = run.steps.find((candidate) => candidate.id === talosResearchStepIdFor(branch.id, 'search'))
52
+ return { id: branch.id, question: branch.question, state: step?.state ?? 'pending' }
53
+ })
54
+ }
55
+
56
+ /**
57
+ * Quando una corsa finita è finita davvero.
58
+ *
59
+ * NON `updatedAt`, che viene timbrato da ogni evento che il giornale accetta —
60
+ * una rinomina compresa. Una ricerca conclusa in quattro minuti ieri e
61
+ * rinominata oggi leggerebbe «conclusa in 1 giorno», e la pagina starebbe
62
+ * citando il momento in cui le hai cambiato titolo come il momento in cui ha
63
+ * smesso di pensare.
64
+ *
65
+ * L'ultimo passo che riporta una fine è la fine vera. Una corsa annullata prima
66
+ * che un passo finisse non ne ha nessuno, e lì `updatedAt` è il meglio che c'è.
67
+ *
68
+ * @param {TalosResearchRun} run
69
+ * @returns {string}
70
+ */
71
+ function endedAt(run) {
72
+ /** @type {string | null} */
73
+ let last = null
74
+ for (const step of run.steps) {
75
+ if (step.finishedAt && (last === null || step.finishedAt > last)) last = step.finishedAt
76
+ }
77
+ return last ?? run.updatedAt
78
+ }
79
+
80
+ /**
81
+ * Da quanto sta andando, in secondi.
82
+ *
83
+ * Dai tempi della corsa, mai da un cronometro fatto partire quando lo schermo
84
+ * si è montato: una ricerca la si guarda da più posti e sopravvive a tutti,
85
+ * quindi una durata posseduta da un componente ripartirebbe ogni volta che
86
+ * qualcuno guarda. Una corsa finita misura fino a quando è finita; una viva
87
+ * fino ad adesso.
88
+ *
89
+ * @param {TalosResearchRun} run
90
+ * @param {string} now
91
+ * @returns {number}
92
+ */
93
+ export function talosResearchElapsedSeconds(run, now) {
94
+ const started = Date.parse(run.startedAt)
95
+ const until = Date.parse(talosResearchIsTerminal(run.status) ? endedAt(run) : now)
96
+ if (!Number.isFinite(started) || !Number.isFinite(until)) return 0
97
+ return Math.max(0, Math.round((until - started) / 1000))
98
+ }
99
+
100
+ /**
101
+ * `4 min 08 s`, oppure `38 s`. Tabellare, e mai un numero nudo di secondi oltre
102
+ * il minuto.
103
+ *
104
+ * @param {number} seconds
105
+ * @returns {string}
106
+ */
107
+ export function talosResearchDuration(seconds) {
108
+ if (seconds < 60) return `${seconds} s`
109
+ const minutes = Math.floor(seconds / 60)
110
+ return `${minutes} min ${String(seconds % 60).padStart(2, '0')} s`
111
+ }
@@ -0,0 +1,209 @@
1
+ /*
2
+ * L6 — IL BUDGET DETERMINISTICO PER PAGINA.
3
+ *
4
+ * ## Il difetto che chiude
5
+ *
6
+ * Una pagina web è lunga quanto le pare. Il modello riceve tutto, e la finestra
7
+ * di contesto è la prima cosa che finisce: `naviga` nel kernel taglia già a
8
+ * 4.000 caratteri (`talosHarness.mjs:1296`, `uscitaUtile`) e la sintesi ne
9
+ * prende 4.000 in testa per fonte (`synthesis.mjs:59`). Nessuno dei due dice
10
+ * dove sia finito il resto, e la sintesi non guarda nemmeno la coda.
11
+ *
12
+ * ⛔ Il punto NON è tagliare — quello lo facciamo già. Il punto è che oggi il
13
+ * resto **sparisce**: non è da nessuna parte, quindi non si può né sfogliare né
14
+ * ri-verificare. Questo modulo separa tre cose che oggi sono una sola:
15
+ *
16
+ * 1. il testo INTERO, che si conserva (è il dossier: `collector.mjs`);
17
+ * 2. la FINESTRA, cioè quanto ne vede il modello adesso;
18
+ * 3. il RIFERIMENTO, cioè come arrivare al resto.
19
+ *
20
+ * ⛔ La (1) resta la fonte della verità per `talosResearchLocate`
21
+ * (`verification.mjs:201`): un passaggio citato si cerca nel testo intero, MAI
22
+ * nella finestra — altrimenti tagliare una pagina trasformerebbe una citazione
23
+ * vera in una citazione «non trovata», che è il verso peggiore in cui si possa
24
+ * sbagliare (una fonte onesta marcata come inventata).
25
+ *
26
+ * ## Perché 15.000, misurato invece che copiato
27
+ *
28
+ * Hermes v0.21 usa 15.000 caratteri per pagina, testa 75% / coda 25%, il resto
29
+ * su disco col percorso e la chiamata esatta per sfogliarlo, tetto 2 MB
30
+ * (`website/docs/user-guide/features/web-search.md:47-57` nel clone
31
+ * `%LOCALAPPDATA%\Temp\talos-competitor\hermes-agent-v21`, letto l'11/09/2026).
32
+ * Il numero è il loro, la ragione doveva essere nostra.
33
+ *
34
+ * MISURATO l'11/09/2026 su 430 pagine di documentazione vera (le `.md`/`.mdx`
35
+ * di `website/docs` dello stesso clone: sono pagine web pubblicate, non un
36
+ * campione inventato), con gli spazi compattati come fa il collettore:
37
+ *
38
+ * mediana 10.688 · p75 15.752 · p90 27.983 · p95 43.899 · max 187.135
39
+ *
40
+ * tetto pagine intere caratteri coperti
41
+ * 4.000 30/430 ( 7,0%) 26,1%
42
+ * 8.000 130/430 (30,2%) 47,9%
43
+ * 15.000 313/430 (72,8%) 69,4%
44
+ * 20.000 357/430 (83,0%) 76,3%
45
+ * 40.000 403/430 (93,7%) 89,3%
46
+ *
47
+ * ⇒ I 4.000 di oggi consegnano al modello il 26% dei caratteri e fanno arrivare
48
+ * intera UNA PAGINA SU QUATTORDICI: non è un budget, è un troncone. I 15.000 di
49
+ * Hermes cadono quasi esattamente sul 75° percentile (15.752): tre pagine su
50
+ * quattro arrivano intere e il taglio smette di essere la regola.
51
+ *
52
+ * ⛔ E la ragione per cui NON prendo i 20.000 del mobile (`collector.mjs:79`,
53
+ * `MAX_CHARS_PER_SOURCE`) è strutturale, non di gusto: quello è il tetto di ciò
54
+ * che si CONSERVA. Se il tetto mostrato fosse uguale a quello conservato, il
55
+ * riferimento «il resto è in …» punterebbe sempre a zero caratteri residui, e
56
+ * questo modulo sarebbe una bugia cortese. Il tetto mostrato deve stare
57
+ * STRETTAMENTE sotto quello conservato. 15.000 < 20.000.
58
+ *
59
+ * ## Perché testa 75% / coda 25%, al contrario di `uscitaUtile`
60
+ *
61
+ * `uscitaUtile` tiene un quarto in testa e tre quarti in coda, e ha ragione:
62
+ * misura l'uscita di una SUITE DI TEST, dove la diagnosi sta in fondo
63
+ * (`talosHarness.mjs:1282-1295`). Una pagina web è l'opposto — titolo, apertura
64
+ * e tesi stanno in cima, e la coda è note, footer, commenti. ⇒ stesso
65
+ * meccanismo, quote invertite, e la ragione scritta accanto a tutte e due.
66
+ *
67
+ * ## Deterministico, e la parola conta
68
+ *
69
+ * Nessun modello, nessuna sintesi, nessuna data, nessun `toLocaleString`: la
70
+ * stessa pagina produce la stessa identica finestra, byte per byte. Serve
71
+ * perché la cache del prompt dei fornitori funziona su PREFISSO ESATTO — «If
72
+ * your breakpoint is on content that changes every request, cache hits never
73
+ * occur» (platform.claude.com/docs/en/build-with-claude/prompt-caching, letta
74
+ * l'11/09/2026). Una finestra che cambia fra due giri identici brucia la cache
75
+ * di tutto ciò che le sta dopo.
76
+ */
77
+
78
+ /**
79
+ * Quanti caratteri di una pagina vede il modello.
80
+ * Vedi la misura qui sopra: è il 75° percentile di 430 pagine vere.
81
+ */
82
+ export const TALOS_RESEARCH_PAGE_BUDGET = 15_000;
83
+
84
+ /** Quanta parte della finestra è la testa. Una pagina dice la sua tesi in cima. */
85
+ export const TALOS_RESEARCH_HEAD_SHARE = 0.75;
86
+
87
+ /**
88
+ * Quanto testo si CONSERVA di una pagina. Stesso tetto di Hermes (2 MB): oltre,
89
+ * un solo documento patologico si mangerebbe il dossier.
90
+ */
91
+ export const TALOS_RESEARCH_KEPT_CAP = 2 * 1024 * 1024;
92
+
93
+ /**
94
+ * @typedef {object} TalosResearchPageReference
95
+ * @property {string} percorso Dove il testo intero è stato depositato.
96
+ * @property {string} [chiamata]
97
+ * La chiamata ESATTA per sfogliare il mezzo, se esiste davvero un attrezzo che
98
+ * la accetta. ⛔ Non si inventa: oggi `leggi` non ha né offset né lunghezza
99
+ * (`talosHarness.mjs:1446-1451`), quindi chi non può scriverne una vera non la
100
+ * passa, e il marcatore tace invece di mentire.
101
+ */
102
+
103
+ /**
104
+ * @typedef {object} TalosResearchPageWindow
105
+ * @property {string} window Ciò che il modello vede: testa + marcatore + coda.
106
+ * @property {number} total Caratteri della pagina intera.
107
+ * @property {number} shown Caratteri davvero mostrati (marcatore escluso).
108
+ * @property {number} omitted `total - shown`. Contato, mai stimato.
109
+ * @property {boolean} truncated
110
+ * @property {string | null} marker Il marcatore, per chi lo vuole altrove.
111
+ */
112
+
113
+ /**
114
+ * Il taglio della testa, portato indietro fino a un confine di riga se ce n'è
115
+ * uno vicino — Hermes taglia «on markdown line boundaries», e mezza riga di
116
+ * markdown letta a metà è rumore. Se non c'è una riga si ripiega su uno spazio;
117
+ * se non c'è nemmeno quello (testo compattato, o una lingua senza spazi) si
118
+ * taglia netto: meglio un taglio netto che una regola che non si applica.
119
+ *
120
+ * @param {string} testo
121
+ * @param {number} tetto
122
+ * @returns {number}
123
+ */
124
+ function tagliaInTesta(testo, tetto) {
125
+ if (tetto <= 0) return 0;
126
+ const finestra = testo.slice(0, tetto);
127
+ const riga = finestra.lastIndexOf('\n');
128
+ if (riga >= Math.floor(tetto * 0.8)) return riga;
129
+ const spazio = finestra.lastIndexOf(' ');
130
+ if (spazio >= tetto - 200) return spazio;
131
+ return tetto;
132
+ }
133
+
134
+ /**
135
+ * L'inizio della coda, portato AVANTI (mai indietro: allargherebbe la finestra
136
+ * oltre il tetto) fino al primo confine di riga vicino.
137
+ *
138
+ * @param {string} testo
139
+ * @param {number} tetto
140
+ * @returns {number}
141
+ */
142
+ function tagliaInCoda(testo, tetto) {
143
+ if (tetto <= 0) return testo.length;
144
+ const da = testo.length - tetto;
145
+ const finestra = testo.slice(da);
146
+ const riga = finestra.indexOf('\n');
147
+ if (riga >= 0 && riga <= Math.floor(tetto * 0.2)) return da + riga + 1;
148
+ const spazio = finestra.indexOf(' ');
149
+ if (spazio >= 0 && spazio <= 200) return da + spazio + 1;
150
+ return da;
151
+ }
152
+
153
+ /**
154
+ * @param {number} valore
155
+ * @param {number} minimo
156
+ * @param {number} massimo
157
+ * @returns {number}
158
+ */
159
+ function stretto(valore, minimo, massimo) {
160
+ if (!Number.isFinite(valore)) return minimo;
161
+ return Math.min(massimo, Math.max(minimo, valore));
162
+ }
163
+
164
+ /**
165
+ * La finestra che il modello vede, e il conto esatto di ciò che non vede.
166
+ *
167
+ * @param {string} testo
168
+ * @param {{cap?: number, headShare?: number, reference?: TalosResearchPageReference | null}} [opzioni]
169
+ * @returns {TalosResearchPageWindow}
170
+ */
171
+ export function talosResearchPageBudget(testo, opzioni = {}) {
172
+ const pagina = typeof testo === 'string' ? testo : String(testo ?? '');
173
+ const tetto = Math.trunc(stretto(opzioni.cap ?? TALOS_RESEARCH_PAGE_BUDGET, 1, TALOS_RESEARCH_KEPT_CAP));
174
+ const quotaTesta = stretto(opzioni.headShare ?? TALOS_RESEARCH_HEAD_SHARE, 0, 1);
175
+ const riferimento = opzioni.reference ?? null;
176
+ const totali = pagina.length;
177
+
178
+ if (totali <= tetto) {
179
+ return { window: pagina, total: totali, shown: totali, omitted: 0, truncated: false, marker: null };
180
+ }
181
+
182
+ const tettoTesta = Math.round(tetto * quotaTesta);
183
+ const testa = pagina.slice(0, tagliaInTesta(pagina, tettoTesta));
184
+ const coda = pagina.slice(tagliaInCoda(pagina, tetto - tettoTesta));
185
+ const mostrati = testa.length + coda.length;
186
+ const tolti = totali - mostrati;
187
+
188
+ /*
189
+ * ⛔ D-10G, 10/09 — la lezione già pagata su questa stessa riga di codice: il
190
+ * marcatore di `uscitaUtile` diceva «l'elenco completo dei test» su QUALUNQUE
191
+ * troncamento, ed è stato visto dall'owner su una PAGINA WEB. Un marcatore che
192
+ * dice COSA ha tagliato mente appena il contenuto non è quello; questo dice
193
+ * solo QUANTO, e dove trovare il resto quando il resto ha davvero un posto.
194
+ */
195
+ const dove = riferimento?.percorso
196
+ ? `Il testo intero è in ${riferimento.percorso}.${riferimento.chiamata ? ` Per sfogliare il mezzo: ${riferimento.chiamata}` : ''}`
197
+ : 'Il testo intero è conservato nel dossier di questa ricerca.';
198
+
199
+ const marcatore = `… [visti ${mostrati} caratteri su ${totali}: ${testa.length} in testa, ${coda.length} in coda; ${tolti} tolti dal mezzo. ${dove}] …`;
200
+
201
+ return {
202
+ window: `${testa}\n\n${marcatore}\n\n${coda}`,
203
+ total: totali,
204
+ shown: mostrati,
205
+ omitted: tolti,
206
+ truncated: true,
207
+ marker: marcatore,
208
+ };
209
+ }
@@ -0,0 +1,291 @@
1
+ import { talosResearchSupportLabel } from './report.mjs'
2
+ import { inlineInTestoSemplice, markdownInBlocchiReport, runsDiMarkdown } from './markdown-server.mjs'
3
+
4
+ /*
5
+ * PORTO di AVM/mobile/src/lib/research/researchPdf.ts (246 righe, letto per intero il
6
+ * 12/09/2026 prima di scrivere una riga). ⛔ SOLA LETTURA sul mobile: qui non si tocca.
7
+ *
8
+ * ⛔⛔ EXPORT — una ricerca che diventa un PDF, in TRE TONI.
9
+ *
10
+ * Owner 2026-08-03 (mobile): «quando clicchi per generare il pdf appare un popup che ti fa
11
+ * scegliere il "tono" del pdf tra 3 template». Owner 12/09/2026 (desktop): «la ricerca
12
+ * approfondita deve avere una suite di esportazioni COMPLETA».
13
+ *
14
+ * I tre sono documenti DIVERSI, non tre tavolozze sullo stesso testo. Un cambio di colore
15
+ * travestito da scelta è una domanda posta a vuoto: chi la riceve deve fermarsi a pensare, e
16
+ * qualunque cosa risponda ottiene la stessa cosa.
17
+ *
18
+ * `report` — a chi deve leggerlo tutto: copertina, sintesi, ogni affermazione col suo
19
+ * verdetto e il passaggio, poi le fonti.
20
+ * `brief` — a chi ha due minuti: la risposta, cosa regge, cosa NON regge. Niente
21
+ * passaggi, niente elenco fonti.
22
+ * `dossier` — a chi deve controllare: affermazione, verdetto, fonte, in tabella. Nessuna
23
+ * prosa. È quello che gli altri non hanno.
24
+ *
25
+ * ⛔ Il modulo è PURO di proposito, come il suo originale: il documento si prova senza
26
+ * pdfmake, senza rete e senza telefono. Chi lo trasforma in byte è `esportazioni.mjs`, che
27
+ * passa questo `TalosReportInput` a `generateTalosDocument({format:'pdf', report})` — cioè
28
+ * allo STESSO impaginatore (`document-report.mjs`) che usa `document_create`. Un secondo
29
+ * impaginatore sarebbe un secondo aspetto per gli stessi documenti.
30
+ *
31
+ * ════════════════════════════════════════════════════════════════════════════════════════
32
+ * ⛔⛔⛔ L'UNICA DIVERGENZA DAL MOBILE, E NON È UNO STILE: `sourceIndex` È 1-BASED.
33
+ * ════════════════════════════════════════════════════════════════════════════════════════
34
+ *
35
+ * `researchPdf.ts` fa `report.sources[claim.sourceIndex]`. Ogni altro lettore dello stesso
36
+ * record — su mobile E qui — fa `sources[claim.sourceIndex - 1]`:
37
+ * · `researchReport.ts:128` / `report.mjs` (la prosa del rapporto)
38
+ * · `researchRecheck.ts:114`, `researchSynthesis.ts:254`, `researchVerification.ts:397,422`
39
+ * ⇒ Il PDF del mobile attribuisce ogni affermazione alla fonte SEGUENTE, e l'ultima a «—».
40
+ * Il suo test non lo vede perché la sua fixture numera le fonti da 0, cioè con una
41
+ * convenzione che nessun motore produce.
42
+ * ⛔ Portarlo «fedele» qui avrebbe importato il difetto su un record scritto da `report.mjs`,
43
+ * che è 1-based per costruzione. Qui si usa `- 1`, e il test lo morde con un record vero.
44
+ * ⛔ Il difetto resta APERTO sul mobile: non ho ownership lì, si segnala e non si corregge.
45
+ *
46
+ * ═════════════════════════════════════════════════════════════════════════════════════
47
+ * ⛔⛔ LA SECONDA DIVERGENZA, 12/09: IL MARKDOWN SI RENDE.
48
+ * ═════════════════════════════════════════════════════════════════════════════════════
49
+ *
50
+ * `researchPdf.ts` mette la sintesi in un blocco solo (`{t:'p', x: report.summary}`) e il
51
+ * testo di ogni affermazione dentro un titolo, così com'è. Ma quel testo lo scrive un modello,
52
+ * e un modello scrive **Markdown**: nel PDF di una ricerca vera (L8, 12/09) uscivano
53
+ * `## Executive Summary` e `**Key Components:**` LETTERALI, come nell'HTML.
54
+ * ⇒ Qui la sintesi passa da `markdownInBlocchiReport` (titoli, elenchi, tabelle veri) e il
55
+ * testo delle affermazioni da `runsDiMarkdown` / `inlineInTestoSemplice`.
56
+ * ⛔ Il PASSAGGIO no, mai: è la PROVA, cioè il testo com'è nella fonte. Renderlo vorrebbe dire
57
+ * modificare l'unica cosa che il rapporto conserva perché non sia modificabile.
58
+ */
59
+
60
+ /**
61
+ * @import { TalosResearchReportRecord } from './report.mjs'
62
+ */
63
+
64
+ export const TALOS_RESEARCH_PDF_TONES = Object.freeze(['report', 'brief', 'dossier'])
65
+
66
+ /** Il tono di partenza: quello completo, che non lascia fuori niente. */
67
+ export const TALOS_RESEARCH_PDF_DEFAULT_TONE = 'report'
68
+
69
+ /** @param {{checks?:object}} claim */
70
+ function verdetto(claim) {
71
+ return talosResearchSupportLabel(claim?.checks ?? {})
72
+ }
73
+
74
+ /**
75
+ * Il nome della fonte di un'affermazione. ⛔ `sourceIndex` è 1-BASED (vedi la testa del file).
76
+ * @param {TalosResearchReportRecord} report
77
+ * @param {number} numero
78
+ * @returns {string}
79
+ */
80
+ function fonteDi(report, numero) {
81
+ const source = report.sources[Number(numero) - 1]
82
+ if (!source) return '—'
83
+ // Il titolo se c'è, altrimenti il dominio: un URL intero in una cella di tabella la
84
+ // sfonda, e nessuno lo legge comunque.
85
+ if (String(source.title ?? '').trim().length > 0) return source.title
86
+ /*
87
+ * ⛔ L'host INTERO (`altro.example.org`), non il dominio registrabile: il porto del mobile fa
88
+ * `new URL(url).hostname`, e qui era partita una scorciatoia verso
89
+ * `talosResearchRegistrableHost` di `independence.mjs` — che torna l'eTLD+1
90
+ * (`example.org`). Quella funzione esiste per decidere se due fonti sono INDIPENDENTI, cioè
91
+ * per accorpare i sottodomini apposta: usarla per un'etichetta farebbe leggere due fonti
92
+ * diverse come la stessa. Trovato dal test, non ragionandoci sopra.
93
+ */
94
+ try {
95
+ return new URL(source.url).hostname || String(source.url ?? '—')
96
+ } catch {
97
+ return String(source.url ?? '—')
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Quante reggono, quante a metà, quante smentite, quante mai verificate.
103
+ * @param {TalosResearchReportRecord} report
104
+ * @returns {{supported:number, partial:number, contradicted:number, unverified:number}}
105
+ */
106
+ export function talosResearchPdfTally(report) {
107
+ const tally = { supported: 0, partial: 0, contradicted: 0, unverified: 0 }
108
+ for (const claim of report.claims ?? []) {
109
+ switch (claim?.checks?.claimSupported) {
110
+ case 'yes': tally.supported += 1; break
111
+ case 'partial': tally.partial += 1; break
112
+ case 'no': tally.contradicted += 1; break
113
+ default: tally.unverified += 1
114
+ }
115
+ }
116
+ return tally
117
+ }
118
+
119
+ /**
120
+ * La riga che dice come è stato giudicato, o che NON lo è stato.
121
+ *
122
+ * «Nessun giudice indipendente era disponibile» e «tutte le citazioni hanno fallito il
123
+ * controllo meccanico» sono due fatti diversi, e il record li tiene separati apposta. Un PDF
124
+ * che tace su questo consegna un verdetto senza dire chi l'ha dato.
125
+ */
126
+ function nota(report) {
127
+ return {
128
+ t: 'note',
129
+ x: report.judge
130
+ ? `Le affermazioni sono state giudicate da ${report.judge}, confrontandole con il passaggio della fonte.`
131
+ : 'Nessun giudice indipendente era disponibile: i verdetti vengono dal solo controllo meccanico della citazione.',
132
+ }
133
+ }
134
+
135
+ function copertina(report, options) {
136
+ const titolo = String(options.title ?? '').trim()
137
+ return {
138
+ t: 'cover',
139
+ title: titolo || report.question,
140
+ subtitle: titolo ? report.question : 'Ricerca approfondita TALOS',
141
+ ...(options.date ? { date: options.date } : {}),
142
+ }
143
+ }
144
+
145
+ function bilancio(report) {
146
+ const tally = talosResearchPdfTally(report)
147
+ return {
148
+ t: 'kpi',
149
+ items: [
150
+ { l: 'Sostenute', v: String(tally.supported) },
151
+ { l: 'In parte', v: String(tally.partial) },
152
+ { l: 'Smentite', v: String(tally.contradicted) },
153
+ { l: 'Non verificate', v: String(tally.unverified) },
154
+ ],
155
+ }
156
+ }
157
+
158
+ function rapportoCompleto(report, options) {
159
+ const blocks = [
160
+ copertina(report, options),
161
+ { t: 'h', lvl: 1, x: 'In breve' },
162
+ ...markdownInBlocchiReport(report.summary, { livelloMinimo: 2 }),
163
+ bilancio(report),
164
+ nota(report),
165
+ { t: 'pb' },
166
+ { t: 'h', lvl: 1, x: 'Le affermazioni, una per una' },
167
+ ]
168
+ report.claims.forEach((claim, index) => {
169
+ blocks.push({ t: 'h', lvl: 3, x: `${index + 1}. ${inlineInTestoSemplice(claim.text)}` })
170
+ blocks.push({ t: 'p', x: `Verdetto: ${verdetto(claim)} — fonte: ${fonteDi(report, claim.sourceIndex)}` })
171
+ // Il passaggio è la prova. Senza, «sostenuta» è una parola che chiede fiducia invece
172
+ // di darla.
173
+ if (String(claim.passage ?? '').trim().length > 0) blocks.push({ t: 'note', x: `«${claim.passage}»` })
174
+ })
175
+ if (report.sources.length > 0) {
176
+ blocks.push({ t: 'pb' }, { t: 'h', lvl: 1, x: 'Le fonti' })
177
+ blocks.push({
178
+ t: 'table',
179
+ head: ['#', 'Titolo', 'Indirizzo', 'Come'],
180
+ align: ['r', 'l', 'l', 'l'],
181
+ rows: report.sources.map((source, index) => [
182
+ String(index + 1),
183
+ source.title || '—',
184
+ source.url,
185
+ source.obtained === 'page' ? 'pagina letta' : 'solo estratto',
186
+ ]),
187
+ })
188
+ }
189
+ return blocks
190
+ }
191
+
192
+ function sintesi(report, options) {
193
+ const tally = talosResearchPdfTally(report)
194
+ const regge = report.claims.filter((claim) => claim?.checks?.claimSupported === 'yes')
195
+ const nonRegge = report.claims.filter((claim) => (
196
+ claim?.checks?.claimSupported === 'no' || claim?.checks?.claimSupported === 'partial'
197
+ ))
198
+ /*
199
+ * Niente copertina, e non è una svista.
200
+ *
201
+ * Misurato sul OnePlus Pad 3 (2026-08-04): con la copertina la sintesi usciva di DUE
202
+ * pagine — il blocco `cover` ha 140 punti di margine in cima e da solo si mangia la prima.
203
+ * La riga nel popup promette «una pagina», e una promessa che il documento non mantiene è
204
+ * peggio della promessa assente.
205
+ */
206
+ const titolo = String(options.title ?? '').trim()
207
+ const blocks = [
208
+ { t: 'h', lvl: 1, x: titolo || report.question },
209
+ ...(titolo ? [{ t: 'note', x: report.question }] : []),
210
+ ...markdownInBlocchiReport(report.summary, { livelloMinimo: 3 }),
211
+ bilancio(report),
212
+ ]
213
+ if (regge.length > 0) {
214
+ blocks.push({ t: 'h', lvl: 2, x: 'Quello che regge' })
215
+ // Quattro, non tutte: una sintesi che riporta trenta punti non è una sintesi, è il
216
+ // rapporto senza le prove.
217
+ blocks.push({ t: 'list', items: regge.slice(0, 4).map((claim) => runsDiMarkdown(claim.text)) })
218
+ }
219
+ if (nonRegge.length > 0) {
220
+ blocks.push({ t: 'h', lvl: 2, x: 'Quello che NON regge' })
221
+ blocks.push({
222
+ t: 'list',
223
+ items: nonRegge.slice(0, 4).map((claim) => `${inlineInTestoSemplice(claim.text)} — ${verdetto(claim)}`),
224
+ })
225
+ }
226
+ if (tally.unverified > 0) {
227
+ blocks.push({
228
+ t: 'note',
229
+ x: `${tally.unverified} affermazioni non è stato possibile verificarle: la fonte non è stata riaperta o il passaggio non c'era.`,
230
+ })
231
+ }
232
+ blocks.push(nota(report))
233
+ return blocks
234
+ }
235
+
236
+ function dossier(report, options) {
237
+ return [
238
+ copertina(report, options),
239
+ { t: 'h', lvl: 1, x: 'Affermazioni e prove' },
240
+ nota(report),
241
+ {
242
+ t: 'table',
243
+ head: ['#', 'Affermazione', 'Verdetto', 'Fonte'],
244
+ align: ['r', 'l', 'l', 'l'],
245
+ rows: report.claims.map((claim, index) => [
246
+ String(index + 1),
247
+ runsDiMarkdown(claim.text),
248
+ verdetto(claim),
249
+ fonteDi(report, claim.sourceIndex),
250
+ ]),
251
+ },
252
+ {
253
+ t: 'chart',
254
+ kind: 'pie',
255
+ labels: ['Sostenute', 'In parte', 'Smentite', 'Non verificate'],
256
+ series: [{ data: Object.values(talosResearchPdfTally(report)) }],
257
+ },
258
+ ]
259
+ }
260
+
261
+ /**
262
+ * Il documento, nel tono chiesto.
263
+ *
264
+ * Un rapporto senza affermazioni non è un errore — una ricerca può finire senza che nessuna
265
+ * citazione regga — ma un PDF di sole intestazioni vuote non lo dice a nessuno. Quindi si dice.
266
+ *
267
+ * @param {TalosResearchReportRecord} report
268
+ * @param {'report'|'brief'|'dossier'} tone
269
+ * @param {{date?:string, title?:string|null}} [options]
270
+ * @returns {{theme:string, footer:object, blocks:object[]}}
271
+ */
272
+ export function talosResearchPdfSpec(report, tone, options = {}) {
273
+ const blocks = (report.claims?.length ?? 0) === 0
274
+ ? [
275
+ copertina(report, options),
276
+ ...markdownInBlocchiReport(report.summary, { livelloMinimo: 2 }),
277
+ { t: 'note', x: 'Questa ricerca non ha prodotto affermazioni verificabili.' },
278
+ ]
279
+ : tone === 'brief'
280
+ ? sintesi(report, options)
281
+ : tone === 'dossier'
282
+ ? dossier(report, options)
283
+ : rapportoCompleto(report, options)
284
+
285
+ return {
286
+ // Il dossier vive di tabelle larghe; gli altri due si leggono.
287
+ theme: tone === 'dossier' ? 'plain' : 'report',
288
+ footer: { text: 'TALOS · ricerca approfondita', pageNo: true },
289
+ blocks,
290
+ }
291
+ }