talos-code 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +111 -3
- package/THIRD_PARTY_NOTICES.md +40 -0
- package/dist/archive/zip.js +73 -0
- package/dist/args.js +97 -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 +185 -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 +43 -0
- package/dist/i18n/en/common.js +9 -0
- package/dist/i18n/en/credentials.js +82 -0
- package/dist/i18n/en/errors.js +246 -0
- package/dist/i18n/en/firstrun.js +89 -0
- package/dist/i18n/en/providers.js +37 -0
- package/dist/i18n/en/screen.js +736 -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 +330 -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/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-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 +262 -0
- package/dist/runtime/talos-composition.js +1006 -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/app.js +3761 -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 +559 -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 +32 -0
- package/dist/tui/components/terminal-shell.js +205 -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/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 +139 -0
- package/dist/tui/line-diff.js +57 -0
- package/dist/tui/live-activity.js +45 -0
- package/dist/tui/metrics.js +123 -0
- package/dist/tui/onboarding.js +36 -0
- package/dist/tui/overlays/agent-tree.js +39 -0
- package/dist/tui/overlays/approval-dialog.js +640 -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 +72 -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 +145 -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 +287 -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 +778 -0
- package/dist/tui/session-export.js +54 -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 +80 -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 +25 -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 +63 -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,84 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
export const ATTACHMENT_MAX_COUNT = 10;
|
|
3
|
+
export const TEXT_ATTACHMENT_MAX_BYTES = 256 * 1024;
|
|
4
|
+
export const TEXT_ATTACHMENTS_MAX_BYTES = 1024 * 1024;
|
|
5
|
+
export const IMAGE_ATTACHMENT_MAX_BYTES = 5 * 1024 * 1024;
|
|
6
|
+
export const IMAGE_ATTACHMENTS_MAX_BYTES = 12 * 1024 * 1024;
|
|
7
|
+
export class CliAttachmentError extends Error {
|
|
8
|
+
code;
|
|
9
|
+
constructor(code, message = code) { super(message); this.name = 'CliAttachmentError'; this.code = code; }
|
|
10
|
+
}
|
|
11
|
+
function safePath(value) {
|
|
12
|
+
if (typeof value !== 'string' || value.length === 0 || value.length > 1024 || /[\0\r\n]/u.test(value) || value.includes('\\') || path.posix.isAbsolute(value) || path.win32.isAbsolute(value) || value.split('/').some(part => part === '..'))
|
|
13
|
+
throw new CliAttachmentError('ATTACHMENT_INVALID', 'Attachment path is invalid.');
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
function exactBase64(value) {
|
|
17
|
+
if (typeof value !== 'string' || value.length === 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u.test(value))
|
|
18
|
+
throw new CliAttachmentError('ATTACHMENT_INVALID', 'Attachment image data is invalid.');
|
|
19
|
+
const bytes = Buffer.from(value, 'base64');
|
|
20
|
+
if (bytes.toString('base64') !== value)
|
|
21
|
+
throw new CliAttachmentError('ATTACHMENT_INVALID', 'Attachment image data is not canonical base64.');
|
|
22
|
+
return bytes;
|
|
23
|
+
}
|
|
24
|
+
export function imageMimeFromBytes(value) {
|
|
25
|
+
const bytes = Buffer.from(value);
|
|
26
|
+
if (bytes.length >= 8 && bytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])))
|
|
27
|
+
return 'image/png';
|
|
28
|
+
if (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255)
|
|
29
|
+
return 'image/jpeg';
|
|
30
|
+
if (bytes.length >= 12 && bytes.toString('ascii', 0, 4) === 'RIFF' && bytes.toString('ascii', 8, 12) === 'WEBP')
|
|
31
|
+
return 'image/webp';
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
export function validateCliAttachments(input) {
|
|
35
|
+
if (input === undefined)
|
|
36
|
+
return [];
|
|
37
|
+
if (!Array.isArray(input))
|
|
38
|
+
throw new CliAttachmentError('ATTACHMENT_INVALID', 'Attachments must be an array.');
|
|
39
|
+
if (input.length > ATTACHMENT_MAX_COUNT)
|
|
40
|
+
throw new CliAttachmentError('ATTACHMENT_COUNT_LIMIT', `A message can attach at most ${ATTACHMENT_MAX_COUNT} files.`);
|
|
41
|
+
let textBytes = 0, imageBytes = 0;
|
|
42
|
+
const out = [];
|
|
43
|
+
for (const row of input) {
|
|
44
|
+
if (!row || typeof row !== 'object')
|
|
45
|
+
throw new CliAttachmentError('ATTACHMENT_INVALID');
|
|
46
|
+
const attachmentPath = safePath(row.path);
|
|
47
|
+
if (row.kind === 'text') {
|
|
48
|
+
if (row.mimeType !== 'text/plain' || typeof row.text !== 'string' || !Number.isSafeInteger(row.bytes) || row.bytes < 0 || Buffer.byteLength(row.text, 'utf8') !== row.bytes)
|
|
49
|
+
throw new CliAttachmentError('ATTACHMENT_INVALID', 'Text attachment metadata does not match its content.');
|
|
50
|
+
if (row.bytes > TEXT_ATTACHMENT_MAX_BYTES)
|
|
51
|
+
throw new CliAttachmentError('ATTACHMENT_TEXT_TOO_LARGE', `Text references are limited to ${TEXT_ATTACHMENT_MAX_BYTES} bytes each.`);
|
|
52
|
+
textBytes += row.bytes;
|
|
53
|
+
if (textBytes > TEXT_ATTACHMENTS_MAX_BYTES)
|
|
54
|
+
throw new CliAttachmentError('ATTACHMENT_TEXT_TOTAL_LIMIT', `Text references are limited to ${TEXT_ATTACHMENTS_MAX_BYTES} bytes per message.`);
|
|
55
|
+
out.push({ kind: 'text', path: attachmentPath, mimeType: 'text/plain', bytes: row.bytes, text: row.text });
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (row.kind === 'image') {
|
|
59
|
+
if (!['image/png', 'image/jpeg', 'image/webp'].includes(row.mimeType) || !Number.isSafeInteger(row.bytes) || row.bytes <= 0)
|
|
60
|
+
throw new CliAttachmentError('ATTACHMENT_INVALID', 'Image attachment metadata is invalid.');
|
|
61
|
+
const bytes = exactBase64(row.dataBase64);
|
|
62
|
+
if (bytes.length !== row.bytes)
|
|
63
|
+
throw new CliAttachmentError('ATTACHMENT_INVALID', 'Image attachment byte count does not match its content.');
|
|
64
|
+
if (row.bytes > IMAGE_ATTACHMENT_MAX_BYTES)
|
|
65
|
+
throw new CliAttachmentError('ATTACHMENT_IMAGE_TOO_LARGE', `Images are limited to ${IMAGE_ATTACHMENT_MAX_BYTES} bytes each.`);
|
|
66
|
+
if (imageMimeFromBytes(bytes) !== row.mimeType)
|
|
67
|
+
throw new CliAttachmentError('ATTACHMENT_IMAGE_SIGNATURE', 'The declared image type does not match its bytes.');
|
|
68
|
+
imageBytes += row.bytes;
|
|
69
|
+
if (imageBytes > IMAGE_ATTACHMENTS_MAX_BYTES)
|
|
70
|
+
throw new CliAttachmentError('ATTACHMENT_IMAGE_TOTAL_LIMIT', `Images are limited to ${IMAGE_ATTACHMENTS_MAX_BYTES} bytes per message.`);
|
|
71
|
+
out.push({ kind: 'image', path: attachmentPath, mimeType: row.mimeType, bytes: row.bytes, dataBase64: row.dataBase64 });
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
throw new CliAttachmentError('ATTACHMENT_INVALID', 'Attachment kind is unsupported.');
|
|
75
|
+
}
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
export function renderPromptWithAttachments(prompt, attachments) {
|
|
79
|
+
const textRows = attachments.filter((row) => row.kind === 'text');
|
|
80
|
+
if (textRows.length === 0)
|
|
81
|
+
return prompt;
|
|
82
|
+
const blocks = textRows.map(row => `[TALOS project reference: ${row.path} · ${row.bytes} bytes]\n${row.text}\n[End TALOS project reference]`);
|
|
83
|
+
return `${prompt}\n\n${blocks.join('\n\n')}`;
|
|
84
|
+
}
|
|
@@ -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,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
|
+
}
|