@gajae-code/coding-agent 0.18.11 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +760 -0
- package/dist/types/async/job-manager.d.ts +7 -3
- package/dist/types/async/result-formatting.d.ts +2 -0
- package/dist/types/autoresearch/git.d.ts +1 -1
- package/dist/types/capability/fs.d.ts +2 -2
- package/dist/types/capability/rule.d.ts +7 -2
- package/dist/types/cli/accounts-cli.d.ts +2 -2
- package/dist/types/cli/append-system-prompt.d.ts +6 -0
- package/dist/types/cli/args.d.ts +7 -2
- package/dist/types/cli/customize-doctor-precedence.d.ts +16 -0
- package/dist/types/cli/customize-doctor.d.ts +4 -3
- package/dist/types/cli/doctor/install-repairs.d.ts +4 -1
- package/dist/types/cli/install-activation.d.ts +10 -4
- package/dist/types/cli/public-command-errors.d.ts +2 -0
- package/dist/types/cli/root-flags.d.ts +0 -12
- package/dist/types/cli/update-cli.d.ts +21 -3
- package/dist/types/cli-main.d.ts +0 -6
- package/dist/types/cli-ordinary.d.ts +2 -2
- package/dist/types/commands/accounts.d.ts +2 -1
- package/dist/types/commands/launch.d.ts +0 -6
- package/dist/types/commands/migrate.d.ts +1 -1
- package/dist/types/commands/sdk.d.ts +13 -0
- package/dist/types/commit/changelog/index.d.ts +1 -0
- package/dist/types/commit/map-reduce/index.d.ts +4 -4
- package/dist/types/config/autorouting-tier-map.d.ts +53 -1
- package/dist/types/config/config-hot-reload-trust.d.ts +12 -0
- package/dist/types/config/config-hot-reload.d.ts +44 -0
- package/dist/types/config/file-lock.d.ts +52 -3
- package/dist/types/config/model-discovery-manager.d.ts +2 -0
- package/dist/types/config/model-profile-activation.d.ts +79 -9
- package/dist/types/config/model-registry.d.ts +72 -8
- package/dist/types/config/model-resolver.d.ts +7 -4
- package/dist/types/config/models-config-schema.d.ts +10 -0
- package/dist/types/config/settings-schema.d.ts +57 -4
- package/dist/types/config/settings.d.ts +33 -1
- package/dist/types/coordinator-mcp/server.d.ts +4 -0
- package/dist/types/customization/import.d.ts +2 -0
- package/dist/types/customization/types.d.ts +1 -1
- package/dist/types/dap/config.d.ts +8 -4
- package/dist/types/dap/session.d.ts +11 -2
- package/dist/types/debug/system-info.d.ts +6 -1
- package/dist/types/discovery/helpers.d.ts +7 -2
- package/dist/types/discovery/mcp-compat.d.ts +3 -1
- package/dist/types/edit/index.d.ts +5 -0
- package/dist/types/edit/modes/patch.d.ts +14 -0
- package/dist/types/edit/modes/replace.d.ts +3 -0
- package/dist/types/eval/py/runtime.d.ts +9 -0
- package/dist/types/exec/bash-executor.d.ts +12 -0
- package/dist/types/export/ttsr.d.ts +19 -0
- package/dist/types/extensibility/extensions/types.d.ts +5 -1
- package/dist/types/extensibility/slash-commands.d.ts +1 -0
- package/dist/types/gjc-runtime/managed-owner-admission.d.ts +3 -0
- package/dist/types/gjc-runtime/ralplan-current-final.d.ts +54 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +5 -0
- package/dist/types/gjc-runtime/session-state-lock.d.ts +2 -0
- package/dist/types/gjc-runtime/state-runtime.d.ts +0 -2
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +24 -0
- package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +6 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +1 -0
- package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
- package/dist/types/hindsight/content.d.ts +5 -6
- package/dist/types/internal-urls/types.d.ts +2 -0
- package/dist/types/lsp/clients/swiftlint-client.d.ts +0 -4
- package/dist/types/main.d.ts +23 -18
- package/dist/types/migrate/action-planner.d.ts +10 -1
- package/dist/types/migrate/adapters/codex.d.ts +2 -1
- package/dist/types/migrate/adapters/index.d.ts +42 -1
- package/dist/types/migrate/executor.d.ts +3 -1
- package/dist/types/migrate/hook-module.d.ts +23 -0
- package/dist/types/migrate/report.d.ts +2 -1
- package/dist/types/migrate/types.d.ts +82 -3
- package/dist/types/modes/components/agent-dashboard.d.ts +1 -1
- package/dist/types/modes/components/model-selector.d.ts +43 -0
- package/dist/types/modes/components/settings-selector.d.ts +6 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +2 -0
- package/dist/types/modes/prompt-suggestion-controller.d.ts +1 -1
- package/dist/types/modes/theme/theme.d.ts +1 -0
- package/dist/types/modes/utils/host-status.d.ts +15 -11
- package/dist/types/runtime-mcp/content-limits.d.ts +4 -0
- package/dist/types/runtime-mcp/manager.d.ts +7 -0
- package/dist/types/runtime-mcp/plugin-mcp-name-filter.d.ts +22 -0
- package/dist/types/runtime-mcp/project-host-values.d.ts +11 -5
- package/dist/types/runtime-mcp/tool-bridge.d.ts +4 -0
- package/dist/types/sdk/broker/broker-exit.d.ts +3 -3
- package/dist/types/sdk/broker/broker.d.ts +29 -2
- package/dist/types/sdk/broker/daemon-entry.d.ts +11 -1
- package/dist/types/sdk/broker/doctor-restart.d.ts +1 -1
- package/dist/types/sdk/broker/ensure.d.ts +141 -9
- package/dist/types/sdk/broker/hop.d.ts +45 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +18 -10
- package/dist/types/sdk/broker/lifecycle.d.ts +22 -0
- package/dist/types/sdk/broker/lock-host-identity.d.ts +5 -0
- package/dist/types/sdk/broker/session-index.d.ts +6 -1
- package/dist/types/sdk/broker/transport.d.ts +2 -0
- package/dist/types/sdk/bus/chat-command-policy.d.ts +2 -1
- package/dist/types/sdk/bus/index.d.ts +44 -0
- package/dist/types/sdk/bus/reconciliation-store.d.ts +10 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +9 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +2 -0
- package/dist/types/sdk/bus/threaded-render.d.ts +2 -1
- package/dist/types/sdk/cli/session-cli.d.ts +0 -1
- package/dist/types/sdk/host/control/operations.d.ts +5 -1
- package/dist/types/sdk/host/events.d.ts +4 -0
- package/dist/types/sdk/host/host.d.ts +2 -1
- package/dist/types/sdk/host/prompt-image-upload.d.ts +43 -0
- package/dist/types/sdk/host/session-runtime.d.ts +40 -8
- package/dist/types/sdk/host/surface-policy.d.ts +2 -1
- package/dist/types/sdk/lifecycle/service.d.ts +12 -0
- package/dist/types/sdk/prompt-deadline-flush.d.ts +42 -4
- package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -0
- package/dist/types/sdk/prompt-status.d.ts +11 -4
- package/dist/types/sdk/protocol/adapter-validation.d.ts +10 -4
- package/dist/types/sdk/reconciliation-extensions.d.ts +1 -1
- package/dist/types/sdk/session-list.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +107 -9
- package/dist/types/session/internal/managed-session-scope.d.ts +2 -2
- package/dist/types/session/internal/managed-session-storage.d.ts +1 -1
- package/dist/types/session/internal/native-publish-outcome.d.ts +1 -1
- package/dist/types/session/messages.d.ts +5 -1
- package/dist/types/session/session-manager.d.ts +29 -3
- package/dist/types/session/startup-auth-config.d.ts +24 -2
- package/dist/types/session/streaming-output.d.ts +11 -0
- package/dist/types/session/terminal-abort.d.ts +3 -1
- package/dist/types/session-import/service.d.ts +1 -1
- package/dist/types/skill-state/workflow-mutation-guard.d.ts +20 -4
- package/dist/types/slash-commands/helpers/mcp.d.ts +5 -0
- package/dist/types/slash-commands/helpers/provider-auth-status.d.ts +8 -0
- package/dist/types/ssh/ssh-executor.d.ts +8 -1
- package/dist/types/system-prompt.d.ts +3 -2
- package/dist/types/task/executor.d.ts +19 -2
- package/dist/types/task/role-body.d.ts +11 -0
- package/dist/types/tools/ast-edit-write-path.d.ts +10 -0
- package/dist/types/tools/atomic-file-write.d.ts +9 -7
- package/dist/types/tools/awaiting-input.d.ts +28 -0
- package/dist/types/tools/bash-allowed-prefixes.d.ts +17 -0
- package/dist/types/tools/bash-skill-urls.d.ts +4 -0
- package/dist/types/tools/bash.d.ts +7 -0
- package/dist/types/tools/descriptors.d.ts +15 -2
- package/dist/types/tools/fetch.d.ts +7 -1
- package/dist/types/tools/index.d.ts +2 -0
- package/dist/types/tools/irc.d.ts +5 -3
- package/dist/types/tools/python.d.ts +1 -1
- package/dist/types/tools/report-issue.d.ts +41 -0
- package/dist/types/tools/subagent.d.ts +23 -0
- package/dist/types/tools/tmux-self-injection-guard.d.ts +2 -0
- package/dist/types/tools/ultragoal-ask-guard.d.ts +1 -1
- package/dist/types/tools/write.d.ts +2 -0
- package/dist/types/utils/file-mentions.d.ts +5 -0
- package/dist/types/utils/image-limits.d.ts +7 -0
- package/dist/types/utils/image-loading.d.ts +0 -1
- package/dist/types/utils/open.d.ts +0 -1
- package/dist/types/utils/pasted-image-loading.d.ts +1 -5
- package/dist/types/utils/prompt-suggestion.d.ts +2 -2
- package/dist/types/utils/shell-snapshot.d.ts +2 -0
- package/dist/types/utils/title-generator.d.ts +13 -3
- package/dist/types/web/scrapers/types.d.ts +8 -1
- package/dist/types/web/search/providers/codex.d.ts +6 -7
- package/dist/types/web/search/providers/insane.d.ts +7 -1
- package/dist/types/web/search/providers/searxng.d.ts +5 -0
- package/package.json +10 -9
- package/scripts/acp-conformance-agent.ts +12 -2
- package/scripts/build-binary.ts +2 -1
- package/scripts/capture-subagent-compact-panel-showcase.ts +105 -0
- package/scripts/generate-docs-index.ts +8 -1
- package/scripts/generate-sdk-operation-inventory.ts +38 -4
- package/src/async/job-manager.ts +356 -56
- package/src/async/result-formatting.ts +40 -0
- package/src/autoresearch/git.ts +9 -2
- package/src/autoresearch/prompts/prompt-setup.md +1 -1
- package/src/capability/fs.ts +58 -22
- package/src/capability/index.ts +2 -2
- package/src/capability/rule.ts +11 -2
- package/src/cli/accounts-cli.ts +176 -8
- package/src/cli/append-system-prompt.ts +12 -0
- package/src/cli/args.ts +11 -7
- package/src/cli/auth-broker-cli.ts +21 -11
- package/src/cli/customize-doctor-precedence.ts +31 -0
- package/src/cli/customize-doctor.ts +49 -39
- package/src/cli/doctor/install-repairs.ts +35 -5
- package/src/cli/fast-help.ts +1 -3
- package/src/cli/install-activation.ts +47 -4
- package/src/cli/migrate-cli.ts +19 -6
- package/src/cli/public-command-errors.ts +6 -0
- package/src/cli/root-flags.ts +2 -4
- package/src/cli/stats-cli.ts +9 -5
- package/src/cli/update-cli.ts +471 -13
- package/src/cli-ordinary.ts +7 -2
- package/src/commands/accounts.ts +10 -5
- package/src/commands/harness.ts +25 -15
- package/src/commands/migrate.ts +3 -3
- package/src/commands/sdk.ts +277 -50
- package/src/commands/ultragoal.ts +16 -8
- package/src/commit/agentic/agent.ts +6 -6
- package/src/commit/analysis/conventional.ts +14 -5
- package/src/commit/changelog/index.ts +39 -1
- package/src/commit/map-reduce/index.ts +7 -7
- package/src/commit/message.ts +10 -3
- package/src/commit/pipeline.ts +12 -12
- package/src/config/autorouting-tier-map.ts +50 -1
- package/src/config/config-file.ts +106 -3
- package/src/config/config-hot-reload-trust.ts +148 -0
- package/src/config/config-hot-reload.ts +742 -0
- package/src/config/file-lock.ts +1615 -328
- package/src/config/keybindings.ts +154 -7
- package/src/config/model-bindings-applier.ts +85 -47
- package/src/config/model-discovery-manager.ts +10 -0
- package/src/config/model-profile-activation.ts +889 -148
- package/src/config/model-registry.ts +1706 -205
- package/src/config/model-resolver.ts +52 -22
- package/src/config/models-config-schema.ts +6 -0
- package/src/config/settings-schema.ts +73 -4
- package/src/config/settings.ts +460 -24
- package/src/coordinator-mcp/policy.ts +26 -1
- package/src/coordinator-mcp/server.ts +37 -2
- package/src/crash/sanitize.ts +7 -1
- package/src/customization/import.ts +279 -8
- package/src/customization/inventory.ts +24 -8
- package/src/customization/types.ts +1 -0
- package/src/dap/client.ts +3 -2
- package/src/dap/config.ts +31 -11
- package/src/dap/defaults.json +1 -1
- package/src/dap/session.ts +161 -36
- package/src/debug/crash-diagnostics.ts +89 -6
- package/src/debug/report-bundle.ts +90 -2
- package/src/debug/system-info.ts +8 -3
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/shared/base-url.ts +21 -7
- package/src/discovery/agents-md.ts +1 -1
- package/src/discovery/builtin.ts +4 -3
- package/src/discovery/helpers.ts +25 -16
- package/src/discovery/mcp-compat.ts +120 -17
- package/src/edit/apply-patch/index.ts +12 -1
- package/src/edit/index.ts +204 -22
- package/src/edit/modes/patch.ts +214 -8
- package/src/edit/modes/replace.ts +136 -0
- package/src/eval/js/context-manager.ts +29 -3
- package/src/eval/js/worker-entry.ts +51 -18
- package/src/eval/py/executor.ts +14 -4
- package/src/eval/py/runner.py +144 -5
- package/src/eval/py/runtime.ts +44 -4
- package/src/exec/bash-executor.ts +81 -4
- package/src/exec/bash-shell-guardian.ts +4 -1
- package/src/exec/bash-shell-supervisor.ts +8 -4
- package/src/exec/isolated-shell.ts +5 -1
- package/src/exec/non-interactive-env.ts +0 -1
- package/src/export/html/index.ts +86 -6
- package/src/export/ttsr.ts +176 -1
- package/src/extensibility/custom-tools/wrapper.ts +3 -1
- package/src/extensibility/extensions/loader.ts +10 -1
- package/src/extensibility/extensions/ouroboros-ooo-bridge.ts +63 -1
- package/src/extensibility/extensions/types.ts +5 -1
- package/src/extensibility/hooks/loader.ts +10 -2
- package/src/extensibility/plugins/marketplace/fetcher.ts +2 -2
- package/src/extensibility/plugins/marketplace/manager.ts +36 -10
- package/src/extensibility/slash-commands.ts +5 -0
- package/src/gjc-runtime/gc-runtime.ts +37 -7
- package/src/gjc-runtime/launch-tmux.ts +30 -15
- package/src/gjc-runtime/launch-worktree.test.ts +148 -0
- package/src/gjc-runtime/launch-worktree.ts +101 -14
- package/src/gjc-runtime/managed-owner-admission.ts +46 -2
- package/src/gjc-runtime/ralplan-current-final.ts +294 -0
- package/src/gjc-runtime/ralplan-runtime.ts +95 -1
- package/src/gjc-runtime/session-resolution.ts +38 -6
- package/src/gjc-runtime/session-state-lock.ts +59 -14
- package/src/gjc-runtime/state-runtime.ts +23 -19
- package/src/gjc-runtime/state-writer.ts +109 -5
- package/src/gjc-runtime/tmux-sessions.ts +93 -13
- package/src/gjc-runtime/ultragoal-change-set.ts +90 -11
- package/src/gjc-runtime/ultragoal-guard.ts +9 -1
- package/src/gjc-runtime/ultragoal-runtime.ts +15 -5
- package/src/harness-control-plane/finalize.ts +11 -0
- package/src/harness-control-plane/receipt-spool.ts +105 -28
- package/src/harness-control-plane/storage.ts +124 -6
- package/src/hindsight/content.ts +116 -16
- package/src/hindsight/mental-models.ts +22 -10
- package/src/hindsight/state.ts +7 -4
- package/src/hooks/native-skill-hook.ts +17 -12
- package/src/internal-urls/artifact-protocol.ts +3 -1
- package/src/internal-urls/docs-index.generated.ts +23 -22
- package/src/internal-urls/local-protocol.ts +167 -8
- package/src/internal-urls/types.ts +2 -0
- package/src/lsp/client.ts +2 -1
- package/src/lsp/clients/biome-client.ts +2 -0
- package/src/lsp/clients/swiftlint-client.ts +2 -0
- package/src/lsp/index.ts +29 -0
- package/src/lsp/workspace-path.ts +23 -0
- package/src/main.ts +330 -92
- package/src/memories/index.ts +25 -2
- package/src/migrate/action-planner.ts +574 -2
- package/src/migrate/adapters/claude-code.ts +162 -5
- package/src/migrate/adapters/codex.ts +77 -7
- package/src/migrate/adapters/index.ts +258 -5
- package/src/migrate/adapters/opencode.ts +10 -1
- package/src/migrate/executor.ts +222 -7
- package/src/migrate/hook-module.ts +193 -0
- package/src/migrate/report.ts +63 -2
- package/src/migrate/types.ts +84 -4
- package/src/modes/DESIGN.md +51 -0
- package/src/modes/acp/acp-agent.ts +10 -1
- package/src/modes/acp/permission-mode.ts +18 -1
- package/src/modes/components/agent-dashboard.ts +20 -4
- package/src/modes/components/assistant-message.ts +55 -1
- package/src/modes/components/customization/customization-dashboard.ts +7 -0
- package/src/modes/components/customization/import-wizard.ts +29 -3
- package/src/modes/components/model-selector.ts +157 -103
- package/src/modes/components/settings-selector.ts +103 -37
- package/src/modes/components/welcome.ts +3 -1
- package/src/modes/controllers/command-controller.ts +300 -9
- package/src/modes/controllers/event-controller.ts +1 -1
- package/src/modes/controllers/extension-ui-controller.ts +31 -1
- package/src/modes/controllers/goal-mode-controller.ts +79 -10
- package/src/modes/controllers/input-controller.ts +2 -0
- package/src/modes/controllers/plan-mode-controller.ts +66 -11
- package/src/modes/controllers/runtime-mcp-command-controller.ts +7 -6
- package/src/modes/controllers/selector-controller.ts +76 -7
- package/src/modes/interactive-mode.ts +123 -4
- package/src/modes/prompt-suggestion-controller.ts +1 -1
- package/src/modes/runtime-init.ts +5 -1
- package/src/modes/theme/theme.ts +15 -0
- package/src/modes/utils/host-status.ts +21 -10
- package/src/prompts/agent-fragments/browser-aside.md +2 -2
- package/src/prompts/system/irc-incoming.md +3 -1
- package/src/prompts/tools/debug.md +1 -1
- package/src/prompts/tools/irc.md +1 -1
- package/src/prompts/tools/read.md +1 -1
- package/src/prompts/tools/report-issue.md +13 -0
- package/src/prompts/tools/task.md +1 -1
- package/src/runtime-credential-selector.ts +2 -2
- package/src/runtime-mcp/content-limits.ts +7 -0
- package/src/runtime-mcp/manager-pool.test.ts +5 -4
- package/src/runtime-mcp/manager.ts +40 -3
- package/src/runtime-mcp/oauth-flow.ts +32 -6
- package/src/runtime-mcp/plugin-mcp-name-filter.ts +62 -0
- package/src/runtime-mcp/project-host-values.ts +12 -8
- package/src/runtime-mcp/render.ts +16 -1
- package/src/runtime-mcp/tool-bridge.ts +194 -21
- package/src/runtime-mcp/transports/stdio.ts +2 -1
- package/src/sdk/broker/broker-exit.ts +10 -5
- package/src/sdk/broker/broker.ts +484 -85
- package/src/sdk/broker/daemon-entry.ts +338 -116
- package/src/sdk/broker/doctor-restart.ts +2 -1
- package/src/sdk/broker/ensure.ts +1214 -268
- package/src/sdk/broker/hop.ts +286 -0
- package/src/sdk/broker/lifecycle-ledger.ts +38 -11
- package/src/sdk/broker/lifecycle.ts +102 -6
- package/src/sdk/broker/lock-host-identity.ts +29 -0
- package/src/sdk/broker/session-index.ts +91 -16
- package/src/sdk/broker/transport.ts +17 -1
- package/src/sdk/bus/chat-command-policy.ts +16 -3
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/index.ts +460 -35
- package/src/sdk/bus/reconciliation-store.ts +201 -8
- package/src/sdk/bus/session-control.ts +2 -0
- package/src/sdk/bus/slack-daemon.ts +105 -9
- package/src/sdk/bus/telegram-daemon-contract.ts +9 -1
- package/src/sdk/bus/telegram-daemon.ts +10 -2
- package/src/sdk/bus/threaded-render.ts +20 -1
- package/src/sdk/cli/session-cli.ts +23 -6
- package/src/sdk/host/control/dispatch.ts +13 -1
- package/src/sdk/host/control/operations.ts +10 -1
- package/src/sdk/host/events.ts +67 -4
- package/src/sdk/host/host.ts +8 -2
- package/src/sdk/host/prompt-image-upload.ts +438 -0
- package/src/sdk/host/sdk-surface-parity.test.ts +15 -0
- package/src/sdk/host/session-runtime.test.ts +1737 -129
- package/src/sdk/host/session-runtime.ts +684 -83
- package/src/sdk/host/surface-policy.ts +4 -0
- package/src/sdk/host/websocket-transport.lifecycle.test.ts +90 -2
- package/src/sdk/host/websocket-transport.ts +19 -7
- package/src/sdk/lifecycle/service.ts +15 -1
- package/src/sdk/prompt-deadline-flush.ts +78 -5
- package/src/sdk/prompt-deadline-manager.ts +68 -14
- package/src/sdk/prompt-status.ts +6 -4
- package/src/sdk/protocol/adapter-validation.ts +81 -12
- package/src/sdk/protocol/operation-inventory.generated.json +261 -2
- package/src/sdk/protocol/operation-registry.ts +33 -3
- package/src/sdk/reconciliation-extensions.ts +1 -0
- package/src/sdk/session-list.ts +1 -0
- package/src/sdk/session.ts +237 -97
- package/src/session/agent-session.ts +2726 -479
- package/src/session/history-storage.ts +182 -12
- package/src/session/internal/managed-session-scope.ts +173 -57
- package/src/session/internal/managed-session-storage.ts +85 -12
- package/src/session/internal/native-publish-outcome.ts +5 -1
- package/src/session/messages.ts +47 -6
- package/src/session/session-manager.ts +326 -19
- package/src/session/startup-auth-config.ts +116 -8
- package/src/session/streaming-output.ts +262 -4
- package/src/session/terminal-abort.ts +14 -2
- package/src/session-import/redact.ts +53 -2
- package/src/session-import/service.ts +1 -0
- package/src/skill-state/workflow-mutation-guard.ts +2145 -206
- package/src/slash-commands/builtin-registry.ts +21 -6
- package/src/slash-commands/helpers/credential-switch.ts +10 -5
- package/src/slash-commands/helpers/mcp.ts +11 -3
- package/src/slash-commands/helpers/provider-auth-status.ts +456 -0
- package/src/ssh/ssh-executor.ts +9 -2
- package/src/stt/recorder.ts +26 -9
- package/src/system-prompt.ts +61 -16
- package/src/task/executor.ts +115 -20
- package/src/task/index.ts +389 -175
- package/src/task/role-body.ts +84 -0
- package/src/task/token-log-mode.test.ts +162 -0
- package/src/task/token-log.ts +91 -2
- package/src/tools/archive-reader.ts +650 -37
- package/src/tools/ask.ts +1 -0
- package/src/tools/ast-edit-write-path.ts +64 -0
- package/src/tools/ast-edit.ts +18 -1
- package/src/tools/ast-grep.ts +7 -2
- package/src/tools/atomic-file-write.ts +46 -15
- package/src/tools/auto-generated-guard.ts +15 -3
- package/src/tools/awaiting-input.ts +114 -0
- package/src/tools/bash-allowed-prefixes.ts +214 -6
- package/src/tools/bash-interactive.ts +14 -2
- package/src/tools/bash-skill-urls.ts +58 -5
- package/src/tools/bash.ts +113 -26
- package/src/tools/browser/tab-worker.ts +39 -13
- package/src/tools/browser.ts +17 -7
- package/src/tools/cron.ts +10 -1
- package/src/tools/debug.ts +16 -8
- package/src/tools/descriptors.test.ts +44 -0
- package/src/tools/descriptors.ts +50 -6
- package/src/tools/eval.ts +15 -0
- package/src/tools/fetch.ts +93 -4
- package/src/tools/gh.ts +27 -12
- package/src/tools/image-gen.ts +20 -6
- package/src/tools/index.ts +2 -0
- package/src/tools/irc.ts +5 -3
- package/src/tools/monitor.ts +9 -1
- package/src/tools/output-meta.ts +74 -5
- package/src/tools/python.ts +1 -1
- package/src/tools/read.ts +26 -37
- package/src/tools/recipe/runner.ts +23 -12
- package/src/tools/render-utils.ts +2 -2
- package/src/tools/report-issue.ts +184 -0
- package/src/tools/search.ts +3 -2
- package/src/tools/ssh.ts +274 -8
- package/src/tools/subagent-render.ts +114 -12
- package/src/tools/subagent.ts +118 -5
- package/src/tools/tmux-self-injection-guard.ts +3301 -122
- package/src/tools/todo-write.ts +41 -3
- package/src/tools/tool-catalog.generated.ts +32 -4
- package/src/tools/ultragoal-ask-guard.ts +13 -1
- package/src/tools/write.ts +42 -3
- package/src/tui/tree-list.ts +15 -1
- package/src/utils/commit-message-generator.ts +12 -4
- package/src/utils/external-editor.ts +21 -7
- package/src/utils/file-mentions.ts +75 -7
- package/src/utils/git.ts +38 -7
- package/src/utils/image-limits.ts +8 -0
- package/src/utils/image-loading.ts +1 -1
- package/src/utils/open.ts +73 -4
- package/src/utils/pasted-image-loading.ts +9 -8
- package/src/utils/prompt-suggestion.ts +5 -4
- package/src/utils/shell-snapshot.ts +9 -1
- package/src/utils/title-generator.ts +72 -22
- package/src/web/scrapers/index.ts +3 -1
- package/src/web/scrapers/types.ts +8 -0
- package/src/web/scrapers/youtube.ts +3 -2
- package/src/web/search/index.ts +2 -1
- package/src/web/search/providers/codex.ts +29 -32
- package/src/web/search/providers/insane.ts +91 -28
- package/src/web/search/providers/searxng.ts +62 -10
|
@@ -540,6 +540,76 @@ function isUnwritableResidentCacheFailure(error: unknown): boolean {
|
|
|
540
540
|
);
|
|
541
541
|
}
|
|
542
542
|
|
|
543
|
+
/** Nearest real directory at or above `start`. A file or missing path is not a root. */
|
|
544
|
+
function nearestExistingDirectory(start: string): string | null {
|
|
545
|
+
let current = path.resolve(start);
|
|
546
|
+
for (let depth = 0; depth < 64; depth++) {
|
|
547
|
+
try {
|
|
548
|
+
if (fs.lstatSync(current).isDirectory()) return current;
|
|
549
|
+
} catch {
|
|
550
|
+
// Missing components are not worktree roots.
|
|
551
|
+
}
|
|
552
|
+
const parent = path.dirname(current);
|
|
553
|
+
if (parent === current) return null;
|
|
554
|
+
current = parent;
|
|
555
|
+
}
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* Canonical path of `start`, following a symlink ancestor.
|
|
561
|
+
* The unmatched suffix is appended so a not-yet-created cache root classifies
|
|
562
|
+
* the directory `openVerifiedResidentCacheInstanceDir` would create it in.
|
|
563
|
+
*/
|
|
564
|
+
function canonicalCachePath(start: string): string | null {
|
|
565
|
+
let current = path.resolve(start);
|
|
566
|
+
const pending: string[] = [];
|
|
567
|
+
for (let depth = 0; depth < 64; depth++) {
|
|
568
|
+
try {
|
|
569
|
+
const stat = fs.lstatSync(current);
|
|
570
|
+
if (stat.isDirectory() || stat.isSymbolicLink()) {
|
|
571
|
+
const real = fs.realpathSync(current);
|
|
572
|
+
return pending.length === 0 ? real : path.join(real, ...pending.reverse());
|
|
573
|
+
}
|
|
574
|
+
} catch {
|
|
575
|
+
// Missing components are resolved from the nearest existing ancestor.
|
|
576
|
+
}
|
|
577
|
+
const parent = path.dirname(current);
|
|
578
|
+
if (parent === current) return null;
|
|
579
|
+
pending.push(path.basename(current));
|
|
580
|
+
current = parent;
|
|
581
|
+
}
|
|
582
|
+
return null;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
function cacheDirectoryInsideGitWorktree(directory: string): boolean {
|
|
586
|
+
return git.repo.resolveSync(directory) !== null;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Resident text is a second plaintext copy of assistant and tool output.
|
|
591
|
+
* A cache root inside a Git worktree can be staged by a later `git add`, so
|
|
592
|
+
* that root stays in memory. Both the lexical directory and the canonical
|
|
593
|
+
* directory are classified: a symlink outside the worktree must not hide a
|
|
594
|
+
* target inside it, and a lexical worktree path stays refused when its
|
|
595
|
+
* canonical target is outside. A missing or non-directory root still reaches
|
|
596
|
+
* the resident-cache trust check when both views are outside a worktree.
|
|
597
|
+
* No existing directory within 64 ancestors, or a resolver error, stays in memory.
|
|
598
|
+
*/
|
|
599
|
+
export function residentTextCacheRootAllowsDisk(cacheRoot: string): boolean {
|
|
600
|
+
try {
|
|
601
|
+
const lexical = nearestExistingDirectory(cacheRoot);
|
|
602
|
+
if (lexical === null || cacheDirectoryInsideGitWorktree(lexical)) return false;
|
|
603
|
+
const canonical = canonicalCachePath(cacheRoot);
|
|
604
|
+
if (canonical === null) return false;
|
|
605
|
+
const canonicalDirectory = nearestExistingDirectory(canonical);
|
|
606
|
+
if (canonicalDirectory === null || cacheDirectoryInsideGitWorktree(canonicalDirectory)) return false;
|
|
607
|
+
return true;
|
|
608
|
+
} catch {
|
|
609
|
+
return false;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
543
613
|
export interface SessionEntryBase {
|
|
544
614
|
type: string;
|
|
545
615
|
id: string;
|
|
@@ -3634,7 +3704,15 @@ function isLinkedWorktreePeer(a: string, b: string): boolean {
|
|
|
3634
3704
|
* Read the terminal breadcrumb for the current terminal, scoped to a cwd.
|
|
3635
3705
|
* Returns the session file path if it exists and matches the cwd, null otherwise.
|
|
3636
3706
|
*/
|
|
3637
|
-
async function readTerminalBreadcrumb(
|
|
3707
|
+
async function readTerminalBreadcrumb(
|
|
3708
|
+
cwd: string,
|
|
3709
|
+
options: {
|
|
3710
|
+
sessionsRoot?: string;
|
|
3711
|
+
allowExplicitOutsideRoot?: boolean;
|
|
3712
|
+
/** Managed continuation inventory, including project-local transcripts. */
|
|
3713
|
+
continuationInventory?: readonly SessionInfo[];
|
|
3714
|
+
} = {},
|
|
3715
|
+
): Promise<string | null> {
|
|
3638
3716
|
const terminalId = getTerminalId();
|
|
3639
3717
|
if (!terminalId) return null;
|
|
3640
3718
|
|
|
@@ -3656,9 +3734,9 @@ async function readTerminalBreadcrumb(cwd: string): Promise<string | null> {
|
|
|
3656
3734
|
|
|
3657
3735
|
if (isStagedSessionPath(sessionFile)) return null;
|
|
3658
3736
|
const inspected = inspectResumeSessionFile(sessionFile, new FileSessionStorage());
|
|
3737
|
+
const sessionsRoot = options.sessionsRoot ?? getSessionsDir();
|
|
3659
3738
|
if ("kind" in inspected) {
|
|
3660
3739
|
if (inspected.reason !== "missing") return null;
|
|
3661
|
-
const sessionsRoot = getSessionsDir();
|
|
3662
3740
|
const resolved = resolveManagedScope({
|
|
3663
3741
|
cwd: breadcrumbCwd,
|
|
3664
3742
|
agentDir: path.resolve(sessionsRoot, ".."),
|
|
@@ -3675,7 +3753,6 @@ async function readTerminalBreadcrumb(cwd: string): Promise<string | null> {
|
|
|
3675
3753
|
}
|
|
3676
3754
|
const header = inspected.entries[0] as SessionHeader;
|
|
3677
3755
|
if (resolveEquivalentPath(header.cwd) !== resolveEquivalentPath(breadcrumbCwd)) return null;
|
|
3678
|
-
const sessionsRoot = getSessionsDir();
|
|
3679
3756
|
const resolved = resolveManagedScope({
|
|
3680
3757
|
cwd: header.cwd,
|
|
3681
3758
|
agentDir: path.resolve(sessionsRoot, ".."),
|
|
@@ -3693,7 +3770,22 @@ async function readTerminalBreadcrumb(cwd: string): Promise<string | null> {
|
|
|
3693
3770
|
candidate => !isStagedSessionPath(candidate.path) && candidate.sessionId === header.id,
|
|
3694
3771
|
);
|
|
3695
3772
|
if (byIdentity) return byIdentity.path;
|
|
3696
|
-
|
|
3773
|
+
// Not an owned managed candidate. A file inside the sessions root stays
|
|
3774
|
+
// rejected. A file outside that root is resumed only when this continuation
|
|
3775
|
+
// inventory already contains it. An explicit destination still receives an
|
|
3776
|
+
// unmatched outside path; the caller applies containment.
|
|
3777
|
+
const resolvedFile = path.resolve(sessionFile);
|
|
3778
|
+
const insideSessionsRoot = pathIsWithin(sessionsRoot, resolvedFile);
|
|
3779
|
+
if (
|
|
3780
|
+
!insideSessionsRoot &&
|
|
3781
|
+
options.continuationInventory?.some(
|
|
3782
|
+
session => session.id === header.id && path.resolve(session.path) === resolvedFile,
|
|
3783
|
+
)
|
|
3784
|
+
) {
|
|
3785
|
+
return resolvedFile;
|
|
3786
|
+
}
|
|
3787
|
+
if (!options.allowExplicitOutsideRoot || insideSessionsRoot) return null;
|
|
3788
|
+
return resolvedFile;
|
|
3697
3789
|
} catch (err) {
|
|
3698
3790
|
if (!isEnoent(err)) logger.debug("Terminal breadcrumb read failed", { err });
|
|
3699
3791
|
// Breadcrumb doesn't exist or is corrupt — fall through
|
|
@@ -7289,6 +7381,17 @@ function sessionMatchesResumeArg(session: SessionInfo, sessionArg: string): bool
|
|
|
7289
7381
|
return fileSessionId.startsWith(normalizedArg);
|
|
7290
7382
|
}
|
|
7291
7383
|
|
|
7384
|
+
/**
|
|
7385
|
+
* Equal session id first, the same `id ===` check managed resume already uses.
|
|
7386
|
+
* Prefix matching stays for every other argument, in list order.
|
|
7387
|
+
*/
|
|
7388
|
+
export function pickResumableSession(sessions: readonly SessionInfo[], sessionArg: string): SessionInfo | undefined {
|
|
7389
|
+
return (
|
|
7390
|
+
sessions.find(session => session.id === sessionArg) ??
|
|
7391
|
+
sessions.find(session => sessionMatchesResumeArg(session, sessionArg))
|
|
7392
|
+
);
|
|
7393
|
+
}
|
|
7394
|
+
|
|
7292
7395
|
export async function resolveResumableSession(
|
|
7293
7396
|
sessionArg: string,
|
|
7294
7397
|
cwd: string,
|
|
@@ -7299,7 +7402,7 @@ export async function resolveResumableSession(
|
|
|
7299
7402
|
const localSessions = sessionDir
|
|
7300
7403
|
? await SessionManager.list(cwd, sessionDir, storage)
|
|
7301
7404
|
: await SessionManager.listManagedForResumePickerReadOnly(cwd, managedAgentDir, storage);
|
|
7302
|
-
const localMatch = localSessions
|
|
7405
|
+
const localMatch = pickResumableSession(localSessions, sessionArg);
|
|
7303
7406
|
if (localMatch) {
|
|
7304
7407
|
return { session: localMatch, scope: "local" };
|
|
7305
7408
|
}
|
|
@@ -7309,7 +7412,7 @@ export async function resolveResumableSession(
|
|
|
7309
7412
|
}
|
|
7310
7413
|
|
|
7311
7414
|
const globalSessions = await SessionManager.listAll(storage, managedAgentDir);
|
|
7312
|
-
const globalMatch = globalSessions
|
|
7415
|
+
const globalMatch = pickResumableSession(globalSessions, sessionArg);
|
|
7313
7416
|
if (!globalMatch) {
|
|
7314
7417
|
return undefined;
|
|
7315
7418
|
}
|
|
@@ -7576,14 +7679,14 @@ type ManagedDestinationTransition = {
|
|
|
7576
7679
|
/**
|
|
7577
7680
|
* Freshness snapshot captured with every async whole-session persistence
|
|
7578
7681
|
* preparation. Immediately before the synchronous persistence transaction, the
|
|
7579
|
-
* live values are compared: a
|
|
7580
|
-
*
|
|
7682
|
+
* live values are compared: a logical lifecycle change aborts; a verified storage
|
|
7683
|
+
* relocation or revision change discards prepared bytes and re-prepares (bounded),
|
|
7581
7684
|
* so a stale snapshot is never published.
|
|
7582
7685
|
*/
|
|
7583
7686
|
export interface PersistenceInputToken {
|
|
7584
7687
|
/** Canonical session file path the prepared bytes target. */
|
|
7585
7688
|
sessionFile: string;
|
|
7586
|
-
/**
|
|
7689
|
+
/** Logical lifecycle identity; storage-only relocation preserves its verified origin. */
|
|
7587
7690
|
lifecycleId: string;
|
|
7588
7691
|
/** Revision of #fileEntries affecting persisted bytes. */
|
|
7589
7692
|
entryRevision: number;
|
|
@@ -7800,6 +7903,10 @@ export class SessionManager {
|
|
|
7800
7903
|
#artifactManager: ArtifactManager | null = null;
|
|
7801
7904
|
#artifactManagerSessionFile: string | null = null;
|
|
7802
7905
|
#managedTranscriptStoreCache: { directory: string; store: ManagedSessionDescendantStore } | null = null;
|
|
7906
|
+
#managedTranscriptRelocationResolver: (() => ArtifactManager) | undefined;
|
|
7907
|
+
#managedTranscriptRelocationResolverToken: symbol | undefined;
|
|
7908
|
+
#managedTranscriptRelocationFileOrigin: string | undefined;
|
|
7909
|
+
#managedTranscriptRelocationParentArtifacts: ArtifactManager | undefined;
|
|
7803
7910
|
#ownedManagedAuthority: ManagedSessionDescendantStore | undefined;
|
|
7804
7911
|
#managedSidecarCacheStore: EphemeralBlobStore | undefined;
|
|
7805
7912
|
readonly #managedSidecarCleanupStores = new Set<EphemeralBlobStore>();
|
|
@@ -8066,9 +8173,13 @@ export class SessionManager {
|
|
|
8066
8173
|
this.#residentCacheWin32FallbackCount++;
|
|
8067
8174
|
return { store: this.#newCanonicalResidentTextStore(), ownsStore: false };
|
|
8068
8175
|
}
|
|
8069
|
-
const
|
|
8070
|
-
|
|
8071
|
-
)
|
|
8176
|
+
const cacheRoot = getResidentCacheRootDir(this.#residentCacheProfileAgentDir());
|
|
8177
|
+
// Not a provisioning failure: retain-and-throw must still commit, with no file to stage.
|
|
8178
|
+
if (!residentTextCacheRootAllowsDisk(cacheRoot)) {
|
|
8179
|
+
this.#residentCacheAdoptFallbackCount++;
|
|
8180
|
+
return { store: this.#newCanonicalResidentTextStore(), ownsStore: false };
|
|
8181
|
+
}
|
|
8182
|
+
const instanceDir = openVerifiedResidentCacheInstanceDir(cacheRoot);
|
|
8072
8183
|
return { store: EphemeralBlobStore.adoptVerifiedDir(instanceDir), ownsStore: true };
|
|
8073
8184
|
}
|
|
8074
8185
|
|
|
@@ -10289,6 +10400,7 @@ export class SessionManager {
|
|
|
10289
10400
|
}
|
|
10290
10401
|
this.#artifactManager = null;
|
|
10291
10402
|
this.#artifactManagerSessionFile = null;
|
|
10403
|
+
this.#clearManagedTranscriptRelocationResolver();
|
|
10292
10404
|
this.#artifactLifecycle = Symbol("session-artifact-adoption");
|
|
10293
10405
|
installedGeneration = this.#artifactLifecycle;
|
|
10294
10406
|
installedSessionId = this.#sessionId;
|
|
@@ -10402,6 +10514,7 @@ export class SessionManager {
|
|
|
10402
10514
|
throw error;
|
|
10403
10515
|
}
|
|
10404
10516
|
managedTransition?.adopt();
|
|
10517
|
+
this.#clearManagedTranscriptRelocationResolver();
|
|
10405
10518
|
this.#sessionFile = resolvedSessionFile;
|
|
10406
10519
|
this.#sessionId = sessionId;
|
|
10407
10520
|
this.#sessionName = header?.title;
|
|
@@ -10489,6 +10602,7 @@ export class SessionManager {
|
|
|
10489
10602
|
prepared.dispose();
|
|
10490
10603
|
throw error;
|
|
10491
10604
|
}
|
|
10605
|
+
this.#clearManagedTranscriptRelocationResolver();
|
|
10492
10606
|
managedTransition?.settle();
|
|
10493
10607
|
this.#pendingStrictAdoption = undefined;
|
|
10494
10608
|
await this.#rewriteFile();
|
|
@@ -10958,6 +11072,7 @@ export class SessionManager {
|
|
|
10958
11072
|
this.#adoptedArtifactManager = null;
|
|
10959
11073
|
this.#managedPersistExpectedIdentity = expectedIdentity;
|
|
10960
11074
|
this.#commitResidentTextStoreTransition(transition);
|
|
11075
|
+
this.#clearManagedTranscriptRelocationResolver();
|
|
10961
11076
|
this.#retireEphemeralArtifacts();
|
|
10962
11077
|
stage.committed = true;
|
|
10963
11078
|
this.#preparedNewSessions.delete(stage);
|
|
@@ -12196,6 +12311,9 @@ export class SessionManager {
|
|
|
12196
12311
|
path.basename(oldArtifactDir),
|
|
12197
12312
|
managedPublishedArtifacts,
|
|
12198
12313
|
);
|
|
12314
|
+
// The restored namespace has a new directory identity, even at the same path.
|
|
12315
|
+
this.#artifactManager = null;
|
|
12316
|
+
this.#artifactManagerSessionFile = null;
|
|
12199
12317
|
}
|
|
12200
12318
|
if (managedTranscript && !managedSourceStore.readExpected(path.basename(oldSessionFile)))
|
|
12201
12319
|
await managedSourceStore.publishNoReplace(path.basename(oldSessionFile), managedTranscript.bytes);
|
|
@@ -12303,6 +12421,8 @@ export class SessionManager {
|
|
|
12303
12421
|
path.basename(oldArtifactDir),
|
|
12304
12422
|
managedPublishedArtifacts,
|
|
12305
12423
|
);
|
|
12424
|
+
this.#artifactManager = null;
|
|
12425
|
+
this.#artifactManagerSessionFile = null;
|
|
12306
12426
|
const restored = managedSourceStore.captureTree(path.basename(oldArtifactDir));
|
|
12307
12427
|
if (!retainedTreeSnapshotEqualsAfterRename(restored, managedArtifacts))
|
|
12308
12428
|
throw new Error("managed_move_source_restore_mismatch");
|
|
@@ -12653,7 +12773,7 @@ export class SessionManager {
|
|
|
12653
12773
|
#capturePersistenceInputToken(): PersistenceInputToken {
|
|
12654
12774
|
return {
|
|
12655
12775
|
sessionFile: this.#sessionFile ?? "",
|
|
12656
|
-
lifecycleId: `${this.#sessionId}@${this.#sessionFile ?? ""}`,
|
|
12776
|
+
lifecycleId: `${this.#sessionId}@${this.#managedTranscriptRelocationFileOrigin ?? this.#sessionFile ?? ""}`,
|
|
12657
12777
|
entryRevision: this.#entryRevision,
|
|
12658
12778
|
headerRevision: this.#headerExportRevision,
|
|
12659
12779
|
residentBlobRevision: this.#residentBlobRevision,
|
|
@@ -12667,9 +12787,10 @@ export class SessionManager {
|
|
|
12667
12787
|
*/
|
|
12668
12788
|
#persistenceInputTokenMatches(token: PersistenceInputToken): boolean {
|
|
12669
12789
|
const live = this.#capturePersistenceInputToken();
|
|
12670
|
-
if (live.
|
|
12790
|
+
if (live.lifecycleId !== token.lifecycleId) {
|
|
12671
12791
|
throw new Error("session_persistence_lifecycle_changed");
|
|
12672
12792
|
}
|
|
12793
|
+
if (live.sessionFile !== token.sessionFile) return false;
|
|
12673
12794
|
return (
|
|
12674
12795
|
live.entryRevision === token.entryRevision &&
|
|
12675
12796
|
live.headerRevision === token.headerRevision &&
|
|
@@ -12935,10 +13056,162 @@ export class SessionManager {
|
|
|
12935
13056
|
this.#ownedManagedAuthority = undefined;
|
|
12936
13057
|
}
|
|
12937
13058
|
|
|
13059
|
+
/**
|
|
13060
|
+
* Register the same-owner task capability used to follow a parent's managed
|
|
13061
|
+
* artifact root after its session move. The synchronous resolver must return
|
|
13062
|
+
* only the current ArtifactManager for the same parent ID and parent transcript
|
|
13063
|
+
* basename; it retains the last verified manager on a logical successor.
|
|
13064
|
+
* Registration captures the exact original manager identity. Unchanged identity
|
|
13065
|
+
* keeps using the child's retained store; a changed identity triggers strict
|
|
13066
|
+
* destination transcript verification before re-rooting.
|
|
13067
|
+
*/
|
|
13068
|
+
registerManagedTranscriptRelocationResolver(resolver: () => ArtifactManager): () => void {
|
|
13069
|
+
if (this.destination.kind !== "managed")
|
|
13070
|
+
throw new Error("Managed transcript relocation requires a managed session");
|
|
13071
|
+
if (this.#managedTranscriptRelocationResolver)
|
|
13072
|
+
throw new Error("Managed transcript relocation resolver is already registered");
|
|
13073
|
+
const originalParentArtifacts = resolver();
|
|
13074
|
+
const registrationToken = Symbol("managed-transcript-relocation");
|
|
13075
|
+
this.#managedTranscriptRelocationResolver = resolver;
|
|
13076
|
+
this.#managedTranscriptRelocationResolverToken = registrationToken;
|
|
13077
|
+
this.#managedTranscriptRelocationParentArtifacts = originalParentArtifacts;
|
|
13078
|
+
return () => {
|
|
13079
|
+
if (this.#managedTranscriptRelocationResolverToken === registrationToken)
|
|
13080
|
+
this.#clearManagedTranscriptRelocationResolver();
|
|
13081
|
+
};
|
|
13082
|
+
}
|
|
13083
|
+
|
|
13084
|
+
#clearManagedTranscriptRelocationResolver(): void {
|
|
13085
|
+
this.#managedTranscriptRelocationResolver = undefined;
|
|
13086
|
+
this.#managedTranscriptRelocationResolverToken = undefined;
|
|
13087
|
+
this.#managedTranscriptRelocationFileOrigin = undefined;
|
|
13088
|
+
this.#managedTranscriptRelocationParentArtifacts = undefined;
|
|
13089
|
+
}
|
|
13090
|
+
|
|
13091
|
+
#refreshManagedTranscriptRelocation(sessionFile = this.#sessionFile): void {
|
|
13092
|
+
const currentSessionFile = this.#sessionFile;
|
|
13093
|
+
const resolver = this.#managedTranscriptRelocationResolver;
|
|
13094
|
+
if (this.destination.kind !== "managed" || !currentSessionFile || sessionFile !== currentSessionFile || !resolver)
|
|
13095
|
+
return;
|
|
13096
|
+
|
|
13097
|
+
const parentArtifacts = resolver();
|
|
13098
|
+
const nextDirectory = path.resolve(parentArtifacts.dir);
|
|
13099
|
+
const parentArtifactsChanged = this.#managedTranscriptRelocationParentArtifacts !== parentArtifacts;
|
|
13100
|
+
if (nextDirectory === path.resolve(this.destination.directory) && !parentArtifactsChanged) return;
|
|
13101
|
+
parentArtifacts.assertManagedBinding();
|
|
13102
|
+
const parentStore = parentArtifacts.getManagedStore();
|
|
13103
|
+
if (!parentStore || path.resolve(parentStore.dir) !== nextDirectory)
|
|
13104
|
+
throw new Error("managed_transcript_relocation_parent_authority_unavailable");
|
|
13105
|
+
parentStore.assertBound();
|
|
13106
|
+
if (path.resolve(path.dirname(currentSessionFile)) !== path.resolve(this.destination.directory))
|
|
13107
|
+
throw new Error("managed_transcript_relocation_source_path_unverified");
|
|
13108
|
+
const transcriptName = path.basename(currentSessionFile);
|
|
13109
|
+
const nextSessionFile = path.join(nextDirectory, transcriptName);
|
|
13110
|
+
if (path.basename(nextSessionFile) !== transcriptName)
|
|
13111
|
+
throw new Error("managed_transcript_relocation_transcript_name_mismatch");
|
|
13112
|
+
|
|
13113
|
+
if (this.#stagedPublication) throw new Error("managed_transcript_relocation_staged_publication_unavailable");
|
|
13114
|
+
if (this.#persistWriter || this.#persistWriterPath)
|
|
13115
|
+
throw new Error("managed_transcript_relocation_writer_unavailable");
|
|
13116
|
+
if (this.#boundedManagedSource) throw new Error("managed_transcript_relocation_bounded_source_unavailable");
|
|
13117
|
+
if (this.#coldSidecarActive() || (this.#sidecarRuntime?.coldEntries.size ?? 0) > 0)
|
|
13118
|
+
throw new Error("managed_transcript_relocation_cold_sidecar_unavailable");
|
|
13119
|
+
if (this.#recoveryHydrationContext || this.#recoveryPromotionTranscriptPath || this.#pendingStrictAdoption)
|
|
13120
|
+
throw new Error("managed_transcript_relocation_recovery_state_unavailable");
|
|
13121
|
+
|
|
13122
|
+
const expectedIdentity = this.#managedPersistExpectedIdentity;
|
|
13123
|
+
if (
|
|
13124
|
+
!expectedIdentity ||
|
|
13125
|
+
!Number.isSafeInteger(expectedIdentity.size) ||
|
|
13126
|
+
expectedIdentity.size < 0 ||
|
|
13127
|
+
typeof expectedIdentity.sha256 !== "string" ||
|
|
13128
|
+
!/^[0-9a-f]{64}$/.test(expectedIdentity.sha256)
|
|
13129
|
+
)
|
|
13130
|
+
throw new Error("managed_transcript_relocation_original_identity_unavailable");
|
|
13131
|
+
|
|
13132
|
+
let nextDestination: SessionDestination | undefined;
|
|
13133
|
+
let nextStore: ManagedSessionDescendantStore | undefined;
|
|
13134
|
+
let adopted = false;
|
|
13135
|
+
try {
|
|
13136
|
+
nextDestination = SessionManager.nestedManagedDestination(parentStore, nextDirectory);
|
|
13137
|
+
if (nextDestination.kind !== "managed")
|
|
13138
|
+
throw new Error("managed_transcript_relocation_destination_unavailable");
|
|
13139
|
+
nextStore = managedStoreFromContext(nextDestination.securityContext, nextDirectory);
|
|
13140
|
+
nextStore.verifyRootSecurity();
|
|
13141
|
+
nextStore.assertBound();
|
|
13142
|
+
const destinationTranscript = nextStore.readExpected(transcriptName);
|
|
13143
|
+
if (!destinationTranscript) throw new Error("managed_transcript_relocation_destination_missing");
|
|
13144
|
+
const destinationSha256 = crypto.createHash("sha256").update(destinationTranscript.bytes).digest("hex");
|
|
13145
|
+
if (
|
|
13146
|
+
destinationTranscript.identity.size !== expectedIdentity.size ||
|
|
13147
|
+
destinationTranscript.bytes.byteLength !== expectedIdentity.size ||
|
|
13148
|
+
destinationTranscript.identity.sha256 !== expectedIdentity.sha256 ||
|
|
13149
|
+
destinationSha256 !== expectedIdentity.sha256
|
|
13150
|
+
)
|
|
13151
|
+
throw new Error("managed_transcript_relocation_destination_identity_mismatch");
|
|
13152
|
+
|
|
13153
|
+
parentArtifacts.assertManagedBinding();
|
|
13154
|
+
parentStore.assertBound();
|
|
13155
|
+
nextStore.assertBound();
|
|
13156
|
+
|
|
13157
|
+
const previousDestination = this.destination;
|
|
13158
|
+
const previousCache = this.#managedTranscriptStoreCache;
|
|
13159
|
+
const previousOwnedAuthority = this.#ownedManagedAuthority;
|
|
13160
|
+
const previousArtifactStore = this.#artifactManager?.getManagedStore();
|
|
13161
|
+
// A hot/shadow sidecar remains a disposable cache over the same verified
|
|
13162
|
+
// transcript bytes. Keep its resident state and cache root; only retag the
|
|
13163
|
+
// cache key. Cold and bounded source state was rejected above because it
|
|
13164
|
+
// pins descriptor/path state that cannot be retargeted without rebuilding.
|
|
13165
|
+
if (this.#managedSidecarCacheStore) this.#managedSidecarCacheSessionFile = nextSessionFile;
|
|
13166
|
+
this.#boundedReadStorageProxy = undefined;
|
|
13167
|
+
this.#managedTranscriptRelocationFileOrigin ??= currentSessionFile;
|
|
13168
|
+
this.destination = nextDestination;
|
|
13169
|
+
this.sessionDir = nextDirectory;
|
|
13170
|
+
this.#sessionFile = nextSessionFile;
|
|
13171
|
+
this.#managedTranscriptStoreCache = { directory: nextDirectory, store: nextStore };
|
|
13172
|
+
this.#managedPersistExpectedIdentity = { ...destinationTranscript.identity };
|
|
13173
|
+
this.#managedRangeExpectedDescriptor = {
|
|
13174
|
+
dev: destinationTranscript.identity.dev,
|
|
13175
|
+
ino: destinationTranscript.identity.ino,
|
|
13176
|
+
nlink: destinationTranscript.identity.nlink,
|
|
13177
|
+
size: destinationTranscript.identity.size,
|
|
13178
|
+
mtimeNs: destinationTranscript.identity.mtimeNs,
|
|
13179
|
+
ctimeNs: destinationTranscript.identity.ctimeNs,
|
|
13180
|
+
};
|
|
13181
|
+
this.#adoptedArtifactManager = parentArtifacts;
|
|
13182
|
+
this.#managedTranscriptRelocationParentArtifacts = parentArtifacts;
|
|
13183
|
+
this.#artifactManager = null;
|
|
13184
|
+
this.#artifactManagerSessionFile = null;
|
|
13185
|
+
this.#ownedManagedAuthority = undefined;
|
|
13186
|
+
adopted = true;
|
|
13187
|
+
|
|
13188
|
+
// These stores were created by this manager. Their close methods release
|
|
13189
|
+
// only authorities they actually own; the borrowed parent manager remains
|
|
13190
|
+
// untouched.
|
|
13191
|
+
previousCache?.store.close();
|
|
13192
|
+
if (previousOwnedAuthority && previousOwnedAuthority !== previousCache?.store) previousOwnedAuthority.close();
|
|
13193
|
+
if (previousArtifactStore && previousArtifactStore !== parentStore && previousArtifactStore !== nextStore)
|
|
13194
|
+
previousArtifactStore.close();
|
|
13195
|
+
if (previousDestination.kind === "managed") previousDestination.securityContext.retainedAuthority?.close();
|
|
13196
|
+
} catch (error) {
|
|
13197
|
+
if (!adopted) {
|
|
13198
|
+
nextStore?.close();
|
|
13199
|
+
if (nextDestination?.kind === "managed") nextDestination.securityContext.retainedAuthority?.close();
|
|
13200
|
+
}
|
|
13201
|
+
throw error;
|
|
13202
|
+
}
|
|
13203
|
+
}
|
|
13204
|
+
|
|
12938
13205
|
#managedTranscriptStore(sessionFile = this.#sessionFile): ManagedSessionDescendantStore {
|
|
12939
13206
|
if (this.destination.kind !== "managed" || !sessionFile) {
|
|
12940
13207
|
throw new Error("Managed transcript authority is unavailable");
|
|
12941
13208
|
}
|
|
13209
|
+
const previousSessionFile = this.#sessionFile;
|
|
13210
|
+
if (sessionFile === previousSessionFile) {
|
|
13211
|
+
this.#refreshManagedTranscriptRelocation(sessionFile);
|
|
13212
|
+
if (this.#sessionFile !== previousSessionFile) sessionFile = this.#sessionFile;
|
|
13213
|
+
}
|
|
13214
|
+
if (!sessionFile) throw new Error("Managed transcript authority is unavailable");
|
|
12942
13215
|
const sessionDir = path.resolve(path.dirname(sessionFile));
|
|
12943
13216
|
if (sessionDir !== path.resolve(this.destination.directory)) {
|
|
12944
13217
|
throw new Error("Managed transcript escaped its session directory");
|
|
@@ -16592,6 +16865,7 @@ export class SessionManager {
|
|
|
16592
16865
|
// aborts. A stale snapshot is never published.
|
|
16593
16866
|
let written = false;
|
|
16594
16867
|
for (let attempt = 0; attempt <= 2 && !written; attempt++) {
|
|
16868
|
+
this.#refreshManagedTranscriptRelocation();
|
|
16595
16869
|
this.#ensureFullHotView();
|
|
16596
16870
|
const token = this.#capturePersistenceInputToken();
|
|
16597
16871
|
await this.#closePersistWriterInternal();
|
|
@@ -16601,6 +16875,7 @@ export class SessionManager {
|
|
|
16601
16875
|
),
|
|
16602
16876
|
);
|
|
16603
16877
|
written = this.#withSessionPersistenceFenceSync(() => {
|
|
16878
|
+
this.#refreshManagedTranscriptRelocation();
|
|
16604
16879
|
if (!this.#persistenceInputTokenMatches(token)) return false;
|
|
16605
16880
|
this.#writeEntriesAtomicallySync(entries);
|
|
16606
16881
|
return true;
|
|
@@ -16624,6 +16899,7 @@ export class SessionManager {
|
|
|
16624
16899
|
|
|
16625
16900
|
#rewriteFileSync(): void {
|
|
16626
16901
|
if (!this.persist || !this.#sessionFile) return;
|
|
16902
|
+
this.#refreshManagedTranscriptRelocation();
|
|
16627
16903
|
this.#withSessionPersistenceFenceSync(() => {
|
|
16628
16904
|
this.#ensureFullHotView();
|
|
16629
16905
|
// Sync lane: capture and check the token immediately (always fresh absent
|
|
@@ -16958,6 +17234,7 @@ export class SessionManager {
|
|
|
16958
17234
|
}
|
|
16959
17235
|
|
|
16960
17236
|
#releaseClosedSessionState(): void {
|
|
17237
|
+
this.#clearManagedTranscriptRelocationResolver();
|
|
16961
17238
|
const runtime = this.#sidecarRuntime;
|
|
16962
17239
|
if (runtime) {
|
|
16963
17240
|
runtime.enabled = false;
|
|
@@ -18552,6 +18829,7 @@ export class SessionManager {
|
|
|
18552
18829
|
}
|
|
18553
18830
|
|
|
18554
18831
|
#appendManagedRecordsSync(records: readonly (FileEntry | SessionPatchRecord)[]): void {
|
|
18832
|
+
this.#refreshManagedTranscriptRelocation();
|
|
18555
18833
|
if (!this.#sessionFile) throw new Error("Managed transcript path is unavailable");
|
|
18556
18834
|
this.#withSessionPersistenceFenceSync(() => {
|
|
18557
18835
|
const sessionFile = this.#sessionFile!;
|
|
@@ -18580,12 +18858,23 @@ export class SessionManager {
|
|
|
18580
18858
|
|
|
18581
18859
|
async #persistPatches(records: readonly SessionPatchRecord[]): Promise<void> {
|
|
18582
18860
|
if (records.length === 0) return;
|
|
18583
|
-
|
|
18584
|
-
|
|
18585
|
-
|
|
18861
|
+
try {
|
|
18862
|
+
this.#refreshManagedTranscriptRelocation();
|
|
18863
|
+
} catch (error) {
|
|
18864
|
+
this.#recordPersistError(error);
|
|
18865
|
+
throw this.#persistError ?? toError(error);
|
|
18866
|
+
}
|
|
18867
|
+
if (!this.persist || !this.#sessionFile || !this.#storage.existsSync(this.#sessionFile)) {
|
|
18868
|
+
if (this.#coldSidecarActive()) this.#deactivateColdForBranchMutation();
|
|
18869
|
+
return;
|
|
18870
|
+
}
|
|
18871
|
+
let sessionFile = this.#sessionFile;
|
|
18586
18872
|
const publishResumeBreadcrumb = this.#readOnlyResume;
|
|
18587
18873
|
await this.#queuePersistTask(async () => {
|
|
18588
18874
|
for (let attempt = 0; attempt <= 2; attempt++) {
|
|
18875
|
+
this.#refreshManagedTranscriptRelocation();
|
|
18876
|
+
if (this.#coldSidecarActive()) this.#deactivateColdForBranchMutation();
|
|
18877
|
+
sessionFile = this.#sessionFile!;
|
|
18589
18878
|
const token = this.#capturePersistenceInputToken();
|
|
18590
18879
|
const header = this.#fileEntries.find(entry => entry.type === "session") as SessionHeader | undefined;
|
|
18591
18880
|
if (
|
|
@@ -18594,6 +18883,7 @@ export class SessionManager {
|
|
|
18594
18883
|
(header?.version ?? 1) < CURRENT_SESSION_VERSION
|
|
18595
18884
|
) {
|
|
18596
18885
|
await this.#rewriteFileContents();
|
|
18886
|
+
sessionFile = this.#sessionFile!;
|
|
18597
18887
|
if (publishResumeBreadcrumb) writeTerminalBreadcrumb(this.cwd, sessionFile);
|
|
18598
18888
|
this.#readOnlyResume = false;
|
|
18599
18889
|
return;
|
|
@@ -18613,6 +18903,7 @@ export class SessionManager {
|
|
|
18613
18903
|
SessionManagerTestHooks.beforePersistPatchFence?.(attempt);
|
|
18614
18904
|
let persisted = false;
|
|
18615
18905
|
const written = this.#withSessionPersistenceFenceSync(() => {
|
|
18906
|
+
this.#refreshManagedTranscriptRelocation();
|
|
18616
18907
|
if (!this.#persistenceInputTokenMatches(token)) return false;
|
|
18617
18908
|
if (this.destination.kind === "managed") {
|
|
18618
18909
|
this.#appendManagedRecordsSync(persistedRecords);
|
|
@@ -18645,8 +18936,14 @@ export class SessionManager {
|
|
|
18645
18936
|
_persist(entry: SessionEntry): void {
|
|
18646
18937
|
if (!this.persist || !this.#sessionFile) return;
|
|
18647
18938
|
if (this.#strictClosePending) throw new Error("Session manager is closing.");
|
|
18648
|
-
const publishResumeBreadcrumb = this.#readOnlyResume;
|
|
18649
18939
|
if (this.#persistError) throw this.#persistError;
|
|
18940
|
+
try {
|
|
18941
|
+
this.#refreshManagedTranscriptRelocation();
|
|
18942
|
+
} catch (error) {
|
|
18943
|
+
this.#recordPersistError(error);
|
|
18944
|
+
throw this.#persistError ?? toError(error);
|
|
18945
|
+
}
|
|
18946
|
+
const publishResumeBreadcrumb = this.#readOnlyResume;
|
|
18650
18947
|
|
|
18651
18948
|
// Normally we wait for the first assistant message before persisting to avoid
|
|
18652
18949
|
// creating files for sessions that never produce output. Once ensureOnDisk() has
|
|
@@ -20553,6 +20850,7 @@ export class SessionManager {
|
|
|
20553
20850
|
}
|
|
20554
20851
|
this.#sessionId = newSessionId;
|
|
20555
20852
|
this.#sessionFile = newSessionFile;
|
|
20853
|
+
this.#clearManagedTranscriptRelocationResolver();
|
|
20556
20854
|
this.#flushed = true;
|
|
20557
20855
|
this.#commitResidentTextStoreTransition(transition);
|
|
20558
20856
|
this.#adoptManagedPersistIdentity(newSessionFile);
|
|
@@ -20587,6 +20885,7 @@ export class SessionManager {
|
|
|
20587
20885
|
"retain-and-throw",
|
|
20588
20886
|
);
|
|
20589
20887
|
this.#sessionId = newSessionId;
|
|
20888
|
+
this.#clearManagedTranscriptRelocationResolver();
|
|
20590
20889
|
this.#commitResidentTextStoreTransition(transition);
|
|
20591
20890
|
return undefined;
|
|
20592
20891
|
}
|
|
@@ -23045,7 +23344,15 @@ export class SessionManager {
|
|
|
23045
23344
|
storage,
|
|
23046
23345
|
);
|
|
23047
23346
|
|
|
23048
|
-
const terminalSession = await readTerminalBreadcrumb(cwd
|
|
23347
|
+
const terminalSession = await readTerminalBreadcrumb(cwd, {
|
|
23348
|
+
...(destination.kind === "managed"
|
|
23349
|
+
? {
|
|
23350
|
+
sessionsRoot: destination.securityContext.sessionsRoot,
|
|
23351
|
+
continuationInventory: managedCandidates,
|
|
23352
|
+
}
|
|
23353
|
+
: {}),
|
|
23354
|
+
allowExplicitOutsideRoot: destination.kind === "explicit",
|
|
23355
|
+
});
|
|
23049
23356
|
const terminalSessionIsInExplicitRoot = (() => {
|
|
23050
23357
|
if (destination.kind === "managed" || !terminalSession) return destination.kind === "managed";
|
|
23051
23358
|
const canonicalRoot = canonicalizeTrustedPath(destination.directory);
|