@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
|
@@ -4,14 +4,17 @@
|
|
|
4
4
|
* - 模型:按供应商分组并标 key 状态(`modelItems`,与启动期共用),当前模型预选;
|
|
5
5
|
* - 会话:名字或首条提示、相对时间、消息数(`sessionItems`);
|
|
6
6
|
* - 树:会话文件里全部用户消息,按分叉缩进,`●` 标出当前分支;选中项回填编辑器(由 commands.ts 处理);
|
|
7
|
-
* -
|
|
7
|
+
* - 权限模式(标题「权限模式」,界面顺序 1–6,当前模式 ✓ / Default dim / Recommended accent,底部按键提示,
|
|
8
|
+
* 上下留白,见 permissionItems)与思考级别;
|
|
9
|
+
* - 所有选择器底部一行按键提示(dim),模型选择器带 (i/n) 并给当前模型打 ✓。
|
|
8
10
|
*/
|
|
9
11
|
import { THINKING_LEVELS } from "../../ai/thinking.js";
|
|
10
|
-
import {
|
|
12
|
+
import { PERMISSION_MODE_INFO, PERMISSION_MODE_ORDER, RECOMMENDED_PERMISSION_MODE, } from "../../permissions/modes.js";
|
|
11
13
|
import { Box, SelectList, } from "../../tui.js";
|
|
12
14
|
import { contentText } from "./message-view.js";
|
|
13
15
|
import { relativeTime } from "./startup-ui.js";
|
|
14
16
|
export { modelItems, sessionItems } from "./startup-ui.js";
|
|
17
|
+
export const PICKER_FOOTER = "↑↓ 选择 · Enter 确认 · Esc 取消";
|
|
15
18
|
/** 打开一个居中选择器;Enter 返回选中项,Esc / Ctrl+C 返回 undefined。 */
|
|
16
19
|
export function openPicker(host, spec) {
|
|
17
20
|
return new Promise((resolve) => {
|
|
@@ -26,30 +29,60 @@ export function openPicker(host, spec) {
|
|
|
26
29
|
filterable: spec.filterable ?? spec.items.length > 8,
|
|
27
30
|
...(host.keybindings !== undefined ? { keybindings: host.keybindings } : {}),
|
|
28
31
|
...(spec.emptyText !== undefined ? { emptyText: spec.emptyText } : {}),
|
|
32
|
+
...(spec.numberKeys === true ? { numberKeys: true } : {}),
|
|
33
|
+
...(spec.stacked === true ? { stacked: true } : {}),
|
|
34
|
+
...(spec.currentValue !== undefined ? { currentValue: spec.currentValue } : {}),
|
|
35
|
+
...(spec.showCount === true ? { showCount: true } : {}),
|
|
36
|
+
footer: spec.footer ?? PICKER_FOOTER,
|
|
29
37
|
onSelect: (item) => close(item),
|
|
30
38
|
onCancel: () => close(undefined),
|
|
31
39
|
});
|
|
32
40
|
if (spec.selected !== undefined)
|
|
33
41
|
list.selectValue(spec.selected);
|
|
34
42
|
const width = Math.max(20, Math.min(host.columns() - 2, 72));
|
|
35
|
-
|
|
43
|
+
const box = new Box(list, {
|
|
44
|
+
title: spec.title,
|
|
45
|
+
theme: host.theme,
|
|
46
|
+
...(spec.paddingY !== undefined ? { paddingY: spec.paddingY } : {}),
|
|
47
|
+
});
|
|
48
|
+
handle = host.showOverlay(box, {
|
|
36
49
|
anchor: "center",
|
|
37
50
|
width,
|
|
38
51
|
});
|
|
39
52
|
});
|
|
40
53
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
/**
|
|
55
|
+
* 模式选择器(标题「权限模式」):界面顺序、当前模式打勾(`currentValue`)、配置里的缺省模式标
|
|
56
|
+
* `Default`、Auto 标 `Recommended`,右侧数字快捷键 1–6,说明在下一行。
|
|
57
|
+
*/
|
|
58
|
+
export function permissionItems(_current, configDefault = "default") {
|
|
59
|
+
return PERMISSION_MODE_ORDER.map((mode) => {
|
|
60
|
+
const info = PERMISSION_MODE_INFO[mode];
|
|
61
|
+
const item = { value: mode, label: info.label, description: info.description };
|
|
62
|
+
const badges = [
|
|
63
|
+
...(mode === configDefault ? ["Default"] : []),
|
|
64
|
+
...(mode === RECOMMENDED_PERMISSION_MODE ? ["Recommended"] : []),
|
|
65
|
+
];
|
|
66
|
+
if (badges.length > 0) {
|
|
67
|
+
item.badge = badges.join(" · ");
|
|
68
|
+
if (mode !== RECOMMENDED_PERMISSION_MODE)
|
|
69
|
+
item.badgeColor = "dim";
|
|
70
|
+
}
|
|
71
|
+
return item;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
export function permissionPickerSpec(current, configDefault = "default") {
|
|
75
|
+
return {
|
|
76
|
+
title: "权限模式",
|
|
77
|
+
items: permissionItems(current, configDefault),
|
|
78
|
+
selected: current,
|
|
79
|
+
currentValue: current,
|
|
80
|
+
filterable: false,
|
|
81
|
+
numberKeys: true,
|
|
82
|
+
stacked: true,
|
|
83
|
+
footer: "↑↓ 选择 · 1-6 直接选 · Enter 确认 · Esc 取消",
|
|
84
|
+
paddingY: 1,
|
|
85
|
+
};
|
|
53
86
|
}
|
|
54
87
|
export function thinkingItems(reasoning) {
|
|
55
88
|
return THINKING_LEVELS.map((level) => {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/plan` 的语义(line 模式与交互模式共用,经 commands-core)。[W5-U]
|
|
3
|
+
*
|
|
4
|
+
* - `/plan`:当前计划与状态(版本、状态、文件、步骤、待办进度、所处模式);
|
|
5
|
+
* - `/plan approve [模式|fresh]`:批准待审批的计划(没有计划块时把上一条回复当作计划,docs/wave5-plan.md
|
|
6
|
+
* §6.3);模式缺省回到进入 plan 前的模式,`fresh` 在新会话里执行(新建会话 → `adopt(plan)` → 发计划
|
|
7
|
+
* 全文);
|
|
8
|
+
* - `/plan reject`:放弃待审批的计划(留在 Plan 模式);
|
|
9
|
+
* - `/plan <目标>`:进入 Plan 模式并把目标作为提示发出。
|
|
10
|
+
*/
|
|
11
|
+
import type { AgentSession, PlanData } from "../../agent/types.js";
|
|
12
|
+
import type { SwitchRequest } from "../../cli/compose-session.js";
|
|
13
|
+
import type { PermissionMode } from "../../permissions/types.js";
|
|
14
|
+
import { type PlanController } from "../../plan/controller.js";
|
|
15
|
+
export declare const PLAN_USAGE = "\u7528\u6CD5\uFF1A/plan [\u76EE\u6807] | /plan approve [\u6A21\u5F0F|fresh] | /plan reject";
|
|
16
|
+
export declare function planStatusText(status: PlanData["status"]): string;
|
|
17
|
+
/** 计划的标题:第一个 `#` 标题,没有时取第一行非空文本。 */
|
|
18
|
+
export declare function planTitle(plan: Pick<PlanData, "markdown">): string;
|
|
19
|
+
/** 批准后的执行模式(缺省回到进入 plan 前的模式;进入前就是 plan 则 default)。 */
|
|
20
|
+
export declare function defaultExecutionMode(controller: PlanController): PermissionMode;
|
|
21
|
+
/** `/plan` 的纯文本说明。 */
|
|
22
|
+
export declare function describePlan(controller: PlanController, session: AgentSession): string;
|
|
23
|
+
export interface PlanCommandContext {
|
|
24
|
+
switchSession(request: SwitchRequest): Promise<AgentSession>;
|
|
25
|
+
}
|
|
26
|
+
export type PlanCommandResult = {
|
|
27
|
+
kind: "handled";
|
|
28
|
+
message: string;
|
|
29
|
+
wait?: boolean;
|
|
30
|
+
} | {
|
|
31
|
+
kind: "prompt";
|
|
32
|
+
text: string;
|
|
33
|
+
};
|
|
34
|
+
/** 「新上下文执行」:新建会话、记下计划与 todo、切到执行模式,返回首条消息。 */
|
|
35
|
+
export declare function approveFresh(controller: PlanController, plan: PlanData, mode: PermissionMode, ctx: PlanCommandContext, editedMarkdown?: string): Promise<{
|
|
36
|
+
session: AgentSession;
|
|
37
|
+
prompt: string;
|
|
38
|
+
plan: PlanData;
|
|
39
|
+
}>;
|
|
40
|
+
export declare function planCommand(session: AgentSession, args: string, ctx: PlanCommandContext): Promise<PlanCommandResult>;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/plan` 的语义(line 模式与交互模式共用,经 commands-core)。[W5-U]
|
|
3
|
+
*
|
|
4
|
+
* - `/plan`:当前计划与状态(版本、状态、文件、步骤、待办进度、所处模式);
|
|
5
|
+
* - `/plan approve [模式|fresh]`:批准待审批的计划(没有计划块时把上一条回复当作计划,docs/wave5-plan.md
|
|
6
|
+
* §6.3);模式缺省回到进入 plan 前的模式,`fresh` 在新会话里执行(新建会话 → `adopt(plan)` → 发计划
|
|
7
|
+
* 全文);
|
|
8
|
+
* - `/plan reject`:放弃待审批的计划(留在 Plan 模式);
|
|
9
|
+
* - `/plan <目标>`:进入 Plan 模式并把目标作为提示发出。
|
|
10
|
+
*/
|
|
11
|
+
import { AmaError } from "../../errors.js";
|
|
12
|
+
import { parsePermissionMode, permissionModeLabel } from "../../permissions/modes.js";
|
|
13
|
+
import { planController } from "../../plan/controller.js";
|
|
14
|
+
import { executionMode } from "../../plan/store.js";
|
|
15
|
+
export const PLAN_USAGE = "用法:/plan [目标] | /plan approve [模式|fresh] | /plan reject";
|
|
16
|
+
const STATUS_TEXT = {
|
|
17
|
+
proposed: "待审批",
|
|
18
|
+
approved: "已批准",
|
|
19
|
+
rejected: "已放弃",
|
|
20
|
+
superseded: "已被新版本取代",
|
|
21
|
+
};
|
|
22
|
+
export function planStatusText(status) {
|
|
23
|
+
return STATUS_TEXT[status];
|
|
24
|
+
}
|
|
25
|
+
/** 计划的标题:第一个 `#` 标题,没有时取第一行非空文本。 */
|
|
26
|
+
export function planTitle(plan) {
|
|
27
|
+
const lines = plan.markdown.split(/\r?\n/).map((l) => l.trim());
|
|
28
|
+
const heading = lines.find((l) => /^#{1,6}\s+\S/.test(l));
|
|
29
|
+
if (heading !== undefined)
|
|
30
|
+
return heading.replace(/^#{1,6}\s+/, "");
|
|
31
|
+
return lines.find((l) => l !== "" && !/^<\/?proposed_plan>$/.test(l)) ?? "(无标题)";
|
|
32
|
+
}
|
|
33
|
+
/** 批准后的执行模式(缺省回到进入 plan 前的模式;进入前就是 plan 则 default)。 */
|
|
34
|
+
export function defaultExecutionMode(controller) {
|
|
35
|
+
return executionMode(undefined, controller.prePlanMode());
|
|
36
|
+
}
|
|
37
|
+
/** `/plan` 的纯文本说明。 */
|
|
38
|
+
export function describePlan(controller, session) {
|
|
39
|
+
const plan = controller.current();
|
|
40
|
+
const mode = session.state.permissionMode;
|
|
41
|
+
const pre = controller.prePlanMode();
|
|
42
|
+
const modeLine = mode === "plan"
|
|
43
|
+
? `模式:Plan(批准后回到 ${permissionModeLabel(executionMode(undefined, pre))})`
|
|
44
|
+
: `模式:${permissionModeLabel(mode)}`;
|
|
45
|
+
if (plan === null) {
|
|
46
|
+
return mode === "plan"
|
|
47
|
+
? [modeLine, "还没有计划:模型给出 <proposed_plan> 后在这里审批"].join("\n")
|
|
48
|
+
: "没有计划。/plan <目标> 进入 Plan 模式";
|
|
49
|
+
}
|
|
50
|
+
const lines = [
|
|
51
|
+
`计划 v${plan.version} · ${planStatusText(plan.status)} · ${planTitle(plan)}`,
|
|
52
|
+
...(plan.filePath !== undefined ? [`文件:${plan.filePath}`] : []),
|
|
53
|
+
modeLine,
|
|
54
|
+
];
|
|
55
|
+
if (plan.steps.length > 0) {
|
|
56
|
+
lines.push(`步骤(${plan.steps.length}):`);
|
|
57
|
+
for (const step of plan.steps)
|
|
58
|
+
lines.push(` ${step.id} ${step.text}`);
|
|
59
|
+
}
|
|
60
|
+
const todos = controller.todos();
|
|
61
|
+
if (todos.length > 0) {
|
|
62
|
+
const done = todos.filter((t) => t.status === "done").length;
|
|
63
|
+
const current = todos.find((t) => t.status === "in_progress");
|
|
64
|
+
lines.push(`待办:${done}/${todos.length} 完成${current !== undefined ? ` · 进行中 ${current.text}` : ""}`);
|
|
65
|
+
}
|
|
66
|
+
if (plan.status === "proposed")
|
|
67
|
+
lines.push("/plan approve [模式|fresh] 批准 · /plan reject 放弃 · 直接输入修改意见");
|
|
68
|
+
return lines.join("\n");
|
|
69
|
+
}
|
|
70
|
+
/** 「新上下文执行」:新建会话、记下计划与 todo、切到执行模式,返回首条消息。 */
|
|
71
|
+
export async function approveFresh(controller, plan, mode, ctx, editedMarkdown) {
|
|
72
|
+
const result = await controller.respond({
|
|
73
|
+
planId: plan.id,
|
|
74
|
+
decision: "approve_fresh",
|
|
75
|
+
mode,
|
|
76
|
+
...(editedMarkdown !== undefined ? { editedMarkdown } : {}),
|
|
77
|
+
});
|
|
78
|
+
const next = await ctx.switchSession({ kind: "new" });
|
|
79
|
+
planController(next)?.adopt(result.plan);
|
|
80
|
+
next.setPermissionMode(result.mode ?? mode);
|
|
81
|
+
return { session: next, prompt: result.freshPrompt ?? result.plan.markdown, plan: result.plan };
|
|
82
|
+
}
|
|
83
|
+
function pendingOrLastReply(controller) {
|
|
84
|
+
const plan = controller.pending() ?? controller.proposeFromLastReply();
|
|
85
|
+
if (plan === undefined)
|
|
86
|
+
throw new AmaError("plan_not_found", "没有待审批的计划");
|
|
87
|
+
return plan;
|
|
88
|
+
}
|
|
89
|
+
export async function planCommand(session, args, ctx) {
|
|
90
|
+
const controller = planController(session);
|
|
91
|
+
const [verb = "", ...rest] = args.split(/\s+/).filter((s) => s !== "");
|
|
92
|
+
if (controller === undefined) {
|
|
93
|
+
if (args === "")
|
|
94
|
+
return { kind: "handled", message: "当前会话没有 Plan 能力" };
|
|
95
|
+
throw new AmaError("invalid_arguments", "当前会话没有 Plan 能力");
|
|
96
|
+
}
|
|
97
|
+
if (verb === "")
|
|
98
|
+
return { kind: "handled", message: describePlan(controller, session) };
|
|
99
|
+
if (verb === "approve") {
|
|
100
|
+
if (rest.length > 1)
|
|
101
|
+
throw new AmaError("invalid_arguments", PLAN_USAGE);
|
|
102
|
+
const plan = pendingOrLastReply(controller);
|
|
103
|
+
const arg = rest[0];
|
|
104
|
+
if (arg === "fresh") {
|
|
105
|
+
const fresh = await approveFresh(controller, plan, defaultExecutionMode(controller), ctx);
|
|
106
|
+
return { kind: "prompt", text: fresh.prompt };
|
|
107
|
+
}
|
|
108
|
+
const mode = arg === undefined ? defaultExecutionMode(controller) : parsePermissionMode(arg);
|
|
109
|
+
if (mode === undefined || mode === "plan")
|
|
110
|
+
throw new AmaError("invalid_arguments", `执行模式无效:${arg ?? ""}(${PLAN_USAGE})`);
|
|
111
|
+
const result = await controller.respond({ planId: plan.id, decision: "approve", mode });
|
|
112
|
+
return {
|
|
113
|
+
kind: "handled",
|
|
114
|
+
message: `已批准计划 v${result.plan.version},以 ${permissionModeLabel(result.mode ?? mode)} 执行`,
|
|
115
|
+
wait: true,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
if (verb === "reject" && rest.length === 0) {
|
|
119
|
+
const plan = controller.pending();
|
|
120
|
+
if (plan === undefined)
|
|
121
|
+
throw new AmaError("plan_not_found", "没有待审批的计划");
|
|
122
|
+
await controller.respond({ planId: plan.id, decision: "reject" });
|
|
123
|
+
return { kind: "handled", message: `已放弃计划 v${plan.version}(仍在 Plan 模式)` };
|
|
124
|
+
}
|
|
125
|
+
// 其余:目标文本
|
|
126
|
+
if (session.state.permissionMode !== "plan")
|
|
127
|
+
session.setPermissionMode("plan");
|
|
128
|
+
return { kind: "prompt", text: args };
|
|
129
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 计划审批对话框(docs/wave5-plan.md §6.1、§6.3):底部覆盖层,与权限审批框同一手法。[W5-U]
|
|
3
|
+
*
|
|
4
|
+
* ```
|
|
5
|
+
* ╭─ 计划待审批 ──────────────────────────────────────────────╮
|
|
6
|
+
* │ 计划 v1 · 3 步 · ~/.local/share/ama/plans/3f2a9c1e-v1.md │
|
|
7
|
+
* │ 给 status-bar 加回退模型显示 │
|
|
8
|
+
* │ S1 读 status-bar.ts 与 status-area.ts │
|
|
9
|
+
* │ … │
|
|
10
|
+
* │ │
|
|
11
|
+
* │ › 1. 批准并执行 │
|
|
12
|
+
* │ 2. 批准,在新上下文执行 │
|
|
13
|
+
* │ 3. 继续修改… │
|
|
14
|
+
* │ 4. 放弃,退出 Plan 模式 │
|
|
15
|
+
* │ │
|
|
16
|
+
* │ ↑↓ 选择 · Enter 确认 · e 编辑计划 · Esc 留在 Plan │
|
|
17
|
+
* ╰───────────────────────────────────────────────────────────╯
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* - 1 / 2 之后选执行模式:回到进入前的模式(缺省)/ Accept edits / Auto;Esc 回到上一步。
|
|
21
|
+
* - 3「继续修改」:行内写意见(Enter 发送,`Ctrl+E` 改用外部编辑器写),意见作为普通用户消息、留在 plan;
|
|
22
|
+
* Esc 回到上一步。
|
|
23
|
+
* - `e`:在外部编辑器(`$VISUAL` / `$EDITOR`,TUI 挂起)里改计划全文;批准时以改后的版本(version + 1)
|
|
24
|
+
* 交接。
|
|
25
|
+
* - 4「放弃」:计划标 rejected 并退出 Plan 模式(回到进入前的模式);Esc:计划标 rejected、留在 Plan 模式
|
|
26
|
+
* (§6.1)。
|
|
27
|
+
* - 宽 < 56 时紧凑:去掉空行、按键提示缩短。ASCII 字形走 theme.glyphs。
|
|
28
|
+
*/
|
|
29
|
+
import type { PlanData } from "../../agent/types.js";
|
|
30
|
+
import type { PermissionMode } from "../../permissions/types.js";
|
|
31
|
+
import { type Component, type Focusable, type Keybindings, type OverlayHandle, type Theme } from "../../tui.js";
|
|
32
|
+
/** 对话框里最多列出的步骤数。 */
|
|
33
|
+
export declare const PLAN_DIALOG_STEPS = 6;
|
|
34
|
+
export type PlanChoice = {
|
|
35
|
+
decision: "approve" | "approve_fresh";
|
|
36
|
+
mode: PermissionMode;
|
|
37
|
+
editedMarkdown?: string;
|
|
38
|
+
} | {
|
|
39
|
+
decision: "revise";
|
|
40
|
+
feedback: string;
|
|
41
|
+
}
|
|
42
|
+
/** `exit`:放弃并退出 Plan 模式(选项 4);Esc 为 false。 */
|
|
43
|
+
| {
|
|
44
|
+
decision: "reject";
|
|
45
|
+
exit: boolean;
|
|
46
|
+
};
|
|
47
|
+
export interface PlanDialogHost {
|
|
48
|
+
theme: Theme;
|
|
49
|
+
keybindings?: Keybindings;
|
|
50
|
+
showOverlay(component: Component): OverlayHandle;
|
|
51
|
+
/** 外部编辑器:返回改后的文本,取消或失败返回 undefined。 */
|
|
52
|
+
editExternal?(text: string, kind: "plan" | "feedback"): Promise<string | undefined>;
|
|
53
|
+
/** 计划文件路径的显示(缩写家目录)。 */
|
|
54
|
+
displayPath?(path: string): string;
|
|
55
|
+
/** 重画(外部编辑器回来之后)。 */
|
|
56
|
+
render?(): void;
|
|
57
|
+
onOpen?(): void;
|
|
58
|
+
onClose?(): void;
|
|
59
|
+
}
|
|
60
|
+
export interface PlanDialogInput {
|
|
61
|
+
plan: PlanData;
|
|
62
|
+
/** 「回到进入前的模式」对应的执行模式。 */
|
|
63
|
+
preMode: PermissionMode;
|
|
64
|
+
}
|
|
65
|
+
export declare class PlanDialog implements Component, Focusable {
|
|
66
|
+
private readonly input;
|
|
67
|
+
private readonly host;
|
|
68
|
+
private readonly done;
|
|
69
|
+
focused: boolean;
|
|
70
|
+
private stage;
|
|
71
|
+
private selected;
|
|
72
|
+
private modeSelected;
|
|
73
|
+
/** 选执行模式时记下的是 1 还是 2。 */
|
|
74
|
+
private fresh;
|
|
75
|
+
private feedback;
|
|
76
|
+
private edited;
|
|
77
|
+
constructor(input: PlanDialogInput, host: PlanDialogHost, done: (choice: PlanChoice) => void);
|
|
78
|
+
private modes;
|
|
79
|
+
handleInput(data: string): void;
|
|
80
|
+
private keys;
|
|
81
|
+
private cancelKey;
|
|
82
|
+
private mainInput;
|
|
83
|
+
private choose;
|
|
84
|
+
private modeInput;
|
|
85
|
+
private approve;
|
|
86
|
+
private reviseInput;
|
|
87
|
+
private editPlan;
|
|
88
|
+
private editFeedback;
|
|
89
|
+
render(width: number): string[];
|
|
90
|
+
/** 版本、步数、文件、标题与前几步。 */
|
|
91
|
+
private summary;
|
|
92
|
+
private optionLines;
|
|
93
|
+
private reviseLines;
|
|
94
|
+
private hint;
|
|
95
|
+
invalidate(): void;
|
|
96
|
+
}
|
|
97
|
+
/** 打开对话框,等用户选择。 */
|
|
98
|
+
export declare function openPlanDialog(host: PlanDialogHost, input: PlanDialogInput): Promise<PlanChoice>;
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 计划审批对话框(docs/wave5-plan.md §6.1、§6.3):底部覆盖层,与权限审批框同一手法。[W5-U]
|
|
3
|
+
*
|
|
4
|
+
* ```
|
|
5
|
+
* ╭─ 计划待审批 ──────────────────────────────────────────────╮
|
|
6
|
+
* │ 计划 v1 · 3 步 · ~/.local/share/ama/plans/3f2a9c1e-v1.md │
|
|
7
|
+
* │ 给 status-bar 加回退模型显示 │
|
|
8
|
+
* │ S1 读 status-bar.ts 与 status-area.ts │
|
|
9
|
+
* │ … │
|
|
10
|
+
* │ │
|
|
11
|
+
* │ › 1. 批准并执行 │
|
|
12
|
+
* │ 2. 批准,在新上下文执行 │
|
|
13
|
+
* │ 3. 继续修改… │
|
|
14
|
+
* │ 4. 放弃,退出 Plan 模式 │
|
|
15
|
+
* │ │
|
|
16
|
+
* │ ↑↓ 选择 · Enter 确认 · e 编辑计划 · Esc 留在 Plan │
|
|
17
|
+
* ╰───────────────────────────────────────────────────────────╯
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* - 1 / 2 之后选执行模式:回到进入前的模式(缺省)/ Accept edits / Auto;Esc 回到上一步。
|
|
21
|
+
* - 3「继续修改」:行内写意见(Enter 发送,`Ctrl+E` 改用外部编辑器写),意见作为普通用户消息、留在 plan;
|
|
22
|
+
* Esc 回到上一步。
|
|
23
|
+
* - `e`:在外部编辑器(`$VISUAL` / `$EDITOR`,TUI 挂起)里改计划全文;批准时以改后的版本(version + 1)
|
|
24
|
+
* 交接。
|
|
25
|
+
* - 4「放弃」:计划标 rejected 并退出 Plan 模式(回到进入前的模式);Esc:计划标 rejected、留在 Plan 模式
|
|
26
|
+
* (§6.1)。
|
|
27
|
+
* - 宽 < 56 时紧凑:去掉空行、按键提示缩短。ASCII 字形走 theme.glyphs。
|
|
28
|
+
*/
|
|
29
|
+
import { permissionModeLabel } from "../../permissions/modes.js";
|
|
30
|
+
import { Box, defaultKeybindings, isPasteData, isPrintableText, matchesKey, padToWidth, truncateToWidth, unwrapPaste, wrapTextWithAnsi, } from "../../tui.js";
|
|
31
|
+
import { planTitle } from "./plan-command.js";
|
|
32
|
+
/** 对话框里最多列出的步骤数。 */
|
|
33
|
+
export const PLAN_DIALOG_STEPS = 6;
|
|
34
|
+
const COMPACT_WIDTH = 56;
|
|
35
|
+
function mainOptions(ellipsis) {
|
|
36
|
+
return ["批准并执行", "批准,在新上下文执行", `继续修改${ellipsis}`, "放弃,退出 Plan 模式"];
|
|
37
|
+
}
|
|
38
|
+
const MAIN_COUNT = 4;
|
|
39
|
+
export class PlanDialog {
|
|
40
|
+
input;
|
|
41
|
+
host;
|
|
42
|
+
done;
|
|
43
|
+
focused = false;
|
|
44
|
+
stage = "main";
|
|
45
|
+
selected = 0;
|
|
46
|
+
modeSelected = 0;
|
|
47
|
+
/** 选执行模式时记下的是 1 还是 2。 */
|
|
48
|
+
fresh = false;
|
|
49
|
+
feedback = "";
|
|
50
|
+
edited;
|
|
51
|
+
constructor(input, host, done) {
|
|
52
|
+
this.input = input;
|
|
53
|
+
this.host = host;
|
|
54
|
+
this.done = done;
|
|
55
|
+
}
|
|
56
|
+
modes() {
|
|
57
|
+
const pre = this.input.preMode;
|
|
58
|
+
return [
|
|
59
|
+
{ mode: pre, label: `回到进入前的模式(${permissionModeLabel(pre)})` },
|
|
60
|
+
{ mode: "auto-edit", label: permissionModeLabel("auto-edit") },
|
|
61
|
+
{ mode: "auto", label: permissionModeLabel("auto") },
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
handleInput(data) {
|
|
65
|
+
switch (this.stage) {
|
|
66
|
+
case "main":
|
|
67
|
+
return this.mainInput(data);
|
|
68
|
+
case "mode":
|
|
69
|
+
return this.modeInput(data);
|
|
70
|
+
case "revise":
|
|
71
|
+
return this.reviseInput(data);
|
|
72
|
+
case "editing":
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
keys() {
|
|
77
|
+
return this.host.keybindings ?? defaultKeybindings;
|
|
78
|
+
}
|
|
79
|
+
cancelKey(data) {
|
|
80
|
+
const keys = this.keys();
|
|
81
|
+
return (matchesKey(data, "escape") ||
|
|
82
|
+
keys.matches(data, "app.clear") ||
|
|
83
|
+
keys.matches(data, "tui.select.cancel"));
|
|
84
|
+
}
|
|
85
|
+
mainInput(data) {
|
|
86
|
+
const keys = this.keys();
|
|
87
|
+
if (this.cancelKey(data))
|
|
88
|
+
return this.done({ decision: "reject", exit: false });
|
|
89
|
+
if (/^[1-4]$/.test(data))
|
|
90
|
+
return this.choose(Number(data) - 1);
|
|
91
|
+
if (keys.matches(data, "tui.select.up"))
|
|
92
|
+
this.selected = (this.selected + MAIN_COUNT - 1) % MAIN_COUNT;
|
|
93
|
+
else if (keys.matches(data, "tui.select.down"))
|
|
94
|
+
this.selected = (this.selected + 1) % MAIN_COUNT;
|
|
95
|
+
else if (matchesKey(data, "enter"))
|
|
96
|
+
this.choose(this.selected);
|
|
97
|
+
else if (data === "e" || data === "E")
|
|
98
|
+
void this.editPlan();
|
|
99
|
+
}
|
|
100
|
+
choose(index) {
|
|
101
|
+
this.selected = index;
|
|
102
|
+
if (index === 0 || index === 1) {
|
|
103
|
+
this.fresh = index === 1;
|
|
104
|
+
this.modeSelected = 0;
|
|
105
|
+
this.stage = "mode";
|
|
106
|
+
}
|
|
107
|
+
else if (index === 2) {
|
|
108
|
+
this.stage = "revise";
|
|
109
|
+
}
|
|
110
|
+
else
|
|
111
|
+
this.done({ decision: "reject", exit: true });
|
|
112
|
+
}
|
|
113
|
+
modeInput(data) {
|
|
114
|
+
const keys = this.keys();
|
|
115
|
+
const modes = this.modes();
|
|
116
|
+
if (this.cancelKey(data)) {
|
|
117
|
+
this.stage = "main";
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (/^[1-3]$/.test(data))
|
|
121
|
+
return this.approve(modes[Number(data) - 1].mode);
|
|
122
|
+
if (keys.matches(data, "tui.select.up"))
|
|
123
|
+
this.modeSelected = (this.modeSelected + modes.length - 1) % modes.length;
|
|
124
|
+
else if (keys.matches(data, "tui.select.down"))
|
|
125
|
+
this.modeSelected = (this.modeSelected + 1) % modes.length;
|
|
126
|
+
else if (matchesKey(data, "enter"))
|
|
127
|
+
this.approve(modes[this.modeSelected].mode);
|
|
128
|
+
}
|
|
129
|
+
approve(mode) {
|
|
130
|
+
this.done({
|
|
131
|
+
decision: this.fresh ? "approve_fresh" : "approve",
|
|
132
|
+
mode,
|
|
133
|
+
...(this.edited !== undefined ? { editedMarkdown: this.edited } : {}),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
reviseInput(data) {
|
|
137
|
+
if (this.cancelKey(data)) {
|
|
138
|
+
this.stage = "main";
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (matchesKey(data, "enter")) {
|
|
142
|
+
if (this.feedback.trim() !== "")
|
|
143
|
+
this.done({ decision: "revise", feedback: this.feedback });
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (matchesKey(data, "ctrl+e"))
|
|
147
|
+
return void this.editFeedback();
|
|
148
|
+
if (matchesKey(data, "backspace")) {
|
|
149
|
+
this.feedback = [...this.feedback].slice(0, -1).join("");
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (isPasteData(data)) {
|
|
153
|
+
this.feedback += unwrapPaste(data).replace(/\r\n?/g, "\n");
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (isPrintableText(data))
|
|
157
|
+
this.feedback += data;
|
|
158
|
+
}
|
|
159
|
+
async editPlan() {
|
|
160
|
+
if (this.host.editExternal === undefined)
|
|
161
|
+
return;
|
|
162
|
+
this.stage = "editing";
|
|
163
|
+
const before = this.edited ?? this.input.plan.markdown;
|
|
164
|
+
const after = await this.host.editExternal(before, "plan").catch(() => undefined);
|
|
165
|
+
if (after !== undefined && after.trim() !== "" && after !== this.input.plan.markdown)
|
|
166
|
+
this.edited = after;
|
|
167
|
+
this.stage = "main";
|
|
168
|
+
this.host.render?.();
|
|
169
|
+
}
|
|
170
|
+
async editFeedback() {
|
|
171
|
+
if (this.host.editExternal === undefined)
|
|
172
|
+
return;
|
|
173
|
+
this.stage = "editing";
|
|
174
|
+
const after = await this.host.editExternal(this.feedback, "feedback").catch(() => undefined);
|
|
175
|
+
this.stage = "revise";
|
|
176
|
+
if (after !== undefined && after.trim() !== "") {
|
|
177
|
+
this.done({ decision: "revise", feedback: after.trim() });
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
this.host.render?.();
|
|
181
|
+
}
|
|
182
|
+
render(width) {
|
|
183
|
+
const compact = width + 4 < COMPACT_WIDTH;
|
|
184
|
+
const lines = [];
|
|
185
|
+
const push = (line) => void lines.push(...wrapTextWithAnsi(line, width));
|
|
186
|
+
const blank = () => {
|
|
187
|
+
if (!compact)
|
|
188
|
+
lines.push("");
|
|
189
|
+
};
|
|
190
|
+
// 摘要(版本、标题、步骤)窄屏截断不折行:续行顶格会和步骤编号对不齐
|
|
191
|
+
lines.push(...this.summary());
|
|
192
|
+
blank();
|
|
193
|
+
switch (this.stage) {
|
|
194
|
+
case "main":
|
|
195
|
+
lines.push(...this.optionLines(mainOptions(this.host.theme.glyphs.ellipsis), this.selected, width));
|
|
196
|
+
break;
|
|
197
|
+
case "mode":
|
|
198
|
+
push(this.host.theme.bold(this.fresh ? "在新上下文执行,执行模式" : "执行模式"));
|
|
199
|
+
lines.push(...this.optionLines(this.modes().map((m) => m.label), this.modeSelected, width));
|
|
200
|
+
break;
|
|
201
|
+
case "revise":
|
|
202
|
+
lines.push(...this.reviseLines(width, compact));
|
|
203
|
+
break;
|
|
204
|
+
case "editing":
|
|
205
|
+
push(this.host.theme.fg("dim", `正在外部编辑器里编辑${this.host.theme.glyphs.ellipsis}`));
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
blank();
|
|
209
|
+
lines.push(this.host.theme.fg("dim", this.hint(compact)));
|
|
210
|
+
return lines.map((line) => truncateToWidth(line, width));
|
|
211
|
+
}
|
|
212
|
+
/** 版本、步数、文件、标题与前几步。 */
|
|
213
|
+
summary() {
|
|
214
|
+
const { theme } = this.host;
|
|
215
|
+
const plan = this.input.plan;
|
|
216
|
+
const sep = theme.fg("dim", " · ");
|
|
217
|
+
const head = [`计划 v${plan.version}`, `${plan.steps.length} 步`];
|
|
218
|
+
if (plan.filePath !== undefined)
|
|
219
|
+
head.push(this.host.displayPath?.(plan.filePath) ?? plan.filePath);
|
|
220
|
+
const out = [theme.fg("muted", head.join(sep))];
|
|
221
|
+
out.push(theme.bold(planTitle({ markdown: this.edited ?? plan.markdown })));
|
|
222
|
+
if (this.edited !== undefined) {
|
|
223
|
+
out.push(theme.fg("warning", "已在编辑器里修改:批准时以修改后的计划执行"));
|
|
224
|
+
return out;
|
|
225
|
+
}
|
|
226
|
+
for (const step of plan.steps.slice(0, PLAN_DIALOG_STEPS))
|
|
227
|
+
out.push(` ${theme.fg("dim", step.id)} ${step.text}`);
|
|
228
|
+
const hidden = plan.steps.length - PLAN_DIALOG_STEPS;
|
|
229
|
+
if (hidden > 0)
|
|
230
|
+
out.push(theme.fg("dim", ` ${theme.glyphs.ellipsis} 另 ${hidden} 步(/plan 查看全部)`));
|
|
231
|
+
return out;
|
|
232
|
+
}
|
|
233
|
+
optionLines(labels, selected, width) {
|
|
234
|
+
const { theme } = this.host;
|
|
235
|
+
const g = theme.glyphs;
|
|
236
|
+
return labels.map((label, i) => {
|
|
237
|
+
const on = i === selected;
|
|
238
|
+
const text = `${on ? g.prompt : " "} ${i + 1}. ${label}`;
|
|
239
|
+
const line = padToWidth(truncateToWidth(on ? theme.fg("accent", theme.bold(text)) : text, width), width);
|
|
240
|
+
return on ? theme.bg("selection", line) : line;
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
reviseLines(width, compact) {
|
|
244
|
+
const { theme } = this.host;
|
|
245
|
+
const g = theme.glyphs;
|
|
246
|
+
const out = [theme.bold(compact ? "修改意见" : "修改意见(留在 Plan 模式,模型据此重写计划)")];
|
|
247
|
+
const cursor = "\x1b[7m \x1b[27m";
|
|
248
|
+
const text = this.feedback.replace(/\n/g, " ⏎ ");
|
|
249
|
+
const body = `${theme.fg("user", g.prompt)} ${text}${cursor}`;
|
|
250
|
+
out.push(...wrapTextWithAnsi(body, width));
|
|
251
|
+
return out;
|
|
252
|
+
}
|
|
253
|
+
hint(compact) {
|
|
254
|
+
const g = this.host.theme.glyphs;
|
|
255
|
+
const arrows = g.arrowUp + g.arrowDown;
|
|
256
|
+
const edit = this.host.editExternal !== undefined;
|
|
257
|
+
switch (this.stage) {
|
|
258
|
+
case "main":
|
|
259
|
+
return compact
|
|
260
|
+
? `${arrows} Enter${edit ? " · e 编辑" : ""} · Esc 留在 Plan`
|
|
261
|
+
: `${arrows} 选择 · Enter 确认${edit ? " · e 编辑计划" : ""} · Esc 留在 Plan`;
|
|
262
|
+
case "mode":
|
|
263
|
+
return compact ? `${arrows} Enter · Esc 返回` : `${arrows} 选择 · Enter 确认 · Esc 返回`;
|
|
264
|
+
case "revise":
|
|
265
|
+
return compact
|
|
266
|
+
? `Enter 发送${edit ? " · Ctrl+E 编辑器" : ""} · Esc 返回`
|
|
267
|
+
: `Enter 发送${edit ? " · Ctrl+E 外部编辑器" : ""} · Esc 返回`;
|
|
268
|
+
case "editing":
|
|
269
|
+
return "保存并关闭编辑器后回到这里";
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
invalidate() { }
|
|
273
|
+
}
|
|
274
|
+
/** 打开对话框,等用户选择。 */
|
|
275
|
+
export function openPlanDialog(host, input) {
|
|
276
|
+
return new Promise((resolve) => {
|
|
277
|
+
let handle;
|
|
278
|
+
let settled = false;
|
|
279
|
+
const dialog = new PlanDialog(input, host, (choice) => {
|
|
280
|
+
if (settled)
|
|
281
|
+
return;
|
|
282
|
+
settled = true;
|
|
283
|
+
handle?.hide();
|
|
284
|
+
host.onClose?.();
|
|
285
|
+
resolve(choice);
|
|
286
|
+
});
|
|
287
|
+
host.onOpen?.();
|
|
288
|
+
handle = host.showOverlay(new Box(dialog, { title: "计划待审批", theme: host.theme }));
|
|
289
|
+
});
|
|
290
|
+
}
|