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.
- package/CHANGELOG.md +87 -0
- package/LICENSE +661 -0
- package/README.md +116 -3
- package/THIRD_PARTY_NOTICES.md +40 -0
- package/dist/archive/zip.js +73 -0
- package/dist/args.js +100 -0
- package/dist/automations/history-store.js +34 -0
- package/dist/automations/policy-store.js +43 -0
- package/dist/automations/runner.js +107 -0
- package/dist/automations/schedule.js +85 -0
- package/dist/automations/windows-task.js +53 -0
- package/dist/commands/advanced-cli.js +233 -0
- package/dist/commands/checkpoint-cli.js +45 -0
- package/dist/commands/config-cli.js +107 -0
- package/dist/commands/context.js +17 -0
- package/dist/commands/extensions-cli.js +207 -0
- package/dist/commands/project-cli.js +74 -0
- package/dist/commands/project-commands.js +143 -0
- package/dist/commands/provider-cli.js +244 -0
- package/dist/commands/services-cli.js +248 -0
- package/dist/commands/session-cli.js +171 -0
- package/dist/commands/system-cli.js +405 -0
- package/dist/config/commands.js +60 -0
- package/dist/config/load.js +382 -0
- package/dist/config/migrations.js +48 -0
- package/dist/config/types.js +11 -0
- package/dist/diagnostics/development-log.js +154 -0
- package/dist/diagnostics/doctor.js +104 -0
- package/dist/diagnostics/redact.js +80 -0
- package/dist/diagnostics/zip.js +52 -0
- package/dist/errors.js +156 -0
- package/dist/events/bridge.js +130 -0
- package/dist/extensions/installer.js +178 -0
- package/dist/extensions/package-schema.js +24 -0
- package/dist/headless/result.js +84 -0
- package/dist/headless/run.js +230 -0
- package/dist/i18n/en/approval.js +46 -0
- package/dist/i18n/en/common.js +9 -0
- package/dist/i18n/en/credentials.js +92 -0
- package/dist/i18n/en/errors.js +267 -0
- package/dist/i18n/en/firstrun.js +101 -0
- package/dist/i18n/en/providers.js +37 -0
- package/dist/i18n/en/screen.js +774 -0
- package/dist/i18n/en/tools.js +127 -0
- package/dist/i18n/en.js +14 -0
- package/dist/i18n/error-view.js +307 -0
- package/dist/i18n/index.js +19 -0
- package/dist/i18n/kernel-map.js +139 -0
- package/dist/io.js +45 -0
- package/dist/main.js +331 -0
- package/dist/paths.js +41 -0
- package/dist/protocol/v2/codec.js +9 -0
- package/dist/protocol/v2/events.js +555 -0
- package/dist/protocol/v2/index.js +4 -0
- package/dist/protocol/v2/replay.js +28 -0
- package/dist/protocol/v2/types.js +1 -0
- package/dist/provider/control-plane.js +135 -0
- package/dist/provider/environment-keys.js +275 -0
- package/dist/provider/health.js +110 -0
- package/dist/provider/missing-key.js +48 -0
- package/dist/provider/model-catalog.js +168 -0
- package/dist/provider/openrouter-login.js +172 -0
- package/dist/provider/provider-text.js +13 -0
- package/dist/provider/store.js +95 -0
- package/dist/provider/system-keyring.js +214 -0
- package/dist/runtime/active-run.js +63 -0
- package/dist/runtime/agent-tree.js +74 -0
- package/dist/runtime/attachments.js +84 -0
- package/dist/runtime/brokered-executor.js +395 -0
- package/dist/runtime/context-archive.js +69 -0
- package/dist/runtime/context-status.js +76 -0
- package/dist/runtime/create-runtime.js +111 -0
- package/dist/runtime/model-profile.js +361 -0
- package/dist/runtime/output-store.js +137 -0
- package/dist/runtime/provider-attempts.js +185 -0
- package/dist/runtime/replay-buffer.js +153 -0
- package/dist/runtime/repo.js +95 -0
- package/dist/runtime/session-facade.js +135 -0
- package/dist/runtime/session-summary.js +125 -0
- package/dist/runtime/supervisor.js +265 -0
- package/dist/runtime/talos-composition.js +1011 -0
- package/dist/runtime/types.js +5 -0
- package/dist/runtime/usage-snapshot.js +82 -0
- package/dist/security/auto-classifier.js +38 -0
- package/dist/security/credential-free-environment.js +54 -0
- package/dist/security/evaluate.js +243 -0
- package/dist/security/execution-backends.js +236 -0
- package/dist/security/execution-broker.js +102 -0
- package/dist/security/forge-scan.js +74 -0
- package/dist/security/from-approval.js +39 -0
- package/dist/security/mxc-execution-backend.js +281 -0
- package/dist/security/permission-engine.js +138 -0
- package/dist/security/permission-explanation.js +54 -0
- package/dist/security/persist.js +179 -0
- package/dist/security/plugin-guard.js +230 -0
- package/dist/security/process-tree-evidence-store.js +74 -0
- package/dist/security/process-tree-probe.js +554 -0
- package/dist/security/project-resource-inventory.js +186 -0
- package/dist/security/project-trust-gate.js +38 -0
- package/dist/security/project-trust.js +367 -0
- package/dist/security/rule-parser.js +201 -0
- package/dist/security/shell-segmentation.js +68 -0
- package/dist/security/trust-authority.js +324 -0
- package/dist/security/types.js +1 -0
- package/dist/security/workspace-identity.js +102 -0
- package/dist/services/automation-facade.js +59 -0
- package/dist/services/forge-facade.js +77 -0
- package/dist/services/hook-facade.js +240 -0
- package/dist/services/index.js +16 -0
- package/dist/services/library-facade.js +174 -0
- package/dist/services/mcp-facade.js +348 -0
- package/dist/services/memory-facade.js +126 -0
- package/dist/services/notes-facade.js +157 -0
- package/dist/services/plugin-facade.js +308 -0
- package/dist/services/research-facade.js +110 -0
- package/dist/services/task-board-facade.js +236 -0
- package/dist/services/workflow-catalog.js +246 -0
- package/dist/sessions/export-format.js +98 -0
- package/dist/sessions/metadata-store.js +160 -0
- package/dist/sessions/share.js +122 -0
- package/dist/sessions/transfer.js +16 -0
- package/dist/subcommands.js +62 -0
- package/dist/tui/agent-roster.js +36 -0
- package/dist/tui/agent-view.js +51 -0
- package/dist/tui/app.js +4098 -0
- package/dist/tui/approval.js +36 -0
- package/dist/tui/boot/boot-sequence.js +76 -0
- package/dist/tui/boot/cinematic.js +243 -0
- package/dist/tui/boot/desktop-logo.js +82 -0
- package/dist/tui/boot.js +3 -0
- package/dist/tui/busy-input.js +58 -0
- package/dist/tui/catalog-service.js +560 -0
- package/dist/tui/components/assistant-stream.js +1 -0
- package/dist/tui/components/command-menu.js +68 -0
- package/dist/tui/components/composer.js +219 -0
- package/dist/tui/components/diff.js +35 -0
- package/dist/tui/components/footer.js +48 -0
- package/dist/tui/components/header.js +6 -0
- package/dist/tui/components/markdown.js +305 -0
- package/dist/tui/components/status-indicator.js +38 -0
- package/dist/tui/components/terminal-shell.js +214 -0
- package/dist/tui/components/thinking-row.js +19 -0
- package/dist/tui/components/tool-row.js +97 -0
- package/dist/tui/components/transcript-virtualizer.js +165 -0
- package/dist/tui/components/transcript.js +43 -0
- package/dist/tui/descendant-approvals.js +104 -0
- package/dist/tui/diff-model.js +77 -0
- package/dist/tui/editor-history.js +21 -0
- package/dist/tui/editor.js +210 -0
- package/dist/tui/event-adapter.js +436 -0
- package/dist/tui/exit-output.js +58 -0
- package/dist/tui/external-editor.js +53 -0
- package/dist/tui/file-completion.js +89 -0
- package/dist/tui/focus-manager.js +5 -0
- package/dist/tui/highlight.js +30 -0
- package/dist/tui/input-router.js +18 -0
- package/dist/tui/interrupt.js +99 -0
- package/dist/tui/keybindings.js +194 -0
- package/dist/tui/keymap-resolver.js +91 -0
- package/dist/tui/launch-state.js +148 -0
- package/dist/tui/line-diff.js +57 -0
- package/dist/tui/live-activity.js +56 -0
- package/dist/tui/metrics.js +123 -0
- package/dist/tui/onboarding.js +36 -0
- package/dist/tui/overlays/agent-tree.js +43 -0
- package/dist/tui/overlays/approval-dialog.js +642 -0
- package/dist/tui/overlays/automation-center.js +51 -0
- package/dist/tui/overlays/checkpoint-picker.js +47 -0
- package/dist/tui/overlays/context-inspector.js +36 -0
- package/dist/tui/overlays/effort-line.js +110 -0
- package/dist/tui/overlays/forge-center.js +46 -0
- package/dist/tui/overlays/help-dialog.js +16 -0
- package/dist/tui/overlays/history-picker.js +37 -0
- package/dist/tui/overlays/hook-center.js +70 -0
- package/dist/tui/overlays/library-center.js +55 -0
- package/dist/tui/overlays/mcp-center.js +60 -0
- package/dist/tui/overlays/memory-center.js +63 -0
- package/dist/tui/overlays/model-picker.js +77 -0
- package/dist/tui/overlays/notes-center.js +53 -0
- package/dist/tui/overlays/overlay-host.js +8 -0
- package/dist/tui/overlays/plugin-center.js +76 -0
- package/dist/tui/overlays/provider-picker.js +171 -0
- package/dist/tui/overlays/queue-editor.js +32 -0
- package/dist/tui/overlays/research-center.js +59 -0
- package/dist/tui/overlays/scroll-window.js +234 -0
- package/dist/tui/overlays/session-picker.js +115 -0
- package/dist/tui/overlays/tasks-center.js +83 -0
- package/dist/tui/overlays/theme-picker.js +21 -0
- package/dist/tui/overlays/transcript-search.js +58 -0
- package/dist/tui/overlays/trust-center.js +29 -0
- package/dist/tui/overlays/workflow-center.js +46 -0
- package/dist/tui/project-file-index.js +214 -0
- package/dist/tui/project-references.js +85 -0
- package/dist/tui/project-trust-prompt.js +289 -0
- package/dist/tui/prompt-history-store.js +116 -0
- package/dist/tui/queue-store.js +110 -0
- package/dist/tui/regions/budget.js +59 -0
- package/dist/tui/regions/views.js +96 -0
- package/dist/tui/render-coordinator.js +148 -0
- package/dist/tui/render-scheduler.js +4 -0
- package/dist/tui/run.js +69 -0
- package/dist/tui/selection-list.js +29 -0
- package/dist/tui/session-controller.js +791 -0
- package/dist/tui/session-export.js +54 -0
- package/dist/tui/setup-wizard.js +46 -0
- package/dist/tui/shell-input.js +35 -0
- package/dist/tui/shell-layout.js +48 -0
- package/dist/tui/shell-model.js +98 -0
- package/dist/tui/slash-commands.js +82 -0
- package/dist/tui/state.js +151 -0
- package/dist/tui/status-bar.js +125 -0
- package/dist/tui/status-view.js +40 -0
- package/dist/tui/terminal-capabilities.js +9 -0
- package/dist/tui/terminal-session.js +11 -0
- package/dist/tui/text-width.js +66 -0
- package/dist/tui/theme-catalog.js +27 -0
- package/dist/tui/theme-store.js +23 -0
- package/dist/tui/theme.js +23 -0
- package/dist/tui/tool-display.js +135 -0
- package/dist/tui/tool-facts.js +1 -0
- package/dist/tui/tools/bash-renderer.js +32 -0
- package/dist/tui/tools/change.js +61 -0
- package/dist/tui/tools/edit-renderer.js +17 -0
- package/dist/tui/tools/generic-renderer.js +13 -0
- package/dist/tui/tools/list-renderer.js +14 -0
- package/dist/tui/tools/read-renderer.js +13 -0
- package/dist/tui/tools/registry.js +20 -0
- package/dist/tui/tools/row-format.js +187 -0
- package/dist/tui/tools/search-renderer.js +38 -0
- package/dist/tui/tools/shared.js +97 -0
- package/dist/tui/tools/write-renderer.js +15 -0
- package/dist/tui/transcript-model.js +441 -0
- package/dist/tui/ui-preferences.js +79 -0
- package/dist/tui/usage-view.js +77 -0
- package/dist/tui/vim-mode.js +99 -0
- package/dist/update/check.js +15 -0
- package/dist/update/npm.js +51 -0
- package/dist/update/run.js +129 -0
- package/dist/version.js +2 -0
- package/dist/workspace/checkpoint-store.js +210 -0
- package/dist/workspace/checkpoint.js +413 -0
- package/dist/workspace/restore.js +232 -0
- package/package.json +64 -5
- package/vendor/context-engine/package.json +11 -0
- package/vendor/context-engine/src/compaction-planner.mjs +57 -0
- package/vendor/context-engine/src/contracts.mjs +48 -0
- package/vendor/context-engine/src/engine.mjs +445 -0
- package/vendor/context-engine/src/node/context-export.mjs +164 -0
- package/vendor/context-engine/src/node/legacy-import.mjs +92 -0
- package/vendor/context-engine/src/node/migrations/001-context.sql +126 -0
- package/vendor/context-engine/src/node/sqlite-store.mjs +85 -0
- package/vendor/context-engine/src/node/sqlite-worker.mjs +559 -0
- package/vendor/context-engine/src/profiles.mjs +10 -0
- package/vendor/context-engine/src/retrieval.mjs +104 -0
- package/vendor/context-engine/src/summary.mjs +97 -0
- package/vendor/context-engine/src/usage.mjs +34 -0
- package/vendor/harness-ui/package.json +38 -0
- package/vendor/harness-ui/src/acp-agent.mjs +350 -0
- package/vendor/harness-ui/src/agent-service.mjs +2188 -0
- package/vendor/harness-ui/src/agui-events.mjs +452 -0
- package/vendor/harness-ui/src/ambiente-solo-server.mjs +121 -0
- package/vendor/harness-ui/src/artifact-store.mjs +39 -0
- package/vendor/harness-ui/src/assistenza.mjs +123 -0
- package/vendor/harness-ui/src/automation-scheduler.mjs +69 -0
- package/vendor/harness-ui/src/automation-store.mjs +145 -0
- package/vendor/harness-ui/src/browser-annota.mjs +639 -0
- package/vendor/harness-ui/src/browser-frame.mjs +211 -0
- package/vendor/harness-ui/src/browser-proxy-universale.mjs +519 -0
- package/vendor/harness-ui/src/browser-proxy.mjs +87 -0
- package/vendor/harness-ui/src/browser-sessione-viva.mjs +329 -0
- package/vendor/harness-ui/src/browser-stream.mjs +445 -0
- package/vendor/harness-ui/src/browser-vivo.mjs +694 -0
- package/vendor/harness-ui/src/chat-image-attachments.mjs +72 -0
- package/vendor/harness-ui/src/config.mjs +697 -0
- package/vendor/harness-ui/src/contesto-del-progetto.mjs +385 -0
- package/vendor/harness-ui/src/context-asset-adapter.mjs +72 -0
- package/vendor/harness-ui/src/context-desktop-service.mjs +253 -0
- package/vendor/harness-ui/src/context-embedding-runtime.mjs +252 -0
- package/vendor/harness-ui/src/context-inference-scheduler.mjs +81 -0
- package/vendor/harness-ui/src/context-native-compaction.mjs +75 -0
- package/vendor/harness-ui/src/context-provider-adapter.mjs +141 -0
- package/vendor/harness-ui/src/context-runtime.mjs +118 -0
- package/vendor/harness-ui/src/context-token-counters.mjs +184 -0
- package/vendor/harness-ui/src/context-tool-catalog.mjs +86 -0
- package/vendor/harness-ui/src/context-tool-output.mjs +72 -0
- package/vendor/harness-ui/src/costo-elenco.mjs +252 -0
- package/vendor/harness-ui/src/custom-task.mjs +171 -0
- package/vendor/harness-ui/src/doctor.mjs +142 -0
- package/vendor/harness-ui/src/document-filename.mjs +97 -0
- package/vendor/harness-ui/src/document-generator.mjs +493 -0
- package/vendor/harness-ui/src/document-report.mjs +331 -0
- package/vendor/harness-ui/src/duckduckgo-search.mjs +155 -0
- package/vendor/harness-ui/src/elenco-profondo.mjs +337 -0
- package/vendor/harness-ui/src/favicon-proxy.mjs +113 -0
- package/vendor/harness-ui/src/forge-contract.mjs +221 -0
- package/vendor/harness-ui/src/frequent-dirs.mjs +134 -0
- package/vendor/harness-ui/src/generated-image-store.mjs +147 -0
- package/vendor/harness-ui/src/generation-idle.mjs +332 -0
- package/vendor/harness-ui/src/gguf-header.mjs +207 -0
- package/vendor/harness-ui/src/git-service.mjs +626 -0
- package/vendor/harness-ui/src/gitignore-elenco.mjs +604 -0
- package/vendor/harness-ui/src/harness-receipt-keypair.mjs +207 -0
- package/vendor/harness-ui/src/hf-direct-transfer.mjs +170 -0
- package/vendor/harness-ui/src/hf-hub-client.mjs +106 -0
- package/vendor/harness-ui/src/hf-image-proxy.mjs +105 -0
- package/vendor/harness-ui/src/hf-model-transfer.mjs +245 -0
- package/vendor/harness-ui/src/hook-registry.mjs +186 -0
- package/vendor/harness-ui/src/http-app.mjs +6259 -0
- package/vendor/harness-ui/src/http-lifecycle.mjs +132 -0
- package/vendor/harness-ui/src/id-archivio.mjs +27 -0
- package/vendor/harness-ui/src/image-generator.mjs +143 -0
- package/vendor/harness-ui/src/istruzioni-di-progetto.mjs +234 -0
- package/vendor/harness-ui/src/kernel/dist/kernelPerIlBanco.js +518 -0
- package/vendor/harness-ui/src/kernel/talosHarness.mjs +10437 -0
- package/vendor/harness-ui/src/library-policy-store.mjs +175 -0
- package/vendor/harness-ui/src/library-store.mjs +652 -0
- package/vendor/harness-ui/src/llama-server-supervisor.mjs +629 -0
- package/vendor/harness-ui/src/local-model-store.mjs +339 -0
- package/vendor/harness-ui/src/local-runtime-contract.mjs +66 -0
- package/vendor/harness-ui/src/local-runtime-events.mjs +44 -0
- package/vendor/harness-ui/src/local-runtime-llama-server.mjs +244 -0
- package/vendor/harness-ui/src/local-runtime-probe.mjs +401 -0
- package/vendor/harness-ui/src/machine-capacity.mjs +66 -0
- package/vendor/harness-ui/src/mappa-cartelle.mjs +491 -0
- package/vendor/harness-ui/src/mcp-client.mjs +98 -0
- package/vendor/harness-ui/src/mcp-registry.mjs +157 -0
- package/vendor/harness-ui/src/mcp-session.mjs +177 -0
- package/vendor/harness-ui/src/memory-store.mjs +227 -0
- package/vendor/harness-ui/src/model-catalog-models-dev.mjs +276 -0
- package/vendor/harness-ui/src/model-catalog.mjs +129 -0
- package/vendor/harness-ui/src/model-destination.mjs +189 -0
- package/vendor/harness-ui/src/modifica-ancorata.mjs +177 -0
- package/vendor/harness-ui/src/native-provider-adapter.mjs +205 -0
- package/vendor/harness-ui/src/notes-store.mjs +250 -0
- package/vendor/harness-ui/src/openai-compatible-runtime.mjs +428 -0
- package/vendor/harness-ui/src/openrouter-oauth.mjs +339 -0
- package/vendor/harness-ui/src/path-policy.mjs +442 -0
- package/vendor/harness-ui/src/plugin-registry.mjs +780 -0
- package/vendor/harness-ui/src/plugin-session.mjs +180 -0
- package/vendor/harness-ui/src/process-policy.mjs +345 -0
- package/vendor/harness-ui/src/prompt-enhancer-provider.mjs +94 -0
- package/vendor/harness-ui/src/provider-auth-cloud.mjs +95 -0
- package/vendor/harness-ui/src/provider-credential-store.mjs +541 -0
- package/vendor/harness-ui/src/provider-probe.mjs +582 -0
- package/vendor/harness-ui/src/provider-registry.mjs +1633 -0
- package/vendor/harness-ui/src/pty-terminal.mjs +312 -0
- package/vendor/harness-ui/src/public-problem.mjs +109 -0
- package/vendor/harness-ui/src/research/card.mjs +235 -0
- package/vendor/harness-ui/src/research/citations.mjs +142 -0
- package/vendor/harness-ui/src/research/collector.mjs +275 -0
- package/vendor/harness-ui/src/research/deposito-a-pezzi.mjs +139 -0
- package/vendor/harness-ui/src/research/dossier.mjs +114 -0
- package/vendor/harness-ui/src/research/esportazioni.mjs +560 -0
- package/vendor/harness-ui/src/research/fetch-cache.mjs +465 -0
- package/vendor/harness-ui/src/research/fidelity.mjs +122 -0
- package/vendor/harness-ui/src/research/independence.mjs +159 -0
- package/vendor/harness-ui/src/research/ledger.mjs +166 -0
- package/vendor/harness-ui/src/research/markdown-server.mjs +565 -0
- package/vendor/harness-ui/src/research/narration.mjs +181 -0
- package/vendor/harness-ui/src/research/open-cards.mjs +131 -0
- package/vendor/harness-ui/src/research/opposing.mjs +305 -0
- package/vendor/harness-ui/src/research/outline.mjs +111 -0
- package/vendor/harness-ui/src/research/page-budget.mjs +209 -0
- package/vendor/harness-ui/src/research/pdf.mjs +291 -0
- package/vendor/harness-ui/src/research/plan.mjs +301 -0
- package/vendor/harness-ui/src/research/raccolta-viva.mjs +452 -0
- package/vendor/harness-ui/src/research/recheck-document.mjs +69 -0
- package/vendor/harness-ui/src/research/recheck-history.mjs +192 -0
- package/vendor/harness-ui/src/research/recheck.mjs +194 -0
- package/vendor/harness-ui/src/research/report.mjs +203 -0
- package/vendor/harness-ui/src/research/run.mjs +527 -0
- package/vendor/harness-ui/src/research/synthesis.mjs +318 -0
- package/vendor/harness-ui/src/research/verification.mjs +572 -0
- package/vendor/harness-ui/src/research-orchestrator.mjs +2679 -0
- package/vendor/harness-ui/src/research-store.mjs +1133 -0
- package/vendor/harness-ui/src/runtime-build-manifest.mjs +26 -0
- package/vendor/harness-ui/src/runtime-contract.mjs +59 -0
- package/vendor/harness-ui/src/runtime-owner-adapter.mjs +1348 -0
- package/vendor/harness-ui/src/runtime-owner-contract.mjs +32 -0
- package/vendor/harness-ui/src/scheda-di-lavoro.mjs +249 -0
- package/vendor/harness-ui/src/search-source-store.mjs +172 -0
- package/vendor/harness-ui/src/session-registry.mjs +6095 -0
- package/vendor/harness-ui/src/session-store.mjs +220 -0
- package/vendor/harness-ui/src/sessione-pronta.mjs +73 -0
- package/vendor/harness-ui/src/setup-stato.mjs +31 -0
- package/vendor/harness-ui/src/sezioni-istruzioni.mjs +204 -0
- package/vendor/harness-ui/src/skill-registry.mjs +120 -0
- package/vendor/harness-ui/src/sse-replay-coalescente.mjs +0 -0
- package/vendor/harness-ui/src/static-files.mjs +96 -0
- package/vendor/harness-ui/src/stream-partition.mjs +123 -0
- package/vendor/harness-ui/src/subagent-orchestrator.mjs +453 -0
- package/vendor/harness-ui/src/task-catalog.mjs +65 -0
- package/vendor/harness-ui/src/tasks-store.mjs +220 -0
- package/vendor/harness-ui/src/terminal-registry.mjs +312 -0
- package/vendor/harness-ui/src/terminal-ws.mjs +170 -0
- package/vendor/harness-ui/src/tool-forge-store.mjs +299 -0
- package/vendor/harness-ui/src/tool-schema-normalize.mjs +100 -0
- package/vendor/harness-ui/src/usage-cache.mjs +315 -0
- package/vendor/harness-ui/src/workspace-browser.mjs +213 -0
- package/vendor/harness-ui/src/workspace-context.mjs +124 -0
- package/vendor/harness-ui/src/workspace-disk.mjs +62 -0
- package/vendor/harness-ui/src/workspace-files.mjs +589 -0
- package/vendor/harness-ui/src/workspace-info.mjs +189 -0
- package/vendor/harness-ui/src/workspace-launch-store.mjs +150 -0
- package/vendor/harness-ui/src/workspace-tree.mjs +67 -0
- package/vendor/harness-ui/src/workspace-watcher.mjs +161 -0
- package/vendor/manifest.json +170 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ⛔⛔⛔ IL PREAMBOLO — quello che il modello legge PRIMA della consegna, e che si paga a ogni invio.
|
|
3
|
+
*
|
|
4
|
+
* ════ COS'ERA, MISURATO L'11/09/2026 ═════════════════════════════════════════════════════════
|
|
5
|
+
*
|
|
6
|
+
* Questo modulo mandava al modello **l'elenco dei file** dello spazio di lavoro. Misurato con lo
|
|
7
|
+
* stimatore del prodotto (`costo-elenco.mjs`, metodo «stimato», 3,5 byte/token — la taratura del
|
|
8
|
+
* 09/09 su `z-ai/glm-5.3-flash`):
|
|
9
|
+
*
|
|
10
|
+
* spazio di lavoro elenco file percorsi troncato
|
|
11
|
+
* ───────────────── ─────────── ────────── ─────────────────────────────────────
|
|
12
|
+
* AVM/mobile 17.149 token 1.500 ⚠ SÌ — l'albero ne ha 1.842 (il 30%…)
|
|
13
|
+
* harness-ui/ 7.267 token 693 no
|
|
14
|
+
* TALOS-PAROLA (piccolo) 85 token 10 no
|
|
15
|
+
*
|
|
16
|
+
* ⇒ Su `AVM/mobile` pagavamo 17.000 token per mostrare **il 30% dei file** e per dire al modello,
|
|
17
|
+
* nel testo stesso, di non fidarsi dell'elenco. Sulla mediana misurata in BC-07 il primo
|
|
18
|
+
* messaggio pesa **29.148 token**: l'elenco ne era la parte più grossa.
|
|
19
|
+
*
|
|
20
|
+
* ⛔ E NESSUNO DEI QUATTRO CONCORRENTI FA COSÌ. Letti nel codice l'11/09
|
|
21
|
+
* (`.claude/RAPPORTO-PREAMBOLO-CONCORRENTI-2026-09-11.md`): Codex manda 35 token di ambiente +
|
|
22
|
+
* `AGENTS.md` (32 KiB) e cerca con `rg`; Claude Code 2.1.268 manda quattro chiavi di sessione e
|
|
23
|
+
* `gitStatus` tagliato a 2.000 caratteri; Hermes v0.21 manda 100-130 token di «workspace
|
|
24
|
+
* snapshot»; DeepSeek `dsh` manda **una frase**. Tutti e quattro mandano le ISTRUZIONI di
|
|
25
|
+
* progetto. **TALOS era l'unico che mandava l'inventario e non le istruzioni.**
|
|
26
|
+
*
|
|
27
|
+
* ════ COS'È ADESSO — QUATTRO BLOCCHI, IN ORDINE DI STABILITÀ ═════════════════════════════════
|
|
28
|
+
*
|
|
29
|
+
* 1. Istruzioni del kernel .... in `talosHarness.mjs` (`ISTRUZIONI`), 97 token, non si tocca
|
|
30
|
+
* 2. Istruzioni di progetto ... `istruzioni-di-progetto.mjs` — AGENTS.md/CLAUDE.md, tetto in byte
|
|
31
|
+
* 3. Mappa delle CARTELLE ..... `mappa-cartelle.mjs` — stabile nella finestra SWR
|
|
32
|
+
* 4. Scheda di lavoro ......... `scheda-di-lavoro.mjs` — stato git, permesso, modello, verifica
|
|
33
|
+
*
|
|
34
|
+
* I blocchi 2-4 li compone questo file, in quest'ordine, e il kernel li mette **subito dopo il
|
|
35
|
+
* blocco 1 e PRIMA della consegna**. L'ordine non è una preferenza: è il vincolo della cache.
|
|
36
|
+
*
|
|
37
|
+
* ════ PERCHÉ IL PREFISSO NON SI RISCRIVE MAI ════════════════════════════════════════════════
|
|
38
|
+
*
|
|
39
|
+
* RICERCA WEB, letta l'11/09/2026 PRIMA di toccare una riga — Claude Platform Docs, «Prompt
|
|
40
|
+
* caching» <https://platform.claude.com/docs/en/docs/build-with-claude/prompt-caching>, verbatim:
|
|
41
|
+
* · *«Cache hits require 100% identical prompt segments»*;
|
|
42
|
+
* · *«Prompt caching references the entire prompt — tools, system, and messages (in that order)
|
|
43
|
+
* up to and including the block designated with cache_control»*: la lookup lavora sul
|
|
44
|
+
* **prefisso intero**, non sul singolo blocco;
|
|
45
|
+
* · i minimi per modello sono **512 / 1.024 / 2.048 / 4.096 token** a seconda del modello, e
|
|
46
|
+
* valgono sul prefisso, non sull'ultimo blocco.
|
|
47
|
+
* E OpenRouter, «Prompt caching» (letto 11/09/2026): i minimi sono 4.096 token per Opus 4.5-4.8 e
|
|
48
|
+
* Haiku 4.5, 1.024 per Sonnet 4.5/4.6 e per OpenAI; Z.AI, DeepSeek, Grok, Moonshot e Groq
|
|
49
|
+
* cacheggiano **in automatico senza marcatori**, Anthropic e Qwen li vogliono espliciti.
|
|
50
|
+
*
|
|
51
|
+
* ⇒ Da qui la regola che i tre harness che gestiscono contesti mutevoli applicano tutti:
|
|
52
|
+
* **il prefisso si costruisce UNA VOLTA e non si tocca più; ciò che cambia si APPENDE in coda,
|
|
53
|
+
* dichiarando che sostituisce.** Codex lo fa con `WorldState::render_diff` +
|
|
54
|
+
* `REPLACEMENT_NOTICE`; Claude Code con *«The session context has changed; these values replace
|
|
55
|
+
* the earlier ones»*; dsh con *«This complete workspace instruction baseline replaces all earlier
|
|
56
|
+
* workspace instruction baselines»*.
|
|
57
|
+
* Qui: `contestoDelProgetto()` costruisce il prefisso, `aggiornamentoInCoda()` costruisce il
|
|
58
|
+
* messaggio da appendere quando qualcosa è cambiato davvero.
|
|
59
|
+
*
|
|
60
|
+
* ⛔ E VALE ANCHE SE LA CACHE NON PRENDE. L'A/B dell'11/09 su `z-ai/glm-5.3-flash` ha dato **0
|
|
61
|
+
* token da cache su due invii consecutivi** anche col `cache_control` per blocco. Un prefisso che
|
|
62
|
+
* non cambia resta comunque **meno byte** e **meno rumore** — e il rumore ha una misura: Chroma,
|
|
63
|
+
* «Context Rot» (14/07/2025, 18 modelli): *«a single distractor reduces performance relative to
|
|
64
|
+
* the baseline»*, e l'effetto cresce con l'input.
|
|
65
|
+
*
|
|
66
|
+
* ════ LA CHIAVE DELLA CACHE — TRE COSE, DICHIARATE ══════════════════════════════════════════
|
|
67
|
+
*
|
|
68
|
+
* Il preambolo dipende da **cartella**, **permesso del giro** e **modello**: sono le tre cose che
|
|
69
|
+
* compaiono nel testo e che possono cambiare senza che il disco cambi. La cache è indicizzata su
|
|
70
|
+
* quelle tre, quindi:
|
|
71
|
+
* · due giri di fila con gli stessi tre valori ⇒ **la STESSA stringa, byte per byte**;
|
|
72
|
+
* · cambia uno dei tre ⇒ stringa nuova, perché il testo dice davvero una cosa diversa.
|
|
73
|
+
* ⛔ La prova sta in `tests/preambolo-quattro-blocchi.test.mjs`, ed è la prova che conta più di
|
|
74
|
+
* tutte le altre di questo modulo.
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
import { costruisciMappaCartelle, mappaEntroIlTetto, TETTO_TOKEN_MAPPA_PREDEFINITO } from './mappa-cartelle.mjs';
|
|
78
|
+
import { istruzioniDiProgetto, trovaRadiceProgetto, TETTO_BYTE_PREDEFINITO } from './istruzioni-di-progetto.mjs';
|
|
79
|
+
import { schedaDiLavoro } from './scheda-di-lavoro.mjs';
|
|
80
|
+
import { costoElenco } from './costo-elenco.mjs';
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Quanto a lungo un preambolo resta buono senza che nessuno dica che i file sono cambiati.
|
|
84
|
+
* ⛔ Non è pigrizia: è la difesa contro il caso in cui il segnale di cambiamento si perda (un file
|
|
85
|
+
* creato da un processo esterno, un `git checkout` fuori da TALOS). Cinque minuti è il compromesso
|
|
86
|
+
* fra «non ricostruire per niente» e «non mentire troppo a lungo» — dichiarato, non misurato.
|
|
87
|
+
*/
|
|
88
|
+
export const VALIDITA_MS = 5 * 60 * 1000;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* ⛔⛔⛔ 12/09/2026 — LA CACHE SERVE SUBITO E SI RINNOVA DOPO (stale-while-revalidate).
|
|
92
|
+
* Owner: «i modelli OpenRouter sono estremamente lenti al primo messaggio, quasi un minuto».
|
|
93
|
+
* Misurato: su `Desktop` il preambolo costa 34.356 ms da costruire, e con una validità di cinque
|
|
94
|
+
* minuti OGNI messaggio mandato dopo una pausa lo ripagava per intero (record `tempi-giro` della
|
|
95
|
+
* sessione 78247740: 41,8 s · 34,3 s · 39,9 s al primo token, tre invii di fila). Una persona che
|
|
96
|
+
* legge la risposta, pensa, e riscrive dopo sei minuti non deve aspettare che il disco venga
|
|
97
|
+
* ricamminato: riceve la mappa di prima — che è anche il prefisso IDENTICO su cui prende la cache
|
|
98
|
+
* del fornitore — e la mappa nuova si costruisce in sottofondo per il messaggio dopo.
|
|
99
|
+
* ⛔ Non è «cache per sempre»: `segnalaFileCambiati` continua a buttarla quando la cartella cambia
|
|
100
|
+
* (WorkspaceChanged), e in quel caso la ricostruzione è sincrona ma ora ha il tetto in tempo
|
|
101
|
+
* di `mappa-cartelle.mjs`. Ciò che cambia è solo il caso «scaduta per età»: prima faceva
|
|
102
|
+
* aspettare, ora no. È la forma di HTTP `stale-while-revalidate` (RFC 5861, §3).
|
|
103
|
+
* ⭐ Il rinnovo in sottofondo è UNO per chiave (`rinnovo` sulla voce): dieci messaggi in fila su
|
|
104
|
+
* una cache scaduta fanno partire una sola camminata, non dieci.
|
|
105
|
+
*/
|
|
106
|
+
export const RINNOVA_IN_SOTTOFONDO = true;
|
|
107
|
+
|
|
108
|
+
/** La memoria dei preamboli già costruiti, per `cartella|permesso|modello`. */
|
|
109
|
+
const cache = new Map();
|
|
110
|
+
|
|
111
|
+
const chiaveDi = (cartella, permesso, modello) => `${cartella}|${permesso ?? ''}|${modello ?? ''}`;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Le frasi della scheda e dell'aggiornamento. Servono a RITROVARLO dentro una
|
|
115
|
+
* conversazione già iniziata — cioè a rispondere alla domanda «che cosa ha già visto questo
|
|
116
|
+
* modello?» **senza tenere nessuno stato in memoria**.
|
|
117
|
+
*
|
|
118
|
+
* ⛔ Perché senza stato: una mappa `sessione → ultimo preambolo` sopravvive al riavvio del server
|
|
119
|
+
* come `null`, e la sessione ripresa dopo un riavvio riceverebbe un «aggiornamento» che non
|
|
120
|
+
* aggiorna niente, oppure niente quando invece qualcosa era cambiato. La conversazione salvata è
|
|
121
|
+
* l'unica fonte che non mente su cosa il modello ha letto. È la stessa scelta di Claude Code
|
|
122
|
+
* 2.1.268, che confronta il contesto di sessione per uguaglianza secca
|
|
123
|
+
* (`function N$t(e,n){return soe.every((r)=>e[r]===n[r])}`) invece di ricordarselo.
|
|
124
|
+
* ⛔ E non sono sentinelle invisibili (`<!--TALOS-PREAMBOLO-->`): sono le prime parole che il
|
|
125
|
+
* modello legge davvero. Una sentinella tecnica costerebbe token per non dire niente a chi legge.
|
|
126
|
+
*/
|
|
127
|
+
export const INIZIO_SCHEDA = 'Scheda di lavoro — ';
|
|
128
|
+
export const INIZIO_AGGIORNAMENTO = 'Aggiornamento del contesto del progetto:';
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Costruisce (o riusa) il PREAMBOLO di una cartella: blocchi 2, 3 e 4 in un testo solo.
|
|
132
|
+
*
|
|
133
|
+
* @param {object} input
|
|
134
|
+
* @param {string} input.cartella
|
|
135
|
+
* @param {(radice: string) => Promise<Function|null>} [input.creaFiltro] — il filtro `.gitignore`,
|
|
136
|
+
* iniettato: questo modulo non deve sapere come si leggono quelle regole.
|
|
137
|
+
* @param {string|null} [input.permesso] — l'etichetta del permesso del giro (entra nella scheda finale)
|
|
138
|
+
* @param {string|null} [input.modello] — il modello del giro (entra nella scheda finale)
|
|
139
|
+
* @param {string|null} [input.piattaforma]
|
|
140
|
+
* @param {number} [input.tettoIstruzioni] — il tetto in byte delle istruzioni
|
|
141
|
+
* @param {boolean} [input.statoVolatile=true] — se falso, la scheda non porta lo stato di git
|
|
142
|
+
* @param {object} [input.contatore] — il contatore di token, se ce n'è uno vero
|
|
143
|
+
* @param {number} [input.finestra] — la finestra del modello, per dire quanto pesa
|
|
144
|
+
* @param {object} [input.deps] — `{fs, adesso, eseguiGit}` per le prove
|
|
145
|
+
* @returns {Promise<{testo:string, blocchi:object, costo:object, riusato:boolean}|null>}
|
|
146
|
+
*/
|
|
147
|
+
export async function contestoDelProgetto({
|
|
148
|
+
cartella, creaFiltro, permesso = null, modello = null, piattaforma = null,
|
|
149
|
+
tettoIstruzioni = TETTO_BYTE_PREDEFINITO, tettoTokenMappa = TETTO_TOKEN_MAPPA_PREDEFINITO,
|
|
150
|
+
statoVolatile = true,
|
|
151
|
+
contatore, finestra, deps = {},
|
|
152
|
+
} = {}) {
|
|
153
|
+
if (typeof cartella !== 'string' || cartella.trim() === '') return null;
|
|
154
|
+
const adesso = deps.adesso ?? (() => Date.now());
|
|
155
|
+
const ora = adesso();
|
|
156
|
+
const chiave = chiaveDi(cartella, permesso, modello);
|
|
157
|
+
|
|
158
|
+
const voce = cache.get(chiave);
|
|
159
|
+
if (voce && ora - voce.quando < VALIDITA_MS) {
|
|
160
|
+
/* ⛔ `riusato` non è un dettaglio da registro: è la prova che il prefisso mandato al fornitore
|
|
161
|
+
è lo STESSO di prima. Se fosse sempre `false`, questo modulo starebbe ricostruendo il
|
|
162
|
+
preambolo a ogni giro e nessuno se ne accorgerebbe. */
|
|
163
|
+
return { ...voce.esito, riusato: true };
|
|
164
|
+
}
|
|
165
|
+
if (voce && RINNOVA_IN_SOTTOFONDO) {
|
|
166
|
+
/* Scaduta per età: si serve quella di prima SUBITO e si rinnova dopo (vedi la nota in testa).
|
|
167
|
+
`stantio` lo dice a chi legge il registro; il testo è byte-identico al precedente. */
|
|
168
|
+
if (!voce.rinnovo) {
|
|
169
|
+
voce.rinnovo = costruisciPreambolo({ cartella, creaFiltro, permesso, modello, piattaforma, tettoIstruzioni, tettoTokenMappa, statoVolatile, contatore, finestra, deps, chiave, rinnovo: true })
|
|
170
|
+
.catch(() => null)
|
|
171
|
+
.finally(() => { const attuale = cache.get(chiave); if (attuale) attuale.rinnovo = null; });
|
|
172
|
+
}
|
|
173
|
+
return { ...voce.esito, riusato: true, stantio: true };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return costruisciPreambolo({ cartella, creaFiltro, permesso, modello, piattaforma, tettoIstruzioni, tettoTokenMappa, statoVolatile, contatore, finestra, deps, chiave });
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** La costruzione vera, separata dalla lettura della cache perché il rinnovo in sottofondo la chiama da solo. */
|
|
180
|
+
async function costruisciPreambolo({ cartella, creaFiltro, permesso, modello, piattaforma, tettoIstruzioni, tettoTokenMappa, statoVolatile, contatore, finestra, deps, chiave, rinnovo = false }) {
|
|
181
|
+
const adesso = deps.adesso ?? (() => Date.now());
|
|
182
|
+
const ora = adesso();
|
|
183
|
+
const filtro = await filtroGitignore(creaFiltro, cartella);
|
|
184
|
+
|
|
185
|
+
/*
|
|
186
|
+
* I tre blocchi si costruiscono IN PARALLELO: la mappa è la parte lenta (404 ms su `AVM/mobile`,
|
|
187
|
+
* 20 ms su `harness-ui/`) e le altre due sono `stat` e `spawn` di git. In serie il preambolo
|
|
188
|
+
* costerebbe la somma; qui costa il massimo.
|
|
189
|
+
* ⛔ Nessuno dei tre può far cadere l'avvio di una sessione: ognuno degrada al proprio vuoto.
|
|
190
|
+
* Ma i due modi di degradare NON sono lo stesso, e la differenza è quella che il 10/09 è
|
|
191
|
+
* costata 25.163 token invece di 6.518 — vedi `filtroGitignore()` qui sotto.
|
|
192
|
+
*/
|
|
193
|
+
const [mappa, istruzioni, scheda, nomeProgetto] = await Promise.all([
|
|
194
|
+
costruisciMappaCartelle({ radice: cartella, filtro, fs: deps.fs }).catch(() => null),
|
|
195
|
+
istruzioniDiProgetto({ cartella, tetto: tettoIstruzioni, fs: deps.fs }),
|
|
196
|
+
schedaDiLavoro({ cartella, permesso, modello, piattaforma, statoVolatile, fs: deps.fs, eseguiGit: deps.eseguiGit }).catch(() => null),
|
|
197
|
+
trovaRadiceProgetto(cartella, { fs: deps.fs }).catch(() => null),
|
|
198
|
+
]);
|
|
199
|
+
|
|
200
|
+
/*
|
|
201
|
+
* ⛔ ZERO CARTELLE E ZERO FILE NON È UN CONTESTO, È UNA BUGIA. Il camminatore non lancia quando
|
|
202
|
+
* una cartella non si legge: la salta con onestà. Ma se l'albero INTERO è vuoto, dire al
|
|
203
|
+
* modello «in questo progetto non c'è niente» sarebbe peggio che non dirgli niente — gli farebbe
|
|
204
|
+
* concludere che i file non esistono, che è esattamente la conclusione sbagliata che tutto
|
|
205
|
+
* questo esiste per impedire ([[un-modello-che-non-vede-non-tace-spiega]]: alla domanda «quanti
|
|
206
|
+
* file .mjs ci sono in harness-ui/src?» TALOS rispose «0 — la cartella non esiste». Sono 104).
|
|
207
|
+
* ⭐ La scheda di lavoro da sola NON basta a far esistere il preambolo: senza mappa e senza
|
|
208
|
+
* istruzioni, ciò che resta («sei in una cartella») non vale i suoi token.
|
|
209
|
+
*/
|
|
210
|
+
const mappaHaSostanza = Boolean(mappa && (mappa.cartelle.length > 0 || mappa.fileTotali > 0));
|
|
211
|
+
if (!mappaHaSostanza && !istruzioni) return null;
|
|
212
|
+
|
|
213
|
+
/*
|
|
214
|
+
* BC-48 C — istruzioni e mappa precedono la scheda: un cambiamento di git non sposta
|
|
215
|
+
* il primo byte diverso davanti ai blocchi stabili. Il marcatore resta al kernel;
|
|
216
|
+
* il riordino da solo non garantisce un hit sui fornitori che cercano confini di blocco.
|
|
217
|
+
* La scheda conserva un ripiego riconoscibile anche quando non si riesce a costruirla.
|
|
218
|
+
*/
|
|
219
|
+
const pezzi = [];
|
|
220
|
+
if (istruzioni?.testo) pezzi.push(istruzioni.testo);
|
|
221
|
+
/*
|
|
222
|
+
* ⛔ IL TETTO DELLA MAPPA E' IN TOKEN, non in cartelle — misurato l'11/09 e non negoziabile:
|
|
223
|
+
* col solo tetto sulle cartelle, lo spazio di lavoro «repo intero» produceva una mappa da
|
|
224
|
+
* 17.966 token e il preambolo nuovo costava +8,4% del vecchio. Cioe' la cura peggiorava il
|
|
225
|
+
* caso peggiore, che e' l'unico che conta. Qui si taglia in PROFONDITA' finche' non entra, e
|
|
226
|
+
* il testo lo dichiara.
|
|
227
|
+
*/
|
|
228
|
+
const resaMappa = mappaHaSostanza ? mappaEntroIlTetto(mappa, { radice: cartella, tettoToken: tettoTokenMappa }) : null;
|
|
229
|
+
if (resaMappa) pezzi.push(resaMappa.testo);
|
|
230
|
+
pezzi.push(scheda?.testo ?? `${INIZIO_SCHEDA}non sono riuscito a leggere lo stato di questa cartella; quello che precede e' comunque vero.`);
|
|
231
|
+
/* Doppio a-capo fra i blocchi: sono tre cose diverse, e un modello che legge un muro di testo
|
|
232
|
+
senza confini le mescola. Costa 2 byte per blocco. */
|
|
233
|
+
const testo = pezzi.join('\n\n');
|
|
234
|
+
|
|
235
|
+
const costo = costoElenco(testo, { finestra, contatore });
|
|
236
|
+
const esito = {
|
|
237
|
+
testo,
|
|
238
|
+
blocchi: {
|
|
239
|
+
scheda: scheda ? { byte: Buffer.byteLength(scheda.testo, 'utf8') } : null,
|
|
240
|
+
istruzioni: istruzioni ? { byte: istruzioni.byte, usati: istruzioni.usati, omessi: istruzioni.omessi, tagliati: istruzioni.tagliati, indicizzati: istruzioni.indicizzati, sezioniSempre: istruzioni.sezioniSempre } : null,
|
|
241
|
+
mappa: resaMappa
|
|
242
|
+
? {
|
|
243
|
+
cartelle: mappa.cartelle.filter((c) => c.livello <= resaMappa.profonditaUsata).length,
|
|
244
|
+
cartelleTotali: mappa.cartelle.length,
|
|
245
|
+
file: mappa.fileTotali,
|
|
246
|
+
/* ⛔ Due modi diversi di essere incompleta, e si dicono per nome: il camminatore si e'
|
|
247
|
+
fermato (`troncata`), oppure e' entrata solo fino a una certa profondita' per stare
|
|
248
|
+
nel tetto di token (`tagliataInProfondita`). Un booleano solo li confonderebbe. */
|
|
249
|
+
troncata: mappa.troncato,
|
|
250
|
+
tagliataInProfondita: resaMappa.tagliataInProfondita,
|
|
251
|
+
/* ⛔ BC-40 (12/09) — TERZO modo, ed è quello NORMALE da oggi: la mappa si ferma alla
|
|
252
|
+
profondità predefinita (2) perché così è stata disegnata, non perché un tetto abbia
|
|
253
|
+
morso. Campo AGGIUNTO, mai sostituito: chi leggeva `troncata`/`tagliataInProfondita`
|
|
254
|
+
continua a leggere esattamente quello che leggeva prima. */
|
|
255
|
+
ridottaPerDisegno: Boolean(mappa.fermatoInProfondita),
|
|
256
|
+
profondita: resaMappa.profonditaUsata,
|
|
257
|
+
profonditaPiena: mappa.profonditaRaggiunta,
|
|
258
|
+
token: resaMappa.token,
|
|
259
|
+
}
|
|
260
|
+
: null,
|
|
261
|
+
},
|
|
262
|
+
nomeProgetto,
|
|
263
|
+
costo,
|
|
264
|
+
riusato: false,
|
|
265
|
+
};
|
|
266
|
+
/* ⛔ Un rinnovo in sottofondo che finisce DOPO un `segnalaFileCambiati` non deve resuscitare
|
|
267
|
+
una voce buttata: si scrive solo se la chiave è ancora quella attesa o se non c'è niente. */
|
|
268
|
+
const precedente = cache.get(chiave);
|
|
269
|
+
if (rinnovo && !precedente) return esito; // buttata da segnalaFileCambiati mentre si ricostruiva: la cartella e' cambiata, questa mappa e' gia' vecchia
|
|
270
|
+
cache.set(chiave, { quando: ora, esito, rinnovo: precedente?.rinnovo ?? null });
|
|
271
|
+
return esito;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Il filtro `.gitignore`, con i DUE MODI DI DEGRADARE tenuti distinti.
|
|
276
|
+
*
|
|
277
|
+
* ⛔⛔ QUESTO CATCH HA GIÀ NASCOSTO UN BUG, il 10/09: il chiamante passava la stringa nuda a
|
|
278
|
+
* `creaFiltroGitignore`, che vuole `{radice}`; Node lanciava `ERR_INVALID_ARG_TYPE` e qui veniva
|
|
279
|
+
* scambiato per un file di regole illeggibile — elenco senza filtro, 1500 percorsi troncati e
|
|
280
|
+
* **25.163 token al posto di ~6.500**, e nessun errore da nessuna parte.
|
|
281
|
+
* ⇒ Un `.gitignore` illeggibile si degrada in silenzio (giusto: il modello vede qualche cartella in
|
|
282
|
+
* più, e il contrario — nessun contesto per colpa di un file di regole — sarebbe rifare il difetto
|
|
283
|
+
* che stiamo curando). Un errore di **CONTRATTO** no: quello è un bug di chi chiama, e deve farsi
|
|
284
|
+
* sentire. Un catch che degrada dice QUALE guasto copre e rilancia gli altri.
|
|
285
|
+
*/
|
|
286
|
+
async function filtroGitignore(creaFiltro, cartella) {
|
|
287
|
+
if (typeof creaFiltro !== 'function') return undefined;
|
|
288
|
+
let regole;
|
|
289
|
+
try {
|
|
290
|
+
regole = await creaFiltro(cartella);
|
|
291
|
+
} catch (errore) {
|
|
292
|
+
if (errore?.code === 'ERR_INVALID_ARG_TYPE' || errore instanceof TypeError) throw errore;
|
|
293
|
+
return undefined;
|
|
294
|
+
}
|
|
295
|
+
if (typeof regole !== 'function') return undefined;
|
|
296
|
+
/*
|
|
297
|
+
* L'ADATTATORE FRA I DUE CONTRATTI. Il camminatore chiama `filtro(percorso, { cartella })` — un
|
|
298
|
+
* OGGETTO; il filtro delle regole si aspetta `(percorso, eDirectory)` — un BOOLEANO
|
|
299
|
+
* (`gitignore-elenco.mjs:281`). Un oggetto è sempre vero: senza questa conversione ogni file
|
|
300
|
+
* verrebbe giudicato come se fosse una cartella, e le regole non morderebbero.
|
|
301
|
+
* ⛔ MISURATO il 10/09: la conversione NON cambia il risultato sull'albero vero (1.629 file in
|
|
302
|
+
* entrambi i casi) — l'avevo scritta credendo fosse la causa di un elenco troncato, e la misura
|
|
303
|
+
* mi ha smentito. Resta perché rende esplicito un contratto che altrimenti regge per caso.
|
|
304
|
+
*/
|
|
305
|
+
return (percorso, forma) => regole(percorso, typeof forma === 'object' && forma !== null ? Boolean(forma.cartella) : Boolean(forma));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* IL CONTESTO CHE SI APPENDE — il messaggio da mettere IN CODA quando il preambolo e' cambiato
|
|
310
|
+
* dopo che il modello l'ha gia' ricevuto.
|
|
311
|
+
*
|
|
312
|
+
* ⛔ Non rigenera il prefisso: lo lascia esattamente dov'e' e dice al modello che cio' che segue
|
|
313
|
+
* SOSTITUISCE. E' la forma che usano tutti e tre gli harness che gestiscono contesti mutevoli:
|
|
314
|
+
* · Codex, `world_state/agents_md.rs:9-11` — «These AGENTS.md instructions replace all
|
|
315
|
+
* previously provided AGENTS.md instructions.»
|
|
316
|
+
* · Claude Code 2.1.268 — «The session context has changed; these values replace the earlier
|
|
317
|
+
* ones», con confronto per uguaglianza secca e un elenco chiuso di cause;
|
|
318
|
+
* · dsh, `src/render.ts:12-19` — «This complete workspace instruction baseline replaces all
|
|
319
|
+
* earlier workspace instruction baselines.»
|
|
320
|
+
*
|
|
321
|
+
* @param {object} input
|
|
322
|
+
* @param {Array<object>} input.storia — i messaggi che il modello ha gia' davanti (`messaggiIniziali`)
|
|
323
|
+
* @param {string} input.testo — il preambolo corrente
|
|
324
|
+
* @returns {string|null} il messaggio da appendere, oppure `null` se non e' cambiato NIENTE — e
|
|
325
|
+
* allora non si appende niente: zero token, come Hermes, che della sua sonda d'ambiente scrive
|
|
326
|
+
* «Emits a single line; emits NOTHING when the environment is clean (no token cost)».
|
|
327
|
+
*/
|
|
328
|
+
export function aggiornamentoInCoda({ storia, testo } = {}) {
|
|
329
|
+
if (typeof testo !== 'string' || testo === '') return null;
|
|
330
|
+
const visto = preamboloVistoDa(storia);
|
|
331
|
+
/* ⛔ Nessun preambolo nella storia: o e' una sessione fresca (e il preambolo sta gia' in testa,
|
|
332
|
+
ripeterlo in coda sarebbe pagarlo due volte) o e' una conversazione nata prima di questa cura.
|
|
333
|
+
In entrambi i casi non si appende: non c'e' niente da SOSTITUIRE. */
|
|
334
|
+
if (visto === null) return null;
|
|
335
|
+
if (visto === testo) return null;
|
|
336
|
+
return INIZIO_AGGIORNAMENTO + ' quanto segue SOSTITUISCE la scheda di lavoro, le istruzioni di '
|
|
337
|
+
+ 'progetto e la mappa delle cartelle che hai ricevuto prima in questa conversazione. Quelle '
|
|
338
|
+
+ 'non valgono piu\u0027.\n\n' + testo;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* L'ultimo preambolo che il modello ha davvero letto, ricavato dalla conversazione salvata.
|
|
343
|
+
* Si cammina dalla FINE: l'ultimo che parla e' quello che vale.
|
|
344
|
+
*/
|
|
345
|
+
export function preamboloVistoDa(storia) {
|
|
346
|
+
if (!Array.isArray(storia)) return null;
|
|
347
|
+
for (let i = storia.length - 1; i >= 0; i -= 1) {
|
|
348
|
+
const m = storia[i];
|
|
349
|
+
if (m?.role !== 'system' || typeof m.content !== 'string') continue;
|
|
350
|
+
if (m.content.startsWith(INIZIO_AGGIORNAMENTO)) {
|
|
351
|
+
const taglio = m.content.indexOf('\n\n');
|
|
352
|
+
return taglio >= 0 ? m.content.slice(taglio + 2) : null;
|
|
353
|
+
}
|
|
354
|
+
if (m.content.startsWith(INIZIO_SCHEDA)) return m.content;
|
|
355
|
+
// BC-48 C: i preamboli nuovi iniziano col blocco stabile; quelli salvati prima restano validi.
|
|
356
|
+
const inizioStabile = m.content.startsWith('Istruzioni di questo progetto — ')
|
|
357
|
+
|| m.content.startsWith('Struttura di «');
|
|
358
|
+
if (inizioStabile && m.content.includes(`\n\n${INIZIO_SCHEDA}`)) return m.content;
|
|
359
|
+
}
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Dice che i file di una cartella sono cambiati: il prossimo giro ricostruira' il preambolo.
|
|
365
|
+
* ⛔ Si chiama da `WorkspaceChanged`, cioe' quando il disco cambia DAVVERO. Chiamarla a ogni evento
|
|
366
|
+
* annullerebbe la cache e con essa tutto il vantaggio.
|
|
367
|
+
* ⛔ Cancella TUTTE le chiavi di quella cartella, qualunque permesso e qualunque modello: i file
|
|
368
|
+
* sono cambiati per tutte.
|
|
369
|
+
*/
|
|
370
|
+
export function segnalaFileCambiati(cartella) {
|
|
371
|
+
if (typeof cartella !== 'string') return false;
|
|
372
|
+
const prefisso = cartella + '|';
|
|
373
|
+
let tolte = 0;
|
|
374
|
+
for (const chiave of [...cache.keys()]) {
|
|
375
|
+
if (chiave.startsWith(prefisso)) { cache.delete(chiave); tolte += 1; }
|
|
376
|
+
}
|
|
377
|
+
return tolte > 0;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/** Svuota tutto. Serve alle prove, e a un riavvio pulito. */
|
|
381
|
+
export function dimenticaTuttiGliElenchi() {
|
|
382
|
+
const quanti = cache.size;
|
|
383
|
+
cache.clear();
|
|
384
|
+
return quanti;
|
|
385
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
const MAX_BYTES = 10 * 1024 * 1024;
|
|
4
|
+
const IMAGE_MAX_BYTES = 5 * 1024 * 1024;
|
|
5
|
+
const MIMES = new Set(['image/png', 'image/jpeg', 'image/webp', 'application/pdf', 'text/plain', 'text/markdown', 'text/csv', 'application/json', 'application/octet-stream']);
|
|
6
|
+
const fail = (message, code = 'CTX_ASSET_INVALID') => { throw Object.assign(new Error(message), { code }); };
|
|
7
|
+
|
|
8
|
+
function identifiers(sessionId, id) {
|
|
9
|
+
if (typeof sessionId !== 'string' || !sessionId.trim() || sessionId.length > 256
|
|
10
|
+
|| typeof id !== 'string' || !id.trim() || id.length > 256 || /[\u0000-\u001f]/u.test(sessionId)
|
|
11
|
+
|| /[\u0000-\u001f/\\:]/u.test(id) || id === '.' || id === '..') fail('Invalid session or asset identifier');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function validateBytes(bytes, mimeType, expectedHash) {
|
|
15
|
+
if (!(bytes instanceof Uint8Array) || bytes.length === 0 || bytes.length > MAX_BYTES) fail('Asset byte count is invalid', 'CTX_ASSET_LIMIT');
|
|
16
|
+
if (!MIMES.has(mimeType)) fail('Asset MIME is unsupported', 'CTX_ASSET_MIME');
|
|
17
|
+
if (mimeType.startsWith('image/') && bytes.length > IMAGE_MAX_BYTES) fail('Image exceeds the 5 MiB limit', 'CTX_ASSET_LIMIT');
|
|
18
|
+
const copy = Buffer.from(bytes);
|
|
19
|
+
const signature = mimeType === 'image/png' ? copy.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))
|
|
20
|
+
: mimeType === 'image/jpeg' ? copy[0] === 255 && copy[1] === 216 && copy[2] === 255
|
|
21
|
+
: mimeType === 'image/webp' ? copy.toString('ascii', 0, 4) === 'RIFF' && copy.toString('ascii', 8, 12) === 'WEBP'
|
|
22
|
+
: mimeType === 'application/pdf' ? copy.toString('ascii', 0, 5) === '%PDF-' : true;
|
|
23
|
+
if (!signature) fail('Asset bytes do not match declared MIME', 'CTX_ASSET_MIME');
|
|
24
|
+
if (mimeType.startsWith('text/') || mimeType === 'application/json') {
|
|
25
|
+
try { new TextDecoder('utf-8', { fatal: true }).decode(copy); } catch { fail('Text asset is not valid UTF-8', 'CTX_ASSET_MIME'); }
|
|
26
|
+
}
|
|
27
|
+
const sha256 = createHash('sha256').update(copy).digest('hex');
|
|
28
|
+
if (expectedHash !== undefined && (typeof expectedHash !== 'string' || !/^[a-f0-9]{64}$/iu.test(expectedHash) || sha256 !== expectedHash.toLowerCase())) fail('Asset hash does not match its original bytes', 'CTX_ASSET_HASH');
|
|
29
|
+
return { bytes: Uint8Array.from(copy), sha256, mimeType, byteLength: copy.length };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function createContextAssetAdapter({ store, readAsset } = {}) {
|
|
33
|
+
if (!store || typeof store.putBlob !== 'function' || typeof store.readBlob !== 'function' || (readAsset !== undefined && typeof readAsset !== 'function')) fail('Asset store dependencies are invalid');
|
|
34
|
+
|
|
35
|
+
async function archiveContextAsset({ sessionId, id, mimeType, bytes, sha256 } = {}) {
|
|
36
|
+
identifiers(sessionId, id);
|
|
37
|
+
if (sha256 !== undefined && (typeof sha256 !== 'string' || !/^[a-f0-9]{64}$/iu.test(sha256))) fail('Asset reference hash is invalid', 'CTX_ASSET_HASH');
|
|
38
|
+
if (bytes === undefined) {
|
|
39
|
+
if (!readAsset) fail('Original asset is unavailable', 'CTX_ASSET_MISSING');
|
|
40
|
+
const source = await readAsset({ sessionId, id });
|
|
41
|
+
if (!source) fail('Original asset is unavailable', 'CTX_ASSET_MISSING');
|
|
42
|
+
if (source.sessionId !== sessionId || source.id !== id) fail('Asset belongs to another session', 'CTX_ASSET_OWNERSHIP');
|
|
43
|
+
if (source.mimeType !== mimeType) fail('Original MIME does not match asset reference', 'CTX_ASSET_MIME');
|
|
44
|
+
bytes = source.bytes;
|
|
45
|
+
const verified = validateBytes(bytes, mimeType, source.sha256);
|
|
46
|
+
if (sha256 !== undefined && verified.sha256 !== sha256.toLowerCase()) fail('Reference hash does not match original asset', 'CTX_ASSET_HASH');
|
|
47
|
+
sha256 = verified.sha256;
|
|
48
|
+
}
|
|
49
|
+
const checked = validateBytes(bytes, mimeType, sha256);
|
|
50
|
+
const manifest = await store.putBlob({ sessionId, id, bytes: checked.bytes, mimeType, sha256: checked.sha256 });
|
|
51
|
+
if (!manifest || manifest.id !== id || manifest.sha256 !== checked.sha256 || manifest.mimeType !== mimeType || manifest.byteLength !== checked.byteLength) fail('Stored asset manifest differs from original', 'CTX_ASSET_HASH');
|
|
52
|
+
return structuredClone(manifest);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function resolveContextAsset({ sessionId, id, modelCapabilities } = {}) {
|
|
56
|
+
identifiers(sessionId, id);
|
|
57
|
+
const source = await store.readBlob({ sessionId, id });
|
|
58
|
+
if (!source) fail('Archived asset is unavailable', 'CTX_ASSET_MISSING');
|
|
59
|
+
if (source.id !== id || (source.sessionId !== undefined && source.sessionId !== sessionId)) fail('Asset belongs to another session', 'CTX_ASSET_OWNERSHIP');
|
|
60
|
+
if (typeof source.sha256 !== 'string') fail('Archived asset hash is missing', 'CTX_ASSET_HASH');
|
|
61
|
+
const checked = validateBytes(source.bytes, source.mimeType, source.sha256);
|
|
62
|
+
const capabilities = modelCapabilities ?? {};
|
|
63
|
+
const supported = capabilities.supportedMimeTypes;
|
|
64
|
+
if ((checked.mimeType.startsWith('image/') && capabilities.vision !== true)
|
|
65
|
+
|| (!checked.mimeType.startsWith('image/') && !Array.isArray(supported))
|
|
66
|
+
|| (supported !== undefined && (!Array.isArray(supported) || !supported.includes(checked.mimeType)))
|
|
67
|
+
|| (capabilities.maxAssetBytes !== undefined && (!Number.isSafeInteger(capabilities.maxAssetBytes) || capabilities.maxAssetBytes < checked.byteLength))) fail('Selected model cannot receive this asset type or size', 'CTX_ASSET_CAPABILITY');
|
|
68
|
+
return { id, ...checked };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return Object.freeze({ archiveContextAsset, resolveContextAsset });
|
|
72
|
+
}
|