apex-code 0.0.1-alpha.9 → 0.0.4
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 +150 -2
- package/README.md +9 -8
- package/dist/cli/args.d.ts +25 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +43 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/mcp-command.d.ts +9 -0
- package/dist/cli/mcp-command.d.ts.map +1 -0
- package/dist/cli/mcp-command.js +53 -0
- package/dist/cli/mcp-command.js.map +1 -0
- package/dist/cli/project-trust.d.ts.map +1 -1
- package/dist/cli/project-trust.js +3 -1
- package/dist/cli/project-trust.js.map +1 -1
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +2 -1
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +94 -5
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +24 -5
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +3 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +157 -8
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +565 -22
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +7 -0
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/checkpoints/git-checkpoints.d.ts +39 -0
- package/dist/core/checkpoints/git-checkpoints.d.ts.map +1 -0
- package/dist/core/checkpoints/git-checkpoints.js +251 -0
- package/dist/core/checkpoints/git-checkpoints.js.map +1 -0
- package/dist/core/checkpoints/session-checkpoints.d.ts +23 -0
- package/dist/core/checkpoints/session-checkpoints.d.ts.map +1 -0
- package/dist/core/checkpoints/session-checkpoints.js +36 -0
- package/dist/core/checkpoints/session-checkpoints.js.map +1 -0
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +4 -3
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +5 -0
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +19 -5
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/delegation/runtime.d.ts +6 -5
- package/dist/core/delegation/runtime.d.ts.map +1 -1
- package/dist/core/delegation/runtime.js +4 -3
- package/dist/core/delegation/runtime.js.map +1 -1
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +5 -2
- package/dist/core/exec.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +8 -2
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +5 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +45 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/source-runtime.d.ts +14 -0
- package/dist/core/extensions/source-runtime.d.ts.map +1 -0
- package/dist/core/extensions/source-runtime.js +56 -0
- package/dist/core/extensions/source-runtime.js.map +1 -0
- package/dist/core/extensions/types.d.ts +22 -2
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/formatter-lifecycle.d.ts +69 -0
- package/dist/core/formatter-lifecycle.d.ts.map +1 -0
- package/dist/core/formatter-lifecycle.js +360 -0
- package/dist/core/formatter-lifecycle.js.map +1 -0
- package/dist/core/hooks/command-handler.d.ts +19 -0
- package/dist/core/hooks/command-handler.d.ts.map +1 -0
- package/dist/core/hooks/command-handler.js +112 -0
- package/dist/core/hooks/command-handler.js.map +1 -0
- package/dist/core/hooks/http-handler.d.ts +10 -0
- package/dist/core/hooks/http-handler.d.ts.map +1 -0
- package/dist/core/hooks/http-handler.js +36 -0
- package/dist/core/hooks/http-handler.js.map +1 -0
- package/dist/core/hooks/loader.d.ts +29 -0
- package/dist/core/hooks/loader.d.ts.map +1 -0
- package/dist/core/hooks/loader.js +139 -0
- package/dist/core/hooks/loader.js.map +1 -0
- package/dist/core/hooks/runtime.d.ts +13 -0
- package/dist/core/hooks/runtime.d.ts.map +1 -0
- package/dist/core/hooks/runtime.js +63 -0
- package/dist/core/hooks/runtime.js.map +1 -0
- package/dist/core/hooks/types.d.ts +83 -0
- package/dist/core/hooks/types.d.ts.map +1 -0
- package/dist/core/hooks/types.js +24 -0
- package/dist/core/hooks/types.js.map +1 -0
- package/dist/core/mcp/config.d.ts +16 -0
- package/dist/core/mcp/config.d.ts.map +1 -0
- package/dist/core/mcp/config.js +166 -0
- package/dist/core/mcp/config.js.map +1 -0
- package/dist/core/mcp/connector.d.ts +35 -0
- package/dist/core/mcp/connector.d.ts.map +1 -0
- package/dist/core/mcp/connector.js +105 -0
- package/dist/core/mcp/connector.js.map +1 -0
- package/dist/core/mcp/contract.d.ts +19 -0
- package/dist/core/mcp/contract.d.ts.map +1 -0
- package/dist/core/mcp/contract.js +89 -0
- package/dist/core/mcp/contract.js.map +1 -0
- package/dist/core/mcp/mcp-tool.d.ts +32 -0
- package/dist/core/mcp/mcp-tool.d.ts.map +1 -0
- package/dist/core/mcp/mcp-tool.js +171 -0
- package/dist/core/mcp/mcp-tool.js.map +1 -0
- package/dist/core/mcp/metadata-cache.d.ts +29 -0
- package/dist/core/mcp/metadata-cache.d.ts.map +1 -0
- package/dist/core/mcp/metadata-cache.js +99 -0
- package/dist/core/mcp/metadata-cache.js.map +1 -0
- package/dist/core/mcp/oauth/authorize.d.ts +21 -0
- package/dist/core/mcp/oauth/authorize.d.ts.map +1 -0
- package/dist/core/mcp/oauth/authorize.js +32 -0
- package/dist/core/mcp/oauth/authorize.js.map +1 -0
- package/dist/core/mcp/oauth/discover.d.ts +27 -0
- package/dist/core/mcp/oauth/discover.d.ts.map +1 -0
- package/dist/core/mcp/oauth/discover.js +116 -0
- package/dist/core/mcp/oauth/discover.js.map +1 -0
- package/dist/core/mcp/oauth/flow.d.ts +31 -0
- package/dist/core/mcp/oauth/flow.d.ts.map +1 -0
- package/dist/core/mcp/oauth/flow.js +175 -0
- package/dist/core/mcp/oauth/flow.js.map +1 -0
- package/dist/core/mcp/oauth/mcp-token.d.ts +51 -0
- package/dist/core/mcp/oauth/mcp-token.d.ts.map +1 -0
- package/dist/core/mcp/oauth/mcp-token.js +129 -0
- package/dist/core/mcp/oauth/mcp-token.js.map +1 -0
- package/dist/core/mcp/oauth/pkce.d.ts +12 -0
- package/dist/core/mcp/oauth/pkce.d.ts.map +1 -0
- package/dist/core/mcp/oauth/pkce.js +11 -0
- package/dist/core/mcp/oauth/pkce.js.map +1 -0
- package/dist/core/mcp/oauth/register.d.ts +16 -0
- package/dist/core/mcp/oauth/register.d.ts.map +1 -0
- package/dist/core/mcp/oauth/register.js +42 -0
- package/dist/core/mcp/oauth/register.js.map +1 -0
- package/dist/core/mcp/oauth/token-client.d.ts +33 -0
- package/dist/core/mcp/oauth/token-client.d.ts.map +1 -0
- package/dist/core/mcp/oauth/token-client.js +65 -0
- package/dist/core/mcp/oauth/token-client.js.map +1 -0
- package/dist/core/mcp/runtime.d.ts +20 -0
- package/dist/core/mcp/runtime.d.ts.map +1 -0
- package/dist/core/mcp/runtime.js +37 -0
- package/dist/core/mcp/runtime.js.map +1 -0
- package/dist/core/mcp/schema.d.ts +22 -0
- package/dist/core/mcp/schema.d.ts.map +1 -0
- package/dist/core/mcp/schema.js +20 -0
- package/dist/core/mcp/schema.js.map +1 -0
- package/dist/core/mcp/server-manager.d.ts +43 -0
- package/dist/core/mcp/server-manager.d.ts.map +1 -0
- package/dist/core/mcp/server-manager.js +142 -0
- package/dist/core/mcp/server-manager.js.map +1 -0
- package/dist/core/mcp/types.d.ts +100 -0
- package/dist/core/mcp/types.d.ts.map +1 -0
- package/dist/core/mcp/types.js +8 -0
- package/dist/core/mcp/types.js.map +1 -0
- package/dist/core/permissions/gate.d.ts.map +1 -1
- package/dist/core/permissions/gate.js +45 -4
- package/dist/core/permissions/gate.js.map +1 -1
- package/dist/core/permissions/operations.d.ts +20 -0
- package/dist/core/permissions/operations.d.ts.map +1 -0
- package/dist/core/permissions/operations.js +9 -0
- package/dist/core/permissions/operations.js.map +1 -0
- package/dist/core/permissions/policy-command.d.ts +42 -0
- package/dist/core/permissions/policy-command.d.ts.map +1 -0
- package/dist/core/permissions/policy-command.js +44 -0
- package/dist/core/permissions/policy-command.js.map +1 -0
- package/dist/core/permissions/responder.d.ts +49 -2
- package/dist/core/permissions/responder.d.ts.map +1 -1
- package/dist/core/permissions/responder.js +20 -8
- package/dist/core/permissions/responder.js.map +1 -1
- package/dist/core/permissions/rules.d.ts.map +1 -1
- package/dist/core/permissions/rules.js +11 -1
- package/dist/core/permissions/rules.js.map +1 -1
- package/dist/core/permissions/store.d.ts +18 -0
- package/dist/core/permissions/store.d.ts.map +1 -1
- package/dist/core/permissions/store.js +89 -8
- package/dist/core/permissions/store.js.map +1 -1
- package/dist/core/policy-executor.d.ts +47 -0
- package/dist/core/policy-executor.d.ts.map +1 -0
- package/dist/core/policy-executor.js +228 -0
- package/dist/core/policy-executor.js.map +1 -0
- package/dist/core/policy-loader.d.ts +72 -0
- package/dist/core/policy-loader.d.ts.map +1 -0
- package/dist/core/policy-loader.js +195 -0
- package/dist/core/policy-loader.js.map +1 -0
- package/dist/core/project-trust.d.ts +1 -1
- package/dist/core/project-trust.d.ts.map +1 -1
- package/dist/core/project-trust.js.map +1 -1
- package/dist/core/sandbox/bwrap-arguments.d.ts +41 -0
- package/dist/core/sandbox/bwrap-arguments.d.ts.map +1 -0
- package/dist/core/sandbox/bwrap-arguments.js +136 -0
- package/dist/core/sandbox/bwrap-arguments.js.map +1 -0
- package/dist/core/sandbox/child-entry.d.ts.map +1 -1
- package/dist/core/sandbox/child-entry.js +3 -1
- package/dist/core/sandbox/child-entry.js.map +1 -1
- package/dist/core/sandbox/cli-launch.d.ts +84 -4
- package/dist/core/sandbox/cli-launch.d.ts.map +1 -1
- package/dist/core/sandbox/cli-launch.js +115 -16
- package/dist/core/sandbox/cli-launch.js.map +1 -1
- package/dist/core/sandbox/cli-supervisor.d.ts +2 -0
- package/dist/core/sandbox/cli-supervisor.d.ts.map +1 -1
- package/dist/core/sandbox/cli-supervisor.js +50 -2
- package/dist/core/sandbox/cli-supervisor.js.map +1 -1
- package/dist/core/sandbox/full-access.d.ts +28 -0
- package/dist/core/sandbox/full-access.d.ts.map +1 -0
- package/dist/core/sandbox/full-access.js +63 -0
- package/dist/core/sandbox/full-access.js.map +1 -0
- package/dist/core/sandbox/git-identity.d.ts +57 -0
- package/dist/core/sandbox/git-identity.d.ts.map +1 -0
- package/dist/core/sandbox/git-identity.js +78 -0
- package/dist/core/sandbox/git-identity.js.map +1 -0
- package/dist/core/sandbox/host-approval.d.ts +42 -0
- package/dist/core/sandbox/host-approval.d.ts.map +1 -0
- package/dist/core/sandbox/host-approval.js +99 -0
- package/dist/core/sandbox/host-approval.js.map +1 -0
- package/dist/core/sandbox/linux-backend.d.ts +14 -0
- package/dist/core/sandbox/linux-backend.d.ts.map +1 -1
- package/dist/core/sandbox/linux-backend.js +158 -80
- package/dist/core/sandbox/linux-backend.js.map +1 -1
- package/dist/core/sandbox/macos-backend.d.ts +5 -0
- package/dist/core/sandbox/macos-backend.d.ts.map +1 -1
- package/dist/core/sandbox/macos-backend.js +164 -5
- package/dist/core/sandbox/macos-backend.js.map +1 -1
- package/dist/core/sandbox/network-proxy.d.ts +19 -0
- package/dist/core/sandbox/network-proxy.d.ts.map +1 -1
- package/dist/core/sandbox/network-proxy.js +93 -19
- package/dist/core/sandbox/network-proxy.js.map +1 -1
- package/dist/core/sandbox/policy.d.ts +8 -0
- package/dist/core/sandbox/policy.d.ts.map +1 -1
- package/dist/core/sandbox/policy.js +29 -12
- package/dist/core/sandbox/policy.js.map +1 -1
- package/dist/core/sandbox/profiles.d.ts +25 -0
- package/dist/core/sandbox/profiles.d.ts.map +1 -0
- package/dist/core/sandbox/profiles.js +23 -0
- package/dist/core/sandbox/profiles.js.map +1 -0
- package/dist/core/sandbox/rpc/command-client.d.ts +28 -0
- package/dist/core/sandbox/rpc/command-client.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/command-client.js +86 -0
- package/dist/core/sandbox/rpc/command-client.js.map +1 -0
- package/dist/core/sandbox/rpc/command-proxy.d.ts +48 -0
- package/dist/core/sandbox/rpc/command-proxy.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/command-proxy.js +120 -0
- package/dist/core/sandbox/rpc/command-proxy.js.map +1 -0
- package/dist/core/sandbox/rpc/credential-proxy.d.ts.map +1 -1
- package/dist/core/sandbox/rpc/credential-proxy.js +2 -96
- package/dist/core/sandbox/rpc/credential-proxy.js.map +1 -1
- package/dist/core/sandbox/rpc/framing.d.ts +35 -0
- package/dist/core/sandbox/rpc/framing.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/framing.js +114 -0
- package/dist/core/sandbox/rpc/framing.js.map +1 -0
- package/dist/core/sandbox/rpc/git-credential-helper.d.ts +47 -0
- package/dist/core/sandbox/rpc/git-credential-helper.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/git-credential-helper.js +222 -0
- package/dist/core/sandbox/rpc/git-credential-helper.js.map +1 -0
- package/dist/core/sandbox/rpc/git-credential-proxy.d.ts +66 -0
- package/dist/core/sandbox/rpc/git-credential-proxy.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/git-credential-proxy.js +209 -0
- package/dist/core/sandbox/rpc/git-credential-proxy.js.map +1 -0
- package/dist/core/sandbox/supervisor-temp.d.ts +18 -0
- package/dist/core/sandbox/supervisor-temp.d.ts.map +1 -0
- package/dist/core/sandbox/supervisor-temp.js +21 -0
- package/dist/core/sandbox/supervisor-temp.js.map +1 -0
- package/dist/core/sandbox/supervisor.d.ts +12 -1
- package/dist/core/sandbox/supervisor.d.ts.map +1 -1
- package/dist/core/sandbox/supervisor.js +15 -1
- package/dist/core/sandbox/supervisor.js.map +1 -1
- package/dist/core/sandbox/terminal-handoff.d.ts +68 -0
- package/dist/core/sandbox/terminal-handoff.d.ts.map +1 -0
- package/dist/core/sandbox/terminal-handoff.js +221 -0
- package/dist/core/sandbox/terminal-handoff.js.map +1 -0
- package/dist/core/sandbox/terminal-size.d.ts +13 -0
- package/dist/core/sandbox/terminal-size.d.ts.map +1 -1
- package/dist/core/sandbox/terminal-size.js +23 -2
- package/dist/core/sandbox/terminal-size.js.map +1 -1
- package/dist/core/sdk.d.ts +22 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +53 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +13 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +32 -5
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +163 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +107 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +2 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/tools/background-shell.d.ts +39 -0
- package/dist/core/tools/background-shell.d.ts.map +1 -0
- package/dist/core/tools/background-shell.js +81 -0
- package/dist/core/tools/background-shell.js.map +1 -0
- package/dist/core/tools/bash-command-segments.d.ts.map +1 -1
- package/dist/core/tools/bash-command-segments.js +2 -0
- package/dist/core/tools/bash-command-segments.js.map +1 -1
- package/dist/core/tools/bash.d.ts +30 -15
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +228 -12
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/contract-snapshot.d.ts +58 -0
- package/dist/core/tools/contract-snapshot.d.ts.map +1 -0
- package/dist/core/tools/contract-snapshot.js +51 -0
- package/dist/core/tools/contract-snapshot.js.map +1 -0
- package/dist/core/tools/contract.d.ts +53 -5
- package/dist/core/tools/contract.d.ts.map +1 -1
- package/dist/core/tools/contract.js +22 -2
- package/dist/core/tools/contract.js.map +1 -1
- package/dist/core/tools/delegate.d.ts +6 -4
- package/dist/core/tools/delegate.d.ts.map +1 -1
- package/dist/core/tools/delegate.js +21 -11
- package/dist/core/tools/delegate.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts +48 -0
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +215 -3
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts +8 -0
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +53 -7
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +5 -2
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +5 -2
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +10 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +3 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +5 -2
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/lsp.d.ts +19 -1
- package/dist/core/tools/lsp.d.ts.map +1 -1
- package/dist/core/tools/lsp.js +163 -10
- package/dist/core/tools/lsp.js.map +1 -1
- package/dist/core/tools/path-permission.d.ts +3 -0
- package/dist/core/tools/path-permission.d.ts.map +1 -1
- package/dist/core/tools/path-permission.js +16 -4
- package/dist/core/tools/path-permission.js.map +1 -1
- package/dist/core/tools/path-utils.d.ts +27 -2
- package/dist/core/tools/path-utils.d.ts.map +1 -1
- package/dist/core/tools/path-utils.js +221 -4
- package/dist/core/tools/path-utils.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +20 -11
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/test.d.ts +54 -9
- package/dist/core/tools/test.d.ts.map +1 -1
- package/dist/core/tools/test.js +239 -19
- package/dist/core/tools/test.js.map +1 -1
- package/dist/core/tools/write.d.ts +7 -0
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +64 -9
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/verification-lifecycle.d.ts +77 -0
- package/dist/core/verification-lifecycle.d.ts.map +1 -0
- package/dist/core/verification-lifecycle.js +146 -0
- package/dist/core/verification-lifecycle.js.map +1 -0
- package/dist/core/workspace/artifacts.d.ts +45 -0
- package/dist/core/workspace/artifacts.d.ts.map +1 -0
- package/dist/core/workspace/artifacts.js +165 -0
- package/dist/core/workspace/artifacts.js.map +1 -0
- package/dist/core/workspace/comparison.d.ts +27 -0
- package/dist/core/workspace/comparison.d.ts.map +1 -0
- package/dist/core/workspace/comparison.js +94 -0
- package/dist/core/workspace/comparison.js.map +1 -0
- package/dist/core/workspace/git-observer.d.ts +48 -0
- package/dist/core/workspace/git-observer.d.ts.map +1 -0
- package/dist/core/workspace/git-observer.js +346 -0
- package/dist/core/workspace/git-observer.js.map +1 -0
- package/dist/core/workspace/projection.d.ts +3 -0
- package/dist/core/workspace/projection.d.ts.map +1 -0
- package/dist/core/workspace/projection.js +56 -0
- package/dist/core/workspace/projection.js.map +1 -0
- package/dist/core/workspace/state.d.ts +133 -0
- package/dist/core/workspace/state.d.ts.map +1 -0
- package/dist/core/workspace/state.js +96 -0
- package/dist/core/workspace/state.js.map +1 -0
- package/dist/extensions/llama/client.d.ts +6 -0
- package/dist/extensions/llama/client.d.ts.map +1 -1
- package/dist/extensions/llama/client.js +7 -0
- package/dist/extensions/llama/client.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts +3 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +27 -6
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +3 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +41 -9
- package/dist/main.js.map +1 -1
- package/dist/modes/acp/server.d.ts +55 -0
- package/dist/modes/acp/server.d.ts.map +1 -0
- package/dist/modes/acp/server.js +244 -0
- package/dist/modes/acp/server.js.map +1 -0
- package/dist/modes/acp/translate.d.ts +37 -0
- package/dist/modes/acp/translate.d.ts.map +1 -0
- package/dist/modes/acp/translate.js +50 -0
- package/dist/modes/acp/translate.js.map +1 -0
- package/dist/modes/index.d.ts +1 -0
- package/dist/modes/index.d.ts.map +1 -1
- package/dist/modes/index.js +1 -0
- package/dist/modes/index.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +29 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +182 -23
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +7 -0
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +20 -0
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +9 -4
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +20 -9
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +7 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +7 -3
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +19 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +70 -10
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +6 -6
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/permission-preview.d.ts +15 -0
- package/dist/modes/interactive/components/permission-preview.d.ts.map +1 -0
- package/dist/modes/interactive/components/permission-preview.js +33 -0
- package/dist/modes/interactive/components/permission-preview.js.map +1 -0
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +2 -2
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +10 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +23 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +64 -10
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +34 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +231 -26
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts +12 -0
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +15 -5
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +27 -12
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +7 -0
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +7 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +3 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +12 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +0 -6
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +6 -4
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +6 -4
- package/dist/utils/version-check.js.map +1 -1
- package/docs/compaction.md +4 -0
- package/docs/custom-provider.md +7 -7
- package/docs/environment-variables.md +1 -1
- package/docs/extensions.md +18 -0
- package/docs/keybindings.md +1 -1
- package/docs/quickstart.md +1 -1
- package/docs/rpc.md +23 -0
- package/docs/sdk.md +25 -0
- package/docs/settings.md +12 -4
- package/docs/terminal-setup.md +12 -0
- package/docs/usage.md +4 -3
- package/examples/extensions/built-in-tool-renderer.ts +8 -4
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/git-checkpoint.ts +24 -36
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/minimal-mode.ts +2 -2
- package/examples/extensions/permission-gate.ts +1 -1
- package/examples/extensions/plan-mode/index.ts +1 -1
- package/examples/extensions/rpc-demo.ts +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +194 -46
- package/package.json +14 -12
- package/dist/server/create-harness.d.ts +0 -26
- package/dist/server/create-harness.d.ts.map +0 -1
- package/dist/server/create-harness.js +0 -107
- package/dist/server/create-harness.js.map +0 -1
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* Modes use this class and add their own I/O layer on top.
|
|
14
14
|
*/
|
|
15
15
|
import { readFileSync } from "node:fs";
|
|
16
|
-
import { basename, dirname } from "node:path";
|
|
16
|
+
import { basename, dirname, isAbsolute, relative } from "node:path";
|
|
17
17
|
import { contentText } from "@earendil-works/pi-ai";
|
|
18
18
|
import { clampThinkingLevel, cleanupSessionResources, getSupportedThinkingLevels, isContextOverflow, isRecoverableLength, isRetryableAssistantError, modelsAreEqual, resetApiProviders, } from "@earendil-works/pi-ai/compat";
|
|
19
19
|
import { getThemeByName, theme } from "../modes/interactive/theme/theme.js";
|
|
@@ -22,6 +22,7 @@ import { sleep } from "../utils/sleep.js";
|
|
|
22
22
|
import { normalizeToolResultImages } from "../utils/tool-result-images.js";
|
|
23
23
|
import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage } from "./auth-guidance.js";
|
|
24
24
|
import { executeBashWithOperations } from "./bash-executor.js";
|
|
25
|
+
import { createSessionCheckpoints } from "./checkpoints/session-checkpoints.js";
|
|
25
26
|
import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, estimateTokens, generateBranchSummary, prepareCompaction, shouldCompact, } from "./compaction/index.js";
|
|
26
27
|
import { evictionBudget, installContextPipeline, isDefaultStreamFunction } from "./context/pipeline.js";
|
|
27
28
|
import { DEFAULT_THINKING_LEVEL, THINKING_LEVEL_OPTIONS } from "./defaults.js";
|
|
@@ -30,10 +31,13 @@ import { exportSessionToHtml } from "./export-html/index.js";
|
|
|
30
31
|
import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
|
|
31
32
|
import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
|
|
32
33
|
import { emitSessionShutdownEvent } from "./extensions/runner.js";
|
|
34
|
+
import { runFormatterCommand } from "./formatter-lifecycle.js";
|
|
33
35
|
import { ModelRegistry } from "./model-registry.js";
|
|
34
36
|
import { evaluateToolCall } from "./permissions/gate.js";
|
|
37
|
+
import { authorizeConfiguredCommand } from "./permissions/policy-command.js";
|
|
35
38
|
import { createInteractiveResponder } from "./permissions/responder.js";
|
|
36
39
|
import { resolveEffectiveModeWithOrigin } from "./permissions/startup.js";
|
|
40
|
+
import { loadPolicyConfiguration } from "./policy-loader.js";
|
|
37
41
|
import { expandPromptTemplate } from "./prompt-templates.js";
|
|
38
42
|
import { exportSessionToJsonl } from "./session-export.js";
|
|
39
43
|
import { getLatestCompactionEntry, TODO_CUSTOM_ENTRY_TYPE } from "./session-manager.js";
|
|
@@ -41,12 +45,18 @@ import { slugifySkillCommandName } from "./skills.js";
|
|
|
41
45
|
import { createSyntheticSourceInfo } from "./source-info.js";
|
|
42
46
|
import { buildSystemPrompt } from "./system-prompt.js";
|
|
43
47
|
import { createLocalBashOperations } from "./tools/bash.js";
|
|
48
|
+
import { buildToolContractSnapshot, isUnclassifiedTool, } from "./tools/contract-snapshot.js";
|
|
44
49
|
import { createAllToolDefinitions } from "./tools/index.js";
|
|
45
50
|
import { createSkillSearchToolDefinition } from "./tools/skill-search.js";
|
|
46
51
|
import { createTodoWriteToolDefinition } from "./tools/todo-write.js";
|
|
47
52
|
import { createToolDefinitionFromAgentTool } from "./tools/tool-definition-wrapper.js";
|
|
48
53
|
import { createToolSchemaToolDefinition } from "./tools/tool-schema.js";
|
|
49
54
|
import { addUsageToTotals, createUsageTotals } from "./usage-totals.js";
|
|
55
|
+
import { VerificationTracker, } from "./verification-lifecycle.js";
|
|
56
|
+
import { buildWorkspaceComparison, compareWorkspaceObservations } from "./workspace/comparison.js";
|
|
57
|
+
import { observeWorkspaceGit } from "./workspace/git-observer.js";
|
|
58
|
+
import { formatWorkspaceProjection } from "./workspace/projection.js";
|
|
59
|
+
import { appendWorkspaceComparison, appendWorkspaceObservation, findLatestWorkspaceObservation, hasWorkspaceObservationAwaitingComparison, } from "./workspace/state.js";
|
|
50
60
|
/**
|
|
51
61
|
* Parse a skill block from message text.
|
|
52
62
|
* Returns null if the text doesn't contain a skill block.
|
|
@@ -77,12 +87,6 @@ function estimateMessagesTokens(messages) {
|
|
|
77
87
|
}
|
|
78
88
|
return tokens;
|
|
79
89
|
}
|
|
80
|
-
// ============================================================================
|
|
81
|
-
// Constants
|
|
82
|
-
// ============================================================================
|
|
83
|
-
// ============================================================================
|
|
84
|
-
// AgentSession Class
|
|
85
|
-
// ============================================================================
|
|
86
90
|
export class AgentSession {
|
|
87
91
|
agent;
|
|
88
92
|
sessionManager;
|
|
@@ -100,10 +104,13 @@ export class AgentSession {
|
|
|
100
104
|
_followUpMessages = [];
|
|
101
105
|
/** Messages queued to be included with the next user prompt as context ("asides"). */
|
|
102
106
|
_pendingNextTurnMessages = [];
|
|
107
|
+
/** Context-only custom messages queued during a run, flushed once the current turn's tool results are in. */
|
|
108
|
+
_pendingCustomMessages = [];
|
|
103
109
|
// Compaction state
|
|
104
110
|
_compactionAbortController = undefined;
|
|
105
111
|
_autoCompactionAbortController = undefined;
|
|
106
112
|
_overflowRecoveryAttempted = false;
|
|
113
|
+
_midRunCompactionNeeded = false;
|
|
107
114
|
// Branch summarization state
|
|
108
115
|
_branchSummaryAbortController = undefined;
|
|
109
116
|
// Retry state
|
|
@@ -119,6 +126,21 @@ export class AgentSession {
|
|
|
119
126
|
_customTools;
|
|
120
127
|
_baseToolDefinitions = new Map();
|
|
121
128
|
_cwd;
|
|
129
|
+
/**
|
|
130
|
+
* Workspace observation adapter for compaction capture (WS.4). Injectable
|
|
131
|
+
* so tests can force capture outcomes without a real repository.
|
|
132
|
+
*/
|
|
133
|
+
_workspaceObserver = observeWorkspaceGit;
|
|
134
|
+
/**
|
|
135
|
+
* WS.5: one workspace comparison is due at the next model-turn boundary.
|
|
136
|
+
* Set after a compaction stored an observation, or on construction when
|
|
137
|
+
* the session's latest observation has no later comparison (resume).
|
|
138
|
+
*/
|
|
139
|
+
_workspaceComparePending = false;
|
|
140
|
+
/** VF.4: verification lifecycle state, built lazily from policy settings. */
|
|
141
|
+
_verificationTracker;
|
|
142
|
+
/** The workspace observation a verification result described, for staleness. */
|
|
143
|
+
_verificationBaseline;
|
|
122
144
|
_extensionRunnerRef;
|
|
123
145
|
_initialActiveToolNames;
|
|
124
146
|
_allowedToolNames;
|
|
@@ -129,6 +151,19 @@ export class AgentSession {
|
|
|
129
151
|
_evidenceSink;
|
|
130
152
|
_diagnosticsOperations;
|
|
131
153
|
_lspOperations;
|
|
154
|
+
_mcpRuntime;
|
|
155
|
+
/** Configured MCP subsystem, or undefined when no server is configured. */
|
|
156
|
+
get mcpRuntime() {
|
|
157
|
+
return this._mcpRuntime;
|
|
158
|
+
}
|
|
159
|
+
_checkpoints;
|
|
160
|
+
_hookRuntime;
|
|
161
|
+
_backgroundShellRegistry;
|
|
162
|
+
_permissionResponderFactory;
|
|
163
|
+
/** Worktree checkpoints for this session. Inert unless `checkpoints.enabled` is set. */
|
|
164
|
+
get checkpoints() {
|
|
165
|
+
return this._checkpoints;
|
|
166
|
+
}
|
|
132
167
|
_webSearchOperations;
|
|
133
168
|
_extensionUIContext;
|
|
134
169
|
_extensionMode = "print";
|
|
@@ -167,13 +202,33 @@ export class AgentSession {
|
|
|
167
202
|
this._evidenceSink = config.evidenceSink ?? new SessionEvidenceSink(this.sessionManager);
|
|
168
203
|
this._diagnosticsOperations = config.diagnosticsOperations;
|
|
169
204
|
this._lspOperations = config.lspOperations;
|
|
205
|
+
this._mcpRuntime = config.mcpRuntime;
|
|
170
206
|
this._webSearchOperations = config.webSearchOperations;
|
|
207
|
+
this._checkpoints = createSessionCheckpoints({
|
|
208
|
+
workspace: this._cwd,
|
|
209
|
+
sessionId: this.sessionManager.getSessionId(),
|
|
210
|
+
settings: config.checkpointSettings,
|
|
211
|
+
});
|
|
212
|
+
this._hookRuntime = config.hookRuntime;
|
|
213
|
+
this._backgroundShellRegistry = config.backgroundShellRegistry;
|
|
214
|
+
this._permissionResponderFactory = config.permissionResponderFactory;
|
|
215
|
+
this._workspaceComparePending = hasWorkspaceObservationAwaitingComparison(this.sessionManager);
|
|
171
216
|
// Always subscribe to agent events for internal handling
|
|
172
217
|
// (session persistence, extensions, auto-compaction, retry logic)
|
|
173
218
|
this._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);
|
|
174
219
|
this._installAgentToolHooks();
|
|
175
220
|
this._installAgentNextTurnRefresh();
|
|
221
|
+
this._installMidRunCompactionHook();
|
|
176
222
|
this._installContextPipeline();
|
|
223
|
+
// Declarative hooks: session_start is observe-only and must neither delay
|
|
224
|
+
// nor fail construction, so it fires detached (emitObserve swallows
|
|
225
|
+
// handler failures already).
|
|
226
|
+
if (this._hookRuntime?.hasHandlers("session_start")) {
|
|
227
|
+
void this._hookRuntime.emitObserve("session_start", {
|
|
228
|
+
type: "session_start",
|
|
229
|
+
reason: this._sessionStartEvent.reason,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
177
232
|
this._buildRuntime({
|
|
178
233
|
activeToolNames: this._initialActiveToolNames,
|
|
179
234
|
includeAllExtensionTools: true,
|
|
@@ -264,6 +319,20 @@ export class AgentSession {
|
|
|
264
319
|
if (extensionResult?.block === true)
|
|
265
320
|
return extensionResult;
|
|
266
321
|
}
|
|
322
|
+
// Declarative hooks (spec 2026-08-31-declarative-hooks) ride the same
|
|
323
|
+
// seam, after extensions and before the gate. Restriction-only: a block
|
|
324
|
+
// short-circuits, allow and ask fall through, and the gate below still
|
|
325
|
+
// evaluates the call, so a hook can narrow authority but never widen it.
|
|
326
|
+
if (this._hookRuntime?.hasHandlers("tool_call")) {
|
|
327
|
+
const hookBlock = await this._hookRuntime.decideToolCall(toolCall.name, {
|
|
328
|
+
type: "tool_call",
|
|
329
|
+
toolName: toolCall.name,
|
|
330
|
+
toolCallId: toolCall.id,
|
|
331
|
+
input: args,
|
|
332
|
+
});
|
|
333
|
+
if (hookBlock)
|
|
334
|
+
return { block: true, reason: hookBlock.reason };
|
|
335
|
+
}
|
|
267
336
|
// Permission gate (roadmap Phase 2a, ADR 0004). Off by default — see
|
|
268
337
|
// AgentSessionConfig.permissionGate. When present, every registered tool
|
|
269
338
|
// call passes through it (contracts.md invariant 2): this is the seam,
|
|
@@ -272,9 +341,10 @@ export class AgentSession {
|
|
|
272
341
|
const decision = await evaluateToolCall(toolCall.name, args, {
|
|
273
342
|
...this._permissionGate,
|
|
274
343
|
getContract: (name) => this.getToolDefinition(name)?.contract,
|
|
275
|
-
getResponder: () => this.
|
|
276
|
-
|
|
277
|
-
|
|
344
|
+
getResponder: () => this._permissionResponderFactory?.() ??
|
|
345
|
+
(this._extensionMode === "tui" && this._extensionUIContext
|
|
346
|
+
? createInteractiveResponder(this._extensionUIContext)
|
|
347
|
+
: undefined),
|
|
278
348
|
});
|
|
279
349
|
if (decision.block)
|
|
280
350
|
return { block: true, reason: decision.reason };
|
|
@@ -312,6 +382,16 @@ export class AgentSession {
|
|
|
312
382
|
usage: result.usage,
|
|
313
383
|
})
|
|
314
384
|
: undefined;
|
|
385
|
+
// Declarative hooks observe tool results after extension rewrites and
|
|
386
|
+
// before image normalization; no decision is read from them (spec).
|
|
387
|
+
if (this._hookRuntime?.hasHandlers("tool_result")) {
|
|
388
|
+
await this._hookRuntime.emitObserve("tool_result", {
|
|
389
|
+
type: "tool_result",
|
|
390
|
+
toolName: toolCall.name,
|
|
391
|
+
toolCallId: toolCall.id,
|
|
392
|
+
input: args,
|
|
393
|
+
});
|
|
394
|
+
}
|
|
315
395
|
const content = hookResult?.content ?? result.content ?? [];
|
|
316
396
|
// Runs after the extension hook so images injected or replaced by extensions are normalized too.
|
|
317
397
|
const normalizedContent = await normalizeToolResultImages(content, {
|
|
@@ -328,18 +408,33 @@ export class AgentSession {
|
|
|
328
408
|
};
|
|
329
409
|
};
|
|
330
410
|
}
|
|
411
|
+
async _compactBeforeNextAssistantResponse(context) {
|
|
412
|
+
const model = this.model;
|
|
413
|
+
const settings = this.settingsManager.getCompactionSettings();
|
|
414
|
+
if (!model ||
|
|
415
|
+
model.contextWindow <= 0 ||
|
|
416
|
+
!shouldCompact(estimateContextTokens(context.messages).tokens, model.contextWindow, settings)) {
|
|
417
|
+
return context;
|
|
418
|
+
}
|
|
419
|
+
await this._runAutoCompaction("threshold", false);
|
|
420
|
+
return {
|
|
421
|
+
...context,
|
|
422
|
+
messages: this.agent.state.messages.slice(),
|
|
423
|
+
};
|
|
424
|
+
}
|
|
331
425
|
_installAgentNextTurnRefresh() {
|
|
332
426
|
const previousPrepareNextTurnWithContext = this.agent.prepareNextTurnWithContext ??
|
|
333
427
|
(this.agent.prepareNextTurn
|
|
334
428
|
? async (_turn, signal) => await this.agent.prepareNextTurn?.(signal)
|
|
335
429
|
: undefined);
|
|
336
430
|
this.agent.prepareNextTurnWithContext = async (turn, signal) => {
|
|
337
|
-
const
|
|
338
|
-
const
|
|
431
|
+
const context = await this._compactBeforeNextAssistantResponse(turn.context);
|
|
432
|
+
const previousSnapshot = await previousPrepareNextTurnWithContext?.({ ...turn, context }, signal);
|
|
433
|
+
const nextContext = previousSnapshot?.context ?? context;
|
|
339
434
|
return {
|
|
340
435
|
...previousSnapshot,
|
|
341
436
|
context: {
|
|
342
|
-
...
|
|
437
|
+
...nextContext,
|
|
343
438
|
systemPrompt: this._systemPromptOverride ?? this._baseSystemPrompt,
|
|
344
439
|
tools: this.agent.state.tools.slice(),
|
|
345
440
|
},
|
|
@@ -348,6 +443,35 @@ export class AgentSession {
|
|
|
348
443
|
};
|
|
349
444
|
};
|
|
350
445
|
}
|
|
446
|
+
/** Stop an over-threshold tool loop before it sends another provider request. */
|
|
447
|
+
_installMidRunCompactionHook() {
|
|
448
|
+
const previousShouldStopAfterTurn = this.agent.shouldStopAfterTurn;
|
|
449
|
+
this.agent.shouldStopAfterTurn = async (turn, signal) => {
|
|
450
|
+
if (await previousShouldStopAfterTurn?.(turn, signal)) {
|
|
451
|
+
return true;
|
|
452
|
+
}
|
|
453
|
+
return this._shouldStopForMidRunCompaction(turn);
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
_shouldStopForMidRunCompaction(turn) {
|
|
457
|
+
if (!turn.hasMoreToolCalls || turn.toolResults.length === 0) {
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
const settings = this.settingsManager.getCompactionSettings();
|
|
461
|
+
if (!settings.enabled) {
|
|
462
|
+
return false;
|
|
463
|
+
}
|
|
464
|
+
const contextWindow = this.model?.contextWindow ?? 0;
|
|
465
|
+
if (contextWindow <= 0) {
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
const contextTokens = estimateContextTokens(turn.context.messages).tokens;
|
|
469
|
+
if (!shouldCompact(contextTokens, contextWindow, settings)) {
|
|
470
|
+
return false;
|
|
471
|
+
}
|
|
472
|
+
this._midRunCompactionNeeded = true;
|
|
473
|
+
return true;
|
|
474
|
+
}
|
|
351
475
|
/**
|
|
352
476
|
* Installs the context pipeline settled in `docs/architecture/contracts.md` § 2:
|
|
353
477
|
* deferred-schema resolution → tool-result eviction → compaction. Compaction
|
|
@@ -499,6 +623,14 @@ export class AgentSession {
|
|
|
499
623
|
}
|
|
500
624
|
}
|
|
501
625
|
}
|
|
626
|
+
// A turn ends after its assistant message and every tool result has been appended,
|
|
627
|
+
// so this is the first point in the run where a context-only custom message can be
|
|
628
|
+
// inserted without landing between a tool call and its result. Flushing after the
|
|
629
|
+
// extension and listener dispatch above also picks up messages that turn_end
|
|
630
|
+
// handlers queued.
|
|
631
|
+
if (event.type === "turn_end") {
|
|
632
|
+
this._flushPendingCustomMessages();
|
|
633
|
+
}
|
|
502
634
|
};
|
|
503
635
|
_willRetryAfterAgentEnd(event) {
|
|
504
636
|
const settings = this.settingsManager.getRetrySettings();
|
|
@@ -548,6 +680,18 @@ export class AgentSession {
|
|
|
548
680
|
await this._extensionRunner.emit({ type: "agent_end", messages: event.messages });
|
|
549
681
|
}
|
|
550
682
|
else if (event.type === "turn_start") {
|
|
683
|
+
// Snapshot before the model gets to act, keyed to the entry `/tree` and `/fork`
|
|
684
|
+
// already navigate to, so the two agree about what an entry means.
|
|
685
|
+
//
|
|
686
|
+
// Awaited, despite the turn latency. Detached, the snapshot races the turn it is
|
|
687
|
+
// supposed to precede: a tool call can edit the worktree while `add -A` is still
|
|
688
|
+
// walking it, and the ref then holds mid-turn state that no `/fork` should ever
|
|
689
|
+
// restore. "The state before the model acted" is the whole guarantee, so paying
|
|
690
|
+
// for it here is the point. The engine's own timeout bounds the wait and a failed
|
|
691
|
+
// capture is never fatal.
|
|
692
|
+
const leafEntryId = this.sessionManager.getLeafEntry()?.id;
|
|
693
|
+
if (leafEntryId)
|
|
694
|
+
await this._checkpoints.capture(leafEntryId);
|
|
551
695
|
const extensionEvent = {
|
|
552
696
|
type: "turn_start",
|
|
553
697
|
turnIndex: this._turnIndex,
|
|
@@ -563,6 +707,9 @@ export class AgentSession {
|
|
|
563
707
|
toolResults: event.toolResults,
|
|
564
708
|
};
|
|
565
709
|
await this._extensionRunner.emit(extensionEvent);
|
|
710
|
+
if (this._hookRuntime?.hasHandlers("turn_end")) {
|
|
711
|
+
await this._hookRuntime.emitObserve("turn_end", { type: "turn_end" });
|
|
712
|
+
}
|
|
566
713
|
this._turnIndex++;
|
|
567
714
|
}
|
|
568
715
|
else if (event.type === "message_start") {
|
|
@@ -662,6 +809,9 @@ export class AgentSession {
|
|
|
662
809
|
this.abortBranchSummary();
|
|
663
810
|
this.abortBash();
|
|
664
811
|
this.agent.abort();
|
|
812
|
+
// Background shell children (spec 2026-08-31-background-shell.md) must
|
|
813
|
+
// never outlive the session that launched them.
|
|
814
|
+
this._backgroundShellRegistry?.dispose();
|
|
665
815
|
}
|
|
666
816
|
catch {
|
|
667
817
|
// Dispose must succeed even if an abort hook throws.
|
|
@@ -669,6 +819,9 @@ export class AgentSession {
|
|
|
669
819
|
this._extensionRunner.invalidate("This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().");
|
|
670
820
|
this._disconnectFromAgent();
|
|
671
821
|
this._eventListeners = [];
|
|
822
|
+
// Every connected MCP server is a child process this session started. Without
|
|
823
|
+
// this, one leaks per server per session, because nothing else owns them.
|
|
824
|
+
this._mcpRuntime?.close().catch(() => undefined);
|
|
672
825
|
cleanupSessionResources(this.sessionId);
|
|
673
826
|
}
|
|
674
827
|
// =========================================================================
|
|
@@ -712,6 +865,13 @@ export class AgentSession {
|
|
|
712
865
|
/**
|
|
713
866
|
* Get all configured tools with name, description, parameter schema, prompt guidelines, and source metadata.
|
|
714
867
|
*/
|
|
868
|
+
/**
|
|
869
|
+
* The ADR 0010 projection over this session's registry: the one read every surface
|
|
870
|
+
* that *describes* the tool set consumes. Never an authorization input.
|
|
871
|
+
*/
|
|
872
|
+
getToolContractSnapshot() {
|
|
873
|
+
return buildToolContractSnapshot(Array.from(this._toolDefinitions.values()).map(({ definition }) => definition));
|
|
874
|
+
}
|
|
715
875
|
getAllTools() {
|
|
716
876
|
const schemaToolActive = this.getActiveToolNames().includes("tool_schema");
|
|
717
877
|
return Array.from(this._toolDefinitions.values())
|
|
@@ -722,7 +882,7 @@ export class AgentSession {
|
|
|
722
882
|
parameters: definition.parameters,
|
|
723
883
|
promptGuidelines: definition.promptGuidelines,
|
|
724
884
|
sourceInfo,
|
|
725
|
-
unclassified:
|
|
885
|
+
unclassified: isUnclassifiedTool(definition),
|
|
726
886
|
}));
|
|
727
887
|
}
|
|
728
888
|
getToolDefinition(name) {
|
|
@@ -858,10 +1018,15 @@ export class AgentSession {
|
|
|
858
1018
|
finally {
|
|
859
1019
|
this._systemPromptOverride = undefined;
|
|
860
1020
|
this._flushPendingBashMessages();
|
|
1021
|
+
this._flushPendingCustomMessages();
|
|
861
1022
|
await this._emitAgentSettled();
|
|
862
1023
|
}
|
|
863
1024
|
}
|
|
864
1025
|
async _handlePostAgentRun() {
|
|
1026
|
+
if (this._midRunCompactionNeeded) {
|
|
1027
|
+
this._midRunCompactionNeeded = false;
|
|
1028
|
+
return await this._runAutoCompaction("threshold", true);
|
|
1029
|
+
}
|
|
865
1030
|
const msg = this._lastAssistantMessage;
|
|
866
1031
|
this._lastAssistantMessage = undefined;
|
|
867
1032
|
if (!msg) {
|
|
@@ -947,8 +1112,9 @@ export class AgentSession {
|
|
|
947
1112
|
preflightResult?.(true);
|
|
948
1113
|
return;
|
|
949
1114
|
}
|
|
950
|
-
// Flush any pending bash messages before the new prompt
|
|
1115
|
+
// Flush any pending bash and custom messages before the new prompt
|
|
951
1116
|
this._flushPendingBashMessages();
|
|
1117
|
+
this._flushPendingCustomMessages();
|
|
952
1118
|
// Validate model
|
|
953
1119
|
if (!this.model) {
|
|
954
1120
|
throw new Error(formatNoModelSelectedMessage());
|
|
@@ -1022,7 +1188,9 @@ export class AgentSession {
|
|
|
1022
1188
|
return;
|
|
1023
1189
|
}
|
|
1024
1190
|
preflightResult?.(true);
|
|
1191
|
+
await this._runWorkspaceComparisonBoundary();
|
|
1025
1192
|
await this._runAgentPrompt(messages);
|
|
1193
|
+
await this._runVerificationTurnBoundary();
|
|
1026
1194
|
}
|
|
1027
1195
|
/**
|
|
1028
1196
|
* Try to execute an extension command. Returns true if command was found and executed.
|
|
@@ -1169,8 +1337,9 @@ export class AgentSession {
|
|
|
1169
1337
|
/**
|
|
1170
1338
|
* Send a custom message to the session. Creates a CustomMessageEntry.
|
|
1171
1339
|
*
|
|
1172
|
-
* Handles
|
|
1340
|
+
* Handles four cases:
|
|
1173
1341
|
* - Streaming: queues message, processed when loop pulls from queue
|
|
1342
|
+
* - Streaming + triggerTurn false: appended to state/session once the current turn ends
|
|
1174
1343
|
* - Not streaming + triggerTurn: appends to state/session, starts new turn
|
|
1175
1344
|
* - Not streaming + no trigger: appends to state/session, no turn
|
|
1176
1345
|
*
|
|
@@ -1202,11 +1371,34 @@ export class AgentSession {
|
|
|
1202
1371
|
else if (options?.triggerTurn) {
|
|
1203
1372
|
await this._runAgentPrompt(appMessage);
|
|
1204
1373
|
}
|
|
1374
|
+
else if (this.isStreaming) {
|
|
1375
|
+
// Appending now would put the message between an assistant tool call and its
|
|
1376
|
+
// result, which providers that validate message order reject on replay. Defer
|
|
1377
|
+
// to the end of the turn. Nothing is emitted yet: message events must not
|
|
1378
|
+
// describe messages the session tree does not contain.
|
|
1379
|
+
this._pendingCustomMessages.push(appMessage);
|
|
1380
|
+
}
|
|
1205
1381
|
else {
|
|
1206
|
-
this.
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1382
|
+
this._appendCustomMessage(appMessage);
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
_appendCustomMessage(appMessage) {
|
|
1386
|
+
this.agent.state.messages.push(appMessage);
|
|
1387
|
+
this.sessionManager.appendCustomMessageEntry(appMessage.customType, appMessage.content, appMessage.display, appMessage.details);
|
|
1388
|
+
this._emit({ type: "message_start", message: appMessage });
|
|
1389
|
+
this._emit({ type: "message_end", message: appMessage });
|
|
1390
|
+
}
|
|
1391
|
+
/**
|
|
1392
|
+
* Append custom messages queued while the agent was running.
|
|
1393
|
+
* Called once the current turn's tool results are in agent state and session history.
|
|
1394
|
+
*/
|
|
1395
|
+
_flushPendingCustomMessages() {
|
|
1396
|
+
if (this._pendingCustomMessages.length === 0)
|
|
1397
|
+
return;
|
|
1398
|
+
const pending = this._pendingCustomMessages;
|
|
1399
|
+
this._pendingCustomMessages = [];
|
|
1400
|
+
for (const appMessage of pending) {
|
|
1401
|
+
this._appendCustomMessage(appMessage);
|
|
1210
1402
|
}
|
|
1211
1403
|
}
|
|
1212
1404
|
/**
|
|
@@ -1345,6 +1537,7 @@ export class AgentSession {
|
|
|
1345
1537
|
this.sessionManager.appendModelChange(model.provider, model.id);
|
|
1346
1538
|
if (options.persist) {
|
|
1347
1539
|
this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
|
|
1540
|
+
this._addPersistedDefaultToNonEmptyScope(model);
|
|
1348
1541
|
}
|
|
1349
1542
|
// Apply thinking level for the new model.
|
|
1350
1543
|
// Per-model thinking level overrides take priority over the global default.
|
|
@@ -1352,6 +1545,20 @@ export class AgentSession {
|
|
|
1352
1545
|
this.setThinkingLevel(thinkingLevel);
|
|
1353
1546
|
await this._emitModelSelect(model, previousModel, "set");
|
|
1354
1547
|
}
|
|
1548
|
+
_addPersistedDefaultToNonEmptyScope(model) {
|
|
1549
|
+
if (this._scopedModels.length === 0)
|
|
1550
|
+
return;
|
|
1551
|
+
if (this._scopedModels.some((scoped) => modelsAreEqual(scoped.model, model)))
|
|
1552
|
+
return;
|
|
1553
|
+
this._scopedModels = [...this._scopedModels, { model }];
|
|
1554
|
+
const enabledModels = this.settingsManager.getEnabledModels();
|
|
1555
|
+
if (!enabledModels?.length)
|
|
1556
|
+
return;
|
|
1557
|
+
const modelReference = `${model.provider}/${model.id}`;
|
|
1558
|
+
if (enabledModels.some((pattern) => pattern.toLowerCase() === modelReference.toLowerCase()))
|
|
1559
|
+
return;
|
|
1560
|
+
this.settingsManager.setEnabledModels([...enabledModels, modelReference]);
|
|
1561
|
+
}
|
|
1355
1562
|
/**
|
|
1356
1563
|
* Cycle to next/previous model.
|
|
1357
1564
|
* Uses scoped models (from --models flag) if available, otherwise all available models.
|
|
@@ -1382,6 +1589,7 @@ export class AgentSession {
|
|
|
1382
1589
|
this.sessionManager.appendModelChange(next.model.provider, next.model.id);
|
|
1383
1590
|
if (options.persist) {
|
|
1384
1591
|
this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);
|
|
1592
|
+
this._addPersistedDefaultToNonEmptyScope(next.model);
|
|
1385
1593
|
}
|
|
1386
1594
|
// Apply thinking level for the new model.
|
|
1387
1595
|
// - Explicit scoped model thinking level overrides defaults
|
|
@@ -1408,6 +1616,7 @@ export class AgentSession {
|
|
|
1408
1616
|
this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);
|
|
1409
1617
|
if (options.persist) {
|
|
1410
1618
|
this.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);
|
|
1619
|
+
this._addPersistedDefaultToNonEmptyScope(nextModel);
|
|
1411
1620
|
}
|
|
1412
1621
|
// Apply thinking level for the new model.
|
|
1413
1622
|
// Model persistence does not implicitly rewrite the global thinking default.
|
|
@@ -1516,7 +1725,209 @@ export class AgentSession {
|
|
|
1516
1725
|
// Compaction
|
|
1517
1726
|
// =========================================================================
|
|
1518
1727
|
/** Generate Pi's built-in compaction summary for manual and automatic compaction. */
|
|
1728
|
+
/**
|
|
1729
|
+
* Attempt exactly one workspace observation for a compaction (spec
|
|
1730
|
+
* 2026-09-01-harness-correctness-and-workspace-state.md § 3 step 1).
|
|
1731
|
+
* Returns undefined when observation is impossible; never throws and
|
|
1732
|
+
* never fails the surrounding compaction.
|
|
1733
|
+
*/
|
|
1734
|
+
async _captureWorkspaceObservation(signal) {
|
|
1735
|
+
try {
|
|
1736
|
+
return await this._workspaceObserver(this._cwd, {
|
|
1737
|
+
signal,
|
|
1738
|
+
// The session's own state directory is harness bookkeeping, not
|
|
1739
|
+
// workspace content; observing it would report every turn as drift.
|
|
1740
|
+
excludePaths: this._sessionExclusionPaths(),
|
|
1741
|
+
});
|
|
1742
|
+
}
|
|
1743
|
+
catch {
|
|
1744
|
+
return undefined;
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
/** Session/artifact directories inside the workspace, relative paths. */
|
|
1748
|
+
_sessionExclusionPaths() {
|
|
1749
|
+
const exclusions = [];
|
|
1750
|
+
const sessionDir = this.sessionManager.getSessionDir();
|
|
1751
|
+
if (sessionDir) {
|
|
1752
|
+
const rel = relative(this._cwd, sessionDir);
|
|
1753
|
+
if (rel.length > 0 && !rel.startsWith("..") && !isAbsolute(rel))
|
|
1754
|
+
exclusions.push(rel);
|
|
1755
|
+
}
|
|
1756
|
+
// Harness runtime bookkeeping (auth, model store, durable state) is
|
|
1757
|
+
// not workspace content either: when the agent directory sits inside
|
|
1758
|
+
// the workspace, its runtime files would report every turn as drift.
|
|
1759
|
+
// Same rule and same name list the fork/workspace fingerprints use.
|
|
1760
|
+
const agentDir = this.settingsManager.getAgentDir();
|
|
1761
|
+
if (agentDir !== undefined) {
|
|
1762
|
+
const rel = relative(this._cwd, agentDir);
|
|
1763
|
+
if (rel === "") {
|
|
1764
|
+
exclusions.push("auth.json", "models-store.json", "state.sqlite");
|
|
1765
|
+
}
|
|
1766
|
+
else if (rel.length > 0 && !rel.startsWith("..") && !isAbsolute(rel)) {
|
|
1767
|
+
exclusions.push(rel);
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
return exclusions;
|
|
1771
|
+
}
|
|
1772
|
+
// ── VF.4: verification lifecycle (spec
|
|
1773
|
+
// 2026-09-01-configured-verification-and-formatting.md § 4) ──────────
|
|
1774
|
+
/**
|
|
1775
|
+
* Build (once) and refresh the tracker from the raw per-source policy
|
|
1776
|
+
* settings. ADR 0028: the loader consumes the sources separately and the
|
|
1777
|
+
* trust gate decides whether the project source exists at all.
|
|
1778
|
+
*/
|
|
1779
|
+
/**
|
|
1780
|
+
* PS.1. Configured commands reach the same permission authority tool calls
|
|
1781
|
+
* use. Undefined only when the session has no gate at all, which is the
|
|
1782
|
+
* documented SDK default; a gated session always authorizes.
|
|
1783
|
+
*/
|
|
1784
|
+
_authorizeConfiguredCommand() {
|
|
1785
|
+
const gate = this._permissionGate;
|
|
1786
|
+
if (gate === undefined)
|
|
1787
|
+
return undefined;
|
|
1788
|
+
return (operation) => authorizeConfiguredCommand(operation, {
|
|
1789
|
+
getMode: gate.getMode,
|
|
1790
|
+
getResponder: () => this._permissionResponderFactory?.() ??
|
|
1791
|
+
(this._extensionMode === "tui" && this._extensionUIContext
|
|
1792
|
+
? createInteractiveResponder(this._extensionUIContext)
|
|
1793
|
+
: undefined),
|
|
1794
|
+
});
|
|
1795
|
+
}
|
|
1796
|
+
_ensureVerificationTracker() {
|
|
1797
|
+
if (this._verificationTracker === undefined) {
|
|
1798
|
+
this._verificationTracker = new VerificationTracker({
|
|
1799
|
+
workspaceRoot: this._cwd,
|
|
1800
|
+
...(this._authorizeConfiguredCommand() !== undefined
|
|
1801
|
+
? { authorize: this._authorizeConfiguredCommand() }
|
|
1802
|
+
: {}),
|
|
1803
|
+
});
|
|
1804
|
+
}
|
|
1805
|
+
const snapshot = loadPolicyConfiguration({
|
|
1806
|
+
globalSettings: this.settingsManager.getGlobalSettings().policies,
|
|
1807
|
+
projectSettings: this.settingsManager.getProjectSettings().policies,
|
|
1808
|
+
projectTrusted: this.settingsManager.isProjectTrusted(),
|
|
1809
|
+
});
|
|
1810
|
+
const boundary = this.settingsManager.getPolicySettings()?.boundary === "post-turn" ? "post-turn" : "explicit";
|
|
1811
|
+
this._verificationTracker.configure(snapshot.verification, boundary);
|
|
1812
|
+
return this._verificationTracker;
|
|
1813
|
+
}
|
|
1814
|
+
/**
|
|
1815
|
+
* Run one configured verification policy now and report the resulting
|
|
1816
|
+
* completion status. Unavailable when nothing is configured; the
|
|
1817
|
+
* workspace observation after the run becomes the staleness baseline.
|
|
1818
|
+
*/
|
|
1819
|
+
async requestVerification(options = {}) {
|
|
1820
|
+
const tracker = this._ensureVerificationTracker();
|
|
1821
|
+
if (tracker.policyIds().length === 0) {
|
|
1822
|
+
return "unavailable";
|
|
1823
|
+
}
|
|
1824
|
+
const record = await tracker.runExplicit(options.policyId, { signal: options.signal });
|
|
1825
|
+
if (record !== undefined) {
|
|
1826
|
+
this._verificationBaseline = await this._captureWorkspaceObservation(options.signal);
|
|
1827
|
+
}
|
|
1828
|
+
return this.verificationStatus();
|
|
1829
|
+
}
|
|
1830
|
+
/**
|
|
1831
|
+
* VF.5: run one configured formatter policy now and report what it
|
|
1832
|
+
* actually mutated. Undefined when no formatter policy matches. Any real
|
|
1833
|
+
* mutation retires a prior verification record: the workspace the
|
|
1834
|
+
* verification described no longer exists.
|
|
1835
|
+
*/
|
|
1836
|
+
async runConfiguredFormatter(options = {}) {
|
|
1837
|
+
const snapshot = loadPolicyConfiguration({
|
|
1838
|
+
globalSettings: this.settingsManager.getGlobalSettings().policies,
|
|
1839
|
+
projectSettings: this.settingsManager.getProjectSettings().policies,
|
|
1840
|
+
projectTrusted: this.settingsManager.isProjectTrusted(),
|
|
1841
|
+
});
|
|
1842
|
+
const policy = options.policyId === undefined
|
|
1843
|
+
? snapshot.formatter[0]
|
|
1844
|
+
: snapshot.formatter.find((entry) => entry.id === options.policyId);
|
|
1845
|
+
if (policy === undefined)
|
|
1846
|
+
return undefined;
|
|
1847
|
+
const authorize = this._authorizeConfiguredCommand();
|
|
1848
|
+
const outcome = await runFormatterCommand(policy, {
|
|
1849
|
+
workspaceRoot: this._cwd,
|
|
1850
|
+
signal: options.signal,
|
|
1851
|
+
...(authorize !== undefined ? { authorize } : {}),
|
|
1852
|
+
});
|
|
1853
|
+
if (outcome.mutations.changedPaths.length > 0) {
|
|
1854
|
+
this._verificationTracker?.noteWorkspaceChange(new Set(outcome.mutations.changedPaths));
|
|
1855
|
+
}
|
|
1856
|
+
return outcome;
|
|
1857
|
+
}
|
|
1858
|
+
/** The current completion status: verified, failed, unavailable, interrupted, or continued-unverified. */
|
|
1859
|
+
verificationStatus() {
|
|
1860
|
+
return this._verificationTracker?.completionStatus() ?? "unavailable";
|
|
1861
|
+
}
|
|
1862
|
+
/** The live verification record with its bounded evidence, if any. */
|
|
1863
|
+
verificationRecord() {
|
|
1864
|
+
return this._verificationTracker?.latest();
|
|
1865
|
+
}
|
|
1866
|
+
/** Record that the user chose to finish without verification. */
|
|
1867
|
+
continueWithoutVerification() {
|
|
1868
|
+
this._ensureVerificationTracker().recordContinuedWithoutVerification();
|
|
1869
|
+
}
|
|
1870
|
+
/**
|
|
1871
|
+
* Turn boundary: retire a verification result the workspace has moved
|
|
1872
|
+
* past (conservatively — anything not provably "same" retires it), then
|
|
1873
|
+
* run the configured post-turn boundary. Never throws: verification is
|
|
1874
|
+
* advisory and the turn already completed.
|
|
1875
|
+
*/
|
|
1876
|
+
async _runVerificationTurnBoundary() {
|
|
1877
|
+
let tracker = this._verificationTracker;
|
|
1878
|
+
if (tracker === undefined) {
|
|
1879
|
+
tracker = this._ensureVerificationTracker();
|
|
1880
|
+
}
|
|
1881
|
+
try {
|
|
1882
|
+
if (tracker.latest() !== undefined) {
|
|
1883
|
+
const fresh = await this._captureWorkspaceObservation(undefined);
|
|
1884
|
+
if (this._verificationBaseline === undefined) {
|
|
1885
|
+
tracker.noteWorkspaceChange(new Set(["unbaseline"]));
|
|
1886
|
+
}
|
|
1887
|
+
else {
|
|
1888
|
+
const comparison = compareWorkspaceObservations(this._verificationBaseline, fresh);
|
|
1889
|
+
tracker.noteWorkspaceChange(comparison.result === "same" ? new Set() : new Set(["workspace-changed"]));
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
if (tracker.boundary === "post-turn" && tracker.policyIds().length > 0) {
|
|
1893
|
+
await tracker.runExplicit();
|
|
1894
|
+
this._verificationBaseline = await this._captureWorkspaceObservation(undefined);
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
catch {
|
|
1898
|
+
// Verification is advisory; the turn already completed.
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
/**
|
|
1902
|
+
* WS.5 (spec 2026-09-01-harness-correctness-and-workspace-state.md § 3):
|
|
1903
|
+
* at the first model turn after a compaction, or after resume onto a
|
|
1904
|
+
* session with an uncompared observation, compare fresh workspace state
|
|
1905
|
+
* against the stored observation once and persist the outcome. The
|
|
1906
|
+
* observation stays historical. Never throws: comparison problems must
|
|
1907
|
+
* not fail the user's turn.
|
|
1908
|
+
*/
|
|
1909
|
+
async _runWorkspaceComparisonBoundary() {
|
|
1910
|
+
if (!this._workspaceComparePending)
|
|
1911
|
+
return;
|
|
1912
|
+
this._workspaceComparePending = false;
|
|
1913
|
+
try {
|
|
1914
|
+
const baseline = findLatestWorkspaceObservation(this.sessionManager);
|
|
1915
|
+
if (!baseline)
|
|
1916
|
+
return;
|
|
1917
|
+
const fresh = await this._captureWorkspaceObservation(undefined);
|
|
1918
|
+
const outcome = compareWorkspaceObservations(baseline.record, fresh);
|
|
1919
|
+
appendWorkspaceComparison(this.sessionManager, buildWorkspaceComparison(baseline.record.observationId, outcome));
|
|
1920
|
+
}
|
|
1921
|
+
catch {
|
|
1922
|
+
// Comparison is advisory; the turn proceeds.
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1519
1925
|
async _runDefaultCompaction(preparation, requestModel, apiKey, headers, customInstructions, signal, env, reason) {
|
|
1926
|
+
// Maintenance budget (spec 2026-09-01-tool-reliability-and-execution-budgets.md):
|
|
1927
|
+
// a compaction summarization is context maintenance, not task progress. It is
|
|
1928
|
+
// recorded on the run's budget for observability and never consumes
|
|
1929
|
+
// maxProviderRequests.
|
|
1930
|
+
this.agent.recordMaintenanceRequest();
|
|
1520
1931
|
return compact(preparation, requestModel, apiKey, headers, customInstructions, signal, this.thinkingLevel, this.agent.streamFunction, env, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason }), undefined);
|
|
1521
1932
|
}
|
|
1522
1933
|
/**
|
|
@@ -1556,6 +1967,12 @@ export class AgentSession {
|
|
|
1556
1967
|
throw new Error("Nothing to compact (session too small)");
|
|
1557
1968
|
}
|
|
1558
1969
|
let extensionCompaction;
|
|
1970
|
+
if (this._hookRuntime?.hasHandlers("session_before_compact")) {
|
|
1971
|
+
await this._hookRuntime.emitObserve("session_before_compact", {
|
|
1972
|
+
type: "session_before_compact",
|
|
1973
|
+
reason: "manual",
|
|
1974
|
+
});
|
|
1975
|
+
}
|
|
1559
1976
|
if (this._extensionRunner.hasHandlers("session_before_compact")) {
|
|
1560
1977
|
const result = (await this._extensionRunner.emit({
|
|
1561
1978
|
type: "session_before_compact",
|
|
@@ -1579,6 +1996,12 @@ export class AgentSession {
|
|
|
1579
1996
|
let tokensBefore;
|
|
1580
1997
|
let usage;
|
|
1581
1998
|
let details;
|
|
1999
|
+
// One workspace observation attempt per compaction (spec
|
|
2000
|
+
// 2026-09-01-harness-correctness-and-workspace-state.md § 3),
|
|
2001
|
+
// before summary generation so the bounded projection can join
|
|
2002
|
+
// the model-facing summary. Capture problems never fail the
|
|
2003
|
+
// compaction.
|
|
2004
|
+
const workspaceRecord = await this._captureWorkspaceObservation(this._compactionAbortController?.signal ?? this._autoCompactionAbortController?.signal);
|
|
1582
2005
|
if (extensionCompaction) {
|
|
1583
2006
|
// Extension provided compaction content
|
|
1584
2007
|
summary = extensionCompaction.summary;
|
|
@@ -1595,11 +2018,28 @@ export class AgentSession {
|
|
|
1595
2018
|
tokensBefore = result.tokensBefore;
|
|
1596
2019
|
usage = result.usage;
|
|
1597
2020
|
details = result.details;
|
|
2021
|
+
if (workspaceRecord) {
|
|
2022
|
+
summary += `\n\n${formatWorkspaceProjection(workspaceRecord)}`;
|
|
2023
|
+
}
|
|
1598
2024
|
}
|
|
1599
2025
|
if (this._compactionAbortController.signal.aborted) {
|
|
1600
2026
|
throw new Error("Compaction cancelled");
|
|
1601
2027
|
}
|
|
1602
2028
|
this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension, usage);
|
|
2029
|
+
if (workspaceRecord) {
|
|
2030
|
+
try {
|
|
2031
|
+
// Historical record, child of the compaction entry; never in
|
|
2032
|
+
// the model context and never a rewrite of history.
|
|
2033
|
+
appendWorkspaceObservation(this.sessionManager, workspaceRecord);
|
|
2034
|
+
// WS.5: the next model turn compares fresh state against
|
|
2035
|
+
// this observation and records the drift outcome.
|
|
2036
|
+
this._workspaceComparePending = true;
|
|
2037
|
+
}
|
|
2038
|
+
catch {
|
|
2039
|
+
// Artifact/entry persistence problems downgrade the
|
|
2040
|
+
// workspace status; they never fail transcript compaction.
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
1603
2043
|
const newEntries = this.sessionManager.getEntries();
|
|
1604
2044
|
const sessionContext = this.sessionManager.buildSessionContext();
|
|
1605
2045
|
this.agent.state.messages = sessionContext.messages;
|
|
@@ -1817,6 +2257,9 @@ export class AgentSession {
|
|
|
1817
2257
|
this._autoCompactionAbortController = new AbortController();
|
|
1818
2258
|
started = true;
|
|
1819
2259
|
let extensionCompaction;
|
|
2260
|
+
if (this._hookRuntime?.hasHandlers("session_before_compact")) {
|
|
2261
|
+
await this._hookRuntime.emitObserve("session_before_compact", { type: "session_before_compact", reason });
|
|
2262
|
+
}
|
|
1820
2263
|
if (this._extensionRunner.hasHandlers("session_before_compact")) {
|
|
1821
2264
|
const extensionResult = (await this._extensionRunner.emit({
|
|
1822
2265
|
type: "session_before_compact",
|
|
@@ -1853,6 +2296,12 @@ export class AgentSession {
|
|
|
1853
2296
|
let tokensBefore;
|
|
1854
2297
|
let usage;
|
|
1855
2298
|
let details;
|
|
2299
|
+
// One workspace observation attempt per compaction (spec
|
|
2300
|
+
// 2026-09-01-harness-correctness-and-workspace-state.md § 3),
|
|
2301
|
+
// before summary generation so the bounded projection can join
|
|
2302
|
+
// the model-facing summary. Capture problems never fail the
|
|
2303
|
+
// compaction.
|
|
2304
|
+
const workspaceRecord = await this._captureWorkspaceObservation(this._compactionAbortController?.signal ?? this._autoCompactionAbortController?.signal);
|
|
1856
2305
|
if (extensionCompaction) {
|
|
1857
2306
|
// Extension provided compaction content
|
|
1858
2307
|
summary = extensionCompaction.summary;
|
|
@@ -1869,6 +2318,9 @@ export class AgentSession {
|
|
|
1869
2318
|
tokensBefore = compactResult.tokensBefore;
|
|
1870
2319
|
usage = compactResult.usage;
|
|
1871
2320
|
details = compactResult.details;
|
|
2321
|
+
if (workspaceRecord) {
|
|
2322
|
+
summary += `\n\n${formatWorkspaceProjection(workspaceRecord)}`;
|
|
2323
|
+
}
|
|
1872
2324
|
}
|
|
1873
2325
|
if (this._autoCompactionAbortController.signal.aborted) {
|
|
1874
2326
|
this._emit({
|
|
@@ -1887,6 +2339,20 @@ export class AgentSession {
|
|
|
1887
2339
|
return false;
|
|
1888
2340
|
}
|
|
1889
2341
|
this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension, usage);
|
|
2342
|
+
if (workspaceRecord) {
|
|
2343
|
+
try {
|
|
2344
|
+
// Historical record, child of the compaction entry; never in
|
|
2345
|
+
// the model context and never a rewrite of history.
|
|
2346
|
+
appendWorkspaceObservation(this.sessionManager, workspaceRecord);
|
|
2347
|
+
// WS.5: the next model turn compares fresh state against
|
|
2348
|
+
// this observation and records the drift outcome.
|
|
2349
|
+
this._workspaceComparePending = true;
|
|
2350
|
+
}
|
|
2351
|
+
catch {
|
|
2352
|
+
// Artifact/entry persistence problems downgrade the
|
|
2353
|
+
// workspace status; they never fail transcript compaction.
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
1890
2356
|
const newEntries = this.sessionManager.getEntries();
|
|
1891
2357
|
const sessionContext = this.sessionManager.buildSessionContext();
|
|
1892
2358
|
this.agent.state.messages = sessionContext.messages;
|
|
@@ -2260,10 +2726,15 @@ export class AgentSession {
|
|
|
2260
2726
|
]))
|
|
2261
2727
|
: createAllToolDefinitions(this._cwd, {
|
|
2262
2728
|
read: { autoResizeImages },
|
|
2263
|
-
bash: {
|
|
2729
|
+
bash: {
|
|
2730
|
+
commandPrefix: shellCommandPrefix,
|
|
2731
|
+
shellPath,
|
|
2732
|
+
backgroundRegistry: this._backgroundShellRegistry,
|
|
2733
|
+
},
|
|
2264
2734
|
edit: { diagnosticsOperations: this._diagnosticsOperations },
|
|
2265
2735
|
write: { diagnosticsOperations: this._diagnosticsOperations },
|
|
2266
2736
|
...(this._lspOperations ? { lsp: { operations: this._lspOperations } } : {}),
|
|
2737
|
+
...(this._mcpRuntime ? { mcp: this._mcpRuntime } : {}),
|
|
2267
2738
|
...(this._webSearchOperations ? { web_search: { operations: this._webSearchOperations } } : {}),
|
|
2268
2739
|
});
|
|
2269
2740
|
baseToolDefinitions.tool_schema = createToolSchemaToolDefinition({
|
|
@@ -2575,6 +3046,13 @@ export class AgentSession {
|
|
|
2575
3046
|
if (targetId === oldLeafId) {
|
|
2576
3047
|
return { cancelled: false };
|
|
2577
3048
|
}
|
|
3049
|
+
// WS.6 (spec 2026-09-01-harness-correctness-and-workspace-state.md § 4):
|
|
3050
|
+
// files move only under an explicit policy, and a refused or cancelled
|
|
3051
|
+
// restore leaves the conversation untouched too.
|
|
3052
|
+
const workspaceStep = await this._resolveTreeWorkspaceStep(targetId, options.workspacePolicy ?? "keep");
|
|
3053
|
+
if (workspaceStep.cancelled) {
|
|
3054
|
+
return { cancelled: true, workspace: workspaceStep.outcome };
|
|
3055
|
+
}
|
|
2578
3056
|
// Model required for summarization
|
|
2579
3057
|
if (options.summarize && !this.model) {
|
|
2580
3058
|
throw new Error("No model available for summarization");
|
|
@@ -2721,12 +3199,77 @@ export class AgentSession {
|
|
|
2721
3199
|
fromExtension: summaryText ? fromExtension : undefined,
|
|
2722
3200
|
});
|
|
2723
3201
|
// Emit to custom tools
|
|
2724
|
-
return { editorText, cancelled: false, summaryEntry };
|
|
3202
|
+
return { editorText, cancelled: false, summaryEntry, workspace: workspaceStep.outcome };
|
|
2725
3203
|
}
|
|
2726
3204
|
finally {
|
|
2727
3205
|
this._branchSummaryAbortController = undefined;
|
|
2728
3206
|
}
|
|
2729
3207
|
}
|
|
3208
|
+
/**
|
|
3209
|
+
* WS.6: resolve what navigation may do to the workspace before the
|
|
3210
|
+
* conversation moves. `keep` never touches files; `restore` overwrites
|
|
3211
|
+
* only through the engine's pinned pre-restore checkpoint; `fail-if-
|
|
3212
|
+
* drifted` and `cancel` refuse when the workspace moved; a missing
|
|
3213
|
+
* checkpoint leaves the workspace unchanged and says so. Never throws.
|
|
3214
|
+
*/
|
|
3215
|
+
async _resolveTreeWorkspaceStep(targetId, policy) {
|
|
3216
|
+
const unchanged = { policy, outcome: "unchanged", warnings: [] };
|
|
3217
|
+
if (policy === "keep")
|
|
3218
|
+
return { outcome: unchanged };
|
|
3219
|
+
try {
|
|
3220
|
+
const engine = await this._checkpoints.engine();
|
|
3221
|
+
if (!engine) {
|
|
3222
|
+
return {
|
|
3223
|
+
outcome: {
|
|
3224
|
+
policy,
|
|
3225
|
+
outcome: "missing-checkpoint",
|
|
3226
|
+
warnings: ["checkpoints are unavailable; workspace left unchanged"],
|
|
3227
|
+
},
|
|
3228
|
+
};
|
|
3229
|
+
}
|
|
3230
|
+
const checkpoint = await engine.lookup(targetId);
|
|
3231
|
+
if (!checkpoint)
|
|
3232
|
+
return { outcome: { policy, outcome: "missing-checkpoint", warnings: [] } };
|
|
3233
|
+
const matches = await engine.matchesWorktree(checkpoint);
|
|
3234
|
+
if (matches === undefined) {
|
|
3235
|
+
return {
|
|
3236
|
+
outcome: {
|
|
3237
|
+
policy,
|
|
3238
|
+
outcome: "failed",
|
|
3239
|
+
warnings: ["could not compare the workspace against the checkpoint"],
|
|
3240
|
+
},
|
|
3241
|
+
};
|
|
3242
|
+
}
|
|
3243
|
+
if (matches)
|
|
3244
|
+
return { outcome: unchanged };
|
|
3245
|
+
if (policy === "fail-if-drifted" || policy === "cancel") {
|
|
3246
|
+
return { cancelled: true, outcome: { policy, outcome: "refused-drifted", warnings: [] } };
|
|
3247
|
+
}
|
|
3248
|
+
const preRestore = await engine.restore(checkpoint);
|
|
3249
|
+
if (!preRestore) {
|
|
3250
|
+
return {
|
|
3251
|
+
outcome: { policy, outcome: "failed", warnings: ["restore failed; workspace left unchanged"] },
|
|
3252
|
+
};
|
|
3253
|
+
}
|
|
3254
|
+
return {
|
|
3255
|
+
outcome: {
|
|
3256
|
+
policy,
|
|
3257
|
+
outcome: "restored",
|
|
3258
|
+
preRestoreCheckpoint: { entryId: preRestore.entryId, commit: preRestore.commit },
|
|
3259
|
+
warnings: [],
|
|
3260
|
+
},
|
|
3261
|
+
};
|
|
3262
|
+
}
|
|
3263
|
+
catch (error) {
|
|
3264
|
+
return {
|
|
3265
|
+
outcome: {
|
|
3266
|
+
policy,
|
|
3267
|
+
outcome: "failed",
|
|
3268
|
+
warnings: [`workspace policy check failed: ${error instanceof Error ? error.message : String(error)}`],
|
|
3269
|
+
},
|
|
3270
|
+
};
|
|
3271
|
+
}
|
|
3272
|
+
}
|
|
2730
3273
|
/**
|
|
2731
3274
|
* Get all user messages from session for fork selector.
|
|
2732
3275
|
*/
|