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,210 @@
|
|
|
1
|
+
import { createEditorHistory, pushEditorHistory, redoEditorHistory, undoEditorHistory } from "./editor-history.js";
|
|
2
|
+
import { splitGraphemes } from "./text-width.js";
|
|
3
|
+
const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
|
|
4
|
+
const clonePastes = (pastes) => pastes.map(paste => ({ ...paste }));
|
|
5
|
+
function clearPreferred(state) { const { preferredColumn: _, ...rest } = state; return rest; }
|
|
6
|
+
function clearSelection(state) { const { selectionAnchor: _, ...rest } = state; return rest; }
|
|
7
|
+
function clearTransient(state) { return clearSelection(clearPreferred(state)); }
|
|
8
|
+
function snapshot(state) { return { text: state.text, cursor: clamp(state.cursor, 0, state.text.length), collapsedPastes: clonePastes(state.collapsedPastes) }; }
|
|
9
|
+
function withCursor(state, cursor, extendSelection = false) {
|
|
10
|
+
const nextCursor = clamp(cursor, 0, state.text.length);
|
|
11
|
+
const base = clearPreferred(state);
|
|
12
|
+
if (!extendSelection)
|
|
13
|
+
return { ...clearSelection(base), cursor: nextCursor };
|
|
14
|
+
const anchor = state.selectionAnchor ?? clamp(state.cursor, 0, state.text.length);
|
|
15
|
+
if (anchor === nextCursor)
|
|
16
|
+
return { ...clearSelection(base), cursor: nextCursor };
|
|
17
|
+
return { ...base, cursor: nextCursor, selectionAnchor: anchor };
|
|
18
|
+
}
|
|
19
|
+
function restoreSnapshot(state, value, editHistory) {
|
|
20
|
+
return { ...clearTransient(state), text: value.text, cursor: clamp(value.cursor, 0, value.text.length), collapsedPastes: clonePastes(value.collapsedPastes), editHistory };
|
|
21
|
+
}
|
|
22
|
+
export function previousGraphemeBoundary(text, cursor) { let offset = 0, previous = 0; for (const g of splitGraphemes(text)) {
|
|
23
|
+
const next = offset + g.length;
|
|
24
|
+
if (next >= cursor)
|
|
25
|
+
return previous;
|
|
26
|
+
previous = next;
|
|
27
|
+
offset = next;
|
|
28
|
+
} return previous; }
|
|
29
|
+
export function nextGraphemeBoundary(text, cursor) { let offset = 0; for (const g of splitGraphemes(text)) {
|
|
30
|
+
offset += g.length;
|
|
31
|
+
if (offset > cursor)
|
|
32
|
+
return offset;
|
|
33
|
+
} return text.length; }
|
|
34
|
+
function graphemeBoundaryAtOrBefore(text, cursor) { const target = clamp(cursor, 0, text.length); let offset = 0; for (const g of splitGraphemes(text)) {
|
|
35
|
+
const next = offset + g.length;
|
|
36
|
+
if (next > target)
|
|
37
|
+
return offset;
|
|
38
|
+
if (next === target)
|
|
39
|
+
return next;
|
|
40
|
+
offset = next;
|
|
41
|
+
} return text.length; }
|
|
42
|
+
export function createEditorState(text = '') { return { text, cursor: text.length, killBuffer: '', collapsedPastes: [], editHistory: createEditorHistory() }; }
|
|
43
|
+
export function replaceEditorText(_state, text) { return createEditorState(text); }
|
|
44
|
+
export function draftOf(state) { return { text: state.text, collapsedPastes: clonePastes(state.collapsedPastes) }; }
|
|
45
|
+
export function draftText(draft) { return typeof draft === 'string' ? draft : draft.text; }
|
|
46
|
+
export function editorFromDraft(draft) {
|
|
47
|
+
const text = draftText(draft), state = createEditorState(text);
|
|
48
|
+
if (typeof draft === 'string')
|
|
49
|
+
return state;
|
|
50
|
+
const valid = draft.collapsedPastes.filter(paste => Number.isSafeInteger(paste.start) && Number.isSafeInteger(paste.end) && paste.start >= 0 && paste.end > paste.start && paste.end <= text.length);
|
|
51
|
+
const pastes = [...valid].sort((a, b) => a.start - b.start).filter((paste, index, sorted) => index === 0 || paste.start >= sorted[index - 1].end);
|
|
52
|
+
return { ...state, collapsedPastes: clonePastes(pastes) };
|
|
53
|
+
}
|
|
54
|
+
export function selectionRange(state) {
|
|
55
|
+
if (state.selectionAnchor === undefined)
|
|
56
|
+
return null;
|
|
57
|
+
const anchor = clamp(state.selectionAnchor, 0, state.text.length), cursor = clamp(state.cursor, 0, state.text.length);
|
|
58
|
+
if (anchor === cursor)
|
|
59
|
+
return null;
|
|
60
|
+
return { start: Math.min(anchor, cursor), end: Math.max(anchor, cursor) };
|
|
61
|
+
}
|
|
62
|
+
export function remapCollapsedPastes(pastes, editStart, removed, inserted) {
|
|
63
|
+
const editEnd = editStart + removed, delta = inserted - removed;
|
|
64
|
+
const out = [];
|
|
65
|
+
for (const p of pastes) {
|
|
66
|
+
if (editEnd <= p.start) {
|
|
67
|
+
out.push({ ...p, start: p.start + delta, end: p.end + delta });
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (editStart >= p.end) {
|
|
71
|
+
out.push({ ...p });
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
export function replaceRange(state, start, end, value) {
|
|
78
|
+
const from = clamp(start, 0, state.text.length), to = Math.max(from, clamp(end, 0, state.text.length));
|
|
79
|
+
if (from === to && value.length === 0)
|
|
80
|
+
return clearTransient(state);
|
|
81
|
+
const editHistory = pushEditorHistory(state.editHistory, snapshot(state));
|
|
82
|
+
return { ...clearTransient(state), text: state.text.slice(0, from) + value + state.text.slice(to), cursor: from + value.length, collapsedPastes: remapCollapsedPastes(state.collapsedPastes, from, to - from, value.length), editHistory };
|
|
83
|
+
}
|
|
84
|
+
export function editInsert(state, value) {
|
|
85
|
+
if (!value)
|
|
86
|
+
return clearPreferred(state);
|
|
87
|
+
const selected = selectionRange(state);
|
|
88
|
+
return selected ? replaceRange(state, selected.start, selected.end, value) : replaceRange(state, state.cursor, state.cursor, value);
|
|
89
|
+
}
|
|
90
|
+
export function moveCursor(state, to, extendSelection = false) {
|
|
91
|
+
const selected = selectionRange(state);
|
|
92
|
+
if (selected && !extendSelection && (to === 'left' || to === 'right'))
|
|
93
|
+
return withCursor(state, to === 'left' ? selected.start : selected.end, false);
|
|
94
|
+
const bounds = lineBounds(state.text, state.cursor);
|
|
95
|
+
const cursor = to === 'left' ? previousGraphemeBoundary(state.text, state.cursor) : to === 'right' ? nextGraphemeBoundary(state.text, state.cursor) : to === 'home' ? bounds.start : bounds.end;
|
|
96
|
+
return withCursor(state, cursor, extendSelection);
|
|
97
|
+
}
|
|
98
|
+
function isWord(ch) { return !!ch && /[\p{L}\p{N}_]/u.test(ch); }
|
|
99
|
+
export function moveWord(state, direction, extendSelection = false) { let c = clamp(state.cursor, 0, state.text.length); if (direction < 0) {
|
|
100
|
+
while (c > 0 && !isWord(state.text[previousGraphemeBoundary(state.text, c)]))
|
|
101
|
+
c = previousGraphemeBoundary(state.text, c);
|
|
102
|
+
while (c > 0 && isWord(state.text[previousGraphemeBoundary(state.text, c)]))
|
|
103
|
+
c = previousGraphemeBoundary(state.text, c);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
while (c < state.text.length && !isWord(state.text[c]))
|
|
107
|
+
c = nextGraphemeBoundary(state.text, c);
|
|
108
|
+
while (c < state.text.length && isWord(state.text[c]))
|
|
109
|
+
c = nextGraphemeBoundary(state.text, c);
|
|
110
|
+
} return withCursor(state, c, extendSelection); }
|
|
111
|
+
function lineBounds(text, cursor) { const c = clamp(cursor, 0, text.length); const start = text.lastIndexOf('\n', Math.max(0, c - 1)) + 1; const next = text.indexOf('\n', c); const end = next < 0 ? text.length : next; return { start, end }; }
|
|
112
|
+
export function moveVertical(state, direction, extendSelection = false) {
|
|
113
|
+
const c = clamp(state.cursor, 0, state.text.length);
|
|
114
|
+
const current = lineBounds(state.text, c);
|
|
115
|
+
const preferred = state.preferredColumn ?? (c - current.start);
|
|
116
|
+
if (direction < 0) {
|
|
117
|
+
if (current.start === 0)
|
|
118
|
+
return extendSelection ? state : withCursor(state, c, false);
|
|
119
|
+
const previousEnd = current.start - 1;
|
|
120
|
+
const previous = lineBounds(state.text, previousEnd);
|
|
121
|
+
const target = graphemeBoundaryAtOrBefore(state.text, previous.start + Math.min(preferred, previous.end - previous.start));
|
|
122
|
+
const moved = withCursor(state, target, extendSelection);
|
|
123
|
+
return { ...moved, preferredColumn: preferred };
|
|
124
|
+
}
|
|
125
|
+
if (current.end === state.text.length)
|
|
126
|
+
return extendSelection ? state : withCursor(state, c, false);
|
|
127
|
+
const nextStart = current.end + 1;
|
|
128
|
+
const next = lineBounds(state.text, nextStart);
|
|
129
|
+
const target = graphemeBoundaryAtOrBefore(state.text, next.start + Math.min(preferred, next.end - next.start));
|
|
130
|
+
const moved = withCursor(state, target, extendSelection);
|
|
131
|
+
return { ...moved, preferredColumn: preferred };
|
|
132
|
+
}
|
|
133
|
+
export function deleteBackward(state) { const selected = selectionRange(state); if (selected)
|
|
134
|
+
return replaceRange(state, selected.start, selected.end, ''); const c = clamp(state.cursor, 0, state.text.length); if (c === 0)
|
|
135
|
+
return clearPreferred(state); return replaceRange(state, previousGraphemeBoundary(state.text, c), c, ''); }
|
|
136
|
+
export function deleteForward(state) { const selected = selectionRange(state); if (selected)
|
|
137
|
+
return replaceRange(state, selected.start, selected.end, ''); const c = clamp(state.cursor, 0, state.text.length); if (c >= state.text.length)
|
|
138
|
+
return clearPreferred(state); return replaceRange(state, c, nextGraphemeBoundary(state.text, c), ''); }
|
|
139
|
+
export function copySelection(state) { const selected = selectionRange(state); return selected ? { ...state, killBuffer: state.text.slice(selected.start, selected.end) } : state; }
|
|
140
|
+
export function cutSelection(state) { const selected = selectionRange(state); if (!selected)
|
|
141
|
+
return state; const killed = state.text.slice(selected.start, selected.end); return { ...replaceRange(state, selected.start, selected.end, ''), killBuffer: killed }; }
|
|
142
|
+
export function killToStart(state) { if (selectionRange(state))
|
|
143
|
+
return cutSelection(state); const c = clamp(state.cursor, 0, state.text.length); const { start } = lineBounds(state.text, c); if (c === start)
|
|
144
|
+
return clearPreferred(state); const killed = state.text.slice(start, c); return { ...replaceRange(state, start, c, ''), killBuffer: killed }; }
|
|
145
|
+
export function killToEnd(state) { if (selectionRange(state))
|
|
146
|
+
return cutSelection(state); const c = clamp(state.cursor, 0, state.text.length); const { end } = lineBounds(state.text, c); if (c >= end)
|
|
147
|
+
return clearPreferred(state); const killed = state.text.slice(c, end); return { ...replaceRange(state, c, end, ''), killBuffer: killed }; }
|
|
148
|
+
export function killWordBackward(state) { if (selectionRange(state))
|
|
149
|
+
return cutSelection(state); const end = clamp(state.cursor, 0, state.text.length); const moved = moveWord(state, -1); if (moved.cursor === end)
|
|
150
|
+
return clearPreferred(state); const killed = state.text.slice(moved.cursor, end); return { ...replaceRange(state, moved.cursor, end, ''), killBuffer: killed }; }
|
|
151
|
+
export function yank(state) { return state.killBuffer ? editInsert(state, state.killBuffer) : clearPreferred(state); }
|
|
152
|
+
export function undoEditor(state) { const step = undoEditorHistory(state.editHistory, snapshot(state)); return step ? restoreSnapshot(state, step.value, step.history) : clearTransient(state); }
|
|
153
|
+
export function redoEditor(state) { const step = redoEditorHistory(state.editHistory, snapshot(state)); return step ? restoreSnapshot(state, step.value, step.history) : clearTransient(state); }
|
|
154
|
+
export function visibleEditorText(state) { const c = clamp(state.cursor, 0, state.text.length); const next = nextGraphemeBoundary(state.text, c); return { before: state.text.slice(0, c), cursor: state.text.slice(c, next) || ' ', after: state.text.slice(next), atEnd: c === state.text.length }; }
|
|
155
|
+
export function insertPaste(state, text) {
|
|
156
|
+
const selected = selectionRange(state);
|
|
157
|
+
const start = selected?.start ?? state.cursor;
|
|
158
|
+
const end = selected?.end ?? state.cursor;
|
|
159
|
+
const next = replaceRange(state, start, end, text);
|
|
160
|
+
const lines = text.split(/\r?\n/u).length;
|
|
161
|
+
return text.length >= 4096 || lines >= 20 ? { ...next, collapsedPastes: [...next.collapsedPastes, { start, end: start + text.length, chars: text.length, lines }] } : next;
|
|
162
|
+
}
|
|
163
|
+
export function composerSegments(state) {
|
|
164
|
+
const out = [];
|
|
165
|
+
const ranges = [...state.collapsedPastes].sort((a, b) => a.start - b.start);
|
|
166
|
+
const selected = selectionRange(state);
|
|
167
|
+
const pushText = (start, end) => {
|
|
168
|
+
if (end < start)
|
|
169
|
+
return;
|
|
170
|
+
if (selected) {
|
|
171
|
+
const selectedStart = Math.max(start, selected.start), selectedEnd = Math.min(end, selected.end);
|
|
172
|
+
if (selectedEnd <= selectedStart) {
|
|
173
|
+
if (end > start)
|
|
174
|
+
out.push({ kind: 'text', text: state.text.slice(start, end) });
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (selectedStart > start)
|
|
178
|
+
out.push({ kind: 'text', text: state.text.slice(start, selectedStart) });
|
|
179
|
+
out.push({ kind: 'text', text: state.text.slice(selectedStart, selectedEnd), selected: true });
|
|
180
|
+
if (selectedEnd < end)
|
|
181
|
+
out.push({ kind: 'text', text: state.text.slice(selectedEnd, end) });
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (state.cursor < start || state.cursor > end) {
|
|
185
|
+
if (end > start)
|
|
186
|
+
out.push({ kind: 'text', text: state.text.slice(start, end) });
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (state.cursor > start)
|
|
190
|
+
out.push({ kind: 'text', text: state.text.slice(start, state.cursor) });
|
|
191
|
+
const next = Math.min(end, nextGraphemeBoundary(state.text, state.cursor));
|
|
192
|
+
out.push({ kind: 'cursor', text: state.text.slice(state.cursor, next) || ' ' });
|
|
193
|
+
if (next < end)
|
|
194
|
+
out.push({ kind: 'text', text: state.text.slice(next, end) });
|
|
195
|
+
};
|
|
196
|
+
let pos = 0;
|
|
197
|
+
for (const p of ranges) {
|
|
198
|
+
if (p.start < pos)
|
|
199
|
+
continue;
|
|
200
|
+
pushText(pos, p.start);
|
|
201
|
+
const pasteSelected = Boolean(selected && selected.end > p.start && selected.start < p.end);
|
|
202
|
+
if (!selected && state.cursor >= p.start && state.cursor < p.end)
|
|
203
|
+
pushText(p.start, p.end);
|
|
204
|
+
else
|
|
205
|
+
out.push({ kind: 'paste', text: '[paste: ' + p.lines + ' lines, ' + p.chars + ' chars]', ...(pasteSelected ? { selected: true } : {}) });
|
|
206
|
+
pos = p.end;
|
|
207
|
+
}
|
|
208
|
+
pushText(pos, state.text.length);
|
|
209
|
+
return out;
|
|
210
|
+
}
|
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
import { createRedactor } from "../diagnostics/redact.js";
|
|
2
|
+
import { createV2EventBridge } from "../protocol/v2/events.js";
|
|
3
|
+
import { describeError, describeKernelNotice, describeKernelRefusalReason, describeKernelToolText, errorViewLines } from "../i18n/error-view.js";
|
|
4
|
+
import { t } from "../i18n/index.js";
|
|
5
|
+
import { REFUSAL_VIA, looksItalian } from "../i18n/kernel-map.js";
|
|
6
|
+
import { toolDisplay } from "./tool-display.js";
|
|
7
|
+
function objectValue(value) {
|
|
8
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : null;
|
|
9
|
+
}
|
|
10
|
+
function stringValue(value) {
|
|
11
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
12
|
+
}
|
|
13
|
+
function booleanValue(value) {
|
|
14
|
+
return typeof value === 'boolean' ? value : undefined;
|
|
15
|
+
}
|
|
16
|
+
function isCanonicalEvent(value) {
|
|
17
|
+
if (!value || typeof value !== 'object')
|
|
18
|
+
return false;
|
|
19
|
+
const row = value;
|
|
20
|
+
return row.schema === 'talos.cli.event.v2' && row.version === 2 && typeof row.sessionId === 'string'
|
|
21
|
+
&& typeof row.eventId === 'string' && typeof row.type === 'string' && Boolean(row.data && typeof row.data === 'object');
|
|
22
|
+
}
|
|
23
|
+
function asToolResult(data) {
|
|
24
|
+
const receipt = objectValue(data.receipt);
|
|
25
|
+
const status = data.status;
|
|
26
|
+
if (typeof data.toolCallId !== 'string' || typeof data.content !== 'string' || typeof status !== 'string' || !receipt)
|
|
27
|
+
return null;
|
|
28
|
+
return data;
|
|
29
|
+
}
|
|
30
|
+
function compactToolOutcome(result) {
|
|
31
|
+
const structured = result.status !== 'completed' || result.receipt.status !== null || result.receipt.allowed !== null
|
|
32
|
+
|| result.receipt.via !== null || result.receipt.reason !== null || result.receipt.risk !== null || result.enforcement !== null;
|
|
33
|
+
if (!structured)
|
|
34
|
+
return undefined;
|
|
35
|
+
return {
|
|
36
|
+
toolCallId: result.toolCallId,
|
|
37
|
+
status: result.status,
|
|
38
|
+
content: result.content,
|
|
39
|
+
receiptStatus: result.receipt.status,
|
|
40
|
+
exitCode: result.enforcement?.exitCode ?? null,
|
|
41
|
+
enforcement: result.enforcement?.sandbox ?? null,
|
|
42
|
+
allowed: result.receipt.allowed,
|
|
43
|
+
permissionVia: result.receipt.via,
|
|
44
|
+
permissionReason: result.receipt.reason,
|
|
45
|
+
risk: result.receipt.risk,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function canonicalError(data) {
|
|
49
|
+
const row = objectValue(data.error);
|
|
50
|
+
const envelope = objectValue(row?.envelope);
|
|
51
|
+
return row && typeof row.message === 'string' && envelope ? row : undefined;
|
|
52
|
+
}
|
|
53
|
+
function identity(event) { return { eventId: event.eventId }; }
|
|
54
|
+
/*
|
|
55
|
+
* R1 lane R (D-04, gate E9): the kernel records the person's prompt ONLY as `RunStarted.input.consegna` (measured through the
|
|
56
|
+
* real composition, r1-resume-history.test.ts); no `TextMessageStart role:user` exists, so a replay rebuilt no user message.
|
|
57
|
+
* The prompt is shown as it was typed: the project-reference blocks `renderPromptWithAttachments` appends
|
|
58
|
+
* (runtime/attachments.ts:65-70) are cut, the `@path` the person wrote stays. The local runtime passes chat messages instead.
|
|
59
|
+
*/
|
|
60
|
+
const REFERENCE_BLOCKS = '\n\n[TALOS project reference: ', REFERENCE_END = '[End TALOS project reference]';
|
|
61
|
+
function typedPrompt(value) { const cut = value.indexOf(REFERENCE_BLOCKS); return cut >= 0 && value.endsWith(REFERENCE_END) ? value.slice(0, cut) : value; }
|
|
62
|
+
function messageText(content) {
|
|
63
|
+
if (typeof content === 'string')
|
|
64
|
+
return content;
|
|
65
|
+
if (!Array.isArray(content))
|
|
66
|
+
return undefined;
|
|
67
|
+
const parts = content.map(part => objectValue(part)).filter(part => part?.type === 'text' && typeof part.text === 'string').map(part => String(part.text));
|
|
68
|
+
return parts.length ? parts.join('\n') : undefined;
|
|
69
|
+
}
|
|
70
|
+
export function runPrompt(input) {
|
|
71
|
+
if (Array.isArray(input)) {
|
|
72
|
+
for (let i = input.length - 1; i >= 0; i--) {
|
|
73
|
+
const row = objectValue(input[i]);
|
|
74
|
+
if (row?.role === 'user')
|
|
75
|
+
return stringValue(messageText(row.content));
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
/* R2 lane J (E11): protocol v2 renames `consegna` to `prompt`; the TUI reads both. */
|
|
80
|
+
const text = stringValue(objectValue(input)?.prompt) ?? stringValue(objectValue(input)?.consegna);
|
|
81
|
+
return text === undefined ? undefined : stringValue(typedPrompt(text));
|
|
82
|
+
}
|
|
83
|
+
function role(value) { return value === 'user' ? 'user' : 'assistant'; }
|
|
84
|
+
function countOrNull(value) { return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? Math.round(value) : null; }
|
|
85
|
+
/* R5a lane R (S10): a kernel tool id in the screen's words, for the English refusal reasons. */
|
|
86
|
+
const toolLabel = (id) => { try {
|
|
87
|
+
return toolDisplay(id).label;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return id;
|
|
91
|
+
} };
|
|
92
|
+
/** The screen's copy of a tool result: the kernel's Italian refusal reason in English (display only; v2 keeps the kernel's). */
|
|
93
|
+
function displayReceipt(result) {
|
|
94
|
+
const reason = result.receipt.reason;
|
|
95
|
+
if (!reason)
|
|
96
|
+
return result;
|
|
97
|
+
const english = describeKernelRefusalReason(reason, { toolLabel });
|
|
98
|
+
return english && english !== reason ? { ...result, receipt: { ...result.receipt, reason: english } } : result;
|
|
99
|
+
}
|
|
100
|
+
function projectCanonical(event) {
|
|
101
|
+
const id = identity(event);
|
|
102
|
+
const data = event.data;
|
|
103
|
+
switch (event.type) {
|
|
104
|
+
case 'run.started': {
|
|
105
|
+
const runId = stringValue(data.runId), prompt = runPrompt(data.input);
|
|
106
|
+
return { type: 'run.started', sessionId: event.sessionId, ...(runId ? { runId } : {}), ...(prompt ? { prompt } : {}), ...id };
|
|
107
|
+
}
|
|
108
|
+
case 'message.started':
|
|
109
|
+
return { type: 'message.started', messageId: String(data.messageId ?? 'assistant'), role: role(data.role), ...id };
|
|
110
|
+
case 'message.delta': {
|
|
111
|
+
/* R2 lane E (gate E4): a kernel notice arrives as one whole assistant message (no code); only its exact template is
|
|
112
|
+
replaced, so the model's own words are never touched. */
|
|
113
|
+
const delta = String(data.delta ?? '');
|
|
114
|
+
return { type: 'message.delta', messageId: String(data.messageId ?? 'assistant'), delta: describeKernelNotice(delta) ?? delta, ...id };
|
|
115
|
+
}
|
|
116
|
+
case 'message.completed':
|
|
117
|
+
return { type: 'message.end', messageId: String(data.messageId ?? 'assistant'), ...id };
|
|
118
|
+
case 'reasoning.started':
|
|
119
|
+
return { type: 'reasoning.started', messageId: String(data.messageId ?? 'reasoning'), ...id };
|
|
120
|
+
case 'reasoning.delta':
|
|
121
|
+
return { type: 'reasoning.delta', messageId: String(data.messageId ?? 'reasoning'), delta: String(data.delta ?? ''), ...id };
|
|
122
|
+
case 'reasoning.completed':
|
|
123
|
+
return { type: 'reasoning.end', messageId: String(data.messageId ?? 'reasoning'), ...id };
|
|
124
|
+
case 'tool.started':
|
|
125
|
+
return { type: 'tool.started', toolCallId: String(data.toolCallId ?? ''), toolName: String(data.toolName ?? 'tool'), ...id };
|
|
126
|
+
case 'tool.args':
|
|
127
|
+
return { type: 'tool.args', toolCallId: String(data.toolCallId ?? ''), delta: String(data.delta ?? ''), ...id };
|
|
128
|
+
case 'tool.output':
|
|
129
|
+
return { type: 'tool.output', toolCallId: String(data.toolCallId ?? ''), delta: String(data.delta ?? ''), ...id };
|
|
130
|
+
case 'tool.completed': {
|
|
131
|
+
const canonical = asToolResult(data);
|
|
132
|
+
if (!canonical)
|
|
133
|
+
return null;
|
|
134
|
+
/* R3 Q-R3-8 (R3-INT): the kernel's stop sentences in English, on the display copy only; a tool the person stopped is
|
|
135
|
+
`cancelled` (shown as interrupted), never `failed`. The canonical v2 result is untouched. */
|
|
136
|
+
const shown = describeKernelToolText(canonical.content);
|
|
137
|
+
const result = displayReceipt(shown.text === canonical.content && !shown.stopped ? canonical : { ...canonical, content: shown.text, ...(shown.stopped ? { status: 'cancelled' } : {}) });
|
|
138
|
+
const outcome = compactToolOutcome(result);
|
|
139
|
+
return {
|
|
140
|
+
type: 'tool.completed', toolCallId: result.toolCallId, content: result.content, result,
|
|
141
|
+
...(outcome ? { outcome } : {}), ...id
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
case 'file.changed':
|
|
145
|
+
return { type: 'file.changed', data: { ...data }, ...id };
|
|
146
|
+
case 'approval.required': {
|
|
147
|
+
const payload = objectValue(data.azione ?? data.action) ?? {};
|
|
148
|
+
const toolCallId = stringValue(payload.toolCallId);
|
|
149
|
+
return {
|
|
150
|
+
type: 'approval.required',
|
|
151
|
+
requestId: String(data.requestId ?? ''),
|
|
152
|
+
payload: { ...payload },
|
|
153
|
+
...(toolCallId ? { toolCallId } : {}),
|
|
154
|
+
...id
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
case 'approval.resolved': {
|
|
158
|
+
const approved = booleanValue(data.approvato) ?? booleanValue(data.approved);
|
|
159
|
+
return { type: 'approval.resolved', requestId: String(data.requestId ?? ''), ...(approved !== undefined ? { approved } : {}), ...id };
|
|
160
|
+
}
|
|
161
|
+
case 'usage.updated': {
|
|
162
|
+
/* R5a lane R (S1): the last request's own usage and the run's declared cost ride inside the value (additive keys), so the
|
|
163
|
+
state keeps one usage object and `usageSnapshot` reads them there. */
|
|
164
|
+
const value = objectValue(data.value);
|
|
165
|
+
const lastRequest = objectValue(data.lastRequest);
|
|
166
|
+
const declared = countOrNull(data.declaredCostUsd) === null ? null : Number(data.declaredCostUsd);
|
|
167
|
+
if (!value || (!lastRequest && declared === null))
|
|
168
|
+
return { type: 'usage.updated', value: data.value, ...id };
|
|
169
|
+
return { type: 'usage.updated', value: { ...value, ...(lastRequest ? { lastRequest: { ...lastRequest } } : {}), ...(declared !== null ? { declaredCostUsd: declared } : {}) }, ...id };
|
|
170
|
+
}
|
|
171
|
+
case 'provider.attempt': {
|
|
172
|
+
const attempt = countOrNull(data.attempt), maxAttempts = countOrNull(data.maxAttempts);
|
|
173
|
+
if (attempt === null || maxAttempts === null)
|
|
174
|
+
return null;
|
|
175
|
+
return { type: 'provider.attempt', attempt, maxAttempts, status: countOrNull(data.status), retryAfterMs: countOrNull(data.retryAfterMs), waitMs: countOrNull(data.waitMs), ...id };
|
|
176
|
+
}
|
|
177
|
+
case 'context.summary.requested': return { type: 'context.summary.requested', ...id };
|
|
178
|
+
case 'context.compaction.paused': {
|
|
179
|
+
const code = typeof data.code === 'string' ? data.code : '', retryAfter = typeof data.retryAfter === 'string' ? data.retryAfter : '';
|
|
180
|
+
if (!code || !Number.isFinite(Date.parse(retryAfter)))
|
|
181
|
+
return null;
|
|
182
|
+
return { type: 'context.compaction.paused', noticeId: typeof data.noticeId === 'string' ? data.noticeId : null, code, attempts: countOrNull(data.attempts), waitSeconds: countOrNull(data.waitSeconds), retryAfter, ...id };
|
|
183
|
+
}
|
|
184
|
+
case 'context.compacted': {
|
|
185
|
+
const trigger = data.trigger === 'manual' || data.trigger === 'automatic' ? data.trigger : null;
|
|
186
|
+
return { type: 'context.compacted', engine: data.engine === 'context-engine' ? 'context-engine' : 'kernel', messagesSummarized: countOrNull(data.messagesSummarized),
|
|
187
|
+
tokensBefore: countOrNull(data.tokensBefore), tokensAfter: countOrNull(data.tokensAfter), ...(trigger ? { trigger } : {}), ...id };
|
|
188
|
+
}
|
|
189
|
+
case 'warning': {
|
|
190
|
+
/* R2 lane E (Q-R2-2): a kernel notice has no code (`onAvviso`, RuntimeFallback): Italian text is replaced by one English
|
|
191
|
+
sentence and kept as `raw` for the expanded view and the log; the CLI's own English notices pass unchanged. */
|
|
192
|
+
const message = String(data.message ?? 'warning');
|
|
193
|
+
return looksItalian(message) ? { type: 'warning', message: t('error.warning.untranslated'), raw: message, ...id } : { type: 'warning', message, ...id };
|
|
194
|
+
}
|
|
195
|
+
case 'session.snapshot':
|
|
196
|
+
return { type: 'session.snapshot', data: { ...data }, ...id };
|
|
197
|
+
case 'run.completed': {
|
|
198
|
+
const runId = stringValue(data.runId);
|
|
199
|
+
return { type: 'run.completed', ...(runId ? { runId } : {}), ...id };
|
|
200
|
+
}
|
|
201
|
+
case 'run.failed': {
|
|
202
|
+
const error = canonicalError(data);
|
|
203
|
+
const runId = stringValue(data.runId);
|
|
204
|
+
/* R2 lane E (gate E4, Q-R2-4): the message is the English three-part view of the CODE; the kernel's text rides along
|
|
205
|
+
only inside `error` (the transcript keeps it as the row's raw detail). */
|
|
206
|
+
const view = describeError(error ?? { message: String(data.message ?? 'run failed'), code: data.code });
|
|
207
|
+
return {
|
|
208
|
+
type: 'run.failed',
|
|
209
|
+
message: errorViewLines(view).join('\n'),
|
|
210
|
+
...(error ? { error } : {}),
|
|
211
|
+
...(runId ? { runId } : {}),
|
|
212
|
+
...id
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
case 'run.cancelled': {
|
|
216
|
+
const runId = stringValue(data.runId);
|
|
217
|
+
const reason = stringValue(data.reason);
|
|
218
|
+
return { type: 'run.cancelled', ...(runId ? { runId } : {}), ...(reason ? { reason } : {}), ...id };
|
|
219
|
+
}
|
|
220
|
+
default:
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/*
|
|
225
|
+
* R3 gate E3 (Q-R3-1/2): the facts of a finished tool, from structured fields only: the receipt's exit code, the kernel's
|
|
226
|
+
* measured `durataMs` (v2 `details.durationMs`, talosHarness.mjs:8661), and the isolation named by the glyph the CLI's own
|
|
227
|
+
* executor puts first in its annotation (`EXECUTION_TEXT.isolation`: ⛉ sandbox, ⛶ host). An absent fact stays absent: a
|
|
228
|
+
* zero would say "instant" or "exit 0" where the truth is unknown (agui-events.mjs OSS-1).
|
|
229
|
+
*/
|
|
230
|
+
const SANDBOX_GLYPH = '⛉', HOST_GLYPH = '⛶';
|
|
231
|
+
export function isolationOf(enforcement) {
|
|
232
|
+
if (typeof enforcement !== 'string')
|
|
233
|
+
return null;
|
|
234
|
+
const head = enforcement.trimStart();
|
|
235
|
+
return head.startsWith(SANDBOX_GLYPH) ? 'sandbox' : head.startsWith(HOST_GLYPH) ? 'host' : null;
|
|
236
|
+
}
|
|
237
|
+
function toolFacts(result, noted = null) {
|
|
238
|
+
const exitCode = result.enforcement?.exitCode, durationMs = objectValue(result.details)?.durationMs, isolation = isolationOf(result.enforcement?.sandbox);
|
|
239
|
+
const denial = noted ?? kernelDenial(result);
|
|
240
|
+
const facts = {
|
|
241
|
+
...(typeof exitCode === 'number' && Number.isInteger(exitCode) ? { exitCode } : {}),
|
|
242
|
+
...(typeof durationMs === 'number' && Number.isFinite(durationMs) && durationMs >= 0 ? { durationMs: Math.round(durationMs) } : {}),
|
|
243
|
+
...(isolation ? { isolation } : {}),
|
|
244
|
+
...(denial ? { denial } : {}),
|
|
245
|
+
};
|
|
246
|
+
return Object.keys(facts).length ? facts : null;
|
|
247
|
+
}
|
|
248
|
+
/*
|
|
249
|
+
* R5a lane R (S10, gate finding 15). Why a refused tool did not run, from the receipt alone, only when the receipt can say
|
|
250
|
+
* it: the session's own level (read-only, research, workspace writes, a tool turned off) is `mode`; the kernel's floors (a
|
|
251
|
+
* command that cannot be undone, the checkpoint guard) are `policy`. An "asked" via is NOT decided here: the kernel writes
|
|
252
|
+
* the same via and the same sentence whether the person said no or the permission engine answered alone (finding 15), so
|
|
253
|
+
* only the session controller, which asked, can say which (`noteDenial`). A stop is not a denial.
|
|
254
|
+
*/
|
|
255
|
+
const MODE_VIAS = new Set(['toolOff', 'readOnly', 'research', 'workspaceWrite']);
|
|
256
|
+
const POLICY_VIAS = new Set(['noRecovery', 'checkpoint']);
|
|
257
|
+
function kernelDenial(result) {
|
|
258
|
+
if (result.receipt.allowed !== false && result.receipt.status !== 'denied')
|
|
259
|
+
return null;
|
|
260
|
+
const key = result.receipt.via ? REFUSAL_VIA[result.receipt.via] : undefined;
|
|
261
|
+
if (!key || (!MODE_VIAS.has(key) && !POLICY_VIAS.has(key)))
|
|
262
|
+
return null;
|
|
263
|
+
const english = result.receipt.reason ? describeKernelRefusalReason(result.receipt.reason, { toolLabel }) : null;
|
|
264
|
+
const reason = english ?? (result.receipt.reason && !looksItalian(result.receipt.reason) ? result.receipt.reason : null);
|
|
265
|
+
return { by: MODE_VIAS.has(key) ? 'mode' : 'policy', ...(reason ? { reason } : {}) };
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* R5a lane R (S10): the denial fact for a decision the permission engine made ALONE (`ApprovalDecision` deny,
|
|
269
|
+
* security/permission-engine.ts:36-44), in English. A matched deny rule is `rule` with its text (`explain.rule`, e.g. the
|
|
270
|
+
* rule `simulatePermission` names) and scope; a command the policy cannot split (`unsupported shell composition`,
|
|
271
|
+
* security/evaluate.ts:134-140) or a path outside the project is `policy`; plan mode, a mode that never asks and the automatic
|
|
272
|
+
* classifier are `mode`. The person's own "no" is `{by:'person'}`, and nothing else is.
|
|
273
|
+
*/
|
|
274
|
+
export function denialFromEngine(decision, explain = {}) {
|
|
275
|
+
const code = String(decision?.code ?? '');
|
|
276
|
+
const message = String(decision?.message ?? '');
|
|
277
|
+
const because = (id) => ({ by: code === 'PATH_NOT_ALLOWED' || id === 'error.denial.reason.unsupportedShell' || id === 'error.denial.reason.pathOutside' ? 'policy' : 'mode', reason: t(id) });
|
|
278
|
+
if (code === 'PLAN_MODE_READ_ONLY')
|
|
279
|
+
return because('error.denial.reason.planMode');
|
|
280
|
+
if (code === 'PERMISSION_REQUIRED')
|
|
281
|
+
return because('error.denial.reason.noAsking');
|
|
282
|
+
if (code === 'PERMISSION_AUTO_DENIED')
|
|
283
|
+
return because('error.denial.reason.autoDenied');
|
|
284
|
+
if (code === 'PATH_NOT_ALLOWED')
|
|
285
|
+
return because('error.denial.reason.pathOutside');
|
|
286
|
+
if (/(?:^|: )matched deny rule$/u.test(message)) {
|
|
287
|
+
let rule = null;
|
|
288
|
+
try {
|
|
289
|
+
rule = explain.rule?.() ?? null;
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
rule = null;
|
|
293
|
+
}
|
|
294
|
+
let scope = null;
|
|
295
|
+
try {
|
|
296
|
+
scope = rule ? explain.scope?.(rule) ?? null : null;
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
scope = null;
|
|
300
|
+
}
|
|
301
|
+
return { by: 'rule', ...(rule ? { rule } : {}), ...(scope ? { scope } : {}) };
|
|
302
|
+
}
|
|
303
|
+
if (/unsupported shell composition$/u.test(message))
|
|
304
|
+
return because('error.denial.reason.unsupportedShell');
|
|
305
|
+
if (/write path is outside the authorized project$/u.test(message))
|
|
306
|
+
return because('error.denial.reason.pathOutside');
|
|
307
|
+
return { by: 'policy', ...(message && !looksItalian(message) ? { reason: message } : {}) };
|
|
308
|
+
}
|
|
309
|
+
/*
|
|
310
|
+
* R3 gate E10 (Q-R3-4): a file the kernel wrote arrives as `StateDelta` rows `/file/<path>` with the text after and, for a
|
|
311
|
+
* file that existed, the text before (`prima`) (agui-events.mjs:427-436); the v2 bridge keeps only `/usage`, so the TUI
|
|
312
|
+
* reads the rows here, through the same redactor as every v2 string. A replaced file whose before is unknown is skipped
|
|
313
|
+
* (it must not look new); texts over MAX_FILE_CHANGE_CHARS are skipped (the diff of a huge file is not a screen). The change
|
|
314
|
+
* belongs to the open tool call whose arguments name the same path, or else to the only open call.
|
|
315
|
+
*/
|
|
316
|
+
const MAX_FILE_CHANGE_CHARS = 1_000_000, MAX_OPEN_ARGS_CHARS = 65_536;
|
|
317
|
+
function samePath(value) { return value.replace(/\\/gu, '/').replace(/^\.\//u, ''); }
|
|
318
|
+
function argsPath(args) {
|
|
319
|
+
try {
|
|
320
|
+
const parsed = objectValue(JSON.parse(args));
|
|
321
|
+
const value = parsed?.percorso ?? parsed?.path ?? parsed?.file_path;
|
|
322
|
+
return typeof value === 'string' && value ? samePath(value) : null;
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
export function createTuiEventAdapter(secretValues = []) {
|
|
329
|
+
let currentSessionId = null;
|
|
330
|
+
let bridge = null;
|
|
331
|
+
const redactor = createRedactor(secretValues);
|
|
332
|
+
const openTools = new Map();
|
|
333
|
+
/* R5a lane R (S10): the denial facts the session controller noted, by tool call, until the tool's result arrives. */
|
|
334
|
+
const noted = new Map();
|
|
335
|
+
/* R5a lane R (S3): the kernel compactions seen live in this run (the fetch observer's event). */
|
|
336
|
+
let liveKernelCompactions = 0;
|
|
337
|
+
function bindSession(sessionId) {
|
|
338
|
+
if (typeof sessionId !== 'string' || sessionId.length === 0)
|
|
339
|
+
throw new Error('SESSION_ID_REQUIRED');
|
|
340
|
+
if (sessionId === currentSessionId && bridge)
|
|
341
|
+
return;
|
|
342
|
+
currentSessionId = sessionId;
|
|
343
|
+
openTools.clear();
|
|
344
|
+
noted.clear();
|
|
345
|
+
liveKernelCompactions = 0;
|
|
346
|
+
bridge = createV2EventBridge(sessionId, undefined, secretValues);
|
|
347
|
+
}
|
|
348
|
+
function canonicalOf(raw) {
|
|
349
|
+
if (isCanonicalEvent(raw))
|
|
350
|
+
return raw;
|
|
351
|
+
if (!raw || typeof raw !== 'object' || !bridge)
|
|
352
|
+
return null;
|
|
353
|
+
return bridge.translate(raw);
|
|
354
|
+
}
|
|
355
|
+
function translate(raw) {
|
|
356
|
+
const canonical = canonicalOf(raw);
|
|
357
|
+
return canonical ? projectCanonical(canonical) : null;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* R5a lane R (S10): the session controller tells the adapter who refused a tool BEFORE its result arrives — the person
|
|
361
|
+
* (`{by:'person'}`, only after asking) or the engine alone (`denialFromEngine`). The next `tool.facts` of that call carries it.
|
|
362
|
+
*/
|
|
363
|
+
function noteDenial(toolCallId, denial) {
|
|
364
|
+
if (typeof toolCallId !== 'string' || !toolCallId || !denial)
|
|
365
|
+
return;
|
|
366
|
+
noted.set(toolCallId, denial);
|
|
367
|
+
if (noted.size > 256)
|
|
368
|
+
noted.delete(noted.keys().next().value);
|
|
369
|
+
}
|
|
370
|
+
function fileChanges(raw) {
|
|
371
|
+
if (raw.type !== 'StateDelta' || !Array.isArray(raw.delta))
|
|
372
|
+
return [];
|
|
373
|
+
const out = [];
|
|
374
|
+
for (const entry of raw.delta) {
|
|
375
|
+
const row = objectValue(entry);
|
|
376
|
+
const where = stringValue(row?.path);
|
|
377
|
+
if (!row || !where?.startsWith('/file/') || typeof row.value !== 'string' || (row.op !== 'add' && row.op !== 'replace'))
|
|
378
|
+
continue;
|
|
379
|
+
const before = row.op === 'add' ? null : typeof row.prima === 'string' ? row.prima : undefined;
|
|
380
|
+
if (before === undefined || row.value.length > MAX_FILE_CHANGE_CHARS || (before?.length ?? 0) > MAX_FILE_CHANGE_CHARS)
|
|
381
|
+
continue;
|
|
382
|
+
const path = where.slice('/file/'.length);
|
|
383
|
+
const owners = [...openTools].filter(([, args]) => argsPath(args) === samePath(path)).map(([id]) => id);
|
|
384
|
+
/* The call whose arguments name the path; failing that, the only open call (lane RD matches by path otherwise). */
|
|
385
|
+
const owner = owners.length === 1 ? owners[0] : owners.length === 0 && openTools.size === 1 ? [...openTools.keys()][0] : undefined;
|
|
386
|
+
const change = { path: redactor.text(path), before: before === null ? null : redactor.text(before), after: redactor.text(row.value), ...(owner ? { toolCallId: owner } : {}) };
|
|
387
|
+
out.push({ type: 'file.changed', change });
|
|
388
|
+
}
|
|
389
|
+
return out;
|
|
390
|
+
}
|
|
391
|
+
function translateAll(raw) {
|
|
392
|
+
const canonical = canonicalOf(raw);
|
|
393
|
+
const event = canonical ? projectCanonical(canonical) : null;
|
|
394
|
+
const out = event ? [event] : [];
|
|
395
|
+
if (event?.type === 'run.started')
|
|
396
|
+
liveKernelCompactions = 0;
|
|
397
|
+
else if (event?.type === 'context.compacted' && event.engine === 'kernel' && event.trigger !== 'manual')
|
|
398
|
+
liveKernelCompactions++;
|
|
399
|
+
if (event?.type === 'run.completed') {
|
|
400
|
+
/* R5a lane R (S3): the kernel counts its own compactions in the run's result (`compattazioni` → v2 `compactions`,
|
|
401
|
+
agent-service.mjs:182). A compaction the live observer did not report — every one, in a replay, where live events do
|
|
402
|
+
not exist — is named here, before the run ends, with what is known: nothing but that it happened. */
|
|
403
|
+
const total = countOrNull(objectValue(objectValue(canonical?.data)?.result)?.compactions) ?? 0;
|
|
404
|
+
const missing = Math.max(0, total - liveKernelCompactions);
|
|
405
|
+
for (let i = 0; i < missing; i++)
|
|
406
|
+
out.unshift({ type: 'context.compacted', engine: 'kernel', messagesSummarized: null, tokensBefore: null, tokensAfter: null, trigger: 'automatic' });
|
|
407
|
+
liveKernelCompactions = 0;
|
|
408
|
+
}
|
|
409
|
+
if (event?.type === 'tool.started')
|
|
410
|
+
openTools.set(event.toolCallId, '');
|
|
411
|
+
else if (event?.type === 'run.completed' || event?.type === 'run.failed' || event?.type === 'run.cancelled')
|
|
412
|
+
openTools.clear();
|
|
413
|
+
else if (event?.type === 'tool.args' && openTools.has(event.toolCallId))
|
|
414
|
+
openTools.set(event.toolCallId, (openTools.get(event.toolCallId) + event.delta).slice(0, MAX_OPEN_ARGS_CHARS));
|
|
415
|
+
else if (event?.type === 'tool.completed') {
|
|
416
|
+
openTools.delete(event.toolCallId);
|
|
417
|
+
const denial = noted.get(event.toolCallId) ?? null;
|
|
418
|
+
noted.delete(event.toolCallId);
|
|
419
|
+
const facts = event.result ? toolFacts(event.result, denial) : null;
|
|
420
|
+
if (facts)
|
|
421
|
+
out.push({ type: 'tool.facts', toolCallId: event.toolCallId, facts });
|
|
422
|
+
/* R5a lane R (Q-R5-10/11): the cut the model read, as facts the row states (the v2 result carries them). */
|
|
423
|
+
const saved = event.result?.outputSaved;
|
|
424
|
+
if (saved?.path)
|
|
425
|
+
out.push({ type: 'tool.output.saved', toolCallId: event.toolCallId, path: saved.path, keptChars: saved.keptChars, totalChars: saved.totalChars });
|
|
426
|
+
const cut = event.result?.readCut;
|
|
427
|
+
if (cut)
|
|
428
|
+
out.push({ type: 'tool.read.cut', toolCallId: event.toolCallId, shownLines: cut.shownLines, totalLines: cut.totalLines, limitChars: cut.limitChars });
|
|
429
|
+
}
|
|
430
|
+
const row = objectValue(raw);
|
|
431
|
+
if (row && !isCanonicalEvent(raw))
|
|
432
|
+
out.push(...fileChanges(row));
|
|
433
|
+
return out;
|
|
434
|
+
}
|
|
435
|
+
return { bindSession, translate, translateAll, noteDenial };
|
|
436
|
+
}
|