@armadra/agent 0.4.0 → 0.5.1
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 +184 -1
- package/README.md +202 -83
- 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 +37605 -21619
- 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/choice-prompt.d.ts +58 -0
- package/dist/cli/choice-prompt.js +140 -0
- 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-cache-probe.d.ts +1 -1
- package/dist/cli/subcommands/models-cache-probe.js +3 -12
- 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.d.ts +1 -1
- package/dist/cli/subcommands/providers.js +8 -15
- 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 +13 -1
- package/dist/modes/commands-core.js +64 -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 +12 -1
- package/dist/modes/interactive/commands.js +31 -1
- package/dist/modes/interactive/confirm-dialog.d.ts +49 -0
- package/dist/modes/interactive/confirm-dialog.js +121 -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 +140 -136
- package/dist/modes/interactive/key-dispatch.d.ts +22 -2
- package/dist/modes/interactive/key-dispatch.js +66 -7
- package/dist/modes/interactive/line/line-mode.d.ts +4 -1
- package/dist/modes/interactive/line/line-mode.js +31 -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/startup-ui.js +5 -1
- 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/bypass.d.ts +32 -0
- package/dist/permissions/bypass.js +36 -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 +6 -1
- package/dist/tui/keybindings.js +6 -1
- 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 +78 -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 +179 -21
- package/package.json +13 -2
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 外部 Agent 并发池(docs/wave5-plan.md §5.4 并发)。[W5-E]
|
|
3
|
+
*
|
|
4
|
+
* 总并发 `agents.maxConcurrent`(缺省 3)+ 每个 Agent 的上限 `agents.<id>.maxConcurrent`
|
|
5
|
+
* (claude 缺省 2:订阅有速率限制);超出排队(先来先得),排队可被 abort。与 ama 自己的
|
|
6
|
+
* `SubagentPool`(子会话)分开计数。
|
|
7
|
+
*/
|
|
8
|
+
import { AmaError } from "../errors.js";
|
|
9
|
+
import { agentEntry } from "../config/types-w5.js";
|
|
10
|
+
export const DEFAULT_MAX_CONCURRENT = 3;
|
|
11
|
+
export const DEFAULT_PER_AGENT = { claude: 2 };
|
|
12
|
+
export class DriverPool {
|
|
13
|
+
maxTotal;
|
|
14
|
+
perAgent;
|
|
15
|
+
active = new Map();
|
|
16
|
+
total = 0;
|
|
17
|
+
queue = [];
|
|
18
|
+
constructor(maxTotal = DEFAULT_MAX_CONCURRENT, perAgent = () => undefined) {
|
|
19
|
+
this.maxTotal = maxTotal;
|
|
20
|
+
this.perAgent = perAgent;
|
|
21
|
+
}
|
|
22
|
+
running(agentId) {
|
|
23
|
+
return agentId === undefined ? this.total : (this.active.get(agentId) ?? 0);
|
|
24
|
+
}
|
|
25
|
+
queued() {
|
|
26
|
+
return this.queue.length;
|
|
27
|
+
}
|
|
28
|
+
limitFor(agentId) {
|
|
29
|
+
return this.perAgent(agentId) ?? this.maxTotal;
|
|
30
|
+
}
|
|
31
|
+
canRun(agentId) {
|
|
32
|
+
return this.total < this.maxTotal && this.running(agentId) < this.limitFor(agentId);
|
|
33
|
+
}
|
|
34
|
+
take(agentId) {
|
|
35
|
+
this.total += 1;
|
|
36
|
+
this.active.set(agentId, this.running(agentId) + 1);
|
|
37
|
+
let released = false;
|
|
38
|
+
return () => {
|
|
39
|
+
if (released)
|
|
40
|
+
return;
|
|
41
|
+
released = true;
|
|
42
|
+
this.total -= 1;
|
|
43
|
+
this.active.set(agentId, this.running(agentId) - 1);
|
|
44
|
+
this.drain();
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
drain() {
|
|
48
|
+
for (let i = 0; i < this.queue.length;) {
|
|
49
|
+
const waiter = this.queue[i];
|
|
50
|
+
if (this.canRun(waiter.agentId)) {
|
|
51
|
+
this.queue.splice(i, 1);
|
|
52
|
+
waiter.grant(this.take(waiter.agentId));
|
|
53
|
+
}
|
|
54
|
+
else
|
|
55
|
+
i++;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/** 拿到一个名额(返回释放函数);abort 时离开队列并以 `aborted` 失败。 */
|
|
59
|
+
acquire(agentId, signal) {
|
|
60
|
+
if (signal?.aborted === true)
|
|
61
|
+
return Promise.reject(abortedError());
|
|
62
|
+
// 有空位时,排队的只可能是卡在各自上限上的其它 Agent:同一 Agent 已有人排队就跟在后面
|
|
63
|
+
if (this.canRun(agentId) && !this.queue.some((w) => w.agentId === agentId))
|
|
64
|
+
return Promise.resolve(this.take(agentId));
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
const onAbort = () => {
|
|
67
|
+
const at = this.queue.indexOf(waiter);
|
|
68
|
+
if (at >= 0)
|
|
69
|
+
this.queue.splice(at, 1);
|
|
70
|
+
reject(abortedError());
|
|
71
|
+
};
|
|
72
|
+
const waiter = {
|
|
73
|
+
agentId,
|
|
74
|
+
grant: (release) => {
|
|
75
|
+
signal?.removeEventListener("abort", onAbort);
|
|
76
|
+
resolve(release);
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
80
|
+
this.queue.push(waiter);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function abortedError() {
|
|
85
|
+
return new AmaError("aborted", "外部 Agent 排队时被中断");
|
|
86
|
+
}
|
|
87
|
+
/** 按配置建池(`agents.maxConcurrent`、`agents.<id>.maxConcurrent`)。 */
|
|
88
|
+
export function poolFromConfig(config) {
|
|
89
|
+
const total = typeof config?.maxConcurrent === "number" && config.maxConcurrent > 0
|
|
90
|
+
? config.maxConcurrent
|
|
91
|
+
: DEFAULT_MAX_CONCURRENT;
|
|
92
|
+
return new DriverPool(total, (agentId) => {
|
|
93
|
+
const own = agentEntry(config, agentId)?.maxConcurrent;
|
|
94
|
+
return typeof own === "number" && own > 0 ? own : DEFAULT_PER_AGENT[agentId];
|
|
95
|
+
});
|
|
96
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 外部 Agent 的探测(docs/wave5-plan.md §5.1 probe.ts)。[W5-E]
|
|
3
|
+
*
|
|
4
|
+
* - PATH 查找不起 shell:逐个目录拼程序名(Windows 加 PATHEXT 后缀);绝对 / 相对路径直接认。
|
|
5
|
+
* - 版本:`<program> --version` 取第一个 `x.y.z`,5 s 超时,不联网、不计费。
|
|
6
|
+
* - 缓存:每进程一次(内存);可选写 `<dataDir>/drivers.json`(按路径 + mtime 失效)。
|
|
7
|
+
*/
|
|
8
|
+
export declare const VERSION_TIMEOUT_MS = 5000;
|
|
9
|
+
export interface LocatedProgram {
|
|
10
|
+
path: string;
|
|
11
|
+
version?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ProbeDeps {
|
|
14
|
+
env: NodeJS.ProcessEnv;
|
|
15
|
+
cwd?: string;
|
|
16
|
+
platform?: NodeJS.Platform;
|
|
17
|
+
/** 缺省:存在且是文件。 */
|
|
18
|
+
isFile?(path: string): boolean;
|
|
19
|
+
/** 缺省:execFile `<path> <args>`,返回 stdout + stderr;失败返回 undefined。 */
|
|
20
|
+
runVersion?(path: string, args: readonly string[]): Promise<string | undefined>;
|
|
21
|
+
/** `<dataDir>/drivers.json`;不给则只做内存缓存。 */
|
|
22
|
+
cacheFile?: string;
|
|
23
|
+
}
|
|
24
|
+
/** 在 PATH 里找程序;找不到返回 undefined。 */
|
|
25
|
+
export declare function findOnPath(program: string, env: NodeJS.ProcessEnv, options?: {
|
|
26
|
+
platform?: NodeJS.Platform;
|
|
27
|
+
cwd?: string;
|
|
28
|
+
isFile?(path: string): boolean;
|
|
29
|
+
}): string | undefined;
|
|
30
|
+
/** 文本里第一个 `x.y.z`(可带预发布后缀)。 */
|
|
31
|
+
export declare function parseVersion(text: string): string | undefined;
|
|
32
|
+
/** 版本区间:空格分隔的 `>=x.y.z` / `<x.y.z` / `>` / `<=` / `=`;全部满足为真。 */
|
|
33
|
+
export declare function versionSatisfies(version: string, range: string): boolean;
|
|
34
|
+
export declare class ProgramProbe {
|
|
35
|
+
private readonly deps;
|
|
36
|
+
private readonly memo;
|
|
37
|
+
private readonly captured;
|
|
38
|
+
constructor(deps: ProbeDeps);
|
|
39
|
+
/** 找程序并取版本;同一进程同一程序只探一次。 */
|
|
40
|
+
locate(program: string, versionArgs?: readonly string[]): Promise<LocatedProgram | undefined>;
|
|
41
|
+
/** 跑一次 `<path> <args>` 取输出(如 `--help`,不联网、不计费);每进程每组参数一次。 */
|
|
42
|
+
capture(path: string, args: readonly string[]): Promise<string | undefined>;
|
|
43
|
+
private locateNow;
|
|
44
|
+
private mtime;
|
|
45
|
+
private readCache;
|
|
46
|
+
private writeCache;
|
|
47
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 外部 Agent 的探测(docs/wave5-plan.md §5.1 probe.ts)。[W5-E]
|
|
3
|
+
*
|
|
4
|
+
* - PATH 查找不起 shell:逐个目录拼程序名(Windows 加 PATHEXT 后缀);绝对 / 相对路径直接认。
|
|
5
|
+
* - 版本:`<program> --version` 取第一个 `x.y.z`,5 s 超时,不联网、不计费。
|
|
6
|
+
* - 缓存:每进程一次(内存);可选写 `<dataDir>/drivers.json`(按路径 + mtime 失效)。
|
|
7
|
+
*/
|
|
8
|
+
import { execFile } from "node:child_process";
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { delimiter, dirname, isAbsolute, join, resolve } from "node:path";
|
|
11
|
+
import { commandLine } from "./process.js";
|
|
12
|
+
export const VERSION_TIMEOUT_MS = 5_000;
|
|
13
|
+
function defaultIsFile(path) {
|
|
14
|
+
try {
|
|
15
|
+
return statSync(path).isFile();
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** 在 PATH 里找程序;找不到返回 undefined。 */
|
|
22
|
+
export function findOnPath(program, env, options = {}) {
|
|
23
|
+
const platform = options.platform ?? process.platform;
|
|
24
|
+
const isFile = options.isFile ?? defaultIsFile;
|
|
25
|
+
const exts = platform === "win32"
|
|
26
|
+
? ["", ...(env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean)]
|
|
27
|
+
: [""];
|
|
28
|
+
const candidates = (base) => exts.map((ext) => base + ext.toLowerCase());
|
|
29
|
+
if (isAbsolute(program) || program.includes("/") || program.includes("\\")) {
|
|
30
|
+
const base = resolve(options.cwd ?? process.cwd(), program);
|
|
31
|
+
return candidates(base).find(isFile);
|
|
32
|
+
}
|
|
33
|
+
const path = env["PATH"] ?? env["Path"] ?? "";
|
|
34
|
+
const sep = platform === "win32" ? ";" : delimiter;
|
|
35
|
+
for (const dir of path.split(sep)) {
|
|
36
|
+
if (dir === "")
|
|
37
|
+
continue;
|
|
38
|
+
const hit = candidates(join(dir, program)).find(isFile);
|
|
39
|
+
if (hit !== undefined)
|
|
40
|
+
return hit;
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
/** 文本里第一个 `x.y.z`(可带预发布后缀)。 */
|
|
45
|
+
export function parseVersion(text) {
|
|
46
|
+
return /(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)/.exec(text)?.[1];
|
|
47
|
+
}
|
|
48
|
+
function compare(a, b) {
|
|
49
|
+
const pa = a.split("-")[0].split(".").map(Number);
|
|
50
|
+
const pb = b.split("-")[0].split(".").map(Number);
|
|
51
|
+
for (let i = 0; i < 3; i++) {
|
|
52
|
+
const d = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
53
|
+
if (d !== 0)
|
|
54
|
+
return d;
|
|
55
|
+
}
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
/** 版本区间:空格分隔的 `>=x.y.z` / `<x.y.z` / `>` / `<=` / `=`;全部满足为真。 */
|
|
59
|
+
export function versionSatisfies(version, range) {
|
|
60
|
+
for (const part of range.trim().split(/\s+/)) {
|
|
61
|
+
const m = /^(>=|<=|>|<|=)?(\d+\.\d+\.\d+)$/.exec(part);
|
|
62
|
+
if (m === null)
|
|
63
|
+
continue;
|
|
64
|
+
const c = compare(version, m[2]);
|
|
65
|
+
const op = m[1] ?? "=";
|
|
66
|
+
const ok = op === ">="
|
|
67
|
+
? c >= 0
|
|
68
|
+
: op === "<="
|
|
69
|
+
? c <= 0
|
|
70
|
+
: op === ">"
|
|
71
|
+
? c > 0
|
|
72
|
+
: op === "<"
|
|
73
|
+
? c < 0
|
|
74
|
+
: c === 0;
|
|
75
|
+
if (!ok)
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
function defaultRunVersion(env, platform) {
|
|
81
|
+
return (path, args) => new Promise((done) => {
|
|
82
|
+
const line = commandLine({ program: path, args, env }, platform);
|
|
83
|
+
execFile(line.file, line.args, {
|
|
84
|
+
env,
|
|
85
|
+
timeout: VERSION_TIMEOUT_MS,
|
|
86
|
+
windowsHide: true,
|
|
87
|
+
windowsVerbatimArguments: line.verbatim,
|
|
88
|
+
}, (error, stdout, stderr) => done(error !== null && stdout === "" ? undefined : `${stdout}${stderr}`));
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
export class ProgramProbe {
|
|
92
|
+
deps;
|
|
93
|
+
memo = new Map();
|
|
94
|
+
captured = new Map();
|
|
95
|
+
constructor(deps) {
|
|
96
|
+
this.deps = deps;
|
|
97
|
+
}
|
|
98
|
+
/** 找程序并取版本;同一进程同一程序只探一次。 */
|
|
99
|
+
locate(program, versionArgs = ["--version"]) {
|
|
100
|
+
const key = `${program}\0${versionArgs.join(" ")}`;
|
|
101
|
+
let hit = this.memo.get(key);
|
|
102
|
+
if (hit === undefined) {
|
|
103
|
+
hit = this.locateNow(program, versionArgs);
|
|
104
|
+
this.memo.set(key, hit);
|
|
105
|
+
}
|
|
106
|
+
return hit;
|
|
107
|
+
}
|
|
108
|
+
/** 跑一次 `<path> <args>` 取输出(如 `--help`,不联网、不计费);每进程每组参数一次。 */
|
|
109
|
+
capture(path, args) {
|
|
110
|
+
const key = `capture\0${path}\0${args.join(" ")}`;
|
|
111
|
+
let hit = this.captured.get(key);
|
|
112
|
+
if (hit === undefined) {
|
|
113
|
+
const platform = this.deps.platform ?? process.platform;
|
|
114
|
+
const run = this.deps.runVersion ?? defaultRunVersion(this.deps.env, platform);
|
|
115
|
+
hit = run(path, args).catch(() => undefined);
|
|
116
|
+
this.captured.set(key, hit);
|
|
117
|
+
}
|
|
118
|
+
return hit;
|
|
119
|
+
}
|
|
120
|
+
async locateNow(program, versionArgs) {
|
|
121
|
+
const platform = this.deps.platform ?? process.platform;
|
|
122
|
+
const path = findOnPath(program, this.deps.env, {
|
|
123
|
+
platform,
|
|
124
|
+
...(this.deps.cwd !== undefined ? { cwd: this.deps.cwd } : {}),
|
|
125
|
+
...(this.deps.isFile !== undefined ? { isFile: this.deps.isFile } : {}),
|
|
126
|
+
});
|
|
127
|
+
if (path === undefined)
|
|
128
|
+
return undefined;
|
|
129
|
+
const mtimeMs = this.mtime(path);
|
|
130
|
+
const cached = this.readCache()[path];
|
|
131
|
+
if (cached !== undefined && cached.mtimeMs === mtimeMs)
|
|
132
|
+
return { path, ...(cached.version !== undefined ? { version: cached.version } : {}) };
|
|
133
|
+
const run = this.deps.runVersion ?? defaultRunVersion(this.deps.env, platform);
|
|
134
|
+
const output = await run(path, versionArgs).catch(() => undefined);
|
|
135
|
+
const version = output === undefined ? undefined : parseVersion(output);
|
|
136
|
+
this.writeCache(path, { mtimeMs, ...(version !== undefined ? { version } : {}) });
|
|
137
|
+
return { path, ...(version !== undefined ? { version } : {}) };
|
|
138
|
+
}
|
|
139
|
+
mtime(path) {
|
|
140
|
+
try {
|
|
141
|
+
return statSync(path).mtimeMs;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return 0;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
readCache() {
|
|
148
|
+
const file = this.deps.cacheFile;
|
|
149
|
+
if (file === undefined || !existsSync(file))
|
|
150
|
+
return {};
|
|
151
|
+
try {
|
|
152
|
+
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
153
|
+
return parsed.programs ?? {};
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return {};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
writeCache(path, entry) {
|
|
160
|
+
const file = this.deps.cacheFile;
|
|
161
|
+
if (file === undefined)
|
|
162
|
+
return;
|
|
163
|
+
try {
|
|
164
|
+
const programs = { ...this.readCache(), [path]: entry };
|
|
165
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
166
|
+
writeFileSync(file, `${JSON.stringify({ version: 1, programs }, null, 2)}\n`);
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// 缓存写不进去不影响探测
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 外部 Agent 子进程(docs/wave5-plan.md §5.4 看门狗 / 孤儿进程)。[W5-E]
|
|
3
|
+
*
|
|
4
|
+
* - POSIX 以 `detached` 自成进程组,结束时 `killProcessTree`(SIGTERM → 宽限 → SIGKILL);
|
|
5
|
+
* 登记到 `tools/process-tree.ts`,ama 退出时同步清掉仍存活的组。
|
|
6
|
+
* - Windows 上 npm 装的 CLI 是 `.cmd` 垫片,Node 不允许直接 spawn,改经 `cmd.exe /d /s /c`。
|
|
7
|
+
* - stderr 只保留尾部 8 KB 供诊断(不落盘、不进会话,§5.4 敏感数据)。
|
|
8
|
+
* - 测试与宿主可注入 {@link SpawnTransport}(内存流),驱动不关心对端是不是真进程。
|
|
9
|
+
*/
|
|
10
|
+
import { type ProcessDeps } from "../tools/process-tree.js";
|
|
11
|
+
export declare const STDERR_TAIL_BYTES: number;
|
|
12
|
+
/** 关 stdin 之后等进程自己退出的时间,过了再杀进程树。 */
|
|
13
|
+
export declare const STDIN_CLOSE_GRACE_MS = 2000;
|
|
14
|
+
export interface TransportSpec {
|
|
15
|
+
program: string;
|
|
16
|
+
args: readonly string[];
|
|
17
|
+
cwd: string;
|
|
18
|
+
env: NodeJS.ProcessEnv;
|
|
19
|
+
}
|
|
20
|
+
export interface AgentTransport {
|
|
21
|
+
readonly stdin: NodeJS.WritableStream;
|
|
22
|
+
readonly stdout: NodeJS.ReadableStream;
|
|
23
|
+
readonly pid?: number;
|
|
24
|
+
/** stderr 尾部(≤ 8 KB)。 */
|
|
25
|
+
stderrTail(): string;
|
|
26
|
+
/** 进程结束(退出码;信号退出为 null)。 */
|
|
27
|
+
readonly exited: Promise<number | null>;
|
|
28
|
+
/** 关 stdin → 等 `graceMs` → 杀进程树。幂等。 */
|
|
29
|
+
terminate(graceMs?: number): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
export type SpawnTransport = (spec: TransportSpec) => AgentTransport;
|
|
32
|
+
export interface SpawnDeps {
|
|
33
|
+
platform?: NodeJS.Platform;
|
|
34
|
+
process?: ProcessDeps;
|
|
35
|
+
/** 进程起来 / 结束时回调(pid 登记,§5.4 孤儿进程)。 */
|
|
36
|
+
onSpawn?(pid: number, spec: TransportSpec): void;
|
|
37
|
+
onExit?(pid: number): void;
|
|
38
|
+
}
|
|
39
|
+
/** Windows `.cmd` / `.bat` 垫片改经 cmd.exe;其余原样。 */
|
|
40
|
+
export declare function commandLine(spec: Pick<TransportSpec, "program" | "args" | "env">, platform?: NodeJS.Platform): {
|
|
41
|
+
file: string;
|
|
42
|
+
args: string[];
|
|
43
|
+
verbatim: boolean;
|
|
44
|
+
};
|
|
45
|
+
/** 起真实子进程。spawn 失败(程序不存在等)时 `exited` 以 -1 结束、stdout 立即结束。 */
|
|
46
|
+
export declare function spawnTransport(spec: TransportSpec, deps?: SpawnDeps): AgentTransport;
|
|
47
|
+
/** 最近一段 stderr,单行化后截断(放进错误信息)。 */
|
|
48
|
+
export declare function stderrHint(transport: AgentTransport, max?: number): string;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 外部 Agent 子进程(docs/wave5-plan.md §5.4 看门狗 / 孤儿进程)。[W5-E]
|
|
3
|
+
*
|
|
4
|
+
* - POSIX 以 `detached` 自成进程组,结束时 `killProcessTree`(SIGTERM → 宽限 → SIGKILL);
|
|
5
|
+
* 登记到 `tools/process-tree.ts`,ama 退出时同步清掉仍存活的组。
|
|
6
|
+
* - Windows 上 npm 装的 CLI 是 `.cmd` 垫片,Node 不允许直接 spawn,改经 `cmd.exe /d /s /c`。
|
|
7
|
+
* - stderr 只保留尾部 8 KB 供诊断(不落盘、不进会话,§5.4 敏感数据)。
|
|
8
|
+
* - 测试与宿主可注入 {@link SpawnTransport}(内存流),驱动不关心对端是不是真进程。
|
|
9
|
+
*/
|
|
10
|
+
import { spawn } from "node:child_process";
|
|
11
|
+
import { killProcessTree, trackProcessGroup, untrackProcessGroup, } from "../tools/process-tree.js";
|
|
12
|
+
export const STDERR_TAIL_BYTES = 8 * 1024;
|
|
13
|
+
/** 关 stdin 之后等进程自己退出的时间,过了再杀进程树。 */
|
|
14
|
+
export const STDIN_CLOSE_GRACE_MS = 2_000;
|
|
15
|
+
function quoteCmd(arg) {
|
|
16
|
+
return /[\s"&|<>^%]/.test(arg) ? `"${arg.replace(/"/g, '""')}"` : arg;
|
|
17
|
+
}
|
|
18
|
+
/** Windows `.cmd` / `.bat` 垫片改经 cmd.exe;其余原样。 */
|
|
19
|
+
export function commandLine(spec, platform = process.platform) {
|
|
20
|
+
if (platform === "win32" && /\.(cmd|bat)$/i.test(spec.program)) {
|
|
21
|
+
const shell = spec.env["ComSpec"] ?? spec.env["COMSPEC"] ?? "cmd.exe";
|
|
22
|
+
const line = [spec.program, ...spec.args].map(quoteCmd).join(" ");
|
|
23
|
+
return { file: shell, args: ["/d", "/s", "/c", `"${line}"`], verbatim: true };
|
|
24
|
+
}
|
|
25
|
+
return { file: spec.program, args: [...spec.args], verbatim: false };
|
|
26
|
+
}
|
|
27
|
+
/** 起真实子进程。spawn 失败(程序不存在等)时 `exited` 以 -1 结束、stdout 立即结束。 */
|
|
28
|
+
export function spawnTransport(spec, deps = {}) {
|
|
29
|
+
const platform = deps.platform ?? process.platform;
|
|
30
|
+
const line = commandLine(spec, platform);
|
|
31
|
+
let tail = "";
|
|
32
|
+
let resolveExit;
|
|
33
|
+
const exited = new Promise((resolve) => (resolveExit = resolve));
|
|
34
|
+
const child = spawn(line.file, line.args, {
|
|
35
|
+
cwd: spec.cwd,
|
|
36
|
+
env: spec.env,
|
|
37
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
38
|
+
detached: platform !== "win32",
|
|
39
|
+
windowsHide: true,
|
|
40
|
+
windowsVerbatimArguments: line.verbatim,
|
|
41
|
+
});
|
|
42
|
+
const pid = child.pid;
|
|
43
|
+
if (pid !== undefined) {
|
|
44
|
+
if (platform !== "win32")
|
|
45
|
+
trackProcessGroup(pid);
|
|
46
|
+
deps.onSpawn?.(pid, spec);
|
|
47
|
+
}
|
|
48
|
+
child.stderr?.on("data", (chunk) => {
|
|
49
|
+
tail = (tail + chunk.toString("utf8")).slice(-STDERR_TAIL_BYTES);
|
|
50
|
+
});
|
|
51
|
+
// 写一个已退出进程的 stdin 会 EPIPE;交给 exited 处理,不让它变成未捕获异常
|
|
52
|
+
child.stdin?.on("error", () => undefined);
|
|
53
|
+
child.on("error", (error) => {
|
|
54
|
+
tail = `${tail}\n${error.message}`.slice(-STDERR_TAIL_BYTES);
|
|
55
|
+
child.stdout?.destroy();
|
|
56
|
+
finish(-1);
|
|
57
|
+
});
|
|
58
|
+
let done = false;
|
|
59
|
+
const finish = (code) => {
|
|
60
|
+
if (done)
|
|
61
|
+
return;
|
|
62
|
+
done = true;
|
|
63
|
+
if (pid !== undefined) {
|
|
64
|
+
untrackProcessGroup(pid);
|
|
65
|
+
deps.onExit?.(pid);
|
|
66
|
+
}
|
|
67
|
+
resolveExit(code);
|
|
68
|
+
};
|
|
69
|
+
child.on("close", (code) => finish(code));
|
|
70
|
+
let terminating;
|
|
71
|
+
return {
|
|
72
|
+
stdin: child.stdin,
|
|
73
|
+
stdout: child.stdout,
|
|
74
|
+
...(pid !== undefined ? { pid } : {}),
|
|
75
|
+
stderrTail: () => tail,
|
|
76
|
+
exited,
|
|
77
|
+
terminate(graceMs = STDIN_CLOSE_GRACE_MS) {
|
|
78
|
+
terminating ??= (async () => {
|
|
79
|
+
if (done)
|
|
80
|
+
return;
|
|
81
|
+
child.stdin?.end();
|
|
82
|
+
const timer = new Promise((resolve) => setTimeout(() => resolve("timeout"), graceMs).unref());
|
|
83
|
+
if ((await Promise.race([exited, timer])) !== "timeout")
|
|
84
|
+
return;
|
|
85
|
+
if (pid !== undefined)
|
|
86
|
+
await killProcessTree(pid, { platform, ...deps.process });
|
|
87
|
+
else
|
|
88
|
+
child.kill("SIGKILL");
|
|
89
|
+
})();
|
|
90
|
+
return terminating;
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/** 最近一段 stderr,单行化后截断(放进错误信息)。 */
|
|
95
|
+
export function stderrHint(transport, max = 400) {
|
|
96
|
+
const text = transport.stderrTail().trim().replace(/\s+/g, " ");
|
|
97
|
+
if (text === "")
|
|
98
|
+
return "";
|
|
99
|
+
return text.length > max ? `…${text.slice(-max)}` : text;
|
|
100
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProcessRunner:把 AgentDriver 适配成 SubagentRunner(docs/wave5-plan.md §7.6、§5.3–§5.4)。[W5-E]
|
|
3
|
+
*
|
|
4
|
+
* 外部 CLI Agent 由此与 ama 子 Agent 共用 `task(agent=…)` 入口(D13)。`start()`:
|
|
5
|
+
* 1. 只在已信任目录里起(§5.4 信任;`claude -p` 会跳过目录信任对话框并执行项目 hooks);
|
|
6
|
+
* 2. 模式夹到父会话当前模式(`agents.<id>.maxMode` 例外),再取驱动支持的不更宽的模式;
|
|
7
|
+
* 按候选顺序选第一个已安装且支持该模式的驱动(D14 优先级;oneshot 只在只读下可选);
|
|
8
|
+
* 3. 会话级美元预算 `agents.sessionBudgetUsd` 用尽则不再起;
|
|
9
|
+
* 4. 子进程环境按 D16 清理;并发池(总 3 / claude 2)每回合取一个名额,排队可被 abort;
|
|
10
|
+
* 5. 权限请求只交给人({@link askHuman});中断 / stop / 超时时挂起的请求回 cancelled;
|
|
11
|
+
* 6. 每回合写 `custom{ama.agent-usage}`,会话建立写 `custom{ama.agent-session}`;
|
|
12
|
+
* 只回 finalText + 工具摘要(原始事件不落盘,§5.4 敏感数据);
|
|
13
|
+
* 7. 看门狗:单回合缺省 30 min;空闲 10 min 关进程(能续接的下次 `send` 以 resume 重开)。
|
|
14
|
+
*/
|
|
15
|
+
import { type AgentsConfig } from "../config/types-w5.js";
|
|
16
|
+
import type { PermissionMode } from "../permissions/types.js";
|
|
17
|
+
import type { RunnerHandle, SubagentRunRequest, SubagentRunner } from "../tools/types.js";
|
|
18
|
+
import { type ApproveFn } from "./permissions.js";
|
|
19
|
+
import type { DriverPool } from "./pool.js";
|
|
20
|
+
import type { AgentStore } from "./store.js";
|
|
21
|
+
import type { AgentDriver, DriverTurnResult } from "./types.js";
|
|
22
|
+
export declare const RUN_TIMEOUT_MS: number;
|
|
23
|
+
export declare const IDLE_CLOSE_MS: number;
|
|
24
|
+
export interface ProcessRunnerDeps {
|
|
25
|
+
/** 审批:只交给人。接到会话的 `requestApproval`(发 permission_request、走 broker 链)。 */
|
|
26
|
+
approve: ApproveFn;
|
|
27
|
+
pool: DriverPool;
|
|
28
|
+
store?: AgentStore;
|
|
29
|
+
/** 原始环境(runner 按 D16 清理)。 */
|
|
30
|
+
env: NodeJS.ProcessEnv;
|
|
31
|
+
config?: AgentsConfig;
|
|
32
|
+
/** 父会话当前模式(外部 Agent 不得更宽)。 */
|
|
33
|
+
parentMode?(): PermissionMode;
|
|
34
|
+
/** 无人值守(`-p`、RPC 未声明 approvals):审批一律拒绝。 */
|
|
35
|
+
unattended?: boolean | (() => boolean);
|
|
36
|
+
/** 目录是否已被 ama 信任。 */
|
|
37
|
+
trusted(cwd: string): boolean;
|
|
38
|
+
/** runner id(缺省取驱动的 agentId)。 */
|
|
39
|
+
id?: string;
|
|
40
|
+
timeoutMs?: number;
|
|
41
|
+
idleMs?: number;
|
|
42
|
+
setTimer?(fn: () => void, ms: number): () => void;
|
|
43
|
+
log?(level: "debug" | "info" | "warn", message: string): void;
|
|
44
|
+
}
|
|
45
|
+
/** 最终报告:最终文本 + 工具摘要 / 触及文件(给协调者当资料,不是指令)。 */
|
|
46
|
+
export declare function reportText(turn: DriverTurnResult): string;
|
|
47
|
+
export declare class ProcessRunner implements SubagentRunner {
|
|
48
|
+
private readonly deps;
|
|
49
|
+
readonly id: string;
|
|
50
|
+
private readonly drivers;
|
|
51
|
+
constructor(driver: AgentDriver | readonly AgentDriver[], deps: ProcessRunnerDeps);
|
|
52
|
+
get agentId(): string;
|
|
53
|
+
private unattended;
|
|
54
|
+
/** 选驱动:第一个已安装、且支持(不宽于)目标模式的候选。 */
|
|
55
|
+
private choose;
|
|
56
|
+
start(request: SubagentRunRequest): Promise<RunnerHandle>;
|
|
57
|
+
/** ProcessHandle 用。 */
|
|
58
|
+
get options(): ProcessRunnerDeps;
|
|
59
|
+
}
|
|
60
|
+
/** §10.2 的签名:`createProcessRunner(driver, { approve, pool, store, … })`。 */
|
|
61
|
+
export declare function createProcessRunner(driver: AgentDriver | readonly AgentDriver[], deps: ProcessRunnerDeps): ProcessRunner;
|