@armadra/agent 0.3.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 +257 -0
- package/README.md +263 -95
- 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/retry.d.ts +1 -1
- package/dist/agent/retry.js +2 -1
- package/dist/agent/session-cache.d.ts +5 -0
- package/dist/agent/session-cache.js +18 -2
- package/dist/agent/session-classifier.d.ts +18 -0
- package/dist/agent/session-classifier.js +105 -0
- package/dist/agent/session-compaction.d.ts +35 -6
- package/dist/agent/session-compaction.js +157 -31
- package/dist/agent/session-core.d.ts +40 -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 +63 -3
- package/dist/agent/session.d.ts +33 -29
- package/dist/agent/session.js +91 -126
- 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 +72 -6
- package/dist/agent/types-w5.d.ts +192 -0
- package/dist/agent/types-w5.js +10 -0
- package/dist/agent/types.d.ts +55 -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-messages.js +3 -2
- 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/google-generative-ai.js +3 -2
- package/dist/ai/apis/openai-compat.d.ts +4 -1
- package/dist/ai/apis/openai-compat.js +8 -1
- package/dist/ai/apis/openai-completions.js +3 -2
- package/dist/ai/apis/openai-responses.js +3 -2
- package/dist/ai/http.d.ts +28 -6
- package/dist/ai/http.js +41 -8
- 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 +28 -11
- package/dist/ai/providers/registry.js +112 -65
- package/dist/ai/providers/suggest.d.ts +18 -0
- package/dist/ai/providers/suggest.js +72 -0
- package/dist/ai/sse.d.ts +6 -2
- package/dist/ai/sse.js +22 -2
- package/dist/ai/types.d.ts +37 -4
- package/dist/ai/types.js +5 -0
- package/dist/bundle/ama.cjs +41979 -21147
- 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 +26 -7
- package/dist/cli/args.js +75 -82
- package/dist/cli/bootstrap.js +40 -4
- package/dist/cli/codemode-notice.d.ts +21 -0
- package/dist/cli/codemode-notice.js +56 -0
- 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 +8 -0
- package/dist/cli/compose-session.js +76 -2
- package/dist/cli/compose-store.d.ts +1 -1
- package/dist/cli/compose-store.js +3 -1
- package/dist/cli/compose.d.ts +17 -4
- package/dist/cli/compose.js +60 -14
- package/dist/cli/default-model.d.ts +38 -1
- package/dist/cli/default-model.js +96 -9
- package/dist/cli/deps.d.ts +42 -0
- package/dist/cli/exit-codes.d.ts +12 -0
- package/dist/cli/exit-codes.js +15 -0
- package/dist/cli/fake-visibility.d.ts +13 -0
- package/dist/cli/fake-visibility.js +26 -0
- package/dist/cli/from-prompt.d.ts +18 -0
- package/dist/cli/from-prompt.js +49 -0
- package/dist/cli/help-text.d.ts +4 -0
- package/dist/cli/help-text.js +102 -0
- package/dist/cli/main.d.ts +9 -2
- package/dist/cli/main.js +77 -3
- package/dist/cli/proxy.d.ts +51 -0
- package/dist/cli/proxy.js +135 -0
- package/dist/cli/startup-screen.d.ts +29 -0
- package/dist/cli/startup-screen.js +51 -2
- package/dist/cli/startup-steps.d.ts +1 -1
- package/dist/cli/startup-steps.js +21 -13
- package/dist/cli/subcommands/config.d.ts +22 -3
- package/dist/cli/subcommands/config.js +119 -21
- package/dist/cli/subcommands/context.js +4 -1
- package/dist/cli/subcommands/doctor.js +33 -1
- package/dist/cli/subcommands/init.js +2 -1
- package/dist/cli/subcommands/models-discover.d.ts +15 -9
- package/dist/cli/subcommands/models-discover.js +58 -52
- package/dist/cli/subcommands/models.d.ts +2 -0
- package/dist/cli/subcommands/models.js +33 -14
- package/dist/cli/subcommands/probe-runner.d.ts +96 -0
- package/dist/cli/subcommands/probe-runner.js +264 -0
- package/dist/cli/subcommands/providers-probe.d.ts +34 -0
- package/dist/cli/subcommands/providers-probe.js +87 -0
- package/dist/cli/subcommands/providers.d.ts +3 -2
- package/dist/cli/subcommands/providers.js +53 -51
- package/dist/cli/subcommands/sessions-export.d.ts +10 -0
- package/dist/cli/subcommands/sessions-export.js +59 -0
- package/dist/cli/subcommands/sessions-search.d.ts +13 -0
- package/dist/cli/subcommands/sessions-search.js +103 -0
- package/dist/cli/subcommands/sessions.d.ts +6 -3
- package/dist/cli/subcommands/sessions.js +58 -3
- package/dist/cli/subcommands/stats.d.ts +17 -0
- package/dist/cli/subcommands/stats.js +198 -0
- package/dist/cli/system-prompt-arg.d.ts +11 -0
- package/dist/cli/system-prompt-arg.js +34 -0
- 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/modes.d.ts +4 -11
- package/dist/codemode/modes.js +5 -27
- package/dist/codemode/tool.d.ts +18 -14
- package/dist/codemode/tool.js +76 -31
- 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/init.d.ts +6 -2
- package/dist/config/init.js +12 -5
- package/dist/config/json-schema.d.ts +1 -0
- package/dist/config/json-schema.js +98 -4
- package/dist/config/key-docs.d.ts +22 -0
- package/dist/config/key-docs.js +174 -0
- package/dist/config/merge.d.ts +12 -9
- package/dist/config/merge.js +102 -13
- 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 +91 -118
- package/dist/config/types-w5.d.ts +118 -0
- package/dist/config/types-w5.js +20 -0
- package/dist/config/types.d.ts +84 -7
- package/dist/config/types.js +29 -1
- 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 +61 -5
- 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 +40 -7
- package/dist/modes/interactive/approval-dialog.js +192 -35
- 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 +20 -3
- package/dist/modes/interactive/commands.js +75 -16
- 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 +16 -2
- package/dist/modes/interactive/interactive-mode.js +184 -202
- package/dist/modes/interactive/key-dispatch.d.ts +18 -2
- package/dist/modes/interactive/key-dispatch.js +53 -6
- package/dist/modes/interactive/line/line-mode.d.ts +3 -1
- package/dist/modes/interactive/line/line-mode.js +28 -9
- package/dist/modes/interactive/line/line-render.d.ts +6 -1
- package/dist/modes/interactive/line/line-render.js +66 -8
- package/dist/modes/interactive/message-view.d.ts +49 -10
- package/dist/modes/interactive/message-view.js +262 -46
- package/dist/modes/interactive/panels.d.ts +35 -0
- package/dist/modes/interactive/panels.js +157 -0
- package/dist/modes/interactive/pickers.d.ts +23 -2
- package/dist/modes/interactive/pickers.js +48 -15
- 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/run-indicator.d.ts +51 -0
- package/dist/modes/interactive/run-indicator.js +189 -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-header.d.ts +40 -0
- package/dist/modes/interactive/startup-header.js +169 -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 +107 -16
- package/dist/modes/interactive/status-bar.js +306 -81
- 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-summary.d.ts +46 -0
- package/dist/modes/interactive/tool-summary.js +218 -0
- package/dist/modes/interactive/tool-view.d.ts +58 -15
- package/dist/modes/interactive/tool-view.js +233 -145
- package/dist/modes/print/print-mode.d.ts +40 -4
- package/dist/modes/print/print-mode.js +161 -8
- package/dist/modes/rpc/commands.d.ts +9 -0
- package/dist/modes/rpc/commands.js +49 -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 +65 -0
- package/dist/permissions/auto-safe.js +547 -0
- package/dist/permissions/classifier.d.ts +68 -0
- package/dist/permissions/classifier.js +186 -0
- package/dist/permissions/dangerous.d.ts +5 -0
- package/dist/permissions/dangerous.js +1 -1
- package/dist/permissions/modes.d.ts +30 -0
- package/dist/permissions/modes.js +78 -0
- package/dist/permissions/pipeline.d.ts +72 -6
- package/dist/permissions/pipeline.js +306 -11
- package/dist/permissions/protected.d.ts +19 -0
- package/dist/permissions/protected.js +74 -0
- package/dist/permissions/readonly-bash.d.ts +30 -0
- package/dist/permissions/readonly-bash.js +118 -0
- package/dist/permissions/rules.js +3 -0
- package/dist/permissions/types.d.ts +92 -3
- package/dist/permissions/types.js +3 -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 +42 -5
- package/dist/sdk.js +34 -4
- package/dist/session/export.d.ts +32 -0
- package/dist/session/export.js +187 -0
- package/dist/session/redact.d.ts +15 -0
- package/dist/session/redact.js +55 -0
- package/dist/session/reuse.d.ts +33 -0
- package/dist/session/reuse.js +86 -0
- package/dist/session/scan.d.ts +34 -0
- package/dist/session/scan.js +140 -0
- package/dist/session/search.d.ts +52 -0
- package/dist/session/search.js +211 -0
- package/dist/session/stats-aggregate.d.ts +63 -0
- package/dist/session/stats-aggregate.js +163 -0
- package/dist/session/stats-index.d.ts +26 -0
- package/dist/session/stats-index.js +91 -0
- package/dist/session/stats-scan.d.ts +54 -0
- package/dist/session/stats-scan.js +236 -0
- 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 +40 -8
- package/dist/tools/presets.js +65 -19
- 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/component.d.ts +8 -2
- package/dist/tui/component.js +3 -1
- package/dist/tui/components/box.d.ts +6 -1
- package/dist/tui/components/box.js +16 -6
- package/dist/tui/components/card.d.ts +23 -0
- package/dist/tui/components/card.js +37 -0
- package/dist/tui/components/editor-history.d.ts +6 -0
- package/dist/tui/components/editor-history.js +45 -0
- package/dist/tui/components/editor-paste.d.ts +1 -1
- package/dist/tui/components/editor-paste.js +4 -4
- package/dist/tui/components/editor.d.ts +11 -5
- package/dist/tui/components/editor.js +52 -58
- package/dist/tui/components/key-value.d.ts +3 -0
- package/dist/tui/components/key-value.js +16 -6
- package/dist/tui/components/loader.d.ts +37 -7
- package/dist/tui/components/loader.js +84 -21
- package/dist/tui/components/markdown.d.ts +5 -1
- package/dist/tui/components/markdown.js +45 -21
- package/dist/tui/components/meter.d.ts +3 -3
- package/dist/tui/components/meter.js +13 -11
- package/dist/tui/components/select-list.d.ts +23 -1
- package/dist/tui/components/select-list.js +76 -13
- package/dist/tui/glyphs.d.ts +72 -0
- package/dist/tui/glyphs.js +118 -0
- package/dist/tui/keybindings.d.ts +5 -0
- package/dist/tui/keybindings.js +5 -0
- package/dist/tui/theme.d.ts +30 -6
- package/dist/tui/theme.js +103 -17
- package/dist/tui.d.ts +4 -2
- package/dist/tui.js +3 -1
- package/docs/acp.md +78 -0
- package/docs/agents.md +250 -0
- package/docs/codemode.md +28 -10
- package/docs/hooks.md +36 -32
- package/docs/permissions.md +212 -0
- package/docs/plan.md +107 -0
- package/docs/providers.md +261 -62
- package/docs/rewind-plan.md +181 -0
- package/docs/rpc.md +127 -40
- package/docs/sandbox.md +215 -0
- package/docs/session-format.md +43 -22
- package/docs/sessions.md +174 -0
- package/docs/tui-design.md +751 -0
- package/docs/tui.md +260 -64
- package/package.json +15 -2
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 后台命令(docs/wave5-plan.md §8.3 H6,D29:不加新工具,`bash{background}` + `bash{job, action}`)。[W5-H2]
|
|
3
|
+
*
|
|
4
|
+
* - `start`:调用方(bash.ts)给出 `spawn(stdout)`——**进程只在 bash.ts 的 `spawnShell` 里创建**,
|
|
5
|
+
* 这里只拿到 ChildProcess;stdout / stderr 直接写进 `outputPath`(文件描述符交给子进程,ama 退出也不
|
|
6
|
+
* 会因管道断开而 SIGPIPE)。POSIX 自成进程组并登记(进程退出时同步 SIGKILL 残留组)。
|
|
7
|
+
* - `wait(id, timeoutMs)`:等到退出或超时;`stop(id)`:杀整棵树(SIGTERM → 宽限 → SIGKILL);
|
|
8
|
+
* `output(id)`:读输出文件尾部(2000 行 / 50 KB)。
|
|
9
|
+
* - 生命周期事件经 `onChange` 发出(started / exited / stopped);`takeExited()` 取走尚未通知的已退出
|
|
10
|
+
* 任务(提醒通道 reminders.ts 据此告诉模型「后台命令 jobId 已退出(码 N)」)。
|
|
11
|
+
* - 按会话 id 登记(`jobsForSession`);`disposeSessionJobs` 在会话 dispose 时回收进程树。
|
|
12
|
+
*/
|
|
13
|
+
import { closeSync, mkdirSync, openSync, readFileSync, statSync } from "node:fs";
|
|
14
|
+
import { dirname } from "node:path";
|
|
15
|
+
import { exitCodeOf, isGroupAlive, killProcessTree, trackProcessGroup, untrackProcessGroup, } from "./process-tree.js";
|
|
16
|
+
import { truncateTail } from "./truncate.js";
|
|
17
|
+
/** 后台 bash 的查询形状:`{ job, action: wait | stop | output }`,不带 command。 */
|
|
18
|
+
export function isBackgroundJobQuery(toolName, input) {
|
|
19
|
+
if (toolName !== "bash" || typeof input !== "object" || input === null)
|
|
20
|
+
return false;
|
|
21
|
+
const record = input;
|
|
22
|
+
return typeof record.job === "string" && record.command === undefined;
|
|
23
|
+
}
|
|
24
|
+
export class BackgroundJobs {
|
|
25
|
+
entries = new Map();
|
|
26
|
+
listeners = new Set();
|
|
27
|
+
seq = 0;
|
|
28
|
+
start(command, options) {
|
|
29
|
+
mkdirSync(dirname(options.outputPath), { recursive: true });
|
|
30
|
+
const fd = openSync(options.outputPath, "a");
|
|
31
|
+
let child;
|
|
32
|
+
try {
|
|
33
|
+
child = options.spawn(fd);
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
closeSync(fd);
|
|
37
|
+
}
|
|
38
|
+
const id = `bg${++this.seq}`;
|
|
39
|
+
const job = {
|
|
40
|
+
id,
|
|
41
|
+
command,
|
|
42
|
+
cwd: options.cwd,
|
|
43
|
+
outputPath: options.outputPath,
|
|
44
|
+
startedAt: Date.now(),
|
|
45
|
+
status: "running",
|
|
46
|
+
};
|
|
47
|
+
if (child.pid !== undefined)
|
|
48
|
+
job.pid = child.pid;
|
|
49
|
+
const isWindows = (options.processDeps?.platform ?? process.platform) === "win32";
|
|
50
|
+
if (job.pid !== undefined && !isWindows)
|
|
51
|
+
trackProcessGroup(job.pid);
|
|
52
|
+
const entry = {
|
|
53
|
+
job,
|
|
54
|
+
notified: false,
|
|
55
|
+
stopping: false,
|
|
56
|
+
processDeps: options.processDeps,
|
|
57
|
+
done: new Promise((resolve) => {
|
|
58
|
+
const finish = (code, signal) => {
|
|
59
|
+
if (job.status !== "running")
|
|
60
|
+
return resolve();
|
|
61
|
+
job.exitCode = exitCodeOf(code, signal);
|
|
62
|
+
job.endedAt = Date.now();
|
|
63
|
+
job.status = entry.stopping ? "stopped" : "exited";
|
|
64
|
+
const pid = job.pid;
|
|
65
|
+
if (pid !== undefined && !isWindows && !isGroupAlive(pid, options.processDeps ?? {}))
|
|
66
|
+
untrackProcessGroup(pid);
|
|
67
|
+
this.notify({ phase: job.status === "stopped" ? "stopped" : "exited", job });
|
|
68
|
+
resolve();
|
|
69
|
+
};
|
|
70
|
+
child.once("exit", finish);
|
|
71
|
+
child.once("error", () => finish(127, null));
|
|
72
|
+
}),
|
|
73
|
+
};
|
|
74
|
+
child.unref();
|
|
75
|
+
this.entries.set(id, entry);
|
|
76
|
+
this.notify({ phase: "started", job });
|
|
77
|
+
return job;
|
|
78
|
+
}
|
|
79
|
+
get(id) {
|
|
80
|
+
return this.entries.get(id)?.job;
|
|
81
|
+
}
|
|
82
|
+
list() {
|
|
83
|
+
return [...this.entries.values()].map((entry) => entry.job);
|
|
84
|
+
}
|
|
85
|
+
/** 等到退出或超时(`signal` 可提前结束等待,不杀进程)。 */
|
|
86
|
+
async wait(id, timeoutMs, signal) {
|
|
87
|
+
const entry = this.entries.get(id);
|
|
88
|
+
if (entry === undefined)
|
|
89
|
+
return undefined;
|
|
90
|
+
if (entry.job.status !== "running")
|
|
91
|
+
return entry.job;
|
|
92
|
+
let timer;
|
|
93
|
+
let onAbort;
|
|
94
|
+
await Promise.race([
|
|
95
|
+
entry.done,
|
|
96
|
+
new Promise((resolve) => {
|
|
97
|
+
timer = setTimeout(resolve, Math.max(0, timeoutMs));
|
|
98
|
+
onAbort = () => resolve();
|
|
99
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
100
|
+
}),
|
|
101
|
+
]);
|
|
102
|
+
if (timer !== undefined)
|
|
103
|
+
clearTimeout(timer);
|
|
104
|
+
if (onAbort !== undefined)
|
|
105
|
+
signal?.removeEventListener("abort", onAbort);
|
|
106
|
+
return entry.job;
|
|
107
|
+
}
|
|
108
|
+
async stop(id) {
|
|
109
|
+
const entry = this.entries.get(id);
|
|
110
|
+
if (entry === undefined)
|
|
111
|
+
return undefined;
|
|
112
|
+
if (entry.job.status !== "running")
|
|
113
|
+
return entry.job;
|
|
114
|
+
entry.stopping = true;
|
|
115
|
+
// 已经由调用方知道结果:停止的任务不再经提醒通道通知
|
|
116
|
+
entry.notified = true;
|
|
117
|
+
if (entry.job.pid !== undefined)
|
|
118
|
+
await killProcessTree(entry.job.pid, entry.processDeps);
|
|
119
|
+
await entry.done;
|
|
120
|
+
return entry.job;
|
|
121
|
+
}
|
|
122
|
+
/** 输出文件尾部(2000 行 / 50 KB)。 */
|
|
123
|
+
output(id) {
|
|
124
|
+
const entry = this.entries.get(id);
|
|
125
|
+
if (entry === undefined)
|
|
126
|
+
return undefined;
|
|
127
|
+
let text = "";
|
|
128
|
+
try {
|
|
129
|
+
if (statSync(entry.job.outputPath).size > 0)
|
|
130
|
+
text = readFileSync(entry.job.outputPath, "utf8");
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// 输出文件被删:按空输出
|
|
134
|
+
}
|
|
135
|
+
return { ...truncateTail(text), job: entry.job };
|
|
136
|
+
}
|
|
137
|
+
/** 取走已退出、尚未通知的任务(提醒通道用;wait 已看到退出的也算已知)。 */
|
|
138
|
+
takeExited() {
|
|
139
|
+
const out = [];
|
|
140
|
+
for (const entry of this.entries.values()) {
|
|
141
|
+
if (entry.job.status === "running" || entry.notified)
|
|
142
|
+
continue;
|
|
143
|
+
entry.notified = true;
|
|
144
|
+
out.push(entry.job);
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
/** 标记为已知(模型已经通过 wait / output 看到了退出)。 */
|
|
149
|
+
markSeen(id) {
|
|
150
|
+
const entry = this.entries.get(id);
|
|
151
|
+
if (entry !== undefined && entry.job.status !== "running")
|
|
152
|
+
entry.notified = true;
|
|
153
|
+
}
|
|
154
|
+
onChange(listener) {
|
|
155
|
+
this.listeners.add(listener);
|
|
156
|
+
return () => this.listeners.delete(listener);
|
|
157
|
+
}
|
|
158
|
+
get running() {
|
|
159
|
+
return this.list().filter((job) => job.status === "running").length;
|
|
160
|
+
}
|
|
161
|
+
/** 杀掉全部仍在运行的任务(会话 dispose)。 */
|
|
162
|
+
async disposeAll() {
|
|
163
|
+
await Promise.all([...this.entries.keys()].map((id) => this.stop(id).catch(() => undefined)));
|
|
164
|
+
this.listeners.clear();
|
|
165
|
+
}
|
|
166
|
+
notify(change) {
|
|
167
|
+
for (const listener of this.listeners) {
|
|
168
|
+
try {
|
|
169
|
+
listener(change);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// 监听器异常不影响任务
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const registry = new Map();
|
|
178
|
+
/** 会话的后台任务表(按会话 id,首次使用时建)。 */
|
|
179
|
+
export function jobsForSession(sessionId) {
|
|
180
|
+
let jobs = registry.get(sessionId);
|
|
181
|
+
if (jobs === undefined) {
|
|
182
|
+
jobs = new BackgroundJobs();
|
|
183
|
+
registry.set(sessionId, jobs);
|
|
184
|
+
}
|
|
185
|
+
return jobs;
|
|
186
|
+
}
|
|
187
|
+
/** 已有的任务表(不新建)。 */
|
|
188
|
+
export function existingJobs(sessionId) {
|
|
189
|
+
return registry.get(sessionId);
|
|
190
|
+
}
|
|
191
|
+
/** 会话 dispose:杀掉该会话仍在运行的后台任务并注销。 */
|
|
192
|
+
export async function disposeSessionJobs(sessionId) {
|
|
193
|
+
const jobs = registry.get(sessionId);
|
|
194
|
+
if (jobs === undefined)
|
|
195
|
+
return;
|
|
196
|
+
registry.delete(sessionId);
|
|
197
|
+
await jobs.disposeAll();
|
|
198
|
+
}
|
package/dist/tools/bash.d.ts
CHANGED
|
@@ -7,17 +7,43 @@
|
|
|
7
7
|
* - 结构化结果 `{ output, exit_code, truncated, full_output_path?, wall_time_seconds }`;
|
|
8
8
|
* 信号退出 `128 + signo`;非零退出码 → isError;
|
|
9
9
|
* - 注入 `AMA_*` 环境变量(shell.ts)。shell 退出后不等仍占着管道的后台进程。
|
|
10
|
+
* - [W5-H2] 后台命令(§8.3 H6,不加新工具):`{ command, background: true }` 立即返回
|
|
11
|
+
* `{ jobId, outputPath, pid }`;`{ job, action: "wait" | "output" | "stop" }` 查询 / 结束
|
|
12
|
+
* (background-jobs.ts,按会话登记,会话 dispose 时回收进程树;退出经提醒通道通知)。
|
|
13
|
+
* - **进程只在 `spawnShell` 里创建**(前台与后台共用)。[S2] `sandbox.bash: auto` 且有能限制写入的
|
|
14
|
+
* OS 沙箱时在这一处包一层(src/sandbox/bash.ts);`sandbox: false` 不包装(权限管线照常审批)。
|
|
15
|
+
* 失败输出像是被沙箱拒绝时末尾追加一行说明。
|
|
10
16
|
*/
|
|
17
|
+
import { type ChildProcess } from "node:child_process";
|
|
11
18
|
import type { ToolContext, ToolDefinition, ToolResult } from "./types.js";
|
|
12
19
|
import { type ShellConfig } from "./shell.js";
|
|
13
20
|
import { type ProcessDeps } from "./process-tree.js";
|
|
21
|
+
import { type BackgroundJobs } from "./background-jobs.js";
|
|
22
|
+
import { type BashCallPlace, type BashSandbox } from "../sandbox/bash.js";
|
|
14
23
|
export declare const DEFAULT_BASH_TIMEOUT_MS = 120000;
|
|
15
24
|
export declare const MAX_BASH_TIMEOUT_MS = 600000;
|
|
16
25
|
export interface BashInput {
|
|
17
|
-
|
|
26
|
+
/** 前台 / 后台命令;查询后台任务时不给。 */
|
|
27
|
+
command?: string;
|
|
18
28
|
timeoutMs?: number;
|
|
19
29
|
cwd?: string;
|
|
20
30
|
description?: string;
|
|
31
|
+
/** [W5-H2] 后台运行:立即返回 jobId。 */
|
|
32
|
+
background?: boolean;
|
|
33
|
+
/** [W5-H2] 后台任务 id(与 action 一起用)。 */
|
|
34
|
+
job?: string;
|
|
35
|
+
action?: "wait" | "output" | "stop";
|
|
36
|
+
/** [S2] false:不经 OS 沙箱运行(走正常审批)。只在沙箱生效时出现在 schema 里。 */
|
|
37
|
+
sandbox?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** [W5-H2] `wait` 的缺省等待(毫秒)。 */
|
|
40
|
+
export declare const DEFAULT_JOB_WAIT_MS = 30000;
|
|
41
|
+
export interface BackgroundStart {
|
|
42
|
+
jobId: string;
|
|
43
|
+
outputPath: string;
|
|
44
|
+
pid?: number;
|
|
45
|
+
/** [S2] 经 OS 沙箱运行。 */
|
|
46
|
+
sandboxed?: true;
|
|
21
47
|
}
|
|
22
48
|
export interface BashStructured {
|
|
23
49
|
output: string;
|
|
@@ -25,6 +51,8 @@ export interface BashStructured {
|
|
|
25
51
|
truncated: boolean;
|
|
26
52
|
full_output_path?: string;
|
|
27
53
|
wall_time_seconds: number;
|
|
54
|
+
/** [S2] 经 OS 沙箱运行。 */
|
|
55
|
+
sandboxed?: true;
|
|
28
56
|
}
|
|
29
57
|
export interface BashDetails extends BashStructured {
|
|
30
58
|
timedOut: boolean;
|
|
@@ -44,6 +72,30 @@ export interface BashToolOptions {
|
|
|
44
72
|
processDeps?: ProcessDeps;
|
|
45
73
|
/** 测试注入:基础环境,缺省 process.env。 */
|
|
46
74
|
baseEnv?(): NodeJS.ProcessEnv;
|
|
75
|
+
/** 测试注入:会话的后台任务表,缺省按会话 id 登记(background-jobs.ts)。 */
|
|
76
|
+
jobs?(sessionId: string): BackgroundJobs;
|
|
77
|
+
/** [S2] bash 的 OS 沙箱设定(组装时算一次,会话内不变);缺省不用沙箱。 */
|
|
78
|
+
sandbox?: BashSandbox;
|
|
79
|
+
}
|
|
80
|
+
export interface SpawnShellOptions {
|
|
81
|
+
cwd: string;
|
|
82
|
+
env: NodeJS.ProcessEnv;
|
|
83
|
+
/** POSIX 自成进程组(杀树用);Windows 为 false。 */
|
|
84
|
+
detached: boolean;
|
|
85
|
+
/** 前台 `["ignore", "pipe", "pipe"]`;后台把输出文件描述符直接交给子进程。 */
|
|
86
|
+
stdio: ["ignore", "pipe" | number, "pipe" | number];
|
|
87
|
+
/** [S2] 经 OS 沙箱运行:设定与这次调用的位置(工作区、输出目录)。 */
|
|
88
|
+
sandbox?: {
|
|
89
|
+
settings: BashSandbox;
|
|
90
|
+
place: BashCallPlace;
|
|
91
|
+
};
|
|
47
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* bash 工具唯一的进程创建点(前台 / 后台共用);[S2] 给了 `sandbox` 时经 OS 沙箱包装(包不上抛错,
|
|
95
|
+
* 不悄悄裸跑)。
|
|
96
|
+
*/
|
|
97
|
+
export declare function spawnShell(shell: ShellConfig, command: string, options: SpawnShellOptions): ChildProcess;
|
|
48
98
|
export declare function executeBash(input: BashInput, ctx: ToolContext, options?: BashToolOptions): Promise<ToolResult>;
|
|
99
|
+
/** [S2] 沙箱生效时追加到描述末尾的一句(会话内不变)。 */
|
|
100
|
+
export declare function sandboxDescription(sandbox: BashSandbox | undefined): string;
|
|
49
101
|
export declare function createBashTool(options?: BashToolOptions): ToolDefinition<BashInput>;
|
package/dist/tools/bash.js
CHANGED
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
* - 结构化结果 `{ output, exit_code, truncated, full_output_path?, wall_time_seconds }`;
|
|
8
8
|
* 信号退出 `128 + signo`;非零退出码 → isError;
|
|
9
9
|
* - 注入 `AMA_*` 环境变量(shell.ts)。shell 退出后不等仍占着管道的后台进程。
|
|
10
|
+
* - [W5-H2] 后台命令(§8.3 H6,不加新工具):`{ command, background: true }` 立即返回
|
|
11
|
+
* `{ jobId, outputPath, pid }`;`{ job, action: "wait" | "output" | "stop" }` 查询 / 结束
|
|
12
|
+
* (background-jobs.ts,按会话登记,会话 dispose 时回收进程树;退出经提醒通道通知)。
|
|
13
|
+
* - **进程只在 `spawnShell` 里创建**(前台与后台共用)。[S2] `sandbox.bash: auto` 且有能限制写入的
|
|
14
|
+
* OS 沙箱时在这一处包一层(src/sandbox/bash.ts);`sandbox: false` 不包装(权限管线照常审批)。
|
|
15
|
+
* 失败输出像是被沙箱拒绝时末尾追加一行说明。
|
|
10
16
|
*/
|
|
11
17
|
import { spawn } from "node:child_process";
|
|
12
18
|
import { stat } from "node:fs/promises";
|
|
@@ -16,11 +22,32 @@ import { buildShellArgs, buildToolEnv, resolveShell } from "./shell.js";
|
|
|
16
22
|
import { exitCodeOf, isGroupAlive, killProcessTree, trackProcessGroup, untrackProcessGroup, } from "./process-tree.js";
|
|
17
23
|
import { OutputAccumulator } from "./output-accumulator.js";
|
|
18
24
|
import { formatSize, resolveOutputDir, safeFileName } from "./truncate.js";
|
|
25
|
+
import { jobsForSession } from "./background-jobs.js";
|
|
26
|
+
import { looksLikeSandboxDenial, runsSandboxed, sandboxDenialHint, wrapBashCommand, } from "../sandbox/bash.js";
|
|
19
27
|
export const DEFAULT_BASH_TIMEOUT_MS = 120_000;
|
|
20
28
|
export const MAX_BASH_TIMEOUT_MS = 600_000;
|
|
21
29
|
const UPDATE_THROTTLE_MS = 100;
|
|
22
30
|
/** shell 退出后等管道关闭的上限(后台子进程可能一直占着)。 */
|
|
23
31
|
const STDIO_DRAIN_MS = 200;
|
|
32
|
+
/** [W5-H2] `wait` 的缺省等待(毫秒)。 */
|
|
33
|
+
export const DEFAULT_JOB_WAIT_MS = 30_000;
|
|
34
|
+
/**
|
|
35
|
+
* bash 工具唯一的进程创建点(前台 / 后台共用);[S2] 给了 `sandbox` 时经 OS 沙箱包装(包不上抛错,
|
|
36
|
+
* 不悄悄裸跑)。
|
|
37
|
+
*/
|
|
38
|
+
export function spawnShell(shell, command, options) {
|
|
39
|
+
const args = buildShellArgs(shell, command);
|
|
40
|
+
const wrapped = options.sandbox === undefined
|
|
41
|
+
? { command: shell.shell, args }
|
|
42
|
+
: wrapBashCommand(options.sandbox.settings, shell.shell, args, options.sandbox.place);
|
|
43
|
+
return spawn(wrapped.command, wrapped.args, {
|
|
44
|
+
cwd: options.cwd,
|
|
45
|
+
env: options.env,
|
|
46
|
+
detached: options.detached,
|
|
47
|
+
stdio: options.stdio,
|
|
48
|
+
windowsHide: true,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
24
51
|
function fail(message) {
|
|
25
52
|
return { content: message, isError: true };
|
|
26
53
|
}
|
|
@@ -56,9 +83,14 @@ function waitForExit(child) {
|
|
|
56
83
|
});
|
|
57
84
|
}
|
|
58
85
|
export async function executeBash(input, ctx, options = {}) {
|
|
86
|
+
if (input.job !== undefined)
|
|
87
|
+
return jobAction(input, ctx, options);
|
|
88
|
+
if (input.action !== undefined)
|
|
89
|
+
return fail("action needs job (a background job id)");
|
|
59
90
|
if (typeof input.command !== "string" || input.command.trim() === "") {
|
|
60
91
|
return fail("command must be a non-empty string");
|
|
61
92
|
}
|
|
93
|
+
const command = input.command;
|
|
62
94
|
const timeoutMs = input.timeoutMs ?? options.defaultTimeoutMs ?? DEFAULT_BASH_TIMEOUT_MS;
|
|
63
95
|
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > MAX_BASH_TIMEOUT_MS) {
|
|
64
96
|
return fail(`timeoutMs must be between 1 and ${MAX_BASH_TIMEOUT_MS}`);
|
|
@@ -83,18 +115,29 @@ export async function executeBash(input, ctx, options = {}) {
|
|
|
83
115
|
depth: ctx.depth,
|
|
84
116
|
});
|
|
85
117
|
const isWindows = (options.processDeps?.platform ?? process.platform) === "win32";
|
|
118
|
+
const sandbox = options.sandbox !== undefined && runsSandboxed(options.sandbox, input)
|
|
119
|
+
? {
|
|
120
|
+
settings: options.sandbox,
|
|
121
|
+
place: {
|
|
122
|
+
workspace: ctx.cwd,
|
|
123
|
+
outputDir: resolveOutputDir(ctx.outputDir),
|
|
124
|
+
},
|
|
125
|
+
}
|
|
126
|
+
: undefined;
|
|
127
|
+
if (input.background === true)
|
|
128
|
+
return startBackground(command, { cwd, env, shell, isWindows, sandbox }, ctx, options);
|
|
86
129
|
const started = Date.now();
|
|
87
130
|
const acc = new OutputAccumulator({
|
|
88
131
|
spillPath: () => join(resolveOutputDir(ctx.outputDir), safeFileName(`bash-${ctx.toolCallId}.log`)),
|
|
89
132
|
});
|
|
90
133
|
let child;
|
|
91
134
|
try {
|
|
92
|
-
child =
|
|
135
|
+
child = spawnShell(shell, command, {
|
|
93
136
|
cwd,
|
|
94
137
|
env,
|
|
95
138
|
detached: !isWindows,
|
|
96
139
|
stdio: ["ignore", "pipe", "pipe"],
|
|
97
|
-
|
|
140
|
+
...(sandbox === undefined ? {} : { sandbox }),
|
|
98
141
|
});
|
|
99
142
|
}
|
|
100
143
|
catch (err) {
|
|
@@ -165,6 +208,7 @@ export async function executeBash(input, ctx, options = {}) {
|
|
|
165
208
|
truncated: out.truncated,
|
|
166
209
|
...(out.fullOutputPath !== undefined ? { full_output_path: out.fullOutputPath } : {}),
|
|
167
210
|
wall_time_seconds: wall,
|
|
211
|
+
...(sandbox === undefined ? {} : { sandboxed: true }),
|
|
168
212
|
};
|
|
169
213
|
const details = {
|
|
170
214
|
...structured,
|
|
@@ -188,6 +232,10 @@ export async function executeBash(input, ctx, options = {}) {
|
|
|
188
232
|
parts.push(`[Command timed out after ${timeoutMs} ms and was killed]`);
|
|
189
233
|
if (exitCode !== 0)
|
|
190
234
|
parts.push(`[exit code: ${exitCode}]`);
|
|
235
|
+
const networkDenied = sandbox?.settings.network === "deny";
|
|
236
|
+
if (sandbox !== undefined && exitCode !== 0 && !aborted && !timedOut)
|
|
237
|
+
if (looksLikeSandboxDenial(out.output, networkDenied))
|
|
238
|
+
parts.push(sandboxDenialHint(networkDenied));
|
|
191
239
|
return {
|
|
192
240
|
content: parts.join("\n\n"),
|
|
193
241
|
isError: exitCode !== 0 || timedOut || aborted,
|
|
@@ -195,22 +243,125 @@ export async function executeBash(input, ctx, options = {}) {
|
|
|
195
243
|
details,
|
|
196
244
|
};
|
|
197
245
|
}
|
|
246
|
+
// ---------------------------------------------------------------------------
|
|
247
|
+
// [W5-H2] 后台命令
|
|
248
|
+
// ---------------------------------------------------------------------------
|
|
249
|
+
function jobsOf(ctx, options) {
|
|
250
|
+
return options.jobs ? options.jobs(ctx.sessionId) : jobsForSession(ctx.sessionId);
|
|
251
|
+
}
|
|
252
|
+
function startBackground(command, spawnInfo, ctx, options) {
|
|
253
|
+
const { cwd, env, shell, isWindows, sandbox } = spawnInfo;
|
|
254
|
+
const outputPath = join(resolveOutputDir(ctx.outputDir), safeFileName(`bash-bg-${ctx.toolCallId}.log`));
|
|
255
|
+
let job;
|
|
256
|
+
try {
|
|
257
|
+
job = jobsOf(ctx, options).start(command, {
|
|
258
|
+
cwd,
|
|
259
|
+
outputPath,
|
|
260
|
+
...(options.processDeps === undefined ? {} : { processDeps: options.processDeps }),
|
|
261
|
+
spawn: (fd) => spawnShell(shell, command, {
|
|
262
|
+
cwd,
|
|
263
|
+
env,
|
|
264
|
+
detached: !isWindows,
|
|
265
|
+
stdio: ["ignore", fd, fd],
|
|
266
|
+
...(sandbox === undefined ? {} : { sandbox }),
|
|
267
|
+
}),
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
catch (err) {
|
|
271
|
+
return fail(`Failed to start shell ${shell.shell}: ${err.message}`);
|
|
272
|
+
}
|
|
273
|
+
const structured = { jobId: job.id, outputPath: job.outputPath };
|
|
274
|
+
if (job.pid !== undefined)
|
|
275
|
+
structured.pid = job.pid;
|
|
276
|
+
if (sandbox !== undefined)
|
|
277
|
+
structured.sandboxed = true;
|
|
278
|
+
return {
|
|
279
|
+
content: `Started background job ${job.id}${job.pid !== undefined ? ` (pid ${job.pid})` : ""}; ` +
|
|
280
|
+
`output: ${job.outputPath}. Check it with bash {"job":"${job.id}","action":"wait"|"output"|"stop"}; ` +
|
|
281
|
+
"you will be told when it exits.",
|
|
282
|
+
structured,
|
|
283
|
+
details: { ...structured, background: true, command, cwd },
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
function jobStatusLine(job) {
|
|
287
|
+
const state = job.status === "running"
|
|
288
|
+
? "still running"
|
|
289
|
+
: job.status === "stopped"
|
|
290
|
+
? `stopped (exit code ${job.exitCode ?? "?"})`
|
|
291
|
+
: `exited with code ${job.exitCode ?? "?"}`;
|
|
292
|
+
return `[job ${job.id} ${state}; output: ${job.outputPath}]`;
|
|
293
|
+
}
|
|
294
|
+
async function jobAction(input, ctx, options) {
|
|
295
|
+
const id = input.job;
|
|
296
|
+
if (input.command !== undefined || input.background === true || input.sandbox !== undefined)
|
|
297
|
+
return fail("job queries take only job, action and timeoutMs");
|
|
298
|
+
const action = input.action ?? "output";
|
|
299
|
+
const jobs = jobsOf(ctx, options);
|
|
300
|
+
if (jobs.get(id) === undefined) {
|
|
301
|
+
const known = jobs.list().map((job) => job.id);
|
|
302
|
+
return fail(`Unknown background job ${id}${known.length > 0 ? ` (jobs: ${known.join(", ")})` : ""}`);
|
|
303
|
+
}
|
|
304
|
+
if (action === "stop") {
|
|
305
|
+
const job = (await jobs.stop(id));
|
|
306
|
+
const out = jobs.output(id);
|
|
307
|
+
const text = out?.content ?? "";
|
|
308
|
+
return {
|
|
309
|
+
content: `${text === "" ? "(no output)" : text}\n\n${jobStatusLine(job)}`,
|
|
310
|
+
structured: { jobId: id, status: job.status, exit_code: job.exitCode ?? null },
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
if (action === "wait") {
|
|
314
|
+
const waitMs = input.timeoutMs ?? DEFAULT_JOB_WAIT_MS;
|
|
315
|
+
if (!Number.isFinite(waitMs) || waitMs <= 0 || waitMs > MAX_BASH_TIMEOUT_MS)
|
|
316
|
+
return fail(`timeoutMs must be between 1 and ${MAX_BASH_TIMEOUT_MS}`);
|
|
317
|
+
await jobs.wait(id, waitMs, ctx.signal);
|
|
318
|
+
}
|
|
319
|
+
const out = jobs.output(id);
|
|
320
|
+
if (out === undefined)
|
|
321
|
+
return fail(`Unknown background job ${id}`);
|
|
322
|
+
const job = out.job;
|
|
323
|
+
if (job.status !== "running")
|
|
324
|
+
jobs.markSeen(id);
|
|
325
|
+
const parts = [out.content === "" ? "(no output)" : out.content];
|
|
326
|
+
if (out.truncated)
|
|
327
|
+
parts.push(`[Output truncated: showing the last ${out.outputLines} of ${out.totalLines} lines ` +
|
|
328
|
+
`(${formatSize(out.totalBytes)} total). Full output: ${job.outputPath}]`);
|
|
329
|
+
parts.push(jobStatusLine(job));
|
|
330
|
+
return {
|
|
331
|
+
content: parts.join("\n\n"),
|
|
332
|
+
isError: job.status === "exited" && job.exitCode !== 0,
|
|
333
|
+
structured: { jobId: id, status: job.status, exit_code: job.exitCode ?? null },
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
/** [S2] 沙箱生效时追加到描述末尾的一句(会话内不变)。 */
|
|
337
|
+
export function sandboxDescription(sandbox) {
|
|
338
|
+
if (sandbox?.active !== true)
|
|
339
|
+
return "";
|
|
340
|
+
const net = sandbox.network === "deny" ? ", no network" : "";
|
|
341
|
+
return ` Runs in an OS sandbox (writes only in workspace/temp${net}); sandbox:false needs approval.`;
|
|
342
|
+
}
|
|
198
343
|
export function createBashTool(options = {}) {
|
|
344
|
+
const sandboxed = options.sandbox?.active === true;
|
|
199
345
|
return {
|
|
200
346
|
name: "bash",
|
|
201
347
|
label: "Bash",
|
|
202
|
-
description: "Run a shell command
|
|
203
|
-
|
|
204
|
-
|
|
348
|
+
description: "Run a shell command; stdout+stderr combined, keeps the last 2000 lines / 50 KB (full " +
|
|
349
|
+
`output saved). Timeout ${DEFAULT_BASH_TIMEOUT_MS / 1000} s, max ${MAX_BASH_TIMEOUT_MS / 1000} s. ` +
|
|
350
|
+
"background:true gives a job id for {job, action}." +
|
|
351
|
+
sandboxDescription(options.sandbox),
|
|
205
352
|
parameters: {
|
|
206
353
|
type: "object",
|
|
207
354
|
properties: {
|
|
208
355
|
command: { type: "string" },
|
|
209
356
|
timeoutMs: { type: "integer" },
|
|
210
357
|
cwd: { type: "string", description: "Default: session cwd" },
|
|
211
|
-
description: { type: "string"
|
|
358
|
+
description: { type: "string" },
|
|
359
|
+
background: { type: "boolean" },
|
|
360
|
+
job: { type: "string" },
|
|
361
|
+
action: { type: "string", enum: ["wait", "output", "stop"] },
|
|
362
|
+
// [S2] 只在沙箱生效时出现:沙箱关闭的会话工具 schema 与以前逐字节相同
|
|
363
|
+
...(sandboxed ? { sandbox: { type: "boolean" } } : {}),
|
|
212
364
|
},
|
|
213
|
-
required: ["command"],
|
|
214
365
|
additionalProperties: false,
|
|
215
366
|
},
|
|
216
367
|
permission: "execute",
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 剪贴板图片(docs/wave5-plan.md §4、D12)。[W5-I] 界面接线(`Ctrl+V`、`/paste`)归 W5-U。
|
|
3
|
+
*
|
|
4
|
+
* 零依赖读不了剪贴板位图,按平台依次调系统命令,成功写 `<dataDir>/clipboard/<时间戳>.png` 并返回
|
|
5
|
+
* 路径(编辑器插入 `@<路径>`,之后走 loadImageFile);没有工具或剪贴板里没有图返回 undefined:
|
|
6
|
+
*
|
|
7
|
+
* | 平台 | 依次尝试 |
|
|
8
|
+
* | ------- | --------------------------------------------------------------------------- |
|
|
9
|
+
* | macOS | `osascript`(`the clipboard as «class PNGf»` 写文件)、`pngpaste <文件>` |
|
|
10
|
+
* | Linux | Wayland(有 WAYLAND_DISPLAY)`wl-paste -t image/png`;`xclip -selection clipboard -t image/png -o` |
|
|
11
|
+
* | Windows | `powershell` 的 `Get-Clipboard -Format Image` 存 PNG(路径经环境变量传入) |
|
|
12
|
+
*
|
|
13
|
+
* 写出的文件必须以 PNG 文件头开头,否则删掉按「没有图」处理。`ama sessions prune` 清理超过 7 天的
|
|
14
|
+
* 剪贴板文件(`gcClipboardImages`)。
|
|
15
|
+
*/
|
|
16
|
+
import { type RunCommand } from "./image-resize.js";
|
|
17
|
+
export declare const CLIPBOARD_DIR = "clipboard";
|
|
18
|
+
export declare const CLIPBOARD_MAX_AGE_DAYS = 7;
|
|
19
|
+
export interface ClipboardDeps {
|
|
20
|
+
platform?: NodeJS.Platform;
|
|
21
|
+
run?: RunCommand;
|
|
22
|
+
env?: NodeJS.ProcessEnv;
|
|
23
|
+
now?(): number;
|
|
24
|
+
}
|
|
25
|
+
export type ClipboardResult = {
|
|
26
|
+
ok: true;
|
|
27
|
+
path: string;
|
|
28
|
+
tool: string;
|
|
29
|
+
}
|
|
30
|
+
/** `no_tool`:一个可用命令都没有;`no_image`:命令能用但剪贴板里没有图。 */
|
|
31
|
+
| {
|
|
32
|
+
ok: false;
|
|
33
|
+
reason: "no_tool" | "no_image";
|
|
34
|
+
};
|
|
35
|
+
/** 读剪贴板图片到数据目录;返回结果与原因(界面据此给一行提示)。 */
|
|
36
|
+
export declare function readClipboardImage(dataDir: string, deps?: ClipboardDeps): Promise<ClipboardResult>;
|
|
37
|
+
/** §10.2 的签名:成功返回 PNG 路径,没有工具或没有图返回 undefined。 */
|
|
38
|
+
export declare function pasteClipboardImage(dataDir: string, deps?: ClipboardDeps): Promise<string | undefined>;
|
|
39
|
+
/** 清理 `<dataDir>/clipboard/` 里超过 `maxAgeDays`(缺省 7)天的文件;返回(将)删除的路径。 */
|
|
40
|
+
export declare function gcClipboardImages(dataDir: string, options?: {
|
|
41
|
+
dryRun?: boolean;
|
|
42
|
+
maxAgeDays?: number;
|
|
43
|
+
now?: number;
|
|
44
|
+
}): Promise<string[]>;
|