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,395 @@
|
|
|
1
|
+
import { t } from "../i18n/index.js";
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { TalosError } from "../errors.js";
|
|
5
|
+
import { TOOL_OUTPUT_LIMIT, cutToolOutput, hasKernelCutMarker, replaceKernelCutMarker } from "./output-store.js";
|
|
6
|
+
/*
|
|
7
|
+
* ⭐⭐⭐ B1 slice 8 — IL COMANDO SCRITTO DALLA PERSONA PASSA DAL BROKER, e lo DICE.
|
|
8
|
+
*
|
|
9
|
+
* Questa e' l'unica implementazione nuova della corsia: un adattatore che si infila nel seam che il
|
|
10
|
+
* kernel espone GIA' — `eseguiComandoDiretto({eseguiComandoSandboxatoFn})` in
|
|
11
|
+
* `harness-ui/src/agent-service.mjs` (L1975) — e che quindi eredita, senza riscriverli, il
|
|
12
|
+
* vocabolario di eventi, l'accorpamento dei pezzi e la cucitura nella cronologia. (Il tracciamento
|
|
13
|
+
* della cartella di lavoro NO: dal round 5 della fetta 12 il ramo brokerato non appende la coda della
|
|
14
|
+
* cartella — vedi sotto.)
|
|
15
|
+
*
|
|
16
|
+
* ⛔ La firma e' quella POSIZIONALE del kernel (`eseguiComandoSandboxato(comando, cartella, opzioni)`),
|
|
17
|
+
* non una nuova: il CLI si conforma al kernel, mai il contrario.
|
|
18
|
+
* ⛔ `harness-ui/` si LEGGE e non si scrive: la regola di troncamento (`uscitaUtile`) e l'esecutore di
|
|
19
|
+
* ripiego arrivano dal kernel per iniezione. `staccaCartellaFinale` e `codaCheStampaLaCartella`
|
|
20
|
+
* restano nel contratto degli aiutanti perche' il kernel li espone, ma il ramo brokerato non li usa.
|
|
21
|
+
*/
|
|
22
|
+
/** ⛔ I due codici di uscita documentati dal kernel: 124 = tempo scaduto, 130 = 128 + SIGINT. */
|
|
23
|
+
export const KERNEL_EXIT = { timeout: 124, stoppedOnRequest: 130 };
|
|
24
|
+
/*
|
|
25
|
+
* ⭐⭐⭐ B1 slice 12, round 5 — SUL RAMO BROKERATO NON SI APPENDE NIENTE AL COMANDO.
|
|
26
|
+
*
|
|
27
|
+
* Tre round di fila hanno ricostruito il codice d'uscita dopo la coda della cartella, e ognuno ha
|
|
28
|
+
* aperto un buco nel codice d'uscita:
|
|
29
|
+
* · round 2, marcatore stampato: un'ultima riga senza a-capo lo incollava e la persona leggeva
|
|
30
|
+
* «exit 0» col token; un comando poteva stamparne uno e falsificare il codice nei due versi;
|
|
31
|
+
* · round 4, stato del processo via `call set` / `call exit`: DENTRO la sandbox MXC quei due nomi si
|
|
32
|
+
* risolvono in un `set.bat`/`set.cmd`/`exit.bat`/`exit.cmd` della cartella di lavoro. Misurato
|
|
33
|
+
* il 17/09/2026 con `findstr /c:zzz talos_absent.txt` (vero: 1): cmd dell'host 1, sandbox semplice
|
|
34
|
+
* 1, ramo brokerato **0** con quei file presenti. E per `type mancante & echo ok` il ramo brokerato
|
|
35
|
+
* dava 1 mentre `cmd /c` semplice e il ripiego del kernel davano 0.
|
|
36
|
+
* La coda esisteva solo perche' quella della cartella sovrascrive il codice d'uscita, e la coda della
|
|
37
|
+
* cartella sul ramo cmd NON FUNZIONA comunque (`cartella: null` su cmd, misurato al round 2, sia qui
|
|
38
|
+
* sia nel kernel). Costava onesta' e non comprava niente che funzioni oggi.
|
|
39
|
+
*
|
|
40
|
+
* ⇒ Si esegue `%ComSpec% /d /s /c <comando>` e basta. Il codice che la persona vede e' lo stato
|
|
41
|
+
* d'uscita del processo nella sandbox, riportato da `mxcSandboxedSpawn`; niente viene stampato,
|
|
42
|
+
* letto o tolto che il comando non abbia prodotto da se'.
|
|
43
|
+
* ⛔ COSTO DICHIARATO, NON UNA REGRESSIONE: sul ramo brokerato un `cd` non persiste fra un comando e
|
|
44
|
+
* l'altro (`cartellaFinale` e' sempre null, e il registro tiene la cartella di prima). E' identico a
|
|
45
|
+
* oggi sul ramo cmd, dove la persistenza e' gia' rotta dal parser della cartella del kernel.
|
|
46
|
+
*/
|
|
47
|
+
/*
|
|
48
|
+
* ⭐ B1 slice 12, round 2 — UN BROKER CHE NON SI E' POTUTO COSTRUIRE NON E' «NON CONFIGURATO».
|
|
49
|
+
* Chi compone ripiega sull'esecuzione (fail-open) ma deve poterlo DIRE: questo sostituto rifiuta
|
|
50
|
+
* ogni esecuzione con un codice che il ramo di ripiego riconosce, e porta il codice dell'errore
|
|
51
|
+
* vero. Un difetto di contratto (un TypeError) arriva a schermo con il suo nome invece di sparire.
|
|
52
|
+
*/
|
|
53
|
+
export const BROKER_CONSTRUCTION_FAILED = 'EXECUTION_BROKER_CONSTRUCTION_FAILED';
|
|
54
|
+
export function createUnbuildableExecutionBroker(cause) {
|
|
55
|
+
const code = typeof cause?.code === 'string' ? String(cause.code) : cause instanceof Error ? cause.name : 'UNKNOWN_ERROR';
|
|
56
|
+
const message = (cause instanceof Error ? cause.message : String(cause)).split(/\r?\n/u)[0].slice(0, 300);
|
|
57
|
+
const detail = `${code}: ${message}`;
|
|
58
|
+
return { async execute(request) { throw new TalosError({ code: BROKER_CONSTRUCTION_FAILED, component: 'execution-broker', retryable: false, hint: detail, traceId: request.id }, cause); } };
|
|
59
|
+
}
|
|
60
|
+
/*
|
|
61
|
+
* The words of the execution row. R2 (gate E1, Q-R2-1): they live in the one dictionary, `src/i18n/en/screen.ts`
|
|
62
|
+
* (`screen.exec.*`); this object keeps the shape its callers use. The `marker` block is NOT screen text: it is a
|
|
63
|
+
* byte-identical copy of kernel constants (gate E2) and never enters the dictionary.
|
|
64
|
+
*
|
|
65
|
+
* ⛔⛔⛔ E la riga `enforcement` NON si accorcia. Misurato il 16/09/2026: una ricerca nel binario di
|
|
66
|
+
* Claude Code per una resa a schermo del suo flag «senza sandbox» torna ZERO, e il suo comando
|
|
67
|
+
* digitato dall'utente gira sempre fuori dall'isolamento senza dirlo; la barra di stato di Hermes,
|
|
68
|
+
* documentata campo per campo, non ha un campo isolamento. Entrambi approvano i comandi in
|
|
69
|
+
* allowlist in silenzio. Questa stringa e' l'unico posto in cui una persona scopre che il suo
|
|
70
|
+
* comando NON era isolato e PERCHE': toglierle la ragione la rende inutile.
|
|
71
|
+
*/
|
|
72
|
+
export const EXECUTION_TEXT = {
|
|
73
|
+
isolation: {
|
|
74
|
+
/** Un backend ha eseguito e ha portato le prove: si nomina il backend. */
|
|
75
|
+
sandbox: (backend) => t('screen.exec.isolation.sandbox', { backend }),
|
|
76
|
+
/** Il giro isolato e' finito prima di dire come: non si promette un isolamento che non e' provato. */
|
|
77
|
+
sandboxWithoutEvidence: t('screen.exec.isolation.sandboxWithoutEvidence'),
|
|
78
|
+
host: t('screen.exec.isolation.host'),
|
|
79
|
+
/**
|
|
80
|
+
* R0 lane S, owner decision 1 (review §J.1): the row of a command the PRODUCT wanted in the sandbox and ran on the
|
|
81
|
+
* host. ⛔ Never "secure" or "safe" anywhere on this path (gate E6): MXC itself is "contained", not a boundary.
|
|
82
|
+
*/
|
|
83
|
+
hostNotIsolated: t('screen.exec.isolation.hostNotIsolated'),
|
|
84
|
+
wsl2: t('screen.exec.isolation.wsl2'),
|
|
85
|
+
device: t('screen.exec.isolation.device'),
|
|
86
|
+
other: (name) => t('screen.exec.isolation.named', { name }),
|
|
87
|
+
},
|
|
88
|
+
reason: {
|
|
89
|
+
verified: (evidence) => t('screen.exec.reason.verified', { appContainer: t(evidence.appContainer ? 'screen.exec.on' : 'screen.exec.off'), filesystem: evidence.filesystem, network: evidence.network, processTree: evidence.processTree }),
|
|
90
|
+
backendUnavailable: (why) => t('screen.exec.reason.backendUnavailable', { why }),
|
|
91
|
+
brokerNotConfigured: t('screen.exec.reason.brokerNotConfigured'),
|
|
92
|
+
/** The broker exists in this build but could not be BUILT: never the same sentence as «not configured». */
|
|
93
|
+
brokerConstructionFailed: (detail) => t('screen.exec.reason.brokerConstructionFailed', { detail }),
|
|
94
|
+
destinationMobile: t('screen.exec.reason.destinationMobile'),
|
|
95
|
+
destinationWsl2: t('screen.exec.reason.destinationWsl2'),
|
|
96
|
+
platformNotWindows: (platform) => t('screen.exec.reason.platformNotWindows', { platform }),
|
|
97
|
+
timedOut: (ms) => t('screen.exec.reason.timedOut', { seconds: Math.round(ms / 1_000) }),
|
|
98
|
+
stoppedOnRequest: t('screen.exec.reason.stoppedOnRequest'),
|
|
99
|
+
/*
|
|
100
|
+
* ⛔ R0 lane S — the declared host fallback. These rows are shared by the person's `!` commands AND the model's
|
|
101
|
+
* shell tool (M1-E: one executor), so they do not say who typed the command; the approval that precedes the
|
|
102
|
+
* run is the permission engine's, not this executor's.
|
|
103
|
+
*/
|
|
104
|
+
sandboxUnverified: (why) => t('screen.exec.reason.sandboxUnverified', { why }),
|
|
105
|
+
brokerUnbuildable: (detail) => t('screen.exec.reason.brokerUnbuildable', { detail }),
|
|
106
|
+
hostPlatform: (platform) => t('screen.exec.reason.hostPlatform', { platform }),
|
|
107
|
+
hostNoBroker: t('screen.exec.reason.hostNoBroker'),
|
|
108
|
+
},
|
|
109
|
+
/*
|
|
110
|
+
* ⛔ Le tre marche del kernel, riprodotte LETTERA PER LETTERA perche' il kernel non le esporta
|
|
111
|
+
* (`MARCA_FERMATO_MENTRE_GIRAVA` e `USCITA_FERMATO_SU_RICHIESTA` sono `const` di modulo, non
|
|
112
|
+
* `export`). Una prova legge il sorgente del kernel e verifica che siano ancora identiche: e'
|
|
113
|
+
* l'unico modo per accorgersi di una deriva, visto che la copia e' inevitabile.
|
|
114
|
+
*/
|
|
115
|
+
marker: {
|
|
116
|
+
stoppedOnRequest: '⛔ Fermato su richiesta:',
|
|
117
|
+
stoppedOnRequestSentence: 'il comando e stato interrotto mentre girava.',
|
|
118
|
+
timedOut: (ms) => `⛔ Fermato allo scadere dei ${Math.round(ms / 1_000)} secondi: non ha finito da solo.`,
|
|
119
|
+
},
|
|
120
|
+
/** ⛔ Un comando senza sessione si RIFIUTA a voce alta: farlo sparire e' peggio che negarlo. */
|
|
121
|
+
shellSessionRequired: t('screen.exec.shellSessionRequired'),
|
|
122
|
+
};
|
|
123
|
+
/** The most of a fallback command's streamed output kept for its file (the kernel itself holds 160,000 characters). */
|
|
124
|
+
const CAPTURE_MAX = 8_000_000;
|
|
125
|
+
function isolationForKernelEnforcement(value) {
|
|
126
|
+
if (value === 'wsl2')
|
|
127
|
+
return EXECUTION_TEXT.isolation.wsl2;
|
|
128
|
+
if (value === 'adb-shell-on-device')
|
|
129
|
+
return EXECUTION_TEXT.isolation.device;
|
|
130
|
+
if (value === 'none' || !value)
|
|
131
|
+
return EXECUTION_TEXT.isolation.host;
|
|
132
|
+
return EXECUTION_TEXT.isolation.other(value);
|
|
133
|
+
}
|
|
134
|
+
function annotate(isolation, reason) { return `${isolation} — ${reason}`; }
|
|
135
|
+
export function createBrokeredKernelExecutor(options) {
|
|
136
|
+
const platform = options.platform ?? process.platform;
|
|
137
|
+
/*
|
|
138
|
+
* ⛔ LA RETE SEGUE IL MOTORE DEI PERMESSI, non una costante inventata qui. Il motore di oggi
|
|
139
|
+
* (`cli/src/security/permission-engine.ts`) non ha ancora una regola che parli della rete di un
|
|
140
|
+
* sottoprocesso: `WebFetch` riguarda le richieste del MODELLO, non quelle che un comando apre
|
|
141
|
+
* per conto suo. ⇒ Il default e' il valore che CONSERVA il comportamento di oggi (il kernel
|
|
142
|
+
* esegue senza alcun confine di rete), e il buco e' dichiarato nel rapporto invece di essere
|
|
143
|
+
* colmato inventando un motore nuovo. Chi compone puo' gia' passare `network` quando il motore
|
|
144
|
+
* imparera' a decidere deny/ask/allow.
|
|
145
|
+
*/
|
|
146
|
+
const network = options.network ?? 'internet-client';
|
|
147
|
+
/*
|
|
148
|
+
* ⛔ `restricted-process` e non `windows-sandbox`: con `windows-sandbox` il broker LANCIA
|
|
149
|
+
* `SANDBOX_REQUIRED_UNAVAILABLE` (execution-broker.ts L85) invece di declinare, e un backend
|
|
150
|
+
* assente diventerebbe un errore duro invece del ripiego che lo scenario 2 pretende. Con
|
|
151
|
+
* `restricted-process` il broker prende comunque `windows-sandbox` se ce l'ha (L82-84) e
|
|
152
|
+
* declina con `EXECUTION_BACKEND_UNAVAILABLE` quando non ha niente (L87).
|
|
153
|
+
*/
|
|
154
|
+
const requiredEnforcement = options.requiredEnforcement ?? 'restricted-process';
|
|
155
|
+
const requireVerifiedIsolation = options.requireVerifiedIsolation ?? false;
|
|
156
|
+
/*
|
|
157
|
+
* ⭐⭐⭐ R0 lane S — THE DECLARED HOST FALLBACK (owner decision 1, 2026-09-23; review D-01/E-01).
|
|
158
|
+
* F16 (`dd9620d9b`) made the product refuse every command whose isolation could not be proven, and on a host where
|
|
159
|
+
* the probe itself was broken that meant NO command ran at all. The product still ASKS for the Windows sandbox
|
|
160
|
+
* (`requiredEnforcement:'windows-sandbox'`, network denied), still never accepts a weaker sandbox in its place, and
|
|
161
|
+
* still lets a sandbox that exists and fails propagate (below). What changes: when no verified sandbox exists, the
|
|
162
|
+
* command runs through the kernel's own executor on the host, and the row says so — `⛶ host · not isolated` and
|
|
163
|
+
* the backend's own reason. Claude Code does the same by default ("shows a warning and runs commands without
|
|
164
|
+
* sandboxing", code.claude.com/docs/en/sandboxing, v2.1.271, 2026-09-14); the approval before it is the permission
|
|
165
|
+
* engine's (gate §0.2 rule 2).
|
|
166
|
+
*/
|
|
167
|
+
const declaredHost = !requireVerifiedIsolation && requiredEnforcement === 'windows-sandbox';
|
|
168
|
+
const timeoutMs = options.timeoutMs ?? 120_000;
|
|
169
|
+
const newId = options.newId ?? (() => randomUUID());
|
|
170
|
+
let loading = null;
|
|
171
|
+
const loadKernel = () => (loading ??= options.kernel());
|
|
172
|
+
/*
|
|
173
|
+
* ⛔ CHI NON PUO' ANDARE NEL BROKER, E PERCHE'. Un AppContainer non puo' ospitare una `adb shell`
|
|
174
|
+
* ne' una distribuzione WSL2: mandarceli sarebbe la cura di una malattia che non esiste, e
|
|
175
|
+
* cambierebbe in silenzio DOVE gira il comando — esattamente il difetto che D-10F ha chiuso.
|
|
176
|
+
*/
|
|
177
|
+
function declineReason(opts) {
|
|
178
|
+
if (opts.mobile === true)
|
|
179
|
+
return EXECUTION_TEXT.reason.destinationMobile;
|
|
180
|
+
if (opts.dove === 'wsl2')
|
|
181
|
+
return EXECUTION_TEXT.reason.destinationWsl2;
|
|
182
|
+
if (platform !== 'win32')
|
|
183
|
+
return declaredHost ? EXECUTION_TEXT.reason.hostPlatform(String(platform)) : EXECUTION_TEXT.reason.platformNotWindows(String(platform));
|
|
184
|
+
if (!options.broker)
|
|
185
|
+
return declaredHost ? EXECUTION_TEXT.reason.hostNoBroker : EXECUTION_TEXT.reason.brokerNotConfigured;
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
async function fallback(helpers, comando, cartella, opts, reason) {
|
|
189
|
+
/*
|
|
190
|
+
* R5a lane R, S6: the kernel's executor cuts its output itself (`uscitaUtile`) and returns only the cut; every piece it
|
|
191
|
+
* reads is also handed to `onPezzo` as it arrives (talosHarness.mjs `eseguiComandoSandboxato`, D-10B). The pieces are
|
|
192
|
+
* kept here, in arrival order, so a cut output can still be saved whole; the caller's listener still gets every piece.
|
|
193
|
+
*/
|
|
194
|
+
const keep = options.keepFullOutput;
|
|
195
|
+
let captured = '';
|
|
196
|
+
let capturedAll = true;
|
|
197
|
+
const listener = opts.onPezzo;
|
|
198
|
+
const withCapture = keep ? { ...opts, onPezzo: (piece) => {
|
|
199
|
+
if (captured.length < CAPTURE_MAX)
|
|
200
|
+
captured += piece.testo;
|
|
201
|
+
else
|
|
202
|
+
capturedAll = false;
|
|
203
|
+
listener?.(piece);
|
|
204
|
+
} } : opts;
|
|
205
|
+
const kernelResult = await helpers.eseguiComandoSandboxato(comando, cartella, withCapture);
|
|
206
|
+
let result = kernelResult;
|
|
207
|
+
if (keep && hasKernelCutMarker(String(kernelResult.testo ?? ''))) {
|
|
208
|
+
const full = capturedAll ? captured : captured.slice(0, CAPTURE_MAX);
|
|
209
|
+
let saved = null;
|
|
210
|
+
try {
|
|
211
|
+
saved = full ? await keep(full) : null;
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
saved = null;
|
|
215
|
+
}
|
|
216
|
+
result = { ...kernelResult, testo: replaceKernelCutMarker(String(kernelResult.testo), saved) };
|
|
217
|
+
}
|
|
218
|
+
const kernelEnforcement = String(result.enforcement ?? '');
|
|
219
|
+
/* ⛔ Only a plain host run takes the declared label: WSL2 and the device keep naming where they ran. */
|
|
220
|
+
const isolation = declaredHost && (kernelEnforcement === 'none' || !kernelEnforcement) ? EXECUTION_TEXT.isolation.hostNotIsolated : isolationForKernelEnforcement(kernelEnforcement);
|
|
221
|
+
return { ...result, enforcement: annotate(isolation, reason) };
|
|
222
|
+
}
|
|
223
|
+
/* R5a lane R, S6: the same head and tail as the kernel's cut, and with `keepFullOutput` the English marker naming the file. */
|
|
224
|
+
async function cutOutput(helpers, full) {
|
|
225
|
+
const keep = options.keepFullOutput;
|
|
226
|
+
if (!keep)
|
|
227
|
+
return helpers.uscitaUtile(full, 4_000, 0.25);
|
|
228
|
+
if (full.length <= TOOL_OUTPUT_LIMIT)
|
|
229
|
+
return full;
|
|
230
|
+
let saved = null;
|
|
231
|
+
try {
|
|
232
|
+
saved = await keep(full);
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
saved = null;
|
|
236
|
+
}
|
|
237
|
+
return cutToolOutput(full, saved);
|
|
238
|
+
}
|
|
239
|
+
return async function brokeredKernelExecutor(comando, cartella, opts = {}) {
|
|
240
|
+
const helpers = await loadKernel();
|
|
241
|
+
const declined = declineReason(opts);
|
|
242
|
+
if (declined !== null) {
|
|
243
|
+
if (requireVerifiedIsolation) {
|
|
244
|
+
let why = t('screen.exec.why.unverified');
|
|
245
|
+
if (opts.mobile === true)
|
|
246
|
+
why = t('screen.exec.why.mobile');
|
|
247
|
+
else if (opts.dove === 'wsl2')
|
|
248
|
+
why = t('screen.exec.why.wsl2');
|
|
249
|
+
else if (platform !== 'win32')
|
|
250
|
+
why = t('screen.exec.why.platform', { platform: String(platform) });
|
|
251
|
+
else if (!options.broker)
|
|
252
|
+
why = t('screen.exec.why.noBroker');
|
|
253
|
+
throw new TalosError({
|
|
254
|
+
code: 'SANDBOX_REQUIRED_UNAVAILABLE',
|
|
255
|
+
component: 'execution-broker',
|
|
256
|
+
retryable: false,
|
|
257
|
+
hint: t('screen.exec.why.notRun', { why }),
|
|
258
|
+
traceId: newId(),
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
return fallback(helpers, comando, cartella, opts, declined);
|
|
262
|
+
}
|
|
263
|
+
const broker = options.broker;
|
|
264
|
+
/*
|
|
265
|
+
* ⛔ Round 5: nessuna coda, nemmeno con `tracciaCartella`. Vedi il blocco in testa al file.
|
|
266
|
+
*
|
|
267
|
+
* ⛔ Invocazione NON INTERATTIVA, identica a quella che Node stesso costruisce per
|
|
268
|
+
* `spawn(comando,{shell:true})` su Windows: `%ComSpec% /d /s /c <comando>`. `/d` spegne gli
|
|
269
|
+
* AutoRun del registro, che dentro un isolamento sarebbero un ingresso non dichiarato.
|
|
270
|
+
* ⛔ La RADICE DEL VOLUME in sola lettura e' OBBLIGATORIA, non una comodita': upstream
|
|
271
|
+
* microsoft/mxc#1109 (SDK 0.8.0) dimostra che una concessione in scrittura su una cartella di
|
|
272
|
+
* profilo utente e' inutilizzabile se la radice del volume non sta anche fra le sole letture.
|
|
273
|
+
*/
|
|
274
|
+
const request = {
|
|
275
|
+
id: newId(),
|
|
276
|
+
executable: options.shellExecutable ?? process.env['ComSpec'] ?? 'cmd.exe',
|
|
277
|
+
args: ['/d', '/s', '/c', comando],
|
|
278
|
+
cwd: cartella,
|
|
279
|
+
readWritePaths: [cartella],
|
|
280
|
+
readOnlyPaths: [path.parse(path.resolve(cartella)).root],
|
|
281
|
+
network,
|
|
282
|
+
requiredEnforcement,
|
|
283
|
+
timeoutMs,
|
|
284
|
+
...(opts.segnaleStop ? { signal: opts.segnaleStop } : {}),
|
|
285
|
+
};
|
|
286
|
+
/*
|
|
287
|
+
* ⛔⛔ I DUE FERMI DEL KERNEL NON SONO RIPRODUCIBILI ATTRAVERSO LA FORMA DEL BROKER: il contratto
|
|
288
|
+
* di risultato di un backend porta `exitCode/stdout/stderr/applied` e nient'altro, quindi
|
|
289
|
+
* «ucciso dal tempo» e «fermato da te» non tornano indietro. Si ricostruiscono QUI, con gli
|
|
290
|
+
* stessi codici (124 / 130) e le stesse marche del kernel. Dichiarato, non nascosto.
|
|
291
|
+
*/
|
|
292
|
+
const work = broker.execute(request).then((value) => ({ kind: 'ok', value }), (error) => ({ kind: 'error', error }));
|
|
293
|
+
let timer;
|
|
294
|
+
const expired = new Promise((resolve) => { timer = setTimeout(() => resolve({ kind: 'timeout' }), timeoutMs); });
|
|
295
|
+
const stopped = new Promise((resolve) => {
|
|
296
|
+
const signal = opts.segnaleStop;
|
|
297
|
+
if (!signal)
|
|
298
|
+
return;
|
|
299
|
+
if (signal.aborted) {
|
|
300
|
+
resolve({ kind: 'stopped' });
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
signal.addEventListener('abort', () => resolve({ kind: 'stopped' }), { once: true });
|
|
304
|
+
});
|
|
305
|
+
let outcome;
|
|
306
|
+
try {
|
|
307
|
+
outcome = await Promise.race([work, expired, stopped]);
|
|
308
|
+
}
|
|
309
|
+
finally {
|
|
310
|
+
if (timer)
|
|
311
|
+
clearTimeout(timer);
|
|
312
|
+
}
|
|
313
|
+
if (outcome.kind === 'timeout')
|
|
314
|
+
return {
|
|
315
|
+
codice: KERNEL_EXIT.timeout,
|
|
316
|
+
fermatoDalTempo: true,
|
|
317
|
+
testo: `\n\n${EXECUTION_TEXT.marker.timedOut(timeoutMs)}`.trim(),
|
|
318
|
+
enforcement: annotate(EXECUTION_TEXT.isolation.sandboxWithoutEvidence, EXECUTION_TEXT.reason.timedOut(timeoutMs)),
|
|
319
|
+
cartellaFinale: null,
|
|
320
|
+
};
|
|
321
|
+
if (outcome.kind === 'stopped')
|
|
322
|
+
return {
|
|
323
|
+
codice: KERNEL_EXIT.stoppedOnRequest,
|
|
324
|
+
fermatoSuRichiesta: true,
|
|
325
|
+
testo: `\n\n${EXECUTION_TEXT.marker.stoppedOnRequest} ${EXECUTION_TEXT.marker.stoppedOnRequestSentence}`.trim(),
|
|
326
|
+
enforcement: annotate(EXECUTION_TEXT.isolation.sandboxWithoutEvidence, EXECUTION_TEXT.reason.stoppedOnRequest),
|
|
327
|
+
cartellaFinale: null,
|
|
328
|
+
};
|
|
329
|
+
if (outcome.kind === 'error') {
|
|
330
|
+
const failure = outcome.error;
|
|
331
|
+
/*
|
|
332
|
+
* ⛔⛔⛔ UN SOLO ERRORE E' CONDIZIONE DI RIPIEGO: «non esiste nessun backend». Tutto il resto —
|
|
333
|
+
* e in particolare `SANDBOX_EVIDENCE_MISMATCH` — RISALE. Una sandbox che esiste e ha
|
|
334
|
+
* RIFIUTATO non si aggira in silenzio: sarebbe la peggiore delle bugie, perche' il comando
|
|
335
|
+
* girerebbe fuori dall'isolamento proprio nel caso in cui l'isolamento aveva qualcosa da dire.
|
|
336
|
+
*/
|
|
337
|
+
/* ⛔ Il broker non si e' potuto COSTRUIRE: nessun isolamento esiste, quindi si esegue fuori, e
|
|
338
|
+
la riga dice perche' con il codice dell'errore — mai «non configurato in questa build». */
|
|
339
|
+
if (failure?.code === BROKER_CONSTRUCTION_FAILED) {
|
|
340
|
+
if (requireVerifiedIsolation)
|
|
341
|
+
throw outcome.error;
|
|
342
|
+
const detail = failure.hint ?? t('screen.exec.why.noDetail');
|
|
343
|
+
return fallback(helpers, comando, cartella, opts, declaredHost ? EXECUTION_TEXT.reason.brokerUnbuildable(detail) : EXECUTION_TEXT.reason.brokerConstructionFailed(detail));
|
|
344
|
+
}
|
|
345
|
+
/*
|
|
346
|
+
* ⛔ R0 lane S: `SANDBOX_REQUIRED_UNAVAILABLE` from the BROKER is the same fact as EXECUTION_BACKEND_UNAVAILABLE —
|
|
347
|
+
* no verified backend exists — for a request that required the Windows sandbox (execution-broker.ts). Its
|
|
348
|
+
* cause carries the backend's own reason (for example the probe's). Everything else still propagates:
|
|
349
|
+
* EXECUTION_BACKEND_FAILED, SANDBOX_EVIDENCE_MISMATCH, SANDBOX_PATH_INVALID, SANDBOX_CWD_NOT_GRANTED.
|
|
350
|
+
*/
|
|
351
|
+
if (declaredHost && failure?.code === 'SANDBOX_REQUIRED_UNAVAILABLE') {
|
|
352
|
+
const cause = outcome.error?.cause;
|
|
353
|
+
const why = cause instanceof Error && cause.message ? cause.message : failure.hint ?? t('screen.exec.why.noBackend');
|
|
354
|
+
return fallback(helpers, comando, cartella, opts, EXECUTION_TEXT.reason.sandboxUnverified(why));
|
|
355
|
+
}
|
|
356
|
+
if (failure?.code !== 'EXECUTION_BACKEND_UNAVAILABLE')
|
|
357
|
+
throw outcome.error;
|
|
358
|
+
if (requireVerifiedIsolation)
|
|
359
|
+
throw outcome.error;
|
|
360
|
+
const why = failure.hint ?? failure.message ?? t('screen.exec.why.noEnforcement');
|
|
361
|
+
return fallback(helpers, comando, cartella, opts, declaredHost ? EXECUTION_TEXT.reason.sandboxUnverified(why) : EXECUTION_TEXT.reason.backendUnavailable(why));
|
|
362
|
+
}
|
|
363
|
+
const { exitCode, stdout, stderr, evidence } = outcome.value;
|
|
364
|
+
/*
|
|
365
|
+
* ⛔ Round 5: nessuna coda, quindi niente da staccare. Stdout e stderr arrivano come il comando li ha
|
|
366
|
+
* scritti — anche se contengono qualcosa che somiglia a un marcatore: e' uscita del comando.
|
|
367
|
+
* ⛔ Round 2, ancora vero: stderr non si perde mai, e non si unisce a stdout prima di un taglio.
|
|
368
|
+
*/
|
|
369
|
+
const out = String(stdout ?? '').replace(/[\r\n]+$/u, '');
|
|
370
|
+
const err = String(stderr ?? '').replace(/[\r\n]+$/u, '');
|
|
371
|
+
/*
|
|
372
|
+
* ⛔ DEBITO B1.10, DICHIARATO: sul ramo brokerato l'uscita dal vivo NON esiste — il contratto di
|
|
373
|
+
* risultato del backend non ha un canale di streaming. Si emette il testo intero UNA volta
|
|
374
|
+
* prima di tornare, cosi' chi ascolta vede qualcosa; il ramo di ripiego continua a trasmettere
|
|
375
|
+
* a pezzi come sempre.
|
|
376
|
+
* ⛔ E per la stessa ragione l'ORDINE fra i due flussi non esiste qui: prima stdout, poi stderr.
|
|
377
|
+
* Il ripiego del kernel li intreccia nell'ordine d'arrivo; questo contratto non lo permette.
|
|
378
|
+
*/
|
|
379
|
+
if (out)
|
|
380
|
+
opts.onPezzo?.({ flusso: 'fuori', testo: out });
|
|
381
|
+
if (err)
|
|
382
|
+
opts.onPezzo?.({ flusso: 'errori', testo: out ? `\n${err}` : err });
|
|
383
|
+
return {
|
|
384
|
+
/* ⛔ Lo stato d'uscita del PROCESSO `cmd /d /s /c <comando>`, lo stesso di `cmd /c` semplice. Mai un
|
|
385
|
+
numero letto dal testo. */
|
|
386
|
+
codice: exitCode,
|
|
387
|
+
/* ⛔ Il taglio e' quello del KERNEL, non una seconda regola: persona e modello devono leggere
|
|
388
|
+
lo stesso testo sotto lo stesso nome. */
|
|
389
|
+
testo: await cutOutput(helpers, `${out}\n${err}`.trim()),
|
|
390
|
+
enforcement: annotate(EXECUTION_TEXT.isolation.sandbox(evidence.backend), EXECUTION_TEXT.reason.verified(evidence)),
|
|
391
|
+
/* ⛔ Nessuna coda, nessuna cartella finale: il registro tiene quella di prima. */
|
|
392
|
+
cartellaFinale: null,
|
|
393
|
+
};
|
|
394
|
+
};
|
|
395
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* P12 (owner, 2026-09-25, "quando riprendo sessione mi dà CTX_HISTORY_DIVERGED"). Measured on a copy of the owner's
|
|
3
|
+
* session and Context Engine archive: the archive held 10 messages, the last an assistant message with a tool call and NO
|
|
4
|
+
* result (12:16:45, the turn interrupted there); the session's own history had dropped that unanswered call, as it must (a
|
|
5
|
+
* call without its result is not sent back to a model), and gone on with the next person's messages. From then on the
|
|
6
|
+
* archive was no longer a prefix of the history, `syncOriginals` (harness-ui/src/context-desktop-service.mjs:202) refused
|
|
7
|
+
* every turn, and the session could not be resumed.
|
|
8
|
+
* Where the unanswered call came from: the kernel archives the whole history at several points of a turn, among them
|
|
9
|
+
* right after the model's answer, BEFORE the tools run (talosHarness.mjs `capture` reason 'response'). The cure, on the
|
|
10
|
+
* CLI's side of the bridge (the kernel and the service are not edited): `capture` never archives an assistant message
|
|
11
|
+
* whose tool calls do not all have a result yet, nor the partial results after it. The next capture, once the results
|
|
12
|
+
* are in, archives the exchange whole; if the turn stops first, nothing unanswered was archived. The archive stays a
|
|
13
|
+
* prefix of the history in both cases.
|
|
14
|
+
*/
|
|
15
|
+
/** The longest prefix of `messages` that does not end inside an unanswered tool exchange. */
|
|
16
|
+
export function archivableHistory(messages) {
|
|
17
|
+
const rows = messages;
|
|
18
|
+
for (let index = rows.length - 1; index >= 0; index--) {
|
|
19
|
+
const message = rows[index];
|
|
20
|
+
if (message?.role !== 'assistant' || !Array.isArray(message.tool_calls) || message.tool_calls.length === 0)
|
|
21
|
+
continue;
|
|
22
|
+
const wanted = new Set(message.tool_calls.map((call) => call?.id).filter((id) => typeof id === 'string' && id));
|
|
23
|
+
for (let later = index + 1; later < rows.length && rows[later]?.role === 'tool'; later++)
|
|
24
|
+
wanted.delete(rows[later].tool_call_id);
|
|
25
|
+
/* The last tool exchange decides: complete, the whole history is archivable; unanswered, it and what follows wait. */
|
|
26
|
+
return wanted.size === 0 ? [...messages] : messages.slice(0, index);
|
|
27
|
+
}
|
|
28
|
+
return [...messages];
|
|
29
|
+
}
|
|
30
|
+
/*
|
|
31
|
+
* The same measurement found a race: `syncOriginals` reads the session revision, then appends with it
|
|
32
|
+
* (context-desktop-service.mjs:199-204), while a Context Engine compaction running in the background can commit a version
|
|
33
|
+
* in between (outside that session's queue). The append is then refused with CTX_STALE_REVISION and the TURN failed
|
|
34
|
+
* (r5a-coord-ce-compaction: 3 of 8 runs once capture waited for whole tool exchanges, 0 of 11 before; the race existed
|
|
35
|
+
* before too, only rarer). A retry is safe: `syncOriginals` rereads the revision and appends only what is missing, and
|
|
36
|
+
* `prepare` recomputes from the archive. So `capture` and `prepare` retry a stale revision, briefly.
|
|
37
|
+
* The shape follows Hermes' SQLite write retry (hermes_state.py:467-489, read 2026-09-26): patience is TIME-based, since
|
|
38
|
+
* "attempt-counted budgets destroyed turns on a healthy store", and each wait is RANDOM (20-150 ms), so two writers that
|
|
39
|
+
* lost the same race do not collide again in step (the "full jitter" of AWS's "Exponential Backoff and Jitter"). The
|
|
40
|
+
* budget is short, like Hermes' wait on a live compression lock: a compaction's commit is one write, and the revision reread
|
|
41
|
+
* after it succeeds; a revision that keeps moving for two seconds is a real conflict, and the error goes on.
|
|
42
|
+
*/
|
|
43
|
+
const STALE_PATIENCE_MS = 2_000, STALE_WAIT_MIN_MS = 20, STALE_WAIT_MAX_MS = 150;
|
|
44
|
+
async function retryStale(operation, patienceMs) {
|
|
45
|
+
const deadline = Date.now() + patienceMs;
|
|
46
|
+
for (;;) {
|
|
47
|
+
try {
|
|
48
|
+
return await operation();
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
const remaining = deadline - Date.now();
|
|
52
|
+
if (error?.code !== 'CTX_STALE_REVISION' || remaining <= 0)
|
|
53
|
+
throw error;
|
|
54
|
+
const wait = STALE_WAIT_MIN_MS + Math.random() * (STALE_WAIT_MAX_MS - STALE_WAIT_MIN_MS);
|
|
55
|
+
await new Promise(resolve => setTimeout(resolve, Math.min(wait, remaining)));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** The service's kernel hooks: `capture` archives only whole tool exchanges; `capture` and `prepare` retry a stale revision. */
|
|
60
|
+
export function withArchivableCapture(hooks, { stalePatienceMs = STALE_PATIENCE_MS } = {}) {
|
|
61
|
+
if (!hooks || typeof hooks.capture !== 'function')
|
|
62
|
+
return hooks;
|
|
63
|
+
const capture = hooks.capture, prepare = hooks.prepare;
|
|
64
|
+
return {
|
|
65
|
+
...hooks,
|
|
66
|
+
capture: (input) => retryStale(() => capture({ ...input, messages: Array.isArray(input?.messages) ? archivableHistory(input.messages) : input?.messages }), stalePatienceMs),
|
|
67
|
+
...(typeof prepare === 'function' ? { prepare: (input) => retryStale(() => prepare(input), stalePatienceMs) } : {}),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const DEFAULT_TRIGGER_RATIO = 0.5;
|
|
2
|
+
function finite(value) { return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : null; }
|
|
3
|
+
function positive(value) { const n = finite(value); return n !== null && n > 0 ? n : null; }
|
|
4
|
+
function ratio(value, fallback = null) { const n = finite(value); return n !== null && n > 0 && n < 1 ? n : fallback; }
|
|
5
|
+
function percent(numerator, denominator) { return Math.round((numerator / denominator) * 1000) / 10; }
|
|
6
|
+
function integer(value) { return Number.isSafeInteger(value) && Number(value) >= 0 ? Number(value) : null; }
|
|
7
|
+
function text(value) { return typeof value === 'string' && value.trim() ? value.trim() : null; }
|
|
8
|
+
export function unavailableContextStatus(sessionId, reason) {
|
|
9
|
+
return {
|
|
10
|
+
schema: 'talos.cli.context-status.v1', sessionId, available: false, reason,
|
|
11
|
+
measurement: null, budget: null,
|
|
12
|
+
autoCompaction: { enabled: true, triggerRatio: DEFAULT_TRIGGER_RATIO, triggerPercent: 50, targetRatio: null, provenance: 'CLI owner policy; active only when Context Engine measurement is available' },
|
|
13
|
+
cache: { promptTokens: null, cachedTokens: null, percent: null, provenance: 'not measured' },
|
|
14
|
+
cost: { usd: null, provenance: 'not reported by runtime' },
|
|
15
|
+
sources: { activeVersionId: null, activeSourceCount: null, summaryCitationCount: null, provenance: 'no measured Context Engine snapshot' },
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function buildContextStatus({ sessionId, snapshot, sessionUsage }) {
|
|
19
|
+
if (!snapshot || typeof snapshot !== 'object')
|
|
20
|
+
return unavailableContextStatus(sessionId, 'not-measured');
|
|
21
|
+
const revision = integer(snapshot.revision);
|
|
22
|
+
const measured = snapshot.measurement && typeof snapshot.measurement === 'object' ? snapshot.measurement : null;
|
|
23
|
+
const tokens = measured?.tokens && typeof measured.tokens === 'object' ? measured.tokens : null;
|
|
24
|
+
const inputTokens = integer(tokens?.inputTokens), windowTokens = positive(tokens?.windowTokens), responseReserve = integer(tokens?.responseReserve);
|
|
25
|
+
const method = ['runtime', 'provider', 'heuristic'].includes(tokens?.method) ? tokens.method : null;
|
|
26
|
+
const measurement = inputTokens !== null && windowTokens !== null && responseReserve !== null && method ? {
|
|
27
|
+
inputTokens, windowTokens, responseReserve,
|
|
28
|
+
percentOfWindow: percent(inputTokens, windowTokens),
|
|
29
|
+
method, exact: tokens?.exact === true,
|
|
30
|
+
measuredAt: text(measured?.measuredAt),
|
|
31
|
+
revision: integer(measured?.revision),
|
|
32
|
+
stale: revision !== null && integer(measured?.revision) !== revision,
|
|
33
|
+
estimatedMarginTokens: integer(tokens?.estimatedMarginTokens),
|
|
34
|
+
} : null;
|
|
35
|
+
const settings = snapshot.settings && typeof snapshot.settings === 'object' ? snapshot.settings : {};
|
|
36
|
+
const triggerRatio = ratio(settings.triggerRatio, DEFAULT_TRIGGER_RATIO) ?? DEFAULT_TRIGGER_RATIO;
|
|
37
|
+
const targetRatio = ratio(settings.targetRatio, null);
|
|
38
|
+
const promptTokens = integer(sessionUsage?.promptTokens);
|
|
39
|
+
const cachedTokens = integer(sessionUsage?.cachedTokens);
|
|
40
|
+
const cacheMeasured = promptTokens !== null && promptTokens > 0 && cachedTokens !== null && cachedTokens <= promptTokens;
|
|
41
|
+
const active = snapshot.activeVersion && typeof snapshot.activeVersion === 'object' ? snapshot.activeVersion : null;
|
|
42
|
+
const sourceIds = Array.isArray(active?.sourceIds) ? active.sourceIds : null;
|
|
43
|
+
const citations = Array.isArray(active?.summary?.sources) ? active.summary.sources : null;
|
|
44
|
+
const profile = snapshot.cliProfileEvidence && typeof snapshot.cliProfileEvidence === 'object' ? snapshot.cliProfileEvidence : null;
|
|
45
|
+
const profileSource = text(profile?.source);
|
|
46
|
+
const profileDate = text(profile?.date);
|
|
47
|
+
const safetyMarginTokens = measurement ? Math.max(measurement.method === 'heuristic' ? 1024 : 256, Math.ceil(measurement.windowTokens * (measurement.method === 'heuristic' ? 0.15 : 0.05))) : null;
|
|
48
|
+
const inputLimitTokens = measurement && safetyMarginTokens !== null ? Math.max(0, measurement.windowTokens - measurement.responseReserve - safetyMarginTokens) : null;
|
|
49
|
+
const budget = measurement && safetyMarginTokens !== null && inputLimitTokens !== null ? {
|
|
50
|
+
windowTokens: measurement.windowTokens, responseReserve: measurement.responseReserve,
|
|
51
|
+
safetyMarginTokens, inputLimitTokens, triggerTokens: Math.floor(inputLimitTokens * triggerRatio),
|
|
52
|
+
estimatedMarginTokens: measurement.estimatedMarginTokens,
|
|
53
|
+
provenance: (profileSource ? 'model profile: ' + profileSource + (profileDate ? ' (' + profileDate + ')' : '') : measurement.method + ' prepared-request measurement') + '; Context Engine effective-input safety budget',
|
|
54
|
+
} : null;
|
|
55
|
+
return {
|
|
56
|
+
schema: 'talos.cli.context-status.v1', sessionId, available: true, reason: measurement ? null : 'not-measured',
|
|
57
|
+
measurement, budget,
|
|
58
|
+
autoCompaction: {
|
|
59
|
+
enabled: settings.auto === true,
|
|
60
|
+
triggerRatio, triggerPercent: Math.round(triggerRatio * 1000) / 10, targetRatio,
|
|
61
|
+
provenance: 'Context Engine session settings; CLI owner trigger policy is 0.50',
|
|
62
|
+
},
|
|
63
|
+
cache: {
|
|
64
|
+
promptTokens, cachedTokens,
|
|
65
|
+
percent: cacheMeasured ? percent(cachedTokens, promptTokens) : null,
|
|
66
|
+
provenance: cacheMeasured ? 'whole-session measured usage' : 'not measured',
|
|
67
|
+
},
|
|
68
|
+
cost: { usd: null, provenance: 'not reported by runtime' },
|
|
69
|
+
sources: {
|
|
70
|
+
activeVersionId: text(active?.id),
|
|
71
|
+
activeSourceCount: sourceIds ? sourceIds.length : null,
|
|
72
|
+
summaryCitationCount: citations ? citations.length : null,
|
|
73
|
+
provenance: active ? 'Context Engine active version' : 'no active compacted version',
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|