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,604 @@
1
+ /**
2
+ * Il filtro che decide che cosa NON entra nell'elenco profondo dei file dato al modello,
3
+ * perche' il progetto stesso lo considera ignorabile (`.gitignore`).
4
+ *
5
+ * ⛔ Perche' non e' «leggere un file e fare match»: sbagliare una regola qui significa
6
+ * NASCONDERE AL MODELLO FILE CHE ESISTONO — cioe' rifare, in un altro modo, il difetto
7
+ * che stiamo curando. Il 27/08/2026 un pattern `mobile/docs/` ha reso inerte
8
+ * `!docs/immagini/*.png` e per giorni ogni screenshot nuovo e' stato ignorato IN SILENZIO.
9
+ * Quel caso e' la prova numero uno della suite (`tests/gitignore-elenco.test.mjs`).
10
+ *
11
+ * ── FONTI ────────────────────────────────────────────────────────────────────────────
12
+ * [G] Git — `gitignore` Documentation, sezione PATTERN FORMAT.
13
+ * https://git-scm.com/docs/gitignore — letta il 10/09/2026.
14
+ * [P] POSIX / fnmatch(3p), flag FNM_PATHNAME + bracket expression negata con `!`.
15
+ * https://www.man7.org/linux/man-pages/man3/fnmatch.3p.html — letta il 10/09/2026.
16
+ * [O] ORACOLO: ogni regola qui sotto e' stata verificata contro `git check-ignore` VERO
17
+ * su un repo di prova, il 10/09/2026, prima di scrivere una riga di questo file.
18
+ *
19
+ * Citazioni verbatim da [G], che questo modulo implementa una per una:
20
+ *
21
+ * 1. «Trailing spaces are ignored unless they are quoted with backslash ("\").»
22
+ * → tagliaSpaziFinali()
23
+ * 2. «An optional prefix "!" which negates the pattern; any matching file excluded by a
24
+ * previous pattern will become included again.»
25
+ * → regola.negata, e l'ULTIMA regola che matcha decide (vedi decidiRiga()).
26
+ * 3. ⛔ «It is not possible to re-include a file if a parent directory of that file is
27
+ * excluded. Git doesn't list excluded directories for performance reasons, so any
28
+ * patterns on contained files have no effect, no matter where they are defined.»
29
+ * → il ciclo sui GENITORI dentro tieni(). E' il cuore del caso 27/08.
30
+ * 4. «If there is a separator at the beginning or middle (or both) of the pattern, then
31
+ * the pattern is relative to the directory level of the particular .gitignore file
32
+ * itself. Otherwise the pattern may also match at any level below the .gitignore level.»
33
+ * → ancorato / fluttuante in compilaRiga().
34
+ * 5. «If there is a separator at the end of the pattern then the pattern will only match
35
+ * directories, otherwise the pattern can match both files and directories.»
36
+ * → regola.soloDirectory.
37
+ * 6. «An asterisk "*" matches anything except a slash. The character "?" matches any one
38
+ * character except "/". The range notation, e.g. [a-zA-Z], can be used to match one of
39
+ * the characters in a range.»
40
+ * → globARegex(): `*` → [^/]*, `?` → [^/], `[...]` → classe che non attraversa mai `/` [P].
41
+ * 7. «A leading "**" followed by a slash means match in all directories.»
42
+ * «A trailing "/**" matches everything inside.»
43
+ * «A slash followed by two consecutive asterisks then a slash matches zero or more
44
+ * directories.» → i tre rami di `**` in globARegex().
45
+ * 8. «A backslash ("\") can be used to escape any character. […] a backslash at the end of
46
+ * a pattern is an invalid pattern that never matches.» → globARegex() + compilaRiga().
47
+ * 9. Annidati e precedenza: «Patterns read from a .gitignore file in the same directory as
48
+ * the path, or in any parent directory […] with patterns in the higher level files
49
+ * being overridden by those in lower level files down to the directory containing the
50
+ * file.» → le regole dei file piu' profondi entrano DOPO nell'elenco, quindi vincono.
51
+ *
52
+ * ── ⛔ COSA NON IMPLEMENTO (limiti DICHIARATI, non da scoprire) ───────────────────────
53
+ * L1. `core.excludesFile` (il gitignore globale dell'utente): richiede leggere la config
54
+ * git dell'utente. Fuori perimetro: un elenco per il modello deve mostrare il
55
+ * progetto, non le preferenze personali di chi lo apre. `.git/info/exclude` invece
56
+ * SI', perche' e' del repo (vedi FONTI_IMPLICITE).
57
+ * L2. `git check-ignore --no-index` e le regole da riga di comando: non esistono qui.
58
+ * L3. Le classi POSIX nominate — `[[:alpha:]]`, `[[:digit:]]` — sono passate alla regex
59
+ * cosi' come sono e NON funzionano. Sono rarissime in un `.gitignore` vero; se un
60
+ * giorno servono, il posto e' classeARegex().
61
+ * L4. Il case-folding di `core.ignoreCase`: qui il confronto e' SEMPRE sensibile alle
62
+ * maiuscole, anche su Windows dove il filesystem non lo e'. Scelta prudente: la
63
+ * direzione dell'errore e' «tengo un file di troppo», mai «ne nascondo uno».
64
+ * L5. I symlink a directory sono trattati come FILE (git fa lo stesso: non ci scende).
65
+ * L6. Un `\` dentro il pattern e' sempre un ESCAPE, mai un separatore di percorso. Su
66
+ * Windows un `.gitignore` con `src\build` non funziona — e non funziona neanche con
67
+ * git vero, quindi e' fedelta', non un limite nostro.
68
+ * L7. ⛔ Se la CARTELLA DI LAVORO STESSA e' ignorata (aprire `node_modules/` o una
69
+ * cartella che il repo padre esclude), il filtro NON svuota l'elenco: le regole dei
70
+ * genitori valgono per i percorsi DENTRO, ma la cartella aperta non si nasconde mai.
71
+ * Non e' un'invenzione: ripgrep fa lo stesso — `skip_entry` in `crates/ignore/src/walk.rs`
72
+ * «Returns Ok(false) without running any ignore/hidden checks for depth-0 entries,
73
+ * which are the paths explicitly provided as arguments» (letto via ctx7 il 10/09/2026).
74
+ * ⛔ E il verso opposto ha un costo misurato da un concorrente: Hermes Agent
75
+ * issue #45286 (giugno 2026) — l'albero file del Desktop filtra col `.gitignore`
76
+ * senza un interruttore «mostra ignorati», e in un monorepo le cartelle top-level
77
+ * possedute da repo figli SPARISCONO dalla vista pur esistendo sul disco.
78
+ * https://github.com/NousResearch/hermes-agent/issues/45286
79
+ * L8. `info/exclude` di un WORKTREE: lo cerco via `commondir`, ma se quel file manca o e'
80
+ * in una forma inattesa si rinuncia in silenzio — perdere `info/exclude` fa TENERE
81
+ * qualche file in piu', mai nasconderne.
82
+ *
83
+ * ── LA SCELTA: A MANO, non una libreria ──────────────────────────────────────────────
84
+ * La libreria di riferimento e' `ignore` (kaelzhang/node-ignore, 500+ test verificati
85
+ * contro `git check-ignore`). Non la aggiungo, per tre ragioni DICHIARATE:
86
+ * a) `package.json` non ha oggi NESSUN matcher di glob (ne' `ignore`, ne' `minimatch`,
87
+ * ne' `picomatch`): sarebbe una dipendenza NUOVA, e il progetto chiede una ragione
88
+ * dichiarata per ognuna. La ragione mancherebbe: vedi (b) e (c).
89
+ * b) Il contratto che il camminatore consuma e' `(percorsoRelativo, eDirectory)`, con
90
+ * `eDirectory` esplicito. `ignore` non ha quel parametro: vuole il suffisso `/` nel
91
+ * percorso, quindi andrebbe comunque avvolto — e l'avvolgimento e' il punto dove si
92
+ * sbaglia il caso 27/08.
93
+ * c) `ignore` non gestisce i `.gitignore` ANNIDATI: la composizione per base andrebbe
94
+ * scritta a mano lo stesso. Cioe' la meta' difficile del lavoro resterebbe nostra.
95
+ * d) ⛔ E `ignore` non risale ai `.gitignore` dei GENITORI: e' il buco misurato il
96
+ * 10/09/2026 partendo da `harness-ui/`, e la parte che ripgrep stesso ha corretto solo
97
+ * nella 15.0.0. Adottarla non ce l'avrebbe evitato.
98
+ * Costo misurato della via a mano: 300 righe di modulo (di cui ~110 di specifica citata)
99
+ * + 38 prove, e un oracolo `git check-ignore` per fissare la semantica prima di scrivere.
100
+ * Il perimetro coperto e' l'insieme dei costrutti che compaiono in un `.gitignore` reale;
101
+ * ogni buco noto e' dichiarato in L1-L8.
102
+ *
103
+ * ── PROVE (10/09/2026) ───────────────────────────────────────────────────────────────
104
+ * · 930 confronti contro `git check-ignore` su repo di prova: 0 disaccordi.
105
+ * · Da `harness-ui/` (sottocartella di un worktree): l'INSIEME dei file tenuti coincide
106
+ * esattamente con `git ls-files` + `git ls-files --others --exclude-standard` —
107
+ * 680 contro 680, zero in piu' e zero in meno, in entrambe le direzioni.
108
+ */
109
+
110
+ import { promises as fsPromises } from 'node:fs';
111
+ import { dirname, isAbsolute, join, relative } from 'node:path';
112
+
113
+ /** Esiti di una valutazione. L'ultima regola che matcha decide [G, punto 2]. */
114
+ const ESCLUSO = 'escluso';
115
+ const INCLUSO = 'incluso';
116
+ const NESSUNA = 'nessuna';
117
+
118
+ /** Il nome del file di regole, e le fonti implicite lette da creaFiltroGitignore(). */
119
+ export const NOME_FILE_REGOLE = '.gitignore';
120
+ export const FONTI_IMPLICITE = Object.freeze(['.git/info/exclude']);
121
+
122
+ /** Tetti di sicurezza della scoperta dei file annidati. Dichiarati, non nascosti. */
123
+ const PROFONDITA_MASSIMA = 24;
124
+ const CARTELLE_MASSIME = 5000;
125
+ /**
126
+ * ⛔⛔⛔ 12/09/2026 — IL TETTO IN TEMPO. Owner: «quasi un minuto al primo messaggio». Misurato
127
+ * sulla cartella `Desktop` (che non e' un repo ma contiene decine di repo): questa raccolta
128
+ * legge 288 `.gitignore` per 6.002 regole in **12.342 ms**, prima ancora di elencare una cartella;
129
+ * sul repo `AVM-harness-desktop` 57 file, 969 regole, 1.593 ms. I tetti in cartelle (5.000) e in
130
+ * profondita' (24) non mordevano in tempo. Oltre il budget la raccolta si ferma e lo dichiara
131
+ * (`filtro.incompleto`): le regole non lette non nascondono niente — la direzione dell'errore
132
+ * resta «tengo di piu'», come per un file illeggibile.
133
+ */
134
+ export const TEMPO_MASSIMO_RACCOLTA_MS = 1500;
135
+ /** ⛔ Quanti livelli si puo' RISALIRE cercando la radice del repo, per non finire su `C:\`. */
136
+ const RISALITA_MASSIMA = 64;
137
+
138
+ // ─────────────────────────────────────────────────────────────────────────────────────
139
+ // Parsing di UNA riga
140
+ // ─────────────────────────────────────────────────────────────────────────────────────
141
+
142
+ /**
143
+ * [G] «Trailing spaces are ignored unless they are quoted with backslash ("\").»
144
+ * Solo lo SPAZIO, non il tab: git taglia ' ' (trim_trailing_spaces in dir.c).
145
+ * Uno spazio e' protetto se preceduto da un numero DISPARI di backslash.
146
+ */
147
+ function tagliaSpaziFinali(riga) {
148
+ let fine = riga.length;
149
+ while (fine > 0 && riga[fine - 1] === ' ') {
150
+ let barre = 0;
151
+ for (let i = fine - 2; i >= 0 && riga[i] === '\\'; i -= 1) barre += 1;
152
+ if (barre % 2 === 1) break; // protetto: si ferma qui
153
+ fine -= 1;
154
+ }
155
+ return riga.slice(0, fine);
156
+ }
157
+
158
+ function scappaRegex(carattere) {
159
+ return carattere.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
160
+ }
161
+
162
+ /** Trova la `]` che chiude una classe aperta in `apertura`, o -1 se non c'e'. */
163
+ function chiusuraClasse(pattern, apertura) {
164
+ let i = apertura + 1;
165
+ if (pattern[i] === '!' || pattern[i] === '^') i += 1;
166
+ if (pattern[i] === ']') i += 1; // una `]` in prima posizione e' letterale
167
+ while (i < pattern.length) {
168
+ if (pattern[i] === '\\') { i += 2; continue; }
169
+ if (pattern[i] === ']') return i;
170
+ i += 1;
171
+ }
172
+ return -1;
173
+ }
174
+
175
+ /**
176
+ * [G] «The range notation, e.g. [a-zA-Z]» + [P] con FNM_PATHNAME la classe non matcha `/`.
177
+ * ⛔ L3: le classi POSIX nominate non sono tradotte.
178
+ */
179
+ function classeARegex(testo) {
180
+ let dentro = testo.slice(1, -1);
181
+ let negata = false;
182
+ if (dentro.startsWith('!') || dentro.startsWith('^')) { negata = true; dentro = dentro.slice(1); }
183
+ // Dentro una classe regex vanno neutralizzati solo `\`, `]` e `^`; `-` e il resto passano.
184
+ const corpo = dentro.replace(/\\/g, '\\\\').replace(/\]/g, '\\]').replace(/\^/g, '\\^');
185
+ return negata ? `[^/${corpo}]` : `[${corpo.replace(/\//g, '')}]`;
186
+ }
187
+
188
+ /**
189
+ * Traduce un glob gitignore in sorgente regex. Il `/` non e' mai attraversato da `*`, `?`
190
+ * o da una classe [G punto 6, P]; i tre casi di `**` sono quelli di [G punto 7].
191
+ */
192
+ function globARegex(pattern) {
193
+ let re = '';
194
+ let i = 0;
195
+ while (i < pattern.length) {
196
+ const c = pattern[i];
197
+
198
+ if (c === '\\') { // [G punto 8] escape di qualunque carattere
199
+ if (i + 1 < pattern.length) { re += scappaRegex(pattern[i + 1]); i += 2; continue; }
200
+ i += 1; continue; // backslash finale: gia' scartato in compilaRiga()
201
+ }
202
+
203
+ if (c === '*') {
204
+ let j = i;
205
+ while (j < pattern.length && pattern[j] === '*') j += 1;
206
+ const quanti = j - i;
207
+ const primaSlash = i === 0 || pattern[i - 1] === '/';
208
+ const dopoSlash = j >= pattern.length || pattern[j] === '/';
209
+
210
+ // ⛔ «Other consecutive asterisks are considered regular asterisks»: il ramo
211
+ // speciale vale SOLO per esattamente due, isolati fra slash o estremi.
212
+ if (quanti === 2 && primaSlash && dopoSlash) {
213
+ if (i === 0 && j < pattern.length) { // «**/» iniziale: in tutte le directory
214
+ re += '(?:.+/)?'; i = j + 1; continue;
215
+ }
216
+ if (j >= pattern.length) { // «/**» finale: tutto quel che c'e' dentro
217
+ re += '.+'; i = j; continue;
218
+ }
219
+ re = `${re.slice(0, -1)}(?:/.+)?/`; i = j + 1; continue; // «/**/»: zero o piu' directory
220
+ }
221
+ re += '[^/]*'; i = j; continue;
222
+ }
223
+
224
+ if (c === '?') { re += '[^/]'; i += 1; continue; }
225
+
226
+ if (c === '[') {
227
+ const fine = chiusuraClasse(pattern, i);
228
+ if (fine === -1) { re += '\\['; i += 1; continue; } // `[` spaiata = letterale
229
+ re += classeARegex(pattern.slice(i, fine + 1));
230
+ i = fine + 1; continue;
231
+ }
232
+
233
+ re += scappaRegex(c); i += 1;
234
+ }
235
+ return re;
236
+ }
237
+
238
+ /**
239
+ * Compila UNA riga in una regola, o null se la riga non e' una regola
240
+ * (vuota, commento, o pattern invalido).
241
+ * @param {string} riga
242
+ * @param {string} base cartella del `.gitignore` che l'ha prodotta, con `/`, senza slash finale
243
+ */
244
+ export function compilaRiga(riga, base = '') {
245
+ let p = typeof riga === 'string' ? riga : '';
246
+ if (p.endsWith('\r')) p = p.slice(0, -1); // file CRLF: su Windows e' la norma, non l'eccezione
247
+ p = tagliaSpaziFinali(p); // [G punto 1]
248
+ if (p === '') return null; // «A blank line matches no files»
249
+ if (p.startsWith('#')) return null; // «A line starting with # serves as a comment»
250
+
251
+ let negata = false;
252
+ if (p.startsWith('!')) { negata = true; p = p.slice(1); } // [G punto 2]
253
+ if (p === '') return null;
254
+
255
+ let soloDirectory = false;
256
+ if (p.endsWith('/')) { soloDirectory = true; p = p.slice(0, -1); } // [G punto 5]
257
+ if (p === '') return null;
258
+
259
+ // [G punto 8] «a backslash at the end of a pattern is an invalid pattern that never matches»
260
+ let barreFinali = 0;
261
+ for (let i = p.length - 1; i >= 0 && p[i] === '\\'; i -= 1) barreFinali += 1;
262
+ if (barreFinali % 2 === 1) return null;
263
+
264
+ // [G punto 4] uno slash all'inizio o in mezzo ancora il pattern alla base.
265
+ // Lo slash FINALE e' gia' stato tolto sopra, quindi non conta: `frotz/` resta fluttuante.
266
+ const ancorato = p.includes('/');
267
+ if (p.startsWith('/')) p = p.slice(1);
268
+ if (p === '') return null;
269
+
270
+ const corpo = globARegex(p);
271
+ const prefisso = ancorato ? '' : '(?:.*/)?'; // fluttuante: «may also match at any level below»
272
+ return {
273
+ negata,
274
+ soloDirectory,
275
+ base,
276
+ origine: riga,
277
+ regex: new RegExp(`^${prefisso}${corpo}$`),
278
+ };
279
+ }
280
+
281
+ // ─────────────────────────────────────────────────────────────────────────────────────
282
+ // Compilazione di un insieme di regole
283
+ // ─────────────────────────────────────────────────────────────────────────────────────
284
+
285
+ function normalizzaPercorso(percorso) {
286
+ if (typeof percorso !== 'string') return '';
287
+ let p = percorso.replace(/\\/g, '/');
288
+ while (p.startsWith('./')) p = p.slice(2);
289
+ while (p.startsWith('/')) p = p.slice(1);
290
+ while (p.endsWith('/')) p = p.slice(0, -1);
291
+ return p;
292
+ }
293
+
294
+ /**
295
+ * Unisce piu' gruppi di righe, ognuno con la sua base, in un solo giudice.
296
+ * ⛔ L'ORDINE E' LA PRECEDENZA [G punto 9]: chi arriva dopo vince. Chi chiama passa
297
+ * prima le fonti deboli (`.git/info/exclude`), poi la radice, poi gli annidati per
298
+ * profondita' crescente.
299
+ * @param {{righe: string[], base?: string}[]} gruppi
300
+ */
301
+ export function componiRegole(gruppi) {
302
+ const regole = [];
303
+ for (const gruppo of gruppi ?? []) {
304
+ const base = normalizzaPercorso(gruppo?.base ?? '');
305
+ for (const riga of gruppo?.righe ?? []) {
306
+ const regola = compilaRiga(riga, base);
307
+ if (regola) regole.push(regola);
308
+ }
309
+ }
310
+ return creaGiudice(regole);
311
+ }
312
+
313
+ /**
314
+ * Le regole in forma pura, per poterle provare senza disco.
315
+ * @param {string[]|string} righe
316
+ * @param {{base?: string}} opzioni
317
+ * @returns {{tieni: (percorso: string, eDirectory?: boolean) => boolean, quante: number}}
318
+ */
319
+ export function compilaRegole(righe, { base = '' } = {}) {
320
+ const elenco = typeof righe === 'string' ? righe.split('\n') : (righe ?? []);
321
+ return componiRegole([{ righe: elenco, base }]);
322
+ }
323
+
324
+ function creaGiudice(regole) {
325
+ const memoria = new Map();
326
+
327
+ /*
328
+ * ⛔ 12/09/2026 — LE REGOLE SI INDICIZZANO PER BASE, non si scorrono tutte. Con 6.002 regole
329
+ * (Desktop) ogni percorso nuovo costava 0,265 ms, e una mappa che conta i file di migliaia di
330
+ * cartelle ne chiede decine di migliaia: secondi interi spesi a confrontare `a/b/c` con regole
331
+ * che vivono in `progetti/x/y/` e non possono riguardarlo. Una regola con base `B` puo' matchare
332
+ * solo un percorso che inizia con `B/`: quindi per un percorso si guardano SOLO le regole della
333
+ * radice e dei suoi antenati. L'ordine resta quello di prima — le basi dalla piu' corta alla piu'
334
+ * lunga, e dentro ogni base l'ordine di inserimento — cioe' «piu' si scende piu' si vince»
335
+ * [G punto 9] e «l'ultima che matcha decide» [G punto 2] valgono identici: due basi diverse
336
+ * sullo stesso ramo sono sempre una antenata dell'altra, e la raccolta le aggiunge in ampiezza.
337
+ */
338
+ const perBase = new Map();
339
+ for (const regola of regole) {
340
+ const gruppo = perBase.get(regola.base);
341
+ if (gruppo) gruppo.push(regola); else perBase.set(regola.base, [regola]);
342
+ }
343
+
344
+ /** L'ultima regola che matcha decide [G punto 2]. */
345
+ function decidiRiga(percorso, eDirectory) {
346
+ const chiave = `${eDirectory ? 'd' : 'f'}:${percorso}`;
347
+ const gia = memoria.get(chiave);
348
+ if (gia !== undefined) return gia;
349
+
350
+ let esito = NESSUNA;
351
+ /* Le basi candidate: '' e ogni antenato del percorso, dalla radice in giu'. */
352
+ const basi = [''];
353
+ for (let i = percorso.indexOf('/'); i !== -1; i = percorso.indexOf('/', i + 1)) basi.push(percorso.slice(0, i));
354
+ for (const base of basi) {
355
+ const gruppo = perBase.get(base);
356
+ if (!gruppo) continue;
357
+ const porzione = base === '' ? percorso : percorso.slice(base.length + 1);
358
+ if (porzione === '') continue;
359
+ for (const regola of gruppo) {
360
+ if (regola.soloDirectory && !eDirectory) continue; // [G punto 5]
361
+ if (!regola.regex.test(porzione)) continue;
362
+ esito = regola.negata ? INCLUSO : ESCLUSO;
363
+ }
364
+ }
365
+ memoria.set(chiave, esito);
366
+ return esito;
367
+ }
368
+
369
+ /**
370
+ * true = TIENI. ⛔ Il ciclo sui genitori e' [G punto 3], la regola del 27/08: una
371
+ * negazione NON puo' ripescare un file se una cartella genitore e' esclusa. La faccio
372
+ * qui dentro e non solo nella potatura del camminatore, cosi' l'esito e' giusto anche
373
+ * se qualcuno interroga un percorso profondo di punto in bianco.
374
+ */
375
+ function tieniDa(percorso, eDirectory = false, daSegmento = 1) {
376
+ const norm = normalizzaPercorso(percorso);
377
+ if (norm === '') return true; // la radice non si nasconde mai
378
+ const segmenti = norm.split('/');
379
+ for (let i = Math.max(1, daSegmento); i < segmenti.length; i += 1) {
380
+ if (decidiRiga(segmenti.slice(0, i).join('/'), true) === ESCLUSO) return false;
381
+ }
382
+ return decidiRiga(norm, Boolean(eDirectory)) !== ESCLUSO;
383
+ }
384
+
385
+ const tieni = (percorso, eDirectory = false) => tieniDa(percorso, eDirectory, 1);
386
+
387
+ return { tieni, tieniDa, quante: regole.length, regole };
388
+ }
389
+
390
+ // ─────────────────────────────────────────────────────────────────────────────────────
391
+ // Lettura dal disco
392
+ // ─────────────────────────────────────────────────────────────────────────────────────
393
+
394
+ /**
395
+ * ⛔ Un file che non c'e', o che non si legge, NON deve far sparire niente dall'elenco.
396
+ * Torna [] e va avanti: la direzione dell'errore e' sempre «tengo di piu'».
397
+ */
398
+ async function leggiRighe(fs, percorsoAssoluto) {
399
+ try {
400
+ const testo = await fs.readFile(percorsoAssoluto, 'utf8');
401
+ return typeof testo === 'string' ? testo.split('\n') : [];
402
+ } catch {
403
+ return [];
404
+ }
405
+ }
406
+
407
+ /**
408
+ * Risale da `radice` cercando la cartella di lavoro del repo — quella che contiene `.git`.
409
+ *
410
+ * ⛔ `.git` puo' essere una DIRECTORY (repo normale) o un FILE (worktree: dentro c'e'
411
+ * `gitdir: <percorso>`). Vanno bene entrambi: questa sessione gira proprio in un worktree,
412
+ * e trattarne solo uno dei due avrebbe fatto fallire la risalita in silenzio.
413
+ *
414
+ * ⛔ Due tetti dichiarati, per non salire all'infinito verso `C:\`:
415
+ * - `risalitaMassima` livelli (default 64);
416
+ * - lo stop naturale quando `dirname(x) === x`, cioe' la radice del volume.
417
+ * Se non si trova nessun `.git`, ci si ferma alla radice DATA: una cartella di lavoro che
418
+ * non e' un repo non deve far salire il filtro sopra quello che l'utente ha aperto.
419
+ */
420
+ async function trovaRadiceRepo(fs, radice, risalitaMassima) {
421
+ if (typeof fs.stat !== 'function') return null;
422
+ let corrente = radice;
423
+ for (let salite = 0; salite <= risalitaMassima; salite += 1) {
424
+ try {
425
+ await fs.stat(join(corrente, '.git')); // file o directory: basta che esista
426
+ return corrente;
427
+ } catch { /* non qui: si sale */ }
428
+ const sopra = dirname(corrente);
429
+ if (!sopra || sopra === corrente) return null; // radice del volume
430
+ corrente = sopra;
431
+ }
432
+ return null; // tetto raggiunto
433
+ }
434
+
435
+ /**
436
+ * Dove sta `info/exclude` per questo repo.
437
+ * Repo normale: `<radiceRepo>/.git/info/exclude`.
438
+ * Worktree: `.git` e' un FILE con `gitdir:`, e le regole condivise stanno nel COMMON DIR,
439
+ * che il file `commondir` dentro il gitdir indica. Se qualcosa non torna si rinuncia:
440
+ * perdere `info/exclude` significa TENERE qualche file in piu', mai nasconderne.
441
+ */
442
+ async function cartellaGit(fs, radiceRepo) {
443
+ const punto = join(radiceRepo, '.git');
444
+ try {
445
+ const stato = await fs.stat(punto);
446
+ if (stato?.isDirectory?.()) return punto;
447
+ } catch { return null; }
448
+ try {
449
+ const testo = await fs.readFile(punto, 'utf8');
450
+ const trovato = /^gitdir:\s*(.+)$/m.exec(String(testo));
451
+ if (!trovato) return null;
452
+ const gitdir = trovato[1].trim();
453
+ try {
454
+ const comune = String(await fs.readFile(join(gitdir, 'commondir'), 'utf8')).trim();
455
+ return isAbsolute(comune) ? comune : join(gitdir, comune);
456
+ } catch {
457
+ return gitdir;
458
+ }
459
+ } catch { return null; }
460
+ }
461
+
462
+ /**
463
+ * Legge le regole da una cartella e restituisce il filtro da dare al camminatore.
464
+ *
465
+ * ⛔⛔ LA RACCOLTA PARTE DALLA RADICE DEL REPO, NON DALLA CARTELLA DI LAVORO.
466
+ * [G] «Patterns read from a .gitignore file in the same directory as the path, or IN ANY
467
+ * PARENT DIRECTORY (up to the top-level of the working tree) […]». Una cartella di lavoro
468
+ * e' quasi sempre una SOTTOCARTELLA del repo, e le regole che contano di piu' (quelle degli
469
+ * artefatti) stanno nel `.gitignore` di radice. Misurato il 10/09/2026 su `harness-ui/`:
470
+ * partendo dalla sottocartella si trovavano 7 regole da 2 fonti invece delle 940 da 56 che
471
+ * si vedono dalla radice, e 944 file di artefatti che git considera ignorati finivano
472
+ * nell'elenco dato al modello, mangiando il tetto di 1.500.
473
+ * ⇒ Il giudice ragiona in coordinate RELATIVE ALLA RADICE DEL REPO; il filtro pubblico
474
+ * riceve percorsi relativi alla cartella di lavoro e antepone il prefisso.
475
+ *
476
+ * ⛔ SCELTA DICHIARATA (L7): se la cartella di lavoro STESSA e' ignorata (aprire
477
+ * `node_modules/` come workspace), il filtro NON svuota l'elenco. Git li' non mostrerebbe
478
+ * niente, ma qui l'utente ha scelto quella cartella apposta, e un elenco vuoto sarebbe di
479
+ * nuovo «nascondere al modello file che esistono». I genitori si controllano solo DENTRO
480
+ * la cartella di lavoro; le regole dei genitori si applicano ai percorsi lo stesso.
481
+ *
482
+ * Cerca i `.gitignore` ANNIDATI scendendo in ampiezza e POTANDO con le regole gia' note:
483
+ * non entra in `node_modules` se il `.gitignore` di radice lo esclude, quindi il costo e'
484
+ * proporzionale alle cartelle che il camminatore visitera' comunque.
485
+ *
486
+ * @param {{radice: string, fs?: object, profonditaMassima?: number, cartelleMassime?: number,
487
+ * risalitaMassima?: number}} opzioni
488
+ * @returns {Promise<((percorsoRelativo: string, eDirectory?: boolean) => boolean) &
489
+ * {quante: number, fonti: string[], radiceRepo: string|null, prefissoLavoro: string}>}
490
+ */
491
+ export async function creaFiltroGitignore({
492
+ radice,
493
+ fs = fsPromises,
494
+ profonditaMassima = PROFONDITA_MASSIMA,
495
+ cartelleMassime = CARTELLE_MASSIME,
496
+ risalitaMassima = RISALITA_MASSIMA,
497
+ tempoMassimoMs = TEMPO_MASSIMO_RACCOLTA_MS,
498
+ orologio = () => performance.now(),
499
+ } = {}) {
500
+ const regole = [];
501
+ const fonti = [];
502
+ const avvioMs = orologio();
503
+ const budgetMs = Number.isFinite(tempoMassimoMs) ? Math.max(0, tempoMassimoMs) : Infinity;
504
+ let incompleto = false;
505
+
506
+ const aggiungi = (righe, base, etichetta) => {
507
+ const prima = regole.length;
508
+ for (const riga of righe) {
509
+ const regola = compilaRiga(riga, base);
510
+ if (regola) regole.push(regola);
511
+ }
512
+ if (regole.length > prima) fonti.push(etichetta);
513
+ };
514
+
515
+ // ⛔ RISALITA FINO ALLA RADICE DEL REPO — e in che cosa DIVERGO da ripgrep.
516
+ // [R] ripgrep, crate `ignore`, `Ignore::add_parents()` in `crates/ignore/src/dir.rs`,
517
+ // sorgente letto il 10/09/2026:
518
+ // https://github.com/BurntSushi/ripgrep/blob/master/crates/ignore/src/dir.rs
519
+ // Accumula TUTTI gli antenati fino alla radice del filesystem e NON si ferma al repo:
520
+ // tiene un flag `has_git`, calcolato con `parent.join(".git").exists()`, e lo usa per
521
+ // la precedenza. ⭐ Da li' prendo la rilevazione con `exists()`, che copre `.git`
522
+ // DIRECTORY e `.git` FILE (worktree) senza distinguerli — e' il caso di oggi.
523
+ // ⛔ Ma qui mi FERMO al primo `.git`: un elenco per il modello non deve ereditare
524
+ // regole da cartelle fuori dal progetto che l'utente ha aperto.
525
+ // [R2] ripgrep CHANGELOG 15.0.0 (2025-10-15), letto il 10/09/2026: fra le correzioni,
526
+ // «a commonly reported bug related to applying gitignore rules from parent
527
+ // directories». ⇒ Il buco che sto chiudendo qui e' il difetto CLASSICO di questa
528
+ // funzione, non una svista locale: chi lo scrive lo sbaglia quasi sempre.
529
+ const radiceRepo = await trovaRadiceRepo(fs, radice, risalitaMassima);
530
+ const partenza = radiceRepo ?? radice;
531
+ // Il pezzo di percorso fra la radice del repo e la cartella di lavoro, con `/`.
532
+ const prefissoLavoro = radiceRepo ? normalizzaPercorso(relative(radiceRepo, radice)) : '';
533
+ const segmentiPrefisso = prefissoLavoro === '' ? 0 : prefissoLavoro.split('/').length;
534
+ const sulDisco = (base) => join(partenza, ...(base ? base.split('/') : []));
535
+
536
+ // `.git/` non entra mai in un elenco per il modello: git stesso non lo lista.
537
+ // Prima di tutto il resto, cosi' resta la regola piu' DEBOLE.
538
+ aggiungi(['.git/'], '', '(implicita) .git/');
539
+
540
+ // Precedenza piu' bassa dei `.gitignore`, quindi prima di loro [G, DESCRIPTION].
541
+ // ⛔ L1: `core.excludesFile` no — quello e' dell'utente, non del progetto.
542
+ const dotGit = radiceRepo ? await cartellaGit(fs, radiceRepo) : null;
543
+ if (dotGit) {
544
+ const righe = await leggiRighe(fs, join(dotGit, 'info', 'exclude'));
545
+ if (righe.length) aggiungi(righe, '', FONTI_IMPLICITE[0]);
546
+ }
547
+
548
+ // I `.gitignore` dei GENITORI, dalla radice del repo giu' fino alla cartella di lavoro
549
+ // (esclusa: quella la legge la camminata qui sotto). Ognuno con la SUA base, e piu' si
550
+ // scende piu' si vince [G punto 9].
551
+ const scaletta = prefissoLavoro === '' ? [] : prefissoLavoro.split('/');
552
+ for (let i = 0; i < scaletta.length; i += 1) {
553
+ const base = scaletta.slice(0, i).join('/');
554
+ const righe = await leggiRighe(fs, join(sulDisco(base), NOME_FILE_REGOLE));
555
+ if (righe.length) aggiungi(righe, base, base ? `${base}/${NOME_FILE_REGOLE}` : NOME_FILE_REGOLE);
556
+ }
557
+
558
+ // Ampiezza dalla cartella di lavoro in giu'. Le basi restano relative al REPO.
559
+ const giudiceVivo = () => creaGiudice(regole);
560
+ const coda = [prefissoLavoro];
561
+ let visitate = 0;
562
+
563
+ while (coda.length > 0 && visitate < cartelleMassime) {
564
+ if (orologio() - avvioMs > budgetMs) { incompleto = true; break; } // tetto in tempo (12/09): si dichiara, non si nasconde
565
+ const base = coda.shift();
566
+ visitate += 1;
567
+
568
+ const righe = await leggiRighe(fs, join(sulDisco(base), NOME_FILE_REGOLE));
569
+ if (righe.length) aggiungi(righe, base, base ? `${base}/${NOME_FILE_REGOLE}` : NOME_FILE_REGOLE);
570
+
571
+ if (base.split('/').filter(Boolean).length - segmentiPrefisso >= profonditaMassima) continue;
572
+
573
+ let voci;
574
+ try {
575
+ voci = await fs.readdir(sulDisco(base), { withFileTypes: true });
576
+ } catch {
577
+ continue; // ⛔ una cartella illeggibile non nasconde nulla: semplicemente non porta regole
578
+ }
579
+
580
+ const giudice = giudiceVivo();
581
+ for (const voce of voci) {
582
+ // ⛔ L5: un symlink a cartella non e' isDirectory() qui, e va bene: git non ci scende.
583
+ if (!voce.isDirectory?.()) continue;
584
+ const figlia = base ? `${base}/${voce.name}` : voce.name;
585
+ if (giudice.tieniDa(figlia, true, segmentiPrefisso + 1)) coda.push(figlia);
586
+ }
587
+ }
588
+
589
+ const giudice = creaGiudice(regole);
590
+ const filtro = (percorsoRelativo, eDirectory = false) => {
591
+ const norm = normalizzaPercorso(percorsoRelativo);
592
+ if (norm === '') return true;
593
+ const dalRepo = prefissoLavoro === '' ? norm : `${prefissoLavoro}/${norm}`;
594
+ // ⛔ Il ciclo sui genitori parte SOTTO la cartella di lavoro: vedi L7.
595
+ return giudice.tieniDa(dalRepo, eDirectory, segmentiPrefisso + 1);
596
+ };
597
+ filtro.quante = giudice.quante;
598
+ filtro.fonti = fonti;
599
+ filtro.radiceRepo = radiceRepo;
600
+ filtro.prefissoLavoro = prefissoLavoro;
601
+ filtro.incompleto = incompleto || visitate >= cartelleMassime;
602
+ filtro.msRaccolta = Math.round(orologio() - avvioMs);
603
+ return filtro;
604
+ }