@calliopelabs/cli 2.5.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -661
- package/dist/acp.d.ts +78 -0
- package/dist/acp.d.ts.map +1 -0
- package/dist/acp.js +572 -0
- package/dist/acp.js.map +1 -0
- package/dist/bin.d.ts +3 -7
- package/dist/bin.d.ts.map +1 -1
- package/dist/bin.js +56 -79
- package/dist/bin.js.map +1 -1
- package/dist/budget.d.ts +64 -0
- package/dist/budget.d.ts.map +1 -0
- package/dist/budget.js +157 -0
- package/dist/budget.js.map +1 -0
- package/dist/checkpoint.d.ts +63 -30
- package/dist/checkpoint.d.ts.map +1 -1
- package/dist/checkpoint.js +247 -160
- package/dist/checkpoint.js.map +1 -1
- package/dist/circuit-breaker/breaker.js.map +1 -1
- package/dist/config.d.ts +86 -81
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +236 -304
- package/dist/config.js.map +1 -1
- package/dist/cost.d.ts +114 -0
- package/dist/cost.d.ts.map +1 -0
- package/dist/cost.js +499 -0
- package/dist/cost.js.map +1 -0
- package/dist/diff.d.ts.map +1 -1
- package/dist/diff.js +11 -7
- package/dist/diff.js.map +1 -1
- package/dist/errors.js +3 -3
- package/dist/errors.js.map +1 -1
- package/dist/files.js.map +1 -1
- package/dist/fleet.d.ts +30 -0
- package/dist/fleet.d.ts.map +1 -0
- package/dist/fleet.js +86 -0
- package/dist/fleet.js.map +1 -0
- package/dist/fuzzy-search.d.ts.map +1 -1
- package/dist/fuzzy-search.js +2 -1
- package/dist/fuzzy-search.js.map +1 -1
- package/dist/git-status.js.map +1 -1
- package/dist/headless.d.ts +1 -2
- package/dist/headless.d.ts.map +1 -1
- package/dist/headless.js +166 -24
- package/dist/headless.js.map +1 -1
- package/dist/hud/api.d.ts +3 -18
- package/dist/hud/api.d.ts.map +1 -1
- package/dist/hud/api.js +9 -352
- package/dist/hud/api.js.map +1 -1
- package/dist/hud/palettes.d.ts.map +1 -1
- package/dist/hud/palettes.js +0 -180
- package/dist/hud/palettes.js.map +1 -1
- package/dist/hud/skins.d.ts.map +1 -1
- package/dist/hud/skins.js +0 -263
- package/dist/hud/skins.js.map +1 -1
- package/dist/hud/types.d.ts +2 -5
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -4
- package/dist/index.js.map +1 -1
- package/dist/iteration-ledger.d.ts.map +1 -1
- package/dist/iteration-ledger.js +3 -2
- package/dist/iteration-ledger.js.map +1 -1
- package/dist/local-model.d.ts +150 -0
- package/dist/local-model.d.ts.map +1 -0
- package/dist/local-model.js +408 -0
- package/dist/local-model.js.map +1 -0
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +5 -2
- package/dist/mcp.js.map +1 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +6 -4
- package/dist/memory.js.map +1 -1
- package/dist/model-detection.js +2 -2
- package/dist/model-detection.js.map +1 -1
- package/dist/parallel-tools.js.map +1 -1
- package/dist/plugins.d.ts +32 -1
- package/dist/plugins.d.ts.map +1 -1
- package/dist/plugins.js +116 -5
- package/dist/plugins.js.map +1 -1
- package/dist/policy.d.ts +43 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +139 -0
- package/dist/policy.js.map +1 -0
- package/dist/project-config.d.ts +1 -2
- package/dist/project-config.d.ts.map +1 -1
- package/dist/project-config.js +0 -3
- package/dist/project-config.js.map +1 -1
- package/dist/providers/bedrock.d.ts.map +1 -1
- package/dist/providers/bedrock.js +2 -5
- package/dist/providers/bedrock.js.map +1 -1
- package/dist/providers/compat.d.ts +21 -0
- package/dist/providers/compat.d.ts.map +1 -1
- package/dist/providers/compat.js +176 -6
- package/dist/providers/compat.js.map +1 -1
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/index.d.ts +19 -4
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +61 -10
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/ollama.d.ts +2 -2
- package/dist/providers/ollama.d.ts.map +1 -1
- package/dist/providers/ollama.js +26 -6
- package/dist/providers/ollama.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +14 -10
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/types.d.ts +8 -0
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js.map +1 -1
- package/dist/replay.d.ts +37 -0
- package/dist/replay.d.ts.map +1 -0
- package/dist/replay.js +168 -0
- package/dist/replay.js.map +1 -0
- package/dist/router.d.ts +133 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/{model-router.js → router.js} +329 -3
- package/dist/router.js.map +1 -0
- package/dist/runlog.d.ts +185 -0
- package/dist/runlog.d.ts.map +1 -0
- package/dist/runlog.js +398 -0
- package/dist/runlog.js.map +1 -0
- package/dist/{sandbox.d.ts → sandbox/docker.d.ts} +1 -1
- package/dist/sandbox/docker.d.ts.map +1 -0
- package/dist/{sandbox.js → sandbox/docker.js} +1 -1
- package/dist/sandbox/docker.js.map +1 -0
- package/dist/sandbox/index.d.ts +36 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +62 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/{sandbox-native.d.ts → sandbox/native.d.ts} +1 -1
- package/dist/sandbox/native.d.ts.map +1 -0
- package/dist/{sandbox-native.js → sandbox/native.js} +1 -1
- package/dist/sandbox/native.js.map +1 -0
- package/dist/scope.js +1 -1
- package/dist/scope.js.map +1 -1
- package/dist/scuttlebot/config.js.map +1 -1
- package/dist/scuttlebot/irc-client.js.map +1 -1
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +22 -54
- package/dist/setup.js.map +1 -1
- package/dist/skills.d.ts +39 -0
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +90 -8
- package/dist/skills.js.map +1 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +6 -3
- package/dist/storage.js.map +1 -1
- package/dist/streaming.d.ts +25 -0
- package/dist/streaming.d.ts.map +1 -1
- package/dist/streaming.js +59 -0
- package/dist/streaming.js.map +1 -1
- package/dist/styles.d.ts +6 -0
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +11 -0
- package/dist/styles.js.map +1 -1
- package/dist/summarization.js.map +1 -1
- package/dist/terminal-image.js +1 -1
- package/dist/terminal-image.js.map +1 -1
- package/dist/themes.d.ts +5 -4
- package/dist/themes.d.ts.map +1 -1
- package/dist/themes.js +35 -90
- package/dist/themes.js.map +1 -1
- package/dist/tools.d.ts +27 -3
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +128 -179
- package/dist/tools.js.map +1 -1
- package/dist/types.d.ts +4 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +21 -40
- package/dist/types.js.map +1 -1
- package/dist/ui/agent.d.ts +3 -6
- package/dist/ui/agent.d.ts.map +1 -1
- package/dist/ui/agent.js +328 -38
- package/dist/ui/agent.js.map +1 -1
- package/dist/ui/animations.d.ts +37 -0
- package/dist/ui/animations.d.ts.map +1 -0
- package/dist/ui/animations.js +227 -0
- package/dist/ui/animations.js.map +1 -0
- package/dist/ui/chat-input-keys.d.ts +42 -0
- package/dist/ui/chat-input-keys.d.ts.map +1 -0
- package/dist/ui/chat-input-keys.js +360 -0
- package/dist/ui/chat-input-keys.js.map +1 -0
- package/dist/ui/chat-input.d.ts +2 -1
- package/dist/ui/chat-input.d.ts.map +1 -1
- package/dist/ui/chat-input.js +31 -350
- package/dist/ui/chat-input.js.map +1 -1
- package/dist/ui/commands.d.ts +14 -46
- package/dist/ui/commands.d.ts.map +1 -1
- package/dist/ui/commands.js +416 -2899
- package/dist/ui/commands.js.map +1 -1
- package/dist/ui/completions.d.ts +1 -0
- package/dist/ui/completions.d.ts.map +1 -1
- package/dist/ui/completions.js +36 -107
- package/dist/ui/completions.js.map +1 -1
- package/dist/ui/components.d.ts +14 -6
- package/dist/ui/components.d.ts.map +1 -1
- package/dist/ui/components.js +17 -226
- package/dist/ui/components.js.map +1 -1
- package/dist/ui/context.js +6 -6
- package/dist/ui/context.js.map +1 -1
- package/dist/ui/debug-log.d.ts +11 -0
- package/dist/ui/debug-log.d.ts.map +1 -0
- package/dist/ui/debug-log.js +21 -0
- package/dist/ui/debug-log.js.map +1 -0
- package/dist/ui/error-boundary.d.ts.map +1 -1
- package/dist/ui/error-boundary.js.map +1 -1
- package/dist/ui/frame.d.ts.map +1 -1
- package/dist/ui/frame.js +1 -3
- package/dist/ui/frame.js.map +1 -1
- package/dist/ui/index.d.ts +11 -3
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +45 -1076
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/messages.d.ts +4 -7
- package/dist/ui/messages.d.ts.map +1 -1
- package/dist/ui/messages.js +15 -30
- package/dist/ui/messages.js.map +1 -1
- package/dist/ui/modals/index.d.ts +11 -0
- package/dist/ui/modals/index.d.ts.map +1 -0
- package/dist/ui/modals/index.js +10 -0
- package/dist/ui/modals/index.js.map +1 -0
- package/dist/ui/modals/prompts.d.ts +37 -0
- package/dist/ui/modals/prompts.d.ts.map +1 -0
- package/dist/ui/modals/prompts.js +124 -0
- package/dist/ui/modals/prompts.js.map +1 -0
- package/dist/ui/modals/selectors.d.ts +33 -0
- package/dist/ui/modals/selectors.d.ts.map +1 -0
- package/dist/ui/modals/selectors.js +111 -0
- package/dist/ui/modals/selectors.js.map +1 -0
- package/dist/ui/modals/setup.d.ts +17 -0
- package/dist/ui/modals/setup.d.ts.map +1 -0
- package/dist/ui/modals/setup.js +51 -0
- package/dist/ui/modals/setup.js.map +1 -0
- package/dist/ui/regions/input-region.d.ts +40 -0
- package/dist/ui/regions/input-region.d.ts.map +1 -0
- package/dist/ui/regions/input-region.js +116 -0
- package/dist/ui/regions/input-region.js.map +1 -0
- package/dist/ui/regions/modal-host.d.ts +41 -0
- package/dist/ui/regions/modal-host.d.ts.map +1 -0
- package/dist/ui/regions/modal-host.js +51 -0
- package/dist/ui/regions/modal-host.js.map +1 -0
- package/dist/ui/regions/render-probe.d.ts +22 -0
- package/dist/ui/regions/render-probe.d.ts.map +1 -0
- package/dist/ui/regions/render-probe.js +45 -0
- package/dist/ui/regions/render-probe.js.map +1 -0
- package/dist/ui/regions/static-scrollback.d.ts +39 -0
- package/dist/ui/regions/static-scrollback.d.ts.map +1 -0
- package/dist/ui/regions/static-scrollback.js +68 -0
- package/dist/ui/regions/static-scrollback.js.map +1 -0
- package/dist/ui/regions/status-region.d.ts +24 -0
- package/dist/ui/regions/status-region.d.ts.map +1 -0
- package/dist/ui/regions/status-region.js +17 -0
- package/dist/ui/regions/status-region.js.map +1 -0
- package/dist/ui/regions/transcript-region.d.ts +41 -0
- package/dist/ui/regions/transcript-region.d.ts.map +1 -0
- package/dist/ui/regions/transcript-region.js +52 -0
- package/dist/ui/regions/transcript-region.js.map +1 -0
- package/dist/ui/self-restart.d.ts +9 -0
- package/dist/ui/self-restart.d.ts.map +1 -0
- package/dist/ui/self-restart.js +24 -0
- package/dist/ui/self-restart.js.map +1 -0
- package/dist/ui/state/use-chat-controller.d.ts +23 -0
- package/dist/ui/state/use-chat-controller.d.ts.map +1 -0
- package/dist/ui/state/use-chat-controller.js +643 -0
- package/dist/ui/state/use-chat-controller.js.map +1 -0
- package/dist/ui/state/use-loop-state.d.ts +23 -0
- package/dist/ui/state/use-loop-state.d.ts.map +1 -0
- package/dist/ui/state/use-loop-state.js +39 -0
- package/dist/ui/state/use-loop-state.js.map +1 -0
- package/dist/ui/state/use-modal-state.d.ts +52 -0
- package/dist/ui/state/use-modal-state.d.ts.map +1 -0
- package/dist/ui/state/use-modal-state.js +44 -0
- package/dist/ui/state/use-modal-state.js.map +1 -0
- package/dist/ui/state/use-model-state.d.ts +29 -0
- package/dist/ui/state/use-model-state.d.ts.map +1 -0
- package/dist/ui/state/use-model-state.js +47 -0
- package/dist/ui/state/use-model-state.js.map +1 -0
- package/dist/ui/state/use-processing-state.d.ts +24 -0
- package/dist/ui/state/use-processing-state.d.ts.map +1 -0
- package/dist/ui/state/use-processing-state.js +46 -0
- package/dist/ui/state/use-processing-state.js.map +1 -0
- package/dist/ui/state/use-queue-state.d.ts +19 -0
- package/dist/ui/state/use-queue-state.d.ts.map +1 -0
- package/dist/ui/state/use-queue-state.js +30 -0
- package/dist/ui/state/use-queue-state.js.map +1 -0
- package/dist/ui/state/use-session-init.d.ts +22 -0
- package/dist/ui/state/use-session-init.d.ts.map +1 -0
- package/dist/ui/state/use-session-init.js +77 -0
- package/dist/ui/state/use-session-init.js.map +1 -0
- package/dist/ui/state/use-session-stats.d.ts +16 -0
- package/dist/ui/state/use-session-stats.d.ts.map +1 -0
- package/dist/ui/state/use-session-stats.js +18 -0
- package/dist/ui/state/use-session-stats.js.map +1 -0
- package/dist/ui/state/use-terminal-width.d.ts +8 -0
- package/dist/ui/state/use-terminal-width.d.ts.map +1 -0
- package/dist/ui/state/use-terminal-width.js +22 -0
- package/dist/ui/state/use-terminal-width.js.map +1 -0
- package/dist/ui/state/use-transcript-state.d.ts +21 -0
- package/dist/ui/state/use-transcript-state.d.ts.map +1 -0
- package/dist/ui/state/use-transcript-state.js +49 -0
- package/dist/ui/state/use-transcript-state.js.map +1 -0
- package/dist/ui/status-bar.d.ts.map +1 -1
- package/dist/ui/status-bar.js +2 -3
- package/dist/ui/status-bar.js.map +1 -1
- package/dist/version-check.d.ts.map +1 -1
- package/dist/version-check.js +10 -0
- package/dist/version-check.js.map +1 -1
- package/package.json +10 -3
- package/dist/agents/agent-config-loader.d.ts +0 -60
- package/dist/agents/agent-config-loader.d.ts.map +0 -1
- package/dist/agents/agent-config-loader.js +0 -402
- package/dist/agents/agent-config-loader.js.map +0 -1
- package/dist/agents/agent-config-presets.d.ts +0 -10
- package/dist/agents/agent-config-presets.d.ts.map +0 -1
- package/dist/agents/agent-config-presets.js +0 -940
- package/dist/agents/agent-config-presets.js.map +0 -1
- package/dist/agents/agent-config-types.d.ts +0 -145
- package/dist/agents/agent-config-types.d.ts.map +0 -1
- package/dist/agents/agent-config-types.js +0 -12
- package/dist/agents/agent-config-types.js.map +0 -1
- package/dist/agents/agent-detection.d.ts +0 -35
- package/dist/agents/agent-detection.d.ts.map +0 -1
- package/dist/agents/agent-detection.js +0 -110
- package/dist/agents/agent-detection.js.map +0 -1
- package/dist/agents/aggregator.d.ts +0 -19
- package/dist/agents/aggregator.d.ts.map +0 -1
- package/dist/agents/aggregator.js +0 -141
- package/dist/agents/aggregator.js.map +0 -1
- package/dist/agents/cli-backend.d.ts +0 -32
- package/dist/agents/cli-backend.d.ts.map +0 -1
- package/dist/agents/cli-backend.js +0 -271
- package/dist/agents/cli-backend.js.map +0 -1
- package/dist/agents/council-types.d.ts +0 -115
- package/dist/agents/council-types.d.ts.map +0 -1
- package/dist/agents/council-types.js +0 -81
- package/dist/agents/council-types.js.map +0 -1
- package/dist/agents/council.d.ts +0 -112
- package/dist/agents/council.d.ts.map +0 -1
- package/dist/agents/council.js +0 -722
- package/dist/agents/council.js.map +0 -1
- package/dist/agents/decomposer.d.ts +0 -33
- package/dist/agents/decomposer.d.ts.map +0 -1
- package/dist/agents/decomposer.js +0 -138
- package/dist/agents/decomposer.js.map +0 -1
- package/dist/agents/dynamic-tools.d.ts +0 -52
- package/dist/agents/dynamic-tools.d.ts.map +0 -1
- package/dist/agents/dynamic-tools.js +0 -424
- package/dist/agents/dynamic-tools.js.map +0 -1
- package/dist/agents/index.d.ts +0 -29
- package/dist/agents/index.d.ts.map +0 -1
- package/dist/agents/index.js +0 -29
- package/dist/agents/index.js.map +0 -1
- package/dist/agents/installer.d.ts +0 -39
- package/dist/agents/installer.d.ts.map +0 -1
- package/dist/agents/installer.js +0 -205
- package/dist/agents/installer.js.map +0 -1
- package/dist/agents/orchestrator.d.ts +0 -106
- package/dist/agents/orchestrator.d.ts.map +0 -1
- package/dist/agents/orchestrator.js +0 -363
- package/dist/agents/orchestrator.js.map +0 -1
- package/dist/agents/sdk-backend.d.ts +0 -63
- package/dist/agents/sdk-backend.d.ts.map +0 -1
- package/dist/agents/sdk-backend.js +0 -489
- package/dist/agents/sdk-backend.js.map +0 -1
- package/dist/agents/swarm-types.d.ts +0 -84
- package/dist/agents/swarm-types.d.ts.map +0 -1
- package/dist/agents/swarm-types.js +0 -20
- package/dist/agents/swarm-types.js.map +0 -1
- package/dist/agents/swarm.d.ts +0 -79
- package/dist/agents/swarm.d.ts.map +0 -1
- package/dist/agents/swarm.js +0 -375
- package/dist/agents/swarm.js.map +0 -1
- package/dist/agents/tools.d.ts +0 -26
- package/dist/agents/tools.d.ts.map +0 -1
- package/dist/agents/tools.js +0 -776
- package/dist/agents/tools.js.map +0 -1
- package/dist/agents/types.d.ts +0 -108
- package/dist/agents/types.d.ts.map +0 -1
- package/dist/agents/types.js +0 -43
- package/dist/agents/types.js.map +0 -1
- package/dist/api-server.d.ts +0 -45
- package/dist/api-server.d.ts.map +0 -1
- package/dist/api-server.js +0 -326
- package/dist/api-server.js.map +0 -1
- package/dist/auto-checkpoint.d.ts +0 -35
- package/dist/auto-checkpoint.d.ts.map +0 -1
- package/dist/auto-checkpoint.js +0 -176
- package/dist/auto-checkpoint.js.map +0 -1
- package/dist/background-jobs.d.ts +0 -45
- package/dist/background-jobs.d.ts.map +0 -1
- package/dist/background-jobs.js +0 -127
- package/dist/background-jobs.js.map +0 -1
- package/dist/branching.d.ts +0 -56
- package/dist/branching.d.ts.map +0 -1
- package/dist/branching.js +0 -224
- package/dist/branching.js.map +0 -1
- package/dist/cli/agent.d.ts +0 -9
- package/dist/cli/agent.d.ts.map +0 -1
- package/dist/cli/agent.js +0 -330
- package/dist/cli/agent.js.map +0 -1
- package/dist/cli/commands.d.ts +0 -12
- package/dist/cli/commands.d.ts.map +0 -1
- package/dist/cli/commands.js +0 -1042
- package/dist/cli/commands.js.map +0 -1
- package/dist/cli/index.d.ts +0 -8
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js +0 -268
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/types.d.ts +0 -33
- package/dist/cli/types.d.ts.map +0 -1
- package/dist/cli/types.js +0 -21
- package/dist/cli/types.js.map +0 -1
- package/dist/companions.d.ts +0 -54
- package/dist/companions.d.ts.map +0 -1
- package/dist/companions.js +0 -440
- package/dist/companions.js.map +0 -1
- package/dist/file-watcher.d.ts +0 -91
- package/dist/file-watcher.d.ts.map +0 -1
- package/dist/file-watcher.js +0 -269
- package/dist/file-watcher.js.map +0 -1
- package/dist/hud/theme-packs/api.d.ts +0 -51
- package/dist/hud/theme-packs/api.d.ts.map +0 -1
- package/dist/hud/theme-packs/api.js +0 -145
- package/dist/hud/theme-packs/api.js.map +0 -1
- package/dist/hud/theme-packs/index.d.ts +0 -18
- package/dist/hud/theme-packs/index.d.ts.map +0 -1
- package/dist/hud/theme-packs/index.js +0 -38
- package/dist/hud/theme-packs/index.js.map +0 -1
- package/dist/hud/theme-packs/types.d.ts +0 -29
- package/dist/hud/theme-packs/types.d.ts.map +0 -1
- package/dist/hud/theme-packs/types.js +0 -9
- package/dist/hud/theme-packs/types.js.map +0 -1
- package/dist/idle-eviction.d.ts +0 -34
- package/dist/idle-eviction.d.ts.map +0 -1
- package/dist/idle-eviction.js +0 -85
- package/dist/idle-eviction.js.map +0 -1
- package/dist/model-router.d.ts +0 -67
- package/dist/model-router.d.ts.map +0 -1
- package/dist/model-router.js.map +0 -1
- package/dist/providers/openai-compat-shims.d.ts +0 -31
- package/dist/providers/openai-compat-shims.d.ts.map +0 -1
- package/dist/providers/openai-compat-shims.js +0 -179
- package/dist/providers/openai-compat-shims.js.map +0 -1
- package/dist/sandbox-native.d.ts.map +0 -1
- package/dist/sandbox-native.js.map +0 -1
- package/dist/sandbox.d.ts.map +0 -1
- package/dist/sandbox.js.map +0 -1
- package/dist/session-timeout.d.ts +0 -31
- package/dist/session-timeout.d.ts.map +0 -1
- package/dist/session-timeout.js +0 -100
- package/dist/session-timeout.js.map +0 -1
- package/dist/smart-router.d.ts +0 -73
- package/dist/smart-router.d.ts.map +0 -1
- package/dist/smart-router.js +0 -332
- package/dist/smart-router.js.map +0 -1
- package/dist/terminal-recording.d.ts +0 -55
- package/dist/terminal-recording.d.ts.map +0 -1
- package/dist/terminal-recording.js +0 -182
- package/dist/terminal-recording.js.map +0 -1
- package/dist/tmux.d.ts +0 -35
- package/dist/tmux.d.ts.map +0 -1
- package/dist/tmux.js +0 -106
- package/dist/tmux.js.map +0 -1
- package/dist/ui/modals.d.ts +0 -72
- package/dist/ui/modals.d.ts.map +0 -1
- package/dist/ui/modals.js +0 -266
- package/dist/ui/modals.js.map +0 -1
- package/dist/ui/pack-picker.d.ts +0 -12
- package/dist/ui/pack-picker.d.ts.map +0 -1
- package/dist/ui/pack-picker.js +0 -101
- package/dist/ui/pack-picker.js.map +0 -1
- package/dist/ui/theme-picker.d.ts +0 -24
- package/dist/ui/theme-picker.d.ts.map +0 -1
- package/dist/ui/theme-picker.js +0 -190
- package/dist/ui/theme-picker.js.map +0 -1
package/dist/acp.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calliope CLI - Agent Client Protocol (ACP) agent mode.
|
|
3
|
+
*
|
|
4
|
+
* `calliope acp` speaks the Agent Client Protocol (https://agentclientprotocol.com)
|
|
5
|
+
* over stdio JSON-RPC, so editors that speak ACP (Zed, JetBrains, Neovim, …) can
|
|
6
|
+
* drive Calliope as a coding agent. This module is the adapter: it maps the ACP
|
|
7
|
+
* surface onto Calliope's existing agent core (the same provider `chat`, `TOOLS`,
|
|
8
|
+
* `executeTool`, governance and audit pieces the headless runner uses) — no forked
|
|
9
|
+
* agent logic.
|
|
10
|
+
*
|
|
11
|
+
* Baseline agent surface implemented: `initialize`, `authenticate`, `session/new`,
|
|
12
|
+
* `session/prompt`; `session/cancel`; streaming `session/update` notifications; and
|
|
13
|
+
* the `session/request_permission` flow. When the client advertises `fs`
|
|
14
|
+
* capabilities, file tools are routed through the client's `fs/read_text_file` and
|
|
15
|
+
* `fs/write_text_file` so edits land on the editor's (possibly unsaved) buffers.
|
|
16
|
+
*
|
|
17
|
+
* The protocol owns stdout/stdin; ALL diagnostics go to stderr (see {@link log}),
|
|
18
|
+
* so a stray `console.log` never corrupts the JSON-RPC stream. The whole module is
|
|
19
|
+
* lazy-loaded from bin.ts only for the `acp` subcommand, so it adds nothing to the
|
|
20
|
+
* default cold-start path.
|
|
21
|
+
*/
|
|
22
|
+
import { AgentSideConnection, type Agent, type Stream, type InitializeRequest, type InitializeResponse, type NewSessionRequest, type NewSessionResponse, type AuthenticateResponse, type PromptRequest, type PromptResponse, type CancelNotification } from '@zed-industries/agent-client-protocol';
|
|
23
|
+
declare class CalliopeAgent implements Agent {
|
|
24
|
+
private readonly conn;
|
|
25
|
+
private clientCapabilities;
|
|
26
|
+
private readonly sessions;
|
|
27
|
+
/** Tail of the outgoing write chain; awaited to flush notifications. */
|
|
28
|
+
private lastWrite;
|
|
29
|
+
constructor(conn: AgentSideConnection);
|
|
30
|
+
initialize(params: InitializeRequest): Promise<InitializeResponse>;
|
|
31
|
+
authenticate(): Promise<AuthenticateResponse>;
|
|
32
|
+
newSession(params: NewSessionRequest): Promise<NewSessionResponse>;
|
|
33
|
+
prompt(params: PromptRequest): Promise<PromptResponse>;
|
|
34
|
+
cancel(params: CancelNotification): Promise<void>;
|
|
35
|
+
private runTurn;
|
|
36
|
+
/** Flush pending notifications and return the cancelled stop reason. */
|
|
37
|
+
private finishCancelled;
|
|
38
|
+
private runToolCall;
|
|
39
|
+
/** Send a terminal (completed/failed) tool_call_update to the client. */
|
|
40
|
+
private reportToolResult;
|
|
41
|
+
private gateToolCall;
|
|
42
|
+
/**
|
|
43
|
+
* Ask the client to authorize a tool call. Returns the user's decision, or
|
|
44
|
+
* falls back to Calliope's non-interactive default (deny) when the client does
|
|
45
|
+
* not support the permission request at all.
|
|
46
|
+
*/
|
|
47
|
+
private requestPermission;
|
|
48
|
+
/**
|
|
49
|
+
* Build an {@link FsDelegate} that routes file tool reads/writes through the
|
|
50
|
+
* client's `fs/read_text_file` / `fs/write_text_file`, but only for the
|
|
51
|
+
* capabilities the client advertised. Returns undefined when the client has no
|
|
52
|
+
* fs capability, so tools fall back to local disk.
|
|
53
|
+
*/
|
|
54
|
+
private clientFsDelegate;
|
|
55
|
+
/**
|
|
56
|
+
* Send a session/update notification. Writes serialize in call order via the
|
|
57
|
+
* SDK's write queue, so the tail promise flushes everything before it. Errors
|
|
58
|
+
* are swallowed to stderr — a failed notification must never crash the loop.
|
|
59
|
+
*/
|
|
60
|
+
private emit;
|
|
61
|
+
/** Await all pending outgoing notifications. */
|
|
62
|
+
private flush;
|
|
63
|
+
/** Close every session's audit log (best-effort) on shutdown. */
|
|
64
|
+
shutdown(): Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Wire a {@link CalliopeAgent} onto an ACP {@link Stream}. Exposed for tests,
|
|
68
|
+
* which drive the SDK's client side against it over an in-memory stream pair.
|
|
69
|
+
* The SDK calls the factory synchronously, so the returned agent is ready.
|
|
70
|
+
*/
|
|
71
|
+
export declare function serveAcp(stream: Stream): CalliopeAgent;
|
|
72
|
+
/**
|
|
73
|
+
* Run Calliope as an ACP agent over stdio (stdout/stdin carry JSON-RPC). Started
|
|
74
|
+
* from bin.ts when argv[0] === 'acp'. Resolves when the client closes the stream.
|
|
75
|
+
*/
|
|
76
|
+
export declare function runAcpAgent(): Promise<number>;
|
|
77
|
+
export {};
|
|
78
|
+
//# sourceMappingURL=acp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acp.d.ts","sourceRoot":"","sources":["../src/acp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,EACL,mBAAmB,EAInB,KAAK,KAAK,EACV,KAAK,MAAM,EAKX,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACxB,MAAM,uCAAuC,CAAC;AAwK/C,cAAM,aAAc,YAAW,KAAK;IAMtB,OAAO,CAAC,QAAQ,CAAC,IAAI;IALjC,OAAO,CAAC,kBAAkB,CAA0B;IACpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiC;IAC1D,wEAAwE;IACxE,OAAO,CAAC,SAAS,CAAoC;gBAExB,IAAI,EAAE,mBAAmB;IAIhD,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAwBlE,YAAY,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAM7C,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAqDlE,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAoBtD,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;YAUzC,OAAO;IAyErB,wEAAwE;YAC1D,eAAe;YAQf,WAAW;IA6DzB,yEAAyE;IACzE,OAAO,CAAC,gBAAgB;YAkBV,YAAY;IAkC1B;;;;OAIG;YACW,iBAAiB;IAiC/B;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAsBxB;;;;OAIG;IACH,OAAO,CAAC,IAAI;IAQZ,gDAAgD;IAChD,OAAO,CAAC,KAAK;IAIb,iEAAiE;IAC3D,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAehC;AAMD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAQtD;AAED;;;GAGG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAkBnD"}
|
package/dist/acp.js
ADDED
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calliope CLI - Agent Client Protocol (ACP) agent mode.
|
|
3
|
+
*
|
|
4
|
+
* `calliope acp` speaks the Agent Client Protocol (https://agentclientprotocol.com)
|
|
5
|
+
* over stdio JSON-RPC, so editors that speak ACP (Zed, JetBrains, Neovim, …) can
|
|
6
|
+
* drive Calliope as a coding agent. This module is the adapter: it maps the ACP
|
|
7
|
+
* surface onto Calliope's existing agent core (the same provider `chat`, `TOOLS`,
|
|
8
|
+
* `executeTool`, governance and audit pieces the headless runner uses) — no forked
|
|
9
|
+
* agent logic.
|
|
10
|
+
*
|
|
11
|
+
* Baseline agent surface implemented: `initialize`, `authenticate`, `session/new`,
|
|
12
|
+
* `session/prompt`; `session/cancel`; streaming `session/update` notifications; and
|
|
13
|
+
* the `session/request_permission` flow. When the client advertises `fs`
|
|
14
|
+
* capabilities, file tools are routed through the client's `fs/read_text_file` and
|
|
15
|
+
* `fs/write_text_file` so edits land on the editor's (possibly unsaved) buffers.
|
|
16
|
+
*
|
|
17
|
+
* The protocol owns stdout/stdin; ALL diagnostics go to stderr (see {@link log}),
|
|
18
|
+
* so a stray `console.log` never corrupts the JSON-RPC stream. The whole module is
|
|
19
|
+
* lazy-loaded from bin.ts only for the `acp` subcommand, so it adds nothing to the
|
|
20
|
+
* default cold-start path.
|
|
21
|
+
*/
|
|
22
|
+
import * as path from 'node:path';
|
|
23
|
+
import { Readable, Writable } from 'node:stream';
|
|
24
|
+
import { AgentSideConnection, ndJsonStream, RequestError, PROTOCOL_VERSION, } from '@zed-industries/agent-client-protocol';
|
|
25
|
+
import * as config from './config.js';
|
|
26
|
+
import { chat, selectProvider } from './providers/index.js';
|
|
27
|
+
import { TOOLS, executeTool } from './tools.js';
|
|
28
|
+
import { DEFAULT_MODELS, calculateCost } from './types.js';
|
|
29
|
+
import { getSystemPromptForProvider, isLocalBackend } from './local-model.js';
|
|
30
|
+
import * as memory from './memory.js';
|
|
31
|
+
import { resolveIterationLimit } from './iteration-limit.js';
|
|
32
|
+
import { RunLog } from './runlog.js';
|
|
33
|
+
import { evaluatePolicy, isPolicyEnabled } from './policy.js';
|
|
34
|
+
import { assessToolRisk } from './risk.js';
|
|
35
|
+
import { checkHooksAllow } from './hooks.js';
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// Diagnostics — stderr only (stdout carries the protocol).
|
|
38
|
+
// ============================================================================
|
|
39
|
+
function log(message) {
|
|
40
|
+
process.stderr.write(`[calliope-acp] ${message}\n`);
|
|
41
|
+
}
|
|
42
|
+
/** Chatty per-request trace, gated on CALLIOPE_DEBUG (matches the rest of the CLI). */
|
|
43
|
+
function debug(message) {
|
|
44
|
+
if (process.env.CALLIOPE_DEBUG === '1')
|
|
45
|
+
log(message);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Best-effort human message from a thrown value. Handles Error instances and the
|
|
49
|
+
* bare `{ code, message, data }` JSON-RPC error object the SDK rejects with.
|
|
50
|
+
*/
|
|
51
|
+
function errMessage(err) {
|
|
52
|
+
if (err instanceof Error)
|
|
53
|
+
return err.message;
|
|
54
|
+
if (typeof err === 'object' && err !== null && 'message' in err) {
|
|
55
|
+
const m = err.message;
|
|
56
|
+
if (typeof m === 'string')
|
|
57
|
+
return m;
|
|
58
|
+
}
|
|
59
|
+
return String(err);
|
|
60
|
+
}
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// Tool → permission / presentation mapping
|
|
63
|
+
// ============================================================================
|
|
64
|
+
/**
|
|
65
|
+
* Tools with side effects. These always route through the permission flow (and
|
|
66
|
+
* are denied under the non-interactive fallback), matching the headless runner's
|
|
67
|
+
* notion of a mutating tool.
|
|
68
|
+
*/
|
|
69
|
+
const MUTATING_TOOLS = new Set(['shell', 'write_file', 'edit_file', 'git', 'execute_code', 'configure']);
|
|
70
|
+
/**
|
|
71
|
+
* Whether a tool call must ask the client for permission before running.
|
|
72
|
+
* Read-only tools (read_file, list_files, think, glob, grep, web_search) run
|
|
73
|
+
* silently; anything that mutates state or that Calliope's risk model flags for
|
|
74
|
+
* confirmation asks first.
|
|
75
|
+
*/
|
|
76
|
+
function toolNeedsPermission(toolCall) {
|
|
77
|
+
if (MUTATING_TOOLS.has(toolCall.name))
|
|
78
|
+
return true;
|
|
79
|
+
return assessToolRisk(toolCall).requiresConfirmation;
|
|
80
|
+
}
|
|
81
|
+
/** Map a Calliope tool name to the ACP tool kind (drives client icons/UX). */
|
|
82
|
+
function toolKind(name) {
|
|
83
|
+
switch (name) {
|
|
84
|
+
case 'read_file':
|
|
85
|
+
case 'list_files':
|
|
86
|
+
case 'glob':
|
|
87
|
+
case 'grep':
|
|
88
|
+
return 'read';
|
|
89
|
+
case 'write_file':
|
|
90
|
+
case 'edit_file':
|
|
91
|
+
return 'edit';
|
|
92
|
+
case 'shell':
|
|
93
|
+
case 'execute_code':
|
|
94
|
+
case 'git':
|
|
95
|
+
return 'execute';
|
|
96
|
+
case 'web_search':
|
|
97
|
+
case 'web_fetch':
|
|
98
|
+
return 'fetch';
|
|
99
|
+
case 'think':
|
|
100
|
+
case 'create_plan':
|
|
101
|
+
return 'think';
|
|
102
|
+
default:
|
|
103
|
+
return 'other';
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** A short human-readable title for a tool call, e.g. `read_file: src/a.ts`. */
|
|
107
|
+
function toolTitle(toolCall) {
|
|
108
|
+
const a = toolCall.arguments;
|
|
109
|
+
const hint = typeof a.path === 'string'
|
|
110
|
+
? a.path
|
|
111
|
+
: typeof a.command === 'string'
|
|
112
|
+
? a.command
|
|
113
|
+
: typeof a.pattern === 'string'
|
|
114
|
+
? a.pattern
|
|
115
|
+
: typeof a.query === 'string'
|
|
116
|
+
? a.query
|
|
117
|
+
: '';
|
|
118
|
+
return hint ? `${toolCall.name}: ${hint}` : toolCall.name;
|
|
119
|
+
}
|
|
120
|
+
/** Absolute file location(s) a tool touches, for the client's follow-along UI. */
|
|
121
|
+
function toolLocations(toolCall, cwd) {
|
|
122
|
+
const p = toolCall.arguments.path;
|
|
123
|
+
if (typeof p !== 'string' || p.length === 0)
|
|
124
|
+
return undefined;
|
|
125
|
+
return [{ path: path.isAbsolute(p) ? p : path.join(cwd, p) }];
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Flatten an ACP prompt (content blocks) into the plain text Calliope's agent
|
|
129
|
+
* loop consumes. Baseline requires Text and ResourceLink; a resource link is
|
|
130
|
+
* surfaced as an `@uri` mention, and an embedded text resource is inlined.
|
|
131
|
+
*/
|
|
132
|
+
function promptToText(blocks) {
|
|
133
|
+
const parts = [];
|
|
134
|
+
for (const block of blocks) {
|
|
135
|
+
if (block.type === 'text') {
|
|
136
|
+
parts.push(block.text);
|
|
137
|
+
}
|
|
138
|
+
else if (block.type === 'resource_link') {
|
|
139
|
+
parts.push(`@${block.uri}`);
|
|
140
|
+
}
|
|
141
|
+
else if (block.type === 'resource') {
|
|
142
|
+
const resource = block.resource;
|
|
143
|
+
if (typeof resource.text === 'string') {
|
|
144
|
+
parts.push(resource.text);
|
|
145
|
+
}
|
|
146
|
+
else if (typeof resource.uri === 'string') {
|
|
147
|
+
parts.push(`@${resource.uri}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// image / audio blocks are not advertised in promptCapabilities; ignore.
|
|
151
|
+
}
|
|
152
|
+
return parts.join('\n');
|
|
153
|
+
}
|
|
154
|
+
// ============================================================================
|
|
155
|
+
// The agent
|
|
156
|
+
// ============================================================================
|
|
157
|
+
class CalliopeAgent {
|
|
158
|
+
conn;
|
|
159
|
+
clientCapabilities = {};
|
|
160
|
+
sessions = new Map();
|
|
161
|
+
/** Tail of the outgoing write chain; awaited to flush notifications. */
|
|
162
|
+
lastWrite = Promise.resolve();
|
|
163
|
+
constructor(conn) {
|
|
164
|
+
this.conn = conn;
|
|
165
|
+
}
|
|
166
|
+
// ---- ACP: initialize --------------------------------------------------
|
|
167
|
+
async initialize(params) {
|
|
168
|
+
this.clientCapabilities = params.clientCapabilities ?? {};
|
|
169
|
+
const requested = typeof params.protocolVersion === 'number' ? params.protocolVersion : PROTOCOL_VERSION;
|
|
170
|
+
// Negotiate down to the newest version we both support (we support 1).
|
|
171
|
+
const negotiated = requested >= 1 && requested <= PROTOCOL_VERSION ? requested : PROTOCOL_VERSION;
|
|
172
|
+
debug(`initialize: client protocol v${requested} -> v${negotiated}; ` +
|
|
173
|
+
`fs=${JSON.stringify(this.clientCapabilities.fs ?? {})} terminal=${this.clientCapabilities.terminal ?? false}`);
|
|
174
|
+
return {
|
|
175
|
+
protocolVersion: negotiated,
|
|
176
|
+
agentCapabilities: {
|
|
177
|
+
// session/load, MCP-over-ACP, and modes are not implemented yet.
|
|
178
|
+
loadSession: false,
|
|
179
|
+
promptCapabilities: { image: false, audio: false, embeddedContext: false },
|
|
180
|
+
},
|
|
181
|
+
// Calliope authenticates via locally-configured provider keys, so no ACP
|
|
182
|
+
// auth method is required.
|
|
183
|
+
authMethods: [],
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
// ---- ACP: authenticate (no-op; no auth methods advertised) ------------
|
|
187
|
+
async authenticate() {
|
|
188
|
+
return {};
|
|
189
|
+
}
|
|
190
|
+
// ---- ACP: session/new -------------------------------------------------
|
|
191
|
+
async newSession(params) {
|
|
192
|
+
const cwd = params.cwd || process.cwd();
|
|
193
|
+
const provider = process.env.CALLIOPE_PROVIDER || config.get('defaultProvider');
|
|
194
|
+
const model = process.env.CALLIOPE_MODEL || config.get('defaultModel') || '';
|
|
195
|
+
// Resolve the provider so 'auto' picks a real backend for the system prompt,
|
|
196
|
+
// cost model, and local-backend flag (mirrors the headless runner). Fall back
|
|
197
|
+
// to the raw provider if selection throws (chat() surfaces the real error).
|
|
198
|
+
let resolvedProvider;
|
|
199
|
+
try {
|
|
200
|
+
resolvedProvider = selectProvider(provider);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
resolvedProvider = provider;
|
|
204
|
+
}
|
|
205
|
+
const localBackend = isLocalBackend(resolvedProvider);
|
|
206
|
+
const costModel = model || DEFAULT_MODELS[resolvedProvider];
|
|
207
|
+
const sessionId = `acp_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
208
|
+
const runlog = RunLog.open(sessionId);
|
|
209
|
+
runlog.runStart({
|
|
210
|
+
session: sessionId,
|
|
211
|
+
cwd,
|
|
212
|
+
provider: resolvedProvider,
|
|
213
|
+
model: costModel,
|
|
214
|
+
config: config.getConfig(),
|
|
215
|
+
mode: 'acp',
|
|
216
|
+
});
|
|
217
|
+
const systemPrompt = getSystemPromptForProvider(resolvedProvider);
|
|
218
|
+
const memoryContext = memory.buildMemoryContext(cwd);
|
|
219
|
+
const fullPrompt = memoryContext.trim()
|
|
220
|
+
? systemPrompt + '\n\n--- Project Context ---\n' + memoryContext
|
|
221
|
+
: systemPrompt;
|
|
222
|
+
this.sessions.set(sessionId, {
|
|
223
|
+
id: sessionId,
|
|
224
|
+
cwd,
|
|
225
|
+
provider,
|
|
226
|
+
resolvedProvider,
|
|
227
|
+
model,
|
|
228
|
+
localBackend,
|
|
229
|
+
messages: [{ role: 'system', content: fullPrompt }],
|
|
230
|
+
runlog,
|
|
231
|
+
cancelled: false,
|
|
232
|
+
totals: { inputTokens: 0, outputTokens: 0, cost: 0, toolCalls: 0 },
|
|
233
|
+
startedAt: Date.now(),
|
|
234
|
+
});
|
|
235
|
+
debug(`session/new: ${sessionId} cwd=${cwd} provider=${resolvedProvider} model=${costModel}`);
|
|
236
|
+
return { sessionId };
|
|
237
|
+
}
|
|
238
|
+
// ---- ACP: session/prompt ---------------------------------------------
|
|
239
|
+
async prompt(params) {
|
|
240
|
+
const session = this.sessions.get(params.sessionId);
|
|
241
|
+
if (!session) {
|
|
242
|
+
throw RequestError.invalidParams({ error: `unknown session: ${params.sessionId}` });
|
|
243
|
+
}
|
|
244
|
+
// Each prompt is a fresh turn; clear any stale cancel from a prior turn.
|
|
245
|
+
session.cancelled = false;
|
|
246
|
+
const text = promptToText(params.prompt);
|
|
247
|
+
session.messages.push({ role: 'user', content: text });
|
|
248
|
+
session.runlog.userPrompt(text);
|
|
249
|
+
debug(`session/prompt: ${session.id} (${text.length} chars)`);
|
|
250
|
+
const stopReason = await this.runTurn(session);
|
|
251
|
+
await session.runlog.flush();
|
|
252
|
+
return { stopReason };
|
|
253
|
+
}
|
|
254
|
+
// ---- ACP: session/cancel (notification) -------------------------------
|
|
255
|
+
async cancel(params) {
|
|
256
|
+
const session = this.sessions.get(params.sessionId);
|
|
257
|
+
if (session) {
|
|
258
|
+
session.cancelled = true;
|
|
259
|
+
debug(`session/cancel: ${params.sessionId}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// ---- The agent loop (ACP-flavoured mirror of the headless loop) --------
|
|
263
|
+
async runTurn(session) {
|
|
264
|
+
const maxIterations = resolveIterationLimit(config.get('maxIterations'));
|
|
265
|
+
const costModel = session.model || DEFAULT_MODELS[session.resolvedProvider];
|
|
266
|
+
let iteration = 0;
|
|
267
|
+
while (iteration < maxIterations) {
|
|
268
|
+
if (session.cancelled)
|
|
269
|
+
return this.finishCancelled(session);
|
|
270
|
+
iteration++;
|
|
271
|
+
// Stream assistant text as agent_message_chunk deltas via the chat seam.
|
|
272
|
+
let streamedChars = 0;
|
|
273
|
+
const onToken = (token) => {
|
|
274
|
+
if (!token)
|
|
275
|
+
return;
|
|
276
|
+
streamedChars += token.length;
|
|
277
|
+
this.emit(session.id, { sessionUpdate: 'agent_message_chunk', content: { type: 'text', text: token } });
|
|
278
|
+
};
|
|
279
|
+
let response;
|
|
280
|
+
try {
|
|
281
|
+
response = await chat(session.provider, session.messages, TOOLS, session.model || undefined, onToken);
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
const msg = errMessage(err);
|
|
285
|
+
log(`chat error: ${msg}`);
|
|
286
|
+
session.runlog.assistantMessage({ content: `[error: ${msg}]`, tokens: { input: 0, output: 0 }, cost: 0 });
|
|
287
|
+
await session.runlog.flush();
|
|
288
|
+
throw RequestError.internalError({ error: msg });
|
|
289
|
+
}
|
|
290
|
+
// Audit + spend accounting (mirrors headless).
|
|
291
|
+
if (response.usage) {
|
|
292
|
+
const cost = calculateCost(costModel, response.usage.inputTokens, response.usage.outputTokens);
|
|
293
|
+
session.totals.inputTokens += response.usage.inputTokens;
|
|
294
|
+
session.totals.outputTokens += response.usage.outputTokens;
|
|
295
|
+
session.totals.cost += cost;
|
|
296
|
+
session.runlog.assistantMessage({
|
|
297
|
+
content: response.content,
|
|
298
|
+
tokens: { input: response.usage.inputTokens, output: response.usage.outputTokens },
|
|
299
|
+
cost,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
session.runlog.assistantMessage({ content: response.content, tokens: { input: 0, output: 0 }, cost: 0 });
|
|
304
|
+
}
|
|
305
|
+
// Providers that don't stream: emit the assembled content once so the
|
|
306
|
+
// client still sees the assistant message.
|
|
307
|
+
if (streamedChars === 0 && response.content) {
|
|
308
|
+
this.emit(session.id, { sessionUpdate: 'agent_message_chunk', content: { type: 'text', text: response.content } });
|
|
309
|
+
}
|
|
310
|
+
if (session.cancelled)
|
|
311
|
+
return this.finishCancelled(session);
|
|
312
|
+
if (response.toolCalls && response.toolCalls.length > 0) {
|
|
313
|
+
session.messages.push({ role: 'assistant', content: response.content, toolCalls: response.toolCalls });
|
|
314
|
+
for (const toolCall of response.toolCalls) {
|
|
315
|
+
if (session.cancelled)
|
|
316
|
+
return this.finishCancelled(session);
|
|
317
|
+
const outcome = await this.runToolCall(session, toolCall);
|
|
318
|
+
if (outcome === 'cancelled')
|
|
319
|
+
return this.finishCancelled(session);
|
|
320
|
+
}
|
|
321
|
+
continue; // next model turn
|
|
322
|
+
}
|
|
323
|
+
// No tool calls: this is the final assistant message → end of turn.
|
|
324
|
+
session.messages.push({ role: 'assistant', content: response.content });
|
|
325
|
+
await this.flush();
|
|
326
|
+
return response.finishReason === 'length' ? 'max_tokens' : 'end_turn';
|
|
327
|
+
}
|
|
328
|
+
// Exhausted the iteration budget.
|
|
329
|
+
await this.flush();
|
|
330
|
+
return 'max_turn_requests';
|
|
331
|
+
}
|
|
332
|
+
/** Flush pending notifications and return the cancelled stop reason. */
|
|
333
|
+
async finishCancelled(session) {
|
|
334
|
+
debug(`turn cancelled: ${session.id}`);
|
|
335
|
+
await this.flush();
|
|
336
|
+
return 'cancelled';
|
|
337
|
+
}
|
|
338
|
+
// ---- One tool call: announce → gate → execute → report ----------------
|
|
339
|
+
async runToolCall(session, toolCall) {
|
|
340
|
+
session.runlog.toolCall({ id: toolCall.id, name: toolCall.name, args: toolCall.arguments });
|
|
341
|
+
session.totals.toolCalls++;
|
|
342
|
+
// Announce the pending tool call.
|
|
343
|
+
await this.emit(session.id, {
|
|
344
|
+
sessionUpdate: 'tool_call',
|
|
345
|
+
toolCallId: toolCall.id,
|
|
346
|
+
title: toolTitle(toolCall),
|
|
347
|
+
kind: toolKind(toolCall.name),
|
|
348
|
+
status: 'pending',
|
|
349
|
+
rawInput: toolCall.arguments,
|
|
350
|
+
locations: toolLocations(toolCall, session.cwd),
|
|
351
|
+
});
|
|
352
|
+
// Permission + hard governance gates.
|
|
353
|
+
const gate = await this.gateToolCall(session, toolCall);
|
|
354
|
+
if (gate.decision === 'cancelled') {
|
|
355
|
+
await this.reportToolResult(session, toolCall.id, '[cancelled]', true);
|
|
356
|
+
session.runlog.toolResult({ id: toolCall.id, result: '[cancelled]', isError: true, durationMs: 0 });
|
|
357
|
+
session.messages.push({ role: 'tool', content: '[cancelled]', toolCallId: toolCall.id });
|
|
358
|
+
return 'cancelled';
|
|
359
|
+
}
|
|
360
|
+
if (gate.decision === 'deny') {
|
|
361
|
+
await this.reportToolResult(session, toolCall.id, gate.reason, true);
|
|
362
|
+
session.runlog.toolResult({ id: toolCall.id, result: gate.reason, isError: true, durationMs: 0 });
|
|
363
|
+
session.messages.push({ role: 'tool', content: gate.reason, toolCallId: toolCall.id });
|
|
364
|
+
return 'ok';
|
|
365
|
+
}
|
|
366
|
+
// Allowed: mark in-progress and execute through the shared tool runtime,
|
|
367
|
+
// preferring the client's filesystem when it advertised fs capabilities.
|
|
368
|
+
await this.emit(session.id, { sessionUpdate: 'tool_call_update', toolCallId: toolCall.id, status: 'in_progress' });
|
|
369
|
+
const started = Date.now();
|
|
370
|
+
let result;
|
|
371
|
+
try {
|
|
372
|
+
result = await executeTool(toolCall, session.cwd, 60000, undefined, {
|
|
373
|
+
appendAnchorHash: session.localBackend,
|
|
374
|
+
fs: this.clientFsDelegate(session.id),
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
catch (err) {
|
|
378
|
+
result = {
|
|
379
|
+
toolCallId: toolCall.id,
|
|
380
|
+
result: `Error: ${errMessage(err)}`,
|
|
381
|
+
isError: true,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
const durationMs = Date.now() - started;
|
|
385
|
+
session.runlog.toolResult({
|
|
386
|
+
id: toolCall.id,
|
|
387
|
+
result: result.result,
|
|
388
|
+
isError: result.isError || false,
|
|
389
|
+
durationMs,
|
|
390
|
+
});
|
|
391
|
+
await this.reportToolResult(session, toolCall.id, result.displayResult || result.result, result.isError || false, result.result);
|
|
392
|
+
session.messages.push({ role: 'tool', content: result.result, toolCallId: toolCall.id });
|
|
393
|
+
return 'ok';
|
|
394
|
+
}
|
|
395
|
+
/** Send a terminal (completed/failed) tool_call_update to the client. */
|
|
396
|
+
reportToolResult(session, toolCallId, text, isError, rawResult) {
|
|
397
|
+
return this.emit(session.id, {
|
|
398
|
+
sessionUpdate: 'tool_call_update',
|
|
399
|
+
toolCallId,
|
|
400
|
+
status: isError ? 'failed' : 'completed',
|
|
401
|
+
content: [{ type: 'content', content: { type: 'text', text } }],
|
|
402
|
+
rawOutput: { result: rawResult ?? text, isError },
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
// ---- Gates: permission, then the hard hooks -------------------------
|
|
406
|
+
async gateToolCall(session, toolCall) {
|
|
407
|
+
// 1. Permission via the client (only for mutating / confirm-worthy tools).
|
|
408
|
+
if (toolNeedsPermission(toolCall)) {
|
|
409
|
+
const permission = await this.requestPermission(session, toolCall);
|
|
410
|
+
if (permission === 'cancelled')
|
|
411
|
+
return { decision: 'cancelled' };
|
|
412
|
+
if (permission === 'reject')
|
|
413
|
+
return { decision: 'deny', reason: '[Permission denied by user]' };
|
|
414
|
+
// 'allow' falls through to the hard gates below.
|
|
415
|
+
}
|
|
416
|
+
// 2. Pre-tool hooks — the hard gate, runs regardless of permission (exit-42
|
|
417
|
+
// veto contract; see hooks.ts / docs/governance.md).
|
|
418
|
+
const hookGate = await checkHooksAllow('pre-tool', { tool: toolCall.name, toolArgs: toolCall.arguments });
|
|
419
|
+
if (!hookGate.allowed) {
|
|
420
|
+
return { decision: 'deny', reason: `[Blocked by hook: ${hookGate.reason || 'no reason given'}]` };
|
|
421
|
+
}
|
|
422
|
+
// 3. Policy hook — the Zentinelle integration point (fail closed).
|
|
423
|
+
if (isPolicyEnabled()) {
|
|
424
|
+
const verdict = await evaluatePolicy(toolCall);
|
|
425
|
+
session.runlog.policyEvent({
|
|
426
|
+
tool: toolCall.name,
|
|
427
|
+
decision: verdict.decision,
|
|
428
|
+
source: verdict.source,
|
|
429
|
+
reason: verdict.reason,
|
|
430
|
+
durationMs: verdict.durationMs,
|
|
431
|
+
});
|
|
432
|
+
if (verdict.decision === 'deny') {
|
|
433
|
+
return { decision: 'deny', reason: `[Policy denied: ${verdict.reason || 'no reason given'}]` };
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return { decision: 'allow' };
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Ask the client to authorize a tool call. Returns the user's decision, or
|
|
440
|
+
* falls back to Calliope's non-interactive default (deny) when the client does
|
|
441
|
+
* not support the permission request at all.
|
|
442
|
+
*/
|
|
443
|
+
async requestPermission(session, toolCall) {
|
|
444
|
+
try {
|
|
445
|
+
const res = await this.conn.requestPermission({
|
|
446
|
+
sessionId: session.id,
|
|
447
|
+
toolCall: {
|
|
448
|
+
toolCallId: toolCall.id,
|
|
449
|
+
title: toolTitle(toolCall),
|
|
450
|
+
kind: toolKind(toolCall.name),
|
|
451
|
+
rawInput: toolCall.arguments,
|
|
452
|
+
},
|
|
453
|
+
options: [
|
|
454
|
+
{ optionId: 'allow', name: 'Allow', kind: 'allow_once' },
|
|
455
|
+
{ optionId: 'allow_always', name: 'Always allow', kind: 'allow_always' },
|
|
456
|
+
{ optionId: 'reject', name: 'Reject', kind: 'reject_once' },
|
|
457
|
+
],
|
|
458
|
+
});
|
|
459
|
+
const outcome = res.outcome;
|
|
460
|
+
if (outcome.outcome === 'cancelled')
|
|
461
|
+
return 'cancelled';
|
|
462
|
+
if (outcome.outcome === 'selected')
|
|
463
|
+
return outcome.optionId.startsWith('allow') ? 'allow' : 'reject';
|
|
464
|
+
return 'reject';
|
|
465
|
+
}
|
|
466
|
+
catch (err) {
|
|
467
|
+
// Client can't handle permission requests: non-interactive default is to
|
|
468
|
+
// deny anything that needed asking (read-only tools never reach here).
|
|
469
|
+
log(`requestPermission unavailable (${errMessage(err)}); ` +
|
|
470
|
+
`denying ${toolCall.name} under the non-interactive default`);
|
|
471
|
+
return 'reject';
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
// ---- Client-side filesystem delegate ---------------------------------
|
|
475
|
+
/**
|
|
476
|
+
* Build an {@link FsDelegate} that routes file tool reads/writes through the
|
|
477
|
+
* client's `fs/read_text_file` / `fs/write_text_file`, but only for the
|
|
478
|
+
* capabilities the client advertised. Returns undefined when the client has no
|
|
479
|
+
* fs capability, so tools fall back to local disk.
|
|
480
|
+
*/
|
|
481
|
+
clientFsDelegate(sessionId) {
|
|
482
|
+
const fsCap = this.clientCapabilities.fs;
|
|
483
|
+
if (!fsCap || (!fsCap.readTextFile && !fsCap.writeTextFile))
|
|
484
|
+
return undefined;
|
|
485
|
+
const conn = this.conn;
|
|
486
|
+
const delegate = {};
|
|
487
|
+
if (fsCap.readTextFile) {
|
|
488
|
+
delegate.readTextFile = async (absPath) => {
|
|
489
|
+
const res = await conn.readTextFile({ sessionId, path: absPath });
|
|
490
|
+
return res.content;
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
if (fsCap.writeTextFile) {
|
|
494
|
+
delegate.writeTextFile = async (absPath, content) => {
|
|
495
|
+
await conn.writeTextFile({ sessionId, path: absPath, content });
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
return delegate;
|
|
499
|
+
}
|
|
500
|
+
// ---- Notification plumbing -------------------------------------------
|
|
501
|
+
/**
|
|
502
|
+
* Send a session/update notification. Writes serialize in call order via the
|
|
503
|
+
* SDK's write queue, so the tail promise flushes everything before it. Errors
|
|
504
|
+
* are swallowed to stderr — a failed notification must never crash the loop.
|
|
505
|
+
*/
|
|
506
|
+
emit(sessionId, update) {
|
|
507
|
+
const p = this.conn.sessionUpdate({ sessionId, update }).catch((err) => {
|
|
508
|
+
log(`sessionUpdate failed: ${errMessage(err)}`);
|
|
509
|
+
});
|
|
510
|
+
this.lastWrite = p;
|
|
511
|
+
return p;
|
|
512
|
+
}
|
|
513
|
+
/** Await all pending outgoing notifications. */
|
|
514
|
+
flush() {
|
|
515
|
+
return this.lastWrite;
|
|
516
|
+
}
|
|
517
|
+
/** Close every session's audit log (best-effort) on shutdown. */
|
|
518
|
+
async shutdown() {
|
|
519
|
+
for (const session of this.sessions.values()) {
|
|
520
|
+
session.runlog.runEnd({
|
|
521
|
+
totals: {
|
|
522
|
+
inputTokens: session.totals.inputTokens,
|
|
523
|
+
outputTokens: session.totals.outputTokens,
|
|
524
|
+
cost: session.totals.cost,
|
|
525
|
+
toolCalls: session.totals.toolCalls,
|
|
526
|
+
durationMs: Date.now() - session.startedAt,
|
|
527
|
+
},
|
|
528
|
+
exitReason: session.cancelled ? 'cancelled' : 'completed',
|
|
529
|
+
});
|
|
530
|
+
await session.runlog.close();
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
// ============================================================================
|
|
535
|
+
// Entry points
|
|
536
|
+
// ============================================================================
|
|
537
|
+
/**
|
|
538
|
+
* Wire a {@link CalliopeAgent} onto an ACP {@link Stream}. Exposed for tests,
|
|
539
|
+
* which drive the SDK's client side against it over an in-memory stream pair.
|
|
540
|
+
* The SDK calls the factory synchronously, so the returned agent is ready.
|
|
541
|
+
*/
|
|
542
|
+
export function serveAcp(stream) {
|
|
543
|
+
let agent;
|
|
544
|
+
// eslint-disable-next-line no-new -- the connection registers itself and reads.
|
|
545
|
+
new AgentSideConnection((conn) => {
|
|
546
|
+
agent = new CalliopeAgent(conn);
|
|
547
|
+
return agent;
|
|
548
|
+
}, stream);
|
|
549
|
+
return agent;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Run Calliope as an ACP agent over stdio (stdout/stdin carry JSON-RPC). Started
|
|
553
|
+
* from bin.ts when argv[0] === 'acp'. Resolves when the client closes the stream.
|
|
554
|
+
*/
|
|
555
|
+
export async function runAcpAgent() {
|
|
556
|
+
const input = Readable.toWeb(process.stdin);
|
|
557
|
+
const output = Writable.toWeb(process.stdout);
|
|
558
|
+
const stream = ndJsonStream(output, input);
|
|
559
|
+
const agent = serveAcp(stream);
|
|
560
|
+
log(`Calliope ACP agent ready on stdio (protocol v${PROTOCOL_VERSION}). Logs go to stderr.`);
|
|
561
|
+
// Stay alive until the client disconnects (stdin closes).
|
|
562
|
+
await new Promise((resolve) => {
|
|
563
|
+
const done = () => resolve();
|
|
564
|
+
process.stdin.on('end', done);
|
|
565
|
+
process.stdin.on('close', done);
|
|
566
|
+
process.stdin.on('error', done);
|
|
567
|
+
});
|
|
568
|
+
await agent.shutdown();
|
|
569
|
+
log('ACP client disconnected; shutting down.');
|
|
570
|
+
return 0;
|
|
571
|
+
}
|
|
572
|
+
//# sourceMappingURL=acp.js.map
|