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
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { takeOverStdout } from "../../core/output-guard.js";
|
|
3
|
+
import { attachJsonlLineReader, serializeJsonLine } from "../rpc/jsonl.js";
|
|
4
|
+
import { translateJsonEvent } from "./translate.js";
|
|
5
|
+
const PERMISSION_OPTIONS = [
|
|
6
|
+
{ optionId: "allow-once", name: "Allow once", kind: "allow_once" },
|
|
7
|
+
// `optionId` and `kind` are the wire contract; only the display name is ours to fix.
|
|
8
|
+
// The gate writes this to `session`, so "always" was never true.
|
|
9
|
+
{ optionId: "allow-always", name: "Allow for this session", kind: "allow_always" },
|
|
10
|
+
{ optionId: "reject-once", name: "Reject", kind: "reject_once" },
|
|
11
|
+
{ optionId: "reject-always", name: "Reject always", kind: "reject_always" },
|
|
12
|
+
];
|
|
13
|
+
export class AcpServer {
|
|
14
|
+
#input;
|
|
15
|
+
#output;
|
|
16
|
+
#host;
|
|
17
|
+
#pendingPermissions = new Map();
|
|
18
|
+
#seenToolCalls = new Set();
|
|
19
|
+
#currentSessionId;
|
|
20
|
+
constructor(deps) {
|
|
21
|
+
this.#input = deps.input;
|
|
22
|
+
this.#output = deps.output;
|
|
23
|
+
this.#host = deps.host;
|
|
24
|
+
}
|
|
25
|
+
start() {
|
|
26
|
+
attachJsonlLineReader(this.#input, (line) => this.handleLine(line));
|
|
27
|
+
}
|
|
28
|
+
get currentSessionId() {
|
|
29
|
+
return this.#currentSessionId;
|
|
30
|
+
}
|
|
31
|
+
handleLine(line) {
|
|
32
|
+
let parsed;
|
|
33
|
+
try {
|
|
34
|
+
parsed = JSON.parse(line);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// ACP is line-delimited JSON; anything else on the wire is dropped, not fatal.
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
41
|
+
return;
|
|
42
|
+
const message = parsed;
|
|
43
|
+
const { id, method, params } = message;
|
|
44
|
+
if (typeof method !== "string") {
|
|
45
|
+
// No method: a response to one of our server->client requests (permission).
|
|
46
|
+
if (id !== undefined)
|
|
47
|
+
this.#resolvePermission(String(id), message.result);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (id === undefined) {
|
|
51
|
+
if (method === "session/cancel") {
|
|
52
|
+
void this.#host.getSession().abort();
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
void this.#dispatch(id, method, params);
|
|
57
|
+
}
|
|
58
|
+
/** Entry point for live session events; translates and emits session/update. */
|
|
59
|
+
onSessionEvent(event) {
|
|
60
|
+
if (this.#currentSessionId === undefined)
|
|
61
|
+
return;
|
|
62
|
+
const translated = translateJsonEvent(event);
|
|
63
|
+
if (!translated)
|
|
64
|
+
return;
|
|
65
|
+
if (translated.kind === "message") {
|
|
66
|
+
this.#notify(this.#currentSessionId, translated.update);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const seen = this.#seenToolCalls.has(translated.toolCallId);
|
|
70
|
+
this.#seenToolCalls.add(translated.toolCallId);
|
|
71
|
+
this.#notify(this.#currentSessionId, {
|
|
72
|
+
sessionUpdate: seen ? "tool_call_update" : "tool_call",
|
|
73
|
+
...translated.update,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The PermissionResponder bridge: turns one ACP permission round trip into
|
|
78
|
+
* the gate's answer shape. Rule persistence itself stays in the gate
|
|
79
|
+
* (ADR 0010) -- `persist` is a request, not a written rule.
|
|
80
|
+
*/
|
|
81
|
+
/**
|
|
82
|
+
* `canPersistSession` mirrors the gate's `sessionScope`. When the tool's
|
|
83
|
+
* `ruleForCall()` yields nothing, the gate has no rule to write, so neither
|
|
84
|
+
* standing choice can keep its promise and neither is offered.
|
|
85
|
+
*/
|
|
86
|
+
askPermission(sessionId, toolName, description, canPersistSession = true) {
|
|
87
|
+
const id = `perm_${randomUUID()}`;
|
|
88
|
+
return new Promise((resolve) => {
|
|
89
|
+
this.#pendingPermissions.set(id, resolve);
|
|
90
|
+
this.#write({
|
|
91
|
+
jsonrpc: "2.0",
|
|
92
|
+
id,
|
|
93
|
+
method: "session/request_permission",
|
|
94
|
+
params: {
|
|
95
|
+
sessionId,
|
|
96
|
+
toolCall: { toolCallId: id, title: `${toolName}: ${description}`, kind: "other", status: "pending" },
|
|
97
|
+
// Both standing choices need a rule to stand on. Offering either when
|
|
98
|
+
// ruleForCall() yields nothing promises a decision that outlives the
|
|
99
|
+
// call and then does not.
|
|
100
|
+
options: canPersistSession
|
|
101
|
+
? PERMISSION_OPTIONS
|
|
102
|
+
: PERMISSION_OPTIONS.filter((option) => option.kind !== "allow_always" && option.kind !== "reject_always"),
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
#write(value) {
|
|
108
|
+
this.#output.write(serializeJsonLine(value));
|
|
109
|
+
}
|
|
110
|
+
#notify(sessionId, update) {
|
|
111
|
+
this.#write({ jsonrpc: "2.0", method: "session/update", params: { sessionId, update } });
|
|
112
|
+
}
|
|
113
|
+
#resolvePermission(id, result) {
|
|
114
|
+
const resolve = this.#pendingPermissions.get(id);
|
|
115
|
+
if (!resolve)
|
|
116
|
+
return;
|
|
117
|
+
this.#pendingPermissions.delete(id);
|
|
118
|
+
const outcome = result?.outcome;
|
|
119
|
+
if (outcome?.outcome !== "selected" || typeof outcome.optionId !== "string") {
|
|
120
|
+
// Cancelled, malformed, or unknown -- fail closed.
|
|
121
|
+
resolve({ allow: false });
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (outcome.optionId.startsWith("allow")) {
|
|
125
|
+
resolve({ allow: true, persist: outcome.optionId === "allow-always" });
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
resolve({ allow: false, persist: outcome.optionId === "reject-always" });
|
|
129
|
+
}
|
|
130
|
+
async #dispatch(id, method, params) {
|
|
131
|
+
const record = (typeof params === "object" && params !== null ? params : {});
|
|
132
|
+
try {
|
|
133
|
+
switch (method) {
|
|
134
|
+
case "initialize": {
|
|
135
|
+
this.#write({
|
|
136
|
+
jsonrpc: "2.0",
|
|
137
|
+
id,
|
|
138
|
+
result: {
|
|
139
|
+
protocolVersion: 1,
|
|
140
|
+
agentCapabilities: { loadSession: true },
|
|
141
|
+
promptCapabilities: { image: false, audio: false, embeddedContext: false },
|
|
142
|
+
agentInfo: { name: "apex-code", title: "Apex Code" },
|
|
143
|
+
authMethods: [],
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
case "session/new": {
|
|
149
|
+
const cwd = typeof record.cwd === "string" ? record.cwd : process.cwd();
|
|
150
|
+
// The host rebinds its live session; the returned session is driven
|
|
151
|
+
// through host.getSession() afterwards.
|
|
152
|
+
await this.#host.createSession(cwd);
|
|
153
|
+
this.#currentSessionId = `sess_${randomUUID()}`;
|
|
154
|
+
this.#seenToolCalls.clear();
|
|
155
|
+
this.#write({ jsonrpc: "2.0", id, result: { sessionId: this.#currentSessionId } });
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
case "session/load": {
|
|
159
|
+
const sessionId = typeof record.sessionId === "string" ? record.sessionId : "";
|
|
160
|
+
const cwd = typeof record.cwd === "string" ? record.cwd : process.cwd();
|
|
161
|
+
await this.#host.loadSession(sessionId, cwd);
|
|
162
|
+
this.#currentSessionId = sessionId;
|
|
163
|
+
this.#seenToolCalls.clear();
|
|
164
|
+
// History replay is deferred (plan, ACP.2): the session reattaches
|
|
165
|
+
// and continues, but prior entries are not streamed in v1.
|
|
166
|
+
this.#write({ jsonrpc: "2.0", id, result: null });
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
case "session/prompt": {
|
|
170
|
+
if (this.#currentSessionId === undefined || record.sessionId !== this.#currentSessionId) {
|
|
171
|
+
this.#write({
|
|
172
|
+
jsonrpc: "2.0",
|
|
173
|
+
id,
|
|
174
|
+
error: { code: -32002, message: "Unknown session; call session/new first" },
|
|
175
|
+
});
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const prompt = Array.isArray(record.prompt) ? record.prompt : [];
|
|
179
|
+
const text = prompt
|
|
180
|
+
.filter((block) => {
|
|
181
|
+
const candidate = block;
|
|
182
|
+
return candidate.type === "text" && typeof candidate.text === "string";
|
|
183
|
+
})
|
|
184
|
+
.map((block) => block.text)
|
|
185
|
+
.join("\n");
|
|
186
|
+
try {
|
|
187
|
+
await this.#host.getSession().prompt(text, { source: "acp" });
|
|
188
|
+
this.#write({ jsonrpc: "2.0", id, result: { stopReason: "end_turn" } });
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
const messageText = error instanceof Error ? error.message : String(error);
|
|
192
|
+
if (/abort/i.test(messageText)) {
|
|
193
|
+
this.#write({ jsonrpc: "2.0", id, result: { stopReason: "cancelled" } });
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
throw error;
|
|
197
|
+
}
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
case "session/set_mode": {
|
|
201
|
+
const mode = typeof record.mode === "string" ? record.mode : "";
|
|
202
|
+
await this.#host.setMode?.(mode);
|
|
203
|
+
this.#write({ jsonrpc: "2.0", id, result: {} });
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
default:
|
|
207
|
+
this.#write({ jsonrpc: "2.0", id, error: { code: -32601, message: `Method not found: ${method}` } });
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
this.#write({
|
|
212
|
+
jsonrpc: "2.0",
|
|
213
|
+
id,
|
|
214
|
+
error: { code: -32000, message: error instanceof Error ? error.message : String(error) },
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Run in ACP mode: ACP v1 agent over stdio for the runtime's session. ACP owns
|
|
221
|
+
* stdout from here on (output guard takes it over).
|
|
222
|
+
*/
|
|
223
|
+
export async function runAcpMode(runtime, bridge) {
|
|
224
|
+
takeOverStdout();
|
|
225
|
+
const host = {
|
|
226
|
+
getSession: () => runtime.session,
|
|
227
|
+
createSession: async () => {
|
|
228
|
+
await runtime.newSession();
|
|
229
|
+
return runtime.session;
|
|
230
|
+
},
|
|
231
|
+
loadSession: async () => runtime.session,
|
|
232
|
+
setMode: async (mode) => {
|
|
233
|
+
await runtime.session.setPermissionMode(mode);
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
const server = new AcpServer({ input: process.stdin, output: process.stdout, host });
|
|
237
|
+
if (bridge)
|
|
238
|
+
bridge.current = server;
|
|
239
|
+
runtime.session.subscribe((event) => server.onSessionEvent(event));
|
|
240
|
+
server.start();
|
|
241
|
+
// The ACP connection owns the process lifetime; it ends when stdin closes.
|
|
242
|
+
return new Promise(() => { });
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/modes/acp/server.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { Readable, Writable } from \"node:stream\";\nimport type { AgentSessionRuntime } from \"../../core/agent-session-runtime.ts\";\nimport type { InputSource } from \"../../core/extensions/types.ts\";\nimport { takeOverStdout } from \"../../core/output-guard.ts\";\nimport type { PermissionAnswer } from \"../../core/permissions/responder.ts\";\nimport { attachJsonlLineReader, serializeJsonLine } from \"../rpc/jsonl.ts\";\nimport { translateJsonEvent } from \"./translate.ts\";\n\n/**\n * The ACP server (spec 2026-08-31-acp-adapter.md): an in-process ACP v1 agent\n * over newline-delimited JSON-RPC on stdio. The host adapters between the\n * protocol and the live AgentSession; the server never imports session types,\n * so tests drive it entirely through fakes.\n */\n\n/** The slice of AgentSession the protocol actually drives. */\nexport interface AcpPromptableSession {\n\tprompt(text: string, options: { source: InputSource }): Promise<unknown>;\n\tabort(): Promise<void> | void;\n}\n\nexport interface AcpHost {\n\tgetSession(): AcpPromptableSession;\n\tcreateSession(cwd: string): Promise<AcpPromptableSession>;\n\tloadSession(sessionId: string, cwd: string): Promise<AcpPromptableSession>;\n\tsetMode?(mode: string): Promise<void> | void;\n}\n\nconst PERMISSION_OPTIONS = [\n\t{ optionId: \"allow-once\", name: \"Allow once\", kind: \"allow_once\" },\n\t// `optionId` and `kind` are the wire contract; only the display name is ours to fix.\n\t// The gate writes this to `session`, so \"always\" was never true.\n\t{ optionId: \"allow-always\", name: \"Allow for this session\", kind: \"allow_always\" },\n\t{ optionId: \"reject-once\", name: \"Reject\", kind: \"reject_once\" },\n\t{ optionId: \"reject-always\", name: \"Reject always\", kind: \"reject_always\" },\n] as const;\n\nexport class AcpServer {\n\treadonly #input: Readable;\n\treadonly #output: Writable;\n\treadonly #host: AcpHost;\n\treadonly #pendingPermissions = new Map<string, (answer: PermissionAnswer) => void>();\n\treadonly #seenToolCalls = new Set<string>();\n\t#currentSessionId: string | undefined;\n\n\tconstructor(deps: { input: Readable; output: Writable; host: AcpHost }) {\n\t\tthis.#input = deps.input;\n\t\tthis.#output = deps.output;\n\t\tthis.#host = deps.host;\n\t}\n\n\tstart(): void {\n\t\tattachJsonlLineReader(this.#input, (line) => this.handleLine(line));\n\t}\n\n\tget currentSessionId(): string | undefined {\n\t\treturn this.#currentSessionId;\n\t}\n\n\thandleLine(line: string): void {\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = JSON.parse(line);\n\t\t} catch {\n\t\t\t// ACP is line-delimited JSON; anything else on the wire is dropped, not fatal.\n\t\t\treturn;\n\t\t}\n\t\tif (typeof parsed !== \"object\" || parsed === null) return;\n\t\tconst message = parsed as Record<string, unknown>;\n\t\tconst { id, method, params } = message;\n\n\t\tif (typeof method !== \"string\") {\n\t\t\t// No method: a response to one of our server->client requests (permission).\n\t\t\tif (id !== undefined) this.#resolvePermission(String(id), message.result);\n\t\t\treturn;\n\t\t}\n\t\tif (id === undefined) {\n\t\t\tif (method === \"session/cancel\") {\n\t\t\t\tvoid this.#host.getSession().abort();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tvoid this.#dispatch(id, method, params);\n\t}\n\n\t/** Entry point for live session events; translates and emits session/update. */\n\tonSessionEvent(event: unknown): void {\n\t\tif (this.#currentSessionId === undefined) return;\n\t\tconst translated = translateJsonEvent(event);\n\t\tif (!translated) return;\n\t\tif (translated.kind === \"message\") {\n\t\t\tthis.#notify(this.#currentSessionId, translated.update);\n\t\t\treturn;\n\t\t}\n\t\tconst seen = this.#seenToolCalls.has(translated.toolCallId);\n\t\tthis.#seenToolCalls.add(translated.toolCallId);\n\t\tthis.#notify(this.#currentSessionId, {\n\t\t\tsessionUpdate: seen ? \"tool_call_update\" : \"tool_call\",\n\t\t\t...translated.update,\n\t\t});\n\t}\n\n\t/**\n\t * The PermissionResponder bridge: turns one ACP permission round trip into\n\t * the gate's answer shape. Rule persistence itself stays in the gate\n\t * (ADR 0010) -- `persist` is a request, not a written rule.\n\t */\n\t/**\n\t * `canPersistSession` mirrors the gate's `sessionScope`. When the tool's\n\t * `ruleForCall()` yields nothing, the gate has no rule to write, so neither\n\t * standing choice can keep its promise and neither is offered.\n\t */\n\taskPermission(\n\t\tsessionId: string,\n\t\ttoolName: string,\n\t\tdescription: string,\n\t\tcanPersistSession = true,\n\t): Promise<PermissionAnswer> {\n\t\tconst id = `perm_${randomUUID()}`;\n\t\treturn new Promise<PermissionAnswer>((resolve) => {\n\t\t\tthis.#pendingPermissions.set(id, resolve);\n\t\t\tthis.#write({\n\t\t\t\tjsonrpc: \"2.0\",\n\t\t\t\tid,\n\t\t\t\tmethod: \"session/request_permission\",\n\t\t\t\tparams: {\n\t\t\t\t\tsessionId,\n\t\t\t\t\ttoolCall: { toolCallId: id, title: `${toolName}: ${description}`, kind: \"other\", status: \"pending\" },\n\t\t\t\t\t// Both standing choices need a rule to stand on. Offering either when\n\t\t\t\t\t// ruleForCall() yields nothing promises a decision that outlives the\n\t\t\t\t\t// call and then does not.\n\t\t\t\t\toptions: canPersistSession\n\t\t\t\t\t\t? PERMISSION_OPTIONS\n\t\t\t\t\t\t: PERMISSION_OPTIONS.filter(\n\t\t\t\t\t\t\t\t(option) => option.kind !== \"allow_always\" && option.kind !== \"reject_always\",\n\t\t\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t}\n\n\t#write(value: unknown): void {\n\t\tthis.#output.write(serializeJsonLine(value));\n\t}\n\n\t#notify(sessionId: string, update: Record<string, unknown>): void {\n\t\tthis.#write({ jsonrpc: \"2.0\", method: \"session/update\", params: { sessionId, update } });\n\t}\n\n\t#resolvePermission(id: string, result: unknown): void {\n\t\tconst resolve = this.#pendingPermissions.get(id);\n\t\tif (!resolve) return;\n\t\tthis.#pendingPermissions.delete(id);\n\t\tconst outcome = (result as { outcome?: { outcome?: string; optionId?: string } } | undefined)?.outcome;\n\t\tif (outcome?.outcome !== \"selected\" || typeof outcome.optionId !== \"string\") {\n\t\t\t// Cancelled, malformed, or unknown -- fail closed.\n\t\t\tresolve({ allow: false });\n\t\t\treturn;\n\t\t}\n\t\tif (outcome.optionId.startsWith(\"allow\")) {\n\t\t\tresolve({ allow: true, persist: outcome.optionId === \"allow-always\" });\n\t\t\treturn;\n\t\t}\n\t\tresolve({ allow: false, persist: outcome.optionId === \"reject-always\" });\n\t}\n\n\tasync #dispatch(id: unknown, method: string, params: unknown): Promise<void> {\n\t\tconst record = (typeof params === \"object\" && params !== null ? params : {}) as Record<string, unknown>;\n\t\ttry {\n\t\t\tswitch (method) {\n\t\t\t\tcase \"initialize\": {\n\t\t\t\t\tthis.#write({\n\t\t\t\t\t\tjsonrpc: \"2.0\",\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tresult: {\n\t\t\t\t\t\t\tprotocolVersion: 1,\n\t\t\t\t\t\t\tagentCapabilities: { loadSession: true },\n\t\t\t\t\t\t\tpromptCapabilities: { image: false, audio: false, embeddedContext: false },\n\t\t\t\t\t\t\tagentInfo: { name: \"apex-code\", title: \"Apex Code\" },\n\t\t\t\t\t\t\tauthMethods: [],\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcase \"session/new\": {\n\t\t\t\t\tconst cwd = typeof record.cwd === \"string\" ? record.cwd : process.cwd();\n\t\t\t\t\t// The host rebinds its live session; the returned session is driven\n\t\t\t\t\t// through host.getSession() afterwards.\n\t\t\t\t\tawait this.#host.createSession(cwd);\n\t\t\t\t\tthis.#currentSessionId = `sess_${randomUUID()}`;\n\t\t\t\t\tthis.#seenToolCalls.clear();\n\t\t\t\t\tthis.#write({ jsonrpc: \"2.0\", id, result: { sessionId: this.#currentSessionId } });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcase \"session/load\": {\n\t\t\t\t\tconst sessionId = typeof record.sessionId === \"string\" ? record.sessionId : \"\";\n\t\t\t\t\tconst cwd = typeof record.cwd === \"string\" ? record.cwd : process.cwd();\n\t\t\t\t\tawait this.#host.loadSession(sessionId, cwd);\n\t\t\t\t\tthis.#currentSessionId = sessionId;\n\t\t\t\t\tthis.#seenToolCalls.clear();\n\t\t\t\t\t// History replay is deferred (plan, ACP.2): the session reattaches\n\t\t\t\t\t// and continues, but prior entries are not streamed in v1.\n\t\t\t\t\tthis.#write({ jsonrpc: \"2.0\", id, result: null });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcase \"session/prompt\": {\n\t\t\t\t\tif (this.#currentSessionId === undefined || record.sessionId !== this.#currentSessionId) {\n\t\t\t\t\t\tthis.#write({\n\t\t\t\t\t\t\tjsonrpc: \"2.0\",\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\terror: { code: -32002, message: \"Unknown session; call session/new first\" },\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst prompt = Array.isArray(record.prompt) ? record.prompt : [];\n\t\t\t\t\tconst text = prompt\n\t\t\t\t\t\t.filter((block): block is { type: \"text\"; text: string } => {\n\t\t\t\t\t\t\tconst candidate = block as { type?: string; text?: string };\n\t\t\t\t\t\t\treturn candidate.type === \"text\" && typeof candidate.text === \"string\";\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.map((block) => block.text)\n\t\t\t\t\t\t.join(\"\\n\");\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this.#host.getSession().prompt(text, { source: \"acp\" });\n\t\t\t\t\t\tthis.#write({ jsonrpc: \"2.0\", id, result: { stopReason: \"end_turn\" } });\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tconst messageText = error instanceof Error ? error.message : String(error);\n\t\t\t\t\t\tif (/abort/i.test(messageText)) {\n\t\t\t\t\t\t\tthis.#write({ jsonrpc: \"2.0\", id, result: { stopReason: \"cancelled\" } });\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcase \"session/set_mode\": {\n\t\t\t\t\tconst mode = typeof record.mode === \"string\" ? record.mode : \"\";\n\t\t\t\t\tawait this.#host.setMode?.(mode);\n\t\t\t\t\tthis.#write({ jsonrpc: \"2.0\", id, result: {} });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tthis.#write({ jsonrpc: \"2.0\", id, error: { code: -32601, message: `Method not found: ${method}` } });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.#write({\n\t\t\t\tjsonrpc: \"2.0\",\n\t\t\t\tid,\n\t\t\t\terror: { code: -32000, message: error instanceof Error ? error.message : String(error) },\n\t\t\t});\n\t\t}\n\t}\n}\n\n/**\n * Run in ACP mode: ACP v1 agent over stdio for the runtime's session. ACP owns\n * stdout from here on (output guard takes it over).\n */\nexport async function runAcpMode(runtime: AgentSessionRuntime, bridge?: { current?: AcpServer }): Promise<never> {\n\ttakeOverStdout();\n\tconst host: AcpHost = {\n\t\tgetSession: () => runtime.session,\n\t\tcreateSession: async () => {\n\t\t\tawait runtime.newSession();\n\t\t\treturn runtime.session;\n\t\t},\n\t\tloadSession: async () => runtime.session,\n\t\tsetMode: async (mode) => {\n\t\t\tawait runtime.session.setPermissionMode(mode as Parameters<typeof runtime.session.setPermissionMode>[0]);\n\t\t},\n\t};\n\tconst server = new AcpServer({ input: process.stdin, output: process.stdout, host });\n\tif (bridge) bridge.current = server;\n\truntime.session.subscribe((event) => server.onSessionEvent(event));\n\tserver.start();\n\t// The ACP connection owns the process lifetime; it ends when stdin closes.\n\treturn new Promise(() => {});\n}\n"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ACP translation (spec 2026-08-31-acp-adapter.md): maps Apex session/json
|
|
3
|
+
* events onto ACP v1 `session/update` variants. Deliberately stateless --
|
|
4
|
+
* first-sight versus update for tool calls is the server's concern. Unknown
|
|
5
|
+
* events translate to nothing rather than guessing at a shape.
|
|
6
|
+
*/
|
|
7
|
+
export type AcpToolKind = "read" | "edit" | "delete" | "move" | "search" | "execute" | "think" | "fetch" | "other";
|
|
8
|
+
export interface AcpToolCallUpdate {
|
|
9
|
+
toolCallId: string;
|
|
10
|
+
title?: string;
|
|
11
|
+
kind?: AcpToolKind;
|
|
12
|
+
status?: "pending" | "in_progress" | "completed" | "failed";
|
|
13
|
+
}
|
|
14
|
+
export type AcpUpdate = {
|
|
15
|
+
sessionUpdate: "agent_message_chunk";
|
|
16
|
+
content: {
|
|
17
|
+
type: "text";
|
|
18
|
+
text: string;
|
|
19
|
+
};
|
|
20
|
+
} | ({
|
|
21
|
+
sessionUpdate: "tool_call";
|
|
22
|
+
} & AcpToolCallUpdate) | ({
|
|
23
|
+
sessionUpdate: "tool_call_update";
|
|
24
|
+
} & AcpToolCallUpdate);
|
|
25
|
+
export type TranslatedEvent = {
|
|
26
|
+
kind: "message";
|
|
27
|
+
update: Extract<AcpUpdate, {
|
|
28
|
+
sessionUpdate: "agent_message_chunk";
|
|
29
|
+
}>;
|
|
30
|
+
} | {
|
|
31
|
+
kind: "tool";
|
|
32
|
+
toolCallId: string;
|
|
33
|
+
update: AcpToolCallUpdate;
|
|
34
|
+
};
|
|
35
|
+
export declare function toolKind(toolName: string): AcpToolKind;
|
|
36
|
+
export declare function translateJsonEvent(event: unknown): TranslatedEvent | undefined;
|
|
37
|
+
//# sourceMappingURL=translate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../../src/modes/acp/translate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAEnH,MAAM,WAAW,iBAAiB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,MAAM,CAAC,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,CAAC;CAC5D;AAED,MAAM,MAAM,SAAS,GAClB;IAAE,aAAa,EAAE,qBAAqB,CAAC;IAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACjF,CAAC;IAAE,aAAa,EAAE,WAAW,CAAA;CAAE,GAAG,iBAAiB,CAAC,GACpD,CAAC;IAAE,aAAa,EAAE,kBAAkB,CAAA;CAAE,GAAG,iBAAiB,CAAC,CAAC;AAE/D,MAAM,MAAM,eAAe,GACxB;IACA,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE;QAAE,aAAa,EAAE,qBAAqB,CAAA;KAAE,CAAC,CAAC;CACpE,GACD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAenE,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAEtD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,GAAG,SAAS,CAyB9E","sourcesContent":["/**\n * ACP translation (spec 2026-08-31-acp-adapter.md): maps Apex session/json\n * events onto ACP v1 `session/update` variants. Deliberately stateless --\n * first-sight versus update for tool calls is the server's concern. Unknown\n * events translate to nothing rather than guessing at a shape.\n */\n\nexport type AcpToolKind = \"read\" | \"edit\" | \"delete\" | \"move\" | \"search\" | \"execute\" | \"think\" | \"fetch\" | \"other\";\n\nexport interface AcpToolCallUpdate {\n\ttoolCallId: string;\n\ttitle?: string;\n\tkind?: AcpToolKind;\n\tstatus?: \"pending\" | \"in_progress\" | \"completed\" | \"failed\";\n}\n\nexport type AcpUpdate =\n\t| { sessionUpdate: \"agent_message_chunk\"; content: { type: \"text\"; text: string } }\n\t| ({ sessionUpdate: \"tool_call\" } & AcpToolCallUpdate)\n\t| ({ sessionUpdate: \"tool_call_update\" } & AcpToolCallUpdate);\n\nexport type TranslatedEvent =\n\t| {\n\t\t\tkind: \"message\";\n\t\t\tupdate: Extract<AcpUpdate, { sessionUpdate: \"agent_message_chunk\" }>;\n\t }\n\t| { kind: \"tool\"; toolCallId: string; update: AcpToolCallUpdate };\n\nconst TOOL_KINDS: Record<string, AcpToolKind> = {\n\tread: \"read\",\n\tedit: \"edit\",\n\twrite: \"edit\",\n\tbash: \"execute\",\n\tpowershell: \"execute\",\n\tgrep: \"search\",\n\tfind: \"search\",\n\tls: \"search\",\n\tweb_fetch: \"fetch\",\n\tweb_search: \"search\",\n};\n\nexport function toolKind(toolName: string): AcpToolKind {\n\treturn TOOL_KINDS[toolName] ?? \"other\";\n}\n\nexport function translateJsonEvent(event: unknown): TranslatedEvent | undefined {\n\tif (typeof event !== \"object\" || event === null) return undefined;\n\tconst record = event as Record<string, unknown>;\n\tif (record.type !== \"message_update\") return undefined;\n\tconst partial = record.partial as Record<string, unknown> | undefined;\n\tif (typeof partial !== \"object\" || partial === null) return undefined;\n\n\tif (partial.type === \"text_delta\" && typeof partial.delta === \"string\") {\n\t\treturn {\n\t\t\tkind: \"message\",\n\t\t\tupdate: { sessionUpdate: \"agent_message_chunk\", content: { type: \"text\", text: partial.delta } },\n\t\t};\n\t}\n\tif (partial.type === \"toolcall_start\" && typeof partial.id === \"string\") {\n\t\tconst toolName = typeof partial.toolName === \"string\" ? partial.toolName : \"tool\";\n\t\treturn {\n\t\t\tkind: \"tool\",\n\t\t\ttoolCallId: partial.id,\n\t\t\tupdate: { toolCallId: partial.id, title: toolName, kind: toolKind(toolName), status: \"pending\" },\n\t\t};\n\t}\n\tif ((partial.type === \"toolcall_finish\" || partial.type === \"toolcall_end\") && typeof partial.id === \"string\") {\n\t\treturn { kind: \"tool\", toolCallId: partial.id, update: { toolCallId: partial.id, status: \"completed\" } };\n\t}\n\treturn undefined;\n}\n"]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ACP translation (spec 2026-08-31-acp-adapter.md): maps Apex session/json
|
|
3
|
+
* events onto ACP v1 `session/update` variants. Deliberately stateless --
|
|
4
|
+
* first-sight versus update for tool calls is the server's concern. Unknown
|
|
5
|
+
* events translate to nothing rather than guessing at a shape.
|
|
6
|
+
*/
|
|
7
|
+
const TOOL_KINDS = {
|
|
8
|
+
read: "read",
|
|
9
|
+
edit: "edit",
|
|
10
|
+
write: "edit",
|
|
11
|
+
bash: "execute",
|
|
12
|
+
powershell: "execute",
|
|
13
|
+
grep: "search",
|
|
14
|
+
find: "search",
|
|
15
|
+
ls: "search",
|
|
16
|
+
web_fetch: "fetch",
|
|
17
|
+
web_search: "search",
|
|
18
|
+
};
|
|
19
|
+
export function toolKind(toolName) {
|
|
20
|
+
return TOOL_KINDS[toolName] ?? "other";
|
|
21
|
+
}
|
|
22
|
+
export function translateJsonEvent(event) {
|
|
23
|
+
if (typeof event !== "object" || event === null)
|
|
24
|
+
return undefined;
|
|
25
|
+
const record = event;
|
|
26
|
+
if (record.type !== "message_update")
|
|
27
|
+
return undefined;
|
|
28
|
+
const partial = record.partial;
|
|
29
|
+
if (typeof partial !== "object" || partial === null)
|
|
30
|
+
return undefined;
|
|
31
|
+
if (partial.type === "text_delta" && typeof partial.delta === "string") {
|
|
32
|
+
return {
|
|
33
|
+
kind: "message",
|
|
34
|
+
update: { sessionUpdate: "agent_message_chunk", content: { type: "text", text: partial.delta } },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
if (partial.type === "toolcall_start" && typeof partial.id === "string") {
|
|
38
|
+
const toolName = typeof partial.toolName === "string" ? partial.toolName : "tool";
|
|
39
|
+
return {
|
|
40
|
+
kind: "tool",
|
|
41
|
+
toolCallId: partial.id,
|
|
42
|
+
update: { toolCallId: partial.id, title: toolName, kind: toolKind(toolName), status: "pending" },
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if ((partial.type === "toolcall_finish" || partial.type === "toolcall_end") && typeof partial.id === "string") {
|
|
46
|
+
return { kind: "tool", toolCallId: partial.id, update: { toolCallId: partial.id, status: "completed" } };
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=translate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translate.js","sourceRoot":"","sources":["../../../src/modes/acp/translate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAuBH,MAAM,UAAU,GAAgC;IAC/C,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,MAAM;IACb,IAAI,EAAE,SAAS;IACf,UAAU,EAAE,SAAS;IACrB,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,QAAQ;IACd,EAAE,EAAE,QAAQ;IACZ,SAAS,EAAE,OAAO;IAClB,UAAU,EAAE,QAAQ;CACpB,CAAC;AAEF,MAAM,UAAU,QAAQ,CAAC,QAAgB,EAAe;IACvD,OAAO,UAAU,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC;AAAA,CACvC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAc,EAA+B;IAC/E,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAClE,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB;QAAE,OAAO,SAAS,CAAC;IACvD,MAAM,OAAO,GAAG,MAAM,CAAC,OAA8C,CAAC;IACtE,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAEtE,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxE,OAAO;YACN,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,EAAE,aAAa,EAAE,qBAAqB,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE;SAChG,CAAC;IACH,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,gBAAgB,IAAI,OAAO,OAAO,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;QACzE,MAAM,QAAQ,GAAG,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;QAClF,OAAO;YACN,IAAI,EAAE,MAAM;YACZ,UAAU,EAAE,OAAO,CAAC,EAAE;YACtB,MAAM,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE;SAChG,CAAC;IACH,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,iBAAiB,IAAI,OAAO,CAAC,IAAI,KAAK,cAAc,CAAC,IAAI,OAAO,OAAO,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;QAC/G,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,CAAC;IAC1G,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB","sourcesContent":["/**\n * ACP translation (spec 2026-08-31-acp-adapter.md): maps Apex session/json\n * events onto ACP v1 `session/update` variants. Deliberately stateless --\n * first-sight versus update for tool calls is the server's concern. Unknown\n * events translate to nothing rather than guessing at a shape.\n */\n\nexport type AcpToolKind = \"read\" | \"edit\" | \"delete\" | \"move\" | \"search\" | \"execute\" | \"think\" | \"fetch\" | \"other\";\n\nexport interface AcpToolCallUpdate {\n\ttoolCallId: string;\n\ttitle?: string;\n\tkind?: AcpToolKind;\n\tstatus?: \"pending\" | \"in_progress\" | \"completed\" | \"failed\";\n}\n\nexport type AcpUpdate =\n\t| { sessionUpdate: \"agent_message_chunk\"; content: { type: \"text\"; text: string } }\n\t| ({ sessionUpdate: \"tool_call\" } & AcpToolCallUpdate)\n\t| ({ sessionUpdate: \"tool_call_update\" } & AcpToolCallUpdate);\n\nexport type TranslatedEvent =\n\t| {\n\t\t\tkind: \"message\";\n\t\t\tupdate: Extract<AcpUpdate, { sessionUpdate: \"agent_message_chunk\" }>;\n\t }\n\t| { kind: \"tool\"; toolCallId: string; update: AcpToolCallUpdate };\n\nconst TOOL_KINDS: Record<string, AcpToolKind> = {\n\tread: \"read\",\n\tedit: \"edit\",\n\twrite: \"edit\",\n\tbash: \"execute\",\n\tpowershell: \"execute\",\n\tgrep: \"search\",\n\tfind: \"search\",\n\tls: \"search\",\n\tweb_fetch: \"fetch\",\n\tweb_search: \"search\",\n};\n\nexport function toolKind(toolName: string): AcpToolKind {\n\treturn TOOL_KINDS[toolName] ?? \"other\";\n}\n\nexport function translateJsonEvent(event: unknown): TranslatedEvent | undefined {\n\tif (typeof event !== \"object\" || event === null) return undefined;\n\tconst record = event as Record<string, unknown>;\n\tif (record.type !== \"message_update\") return undefined;\n\tconst partial = record.partial as Record<string, unknown> | undefined;\n\tif (typeof partial !== \"object\" || partial === null) return undefined;\n\n\tif (partial.type === \"text_delta\" && typeof partial.delta === \"string\") {\n\t\treturn {\n\t\t\tkind: \"message\",\n\t\t\tupdate: { sessionUpdate: \"agent_message_chunk\", content: { type: \"text\", text: partial.delta } },\n\t\t};\n\t}\n\tif (partial.type === \"toolcall_start\" && typeof partial.id === \"string\") {\n\t\tconst toolName = typeof partial.toolName === \"string\" ? partial.toolName : \"tool\";\n\t\treturn {\n\t\t\tkind: \"tool\",\n\t\t\ttoolCallId: partial.id,\n\t\t\tupdate: { toolCallId: partial.id, title: toolName, kind: toolKind(toolName), status: \"pending\" },\n\t\t};\n\t}\n\tif ((partial.type === \"toolcall_finish\" || partial.type === \"toolcall_end\") && typeof partial.id === \"string\") {\n\t\treturn { kind: \"tool\", toolCallId: partial.id, update: { toolCallId: partial.id, status: \"completed\" } };\n\t}\n\treturn undefined;\n}\n"]}
|
package/dist/modes/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Run modes for the coding agent.
|
|
3
3
|
*/
|
|
4
|
+
export { runAcpMode } from "./acp/server.ts";
|
|
4
5
|
export { InteractiveMode, type InteractiveModeOptions } from "./interactive/interactive-mode.ts";
|
|
5
6
|
export type { JsonAgentSessionEvent } from "./json-event.ts";
|
|
6
7
|
export { type PrintModeOptions, runPrintMode } from "./print-mode.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/modes/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AACjG,YAAY,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,KAAK,gBAAgB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,KAAK,SAAS,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC9G,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,YAAY,EACX,UAAU,EACV,qBAAqB,EACrB,sBAAsB,EACtB,WAAW,EACX,eAAe,GACf,MAAM,oBAAoB,CAAC","sourcesContent":["/**\n * Run modes for the coding agent.\n */\n\nexport { InteractiveMode, type InteractiveModeOptions } from \"./interactive/interactive-mode.ts\";\nexport type { JsonAgentSessionEvent } from \"./json-event.ts\";\nexport { type PrintModeOptions, runPrintMode } from \"./print-mode.ts\";\nexport { type ModelInfo, RpcClient, type RpcClientOptions, type RpcEventListener } from \"./rpc/rpc-client.ts\";\nexport { runRpcMode } from \"./rpc/rpc-mode.ts\";\nexport type {\n\tRpcCommand,\n\tRpcExtensionUIRequest,\n\tRpcExtensionUIResponse,\n\tRpcResponse,\n\tRpcSessionState,\n} from \"./rpc/rpc-types.ts\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/modes/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AACjG,YAAY,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,KAAK,gBAAgB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,KAAK,SAAS,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC9G,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,YAAY,EACX,UAAU,EACV,qBAAqB,EACrB,sBAAsB,EACtB,WAAW,EACX,eAAe,GACf,MAAM,oBAAoB,CAAC","sourcesContent":["/**\n * Run modes for the coding agent.\n */\n\nexport { runAcpMode } from \"./acp/server.ts\";\nexport { InteractiveMode, type InteractiveModeOptions } from \"./interactive/interactive-mode.ts\";\nexport type { JsonAgentSessionEvent } from \"./json-event.ts\";\nexport { type PrintModeOptions, runPrintMode } from \"./print-mode.ts\";\nexport { type ModelInfo, RpcClient, type RpcClientOptions, type RpcEventListener } from \"./rpc/rpc-client.ts\";\nexport { runRpcMode } from \"./rpc/rpc-mode.ts\";\nexport type {\n\tRpcCommand,\n\tRpcExtensionUIRequest,\n\tRpcExtensionUIResponse,\n\tRpcResponse,\n\tRpcSessionState,\n} from \"./rpc/rpc-types.ts\";\n"]}
|
package/dist/modes/index.js
CHANGED
package/dist/modes/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/modes/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAA+B,MAAM,mCAAmC,CAAC;AAEjG,OAAO,EAAyB,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAkB,SAAS,EAAgD,MAAM,qBAAqB,CAAC;AAC9G,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC","sourcesContent":["/**\n * Run modes for the coding agent.\n */\n\nexport { InteractiveMode, type InteractiveModeOptions } from \"./interactive/interactive-mode.ts\";\nexport type { JsonAgentSessionEvent } from \"./json-event.ts\";\nexport { type PrintModeOptions, runPrintMode } from \"./print-mode.ts\";\nexport { type ModelInfo, RpcClient, type RpcClientOptions, type RpcEventListener } from \"./rpc/rpc-client.ts\";\nexport { runRpcMode } from \"./rpc/rpc-mode.ts\";\nexport type {\n\tRpcCommand,\n\tRpcExtensionUIRequest,\n\tRpcExtensionUIResponse,\n\tRpcResponse,\n\tRpcSessionState,\n} from \"./rpc/rpc-types.ts\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/modes/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAA+B,MAAM,mCAAmC,CAAC;AAEjG,OAAO,EAAyB,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAkB,SAAS,EAAgD,MAAM,qBAAqB,CAAC;AAC9G,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC","sourcesContent":["/**\n * Run modes for the coding agent.\n */\n\nexport { runAcpMode } from \"./acp/server.ts\";\nexport { InteractiveMode, type InteractiveModeOptions } from \"./interactive/interactive-mode.ts\";\nexport type { JsonAgentSessionEvent } from \"./json-event.ts\";\nexport { type PrintModeOptions, runPrintMode } from \"./print-mode.ts\";\nexport { type ModelInfo, RpcClient, type RpcClientOptions, type RpcEventListener } from \"./rpc/rpc-client.ts\";\nexport { runRpcMode } from \"./rpc/rpc-mode.ts\";\nexport type {\n\tRpcCommand,\n\tRpcExtensionUIRequest,\n\tRpcExtensionUIResponse,\n\tRpcResponse,\n\tRpcSessionState,\n} from \"./rpc/rpc-types.ts\";\n"]}
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import type { AssistantMessage } from "@earendil-works/pi-ai";
|
|
2
2
|
import { Container, type MarkdownTheme } from "@earendil-works/pi-tui";
|
|
3
3
|
import type { MarkdownTransformer } from "../../../core/extensions/types.ts";
|
|
4
|
+
/**
|
|
5
|
+
* Split streamed markdown into render units at boundaries that render
|
|
6
|
+
* independently: closed column-0 code fences, and blank-line block
|
|
7
|
+
* boundaries that cannot continue a preceding construct.
|
|
8
|
+
*
|
|
9
|
+
* The result is prefix-stable: appending text can only add units at the end,
|
|
10
|
+
* never change earlier ones, which is what makes the units cacheable while
|
|
11
|
+
* a message streams.
|
|
12
|
+
*/
|
|
13
|
+
export declare function splitStreamingMarkdown(text: string): string[];
|
|
4
14
|
/**
|
|
5
15
|
* Component that renders a complete assistant message
|
|
6
16
|
*/
|
|
@@ -14,6 +24,8 @@ export declare class AssistantMessageComponent extends Container {
|
|
|
14
24
|
private lastMessage?;
|
|
15
25
|
private hasToolCalls;
|
|
16
26
|
private isStreaming;
|
|
27
|
+
private forceFullRebuild;
|
|
28
|
+
private sections;
|
|
17
29
|
constructor(message?: AssistantMessage, hideThinkingBlock?: boolean, markdownTheme?: MarkdownTheme, hiddenThinkingLabel?: string, outputPad?: number, markdownTransformers?: readonly MarkdownTransformer[]);
|
|
18
30
|
invalidate(): void;
|
|
19
31
|
setHideThinkingBlock(hide: boolean): void;
|
|
@@ -21,5 +33,22 @@ export declare class AssistantMessageComponent extends Container {
|
|
|
21
33
|
setOutputPad(padding: number): void;
|
|
22
34
|
render(width: number): string[];
|
|
23
35
|
updateContent(message: AssistantMessage, isStreaming?: boolean): void;
|
|
36
|
+
private buildSectionSpecs;
|
|
37
|
+
private appendContentSpecs;
|
|
38
|
+
private appendStatusSpecs;
|
|
39
|
+
/**
|
|
40
|
+
* Push markdown sections for one content block. While streaming, the block
|
|
41
|
+
* is split at render-independent boundaries so completed units keep their
|
|
42
|
+
* rendered Markdown instances and only the active tail re-parses per
|
|
43
|
+
* chunk; otherwise the block renders whole, byte-identical to the
|
|
44
|
+
* pre-split behaviour.
|
|
45
|
+
*
|
|
46
|
+
* Transformers are assumed block-local (the built-in mermaid transformer
|
|
47
|
+
* maps tokens and preserves the rest, so per-unit application is
|
|
48
|
+
* equivalent). A transformer that genuinely needs whole-message context
|
|
49
|
+
* still gets it: a non-streaming update always renders whole blocks.
|
|
50
|
+
*/
|
|
51
|
+
private pushMarkdownSpecs;
|
|
52
|
+
private createComponent;
|
|
24
53
|
}
|
|
25
54
|
//# sourceMappingURL=assistant-message.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,wBAAwB,CAAC;AAC/F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAQ7E;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACvD,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,iBAAiB,CAAU;IACnC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,oBAAoB,CAAiC;IAC7D,OAAO,CAAC,WAAW,CAAC,CAAmB;IACvC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAS;IAE5B,YACC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,iBAAiB,UAAQ,EACzB,aAAa,GAAE,aAAkC,EACjD,mBAAmB,SAAgB,EACnC,SAAS,SAAI,EACb,oBAAoB,GAAE,SAAS,mBAAmB,EAAO,EAiBzD;IAEQ,UAAU,IAAI,IAAI,CAK1B;IAED,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAKxC;IAED,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAK1C;IAED,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAKlC;IAEQ,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CASvC;IAED,aAAa,CAAC,OAAO,EAAE,gBAAgB,EAAE,WAAW,UAAmB,GAAG,IAAI,CA2G7E;CACD","sourcesContent":["import type { AssistantMessage } from \"@earendil-works/pi-ai\";\nimport { Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { MarkdownTransformer } from \"../../../core/extensions/types.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { createMarkdownTransform } from \"./markdown-transform.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\tprivate markdownTheme: MarkdownTheme;\n\tprivate hiddenThinkingLabel: string;\n\tprivate outputPad: number;\n\tprivate markdownTransformers: readonly MarkdownTransformer[];\n\tprivate lastMessage?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\tprivate isStreaming = false;\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = \"Thinking...\",\n\t\toutputPad = 1,\n\t\tmarkdownTransformers: readonly MarkdownTransformer[] = [],\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\t\tthis.outputPad = outputPad;\n\t\tthis.markdownTransformers = markdownTransformers;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetOutputPad(padding: number): void {\n\t\tthis.outputPad = padding;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst lines = super.render(width);\n\t\tif (this.hasToolCalls || lines.length === 0) {\n\t\t\treturn lines;\n\t\t}\n\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\t\treturn lines;\n\t}\n\n\tupdateContent(message: AssistantMessage, isStreaming = this.isStreaming): void {\n\t\tthis.lastMessage = message;\n\t\tthis.isStreaming = isStreaming;\n\n\t\t// Clear content container\n\t\tthis.contentContainer.clear();\n\n\t\tconst hasVisibleContent = message.content.some(\n\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\n\t\tif (hasVisibleContent) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\t// Render content in order\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[i];\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\t// Assistant text messages with no background - trim the text\n\t\t\t\t// Set paddingY=0 to avoid extra spacing before tool executions\n\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\tnew Markdown(content.text.trim(), this.outputPad, 0, this.markdownTheme, undefined, {\n\t\t\t\t\t\ttransform: createMarkdownTransform(\"assistant\", this.isStreaming, this.markdownTransformers),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t} else if (content.type === \"thinking\") {\n\t\t\t\tconst thinkingBlocks: string[] = [];\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) {\n\t\t\t\t\t\tthinkingBlocks.push(thinking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti--;\n\n\t\t\t\tif (thinkingBlocks.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Add spacing only when another visible assistant content block follows.\n\t\t\t\t// This avoids a superfluous blank line before separately-rendered tool execution blocks.\n\t\t\t\tconst hasVisibleContentAfter = message.content\n\t\t\t\t\t.slice(i + 1)\n\t\t\t\t\t.some((c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()));\n\n\t\t\t\tif (this.hideThinkingBlock) {\n\t\t\t\t\t// Show one static label for each run of thinking blocks when hidden.\n\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\tnew Text(theme.italic(theme.fg(\"thinkingText\", this.hiddenThinkingLabel)), this.outputPad, 0),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t// Render each run of thinking blocks as one Markdown section.\n\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\tnew Markdown(\n\t\t\t\t\t\t\tthinkingBlocks.join(\"\\n\\n\"),\n\t\t\t\t\t\t\tthis.outputPad,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tthis.markdownTheme,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\t\t\titalic: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttransform: createMarkdownTransform(\n\t\t\t\t\t\t\t\t\t\"assistant-thinking\",\n\t\t\t\t\t\t\t\t\tthis.isStreaming,\n\t\t\t\t\t\t\t\t\tthis.markdownTransformers,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check if incomplete/failed - show after partial content.\n\t\t// For aborted/error tool calls, tool execution components show the error.\n\t\t// Length stops can happen before a tool call is complete, so surface them here too.\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tthis.hasToolCalls = hasToolCalls;\n\t\tif (message.stopReason === \"length\") {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\tthis.contentContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"error\", \"Response was truncated before completion.\"), this.outputPad, 0),\n\t\t\t);\n\t\t} else if (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), this.outputPad, 0));\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMsg}`), this.outputPad, 0));\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"assistant-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,wBAAwB,CAAC;AAC/F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAiC7E;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAqC7D;AAcD;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACvD,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,iBAAiB,CAAU;IACnC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,oBAAoB,CAAiC;IAC7D,OAAO,CAAC,WAAW,CAAC,CAAmB;IACvC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,gBAAgB,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAiB;IAEjC,YACC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,iBAAiB,UAAQ,EACzB,aAAa,GAAE,aAAkC,EACjD,mBAAmB,SAAgB,EACnC,SAAS,SAAI,EACb,oBAAoB,GAAE,SAAS,mBAAmB,EAAO,EAiBzD;IAEQ,UAAU,IAAI,IAAI,CAM1B;IAED,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAMxC;IAED,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAM1C;IAED,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAMlC;IAEQ,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CASvC;IAED,aAAa,CAAC,OAAO,EAAE,gBAAgB,EAAE,WAAW,UAAmB,GAAG,IAAI,CA0C7E;IAED,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,kBAAkB;IAyD1B,OAAO,CAAC,iBAAiB;IAqBzB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,eAAe;CA0BvB","sourcesContent":["import type { AssistantMessage } from \"@earendil-works/pi-ai\";\nimport { Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { MarkdownTransformer } from \"../../../core/extensions/types.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { createMarkdownTransform } from \"./markdown-transform.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\nconst FENCE_OPENER = /^(```|~~~)/;\nconst FENCE_CLOSER = /^(```|~~~)\\s*$/;\nconst LIST_MARKER = /^([-*+]\\s|\\d+[.)]\\s)/;\nconst QUOTE_MARKER = /^>\\s?/;\nconst INDENTED_CODE = /^(?:\\t| {4})/;\n\nfunction lastNonEmpty(lines: string[]): string | undefined {\n\tfor (let i = lines.length - 1; i >= 0; i--) {\n\t\tif (lines[i].trim() !== \"\") return lines[i];\n\t}\n\treturn undefined;\n}\n\nfunction shouldSplitBefore(next: string, current: string[]): boolean {\n\t// Indented lines can continue indented code blocks; never split there.\n\tif (INDENTED_CODE.test(next)) return false;\n\tconst previous = lastNonEmpty(current);\n\tif (previous && INDENTED_CODE.test(previous)) return false;\n\t// A loose list (\"item\\n\\nitem\") and a blockquote with a blank line render\n\t// as one construct; splitting them would change the output.\n\tif (LIST_MARKER.test(next) && previous && LIST_MARKER.test(previous)) return false;\n\tif (QUOTE_MARKER.test(next) && previous && QUOTE_MARKER.test(previous)) return false;\n\treturn true;\n}\n\n/**\n * Split streamed markdown into render units at boundaries that render\n * independently: closed column-0 code fences, and blank-line block\n * boundaries that cannot continue a preceding construct.\n *\n * The result is prefix-stable: appending text can only add units at the end,\n * never change earlier ones, which is what makes the units cacheable while\n * a message streams.\n */\nexport function splitStreamingMarkdown(text: string): string[] {\n\tif (!text) return [];\n\tconst lines = text.split(\"\\n\");\n\tconst units: string[] = [];\n\tlet current: string[] = [];\n\tlet inFence = false;\n\tconst flush = (): void => {\n\t\tif (current.length > 0) {\n\t\t\tunits.push(current.join(\"\\n\"));\n\t\t\tcurrent = [];\n\t\t}\n\t};\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tconst line = lines[i];\n\t\tif (!inFence && FENCE_OPENER.test(line)) {\n\t\t\tinFence = true;\n\t\t\tcurrent.push(line);\n\t\t\tcontinue;\n\t\t}\n\t\tif (inFence) {\n\t\t\tcurrent.push(line);\n\t\t\tif (FENCE_CLOSER.test(line)) {\n\t\t\t\tflush();\n\t\t\t\tinFence = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tcurrent.push(line);\n\t\tif (line.trim() === \"\") {\n\t\t\tconst next = lines[i + 1];\n\t\t\tif (next !== undefined && next.trim() !== \"\" && shouldSplitBefore(next, current)) {\n\t\t\t\tflush();\n\t\t\t}\n\t\t}\n\t}\n\tflush();\n\treturn units;\n}\n\ntype SectionSpec =\n\t| { kind: \"spacer\" }\n\t| { kind: \"markdown-text\"; text: string }\n\t| { kind: \"markdown-thinking\"; text: string }\n\t| { kind: \"label\"; text: string };\n\ntype Section = { spec: SectionSpec; component: Container[\"children\"][number] };\n\nfunction specText(spec: SectionSpec): string | undefined {\n\treturn spec.kind === \"spacer\" ? undefined : spec.text;\n}\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\tprivate markdownTheme: MarkdownTheme;\n\tprivate hiddenThinkingLabel: string;\n\tprivate outputPad: number;\n\tprivate markdownTransformers: readonly MarkdownTransformer[];\n\tprivate lastMessage?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\tprivate isStreaming = false;\n\tprivate forceFullRebuild = true;\n\tprivate sections: Section[] = [];\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = \"Thinking...\",\n\t\toutputPad = 1,\n\t\tmarkdownTransformers: readonly MarkdownTransformer[] = [],\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\t\tthis.outputPad = outputPad;\n\t\tthis.markdownTransformers = markdownTransformers;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetOutputPad(padding: number): void {\n\t\tthis.outputPad = padding;\n\t\tif (this.lastMessage) {\n\t\t\tthis.forceFullRebuild = true;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst lines = super.render(width);\n\t\tif (this.hasToolCalls || lines.length === 0) {\n\t\t\treturn lines;\n\t\t}\n\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\t\treturn lines;\n\t}\n\n\tupdateContent(message: AssistantMessage, isStreaming = this.isStreaming): void {\n\t\tthis.lastMessage = message;\n\t\t// The transform closures capture isStreaming, and non-streaming updates\n\t\t// render whole blocks rather than split units, so an isStreaming flip\n\t\t// rebuilds every section.\n\t\tconst rebuildAll = this.forceFullRebuild || isStreaming !== this.isStreaming;\n\t\tthis.isStreaming = isStreaming;\n\n\t\tconst specs = this.buildSectionSpecs(message);\n\t\tconst sections: Section[] = [];\n\t\tfor (let i = 0; i < specs.length; i++) {\n\t\t\tconst spec = specs[i];\n\t\t\tconst previous = rebuildAll ? undefined : this.sections[i];\n\t\t\tconst sameKind = previous !== undefined && previous.spec.kind === spec.kind;\n\t\t\tif (sameKind && (spec.kind === \"spacer\" || specText(previous.spec) === specText(spec))) {\n\t\t\t\tsections.push({ spec, component: previous.component });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (sameKind && spec.kind !== \"spacer\") {\n\t\t\t\t// Same slot, new content (the growing tail of a streamed\n\t\t\t\t// message): update in place so only this unit re-parses.\n\t\t\t\tconst component = previous.component as Text;\n\t\t\t\tcomponent.setText(specText(spec) ?? \"\");\n\t\t\t\tsections.push({ spec, component: previous.component });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsections.push({ spec, component: this.createComponent(spec) });\n\t\t}\n\n\t\tthis.forceFullRebuild = false;\n\t\tthis.sections = sections;\n\n\t\tthis.contentContainer.clear();\n\t\tfor (const section of sections) {\n\t\t\tthis.contentContainer.addChild(section.component);\n\t\t}\n\n\t\t// Check if incomplete/failed - show after partial content.\n\t\t// For aborted/error tool calls, tool execution components show the error.\n\t\t// Length stops can happen before a tool call is complete, so surface them here too.\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tthis.hasToolCalls = hasToolCalls;\n\t}\n\n\tprivate buildSectionSpecs(message: AssistantMessage): SectionSpec[] {\n\t\tconst specs: SectionSpec[] = [];\n\t\tthis.appendContentSpecs(message, specs);\n\t\tthis.appendStatusSpecs(message, specs);\n\t\treturn specs;\n\t}\n\n\tprivate appendContentSpecs(message: AssistantMessage, specs: SectionSpec[]): void {\n\t\tconst hasVisibleContent = message.content.some(\n\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\n\t\tif (hasVisibleContent) {\n\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t}\n\n\t\t// Render content in order\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[i];\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\t// Assistant text messages with no background - trim the text\n\t\t\t\t// Set paddingY=0 to avoid extra spacing before tool executions\n\t\t\t\tthis.pushMarkdownSpecs(specs, content.text.trim(), \"markdown-text\");\n\t\t\t} else if (content.type === \"thinking\") {\n\t\t\t\tconst thinkingBlocks: string[] = [];\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) {\n\t\t\t\t\t\tthinkingBlocks.push(thinking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti--;\n\n\t\t\t\tif (thinkingBlocks.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Add spacing only when another visible assistant content block follows.\n\t\t\t\t// This avoids a superfluous blank line before separately-rendered tool execution blocks.\n\t\t\t\tconst hasVisibleContentAfter = message.content\n\t\t\t\t\t.slice(i + 1)\n\t\t\t\t\t.some((c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()));\n\n\t\t\t\tif (this.hideThinkingBlock) {\n\t\t\t\t\t// Show one static label for each run of thinking blocks when hidden.\n\t\t\t\t\tspecs.push({\n\t\t\t\t\t\tkind: \"label\",\n\t\t\t\t\t\ttext: theme.italic(theme.fg(\"thinkingText\", this.hiddenThinkingLabel)),\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\t// Render each run of thinking blocks as one Markdown section.\n\t\t\t\t\tthis.pushMarkdownSpecs(specs, thinkingBlocks.join(\"\\n\\n\"), \"markdown-thinking\");\n\t\t\t\t}\n\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate appendStatusSpecs(message: AssistantMessage, specs: SectionSpec[]): void {\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tif (message.stopReason === \"length\") {\n\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\tspecs.push({ kind: \"label\", text: theme.fg(\"error\", \"Response was truncated before completion.\") });\n\t\t} else if (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\t\tspecs.push({ kind: \"label\", text: theme.fg(\"error\", abortMessage) });\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tspecs.push({ kind: \"spacer\" });\n\t\t\t\tspecs.push({ kind: \"label\", text: theme.fg(\"error\", `Error: ${errorMsg}`) });\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Push markdown sections for one content block. While streaming, the block\n\t * is split at render-independent boundaries so completed units keep their\n\t * rendered Markdown instances and only the active tail re-parses per\n\t * chunk; otherwise the block renders whole, byte-identical to the\n\t * pre-split behaviour.\n\t *\n\t * Transformers are assumed block-local (the built-in mermaid transformer\n\t * maps tokens and preserves the rest, so per-unit application is\n\t * equivalent). A transformer that genuinely needs whole-message context\n\t * still gets it: a non-streaming update always renders whole blocks.\n\t */\n\tprivate pushMarkdownSpecs(specs: SectionSpec[], text: string, kind: \"markdown-text\" | \"markdown-thinking\"): void {\n\t\tif (this.isStreaming) {\n\t\t\tfor (const unit of splitStreamingMarkdown(text)) {\n\t\t\t\tspecs.push({ kind, text: unit });\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tspecs.push({ kind, text });\n\t}\n\n\tprivate createComponent(spec: SectionSpec): Section[\"component\"] {\n\t\tswitch (spec.kind) {\n\t\t\tcase \"spacer\":\n\t\t\t\treturn new Spacer(1);\n\t\t\tcase \"label\":\n\t\t\t\treturn new Text(spec.text, this.outputPad, 0);\n\t\t\tcase \"markdown-text\":\n\t\t\t\treturn new Markdown(spec.text, this.outputPad, 0, this.markdownTheme, undefined, {\n\t\t\t\t\ttransform: createMarkdownTransform(\"assistant\", this.isStreaming, this.markdownTransformers),\n\t\t\t\t});\n\t\t\tcase \"markdown-thinking\":\n\t\t\t\treturn new Markdown(\n\t\t\t\t\tspec.text,\n\t\t\t\t\tthis.outputPad,\n\t\t\t\t\t0,\n\t\t\t\t\tthis.markdownTheme,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\titalic: true,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttransform: createMarkdownTransform(\"assistant-thinking\", this.isStreaming, this.markdownTransformers),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t}\n\t}\n}\n"]}
|