@armadra/agent 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +174 -1
- package/README.md +201 -82
- package/THIRD_PARTY_NOTICES.md +34 -0
- package/dist/acp.d.ts +18 -0
- package/dist/acp.js +19 -0
- package/dist/agent/limits.d.ts +38 -0
- package/dist/agent/limits.js +127 -0
- package/dist/agent/loop-guard.d.ts +38 -0
- package/dist/agent/loop-guard.js +95 -0
- package/dist/agent/loop.d.ts +4 -0
- package/dist/agent/loop.js +7 -0
- package/dist/agent/prompt-rules.d.ts +12 -0
- package/dist/agent/prompt-rules.js +18 -0
- package/dist/agent/reminders.d.ts +59 -0
- package/dist/agent/reminders.js +327 -0
- package/dist/agent/session-cache.d.ts +5 -0
- package/dist/agent/session-cache.js +17 -1
- package/dist/agent/session-classifier.d.ts +1 -1
- package/dist/agent/session-classifier.js +3 -1
- package/dist/agent/session-compaction.d.ts +35 -6
- package/dist/agent/session-compaction.js +157 -31
- package/dist/agent/session-core.d.ts +27 -1
- package/dist/agent/session-extensions.d.ts +61 -0
- package/dist/agent/session-extensions.js +129 -0
- package/dist/agent/session-images.d.ts +23 -0
- package/dist/agent/session-images.js +97 -0
- package/dist/agent/session-plan.d.ts +21 -0
- package/dist/agent/session-plan.js +524 -0
- package/dist/agent/session-rewind.d.ts +81 -0
- package/dist/agent/session-rewind.js +354 -0
- package/dist/agent/session-run.d.ts +28 -1
- package/dist/agent/session-run.js +157 -6
- package/dist/agent/session-settings.d.ts +49 -0
- package/dist/agent/session-settings.js +95 -0
- package/dist/agent/session-subagent.d.ts +36 -24
- package/dist/agent/session-subagent.js +259 -129
- package/dist/agent/session-sync.d.ts +10 -3
- package/dist/agent/session-sync.js +37 -8
- package/dist/agent/session-telemetry.d.ts +39 -0
- package/dist/agent/session-telemetry.js +231 -0
- package/dist/agent/session-tools.js +40 -1
- package/dist/agent/session.d.ts +30 -29
- package/dist/agent/session.js +79 -123
- package/dist/agent/subagent-registry.d.ts +91 -0
- package/dist/agent/subagent-registry.js +494 -0
- package/dist/agent/system-prompt.d.ts +6 -3
- package/dist/agent/system-prompt.js +7 -2
- package/dist/agent/tool-runner.d.ts +8 -1
- package/dist/agent/tool-runner.js +57 -4
- package/dist/agent/types-w5.d.ts +192 -0
- package/dist/agent/types-w5.js +10 -0
- package/dist/agent/types.d.ts +47 -4
- package/dist/agent/types.js +2 -0
- package/dist/agent/worktree.d.ts +36 -0
- package/dist/agent/worktree.js +86 -0
- package/dist/agents/builtin.d.ts +14 -0
- package/dist/agents/builtin.js +39 -0
- package/dist/agents/catalog.d.ts +43 -0
- package/dist/agents/catalog.js +82 -0
- package/dist/agents/discover.d.ts +35 -0
- package/dist/agents/discover.js +83 -0
- package/dist/agents/external.d.ts +82 -0
- package/dist/agents/external.js +326 -0
- package/dist/agents/parse.d.ts +18 -0
- package/dist/agents/parse.js +116 -0
- package/dist/agents/result.d.ts +32 -0
- package/dist/agents/result.js +67 -0
- package/dist/agents/task-control.d.ts +17 -0
- package/dist/agents/task-control.js +17 -0
- package/dist/agents/task-record.d.ts +78 -0
- package/dist/agents/task-record.js +141 -0
- package/dist/agents/types.d.ts +46 -0
- package/dist/agents/types.js +8 -0
- package/dist/ai/apis/anthropic-compat.d.ts +36 -0
- package/dist/ai/apis/anthropic-compat.js +92 -0
- package/dist/ai/apis/anthropic-request.d.ts +7 -6
- package/dist/ai/apis/anthropic-request.js +10 -28
- package/dist/ai/apis/cache-params.d.ts +11 -2
- package/dist/ai/apis/cache-params.js +25 -6
- package/dist/ai/apis/openai-compat.d.ts +4 -1
- package/dist/ai/apis/openai-compat.js +8 -1
- package/dist/ai/image-limits.d.ts +45 -0
- package/dist/ai/image-limits.js +68 -0
- package/dist/ai/providers/builtin.d.ts +18 -6
- package/dist/ai/providers/builtin.js +135 -6
- package/dist/ai/providers/catalog-data.js +17 -13
- package/dist/ai/providers/catalog.d.ts +60 -7
- package/dist/ai/providers/catalog.js +197 -38
- package/dist/ai/providers/channels.d.ts +33 -3
- package/dist/ai/providers/channels.js +108 -7
- package/dist/ai/providers/enrich.d.ts +6 -3
- package/dist/ai/providers/enrich.js +19 -4
- package/dist/ai/providers/models-dev-cache.d.ts +28 -24
- package/dist/ai/providers/models-dev-cache.js +92 -78
- package/dist/ai/providers/models-dev-data.d.ts +7 -0
- package/dist/ai/providers/models-dev-data.js +32 -0
- package/dist/ai/providers/models-dev-snapshot.d.ts +50 -0
- package/dist/ai/providers/models-dev-snapshot.js +137 -0
- package/dist/ai/providers/models-dev.d.ts +51 -10
- package/dist/ai/providers/models-dev.js +132 -39
- package/dist/ai/providers/registry.d.ts +20 -10
- package/dist/ai/providers/registry.js +82 -43
- package/dist/ai/types.d.ts +28 -2
- package/dist/ai/types.js +5 -0
- package/dist/bundle/ama.cjs +36203 -20499
- package/dist/checkpoints/backend.d.ts +61 -0
- package/dist/checkpoints/backend.js +135 -0
- package/dist/checkpoints/blobs.d.ts +60 -0
- package/dist/checkpoints/blobs.js +203 -0
- package/dist/checkpoints/gc.d.ts +47 -0
- package/dist/checkpoints/gc.js +144 -0
- package/dist/checkpoints/git-head.d.ts +15 -0
- package/dist/checkpoints/git-head.js +89 -0
- package/dist/checkpoints/index.d.ts +17 -0
- package/dist/checkpoints/index.js +17 -0
- package/dist/checkpoints/replay.d.ts +48 -0
- package/dist/checkpoints/replay.js +154 -0
- package/dist/checkpoints/restore.d.ts +86 -0
- package/dist/checkpoints/restore.js +263 -0
- package/dist/checkpoints/settings.d.ts +14 -0
- package/dist/checkpoints/settings.js +23 -0
- package/dist/checkpoints/shadow-git.d.ts +108 -0
- package/dist/checkpoints/shadow-git.js +491 -0
- package/dist/checkpoints/shadow-restore.d.ts +25 -0
- package/dist/checkpoints/shadow-restore.js +128 -0
- package/dist/checkpoints/tracker.d.ts +64 -0
- package/dist/checkpoints/tracker.js +192 -0
- package/dist/checkpoints/types.d.ts +99 -0
- package/dist/checkpoints/types.js +12 -0
- package/dist/cli/args.d.ts +8 -4
- package/dist/cli/args.js +17 -97
- package/dist/cli/bootstrap.js +13 -1
- package/dist/cli/codemode-notice.d.ts +3 -2
- package/dist/cli/codemode-notice.js +3 -2
- package/dist/cli/compose-agents.d.ts +27 -0
- package/dist/cli/compose-agents.js +111 -0
- package/dist/cli/compose-extensions.d.ts +29 -0
- package/dist/cli/compose-extensions.js +44 -0
- package/dist/cli/compose-session.d.ts +3 -0
- package/dist/cli/compose-session.js +47 -4
- package/dist/cli/compose.d.ts +3 -0
- package/dist/cli/compose.js +33 -6
- package/dist/cli/deps.d.ts +6 -0
- package/dist/cli/exit-codes.d.ts +10 -0
- package/dist/cli/exit-codes.js +12 -0
- package/dist/cli/help-text.d.ts +4 -0
- package/dist/cli/help-text.js +102 -0
- package/dist/cli/startup-screen.js +5 -3
- package/dist/cli/startup-steps.js +7 -1
- package/dist/cli/subcommands/config.d.ts +4 -1
- package/dist/cli/subcommands/config.js +17 -6
- package/dist/cli/subcommands/doctor.js +21 -0
- package/dist/cli/subcommands/models-discover.js +5 -6
- package/dist/cli/subcommands/models.d.ts +2 -0
- package/dist/cli/subcommands/models.js +33 -14
- package/dist/cli/subcommands/providers.js +5 -6
- package/dist/cli/subcommands/sessions.d.ts +3 -1
- package/dist/cli/subcommands/sessions.js +36 -2
- package/dist/codemode/capability.d.ts +24 -7
- package/dist/codemode/capability.js +38 -10
- package/dist/codemode/host-side.d.ts +14 -0
- package/dist/codemode/host-side.js +24 -1
- package/dist/codemode/tool.d.ts +1 -1
- package/dist/codemode/tool.js +6 -4
- package/dist/compaction/breaker.d.ts +25 -9
- package/dist/compaction/breaker.js +47 -17
- package/dist/compaction/estimate.d.ts +11 -3
- package/dist/compaction/estimate.js +64 -22
- package/dist/compaction/image-budget.d.ts +45 -0
- package/dist/compaction/image-budget.js +115 -0
- package/dist/compaction/post-compact.d.ts +38 -0
- package/dist/compaction/post-compact.js +152 -0
- package/dist/compaction/protect.d.ts +27 -0
- package/dist/compaction/protect.js +56 -0
- package/dist/compaction/prune-tier.d.ts +58 -12
- package/dist/compaction/prune-tier.js +120 -54
- package/dist/compaction/summarize-tier.d.ts +23 -4
- package/dist/compaction/summarize-tier.js +100 -29
- package/dist/config/checker.d.ts +28 -0
- package/dist/config/checker.js +97 -0
- package/dist/config/json-schema.js +63 -2
- package/dist/config/key-docs.js +72 -3
- package/dist/config/merge.d.ts +5 -3
- package/dist/config/merge.js +81 -7
- package/dist/config/profile.d.ts +2 -0
- package/dist/config/profile.js +2 -0
- package/dist/config/schema-w5.d.ts +18 -0
- package/dist/config/schema-w5.js +109 -0
- package/dist/config/schema.d.ts +5 -9
- package/dist/config/schema.js +68 -114
- package/dist/config/types-w5.d.ts +118 -0
- package/dist/config/types-w5.js +20 -0
- package/dist/config/types.d.ts +50 -1
- package/dist/config/types.js +12 -0
- package/dist/drivers/acp/client.d.ts +57 -0
- package/dist/drivers/acp/client.js +160 -0
- package/dist/drivers/acp/driver.d.ts +31 -0
- package/dist/drivers/acp/driver.js +274 -0
- package/dist/drivers/acp/testing/fake-agent-main.d.ts +5 -0
- package/dist/drivers/acp/testing/fake-agent-main.js +7 -0
- package/dist/drivers/acp/testing/fake-agent.d.ts +27 -0
- package/dist/drivers/acp/testing/fake-agent.js +211 -0
- package/dist/drivers/acp/types.d.ts +285 -0
- package/dist/drivers/acp/types.js +36 -0
- package/dist/drivers/agents.d.ts +58 -0
- package/dist/drivers/agents.js +142 -0
- package/dist/drivers/base.d.ts +35 -0
- package/dist/drivers/base.js +59 -0
- package/dist/drivers/catalog.d.ts +46 -0
- package/dist/drivers/catalog.js +167 -0
- package/dist/drivers/env.d.ts +20 -0
- package/dist/drivers/env.js +46 -0
- package/dist/drivers/host-runners.d.ts +18 -0
- package/dist/drivers/host-runners.js +45 -0
- package/dist/drivers/jsonrpc.d.ts +58 -0
- package/dist/drivers/jsonrpc.js +180 -0
- package/dist/drivers/native/claude-normalize.d.ts +46 -0
- package/dist/drivers/native/claude-normalize.js +106 -0
- package/dist/drivers/native/claude-stream.d.ts +29 -0
- package/dist/drivers/native/claude-stream.js +456 -0
- package/dist/drivers/native/codex-app-server.d.ts +26 -0
- package/dist/drivers/native/codex-app-server.js +407 -0
- package/dist/drivers/native/codex-normalize.d.ts +38 -0
- package/dist/drivers/native/codex-normalize.js +124 -0
- package/dist/drivers/native/oneshot.d.ts +28 -0
- package/dist/drivers/native/oneshot.js +312 -0
- package/dist/drivers/permissions.d.ts +40 -0
- package/dist/drivers/permissions.js +92 -0
- package/dist/drivers/pids.d.ts +32 -0
- package/dist/drivers/pids.js +93 -0
- package/dist/drivers/pool.d.ts +28 -0
- package/dist/drivers/pool.js +96 -0
- package/dist/drivers/probe.d.ts +47 -0
- package/dist/drivers/probe.js +172 -0
- package/dist/drivers/process.d.ts +48 -0
- package/dist/drivers/process.js +100 -0
- package/dist/drivers/runner.d.ts +61 -0
- package/dist/drivers/runner.js +388 -0
- package/dist/drivers/store.d.ts +49 -0
- package/dist/drivers/store.js +91 -0
- package/dist/drivers/turn.d.ts +41 -0
- package/dist/drivers/turn.js +99 -0
- package/dist/drivers/types.d.ts +122 -0
- package/dist/drivers/types.js +11 -0
- package/dist/git/info.d.ts +75 -0
- package/dist/git/info.js +191 -0
- package/dist/hooks/protocol.js +6 -1
- package/dist/hooks/types.d.ts +10 -1
- package/dist/hooks/types.js +2 -0
- package/dist/host/api-impl.d.ts +7 -0
- package/dist/host/api-impl.js +15 -0
- package/dist/host/types.d.ts +24 -2
- package/dist/host/types.js +4 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -0
- package/dist/modes/acp/acp-events.d.ts +46 -0
- package/dist/modes/acp/acp-events.js +233 -0
- package/dist/modes/acp/acp-mode.d.ts +17 -0
- package/dist/modes/acp/acp-mode.js +47 -0
- package/dist/modes/acp/acp-server.d.ts +79 -0
- package/dist/modes/acp/acp-server.js +315 -0
- package/dist/modes/commands-core.d.ts +7 -1
- package/dist/modes/commands-core.js +55 -0
- package/dist/modes/image-input.d.ts +12 -4
- package/dist/modes/image-input.js +22 -5
- package/dist/modes/interactive/agent-panels.d.ts +14 -0
- package/dist/modes/interactive/agent-panels.js +103 -0
- package/dist/modes/interactive/agent-ui.d.ts +73 -0
- package/dist/modes/interactive/agent-ui.js +234 -0
- package/dist/modes/interactive/approval-dialog.d.ts +21 -4
- package/dist/modes/interactive/approval-dialog.js +98 -20
- package/dist/modes/interactive/approval-merge.d.ts +41 -0
- package/dist/modes/interactive/approval-merge.js +89 -0
- package/dist/modes/interactive/clipboard-paste.d.ts +18 -0
- package/dist/modes/interactive/clipboard-paste.js +28 -0
- package/dist/modes/interactive/commands.d.ts +9 -1
- package/dist/modes/interactive/commands.js +19 -0
- package/dist/modes/interactive/double-esc.d.ts +20 -0
- package/dist/modes/interactive/double-esc.js +34 -0
- package/dist/modes/interactive/event-notices.d.ts +32 -0
- package/dist/modes/interactive/event-notices.js +79 -0
- package/dist/modes/interactive/external-editor.d.ts +16 -0
- package/dist/modes/interactive/external-editor.js +39 -0
- package/dist/modes/interactive/interactive-mode.d.ts +14 -1
- package/dist/modes/interactive/interactive-mode.js +134 -136
- package/dist/modes/interactive/key-dispatch.d.ts +16 -2
- package/dist/modes/interactive/key-dispatch.js +49 -1
- package/dist/modes/interactive/line/line-mode.d.ts +2 -1
- package/dist/modes/interactive/line/line-mode.js +22 -5
- package/dist/modes/interactive/line/line-render.d.ts +2 -1
- package/dist/modes/interactive/line/line-render.js +40 -4
- package/dist/modes/interactive/message-view.d.ts +1 -1
- package/dist/modes/interactive/message-view.js +24 -2
- package/dist/modes/interactive/panels.d.ts +18 -1
- package/dist/modes/interactive/panels.js +19 -5
- package/dist/modes/interactive/plan-command.d.ts +40 -0
- package/dist/modes/interactive/plan-command.js +129 -0
- package/dist/modes/interactive/plan-dialog.d.ts +98 -0
- package/dist/modes/interactive/plan-dialog.js +290 -0
- package/dist/modes/interactive/plan-flow.d.ts +34 -0
- package/dist/modes/interactive/plan-flow.js +98 -0
- package/dist/modes/interactive/rewind-command.d.ts +31 -0
- package/dist/modes/interactive/rewind-command.js +106 -0
- package/dist/modes/interactive/rewind-flow.d.ts +37 -0
- package/dist/modes/interactive/rewind-flow.js +151 -0
- package/dist/modes/interactive/rewind-list.d.ts +36 -0
- package/dist/modes/interactive/rewind-list.js +123 -0
- package/dist/modes/interactive/rewind-panel.d.ts +77 -0
- package/dist/modes/interactive/rewind-panel.js +309 -0
- package/dist/modes/interactive/rewind-text.d.ts +40 -0
- package/dist/modes/interactive/rewind-text.js +139 -0
- package/dist/modes/interactive/session-events.d.ts +24 -0
- package/dist/modes/interactive/session-events.js +96 -0
- package/dist/modes/interactive/status-area.d.ts +73 -0
- package/dist/modes/interactive/status-area.js +190 -0
- package/dist/modes/interactive/status-bar.d.ts +99 -11
- package/dist/modes/interactive/status-bar.js +273 -90
- package/dist/modes/interactive/status-line.d.ts +33 -0
- package/dist/modes/interactive/status-line.js +113 -0
- package/dist/modes/interactive/subagent-view.d.ts +56 -0
- package/dist/modes/interactive/subagent-view.js +154 -0
- package/dist/modes/interactive/tasks-report.d.ts +27 -0
- package/dist/modes/interactive/tasks-report.js +114 -0
- package/dist/modes/interactive/tool-view.d.ts +12 -2
- package/dist/modes/interactive/tool-view.js +34 -4
- package/dist/modes/print/print-mode.d.ts +13 -4
- package/dist/modes/print/print-mode.js +56 -12
- package/dist/modes/rpc/commands.d.ts +9 -0
- package/dist/modes/rpc/commands.js +44 -0
- package/dist/modes/rpc/rpc-mode.js +7 -1
- package/dist/modes/session-report.d.ts +11 -0
- package/dist/modes/session-report.js +48 -1
- package/dist/permissions/auto-safe.d.ts +5 -0
- package/dist/permissions/auto-safe.js +18 -0
- package/dist/permissions/classifier.d.ts +4 -0
- package/dist/permissions/classifier.js +2 -0
- package/dist/permissions/modes.js +1 -1
- package/dist/permissions/pipeline.d.ts +43 -4
- package/dist/permissions/pipeline.js +114 -9
- package/dist/permissions/readonly-bash.d.ts +30 -0
- package/dist/permissions/readonly-bash.js +118 -0
- package/dist/permissions/types.d.ts +42 -0
- package/dist/plan/compose.d.ts +9 -0
- package/dist/plan/compose.js +19 -0
- package/dist/plan/controller.d.ts +71 -0
- package/dist/plan/controller.js +27 -0
- package/dist/plan/done-markers.d.ts +17 -0
- package/dist/plan/done-markers.js +51 -0
- package/dist/plan/extract.d.ts +29 -0
- package/dist/plan/extract.js +160 -0
- package/dist/plan/prompts.d.ts +36 -0
- package/dist/plan/prompts.js +89 -0
- package/dist/plan/store.d.ts +37 -0
- package/dist/plan/store.js +90 -0
- package/dist/rpc.d.ts +58 -2
- package/dist/rpc.js +7 -0
- package/dist/sandbox/bash.d.ts +74 -0
- package/dist/sandbox/bash.js +126 -0
- package/dist/sandbox/detect.d.ts +48 -0
- package/dist/sandbox/detect.js +149 -0
- package/dist/sandbox/index.d.ts +5 -0
- package/dist/sandbox/index.js +5 -0
- package/dist/sandbox/profile.d.ts +33 -0
- package/dist/sandbox/profile.js +76 -0
- package/dist/sandbox/wrap.d.ts +29 -0
- package/dist/sandbox/wrap.js +117 -0
- package/dist/sdk.d.ts +33 -2
- package/dist/sdk.js +24 -2
- package/dist/session/types.d.ts +3 -1
- package/dist/session/types.js +1 -0
- package/dist/skills/builtin.d.ts +31 -0
- package/dist/skills/builtin.js +109 -0
- package/dist/skills/discover.d.ts +2 -1
- package/dist/skills/index-prompt.js +5 -8
- package/dist/tools/background-jobs.d.ts +71 -0
- package/dist/tools/background-jobs.js +198 -0
- package/dist/tools/bash.d.ts +53 -1
- package/dist/tools/bash.js +158 -7
- package/dist/tools/clipboard-image.d.ts +44 -0
- package/dist/tools/clipboard-image.js +148 -0
- package/dist/tools/edit.d.ts +2 -0
- package/dist/tools/edit.js +18 -3
- package/dist/tools/image-file.d.ts +38 -3
- package/dist/tools/image-file.js +81 -10
- package/dist/tools/image-resize.d.ts +58 -0
- package/dist/tools/image-resize.js +97 -0
- package/dist/tools/presets.d.ts +7 -2
- package/dist/tools/presets.js +11 -4
- package/dist/tools/read.d.ts +5 -2
- package/dist/tools/read.js +13 -10
- package/dist/tools/registry.d.ts +7 -1
- package/dist/tools/registry.js +27 -4
- package/dist/tools/task-ctl.d.ts +22 -0
- package/dist/tools/task-ctl.js +116 -0
- package/dist/tools/task.d.ts +22 -10
- package/dist/tools/task.js +66 -26
- package/dist/tools/todo.d.ts +22 -2
- package/dist/tools/todo.js +58 -14
- package/dist/tools/truncate.d.ts +15 -0
- package/dist/tools/truncate.js +25 -0
- package/dist/tools/types.d.ts +113 -0
- package/dist/tools/types.js +5 -0
- package/dist/tools/write.js +3 -0
- package/dist/tui/glyphs.d.ts +4 -0
- package/dist/tui/glyphs.js +4 -0
- package/dist/tui/keybindings.d.ts +5 -0
- package/dist/tui/keybindings.js +5 -0
- package/docs/acp.md +78 -0
- package/docs/agents.md +250 -0
- package/docs/codemode.md +12 -8
- package/docs/hooks.md +26 -22
- package/docs/permissions.md +77 -13
- package/docs/plan.md +107 -0
- package/docs/providers.md +228 -52
- package/docs/rewind-plan.md +181 -0
- package/docs/rpc.md +92 -5
- package/docs/sandbox.md +215 -0
- package/docs/session-format.md +41 -21
- package/docs/sessions.md +41 -1
- package/docs/tui-design.md +751 -0
- package/docs/tui.md +125 -6
- package/package.json +13 -2
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 外部 Agent 的入口(W5-G 的 `task(agent=…)` 经它拿 runner,docs/wave5-plan.md §5.5、§7.6、D13、D17)。[W5-E]
|
|
3
|
+
*
|
|
4
|
+
* - `resolve("claude" | "codex" | "acp:<program>" | 表里的 id)` → {@link ProcessRunner}(按驱动表候选链,
|
|
5
|
+
* 每次 `start` 时按模式与安装情况选驱动);同一 spec 复用同一个 runner。
|
|
6
|
+
* - 宿主(`HostApi.runners.provide`)注入的 runner 优先:同名替换内置外部 runner。
|
|
7
|
+
* - **有宿主(profile.host)时不自 spawn**:内置外部 runner 一律不可用,只认宿主注入的(D17;绕过画布
|
|
8
|
+
* spawn 会让节点、连线授权与审批全部失效)。
|
|
9
|
+
* - 共用一个并发池、一个探测缓存(`<dataDir>/drivers.json`)与 pid 登记(`<dataDir>/drivers/pids.json`;
|
|
10
|
+
* 首次创建时清理上次崩溃留下的孤儿进程)。
|
|
11
|
+
*/
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { AmaError } from "../errors.js";
|
|
14
|
+
import { AcpDriver } from "./acp/driver.js";
|
|
15
|
+
import { DRIVER_CATALOG, candidatesFor } from "./catalog.js";
|
|
16
|
+
import { HostRunnerRegistry } from "./host-runners.js";
|
|
17
|
+
import { ClaudeStreamDriver } from "./native/claude-stream.js";
|
|
18
|
+
import { CodexAppServerDriver } from "./native/codex-app-server.js";
|
|
19
|
+
import { OneshotDriver } from "./native/oneshot.js";
|
|
20
|
+
import { PidRegistry, pidsFile } from "./pids.js";
|
|
21
|
+
import { poolFromConfig } from "./pool.js";
|
|
22
|
+
import { ProgramProbe } from "./probe.js";
|
|
23
|
+
import { spawnTransport } from "./process.js";
|
|
24
|
+
import { ProcessRunner } from "./runner.js";
|
|
25
|
+
/** 按候选种类建驱动。 */
|
|
26
|
+
export function createDriver(agentId, candidate, deps) {
|
|
27
|
+
switch (candidate.kind) {
|
|
28
|
+
case "acp":
|
|
29
|
+
case "acp-adapter":
|
|
30
|
+
return new AcpDriver(agentId, candidate, deps);
|
|
31
|
+
case "claude-stream":
|
|
32
|
+
return new ClaudeStreamDriver(agentId, candidate, deps);
|
|
33
|
+
case "codex-app-server":
|
|
34
|
+
return new CodexAppServerDriver(agentId, candidate, deps);
|
|
35
|
+
case "oneshot":
|
|
36
|
+
return new OneshotDriver(agentId, candidate, deps);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export { HostRunnerRegistry };
|
|
40
|
+
let reaped = false;
|
|
41
|
+
export class ExternalAgents {
|
|
42
|
+
options;
|
|
43
|
+
hostRunners;
|
|
44
|
+
pool;
|
|
45
|
+
runners = new Map();
|
|
46
|
+
driverDeps;
|
|
47
|
+
constructor(options) {
|
|
48
|
+
this.options = options;
|
|
49
|
+
this.hostRunners = options.hostRunners ?? new HostRunnerRegistry();
|
|
50
|
+
this.pool = poolFromConfig(options.config);
|
|
51
|
+
const registry = options.dataDir !== undefined ? new PidRegistry(pidsFile(options.dataDir)) : undefined;
|
|
52
|
+
if (registry !== undefined && !reaped && options.driverDeps?.spawn === undefined) {
|
|
53
|
+
reaped = true;
|
|
54
|
+
void registry
|
|
55
|
+
.reapOrphans()
|
|
56
|
+
.then((killed) => {
|
|
57
|
+
if (killed.length > 0)
|
|
58
|
+
options.log?.("info", `清理了上次遗留的外部 Agent 进程:${killed.join(", ")}`);
|
|
59
|
+
})
|
|
60
|
+
.catch(() => undefined);
|
|
61
|
+
}
|
|
62
|
+
const log = options.log;
|
|
63
|
+
this.driverDeps = {
|
|
64
|
+
probe: new ProgramProbe({
|
|
65
|
+
env: options.env,
|
|
66
|
+
cwd: options.cwd,
|
|
67
|
+
...(options.dataDir !== undefined
|
|
68
|
+
? { cacheFile: join(options.dataDir, "drivers.json") }
|
|
69
|
+
: {}),
|
|
70
|
+
}),
|
|
71
|
+
spawn: (spec) => spawnTransport(spec, {
|
|
72
|
+
onSpawn: (pid) => registry?.add(pid, spec.program),
|
|
73
|
+
onExit: (pid) => registry?.remove(pid),
|
|
74
|
+
}),
|
|
75
|
+
...(log !== undefined ? { log } : {}),
|
|
76
|
+
...options.driverDeps,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/** `task(agent=<spec>)` 的 runner;不可用时抛 AmaError(`agent_host_only` / `agent_unknown`)。 */
|
|
80
|
+
resolve(spec) {
|
|
81
|
+
const hosted = this.hostRunners.get(spec);
|
|
82
|
+
if (hosted !== undefined)
|
|
83
|
+
return hosted;
|
|
84
|
+
if (this.options.hosted)
|
|
85
|
+
throw new AmaError("agent_host_only", `嵌入宿主时外部 Agent 由宿主提供:「${spec}」没有被宿主注入(ama 不自行启动外部 CLI)`);
|
|
86
|
+
const cached = this.runners.get(spec);
|
|
87
|
+
if (cached !== undefined)
|
|
88
|
+
return cached;
|
|
89
|
+
const found = candidatesFor(spec);
|
|
90
|
+
if (found === undefined)
|
|
91
|
+
throw new AmaError("agent_unknown", `未知的外部 Agent:${spec}`);
|
|
92
|
+
const drivers = found.candidates.map((c) => createDriver(found.agentId, c, this.driverDeps));
|
|
93
|
+
const o = this.options;
|
|
94
|
+
const runner = new ProcessRunner(drivers, {
|
|
95
|
+
approve: o.approve,
|
|
96
|
+
pool: this.pool,
|
|
97
|
+
env: o.env,
|
|
98
|
+
trusted: o.trusted,
|
|
99
|
+
...(o.store !== undefined ? { store: o.store } : {}),
|
|
100
|
+
...(o.config !== undefined ? { config: o.config } : {}),
|
|
101
|
+
...(o.parentMode !== undefined ? { parentMode: o.parentMode } : {}),
|
|
102
|
+
...(o.unattended !== undefined ? { unattended: o.unattended } : {}),
|
|
103
|
+
...(o.log !== undefined ? { log: o.log } : {}),
|
|
104
|
+
});
|
|
105
|
+
this.runners.set(spec, runner);
|
|
106
|
+
return runner;
|
|
107
|
+
}
|
|
108
|
+
/** `/agents` 与 RPC `get_agents` 的外部 Agent 部分(探测 PATH 与版本,不联网)。 */
|
|
109
|
+
async list() {
|
|
110
|
+
const out = this.hostRunners.list().map((r) => ({
|
|
111
|
+
name: r.id,
|
|
112
|
+
description: r.description,
|
|
113
|
+
runner: r.id,
|
|
114
|
+
source: "host",
|
|
115
|
+
}));
|
|
116
|
+
if (this.options.hosted)
|
|
117
|
+
return out;
|
|
118
|
+
for (const entry of DRIVER_CATALOG) {
|
|
119
|
+
if (out.some((a) => a.name === entry.agentId))
|
|
120
|
+
continue;
|
|
121
|
+
let installed = false;
|
|
122
|
+
let version;
|
|
123
|
+
for (const c of entry.candidates) {
|
|
124
|
+
const probe = await createDriver(entry.agentId, c, this.driverDeps).probe();
|
|
125
|
+
if (probe.installed) {
|
|
126
|
+
installed = true;
|
|
127
|
+
version = probe.version;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
out.push({
|
|
132
|
+
name: entry.agentId,
|
|
133
|
+
description: entry.label,
|
|
134
|
+
runner: entry.agentId,
|
|
135
|
+
source: "builtin",
|
|
136
|
+
installed,
|
|
137
|
+
...(version !== undefined ? { version } : {}),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return out;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 各驱动共用的依赖与看门狗(docs/wave5-plan.md §5.4)。[W5-E]
|
|
3
|
+
*/
|
|
4
|
+
import type { PermissionMode } from "../permissions/types.js";
|
|
5
|
+
import type { CatalogCandidate } from "./catalog.js";
|
|
6
|
+
import type { ProgramProbe } from "./probe.js";
|
|
7
|
+
import { type AgentTransport, type SpawnTransport } from "./process.js";
|
|
8
|
+
import type { DriverProbe } from "./types.js";
|
|
9
|
+
/** 中断后等回合结束的宽限;过了关 stdin,再 SIGTERM 进程树(§5.2 cancel)。 */
|
|
10
|
+
export declare const CANCEL_GRACE_MS = 15000;
|
|
11
|
+
export interface DriverDeps {
|
|
12
|
+
/** 缺省起真实子进程。 */
|
|
13
|
+
spawn?: SpawnTransport;
|
|
14
|
+
/** 缺省:认为已安装(测试 / 宿主注入的 transport 用)。 */
|
|
15
|
+
probe?: ProgramProbe;
|
|
16
|
+
log?(level: "debug" | "info" | "warn", message: string): void;
|
|
17
|
+
/** 缺省 {@link CANCEL_GRACE_MS}。 */
|
|
18
|
+
cancelGraceMs?: number;
|
|
19
|
+
/** 计时器(测试注入假时钟)。 */
|
|
20
|
+
setTimer?(fn: () => void, ms: number): () => void;
|
|
21
|
+
}
|
|
22
|
+
export declare function defaultSetTimer(fn: () => void, ms: number): () => void;
|
|
23
|
+
export declare function spawnOf(deps: DriverDeps): SpawnTransport;
|
|
24
|
+
/** 探测一个候选:已安装、版本、静态能力;版本越过已验证区间时附 warn。 */
|
|
25
|
+
export declare function probeCandidate(candidate: CatalogCandidate, deps: DriverDeps): Promise<DriverProbe & {
|
|
26
|
+
path?: string;
|
|
27
|
+
warning?: string;
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* 中断的看门狗:发出协议级中断后,`graceMs` 内回合没结束就关 stdin 并杀进程树。
|
|
31
|
+
* 返回取消函数(回合正常结束时调用)。
|
|
32
|
+
*/
|
|
33
|
+
export declare function armCancelWatchdog(transport: AgentTransport, turnDone: Promise<unknown>, deps: DriverDeps): () => void;
|
|
34
|
+
/** 模式是否只读类(plan / allowlist):没有对应映射时不能让外部 Agent 以缺省模式跑。 */
|
|
35
|
+
export declare function isReadOnlyMode(mode: PermissionMode): boolean;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 各驱动共用的依赖与看门狗(docs/wave5-plan.md §5.4)。[W5-E]
|
|
3
|
+
*/
|
|
4
|
+
import { candidateCapabilities } from "./catalog.js";
|
|
5
|
+
import { versionSatisfies } from "./probe.js";
|
|
6
|
+
import { spawnTransport } from "./process.js";
|
|
7
|
+
/** 中断后等回合结束的宽限;过了关 stdin,再 SIGTERM 进程树(§5.2 cancel)。 */
|
|
8
|
+
export const CANCEL_GRACE_MS = 15_000;
|
|
9
|
+
export function defaultSetTimer(fn, ms) {
|
|
10
|
+
const timer = setTimeout(fn, ms);
|
|
11
|
+
timer.unref?.();
|
|
12
|
+
return () => clearTimeout(timer);
|
|
13
|
+
}
|
|
14
|
+
export function spawnOf(deps) {
|
|
15
|
+
return deps.spawn ?? ((spec) => spawnTransport(spec));
|
|
16
|
+
}
|
|
17
|
+
/** 探测一个候选:已安装、版本、静态能力;版本越过已验证区间时附 warn。 */
|
|
18
|
+
export async function probeCandidate(candidate, deps) {
|
|
19
|
+
const capabilities = candidateCapabilities(candidate);
|
|
20
|
+
if (deps.probe === undefined)
|
|
21
|
+
return { installed: true, capabilities };
|
|
22
|
+
const located = await deps.probe.locate(candidate.program, candidate.versionArgs);
|
|
23
|
+
if (located === undefined)
|
|
24
|
+
return { installed: false, capabilities };
|
|
25
|
+
const out = {
|
|
26
|
+
installed: true,
|
|
27
|
+
capabilities,
|
|
28
|
+
path: located.path,
|
|
29
|
+
};
|
|
30
|
+
if (located.version !== undefined)
|
|
31
|
+
out.version = located.version;
|
|
32
|
+
if (candidate.verified !== undefined &&
|
|
33
|
+
located.version !== undefined &&
|
|
34
|
+
!versionSatisfies(located.version, candidate.verified))
|
|
35
|
+
out.warning = `${candidate.program} ${located.version} 不在已验证区间 ${candidate.verified},协议可能有变化`;
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 中断的看门狗:发出协议级中断后,`graceMs` 内回合没结束就关 stdin 并杀进程树。
|
|
40
|
+
* 返回取消函数(回合正常结束时调用)。
|
|
41
|
+
*/
|
|
42
|
+
export function armCancelWatchdog(transport, turnDone, deps) {
|
|
43
|
+
const setTimer = deps.setTimer ?? defaultSetTimer;
|
|
44
|
+
let fired = false;
|
|
45
|
+
const clear = setTimer(() => {
|
|
46
|
+
fired = true;
|
|
47
|
+
deps.log?.("warn", "外部 Agent 中断后未在宽限内结束回合,关闭进程");
|
|
48
|
+
void transport.terminate();
|
|
49
|
+
}, deps.cancelGraceMs ?? CANCEL_GRACE_MS);
|
|
50
|
+
void turnDone.finally(() => {
|
|
51
|
+
if (!fired)
|
|
52
|
+
clear();
|
|
53
|
+
});
|
|
54
|
+
return clear;
|
|
55
|
+
}
|
|
56
|
+
/** 模式是否只读类(plan / allowlist):没有对应映射时不能让外部 Agent 以缺省模式跑。 */
|
|
57
|
+
export function isReadOnlyMode(mode) {
|
|
58
|
+
return mode === "plan" || mode === "allowlist";
|
|
59
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 内置驱动表(数据,docs/wave5-plan.md §5.1 catalog.ts,D14)。[W5-E]
|
|
3
|
+
*
|
|
4
|
+
* agentId → 候选链;按 D14 的优先级排:原生 ACP > 已装 ACP 适配器 > 原生结构化协议 > 一次性打印。
|
|
5
|
+
* 探测时取第一个已安装的候选。`verified` 是实测过的版本区间:越界仍可用,但发一条 warn 提示
|
|
6
|
+
* (R3:Claude stream-json 不是公开接口、Codex app-server 标 experimental)。没有实测过的
|
|
7
|
+
* ACP Agent 不写 `verified`,`/agents` 标「未验证」。
|
|
8
|
+
*
|
|
9
|
+
* `runner: acp:<program>` 时先按程序名找本表里的 ACP 候选(拿到参数与模式映射),找不到就以
|
|
10
|
+
* 无参数的通用 ACP 启动。
|
|
11
|
+
*/
|
|
12
|
+
import type { PermissionMode } from "../permissions/types.js";
|
|
13
|
+
import type { DriverCapabilities, DriverKind } from "./types.js";
|
|
14
|
+
export type CandidateKind = Exclude<DriverKind, "host">;
|
|
15
|
+
export interface CatalogCandidate {
|
|
16
|
+
kind: CandidateKind;
|
|
17
|
+
program: string;
|
|
18
|
+
args: readonly string[];
|
|
19
|
+
/** `--version` 以外的版本参数。 */
|
|
20
|
+
versionArgs?: readonly string[];
|
|
21
|
+
/** 实测过的版本区间(`>=x.y.z <x.y.z`)。 */
|
|
22
|
+
verified?: string;
|
|
23
|
+
/** ama 模式 → 该 Agent 的 ACP 模式 id(`session/set_mode`);缺省按同名匹配。 */
|
|
24
|
+
modes?: Partial<Record<PermissionMode, string>>;
|
|
25
|
+
permissions?: DriverCapabilities["permissions"];
|
|
26
|
+
usage?: DriverCapabilities["usage"];
|
|
27
|
+
/** 一次性打印模式的方言。 */
|
|
28
|
+
oneshot?: "claude" | "codex" | "gemini";
|
|
29
|
+
}
|
|
30
|
+
export interface CatalogEntry {
|
|
31
|
+
agentId: string;
|
|
32
|
+
label: string;
|
|
33
|
+
candidates: readonly CatalogCandidate[];
|
|
34
|
+
}
|
|
35
|
+
export declare const DRIVER_CATALOG: readonly CatalogEntry[];
|
|
36
|
+
export declare function catalogEntry(agentId: string): CatalogEntry | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* `runner` 规格 → 候选链:`claude` / `codex` 与表中 id 走表;`acp:<program>` 取表里同程序名的
|
|
39
|
+
* ACP 候选,否则通用 ACP(无参数)。
|
|
40
|
+
*/
|
|
41
|
+
export declare function candidatesFor(spec: string): {
|
|
42
|
+
agentId: string;
|
|
43
|
+
candidates: CatalogCandidate[];
|
|
44
|
+
} | undefined;
|
|
45
|
+
/** 候选的静态能力(ACP 的会话能力要到 initialize 才知道,这里取保守值)。 */
|
|
46
|
+
export declare function candidateCapabilities(c: CatalogCandidate): DriverCapabilities;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 内置驱动表(数据,docs/wave5-plan.md §5.1 catalog.ts,D14)。[W5-E]
|
|
3
|
+
*
|
|
4
|
+
* agentId → 候选链;按 D14 的优先级排:原生 ACP > 已装 ACP 适配器 > 原生结构化协议 > 一次性打印。
|
|
5
|
+
* 探测时取第一个已安装的候选。`verified` 是实测过的版本区间:越界仍可用,但发一条 warn 提示
|
|
6
|
+
* (R3:Claude stream-json 不是公开接口、Codex app-server 标 experimental)。没有实测过的
|
|
7
|
+
* ACP Agent 不写 `verified`,`/agents` 标「未验证」。
|
|
8
|
+
*
|
|
9
|
+
* `runner: acp:<program>` 时先按程序名找本表里的 ACP 候选(拿到参数与模式映射),找不到就以
|
|
10
|
+
* 无参数的通用 ACP 启动。
|
|
11
|
+
*/
|
|
12
|
+
const ALL_MODES = [
|
|
13
|
+
"plan",
|
|
14
|
+
"allowlist",
|
|
15
|
+
"default",
|
|
16
|
+
"auto-edit",
|
|
17
|
+
"auto",
|
|
18
|
+
"full-auto",
|
|
19
|
+
];
|
|
20
|
+
export const DRIVER_CATALOG = [
|
|
21
|
+
{
|
|
22
|
+
agentId: "claude",
|
|
23
|
+
label: "Claude Code",
|
|
24
|
+
candidates: [
|
|
25
|
+
{ kind: "acp-adapter", program: "claude-agent-acp", args: [], usage: "usd" },
|
|
26
|
+
{
|
|
27
|
+
kind: "claude-stream",
|
|
28
|
+
program: "claude",
|
|
29
|
+
args: [],
|
|
30
|
+
verified: ">=2.1.0 <3.0.0",
|
|
31
|
+
usage: "usd",
|
|
32
|
+
},
|
|
33
|
+
{ kind: "oneshot", program: "claude", args: [], oneshot: "claude", usage: "usd" },
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
agentId: "codex",
|
|
38
|
+
label: "Codex",
|
|
39
|
+
candidates: [
|
|
40
|
+
{ kind: "acp-adapter", program: "codex-acp", args: [], usage: "tokens" },
|
|
41
|
+
{
|
|
42
|
+
kind: "codex-app-server",
|
|
43
|
+
program: "codex",
|
|
44
|
+
args: ["app-server"],
|
|
45
|
+
verified: ">=0.160.0 <0.200.0",
|
|
46
|
+
usage: "tokens",
|
|
47
|
+
},
|
|
48
|
+
{ kind: "oneshot", program: "codex", args: [], oneshot: "codex", usage: "tokens" },
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
agentId: "gemini",
|
|
53
|
+
label: "Gemini CLI",
|
|
54
|
+
candidates: [
|
|
55
|
+
{ kind: "acp", program: "gemini", args: ["--acp"], usage: "tokens" },
|
|
56
|
+
{ kind: "oneshot", program: "gemini", args: [], oneshot: "gemini", usage: "tokens" },
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
agentId: "qwen",
|
|
61
|
+
label: "Qwen Code",
|
|
62
|
+
// #11887:0.23.x 受限模式下不发 request_permission 就执行 → 只在 plan 下用
|
|
63
|
+
candidates: [{ kind: "acp", program: "qwen", args: ["--acp"], permissions: "unreliable" }],
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
agentId: "kimi",
|
|
67
|
+
label: "Kimi Code",
|
|
68
|
+
candidates: [{ kind: "acp", program: "kimi", args: ["acp"] }],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
agentId: "opencode",
|
|
72
|
+
label: "OpenCode",
|
|
73
|
+
candidates: [{ kind: "acp", program: "opencode", args: ["acp"] }],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
agentId: "copilot",
|
|
77
|
+
label: "GitHub Copilot CLI",
|
|
78
|
+
candidates: [
|
|
79
|
+
{ kind: "acp", program: "copilot", args: ["--acp", "--stdio"], usage: "requests" },
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
agentId: "goose",
|
|
84
|
+
label: "Goose",
|
|
85
|
+
candidates: [{ kind: "acp", program: "goose", args: ["acp"] }],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
agentId: "ama",
|
|
89
|
+
label: "ama",
|
|
90
|
+
candidates: [
|
|
91
|
+
{
|
|
92
|
+
kind: "acp",
|
|
93
|
+
program: "ama",
|
|
94
|
+
args: ["--mode", "acp"],
|
|
95
|
+
usage: "usd",
|
|
96
|
+
modes: Object.fromEntries(ALL_MODES.map((m) => [m, m])),
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
];
|
|
101
|
+
export function catalogEntry(agentId) {
|
|
102
|
+
return DRIVER_CATALOG.find((entry) => entry.agentId === agentId);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* `runner` 规格 → 候选链:`claude` / `codex` 与表中 id 走表;`acp:<program>` 取表里同程序名的
|
|
106
|
+
* ACP 候选,否则通用 ACP(无参数)。
|
|
107
|
+
*/
|
|
108
|
+
export function candidatesFor(spec) {
|
|
109
|
+
if (spec.startsWith("acp:")) {
|
|
110
|
+
const program = spec.slice(4).trim();
|
|
111
|
+
if (program === "")
|
|
112
|
+
return undefined;
|
|
113
|
+
for (const entry of DRIVER_CATALOG)
|
|
114
|
+
for (const c of entry.candidates)
|
|
115
|
+
if (c.kind === "acp" && c.program === program)
|
|
116
|
+
return { agentId: spec, candidates: [c] };
|
|
117
|
+
return { agentId: spec, candidates: [{ kind: "acp", program, args: [] }] };
|
|
118
|
+
}
|
|
119
|
+
const entry = catalogEntry(spec);
|
|
120
|
+
return entry === undefined ? undefined : { agentId: spec, candidates: [...entry.candidates] };
|
|
121
|
+
}
|
|
122
|
+
/** 候选的静态能力(ACP 的会话能力要到 initialize 才知道,这里取保守值)。 */
|
|
123
|
+
export function candidateCapabilities(c) {
|
|
124
|
+
switch (c.kind) {
|
|
125
|
+
case "claude-stream":
|
|
126
|
+
return {
|
|
127
|
+
resume: "resume",
|
|
128
|
+
list: false,
|
|
129
|
+
permissions: "interactive",
|
|
130
|
+
steer: true,
|
|
131
|
+
modes: ALL_MODES,
|
|
132
|
+
usage: "usd",
|
|
133
|
+
images: true,
|
|
134
|
+
};
|
|
135
|
+
case "codex-app-server":
|
|
136
|
+
return {
|
|
137
|
+
resume: "resume",
|
|
138
|
+
list: true,
|
|
139
|
+
permissions: "interactive",
|
|
140
|
+
steer: true,
|
|
141
|
+
modes: ALL_MODES,
|
|
142
|
+
usage: "tokens",
|
|
143
|
+
images: false,
|
|
144
|
+
};
|
|
145
|
+
case "oneshot":
|
|
146
|
+
return {
|
|
147
|
+
resume: c.oneshot === "gemini" ? "none" : "resume",
|
|
148
|
+
list: false,
|
|
149
|
+
permissions: "none",
|
|
150
|
+
steer: false,
|
|
151
|
+
// 不能审批:只在只读任务下用(§5.1 oneshot)
|
|
152
|
+
modes: ["plan"],
|
|
153
|
+
usage: c.usage ?? "none",
|
|
154
|
+
images: false,
|
|
155
|
+
};
|
|
156
|
+
default:
|
|
157
|
+
return {
|
|
158
|
+
resume: "resume",
|
|
159
|
+
list: true,
|
|
160
|
+
permissions: c.permissions ?? "interactive",
|
|
161
|
+
steer: false,
|
|
162
|
+
modes: c.permissions === "unreliable" ? ["plan"] : ALL_MODES,
|
|
163
|
+
usage: c.usage ?? "tokens",
|
|
164
|
+
images: false,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 外部 Agent 子进程环境清理(docs/wave5-plan.md §5.4,D16)。[W5-E]
|
|
3
|
+
*
|
|
4
|
+
* ama 分不清「用户 shell 本来就有」与「为 ama 设的」变量,所以缺省全剥、显式放回:
|
|
5
|
+
* - 删:`BUILTIN_PROVIDERS[].envKeys`(各家 API key)、`*_BASE_URL`、`AMA_*`、`CODEX_API_KEY`、
|
|
6
|
+
* `ANTHROPIC_AUTH_TOKEN`——它们漏进 Claude / Codex 会把订阅登录切成 API 计费(R2 K4);
|
|
7
|
+
* - 删:`ARMADRA_*`(`ARMADRA_ASKPASS_*` 除外)——在 Armadra 画布终端里直接运行 ama 时,这些是该终端节点的
|
|
8
|
+
* 身份(节点 / 会话 / Hook 端点 / 画布控制);子进程继承后,Armadra 装在 Claude / Codex 上的 Hook 会把
|
|
9
|
+
* 子 Agent 的事件记到这个节点名下(状态、审批等待、投递确认都会串)。askpass 留给 git 凭据提示;
|
|
10
|
+
* - 留:其余全部(PATH / HOME / LANG / TERM / SSH_* / 代理变量 / CLI 自己的 OAuth 令牌等);
|
|
11
|
+
* - 放回:`agents.<id>.env.passthrough` 列出的变量(从原环境取值)。
|
|
12
|
+
*
|
|
13
|
+
* Windows 上变量名不分大小写,比较一律转大写。`--bare` 之类改用 API key 的旗标永不缺省(驱动侧)。
|
|
14
|
+
*/
|
|
15
|
+
import { type AgentsConfig } from "../config/types-w5.js";
|
|
16
|
+
/** 除供应商表之外也要剥离的变量(会让 CLI 改用 API 计费)。 */
|
|
17
|
+
export declare const EXTRA_STRIPPED_KEYS: readonly string[];
|
|
18
|
+
/** 该变量是否缺省剥离。 */
|
|
19
|
+
export declare function isStrippedEnvKey(name: string): boolean;
|
|
20
|
+
export declare function buildChildEnv(env: NodeJS.ProcessEnv, agentId: string, config: AgentsConfig | undefined): NodeJS.ProcessEnv;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 外部 Agent 子进程环境清理(docs/wave5-plan.md §5.4,D16)。[W5-E]
|
|
3
|
+
*
|
|
4
|
+
* ama 分不清「用户 shell 本来就有」与「为 ama 设的」变量,所以缺省全剥、显式放回:
|
|
5
|
+
* - 删:`BUILTIN_PROVIDERS[].envKeys`(各家 API key)、`*_BASE_URL`、`AMA_*`、`CODEX_API_KEY`、
|
|
6
|
+
* `ANTHROPIC_AUTH_TOKEN`——它们漏进 Claude / Codex 会把订阅登录切成 API 计费(R2 K4);
|
|
7
|
+
* - 删:`ARMADRA_*`(`ARMADRA_ASKPASS_*` 除外)——在 Armadra 画布终端里直接运行 ama 时,这些是该终端节点的
|
|
8
|
+
* 身份(节点 / 会话 / Hook 端点 / 画布控制);子进程继承后,Armadra 装在 Claude / Codex 上的 Hook 会把
|
|
9
|
+
* 子 Agent 的事件记到这个节点名下(状态、审批等待、投递确认都会串)。askpass 留给 git 凭据提示;
|
|
10
|
+
* - 留:其余全部(PATH / HOME / LANG / TERM / SSH_* / 代理变量 / CLI 自己的 OAuth 令牌等);
|
|
11
|
+
* - 放回:`agents.<id>.env.passthrough` 列出的变量(从原环境取值)。
|
|
12
|
+
*
|
|
13
|
+
* Windows 上变量名不分大小写,比较一律转大写。`--bare` 之类改用 API key 的旗标永不缺省(驱动侧)。
|
|
14
|
+
*/
|
|
15
|
+
import { BUILTIN_PROVIDERS } from "../ai/providers/builtin.js";
|
|
16
|
+
import { agentEntry } from "../config/types-w5.js";
|
|
17
|
+
/** 除供应商表之外也要剥离的变量(会让 CLI 改用 API 计费)。 */
|
|
18
|
+
export const EXTRA_STRIPPED_KEYS = ["CODEX_API_KEY", "ANTHROPIC_AUTH_TOKEN"];
|
|
19
|
+
let providerKeys;
|
|
20
|
+
function strippedKeys() {
|
|
21
|
+
providerKeys ??= new Set([...BUILTIN_PROVIDERS.flatMap((p) => p.envKeys ?? []), ...EXTRA_STRIPPED_KEYS].map((k) => k.toUpperCase()));
|
|
22
|
+
return providerKeys;
|
|
23
|
+
}
|
|
24
|
+
/** 该变量是否缺省剥离。 */
|
|
25
|
+
export function isStrippedEnvKey(name) {
|
|
26
|
+
const upper = name.toUpperCase();
|
|
27
|
+
if (upper.startsWith("ARMADRA_"))
|
|
28
|
+
return !upper.startsWith("ARMADRA_ASKPASS_");
|
|
29
|
+
return upper.startsWith("AMA_") || upper.endsWith("_BASE_URL") || strippedKeys().has(upper);
|
|
30
|
+
}
|
|
31
|
+
export function buildChildEnv(env, agentId, config) {
|
|
32
|
+
const out = {};
|
|
33
|
+
for (const [name, value] of Object.entries(env)) {
|
|
34
|
+
if (value === undefined || isStrippedEnvKey(name))
|
|
35
|
+
continue;
|
|
36
|
+
out[name] = value;
|
|
37
|
+
}
|
|
38
|
+
const passthrough = agentEntry(config, agentId)?.env?.passthrough ?? [];
|
|
39
|
+
if (passthrough.length > 0) {
|
|
40
|
+
const wanted = new Set(passthrough.map((n) => n.toUpperCase()));
|
|
41
|
+
for (const [name, value] of Object.entries(env))
|
|
42
|
+
if (value !== undefined && wanted.has(name.toUpperCase()))
|
|
43
|
+
out[name] = value;
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 宿主注入的 runner(`HostApi.runners.provide` 的底座,docs/wave5-plan.md §5.5,D17)。[W5-E → W5-EG]
|
|
3
|
+
*
|
|
4
|
+
* 一个宿主适配器一份(host/api-impl.ts 建,经 {@link ExternalAgents} 的 `hostRunners` 选项交给每个
|
|
5
|
+
* 主会话):宿主可以在 `create()` 里或之后任何时候 `provide`,同名替换;返回的函数注销。
|
|
6
|
+
* `onChange` 供 `/agents` / RPC `get_agents` 的缓存刷新。
|
|
7
|
+
*/
|
|
8
|
+
import type { HostRunner } from "../host/types.js";
|
|
9
|
+
export declare class HostRunnerRegistry {
|
|
10
|
+
private readonly runners;
|
|
11
|
+
private readonly listeners;
|
|
12
|
+
provide(runner: HostRunner): () => void;
|
|
13
|
+
get(id: string): HostRunner | undefined;
|
|
14
|
+
list(): HostRunner[];
|
|
15
|
+
/** 注入 / 注销时回调;返回取消订阅。 */
|
|
16
|
+
onChange(listener: () => void): () => void;
|
|
17
|
+
private changed;
|
|
18
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 宿主注入的 runner(`HostApi.runners.provide` 的底座,docs/wave5-plan.md §5.5,D17)。[W5-E → W5-EG]
|
|
3
|
+
*
|
|
4
|
+
* 一个宿主适配器一份(host/api-impl.ts 建,经 {@link ExternalAgents} 的 `hostRunners` 选项交给每个
|
|
5
|
+
* 主会话):宿主可以在 `create()` 里或之后任何时候 `provide`,同名替换;返回的函数注销。
|
|
6
|
+
* `onChange` 供 `/agents` / RPC `get_agents` 的缓存刷新。
|
|
7
|
+
*/
|
|
8
|
+
import { AmaError } from "../errors.js";
|
|
9
|
+
export class HostRunnerRegistry {
|
|
10
|
+
runners = new Map();
|
|
11
|
+
listeners = new Set();
|
|
12
|
+
provide(runner) {
|
|
13
|
+
if (typeof runner?.id !== "string" || runner.id === "" || typeof runner.start !== "function")
|
|
14
|
+
throw new AmaError("invalid_arguments", "runners.provide:需要带 id 与 start 的 runner");
|
|
15
|
+
this.runners.set(runner.id, runner);
|
|
16
|
+
this.changed();
|
|
17
|
+
return () => {
|
|
18
|
+
if (this.runners.get(runner.id) !== runner)
|
|
19
|
+
return;
|
|
20
|
+
this.runners.delete(runner.id);
|
|
21
|
+
this.changed();
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
get(id) {
|
|
25
|
+
return this.runners.get(id);
|
|
26
|
+
}
|
|
27
|
+
list() {
|
|
28
|
+
return [...this.runners.values()];
|
|
29
|
+
}
|
|
30
|
+
/** 注入 / 注销时回调;返回取消订阅。 */
|
|
31
|
+
onChange(listener) {
|
|
32
|
+
this.listeners.add(listener);
|
|
33
|
+
return () => void this.listeners.delete(listener);
|
|
34
|
+
}
|
|
35
|
+
changed() {
|
|
36
|
+
for (const listener of [...this.listeners]) {
|
|
37
|
+
try {
|
|
38
|
+
listener();
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// 监听方出错不影响宿主
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC 2.0 over NDJSON 的对等端(docs/wave5-plan.md §5.1)。[W5-E]
|
|
3
|
+
*
|
|
4
|
+
* ACP 客户端 / 服务端与 Codex app-server 驱动共用:
|
|
5
|
+
* - 分帧复用 `modes/rpc/jsonl.ts`(只按 `\n` 切行、64 KiB 分片写、背压等 drain),写入串行;
|
|
6
|
+
* - 双向:本端可发请求 / 通知,也处理对端的请求(`onRequest` 抛 {@link RpcError} 即回错误)与通知;
|
|
7
|
+
* - `jsonrpcField: false` 时不写 `"jsonrpc":"2.0"`(Codex app-server 的线上形状),读取两种都认;
|
|
8
|
+
* - 连接关闭(输入流结束)时所有挂起的请求以 `connection_closed` 失败。
|
|
9
|
+
*/
|
|
10
|
+
export type RpcId = string | number;
|
|
11
|
+
export declare class RpcError extends Error {
|
|
12
|
+
readonly code: number;
|
|
13
|
+
readonly data?: unknown | undefined;
|
|
14
|
+
constructor(code: number, message: string, data?: unknown | undefined);
|
|
15
|
+
}
|
|
16
|
+
export interface IncomingRequestContext {
|
|
17
|
+
readonly id: RpcId;
|
|
18
|
+
/** 连接关闭时 abort。 */
|
|
19
|
+
readonly signal: AbortSignal;
|
|
20
|
+
}
|
|
21
|
+
export interface JsonRpcPeerOptions {
|
|
22
|
+
input: NodeJS.ReadableStream;
|
|
23
|
+
output: NodeJS.WritableStream;
|
|
24
|
+
/** 缺省 true。 */
|
|
25
|
+
jsonrpcField?: boolean;
|
|
26
|
+
onRequest?(method: string, params: unknown, ctx: IncomingRequestContext): Promise<unknown>;
|
|
27
|
+
onNotification?(method: string, params: unknown): void;
|
|
28
|
+
/** 输入流结束(对端退出或关管道)。 */
|
|
29
|
+
onClose?(): void;
|
|
30
|
+
/** 无法解析的行(不影响连接)。 */
|
|
31
|
+
onProtocolError?(line: string, reason: string): void;
|
|
32
|
+
}
|
|
33
|
+
export declare class JsonRpcPeer {
|
|
34
|
+
private readonly options;
|
|
35
|
+
private readonly pending;
|
|
36
|
+
private readonly reader;
|
|
37
|
+
private readonly lifetime;
|
|
38
|
+
private nextId;
|
|
39
|
+
private writing;
|
|
40
|
+
private isClosed;
|
|
41
|
+
private resolveClosed;
|
|
42
|
+
/** 输入流结束或 `close()` 后 resolve。 */
|
|
43
|
+
readonly closed: Promise<void>;
|
|
44
|
+
constructor(options: JsonRpcPeerOptions);
|
|
45
|
+
get isOpen(): boolean;
|
|
46
|
+
/** 发请求;`signal` abort 时本端不再等(不通知对端,协议级取消由调用方另发)。 */
|
|
47
|
+
request<T = unknown>(method: string, params?: unknown, signal?: AbortSignal): Promise<T>;
|
|
48
|
+
/** 输入流结束后仍可写(对端可能只关了自己的写端,还在读);写失败静默。 */
|
|
49
|
+
notify(method: string, params?: unknown): Promise<void>;
|
|
50
|
+
/** 停止读取并让挂起请求失败;不关闭底层流(由调用方决定)。 */
|
|
51
|
+
close(): void;
|
|
52
|
+
/** 等所有已排队的写入完成。 */
|
|
53
|
+
flush(): Promise<void>;
|
|
54
|
+
private shutdown;
|
|
55
|
+
private send;
|
|
56
|
+
private onLine;
|
|
57
|
+
private handleRequest;
|
|
58
|
+
}
|