@gajae-code/coding-agent 0.10.1 → 0.11.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 +70 -2
- package/dist/types/append-only-mode.d.ts +1 -1
- package/dist/types/cli/args.d.ts +4 -5
- package/dist/types/cli/daemon-cli.d.ts +12 -1
- package/dist/types/cli/notify-cli.d.ts +21 -1
- package/dist/types/cli.d.ts +3 -0
- package/dist/types/commands/daemon.d.ts +39 -0
- package/dist/types/commands/launch.d.ts +3 -0
- package/dist/types/commands/notify.d.ts +28 -1
- package/dist/types/commands/sdk.d.ts +33 -0
- package/dist/types/config/atomic-yaml-patch.d.ts +85 -0
- package/dist/types/config/model-profile-activation.d.ts +35 -15
- package/dist/types/config/model-profiles.d.ts +11 -5
- package/dist/types/config/model-registry.d.ts +3 -3
- package/dist/types/config/model-resolver.d.ts +39 -6
- package/dist/types/config/model-selector-value.d.ts +17 -0
- package/dist/types/config/models-config-schema.d.ts +10 -6
- package/dist/types/config/settings-schema.d.ts +133 -6
- package/dist/types/config/settings.d.ts +63 -35
- package/dist/types/coordinator-mcp/model-preset.d.ts +7 -6
- package/dist/types/coordinator-mcp/server.d.ts +6 -49
- package/dist/types/daemon/builtin.d.ts +6 -5
- package/dist/types/daemon/control-types.d.ts +1 -1
- package/dist/types/discovery/mcp-json.d.ts +12 -1
- package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
- package/dist/types/extensibility/extensions/compact-handler.d.ts +4 -2
- package/dist/types/extensibility/extensions/get-commands-handler.d.ts +2 -2
- package/dist/types/extensibility/extensions/loader.d.ts +10 -1
- package/dist/types/extensibility/extensions/runner.d.ts +3 -3
- package/dist/types/extensibility/extensions/types.d.ts +141 -16
- package/dist/types/extensibility/hooks/types.d.ts +1 -1
- package/dist/types/gjc-runtime/launch-tmux.d.ts +3 -2
- package/dist/types/gjc-runtime/psmux-detect.d.ts +3 -0
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +3 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +3 -4
- package/dist/types/gjc-runtime/tmux-owner-isolation-cli.d.ts +13 -0
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +4 -1
- package/dist/types/gjc-runtime/windows-powershell-command.d.ts +9 -0
- package/dist/types/harness-control-plane/operate.d.ts +5 -5
- package/dist/types/harness-control-plane/owner.d.ts +18 -4
- package/dist/types/harness-control-plane/receipts.d.ts +0 -1
- package/dist/types/harness-control-plane/sdk-transport.d.ts +43 -0
- package/dist/types/harness-control-plane/session-transport.d.ts +48 -0
- package/dist/types/harness-control-plane/types.d.ts +3 -4
- package/dist/types/lsp/index.d.ts +1 -1
- package/dist/types/main.d.ts +32 -38
- package/dist/types/modes/acp/acp-agent.d.ts +224 -53
- package/dist/types/modes/acp/acp-client-bridge.d.ts +1 -0
- package/dist/types/modes/acp/acp-mode.d.ts +6 -15
- package/dist/types/modes/acp/permission-mode.d.ts +4 -0
- package/dist/types/modes/acp/startup-options.d.ts +6 -0
- package/dist/types/modes/components/agent-dashboard.d.ts +3 -0
- package/dist/types/modes/components/gajae-pet-widget.d.ts +1 -0
- package/dist/types/modes/components/model-selector.d.ts +1 -0
- package/dist/types/modes/components/notifications-settings-editor.d.ts +135 -0
- package/dist/types/modes/components/pet-capability.d.ts +37 -0
- package/dist/types/modes/components/pet-selector.d.ts +1 -1
- package/dist/types/modes/components/settings-selector.d.ts +15 -4
- package/dist/types/modes/components/welcome.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +35 -1
- package/dist/types/modes/index.d.ts +0 -4
- package/dist/types/modes/interactive-mode.d.ts +5 -1
- package/dist/types/modes/runtime-init.d.ts +2 -2
- package/dist/types/modes/shared/agent-wire/approval-gate.d.ts +6 -9
- package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -6
- package/dist/types/modes/shared/agent-wire/event-contract.d.ts +6 -6
- package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +4 -9
- package/dist/types/modes/shared/agent-wire/event-observation.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +169 -30
- package/dist/types/modes/shared/agent-wire/workflow-gate-schema.d.ts +7 -7
- package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +105 -0
- package/dist/types/modes/types.d.ts +16 -1
- package/dist/types/runtime-mcp/client.d.ts +2 -0
- package/dist/types/runtime-mcp/config.d.ts +5 -1
- package/dist/types/runtime-mcp/manager.d.ts +8 -1
- package/dist/types/runtime-mcp/types.d.ts +4 -0
- package/dist/types/sdk/acp/adapter.d.ts +67 -0
- package/dist/types/sdk/acp/index.d.ts +2 -0
- package/dist/types/sdk/broker/broker.d.ts +53 -0
- package/dist/types/sdk/broker/discovery.d.ts +30 -0
- package/dist/types/sdk/broker/ensure.d.ts +33 -0
- package/dist/types/sdk/broker/identity.d.ts +3 -0
- package/dist/types/sdk/broker/index.d.ts +8 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +95 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +85 -0
- package/dist/types/sdk/broker/process-incarnation.d.ts +14 -0
- package/dist/types/sdk/broker/runtime.d.ts +33 -0
- package/dist/types/sdk/broker/session-index.d.ts +57 -0
- package/dist/types/sdk/broker/state-version.d.ts +8 -0
- package/dist/types/sdk/broker/transport.d.ts +9 -0
- package/dist/types/sdk/bus/chat-command-policy.d.ts +49 -0
- package/dist/types/sdk/bus/chat-daemon-cli.d.ts +21 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +111 -0
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +77 -0
- package/dist/types/sdk/bus/chat-effect-journal.d.ts +84 -0
- package/dist/types/{notifications → sdk/bus}/config-commands.d.ts +7 -2
- package/dist/types/sdk/bus/config.d.ts +274 -0
- package/dist/types/sdk/bus/conversation-store.d.ts +72 -0
- package/dist/types/sdk/bus/discord-conversation.d.ts +58 -0
- package/dist/types/sdk/bus/discord-daemon.d.ts +45 -0
- package/dist/types/sdk/bus/discord-live-provider.d.ts +70 -0
- package/dist/types/sdk/bus/discord-provider.d.ts +85 -0
- package/dist/types/{notifications → sdk/bus}/html-format.d.ts +2 -2
- package/dist/types/{notifications → sdk/bus}/index.d.ts +113 -13
- package/dist/types/{notifications → sdk/bus}/lifecycle-control-runtime.d.ts +4 -2
- package/dist/types/{notifications → sdk/bus}/lifecycle-orchestrator.d.ts +18 -21
- package/dist/types/{notifications → sdk/bus}/managed-daemon.d.ts +1 -1
- package/dist/types/sdk/bus/native-runtime-compatibility.d.ts +13 -0
- package/dist/types/sdk/bus/notification-orchestration.d.ts +170 -0
- package/dist/types/{notifications → sdk/bus}/notification-service.d.ts +7 -1
- package/dist/types/sdk/bus/session-control.d.ts +83 -0
- package/dist/types/sdk/bus/slack-conversation.d.ts +56 -0
- package/dist/types/sdk/bus/slack-daemon.d.ts +60 -0
- package/dist/types/sdk/bus/slack-live-provider.d.ts +59 -0
- package/dist/types/sdk/bus/slack-provider.d.ts +55 -0
- package/dist/types/{notifications → sdk/bus}/telegram-cli.d.ts +4 -4
- package/dist/types/{notifications → sdk/bus}/telegram-daemon-cli.d.ts +14 -5
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -0
- package/dist/types/{notifications → sdk/bus}/telegram-daemon-control.d.ts +2 -2
- package/dist/types/{notifications → sdk/bus}/telegram-daemon.d.ts +55 -17
- package/dist/types/{notifications → sdk/bus}/telegram-reference.d.ts +2 -2
- package/dist/types/sdk/bus/telegram-setup.d.ts +128 -0
- package/dist/types/{notifications → sdk/bus}/topic-registry.d.ts +11 -0
- package/dist/types/sdk/cli/index.d.ts +1 -0
- package/dist/types/sdk/cli/session-cli.d.ts +19 -0
- package/dist/types/sdk/client/client.d.ts +1 -0
- package/dist/types/sdk/client/discovery.d.ts +27 -0
- package/dist/types/sdk/client/index.d.ts +2 -0
- package/dist/types/sdk/host/control/dispatch.d.ts +34 -0
- package/dist/types/sdk/host/control/index.d.ts +2 -0
- package/dist/types/sdk/host/control/operations.d.ts +65 -0
- package/dist/types/sdk/host/events.d.ts +35 -0
- package/dist/types/sdk/host/host.d.ts +35 -0
- package/dist/types/sdk/host/index.d.ts +4 -0
- package/dist/types/sdk/host/query/cursor.d.ts +62 -0
- package/dist/types/sdk/host/query/handlers.d.ts +70 -0
- package/dist/types/sdk/host/query/index.d.ts +3 -0
- package/dist/types/sdk/host/query/revision-store.d.ts +60 -0
- package/dist/types/sdk/host/reverse-leases.d.ts +45 -0
- package/dist/types/sdk/host/types.d.ts +32 -0
- package/dist/types/sdk/index.d.ts +6 -0
- package/dist/types/sdk/lifecycle-session.d.ts +14 -0
- package/dist/types/sdk/mcp/index.d.ts +1 -0
- package/dist/types/sdk/mcp/server.d.ts +37 -0
- package/dist/types/sdk/models.d.ts +44 -0
- package/dist/types/sdk/protocol/adapter-validation.d.ts +14 -0
- package/dist/types/sdk/protocol/operation-registry.d.ts +24 -0
- package/dist/types/{sdk.d.ts → sdk/session.d.ts} +44 -38
- package/dist/types/sdk/startup-capability.d.ts +50 -0
- package/dist/types/session/agent-session.d.ts +114 -21
- package/dist/types/session/default-model-selection.d.ts +25 -0
- package/dist/types/session/fallback-chain-controller.d.ts +52 -0
- package/dist/types/session/session-manager.d.ts +58 -1
- package/dist/types/setup/credential-auto-import.d.ts +36 -6
- package/dist/types/tools/ask-answer-registry.d.ts +1 -1
- package/dist/types/tools/browser/benchmark/detector-report.d.ts +63 -0
- package/dist/types/tools/browser/benchmark/run-suite.d.ts +18 -0
- package/dist/types/tools/browser/launch.d.ts +22 -0
- package/dist/types/tools/browser/profile-discovery.d.ts +31 -0
- package/dist/types/tools/browser/profile-posture.d.ts +37 -0
- package/dist/types/tools/browser/profile-reuse.d.ts +39 -0
- package/dist/types/tools/browser/profile-warmup.d.ts +39 -0
- package/dist/types/tools/browser/registry.d.ts +19 -0
- package/dist/types/tools/browser/tab-protocol.d.ts +4 -0
- package/dist/types/tools/index.d.ts +8 -8
- package/package.json +34 -13
- package/scripts/build-sdk-package-smoke.ts +94 -0
- package/scripts/capture-notifications-settings-showcase.ts +435 -0
- package/scripts/compile-args.ts +4 -2
- package/scripts/g005-daemon-smoke.ts +4 -5
- package/scripts/g011-daemon-path-smoke.ts +5 -5
- package/scripts/generate-sdk-adapter-parity-manifest.ts +163 -0
- package/scripts/generate-sdk-operation-inventory.ts +867 -0
- package/scripts/generate-telegram-baseline-manifest.ts +128 -0
- package/scripts/manifest-schema.ts +124 -0
- package/scripts/run-test-manifest.ts +153 -0
- package/scripts/run-threat-model-check.ts +157 -0
- package/scripts/verify-gjc-sdk-canonicalization.ts +3467 -0
- package/scripts/verify-gjc-sdk-rename.ts +90 -0
- package/src/append-only-mode.ts +1 -1
- package/src/cli/args.ts +43 -12
- package/src/cli/auth-gateway-cli.ts +2 -2
- package/src/cli/config-cli.ts +2 -1
- package/src/cli/daemon-cli.ts +63 -14
- package/src/cli/list-models.ts +1 -1
- package/src/cli/notify-cli.ts +288 -286
- package/src/cli.ts +21 -2
- package/src/commands/daemon.ts +50 -6
- package/src/commands/harness.ts +93 -36
- package/src/commands/launch.ts +5 -2
- package/src/commands/mcp-serve.ts +19 -12
- package/src/commands/notify.ts +36 -3
- package/src/commands/sdk.ts +426 -0
- package/src/commit/agentic/agent.ts +1 -0
- package/src/config/atomic-yaml-patch.ts +423 -0
- package/src/config/model-profile-activation.ts +240 -89
- package/src/config/model-profiles.ts +37 -34
- package/src/config/model-registry.ts +51 -26
- package/src/config/model-resolver.ts +138 -51
- package/src/config/model-selector-value.ts +50 -0
- package/src/config/models-config-schema.ts +14 -21
- package/src/config/settings-schema.ts +128 -10
- package/src/config/settings.ts +1120 -158
- package/src/coordinator-mcp/model-preset.ts +74 -20
- package/src/coordinator-mcp/server.ts +1597 -3052
- package/src/daemon/builtin.ts +8 -5
- package/src/daemon/control-types.ts +1 -1
- package/src/defaults/gjc/skills/team/SKILL.md +4 -4
- package/src/discovery/mcp-json.ts +327 -20
- package/src/extensibility/custom-tools/types.ts +1 -1
- package/src/extensibility/extensions/compact-handler.ts +3 -3
- package/src/extensibility/extensions/get-commands-handler.ts +2 -2
- package/src/extensibility/extensions/loader.ts +69 -5
- package/src/extensibility/extensions/runner.ts +112 -4
- package/src/extensibility/extensions/types.ts +176 -17
- package/src/extensibility/hooks/types.ts +1 -1
- package/src/extensibility/slash-commands.ts +3 -3
- package/src/gjc-runtime/launch-tmux.ts +170 -86
- package/src/gjc-runtime/psmux-detect.ts +82 -4
- package/src/gjc-runtime/session-state-sidecar.ts +41 -31
- package/src/gjc-runtime/team-runtime.ts +54 -35
- package/src/gjc-runtime/tmux-owner-isolation-cli.ts +53 -17
- package/src/gjc-runtime/tmux-owner-isolation.ts +5 -2
- package/src/gjc-runtime/tmux-sessions.ts +19 -13
- package/src/gjc-runtime/ultragoal-guard.ts +53 -6
- package/src/gjc-runtime/ultragoal-runtime.ts +155 -3
- package/src/gjc-runtime/windows-powershell-command.ts +58 -0
- package/src/harness-control-plane/operate.ts +9 -9
- package/src/harness-control-plane/owner.ts +283 -39
- package/src/harness-control-plane/receipts.ts +0 -1
- package/src/harness-control-plane/sdk-transport.ts +395 -0
- package/src/harness-control-plane/session-transport.ts +94 -0
- package/src/harness-control-plane/types.ts +1 -1
- package/src/internal-urls/docs-index.generated.ts +36 -37
- package/src/lsp/client.ts +42 -6
- package/src/lsp/index.ts +2 -2
- package/src/main.ts +299 -204
- package/src/modes/DESIGN.md +258 -0
- package/src/modes/acp/acp-agent.ts +1228 -2612
- package/src/modes/acp/acp-client-bridge.ts +2 -20
- package/src/modes/acp/acp-event-mapper.ts +18 -2
- package/src/modes/acp/acp-mode.ts +8 -36
- package/src/modes/acp/permission-mode.ts +25 -0
- package/src/modes/acp/startup-options.ts +6 -0
- package/src/modes/components/agent-dashboard.ts +37 -17
- package/src/modes/components/custom-editor.ts +1 -0
- package/src/modes/components/gajae-pet-widget.ts +169 -20
- package/src/modes/components/model-selector.ts +93 -35
- package/src/modes/components/notifications-settings-editor.ts +1379 -0
- package/src/modes/components/pet-capability.ts +115 -0
- package/src/modes/components/pet-selector.ts +4 -6
- package/src/modes/components/settings-selector.ts +86 -11
- package/src/modes/components/welcome.ts +4 -4
- package/src/modes/controllers/command-controller.ts +1 -2
- package/src/modes/controllers/event-controller.ts +11 -16
- package/src/modes/controllers/extension-ui-controller.ts +357 -12
- package/src/modes/controllers/input-controller.ts +43 -13
- package/src/modes/controllers/selector-controller.ts +671 -44
- package/src/modes/index.ts +0 -22
- package/src/modes/interactive-mode.ts +108 -24
- package/src/modes/runtime-init.ts +298 -6
- package/src/modes/shared/agent-wire/approval-gate.ts +9 -11
- package/src/modes/shared/agent-wire/deep-interview-gate.ts +10 -11
- package/src/modes/shared/agent-wire/event-contract.ts +7 -8
- package/src/modes/shared/agent-wire/event-envelope.ts +9 -17
- package/src/modes/shared/agent-wire/event-observation.ts +16 -7
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +1254 -87
- package/src/modes/shared/agent-wire/workflow-gate-schema.ts +15 -15
- package/src/modes/shared/agent-wire/workflow-gate-types.ts +113 -0
- package/src/modes/types.ts +16 -1
- package/src/runtime-mcp/client.ts +94 -19
- package/src/runtime-mcp/config.ts +27 -15
- package/src/runtime-mcp/manager.ts +343 -105
- package/src/runtime-mcp/oauth-flow.ts +42 -12
- package/src/runtime-mcp/transports/http.ts +49 -19
- package/src/runtime-mcp/transports/stdio.ts +47 -28
- package/src/runtime-mcp/types.ts +10 -0
- package/src/sdk/acp/adapter.ts +418 -0
- package/src/sdk/acp/index.ts +2 -0
- package/src/sdk/broker/broker.ts +642 -0
- package/src/sdk/broker/discovery.ts +94 -0
- package/src/sdk/broker/ensure.ts +249 -0
- package/src/sdk/broker/identity.ts +42 -0
- package/src/sdk/broker/index.ts +8 -0
- package/src/sdk/broker/internal-source-marker-2178.txt +1 -0
- package/src/sdk/broker/internal-source.bunfig.toml +1 -0
- package/src/sdk/broker/lifecycle-ledger.ts +286 -0
- package/src/sdk/broker/lifecycle.ts +2157 -0
- package/src/sdk/broker/process-incarnation.ts +159 -0
- package/src/sdk/broker/runtime.ts +164 -0
- package/src/sdk/broker/session-index.ts +318 -0
- package/src/sdk/broker/state-version.ts +23 -0
- package/src/sdk/broker/transport.ts +125 -0
- package/src/sdk/bus/chat-command-policy.ts +107 -0
- package/src/sdk/bus/chat-daemon-cli.ts +214 -0
- package/src/sdk/bus/chat-daemon-control.ts +713 -0
- package/src/sdk/bus/chat-daemon-runtime.ts +526 -0
- package/src/sdk/bus/chat-effect-journal.ts +353 -0
- package/src/{notifications → sdk/bus}/config-commands.ts +39 -10
- package/src/sdk/bus/config.ts +433 -0
- package/src/sdk/bus/conversation-store.ts +391 -0
- package/src/sdk/bus/discord-conversation.ts +85 -0
- package/src/sdk/bus/discord-daemon.ts +2275 -0
- package/src/sdk/bus/discord-live-provider.ts +521 -0
- package/src/sdk/bus/discord-provider.ts +56 -0
- package/src/{notifications → sdk/bus}/html-format.ts +2 -2
- package/src/sdk/bus/index.ts +3943 -0
- package/src/{notifications → sdk/bus}/lifecycle-commands.ts +2 -0
- package/src/{notifications → sdk/bus}/lifecycle-control-runtime.ts +225 -196
- package/src/{notifications → sdk/bus}/lifecycle-orchestrator.ts +161 -74
- package/src/{notifications → sdk/bus}/managed-daemon.ts +2 -2
- package/src/sdk/bus/native-runtime-compatibility.ts +42 -0
- package/src/sdk/bus/natives-augment.d.ts +38 -0
- package/src/sdk/bus/notification-orchestration.ts +535 -0
- package/src/{notifications → sdk/bus}/notification-service.ts +106 -12
- package/src/sdk/bus/session-control.ts +333 -0
- package/src/sdk/bus/slack-conversation.ts +74 -0
- package/src/sdk/bus/slack-daemon.ts +2144 -0
- package/src/sdk/bus/slack-live-provider.ts +380 -0
- package/src/sdk/bus/slack-provider.ts +76 -0
- package/src/{notifications → sdk/bus}/telegram-cli.ts +8 -8
- package/src/sdk/bus/telegram-daemon-cli.ts +330 -0
- package/src/sdk/bus/telegram-daemon-contract.ts +14 -0
- package/src/{notifications → sdk/bus}/telegram-daemon-control.ts +4 -4
- package/src/{notifications → sdk/bus}/telegram-daemon.ts +502 -54
- package/src/{notifications → sdk/bus}/telegram-reference.ts +2 -2
- package/src/sdk/bus/telegram-setup.ts +663 -0
- package/src/{notifications → sdk/bus}/topic-registry.ts +32 -0
- package/src/sdk/cli/index.ts +1 -0
- package/src/sdk/cli/session-cli.ts +275 -0
- package/src/sdk/client/client.ts +1 -0
- package/src/sdk/client/discovery.ts +108 -0
- package/src/sdk/client/index.ts +2 -0
- package/src/sdk/host/control/dispatch.ts +367 -0
- package/src/sdk/host/control/index.ts +10 -0
- package/src/sdk/host/control/operations.ts +63 -0
- package/src/sdk/host/events.ts +91 -0
- package/src/sdk/host/host.ts +296 -0
- package/src/sdk/host/index.ts +4 -0
- package/src/sdk/host/query/cursor.ts +189 -0
- package/src/sdk/host/query/handlers.ts +533 -0
- package/src/sdk/host/query/index.ts +3 -0
- package/src/sdk/host/query/revision-store.ts +1126 -0
- package/src/sdk/host/reverse-leases.ts +325 -0
- package/src/sdk/host/types.ts +29 -0
- package/src/sdk/index.ts +13 -0
- package/src/sdk/lifecycle-session.ts +39 -0
- package/src/sdk/mcp/index.ts +1 -0
- package/src/sdk/mcp/server.ts +332 -0
- package/src/sdk/models.ts +168 -0
- package/src/sdk/protocol/adapter-validation.ts +48 -0
- package/src/sdk/protocol/operation-inventory.generated.json +5654 -0
- package/src/sdk/protocol/operation-registry.ts +312 -0
- package/src/{sdk.ts → sdk/session.ts} +339 -212
- package/src/sdk/startup-capability.ts +189 -0
- package/src/session/agent-session.ts +2470 -866
- package/src/session/default-model-selection.ts +93 -0
- package/src/session/fallback-chain-controller.ts +136 -0
- package/src/session/session-manager.ts +447 -13
- package/src/session/session-storage.ts +8 -1
- package/src/setup/credential-auto-import.ts +290 -35
- package/src/setup/hermes/templates/operator-instructions.v1.md +3 -5
- package/src/slash-commands/builtin-registry.ts +33 -30
- package/src/task/executor.ts +62 -13
- package/src/tools/ask-answer-registry.ts +1 -1
- package/src/tools/ask.ts +13 -8
- package/src/tools/browser/STEALTH-THIRD-PARTY-NOTICES.md +26 -0
- package/src/tools/browser/benchmark/detector-report.ts +157 -0
- package/src/tools/browser/benchmark/run-suite.ts +39 -0
- package/src/tools/browser/launch.ts +124 -19
- package/src/tools/browser/profile-discovery.ts +63 -0
- package/src/tools/browser/profile-posture.ts +59 -0
- package/src/tools/browser/profile-reuse.ts +102 -0
- package/src/tools/browser/profile-warmup.ts +109 -0
- package/src/tools/browser/registry.ts +87 -11
- package/src/tools/browser/tab-protocol.ts +1 -0
- package/src/tools/browser/tab-supervisor.ts +1 -0
- package/src/tools/browser/tab-worker.ts +1 -1
- package/src/tools/browser.ts +6 -0
- package/src/tools/index.ts +8 -8
- package/src/tools/puppeteer/14_stealth_permissions.txt +57 -0
- package/src/tools/puppeteer/15_stealth_webrtc.txt +60 -0
- package/src/tools/telegram-send.ts +2 -2
- package/vendor/insane-search/MANIFEST.json +2 -1
- package/vendor/insane-search/engine/bias_check.py +4 -1
- package/vendor/insane-search/engine/phase0.py +26 -1
- package/dist/types/harness-control-plane/rpc-adapter.d.ts +0 -69
- package/dist/types/modes/bridge/auth.d.ts +0 -12
- package/dist/types/modes/bridge/bridge-client-bridge.d.ts +0 -9
- package/dist/types/modes/bridge/bridge-mode.d.ts +0 -47
- package/dist/types/modes/bridge/bridge-ui-context.d.ts +0 -88
- package/dist/types/modes/bridge/event-stream.d.ts +0 -8
- package/dist/types/modes/rpc/host-tools.d.ts +0 -1
- package/dist/types/modes/rpc/host-uris.d.ts +0 -1
- package/dist/types/modes/rpc/rpc-client.d.ts +0 -299
- package/dist/types/modes/rpc/rpc-mode.d.ts +0 -86
- package/dist/types/modes/rpc/rpc-socket-security.d.ts +0 -10
- package/dist/types/modes/rpc/rpc-types.d.ts +0 -810
- package/dist/types/modes/shared/agent-wire/command-contract.d.ts +0 -18
- package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +0 -37
- package/dist/types/modes/shared/agent-wire/command-validation.d.ts +0 -2
- package/dist/types/modes/shared/agent-wire/handshake.d.ts +0 -56
- package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +0 -16
- package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +0 -17
- package/dist/types/modes/shared/agent-wire/protocol.d.ts +0 -25
- package/dist/types/modes/shared/agent-wire/responses.d.ts +0 -4
- package/dist/types/modes/shared/agent-wire/scopes.d.ts +0 -18
- package/dist/types/modes/shared/agent-wire/session-registry.d.ts +0 -25
- package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +0 -42
- package/dist/types/modes/shared/agent-wire/ui-result.d.ts +0 -27
- package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +0 -29
- package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +0 -68
- package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +0 -166
- package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +0 -127
- package/dist/types/notifications/config.d.ts +0 -132
- package/src/harness-control-plane/rpc-adapter.ts +0 -290
- package/src/modes/bridge/auth.ts +0 -41
- package/src/modes/bridge/bridge-client-bridge.ts +0 -47
- package/src/modes/bridge/bridge-mode.ts +0 -675
- package/src/modes/bridge/bridge-ui-context.ts +0 -200
- package/src/modes/bridge/event-stream.ts +0 -70
- package/src/modes/rpc/host-tools.ts +0 -1
- package/src/modes/rpc/host-uris.ts +0 -1
- package/src/modes/rpc/rpc-client.ts +0 -1166
- package/src/modes/rpc/rpc-mode.ts +0 -1029
- package/src/modes/rpc/rpc-socket-security.ts +0 -115
- package/src/modes/rpc/rpc-types.ts +0 -637
- package/src/modes/shared/agent-wire/command-contract.ts +0 -18
- package/src/modes/shared/agent-wire/command-dispatch.ts +0 -498
- package/src/modes/shared/agent-wire/command-validation.ts +0 -181
- package/src/modes/shared/agent-wire/handshake.ts +0 -157
- package/src/modes/shared/agent-wire/host-tool-bridge.ts +0 -197
- package/src/modes/shared/agent-wire/host-uri-bridge.ts +0 -236
- package/src/modes/shared/agent-wire/protocol.ts +0 -46
- package/src/modes/shared/agent-wire/responses.ts +0 -17
- package/src/modes/shared/agent-wire/scopes.ts +0 -94
- package/src/modes/shared/agent-wire/session-registry.ts +0 -109
- package/src/modes/shared/agent-wire/ui-request-broker.ts +0 -150
- package/src/modes/shared/agent-wire/ui-result.ts +0 -48
- package/src/modes/shared/agent-wire/unattended-action-policy.ts +0 -365
- package/src/modes/shared/agent-wire/unattended-audit.ts +0 -176
- package/src/modes/shared/agent-wire/unattended-run-controller.ts +0 -426
- package/src/modes/shared/agent-wire/unattended-session.ts +0 -528
- package/src/notifications/config.ts +0 -219
- package/src/notifications/index.ts +0 -1835
- package/src/notifications/telegram-daemon-cli.ts +0 -243
- package/src/tools/puppeteer/09_stealth_locale.txt +0 -46
- /package/dist/types/{notifications → sdk/bus}/attachment-registry.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/chat-adapters.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/daemon-paths.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/engine.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/helpers.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/lifecycle-commands.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/operator-runtime.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/rate-limit-pool.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/recent-activity.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/reply-sent-store.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/rich-draft.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/rich-render.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/threaded-inbound.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/threaded-render.d.ts +0 -0
- /package/src/{notifications → sdk/bus}/attachment-registry.ts +0 -0
- /package/src/{notifications → sdk/bus}/chat-adapters.ts +0 -0
- /package/src/{notifications → sdk/bus}/daemon-paths.ts +0 -0
- /package/src/{notifications → sdk/bus}/engine.ts +0 -0
- /package/src/{notifications → sdk/bus}/helpers.ts +0 -0
- /package/src/{notifications → sdk/bus}/operator-runtime.ts +0 -0
- /package/src/{notifications → sdk/bus}/rate-limit-pool.ts +0 -0
- /package/src/{notifications → sdk/bus}/recent-activity.ts +0 -0
- /package/src/{notifications → sdk/bus}/reply-sent-store.ts +0 -0
- /package/src/{notifications → sdk/bus}/rich-draft.ts +0 -0
- /package/src/{notifications → sdk/bus}/rich-render.ts +0 -0
- /package/src/{notifications → sdk/bus}/threaded-inbound.ts +0 -0
- /package/src/{notifications → sdk/bus}/threaded-render.ts +0 -0
|
@@ -4,6 +4,7 @@ import * as fs from "node:fs";
|
|
|
4
4
|
import * as os from "node:os";
|
|
5
5
|
import * as path from "node:path";
|
|
6
6
|
import { type AgentMessage, canContinuePersistedHistory } from "@gajae-code/agent-core";
|
|
7
|
+
import type { ConfiguredModelChainEntry as SharedConfiguredModelChainEntry } from "@gajae-code/agent-core/compaction";
|
|
7
8
|
import type {
|
|
8
9
|
ImageContent,
|
|
9
10
|
Message,
|
|
@@ -221,6 +222,14 @@ export interface ModelChangeEntry extends SessionEntryBase {
|
|
|
221
222
|
thinkingLevel?: string | null;
|
|
222
223
|
}
|
|
223
224
|
|
|
225
|
+
/** Persisted configured fallback chain for one model role. */
|
|
226
|
+
export type ConfiguredModelChainEntry = SharedConfiguredModelChainEntry;
|
|
227
|
+
|
|
228
|
+
export type ConfiguredModelChain = Pick<
|
|
229
|
+
ConfiguredModelChainEntry,
|
|
230
|
+
"role" | "entries" | "origin" | "identity" | "explicitHead" | "cleared"
|
|
231
|
+
>;
|
|
232
|
+
|
|
224
233
|
export interface ServiceTierChangeEntry extends SessionEntryBase {
|
|
225
234
|
type: "service_tier_change";
|
|
226
235
|
serviceTier: ServiceTier | null;
|
|
@@ -353,11 +362,31 @@ export type SessionEntry =
|
|
|
353
362
|
| TtsrInjectionEntry
|
|
354
363
|
| MCPToolSelectionEntry
|
|
355
364
|
| SessionInitEntry
|
|
356
|
-
| ModeChangeEntry
|
|
365
|
+
| ModeChangeEntry
|
|
366
|
+
| ConfiguredModelChainEntry;
|
|
357
367
|
|
|
358
368
|
/** Raw file entry (includes header) */
|
|
359
369
|
export type FileEntry = SessionHeader | SessionEntry;
|
|
360
370
|
|
|
371
|
+
export type DefaultModelSelectionStage = {
|
|
372
|
+
readonly entryRevision: number;
|
|
373
|
+
readonly headerExportRevision: number;
|
|
374
|
+
readonly sessionId: string;
|
|
375
|
+
readonly sessionFile: string | undefined;
|
|
376
|
+
readonly entries: readonly FileEntry[];
|
|
377
|
+
readonly tempPath: string | undefined;
|
|
378
|
+
readonly persistsToExistingFile: boolean;
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
export type DefaultModelSelectionPromotion =
|
|
382
|
+
| { readonly kind: "promoted" }
|
|
383
|
+
| { readonly kind: "not_promoted"; readonly error?: Error }
|
|
384
|
+
| { readonly kind: "unknown"; readonly error: Error };
|
|
385
|
+
|
|
386
|
+
type SessionFileReplacementSyncOutcome =
|
|
387
|
+
| { readonly kind: "replaced" }
|
|
388
|
+
| { readonly kind: "restored_previous"; readonly error: Error };
|
|
389
|
+
|
|
361
390
|
/** Tree node for getTree() - defensive copy of session structure */
|
|
362
391
|
export interface SessionTreeNode {
|
|
363
392
|
entry: SessionEntry;
|
|
@@ -372,6 +401,9 @@ export interface SessionContext {
|
|
|
372
401
|
serviceTier?: ServiceTier;
|
|
373
402
|
/** Model roles: { default: "provider/modelId", small: "provider/modelId", ... } */
|
|
374
403
|
models: Record<string, string>;
|
|
404
|
+
/** Configured fallback chains for model roles on the active branch. */
|
|
405
|
+
configuredModelChains: Record<string, ConfiguredModelChain>;
|
|
406
|
+
|
|
375
407
|
/** Names of TTSR rules that have been injected this session */
|
|
376
408
|
injectedTtsrRules: string[];
|
|
377
409
|
/** Rich TTSR rule injection records for repeat resume. */
|
|
@@ -428,6 +460,20 @@ export interface StrictSessionOpenFailure {
|
|
|
428
460
|
reason: ResumeTailError["reason"] | "identity-mismatch";
|
|
429
461
|
}
|
|
430
462
|
|
|
463
|
+
/** Exact transcript bytes and authority captured from one descriptor-bound read. */
|
|
464
|
+
export interface CapturedSessionTranscriptSnapshot {
|
|
465
|
+
sourcePath: string;
|
|
466
|
+
identity: ResumeSessionIdentity;
|
|
467
|
+
content: Uint8Array;
|
|
468
|
+
storage: SessionStorage;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
export type StrictSessionCaptureResult =
|
|
472
|
+
| { kind: "captured"; snapshot: CapturedSessionTranscriptSnapshot }
|
|
473
|
+
| ResumeTailError;
|
|
474
|
+
|
|
475
|
+
export type StrictSessionForkResult = { kind: "forked"; manager: SessionManager } | StrictSessionOpenFailure;
|
|
476
|
+
|
|
431
477
|
/** Result of opening an inspected session without create-or-rewrite fallback. */
|
|
432
478
|
export type StrictSessionOpenResult = StrictSessionOpenSuccess | StrictSessionOpenFailure;
|
|
433
479
|
|
|
@@ -744,6 +790,31 @@ export function parseSessionEntries(content: string): FileEntry[] {
|
|
|
744
790
|
return parseJsonlLenient<FileEntry>(content);
|
|
745
791
|
}
|
|
746
792
|
|
|
793
|
+
function normalizeConfiguredModelChainEntry(entry: unknown): ConfiguredModelChain | undefined {
|
|
794
|
+
if (!entry || typeof entry !== "object") return undefined;
|
|
795
|
+
const candidate = entry as Partial<ConfiguredModelChainEntry>;
|
|
796
|
+
if (typeof candidate.role !== "string" || candidate.role.length === 0) return undefined;
|
|
797
|
+
if (candidate.cleared === true) {
|
|
798
|
+
return {
|
|
799
|
+
role: candidate.role,
|
|
800
|
+
entries: [],
|
|
801
|
+
origin: typeof candidate.origin === "string" ? candidate.origin : "session",
|
|
802
|
+
explicitHead: candidate.explicitHead === true,
|
|
803
|
+
cleared: true,
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
if (!Array.isArray(candidate.entries)) return undefined;
|
|
807
|
+
const entries = candidate.entries.filter((model): model is string => typeof model === "string" && model.length > 0);
|
|
808
|
+
if (entries.length === 0) return undefined;
|
|
809
|
+
return {
|
|
810
|
+
role: candidate.role,
|
|
811
|
+
entries,
|
|
812
|
+
origin: typeof candidate.origin === "string" ? candidate.origin : "session",
|
|
813
|
+
...(typeof candidate.identity === "string" ? { identity: candidate.identity } : {}),
|
|
814
|
+
explicitHead: candidate.explicitHead === true,
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
|
|
747
818
|
export function getLatestCompactionEntry(entries: SessionEntry[]): CompactionEntry | null {
|
|
748
819
|
for (let i = entries.length - 1; i >= 0; i--) {
|
|
749
820
|
if (entries[i].type === "compaction") {
|
|
@@ -781,6 +852,8 @@ export function buildSessionContext(
|
|
|
781
852
|
thinkingLevel: "off",
|
|
782
853
|
serviceTier: undefined,
|
|
783
854
|
models: {},
|
|
855
|
+
configuredModelChains: {},
|
|
856
|
+
|
|
784
857
|
injectedTtsrRules: [],
|
|
785
858
|
injectedTtsrRuleRecords: [],
|
|
786
859
|
ttsrMessageCount: 0,
|
|
@@ -804,6 +877,8 @@ export function buildSessionContext(
|
|
|
804
877
|
thinkingLevel: "off",
|
|
805
878
|
serviceTier: undefined,
|
|
806
879
|
models: {},
|
|
880
|
+
configuredModelChains: {},
|
|
881
|
+
|
|
807
882
|
injectedTtsrRules: [],
|
|
808
883
|
injectedTtsrRuleRecords: [],
|
|
809
884
|
ttsrMessageCount: 0,
|
|
@@ -829,6 +904,8 @@ export function buildSessionContext(
|
|
|
829
904
|
let thinkingLevel: string | undefined = "off";
|
|
830
905
|
let serviceTier: ServiceTier | undefined;
|
|
831
906
|
const models: Record<string, string> = {};
|
|
907
|
+
const configuredModelChains: Record<string, ConfiguredModelChain> = {};
|
|
908
|
+
|
|
832
909
|
let compaction: CompactionEntry | null = null;
|
|
833
910
|
const injectedTtsrRulesSet = new Set<string>();
|
|
834
911
|
const injectedTtsrRuleRecords = new Map<string, TtsrInjectionRecord>();
|
|
@@ -859,6 +936,13 @@ export function buildSessionContext(
|
|
|
859
936
|
hasExplicitDefaultModel = true;
|
|
860
937
|
}
|
|
861
938
|
}
|
|
939
|
+
} else if (entry.type === "configured_model_chain") {
|
|
940
|
+
const configuredChain = normalizeConfiguredModelChainEntry(entry);
|
|
941
|
+
if (configuredChain?.cleared) {
|
|
942
|
+
delete configuredModelChains[configuredChain.role];
|
|
943
|
+
} else if (configuredChain) {
|
|
944
|
+
configuredModelChains[configuredChain.role] = configuredChain;
|
|
945
|
+
}
|
|
862
946
|
} else if (entry.type === "service_tier_change") {
|
|
863
947
|
serviceTier = entry.serviceTier ?? undefined;
|
|
864
948
|
} else if (entry.type === "message" && entry.message.role === "assistant") {
|
|
@@ -897,6 +981,16 @@ export function buildSessionContext(
|
|
|
897
981
|
}
|
|
898
982
|
|
|
899
983
|
const injectedTtsrRules = Array.from(injectedTtsrRulesSet);
|
|
984
|
+
for (const [role, model] of Object.entries(models)) {
|
|
985
|
+
if (role in configuredModelChains) continue;
|
|
986
|
+
configuredModelChains[role] = {
|
|
987
|
+
role,
|
|
988
|
+
entries: [model],
|
|
989
|
+
origin: "legacy_session",
|
|
990
|
+
explicitHead: true,
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
|
|
900
994
|
const injectedTtsrRuleRecordsArray = Array.from(injectedTtsrRuleRecords.values());
|
|
901
995
|
|
|
902
996
|
// Build messages and collect corresponding entries
|
|
@@ -996,6 +1090,8 @@ export function buildSessionContext(
|
|
|
996
1090
|
thinkingLevel,
|
|
997
1091
|
serviceTier,
|
|
998
1092
|
models,
|
|
1093
|
+
configuredModelChains,
|
|
1094
|
+
|
|
999
1095
|
injectedTtsrRules,
|
|
1000
1096
|
injectedTtsrRuleRecords: injectedTtsrRuleRecordsArray,
|
|
1001
1097
|
ttsrMessageCount,
|
|
@@ -1014,6 +1110,13 @@ function cloneSessionContext(context: SessionContext): SessionContext {
|
|
|
1014
1110
|
...context,
|
|
1015
1111
|
messages,
|
|
1016
1112
|
models: { ...context.models },
|
|
1113
|
+
configuredModelChains: Object.fromEntries(
|
|
1114
|
+
Object.entries(context.configuredModelChains ?? {}).map(([role, chain]) => [
|
|
1115
|
+
role,
|
|
1116
|
+
{ ...chain, entries: [...chain.entries] },
|
|
1117
|
+
]),
|
|
1118
|
+
),
|
|
1119
|
+
|
|
1017
1120
|
injectedTtsrRules: [...context.injectedTtsrRules],
|
|
1018
1121
|
injectedTtsrRuleRecords: context.injectedTtsrRuleRecords?.map(record => ({ ...record })),
|
|
1019
1122
|
ttsrMessageCount: context.ttsrMessageCount,
|
|
@@ -1171,6 +1274,7 @@ function sameResumeStat(left: SessionStorageStat, right: SessionStorageStat): bo
|
|
|
1171
1274
|
|
|
1172
1275
|
interface ResumeInspectionSnapshot {
|
|
1173
1276
|
identity: ResumeSessionIdentity;
|
|
1277
|
+
content: Uint8Array;
|
|
1174
1278
|
entries: FileEntry[];
|
|
1175
1279
|
context: SessionContext;
|
|
1176
1280
|
migrationApplied: boolean;
|
|
@@ -1218,6 +1322,9 @@ function hasStrictSessionSchema(entries: FileEntry[]): boolean {
|
|
|
1218
1322
|
)
|
|
1219
1323
|
return false;
|
|
1220
1324
|
break;
|
|
1325
|
+
case "configured_model_chain":
|
|
1326
|
+
if (!normalizeConfiguredModelChainEntry(value)) return false;
|
|
1327
|
+
break;
|
|
1221
1328
|
case "compaction":
|
|
1222
1329
|
if (
|
|
1223
1330
|
typeof value.summary !== "string" ||
|
|
@@ -1344,7 +1451,7 @@ function inspectResumeSessionFile(
|
|
|
1344
1451
|
mtimeNs: snapshot.mtimeNs,
|
|
1345
1452
|
sha256: crypto.createHash("sha256").update(bytes).digest("hex"),
|
|
1346
1453
|
};
|
|
1347
|
-
return { identity, entries, context, migrationApplied };
|
|
1454
|
+
return { identity, content: Uint8Array.from(bytes), entries, context, migrationApplied };
|
|
1348
1455
|
} catch {
|
|
1349
1456
|
return { kind: "error", reason: "malformed" };
|
|
1350
1457
|
}
|
|
@@ -3131,6 +3238,7 @@ interface SessionManagerStateSnapshot {
|
|
|
3131
3238
|
titleSource: "auto" | "user" | undefined;
|
|
3132
3239
|
sessionFile: string | undefined;
|
|
3133
3240
|
flushed: boolean;
|
|
3241
|
+
ensuredOnDisk: boolean;
|
|
3134
3242
|
needsFullRewriteOnNextPersist: boolean;
|
|
3135
3243
|
fileEntries: FileEntry[];
|
|
3136
3244
|
materializedFileEntries: FileEntry[];
|
|
@@ -3323,6 +3431,7 @@ export class SessionManager {
|
|
|
3323
3431
|
titleSource: this.#titleSource,
|
|
3324
3432
|
sessionFile: this.#sessionFile,
|
|
3325
3433
|
flushed: this.#flushed,
|
|
3434
|
+
ensuredOnDisk: this.#ensuredOnDisk,
|
|
3326
3435
|
needsFullRewriteOnNextPersist: this.#needsFullRewriteOnNextPersist,
|
|
3327
3436
|
// Snapshot entry objects by reference: switch/reload replaces the active entry array,
|
|
3328
3437
|
// so rollback does not need structured cloning of extension/custom details.
|
|
@@ -3335,15 +3444,23 @@ export class SessionManager {
|
|
|
3335
3444
|
|
|
3336
3445
|
restoreState(snapshot: SessionManagerStateSnapshot): void {
|
|
3337
3446
|
const restoredFileEntries = [...snapshot.materializedFileEntries];
|
|
3447
|
+
const retainsPersistWriter =
|
|
3448
|
+
this.#persistWriter?.isOpen() === true &&
|
|
3449
|
+
this.#sessionId === snapshot.sessionId &&
|
|
3450
|
+
this.#sessionFile === snapshot.sessionFile &&
|
|
3451
|
+
this.#persistWriterPath === snapshot.sessionFile;
|
|
3338
3452
|
this.#sessionId = snapshot.sessionId;
|
|
3339
3453
|
this.#sessionName = snapshot.sessionName;
|
|
3340
3454
|
this.#titleSource = snapshot.titleSource;
|
|
3341
3455
|
this.#sessionFile = snapshot.sessionFile;
|
|
3342
3456
|
this.#flushed = snapshot.flushed;
|
|
3457
|
+
this.#ensuredOnDisk = snapshot.ensuredOnDisk;
|
|
3343
3458
|
this.#needsFullRewriteOnNextPersist = snapshot.needsFullRewriteOnNextPersist;
|
|
3344
3459
|
this.#fileEntries = restoredFileEntries;
|
|
3345
|
-
|
|
3346
|
-
|
|
3460
|
+
if (!retainsPersistWriter) {
|
|
3461
|
+
this.#persistWriter = undefined;
|
|
3462
|
+
this.#persistWriterPath = undefined;
|
|
3463
|
+
}
|
|
3347
3464
|
this.#persistChain = Promise.resolve();
|
|
3348
3465
|
this.#persistError = undefined;
|
|
3349
3466
|
this.#persistErrorReported = false;
|
|
@@ -3629,7 +3746,7 @@ export class SessionManager {
|
|
|
3629
3746
|
}
|
|
3630
3747
|
|
|
3631
3748
|
/** Sync version for initial creation (no existing writer to close) */
|
|
3632
|
-
#newSessionSync(options?: NewSessionOptions): string | undefined {
|
|
3749
|
+
#newSessionSync(options?: NewSessionOptions, writeBreadcrumb = true): string | undefined {
|
|
3633
3750
|
this.#persistChain = Promise.resolve();
|
|
3634
3751
|
this.#persistError = undefined;
|
|
3635
3752
|
this.#persistErrorReported = false;
|
|
@@ -3664,7 +3781,7 @@ export class SessionManager {
|
|
|
3664
3781
|
if (this.persist) {
|
|
3665
3782
|
const fileTimestamp = timestamp.replace(/[:.]/g, "-");
|
|
3666
3783
|
this.#sessionFile = path.join(this.getSessionDir(), `${fileTimestamp}_${this.#sessionId}.jsonl`);
|
|
3667
|
-
writeTerminalBreadcrumb(this.cwd, this.#sessionFile);
|
|
3784
|
+
if (writeBreadcrumb) writeTerminalBreadcrumb(this.cwd, this.#sessionFile);
|
|
3668
3785
|
}
|
|
3669
3786
|
this.#resetResidentTextBlobStore();
|
|
3670
3787
|
return this.#sessionFile;
|
|
@@ -3788,7 +3905,11 @@ export class SessionManager {
|
|
|
3788
3905
|
// shared `*.bak` glob on both real and in-memory storage backends and promote it back to
|
|
3789
3906
|
// the primary on the next session-dir scan.
|
|
3790
3907
|
|
|
3791
|
-
#replaceSessionFileAfterEpermSync(
|
|
3908
|
+
#replaceSessionFileAfterEpermSync(
|
|
3909
|
+
tempPath: string,
|
|
3910
|
+
targetPath: string,
|
|
3911
|
+
renameError: unknown,
|
|
3912
|
+
): SessionFileReplacementSyncOutcome {
|
|
3792
3913
|
const dir = path.resolve(targetPath, "..");
|
|
3793
3914
|
const backupPath = path.join(dir, `${path.basename(targetPath)}.${Snowflake.next()}.bak`);
|
|
3794
3915
|
try {
|
|
@@ -3796,7 +3917,7 @@ export class SessionManager {
|
|
|
3796
3917
|
} catch (err) {
|
|
3797
3918
|
if (isEnoent(err)) {
|
|
3798
3919
|
this.storage.renameSync(tempPath, targetPath);
|
|
3799
|
-
return;
|
|
3920
|
+
return { kind: "replaced" };
|
|
3800
3921
|
}
|
|
3801
3922
|
throw toError(renameError);
|
|
3802
3923
|
}
|
|
@@ -3815,7 +3936,7 @@ export class SessionManager {
|
|
|
3815
3936
|
{ cause: originalError },
|
|
3816
3937
|
);
|
|
3817
3938
|
}
|
|
3818
|
-
|
|
3939
|
+
return { kind: "restored_previous", error: replaceError };
|
|
3819
3940
|
}
|
|
3820
3941
|
|
|
3821
3942
|
try {
|
|
@@ -3829,6 +3950,7 @@ export class SessionManager {
|
|
|
3829
3950
|
});
|
|
3830
3951
|
}
|
|
3831
3952
|
}
|
|
3953
|
+
return { kind: "replaced" };
|
|
3832
3954
|
}
|
|
3833
3955
|
|
|
3834
3956
|
async #replaceSessionFileAfterEperm(tempPath: string, targetPath: string, renameError: unknown): Promise<void> {
|
|
@@ -3883,13 +4005,13 @@ export class SessionManager {
|
|
|
3883
4005
|
}
|
|
3884
4006
|
}
|
|
3885
4007
|
|
|
3886
|
-
#replaceSessionFileSync(tempPath: string, targetPath: string):
|
|
4008
|
+
#replaceSessionFileSync(tempPath: string, targetPath: string): SessionFileReplacementSyncOutcome {
|
|
3887
4009
|
try {
|
|
3888
4010
|
this.storage.renameSync(tempPath, targetPath);
|
|
4011
|
+
return { kind: "replaced" };
|
|
3889
4012
|
} catch (err) {
|
|
3890
4013
|
if (hasFsCode(err, "EPERM")) {
|
|
3891
|
-
this.#replaceSessionFileAfterEpermSync(tempPath, targetPath, err);
|
|
3892
|
-
return;
|
|
4014
|
+
return this.#replaceSessionFileAfterEpermSync(tempPath, targetPath, err);
|
|
3893
4015
|
}
|
|
3894
4016
|
|
|
3895
4017
|
throw toError(err);
|
|
@@ -3906,7 +4028,8 @@ export class SessionManager {
|
|
|
3906
4028
|
writer.writeSync(entry);
|
|
3907
4029
|
}
|
|
3908
4030
|
writer.closeSync();
|
|
3909
|
-
this.#replaceSessionFileSync(tempPath, this.#sessionFile);
|
|
4031
|
+
const replacement = this.#replaceSessionFileSync(tempPath, this.#sessionFile);
|
|
4032
|
+
if (replacement.kind === "restored_previous") throw replacement.error;
|
|
3910
4033
|
} catch (err) {
|
|
3911
4034
|
// closeSync is now truthful and may throw; wrap the best-effort cleanup so
|
|
3912
4035
|
// the original error (write/close failure) is the one surfaced, not the
|
|
@@ -3949,6 +4072,38 @@ export class SessionManager {
|
|
|
3949
4072
|
}
|
|
3950
4073
|
}
|
|
3951
4074
|
|
|
4075
|
+
async #writeStagedDefaultModelSelection(
|
|
4076
|
+
entries: readonly FileEntry[],
|
|
4077
|
+
sessionFile: string,
|
|
4078
|
+
): Promise<string | undefined> {
|
|
4079
|
+
if (!this.storage.existsSync(sessionFile)) return undefined;
|
|
4080
|
+
const dir = path.resolve(sessionFile, "..");
|
|
4081
|
+
const tempPath = path.join(dir, `.${path.basename(sessionFile)}.${Snowflake.next()}.default-selection.tmp`);
|
|
4082
|
+
const writer = new NdjsonFileWriter(this.storage, tempPath, { flags: "w" });
|
|
4083
|
+
try {
|
|
4084
|
+
const persistedEntries = await Promise.all(
|
|
4085
|
+
materializeResidentEntriesForPersistenceSync([...entries], this.#residentBlobStores()).map(entry =>
|
|
4086
|
+
prepareEntryForPersistence(entry, this.#blobStore),
|
|
4087
|
+
),
|
|
4088
|
+
);
|
|
4089
|
+
for (const entry of persistedEntries) {
|
|
4090
|
+
await writer.write(entry);
|
|
4091
|
+
}
|
|
4092
|
+
await writer.flush();
|
|
4093
|
+
await writer.fsync();
|
|
4094
|
+
await writer.close();
|
|
4095
|
+
return tempPath;
|
|
4096
|
+
} catch (error) {
|
|
4097
|
+
try {
|
|
4098
|
+
await writer.close();
|
|
4099
|
+
} catch {}
|
|
4100
|
+
try {
|
|
4101
|
+
await this.storage.unlink(tempPath);
|
|
4102
|
+
} catch {}
|
|
4103
|
+
throw toError(error);
|
|
4104
|
+
}
|
|
4105
|
+
}
|
|
4106
|
+
|
|
3952
4107
|
async #rewriteFile(): Promise<void> {
|
|
3953
4108
|
if (!this.persist || !this.#sessionFile) return;
|
|
3954
4109
|
await this.#queuePersistTask(async () => {
|
|
@@ -3981,6 +4136,109 @@ export class SessionManager {
|
|
|
3981
4136
|
return this.persist;
|
|
3982
4137
|
}
|
|
3983
4138
|
|
|
4139
|
+
async stageDefaultModelSelection(
|
|
4140
|
+
model: string,
|
|
4141
|
+
thinkingLevel: string | undefined,
|
|
4142
|
+
options?: { readonly appendThinkingLevel: boolean },
|
|
4143
|
+
): Promise<DefaultModelSelectionStage> {
|
|
4144
|
+
const entryRevision = this.#entryRevision;
|
|
4145
|
+
const headerExportRevision = this.#headerExportRevision;
|
|
4146
|
+
const sessionId = this.#sessionId;
|
|
4147
|
+
const sessionFile = this.#sessionFile;
|
|
4148
|
+
const entryIds = new Map(this.#byId);
|
|
4149
|
+
let parentId = this.#leafId;
|
|
4150
|
+
const entries = [...this.#fileEntries];
|
|
4151
|
+
const temporaryEntry: ModelChangeEntry = {
|
|
4152
|
+
type: "model_change",
|
|
4153
|
+
id: generateId(entryIds),
|
|
4154
|
+
parentId,
|
|
4155
|
+
timestamp: new Date().toISOString(),
|
|
4156
|
+
model,
|
|
4157
|
+
role: "temporary",
|
|
4158
|
+
};
|
|
4159
|
+
entryIds.set(temporaryEntry.id, temporaryEntry);
|
|
4160
|
+
entries.push(temporaryEntry);
|
|
4161
|
+
parentId = temporaryEntry.id;
|
|
4162
|
+
if (options?.appendThinkingLevel) {
|
|
4163
|
+
const thinkingEntry: ThinkingLevelChangeEntry = {
|
|
4164
|
+
type: "thinking_level_change",
|
|
4165
|
+
id: generateId(entryIds),
|
|
4166
|
+
parentId,
|
|
4167
|
+
timestamp: new Date().toISOString(),
|
|
4168
|
+
thinkingLevel: thinkingLevel ?? null,
|
|
4169
|
+
};
|
|
4170
|
+
entryIds.set(thinkingEntry.id, thinkingEntry);
|
|
4171
|
+
entries.push(thinkingEntry);
|
|
4172
|
+
parentId = thinkingEntry.id;
|
|
4173
|
+
}
|
|
4174
|
+
const modelEntry: ModelChangeEntry = {
|
|
4175
|
+
type: "model_change",
|
|
4176
|
+
id: generateId(entryIds),
|
|
4177
|
+
parentId,
|
|
4178
|
+
timestamp: new Date().toISOString(),
|
|
4179
|
+
model,
|
|
4180
|
+
role: "default",
|
|
4181
|
+
};
|
|
4182
|
+
entries.push(modelEntry);
|
|
4183
|
+
const persistsToExistingFile = this.persist && sessionFile !== undefined && this.storage.existsSync(sessionFile);
|
|
4184
|
+
const tempPath = persistsToExistingFile
|
|
4185
|
+
? await this.#writeStagedDefaultModelSelection(entries, sessionFile)
|
|
4186
|
+
: undefined;
|
|
4187
|
+
return {
|
|
4188
|
+
entryRevision,
|
|
4189
|
+
headerExportRevision,
|
|
4190
|
+
sessionId,
|
|
4191
|
+
sessionFile,
|
|
4192
|
+
entries,
|
|
4193
|
+
tempPath,
|
|
4194
|
+
persistsToExistingFile,
|
|
4195
|
+
};
|
|
4196
|
+
}
|
|
4197
|
+
|
|
4198
|
+
promoteDefaultModelSelection(stage: DefaultModelSelectionStage): DefaultModelSelectionPromotion {
|
|
4199
|
+
if (
|
|
4200
|
+
stage.entryRevision !== this.#entryRevision ||
|
|
4201
|
+
stage.headerExportRevision !== this.#headerExportRevision ||
|
|
4202
|
+
stage.sessionId !== this.#sessionId ||
|
|
4203
|
+
stage.sessionFile !== this.#sessionFile
|
|
4204
|
+
) {
|
|
4205
|
+
return { kind: "not_promoted" };
|
|
4206
|
+
}
|
|
4207
|
+
if (stage.persistsToExistingFile) {
|
|
4208
|
+
if (!stage.tempPath || !this.#sessionFile)
|
|
4209
|
+
return { kind: "unknown", error: new Error("Missing staged session replacement") };
|
|
4210
|
+
try {
|
|
4211
|
+
this.#closePersistWriterInternalSync();
|
|
4212
|
+
const replacement = this.#replaceSessionFileSync(stage.tempPath, this.#sessionFile);
|
|
4213
|
+
if (replacement.kind === "restored_previous") {
|
|
4214
|
+
return { kind: "not_promoted", error: replacement.error };
|
|
4215
|
+
}
|
|
4216
|
+
} catch (error) {
|
|
4217
|
+
if (this.#persistWriter?.getCloseState() === "close_failed_retryable") {
|
|
4218
|
+
return { kind: "not_promoted", error: new Error("Session replacement could not be completed.") };
|
|
4219
|
+
}
|
|
4220
|
+
return { kind: "unknown", error: toError(error) };
|
|
4221
|
+
}
|
|
4222
|
+
}
|
|
4223
|
+
this.#fileEntries = [...stage.entries];
|
|
4224
|
+
this.#resetResidentTextBlobStore();
|
|
4225
|
+
this.#reexternalizeFileEntriesForResidentStore();
|
|
4226
|
+
this.#needsFullRewriteOnNextPersist = false;
|
|
4227
|
+
this.#flushed = stage.persistsToExistingFile;
|
|
4228
|
+
this.#ensuredOnDisk = stage.persistsToExistingFile;
|
|
4229
|
+
this.#bumpAllRevisions();
|
|
4230
|
+
return { kind: "promoted" };
|
|
4231
|
+
}
|
|
4232
|
+
|
|
4233
|
+
async discardDefaultModelSelectionStage(stage: DefaultModelSelectionStage): Promise<void> {
|
|
4234
|
+
if (!stage.tempPath) return;
|
|
4235
|
+
try {
|
|
4236
|
+
await this.storage.unlink(stage.tempPath);
|
|
4237
|
+
} catch (error) {
|
|
4238
|
+
if (!isEnoent(error)) throw toError(error);
|
|
4239
|
+
}
|
|
4240
|
+
}
|
|
4241
|
+
|
|
3984
4242
|
/**
|
|
3985
4243
|
* Force-persist all current entries to disk, even when no assistant message exists yet.
|
|
3986
4244
|
* Used by ACP mode where session/new must create a discoverable session immediately.
|
|
@@ -4389,6 +4647,24 @@ export class SessionManager {
|
|
|
4389
4647
|
}
|
|
4390
4648
|
}
|
|
4391
4649
|
|
|
4650
|
+
/** Append a configured fallback chain as child of current leaf, then advance leaf. Returns entry id. */
|
|
4651
|
+
appendConfiguredModelChain(chain: ConfiguredModelChain): string {
|
|
4652
|
+
const entry: ConfiguredModelChainEntry = {
|
|
4653
|
+
type: "configured_model_chain",
|
|
4654
|
+
id: generateId(this.#byId),
|
|
4655
|
+
parentId: this.#leafId,
|
|
4656
|
+
timestamp: new Date().toISOString(),
|
|
4657
|
+
role: chain.role,
|
|
4658
|
+
entries: [...chain.entries],
|
|
4659
|
+
origin: chain.origin,
|
|
4660
|
+
identity: chain.identity,
|
|
4661
|
+
explicitHead: chain.explicitHead,
|
|
4662
|
+
cleared: chain.cleared,
|
|
4663
|
+
};
|
|
4664
|
+
this.#appendEntry(entry);
|
|
4665
|
+
return entry.id;
|
|
4666
|
+
}
|
|
4667
|
+
|
|
4392
4668
|
/** Append a message as child of current leaf, then advance leaf. Returns entry id.
|
|
4393
4669
|
* Does not allow writing CompactionSummaryMessage and BranchSummaryMessage directly.
|
|
4394
4670
|
* Reason: we want these to be top-level entries in the session, not message session entries,
|
|
@@ -5422,6 +5698,11 @@ export class SessionManager {
|
|
|
5422
5698
|
return computeDefaultSessionDir(cwd, storage, getSessionsDir(agentDir));
|
|
5423
5699
|
}
|
|
5424
5700
|
|
|
5701
|
+
/** Resolve the default session directory without creating or migrating storage. */
|
|
5702
|
+
static getDefaultSessionDirReadOnly(cwd: string, agentDir?: string): string {
|
|
5703
|
+
const { encodedDirName } = getDefaultSessionDirName(cwd);
|
|
5704
|
+
return path.join(getSessionsDir(agentDir), encodedDirName);
|
|
5705
|
+
}
|
|
5425
5706
|
/**
|
|
5426
5707
|
* Create a new session.
|
|
5427
5708
|
* @param cwd Working directory (stored in session header)
|
|
@@ -5513,6 +5794,159 @@ export class SessionManager {
|
|
|
5513
5794
|
}
|
|
5514
5795
|
}
|
|
5515
5796
|
|
|
5797
|
+
/** Capture exact source content for a strict fork without granting write ownership. */
|
|
5798
|
+
static captureTranscriptStrict(
|
|
5799
|
+
filePath: string,
|
|
5800
|
+
storage: SessionStorage = new FileSessionStorage(),
|
|
5801
|
+
): StrictSessionCaptureResult {
|
|
5802
|
+
const inspected = inspectResumeSessionFile(filePath, storage);
|
|
5803
|
+
if ("kind" in inspected) return inspected;
|
|
5804
|
+
return {
|
|
5805
|
+
kind: "captured",
|
|
5806
|
+
snapshot: {
|
|
5807
|
+
sourcePath: path.resolve(filePath),
|
|
5808
|
+
identity: inspected.identity,
|
|
5809
|
+
content: Uint8Array.from(inspected.content),
|
|
5810
|
+
storage,
|
|
5811
|
+
},
|
|
5812
|
+
};
|
|
5813
|
+
}
|
|
5814
|
+
|
|
5815
|
+
/**
|
|
5816
|
+
* Fork strictly from captured source bytes. The source pathname is used only to
|
|
5817
|
+
* revalidate captured authority before destination initialization and transcript
|
|
5818
|
+
* persistence; destination history always comes from the captured bytes.
|
|
5819
|
+
*/
|
|
5820
|
+
static async forkFromCaptured(
|
|
5821
|
+
snapshot: CapturedSessionTranscriptSnapshot,
|
|
5822
|
+
cwd: string,
|
|
5823
|
+
sessionDir?: string,
|
|
5824
|
+
): Promise<StrictSessionForkResult> {
|
|
5825
|
+
if (crypto.createHash("sha256").update(snapshot.content).digest("hex") !== snapshot.identity.sha256) {
|
|
5826
|
+
return { kind: "error", reason: "identity-mismatch" };
|
|
5827
|
+
}
|
|
5828
|
+
|
|
5829
|
+
let forkEntries: FileEntry[] = [];
|
|
5830
|
+
try {
|
|
5831
|
+
const content = new TextDecoder("utf-8", { fatal: true }).decode(snapshot.content);
|
|
5832
|
+
for (const line of content.split(/\r?\n/)) {
|
|
5833
|
+
if (line.length > 0) JSON.parse(line);
|
|
5834
|
+
}
|
|
5835
|
+
forkEntries = parseSessionEntries(content);
|
|
5836
|
+
const sourceHeader = forkEntries[0] as SessionHeader | undefined;
|
|
5837
|
+
if (sourceHeader?.type !== "session" || sourceHeader.id !== snapshot.identity.sessionId)
|
|
5838
|
+
return { kind: "error", reason: "identity-mismatch" };
|
|
5839
|
+
migrateToCurrentVersion(forkEntries);
|
|
5840
|
+
if (!hasStrictSessionSchema(forkEntries)) return { kind: "error", reason: "malformed" };
|
|
5841
|
+
} catch {
|
|
5842
|
+
return { kind: "error", reason: "malformed" };
|
|
5843
|
+
}
|
|
5844
|
+
|
|
5845
|
+
const revalidated = inspectResumeSessionFile(snapshot.sourcePath, snapshot.storage);
|
|
5846
|
+
if ("kind" in revalidated) return revalidated;
|
|
5847
|
+
if (!sameResumeIdentity(snapshot.identity, revalidated.identity)) {
|
|
5848
|
+
return { kind: "error", reason: "identity-mismatch" };
|
|
5849
|
+
}
|
|
5850
|
+
|
|
5851
|
+
const dir = sessionDir ?? SessionManager.getDefaultSessionDir(cwd, undefined, snapshot.storage);
|
|
5852
|
+
const removeSessionDirOnFailure =
|
|
5853
|
+
snapshot.storage instanceof FileSessionStorage && !snapshot.storage.existsSync(dir);
|
|
5854
|
+
let manager: SessionManager | undefined;
|
|
5855
|
+
let authorityFailure: StrictSessionOpenFailure | undefined;
|
|
5856
|
+
try {
|
|
5857
|
+
manager = new SessionManager(cwd, dir, true, snapshot.storage);
|
|
5858
|
+
await resolveBlobRefsInEntries(forkEntries, manager.#blobStore);
|
|
5859
|
+
manager.#fileEntries = forkEntries;
|
|
5860
|
+
const sourceHeader = manager.#fileEntries.find(e => e.type === "session") as SessionHeader | undefined;
|
|
5861
|
+
const historyEntries = manager.#fileEntries.filter(entry => entry.type !== "session") as SessionEntry[];
|
|
5862
|
+
manager.#newSessionSync({ parentSession: sourceHeader?.id }, false);
|
|
5863
|
+
manager.#resetResidentTextBlobStore();
|
|
5864
|
+
const newHeader = manager.#fileEntries[0] as SessionHeader;
|
|
5865
|
+
newHeader.title = sourceHeader?.title;
|
|
5866
|
+
newHeader.titleSource = sourceHeader?.titleSource;
|
|
5867
|
+
const residentBlobStores = manager.#residentBlobStores();
|
|
5868
|
+
manager.#fileEntries = [
|
|
5869
|
+
newHeader,
|
|
5870
|
+
...historyEntries.map(entry => prepareEntryForResidentSync(entry, residentBlobStores) as SessionEntry),
|
|
5871
|
+
];
|
|
5872
|
+
manager.#sessionName = newHeader.title;
|
|
5873
|
+
manager.#titleSource = newHeader.titleSource;
|
|
5874
|
+
manager.sanitizeLoadedOpenAIResponsesReplayMetadata();
|
|
5875
|
+
manager.#buildIndex();
|
|
5876
|
+
manager.#bumpAllRevisions();
|
|
5877
|
+
const beforeWrite = inspectResumeSessionFile(snapshot.sourcePath, snapshot.storage);
|
|
5878
|
+
if ("kind" in beforeWrite) {
|
|
5879
|
+
authorityFailure = beforeWrite;
|
|
5880
|
+
throw new Error("Captured fork source authority changed before destination write.");
|
|
5881
|
+
}
|
|
5882
|
+
if (!sameResumeIdentity(snapshot.identity, beforeWrite.identity)) {
|
|
5883
|
+
authorityFailure = { kind: "error", reason: "identity-mismatch" };
|
|
5884
|
+
throw new Error("Captured fork source authority changed before destination write.");
|
|
5885
|
+
}
|
|
5886
|
+
await manager.#rewriteFile();
|
|
5887
|
+
if (manager.#sessionFile) writeTerminalBreadcrumb(manager.cwd, manager.#sessionFile);
|
|
5888
|
+
return { kind: "forked", manager };
|
|
5889
|
+
} catch (error) {
|
|
5890
|
+
if (manager) {
|
|
5891
|
+
const sessionFile = manager.#sessionFile;
|
|
5892
|
+
const cleanupErrors: Error[] = [];
|
|
5893
|
+
try {
|
|
5894
|
+
await manager.close();
|
|
5895
|
+
} catch (cleanupError) {
|
|
5896
|
+
cleanupErrors.push(toError(cleanupError));
|
|
5897
|
+
}
|
|
5898
|
+
if (sessionFile) {
|
|
5899
|
+
try {
|
|
5900
|
+
await manager.storage.unlink(sessionFile);
|
|
5901
|
+
} catch (cleanupError) {
|
|
5902
|
+
if (!isEnoent(cleanupError)) cleanupErrors.push(toError(cleanupError));
|
|
5903
|
+
}
|
|
5904
|
+
if (manager.storage instanceof FileSessionStorage) {
|
|
5905
|
+
try {
|
|
5906
|
+
await fs.promises.rm(sessionFile.slice(0, -6), { recursive: true, force: true });
|
|
5907
|
+
} catch (cleanupError) {
|
|
5908
|
+
cleanupErrors.push(toError(cleanupError));
|
|
5909
|
+
}
|
|
5910
|
+
try {
|
|
5911
|
+
const sessionFileName = path.basename(sessionFile);
|
|
5912
|
+
const transientPrefix = `.${sessionFileName}.`;
|
|
5913
|
+
const backupPrefix = `${sessionFileName}.`;
|
|
5914
|
+
for (const name of await fs.promises.readdir(path.dirname(sessionFile))) {
|
|
5915
|
+
if (
|
|
5916
|
+
(name.startsWith(transientPrefix) && name.endsWith(".tmp")) ||
|
|
5917
|
+
(name.startsWith(backupPrefix) && name.endsWith(".bak"))
|
|
5918
|
+
) {
|
|
5919
|
+
await fs.promises.rm(path.join(path.dirname(sessionFile), name), {
|
|
5920
|
+
recursive: true,
|
|
5921
|
+
force: true,
|
|
5922
|
+
});
|
|
5923
|
+
}
|
|
5924
|
+
}
|
|
5925
|
+
} catch (cleanupError) {
|
|
5926
|
+
if (!isEnoent(cleanupError)) cleanupErrors.push(toError(cleanupError));
|
|
5927
|
+
}
|
|
5928
|
+
}
|
|
5929
|
+
}
|
|
5930
|
+
if (removeSessionDirOnFailure) {
|
|
5931
|
+
try {
|
|
5932
|
+
await fs.promises.rmdir(dir);
|
|
5933
|
+
} catch (cleanupError) {
|
|
5934
|
+
const code = (cleanupError as NodeJS.ErrnoException).code;
|
|
5935
|
+
if (code !== "ENOENT" && code !== "ENOTEMPTY" && code !== "EEXIST")
|
|
5936
|
+
cleanupErrors.push(toError(cleanupError));
|
|
5937
|
+
}
|
|
5938
|
+
}
|
|
5939
|
+
if (cleanupErrors.length > 0) {
|
|
5940
|
+
throw new Error(`Failed to clean up fork destination: ${cleanupErrors[0]!.message}`, {
|
|
5941
|
+
cause: toError(error),
|
|
5942
|
+
});
|
|
5943
|
+
}
|
|
5944
|
+
if (authorityFailure) return authorityFailure;
|
|
5945
|
+
}
|
|
5946
|
+
throw error;
|
|
5947
|
+
}
|
|
5948
|
+
}
|
|
5949
|
+
|
|
5516
5950
|
/** Inspect a selected session without acquiring write-capable ownership. */
|
|
5517
5951
|
static async inspectSessionTailReadOnly(
|
|
5518
5952
|
filePath: string,
|