@armadra/agent 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +184 -1
- package/README.md +202 -83
- package/THIRD_PARTY_NOTICES.md +34 -0
- package/dist/acp.d.ts +18 -0
- package/dist/acp.js +19 -0
- package/dist/agent/limits.d.ts +38 -0
- package/dist/agent/limits.js +127 -0
- package/dist/agent/loop-guard.d.ts +38 -0
- package/dist/agent/loop-guard.js +95 -0
- package/dist/agent/loop.d.ts +4 -0
- package/dist/agent/loop.js +7 -0
- package/dist/agent/prompt-rules.d.ts +12 -0
- package/dist/agent/prompt-rules.js +18 -0
- package/dist/agent/reminders.d.ts +59 -0
- package/dist/agent/reminders.js +327 -0
- package/dist/agent/session-cache.d.ts +5 -0
- package/dist/agent/session-cache.js +17 -1
- package/dist/agent/session-classifier.d.ts +1 -1
- package/dist/agent/session-classifier.js +3 -1
- package/dist/agent/session-compaction.d.ts +35 -6
- package/dist/agent/session-compaction.js +157 -31
- package/dist/agent/session-core.d.ts +27 -1
- package/dist/agent/session-extensions.d.ts +61 -0
- package/dist/agent/session-extensions.js +129 -0
- package/dist/agent/session-images.d.ts +23 -0
- package/dist/agent/session-images.js +97 -0
- package/dist/agent/session-plan.d.ts +21 -0
- package/dist/agent/session-plan.js +524 -0
- package/dist/agent/session-rewind.d.ts +81 -0
- package/dist/agent/session-rewind.js +354 -0
- package/dist/agent/session-run.d.ts +28 -1
- package/dist/agent/session-run.js +157 -6
- package/dist/agent/session-settings.d.ts +49 -0
- package/dist/agent/session-settings.js +95 -0
- package/dist/agent/session-subagent.d.ts +36 -24
- package/dist/agent/session-subagent.js +259 -129
- package/dist/agent/session-sync.d.ts +10 -3
- package/dist/agent/session-sync.js +37 -8
- package/dist/agent/session-telemetry.d.ts +39 -0
- package/dist/agent/session-telemetry.js +231 -0
- package/dist/agent/session-tools.js +40 -1
- package/dist/agent/session.d.ts +30 -29
- package/dist/agent/session.js +79 -123
- package/dist/agent/subagent-registry.d.ts +91 -0
- package/dist/agent/subagent-registry.js +494 -0
- package/dist/agent/system-prompt.d.ts +6 -3
- package/dist/agent/system-prompt.js +7 -2
- package/dist/agent/tool-runner.d.ts +8 -1
- package/dist/agent/tool-runner.js +57 -4
- package/dist/agent/types-w5.d.ts +192 -0
- package/dist/agent/types-w5.js +10 -0
- package/dist/agent/types.d.ts +47 -4
- package/dist/agent/types.js +2 -0
- package/dist/agent/worktree.d.ts +36 -0
- package/dist/agent/worktree.js +86 -0
- package/dist/agents/builtin.d.ts +14 -0
- package/dist/agents/builtin.js +39 -0
- package/dist/agents/catalog.d.ts +43 -0
- package/dist/agents/catalog.js +82 -0
- package/dist/agents/discover.d.ts +35 -0
- package/dist/agents/discover.js +83 -0
- package/dist/agents/external.d.ts +82 -0
- package/dist/agents/external.js +326 -0
- package/dist/agents/parse.d.ts +18 -0
- package/dist/agents/parse.js +116 -0
- package/dist/agents/result.d.ts +32 -0
- package/dist/agents/result.js +67 -0
- package/dist/agents/task-control.d.ts +17 -0
- package/dist/agents/task-control.js +17 -0
- package/dist/agents/task-record.d.ts +78 -0
- package/dist/agents/task-record.js +141 -0
- package/dist/agents/types.d.ts +46 -0
- package/dist/agents/types.js +8 -0
- package/dist/ai/apis/anthropic-compat.d.ts +36 -0
- package/dist/ai/apis/anthropic-compat.js +92 -0
- package/dist/ai/apis/anthropic-request.d.ts +7 -6
- package/dist/ai/apis/anthropic-request.js +10 -28
- package/dist/ai/apis/cache-params.d.ts +11 -2
- package/dist/ai/apis/cache-params.js +25 -6
- package/dist/ai/apis/openai-compat.d.ts +4 -1
- package/dist/ai/apis/openai-compat.js +8 -1
- package/dist/ai/image-limits.d.ts +45 -0
- package/dist/ai/image-limits.js +68 -0
- package/dist/ai/providers/builtin.d.ts +18 -6
- package/dist/ai/providers/builtin.js +135 -6
- package/dist/ai/providers/catalog-data.js +17 -13
- package/dist/ai/providers/catalog.d.ts +60 -7
- package/dist/ai/providers/catalog.js +197 -38
- package/dist/ai/providers/channels.d.ts +33 -3
- package/dist/ai/providers/channels.js +108 -7
- package/dist/ai/providers/enrich.d.ts +6 -3
- package/dist/ai/providers/enrich.js +19 -4
- package/dist/ai/providers/models-dev-cache.d.ts +28 -24
- package/dist/ai/providers/models-dev-cache.js +92 -78
- package/dist/ai/providers/models-dev-data.d.ts +7 -0
- package/dist/ai/providers/models-dev-data.js +32 -0
- package/dist/ai/providers/models-dev-snapshot.d.ts +50 -0
- package/dist/ai/providers/models-dev-snapshot.js +137 -0
- package/dist/ai/providers/models-dev.d.ts +51 -10
- package/dist/ai/providers/models-dev.js +132 -39
- package/dist/ai/providers/registry.d.ts +20 -10
- package/dist/ai/providers/registry.js +82 -43
- package/dist/ai/types.d.ts +28 -2
- package/dist/ai/types.js +5 -0
- package/dist/bundle/ama.cjs +37605 -21619
- package/dist/checkpoints/backend.d.ts +61 -0
- package/dist/checkpoints/backend.js +135 -0
- package/dist/checkpoints/blobs.d.ts +60 -0
- package/dist/checkpoints/blobs.js +203 -0
- package/dist/checkpoints/gc.d.ts +47 -0
- package/dist/checkpoints/gc.js +144 -0
- package/dist/checkpoints/git-head.d.ts +15 -0
- package/dist/checkpoints/git-head.js +89 -0
- package/dist/checkpoints/index.d.ts +17 -0
- package/dist/checkpoints/index.js +17 -0
- package/dist/checkpoints/replay.d.ts +48 -0
- package/dist/checkpoints/replay.js +154 -0
- package/dist/checkpoints/restore.d.ts +86 -0
- package/dist/checkpoints/restore.js +263 -0
- package/dist/checkpoints/settings.d.ts +14 -0
- package/dist/checkpoints/settings.js +23 -0
- package/dist/checkpoints/shadow-git.d.ts +108 -0
- package/dist/checkpoints/shadow-git.js +491 -0
- package/dist/checkpoints/shadow-restore.d.ts +25 -0
- package/dist/checkpoints/shadow-restore.js +128 -0
- package/dist/checkpoints/tracker.d.ts +64 -0
- package/dist/checkpoints/tracker.js +192 -0
- package/dist/checkpoints/types.d.ts +99 -0
- package/dist/checkpoints/types.js +12 -0
- package/dist/cli/args.d.ts +8 -4
- package/dist/cli/args.js +17 -97
- package/dist/cli/bootstrap.js +13 -1
- package/dist/cli/choice-prompt.d.ts +58 -0
- package/dist/cli/choice-prompt.js +140 -0
- package/dist/cli/codemode-notice.d.ts +3 -2
- package/dist/cli/codemode-notice.js +3 -2
- package/dist/cli/compose-agents.d.ts +27 -0
- package/dist/cli/compose-agents.js +111 -0
- package/dist/cli/compose-extensions.d.ts +29 -0
- package/dist/cli/compose-extensions.js +44 -0
- package/dist/cli/compose-session.d.ts +3 -0
- package/dist/cli/compose-session.js +47 -4
- package/dist/cli/compose.d.ts +3 -0
- package/dist/cli/compose.js +33 -6
- package/dist/cli/deps.d.ts +6 -0
- package/dist/cli/exit-codes.d.ts +10 -0
- package/dist/cli/exit-codes.js +12 -0
- package/dist/cli/help-text.d.ts +4 -0
- package/dist/cli/help-text.js +102 -0
- package/dist/cli/startup-screen.js +5 -3
- package/dist/cli/startup-steps.js +7 -1
- package/dist/cli/subcommands/config.d.ts +4 -1
- package/dist/cli/subcommands/config.js +17 -6
- package/dist/cli/subcommands/doctor.js +21 -0
- package/dist/cli/subcommands/models-cache-probe.d.ts +1 -1
- package/dist/cli/subcommands/models-cache-probe.js +3 -12
- package/dist/cli/subcommands/models-discover.js +5 -6
- package/dist/cli/subcommands/models.d.ts +2 -0
- package/dist/cli/subcommands/models.js +33 -14
- package/dist/cli/subcommands/providers.d.ts +1 -1
- package/dist/cli/subcommands/providers.js +8 -15
- package/dist/cli/subcommands/sessions.d.ts +3 -1
- package/dist/cli/subcommands/sessions.js +36 -2
- package/dist/codemode/capability.d.ts +24 -7
- package/dist/codemode/capability.js +38 -10
- package/dist/codemode/host-side.d.ts +14 -0
- package/dist/codemode/host-side.js +24 -1
- package/dist/codemode/tool.d.ts +1 -1
- package/dist/codemode/tool.js +6 -4
- package/dist/compaction/breaker.d.ts +25 -9
- package/dist/compaction/breaker.js +47 -17
- package/dist/compaction/estimate.d.ts +11 -3
- package/dist/compaction/estimate.js +64 -22
- package/dist/compaction/image-budget.d.ts +45 -0
- package/dist/compaction/image-budget.js +115 -0
- package/dist/compaction/post-compact.d.ts +38 -0
- package/dist/compaction/post-compact.js +152 -0
- package/dist/compaction/protect.d.ts +27 -0
- package/dist/compaction/protect.js +56 -0
- package/dist/compaction/prune-tier.d.ts +58 -12
- package/dist/compaction/prune-tier.js +120 -54
- package/dist/compaction/summarize-tier.d.ts +23 -4
- package/dist/compaction/summarize-tier.js +100 -29
- package/dist/config/checker.d.ts +28 -0
- package/dist/config/checker.js +97 -0
- package/dist/config/json-schema.js +63 -2
- package/dist/config/key-docs.js +72 -3
- package/dist/config/merge.d.ts +5 -3
- package/dist/config/merge.js +81 -7
- package/dist/config/profile.d.ts +2 -0
- package/dist/config/profile.js +2 -0
- package/dist/config/schema-w5.d.ts +18 -0
- package/dist/config/schema-w5.js +109 -0
- package/dist/config/schema.d.ts +5 -9
- package/dist/config/schema.js +68 -114
- package/dist/config/types-w5.d.ts +118 -0
- package/dist/config/types-w5.js +20 -0
- package/dist/config/types.d.ts +50 -1
- package/dist/config/types.js +12 -0
- package/dist/drivers/acp/client.d.ts +57 -0
- package/dist/drivers/acp/client.js +160 -0
- package/dist/drivers/acp/driver.d.ts +31 -0
- package/dist/drivers/acp/driver.js +274 -0
- package/dist/drivers/acp/testing/fake-agent-main.d.ts +5 -0
- package/dist/drivers/acp/testing/fake-agent-main.js +7 -0
- package/dist/drivers/acp/testing/fake-agent.d.ts +27 -0
- package/dist/drivers/acp/testing/fake-agent.js +211 -0
- package/dist/drivers/acp/types.d.ts +285 -0
- package/dist/drivers/acp/types.js +36 -0
- package/dist/drivers/agents.d.ts +58 -0
- package/dist/drivers/agents.js +142 -0
- package/dist/drivers/base.d.ts +35 -0
- package/dist/drivers/base.js +59 -0
- package/dist/drivers/catalog.d.ts +46 -0
- package/dist/drivers/catalog.js +167 -0
- package/dist/drivers/env.d.ts +20 -0
- package/dist/drivers/env.js +46 -0
- package/dist/drivers/host-runners.d.ts +18 -0
- package/dist/drivers/host-runners.js +45 -0
- package/dist/drivers/jsonrpc.d.ts +58 -0
- package/dist/drivers/jsonrpc.js +180 -0
- package/dist/drivers/native/claude-normalize.d.ts +46 -0
- package/dist/drivers/native/claude-normalize.js +106 -0
- package/dist/drivers/native/claude-stream.d.ts +29 -0
- package/dist/drivers/native/claude-stream.js +456 -0
- package/dist/drivers/native/codex-app-server.d.ts +26 -0
- package/dist/drivers/native/codex-app-server.js +407 -0
- package/dist/drivers/native/codex-normalize.d.ts +38 -0
- package/dist/drivers/native/codex-normalize.js +124 -0
- package/dist/drivers/native/oneshot.d.ts +28 -0
- package/dist/drivers/native/oneshot.js +312 -0
- package/dist/drivers/permissions.d.ts +40 -0
- package/dist/drivers/permissions.js +92 -0
- package/dist/drivers/pids.d.ts +32 -0
- package/dist/drivers/pids.js +93 -0
- package/dist/drivers/pool.d.ts +28 -0
- package/dist/drivers/pool.js +96 -0
- package/dist/drivers/probe.d.ts +47 -0
- package/dist/drivers/probe.js +172 -0
- package/dist/drivers/process.d.ts +48 -0
- package/dist/drivers/process.js +100 -0
- package/dist/drivers/runner.d.ts +61 -0
- package/dist/drivers/runner.js +388 -0
- package/dist/drivers/store.d.ts +49 -0
- package/dist/drivers/store.js +91 -0
- package/dist/drivers/turn.d.ts +41 -0
- package/dist/drivers/turn.js +99 -0
- package/dist/drivers/types.d.ts +122 -0
- package/dist/drivers/types.js +11 -0
- package/dist/git/info.d.ts +75 -0
- package/dist/git/info.js +191 -0
- package/dist/hooks/protocol.js +6 -1
- package/dist/hooks/types.d.ts +10 -1
- package/dist/hooks/types.js +2 -0
- package/dist/host/api-impl.d.ts +7 -0
- package/dist/host/api-impl.js +15 -0
- package/dist/host/types.d.ts +24 -2
- package/dist/host/types.js +4 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -0
- package/dist/modes/acp/acp-events.d.ts +46 -0
- package/dist/modes/acp/acp-events.js +233 -0
- package/dist/modes/acp/acp-mode.d.ts +17 -0
- package/dist/modes/acp/acp-mode.js +47 -0
- package/dist/modes/acp/acp-server.d.ts +79 -0
- package/dist/modes/acp/acp-server.js +315 -0
- package/dist/modes/commands-core.d.ts +13 -1
- package/dist/modes/commands-core.js +64 -0
- package/dist/modes/image-input.d.ts +12 -4
- package/dist/modes/image-input.js +22 -5
- package/dist/modes/interactive/agent-panels.d.ts +14 -0
- package/dist/modes/interactive/agent-panels.js +103 -0
- package/dist/modes/interactive/agent-ui.d.ts +73 -0
- package/dist/modes/interactive/agent-ui.js +234 -0
- package/dist/modes/interactive/approval-dialog.d.ts +21 -4
- package/dist/modes/interactive/approval-dialog.js +98 -20
- package/dist/modes/interactive/approval-merge.d.ts +41 -0
- package/dist/modes/interactive/approval-merge.js +89 -0
- package/dist/modes/interactive/clipboard-paste.d.ts +18 -0
- package/dist/modes/interactive/clipboard-paste.js +28 -0
- package/dist/modes/interactive/commands.d.ts +12 -1
- package/dist/modes/interactive/commands.js +31 -1
- package/dist/modes/interactive/confirm-dialog.d.ts +49 -0
- package/dist/modes/interactive/confirm-dialog.js +121 -0
- package/dist/modes/interactive/double-esc.d.ts +20 -0
- package/dist/modes/interactive/double-esc.js +34 -0
- package/dist/modes/interactive/event-notices.d.ts +32 -0
- package/dist/modes/interactive/event-notices.js +79 -0
- package/dist/modes/interactive/external-editor.d.ts +16 -0
- package/dist/modes/interactive/external-editor.js +39 -0
- package/dist/modes/interactive/interactive-mode.d.ts +14 -1
- package/dist/modes/interactive/interactive-mode.js +140 -136
- package/dist/modes/interactive/key-dispatch.d.ts +22 -2
- package/dist/modes/interactive/key-dispatch.js +66 -7
- package/dist/modes/interactive/line/line-mode.d.ts +4 -1
- package/dist/modes/interactive/line/line-mode.js +31 -5
- package/dist/modes/interactive/line/line-render.d.ts +2 -1
- package/dist/modes/interactive/line/line-render.js +40 -4
- package/dist/modes/interactive/message-view.d.ts +1 -1
- package/dist/modes/interactive/message-view.js +24 -2
- package/dist/modes/interactive/panels.d.ts +18 -1
- package/dist/modes/interactive/panels.js +19 -5
- package/dist/modes/interactive/plan-command.d.ts +40 -0
- package/dist/modes/interactive/plan-command.js +129 -0
- package/dist/modes/interactive/plan-dialog.d.ts +98 -0
- package/dist/modes/interactive/plan-dialog.js +290 -0
- package/dist/modes/interactive/plan-flow.d.ts +34 -0
- package/dist/modes/interactive/plan-flow.js +98 -0
- package/dist/modes/interactive/rewind-command.d.ts +31 -0
- package/dist/modes/interactive/rewind-command.js +106 -0
- package/dist/modes/interactive/rewind-flow.d.ts +37 -0
- package/dist/modes/interactive/rewind-flow.js +151 -0
- package/dist/modes/interactive/rewind-list.d.ts +36 -0
- package/dist/modes/interactive/rewind-list.js +123 -0
- package/dist/modes/interactive/rewind-panel.d.ts +77 -0
- package/dist/modes/interactive/rewind-panel.js +309 -0
- package/dist/modes/interactive/rewind-text.d.ts +40 -0
- package/dist/modes/interactive/rewind-text.js +139 -0
- package/dist/modes/interactive/session-events.d.ts +24 -0
- package/dist/modes/interactive/session-events.js +96 -0
- package/dist/modes/interactive/startup-ui.js +5 -1
- package/dist/modes/interactive/status-area.d.ts +73 -0
- package/dist/modes/interactive/status-area.js +190 -0
- package/dist/modes/interactive/status-bar.d.ts +99 -11
- package/dist/modes/interactive/status-bar.js +273 -90
- package/dist/modes/interactive/status-line.d.ts +33 -0
- package/dist/modes/interactive/status-line.js +113 -0
- package/dist/modes/interactive/subagent-view.d.ts +56 -0
- package/dist/modes/interactive/subagent-view.js +154 -0
- package/dist/modes/interactive/tasks-report.d.ts +27 -0
- package/dist/modes/interactive/tasks-report.js +114 -0
- package/dist/modes/interactive/tool-view.d.ts +12 -2
- package/dist/modes/interactive/tool-view.js +34 -4
- package/dist/modes/print/print-mode.d.ts +13 -4
- package/dist/modes/print/print-mode.js +56 -12
- package/dist/modes/rpc/commands.d.ts +9 -0
- package/dist/modes/rpc/commands.js +44 -0
- package/dist/modes/rpc/rpc-mode.js +7 -1
- package/dist/modes/session-report.d.ts +11 -0
- package/dist/modes/session-report.js +48 -1
- package/dist/permissions/auto-safe.d.ts +5 -0
- package/dist/permissions/auto-safe.js +18 -0
- package/dist/permissions/bypass.d.ts +32 -0
- package/dist/permissions/bypass.js +36 -0
- package/dist/permissions/classifier.d.ts +4 -0
- package/dist/permissions/classifier.js +2 -0
- package/dist/permissions/modes.js +1 -1
- package/dist/permissions/pipeline.d.ts +43 -4
- package/dist/permissions/pipeline.js +114 -9
- package/dist/permissions/readonly-bash.d.ts +30 -0
- package/dist/permissions/readonly-bash.js +118 -0
- package/dist/permissions/types.d.ts +42 -0
- package/dist/plan/compose.d.ts +9 -0
- package/dist/plan/compose.js +19 -0
- package/dist/plan/controller.d.ts +71 -0
- package/dist/plan/controller.js +27 -0
- package/dist/plan/done-markers.d.ts +17 -0
- package/dist/plan/done-markers.js +51 -0
- package/dist/plan/extract.d.ts +29 -0
- package/dist/plan/extract.js +160 -0
- package/dist/plan/prompts.d.ts +36 -0
- package/dist/plan/prompts.js +89 -0
- package/dist/plan/store.d.ts +37 -0
- package/dist/plan/store.js +90 -0
- package/dist/rpc.d.ts +58 -2
- package/dist/rpc.js +7 -0
- package/dist/sandbox/bash.d.ts +74 -0
- package/dist/sandbox/bash.js +126 -0
- package/dist/sandbox/detect.d.ts +48 -0
- package/dist/sandbox/detect.js +149 -0
- package/dist/sandbox/index.d.ts +5 -0
- package/dist/sandbox/index.js +5 -0
- package/dist/sandbox/profile.d.ts +33 -0
- package/dist/sandbox/profile.js +76 -0
- package/dist/sandbox/wrap.d.ts +29 -0
- package/dist/sandbox/wrap.js +117 -0
- package/dist/sdk.d.ts +33 -2
- package/dist/sdk.js +24 -2
- package/dist/session/types.d.ts +3 -1
- package/dist/session/types.js +1 -0
- package/dist/skills/builtin.d.ts +31 -0
- package/dist/skills/builtin.js +109 -0
- package/dist/skills/discover.d.ts +2 -1
- package/dist/skills/index-prompt.js +5 -8
- package/dist/tools/background-jobs.d.ts +71 -0
- package/dist/tools/background-jobs.js +198 -0
- package/dist/tools/bash.d.ts +53 -1
- package/dist/tools/bash.js +158 -7
- package/dist/tools/clipboard-image.d.ts +44 -0
- package/dist/tools/clipboard-image.js +148 -0
- package/dist/tools/edit.d.ts +2 -0
- package/dist/tools/edit.js +18 -3
- package/dist/tools/image-file.d.ts +38 -3
- package/dist/tools/image-file.js +81 -10
- package/dist/tools/image-resize.d.ts +58 -0
- package/dist/tools/image-resize.js +97 -0
- package/dist/tools/presets.d.ts +7 -2
- package/dist/tools/presets.js +11 -4
- package/dist/tools/read.d.ts +5 -2
- package/dist/tools/read.js +13 -10
- package/dist/tools/registry.d.ts +7 -1
- package/dist/tools/registry.js +27 -4
- package/dist/tools/task-ctl.d.ts +22 -0
- package/dist/tools/task-ctl.js +116 -0
- package/dist/tools/task.d.ts +22 -10
- package/dist/tools/task.js +66 -26
- package/dist/tools/todo.d.ts +22 -2
- package/dist/tools/todo.js +58 -14
- package/dist/tools/truncate.d.ts +15 -0
- package/dist/tools/truncate.js +25 -0
- package/dist/tools/types.d.ts +113 -0
- package/dist/tools/types.js +5 -0
- package/dist/tools/write.js +3 -0
- package/dist/tui/glyphs.d.ts +4 -0
- package/dist/tui/glyphs.js +4 -0
- package/dist/tui/keybindings.d.ts +6 -1
- package/dist/tui/keybindings.js +6 -1
- package/docs/acp.md +78 -0
- package/docs/agents.md +250 -0
- package/docs/codemode.md +12 -8
- package/docs/hooks.md +26 -22
- package/docs/permissions.md +78 -13
- package/docs/plan.md +107 -0
- package/docs/providers.md +228 -52
- package/docs/rewind-plan.md +181 -0
- package/docs/rpc.md +92 -5
- package/docs/sandbox.md +215 -0
- package/docs/session-format.md +41 -21
- package/docs/sessions.md +41 -1
- package/docs/tui-design.md +751 -0
- package/docs/tui.md +179 -21
- package/package.json +13 -2
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 外部编辑器(计划审批框的「编辑计划」与「继续修改」):`$VISUAL` → `$EDITOR` → `vi`(Windows `notepad`)。
|
|
3
|
+
* [W5-U] 编辑期间 TUI 挂起(交还终端),回来后整屏重画。临时文件在系统临时目录,读完即删。
|
|
4
|
+
*/
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { tmpdir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
export function editorCommand(env, platform = process.platform) {
|
|
10
|
+
const configured = env["VISUAL"]?.trim() || env["EDITOR"]?.trim();
|
|
11
|
+
if (configured !== undefined && configured !== "")
|
|
12
|
+
return configured;
|
|
13
|
+
return platform === "win32" ? "notepad" : "vi";
|
|
14
|
+
}
|
|
15
|
+
function runEditor(command, file) {
|
|
16
|
+
// 编辑器变量常带参数(`code --wait`),交给 shell 拆;路径加引号
|
|
17
|
+
const result = spawnSync(`${command} "${file}"`, { stdio: "inherit", shell: true });
|
|
18
|
+
return result.status;
|
|
19
|
+
}
|
|
20
|
+
/** 在外部编辑器里改 `text`;编辑器非零退出或读不回来返回 undefined。 */
|
|
21
|
+
export async function editExternally(text, name, deps) {
|
|
22
|
+
const dir = mkdtempSync(join(tmpdir(), "ama-edit-"));
|
|
23
|
+
const file = join(dir, name);
|
|
24
|
+
writeFileSync(file, text);
|
|
25
|
+
deps.suspend();
|
|
26
|
+
try {
|
|
27
|
+
const code = (deps.run ?? runEditor)(editorCommand(deps.env, deps.platform), file);
|
|
28
|
+
if (code !== 0)
|
|
29
|
+
return undefined;
|
|
30
|
+
return readFileSync(file, "utf8");
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
deps.resume();
|
|
37
|
+
rmSync(dir, { recursive: true, force: true });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -11,15 +11,23 @@
|
|
|
11
11
|
* - 晚绑定:`runtime.approvals.setUiBroker`(审批对话框)与 `runtime.notifier.set`(宿主通知进消息区),
|
|
12
12
|
* 退出时撤下。
|
|
13
13
|
* - 键位:Enter 发送(运行中 = steer),其余应用级键位见 `key-dispatch.ts`。
|
|
14
|
+
* - 回滚(RW-C):`/rewind` 与空闲双击 Esc 走 rewind-flow.ts;回填的原消息图片暂存,随下一条消息发送。
|
|
15
|
+
* - 底部(W5-A,status-area.ts):`ui.statusLine` full 时状态栏上方多一行速率行;Ctrl+G / `/statusline`
|
|
16
|
+
* 切换(只影响本会话)。
|
|
17
|
+
* - 第五波(W5-U,agent-ui.ts):计划审批框、子 Agent 折叠视图、`/tasks` `/agents` `/paste` 与 Ctrl+V、审批来源
|
|
18
|
+
* 标注与外部 Agent 首次运行的合并确认(approval-merge.ts)、harness 提示。
|
|
14
19
|
* - 启动头按 `ui.quietStartup`(startup-header.ts):normal 框 + 模型 / 目录 / 模式 / 资源清单(窄屏或
|
|
15
20
|
* `ui.compact` 去框),header 一行,silent 不输出。
|
|
16
21
|
*/
|
|
17
22
|
import type { AgentSession } from "../../agent/types.js";
|
|
18
23
|
import type { ModeContext } from "../../cli/deps.js";
|
|
19
24
|
import type { Runtime } from "../../cli/runtime.js";
|
|
25
|
+
import type { StatusLineMode } from "../../config/types.js";
|
|
26
|
+
import type { ClipboardDeps } from "../../tools/clipboard-image.js";
|
|
20
27
|
import { Editor, Keybindings, TUI, type Terminal, type Theme } from "../../tui.js";
|
|
21
28
|
import { MessageView } from "./message-view.js";
|
|
22
|
-
import {
|
|
29
|
+
import { StatusArea } from "./status-area.js";
|
|
30
|
+
import type { StatusBar } from "./status-bar.js";
|
|
23
31
|
import { ToolTracker } from "./tool-view.js";
|
|
24
32
|
export interface InteractiveModeOptions {
|
|
25
33
|
/** 缺省 `ProcessTerminal`(测试注入 MemoryTerminal)。 */
|
|
@@ -32,8 +40,12 @@ export interface InteractiveModeOptions {
|
|
|
32
40
|
spinnerIntervalMs?: number;
|
|
33
41
|
/** 输入历史文件;false 不读写(缺省 `<dataDir>/history`)。 */
|
|
34
42
|
historyFile?: string | false;
|
|
43
|
+
/** 底部布局(缺省按 `ui.statusLine`;测试固定)。 */
|
|
44
|
+
statusLine?: StatusLineMode;
|
|
35
45
|
/** 界面就绪后回调(测试驱动用)。 */
|
|
36
46
|
onReady?(handle: InteractiveHandle): void;
|
|
47
|
+
/** 剪贴板读取的注入(测试;缺省调系统命令)。 */
|
|
48
|
+
clipboard?: ClipboardDeps;
|
|
37
49
|
}
|
|
38
50
|
export interface InteractiveHandle {
|
|
39
51
|
readonly tui: TUI;
|
|
@@ -41,6 +53,7 @@ export interface InteractiveHandle {
|
|
|
41
53
|
readonly view: MessageView;
|
|
42
54
|
readonly tools: ToolTracker;
|
|
43
55
|
readonly status: StatusBar;
|
|
56
|
+
readonly area: StatusArea;
|
|
44
57
|
session(): AgentSession;
|
|
45
58
|
exit(code: number): void;
|
|
46
59
|
}
|
|
@@ -11,30 +11,40 @@
|
|
|
11
11
|
* - 晚绑定:`runtime.approvals.setUiBroker`(审批对话框)与 `runtime.notifier.set`(宿主通知进消息区),
|
|
12
12
|
* 退出时撤下。
|
|
13
13
|
* - 键位:Enter 发送(运行中 = steer),其余应用级键位见 `key-dispatch.ts`。
|
|
14
|
+
* - 回滚(RW-C):`/rewind` 与空闲双击 Esc 走 rewind-flow.ts;回填的原消息图片暂存,随下一条消息发送。
|
|
15
|
+
* - 底部(W5-A,status-area.ts):`ui.statusLine` full 时状态栏上方多一行速率行;Ctrl+G / `/statusline`
|
|
16
|
+
* 切换(只影响本会话)。
|
|
17
|
+
* - 第五波(W5-U,agent-ui.ts):计划审批框、子 Agent 折叠视图、`/tasks` `/agents` `/paste` 与 Ctrl+V、审批来源
|
|
18
|
+
* 标注与外部 Agent 首次运行的合并确认(approval-merge.ts)、harness 提示。
|
|
14
19
|
* - 启动头按 `ui.quietStartup`(startup-header.ts):normal 框 + 模型 / 目录 / 模式 / 资源清单(窄屏或
|
|
15
20
|
* `ui.compact` 去框),header 一行,silent 不输出。
|
|
16
21
|
*/
|
|
17
22
|
import { promptImages, sessionModel } from "../image-input.js";
|
|
18
23
|
import { join } from "node:path";
|
|
19
24
|
import { AgentSessionImpl } from "../../agent/session.js";
|
|
25
|
+
import { taskRegistryView } from "../../agent/subagent-registry.js";
|
|
20
26
|
import { currentSession, switchSession } from "../../cli/compose-session.js";
|
|
21
|
-
import { startupInfo, startupScreenLevel } from "../../cli/startup-screen.js";
|
|
27
|
+
import { startupInfo, startupScreenLevel, tildePath } from "../../cli/startup-screen.js";
|
|
22
28
|
import { KEYBINDINGS_FILE } from "../../config/paths.js";
|
|
23
29
|
import { AmaError, isAmaError } from "../../errors.js";
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import { Container, Editor, Keybindings, Loader, ProcessTerminal, Spacer, TUI, Text, createTheme, detectCapabilities, resolveAscii, resolveThemeName, loadKeybindingsFile, truncateToWidth, } from "../../tui.js";
|
|
27
|
-
import { cacheEventNotice, cacheNoticesEnabled } from "../session-report.js";
|
|
30
|
+
import { Container, Editor, Keybindings, Loader, ProcessTerminal, Spacer, TUI, Text, createTheme, detectCapabilities, resolveAscii, resolveThemeName, loadKeybindingsFile, } from "../../tui.js";
|
|
31
|
+
import { BYPASS_MODE, createBypassGate } from "../../permissions/bypass.js";
|
|
28
32
|
import { onTerminationSignals } from "../shared.js";
|
|
33
|
+
import { AgentUi } from "./agent-ui.js";
|
|
29
34
|
import { ApprovalDialogBroker, approvalOutcomeText } from "./approval-dialog.js";
|
|
35
|
+
import { mergingBroker } from "./approval-merge.js";
|
|
30
36
|
import { ALL_COMMANDS, runInteractiveCommand } from "./commands.js";
|
|
31
37
|
import { InteractiveCompletion } from "./completion.js";
|
|
38
|
+
import { confirmBypass } from "./confirm-dialog.js";
|
|
32
39
|
import { createKeyDispatch } from "./key-dispatch.js";
|
|
33
40
|
import { MessageView, exitSummaryLines } from "./message-view.js";
|
|
34
41
|
import { openPicker } from "./pickers.js";
|
|
42
|
+
import { createRewindFlow } from "./rewind-flow.js";
|
|
35
43
|
import { StartupHeader } from "./startup-header.js";
|
|
36
44
|
import { QueueView, RunIndicator } from "./run-indicator.js";
|
|
37
|
-
import {
|
|
45
|
+
import { StatusArea, statusLineSlash } from "./status-area.js";
|
|
46
|
+
import { createSessionEventHandler } from "./session-events.js";
|
|
47
|
+
import { SubagentTracker } from "./subagent-view.js";
|
|
38
48
|
import { ToolTracker } from "./tool-view.js";
|
|
39
49
|
const HINT_MS = 2500;
|
|
40
50
|
const EDITOR_PLACEHOLDER = "输入消息,/ 命令,@ 文件,Shift+Enter 换行";
|
|
@@ -51,17 +61,6 @@ function loadKeys(runtime, warn) {
|
|
|
51
61
|
warn(`keybindings.json:${w}`);
|
|
52
62
|
return new Keybindings(parsed.overrides);
|
|
53
63
|
}
|
|
54
|
-
/** 一行提示;空时不占行。 */
|
|
55
|
-
class HintLine {
|
|
56
|
-
text = "";
|
|
57
|
-
setText(text) {
|
|
58
|
-
this.text = text;
|
|
59
|
-
}
|
|
60
|
-
render(width) {
|
|
61
|
-
return this.text === "" ? [] : [truncateToWidth(this.text, width)];
|
|
62
|
-
}
|
|
63
|
-
invalidate() { }
|
|
64
|
-
}
|
|
65
64
|
export function runInteractiveMode(runtime, context, options = {}) {
|
|
66
65
|
const terminal = options.terminal ?? processTerminal();
|
|
67
66
|
const ui = runtime.config.ui ?? {};
|
|
@@ -83,12 +82,14 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
83
82
|
...(ui.markdown !== undefined ? { markdown: ui.markdown } : {}),
|
|
84
83
|
...(ui.compact === true ? { compact: true } : {}),
|
|
85
84
|
});
|
|
85
|
+
const subagents = new SubagentTracker(now);
|
|
86
86
|
const tools = new ToolTracker({
|
|
87
87
|
theme,
|
|
88
88
|
cwd: session.state.cwd,
|
|
89
89
|
getTool: (name) => session.getTools().find((tool) => tool.name === name),
|
|
90
90
|
now,
|
|
91
91
|
spinner: () => loader.frame,
|
|
92
|
+
subagent: (toolCallId) => subagents.forToolCall(toolCallId),
|
|
92
93
|
});
|
|
93
94
|
const queueView = new QueueView(theme);
|
|
94
95
|
const loaderSlot = new Container();
|
|
@@ -100,19 +101,17 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
100
101
|
...(options.spinnerIntervalMs !== undefined ? { intervalMs: options.spinnerIntervalMs } : {}),
|
|
101
102
|
});
|
|
102
103
|
loader.onFrame(() => tools.tick());
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
const area = new StatusArea({
|
|
105
|
+
runtime,
|
|
106
|
+
theme,
|
|
106
107
|
session: () => session,
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
sandboxStrict: () => (sandboxStrict ??= detectSandboxCapability().strict),
|
|
115
|
-
}, theme);
|
|
108
|
+
now,
|
|
109
|
+
render: () => tui.requestRender(),
|
|
110
|
+
redraw: () => tui.forceFullRedraw(),
|
|
111
|
+
env,
|
|
112
|
+
...(options.statusLine !== undefined ? { layout: options.statusLine } : {}),
|
|
113
|
+
});
|
|
114
|
+
const { hint, bar: status } = area;
|
|
116
115
|
const historyFile = options.historyFile === false
|
|
117
116
|
? undefined
|
|
118
117
|
: (options.historyFile ?? join(runtime.paths.dataDir, "history"));
|
|
@@ -139,6 +138,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
139
138
|
tui.addChild(loaderSlot);
|
|
140
139
|
tui.addChild(editor);
|
|
141
140
|
tui.addChild(hint);
|
|
141
|
+
tui.addChild(area.rate);
|
|
142
142
|
tui.addChild(status);
|
|
143
143
|
// ---- 小工具 ---------------------------------------------------------------
|
|
144
144
|
let finished = false;
|
|
@@ -149,7 +149,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
149
149
|
view.addNotice(level, text);
|
|
150
150
|
render();
|
|
151
151
|
};
|
|
152
|
-
const showHint = (text) => {
|
|
152
|
+
const showHint = (text, ms = HINT_MS) => {
|
|
153
153
|
hint.setText(text === "" ? "" : theme.fg("dim", text));
|
|
154
154
|
if (hintTimer !== undefined)
|
|
155
155
|
clearTimeout(hintTimer);
|
|
@@ -158,7 +158,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
158
158
|
hintTimer = setTimeout(() => {
|
|
159
159
|
hint.setText("");
|
|
160
160
|
render();
|
|
161
|
-
},
|
|
161
|
+
}, ms);
|
|
162
162
|
hintTimer.unref?.();
|
|
163
163
|
}
|
|
164
164
|
render();
|
|
@@ -170,88 +170,18 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
170
170
|
render();
|
|
171
171
|
};
|
|
172
172
|
// ---- 会话事件 -------------------------------------------------------------
|
|
173
|
-
const onEvent = (
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
view.startAssistant(message);
|
|
186
|
-
else if (message.role === "custom" && message.display) {
|
|
187
|
-
view.addNotice("info", typeof message.content === "string" ? message.content : "");
|
|
188
|
-
}
|
|
189
|
-
break;
|
|
190
|
-
}
|
|
191
|
-
case "message_update":
|
|
192
|
-
view.updateAssistant(event.message);
|
|
193
|
-
break;
|
|
194
|
-
case "message_end":
|
|
195
|
-
if (event.message.role === "assistant") {
|
|
196
|
-
view.endAssistant(event.message);
|
|
197
|
-
status.refresh();
|
|
198
|
-
}
|
|
199
|
-
break;
|
|
200
|
-
case "tool_execution_start": {
|
|
201
|
-
const started = tools.start(event);
|
|
202
|
-
if (started.topLevel)
|
|
203
|
-
view.addTool(started.view);
|
|
204
|
-
break;
|
|
205
|
-
}
|
|
206
|
-
case "tool_execution_update":
|
|
207
|
-
tools.update(event.toolCallId, event.partial);
|
|
208
|
-
render();
|
|
209
|
-
return;
|
|
210
|
-
case "tool_execution_end":
|
|
211
|
-
tools.end(event.toolCallId, event.result, event.isError);
|
|
212
|
-
break;
|
|
213
|
-
case "queue_update":
|
|
214
|
-
setQueue(event.steering, event.followUp);
|
|
215
|
-
return;
|
|
216
|
-
case "compaction_end":
|
|
217
|
-
if (event.result !== undefined)
|
|
218
|
-
view.addCompaction(event.result);
|
|
219
|
-
else if (event.error !== undefined)
|
|
220
|
-
view.addNotice("error", `压缩失败:${event.error}`);
|
|
221
|
-
else if (event.aborted)
|
|
222
|
-
view.addNotice("info", "压缩已取消");
|
|
223
|
-
status.refresh();
|
|
224
|
-
break;
|
|
225
|
-
case "auto_retry_start":
|
|
226
|
-
view.addRetry(event.attempt, event.maxAttempts, event.delayMs, event.errorMessage);
|
|
227
|
-
break;
|
|
228
|
-
case "auto_retry_end":
|
|
229
|
-
if (!event.success)
|
|
230
|
-
view.addRetryFailed(event.finalError);
|
|
231
|
-
break;
|
|
232
|
-
case "cache_miss":
|
|
233
|
-
case "context_pressure": {
|
|
234
|
-
const shown = cacheEventNotice(event, cacheNoticesEnabled(session));
|
|
235
|
-
if (shown !== undefined)
|
|
236
|
-
view.addNotice(shown.level, shown.text);
|
|
237
|
-
status.refresh();
|
|
238
|
-
render();
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
case "cache_warm":
|
|
242
|
-
case "permission_mode_changed":
|
|
243
|
-
case "model_changed":
|
|
244
|
-
case "thinking_level_changed":
|
|
245
|
-
case "session_changed":
|
|
246
|
-
status.refresh();
|
|
247
|
-
render();
|
|
248
|
-
return;
|
|
249
|
-
default:
|
|
250
|
-
break;
|
|
251
|
-
}
|
|
252
|
-
indicator.onEvent(event);
|
|
253
|
-
render();
|
|
254
|
-
};
|
|
173
|
+
const onEvent = createSessionEventHandler({
|
|
174
|
+
view,
|
|
175
|
+
tools,
|
|
176
|
+
status,
|
|
177
|
+
area,
|
|
178
|
+
agentUi: () => agentUi,
|
|
179
|
+
indicator,
|
|
180
|
+
session: () => session,
|
|
181
|
+
setQueue,
|
|
182
|
+
notice,
|
|
183
|
+
render,
|
|
184
|
+
});
|
|
255
185
|
let unsubscribe = session.subscribe(onEvent);
|
|
256
186
|
const startupLevel = startupScreenLevel(runtime);
|
|
257
187
|
const home = env["HOME"] ?? env["USERPROFILE"];
|
|
@@ -282,7 +212,8 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
282
212
|
tools.clear();
|
|
283
213
|
replay();
|
|
284
214
|
setQueue([], []);
|
|
285
|
-
|
|
215
|
+
area.rebind();
|
|
216
|
+
agentUi.attach(next);
|
|
286
217
|
indicator.reset();
|
|
287
218
|
if (next instanceof AgentSessionImpl)
|
|
288
219
|
next.announceStart(reason);
|
|
@@ -292,12 +223,20 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
292
223
|
* 空闲时发提示。agent_settled 之后会话周期还要一个微任务才结束,所以先 waitForIdle;
|
|
293
224
|
* 仍然撞上运行中(极少)就排到本轮之后。
|
|
294
225
|
*/
|
|
226
|
+
let draftImages = [];
|
|
227
|
+
const resize = runtime.config.images?.resize;
|
|
228
|
+
const imageResize = resize !== undefined ? { resize } : {};
|
|
295
229
|
const startPrompt = (text) => {
|
|
296
230
|
const target = session;
|
|
231
|
+
const carried = draftImages;
|
|
232
|
+
draftImages = [];
|
|
297
233
|
void target
|
|
298
234
|
.waitForIdle()
|
|
299
235
|
.then(async () => {
|
|
300
|
-
const images =
|
|
236
|
+
const images = [
|
|
237
|
+
...carried,
|
|
238
|
+
...(await promptImages(text, [], target.state.cwd, sessionModel(runtime.providers, target), imageResize)),
|
|
239
|
+
];
|
|
301
240
|
return target.prompt(text, images.length > 0 ? { images } : {});
|
|
302
241
|
})
|
|
303
242
|
.catch((error) => {
|
|
@@ -312,6 +251,40 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
312
251
|
render();
|
|
313
252
|
});
|
|
314
253
|
};
|
|
254
|
+
/** 对话换了路径(/tree、回滚):重画消息区。内容可能缩到视口顶以上,差分画不对,整屏重画。 */
|
|
255
|
+
const reloadView = () => {
|
|
256
|
+
resetView();
|
|
257
|
+
tools.clear();
|
|
258
|
+
replay();
|
|
259
|
+
status.refresh();
|
|
260
|
+
area.refreshGit();
|
|
261
|
+
tui.forceFullRedraw();
|
|
262
|
+
};
|
|
263
|
+
const setDraft = (draft) => {
|
|
264
|
+
editor.setText(draft.text);
|
|
265
|
+
draftImages = [...(draft.images ?? [])];
|
|
266
|
+
render();
|
|
267
|
+
};
|
|
268
|
+
const pickerHost = {
|
|
269
|
+
theme,
|
|
270
|
+
keybindings: keys,
|
|
271
|
+
showOverlay: (c, o) => tui.showOverlay(c, o),
|
|
272
|
+
columns: () => terminal.columns,
|
|
273
|
+
rows: () => terminal.rows,
|
|
274
|
+
};
|
|
275
|
+
// 进入 Bypass 前确认一次;启动时已是 Bypass(命令行 / 配置指定)视为已确认
|
|
276
|
+
const confirmMode = createBypassGate(() => confirmBypass(pickerHost), session.state.permissionMode === BYPASS_MODE);
|
|
277
|
+
const rewind = createRewindFlow({
|
|
278
|
+
...pickerHost,
|
|
279
|
+
session: () => session,
|
|
280
|
+
now,
|
|
281
|
+
render,
|
|
282
|
+
notice,
|
|
283
|
+
hint: (text) => showHint(text),
|
|
284
|
+
reload: reloadView,
|
|
285
|
+
setDraft,
|
|
286
|
+
editorEmpty: () => editor.isEmpty(),
|
|
287
|
+
});
|
|
315
288
|
const commandUi = {
|
|
316
289
|
runtime,
|
|
317
290
|
session: () => session,
|
|
@@ -320,12 +293,10 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
320
293
|
rebind(next, request.kind === "new" ? "new" : request.kind === "fork" ? "fork" : "resume");
|
|
321
294
|
return next;
|
|
322
295
|
},
|
|
323
|
-
pick: (spec) => openPicker(
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
columns: () => terminal.columns,
|
|
328
|
-
}, spec),
|
|
296
|
+
pick: (spec) => openPicker(pickerHost, spec),
|
|
297
|
+
confirmMode,
|
|
298
|
+
rewind: () => rewind.open(),
|
|
299
|
+
setDraft,
|
|
329
300
|
notice,
|
|
330
301
|
panel: (component) => {
|
|
331
302
|
view.add(component);
|
|
@@ -339,17 +310,14 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
339
310
|
render();
|
|
340
311
|
},
|
|
341
312
|
prompt: (text) => startPrompt(text),
|
|
342
|
-
reload:
|
|
343
|
-
resetView();
|
|
344
|
-
tools.clear();
|
|
345
|
-
replay();
|
|
346
|
-
status.refresh();
|
|
347
|
-
render();
|
|
348
|
-
},
|
|
313
|
+
reload: reloadView,
|
|
349
314
|
exit: (code) => exit(code),
|
|
350
315
|
now,
|
|
316
|
+
extra: (name, args) => agentUi.command(name, args),
|
|
351
317
|
};
|
|
352
|
-
const runCommand = (line) =>
|
|
318
|
+
const runCommand = (line) => (statusLineSlash(area, line, notice)
|
|
319
|
+
? Promise.resolve(true)
|
|
320
|
+
: runInteractiveCommand(line, commandUi)).finally(() => {
|
|
353
321
|
status.refresh();
|
|
354
322
|
render();
|
|
355
323
|
});
|
|
@@ -385,16 +353,16 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
385
353
|
now,
|
|
386
354
|
showHint,
|
|
387
355
|
onExpandToggle: (expanded) => view.setThinkingExpanded(expanded),
|
|
356
|
+
onStatusLineToggle: () => area.toggle(),
|
|
357
|
+
onPasteImage: () => void agentUi.paste(),
|
|
358
|
+
confirmMode,
|
|
388
359
|
submit: (text, via) => submit(text, via),
|
|
389
360
|
runCommand: (line) => void runCommand(line),
|
|
390
361
|
exit: (code) => exit(code),
|
|
362
|
+
onInterrupted: (empty) => void rewind.afterInterrupt(empty),
|
|
391
363
|
}));
|
|
392
364
|
// ---- 晚绑定 ---------------------------------------------------------------
|
|
393
|
-
const
|
|
394
|
-
theme,
|
|
395
|
-
keybindings: keys,
|
|
396
|
-
cwd: session.state.cwd,
|
|
397
|
-
permissionMode: () => session.state.permissionMode,
|
|
365
|
+
const overlayHooks = {
|
|
398
366
|
showOverlay: (component) => tui.showOverlay(component, { anchor: "bottom" }),
|
|
399
367
|
onOpen: () => {
|
|
400
368
|
editor.disableSubmit = true;
|
|
@@ -406,12 +374,44 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
406
374
|
tools.setAwaiting(false);
|
|
407
375
|
indicator.setApproval(false);
|
|
408
376
|
},
|
|
377
|
+
};
|
|
378
|
+
const agentUi = new AgentUi({
|
|
379
|
+
theme,
|
|
380
|
+
tui,
|
|
381
|
+
editor,
|
|
382
|
+
tools: () => tools,
|
|
383
|
+
subagents,
|
|
384
|
+
session: () => session,
|
|
385
|
+
dataDir: runtime.paths.dataDir,
|
|
386
|
+
env,
|
|
387
|
+
now,
|
|
388
|
+
notice,
|
|
389
|
+
panel: (component) => commandUi.panel?.(component),
|
|
390
|
+
pick: (spec) => openPicker(pickerHost, spec),
|
|
391
|
+
hint: (text) => showHint(text),
|
|
392
|
+
render,
|
|
393
|
+
switchSession: (request) => commandUi.switchSession(request),
|
|
394
|
+
prompt: (text) => startPrompt(text),
|
|
395
|
+
dialog: { theme, keybindings: keys, ...overlayHooks },
|
|
396
|
+
displayPath: (path) => tildePath(path, home),
|
|
397
|
+
...(options.clipboard !== undefined ? { clipboard: options.clipboard } : {}),
|
|
398
|
+
});
|
|
399
|
+
const taskAgent = (taskId) => taskRegistryView(session.state.sessionId)?.get(taskId)?.agent;
|
|
400
|
+
const broker = mergingBroker(new ApprovalDialogBroker({
|
|
401
|
+
theme,
|
|
402
|
+
keybindings: keys,
|
|
403
|
+
cwd: session.state.cwd,
|
|
404
|
+
permissionMode: () => session.state.permissionMode,
|
|
405
|
+
taskAgent,
|
|
406
|
+
externalRunner: (agent) => agentUi.merge.externalRunner(agent),
|
|
407
|
+
...overlayHooks,
|
|
409
408
|
report: (request, outcome) => {
|
|
410
409
|
if (outcome === "deny" || outcome === "cancelled") {
|
|
411
|
-
|
|
410
|
+
const text = approvalOutcomeText(request, outcome, taskAgent);
|
|
411
|
+
notice(outcome === "deny" ? "info" : "warn", text);
|
|
412
412
|
}
|
|
413
413
|
},
|
|
414
|
-
});
|
|
414
|
+
}), agentUi.merge, (request) => notice("info", `${approvalOutcomeText(request, "allow", taskAgent)}(随上一次确认)`));
|
|
415
415
|
// ---- 启动与退出 -----------------------------------------------------------
|
|
416
416
|
let offSignals = () => undefined;
|
|
417
417
|
function exit(code) {
|
|
@@ -421,11 +421,13 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
421
421
|
if (hintTimer !== undefined)
|
|
422
422
|
clearTimeout(hintTimer);
|
|
423
423
|
loader.stop();
|
|
424
|
+
area.dispose();
|
|
424
425
|
// 退出摘要留在回滚里;输入框、状态栏等底部区域撤掉,屏幕停在摘要下面
|
|
425
426
|
view.addExitSummary(exitSummaryLines(session.getStats(), now() - startedAt, theme));
|
|
426
427
|
tui.clear();
|
|
427
428
|
tui.addChild(view);
|
|
428
429
|
offSignals();
|
|
430
|
+
agentUi.detach();
|
|
429
431
|
runtime.approvals.setUiBroker(undefined);
|
|
430
432
|
runtime.notifier.set(undefined);
|
|
431
433
|
tui.stop();
|
|
@@ -456,6 +458,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
456
458
|
}
|
|
457
459
|
runtime.approvals.setUiBroker(broker);
|
|
458
460
|
runtime.notifier.set((message, level) => notice(level, message));
|
|
461
|
+
agentUi.attach(session);
|
|
459
462
|
offSignals = onTerminationSignals((code) => exit(code));
|
|
460
463
|
tui.setFocus(editor);
|
|
461
464
|
options.onReady?.({
|
|
@@ -464,6 +467,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
464
467
|
view,
|
|
465
468
|
tools,
|
|
466
469
|
status,
|
|
470
|
+
area,
|
|
467
471
|
session: () => session,
|
|
468
472
|
exit,
|
|
469
473
|
});
|
|
@@ -3,9 +3,15 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 编辑器之前的输入监听:Ctrl+C 清空输入 / 再按退出、Esc 中断(clearQueue 回填编辑器后 abort)、
|
|
5
5
|
* Ctrl+D 空输入退出、Alt+Enter followUp、Alt+↑ 取回最后一条排队消息、Shift+Tab 循环权限模式、
|
|
6
|
-
* Ctrl+O 展开工具输出与思考块、Ctrl+L 模型、Ctrl+T
|
|
6
|
+
* Ctrl+O 展开工具输出与思考块、Ctrl+L 模型、Ctrl+T 思考级别、Ctrl+G 底部信息行 full ↔ compact(W5-A)、
|
|
7
|
+
* Ctrl+V 粘贴剪贴板图片(`app.paste.image`,W5-U)。
|
|
8
|
+
* 键位由 `keybindings.json` 覆盖。
|
|
9
|
+
*
|
|
10
|
+
* [RW-C] 空闲时双击 Esc(`app.rewind`,double-esc.ts):输入框为空打开回滚列表,有字则清空并存进
|
|
11
|
+
* 输入历史;运行中 Esc 仍为中断,中断后交给 `onInterrupted`(中断即撤回)。
|
|
7
12
|
*/
|
|
8
13
|
import type { AgentSession } from "../../agent/types.js";
|
|
14
|
+
import type { PermissionMode } from "../../permissions/types.js";
|
|
9
15
|
import type { Editor, Keybindings } from "../../tui.js";
|
|
10
16
|
import type { StatusBar } from "./status-bar.js";
|
|
11
17
|
import type { ToolTracker } from "./tool-view.js";
|
|
@@ -20,12 +26,26 @@ export interface KeyDispatchDeps {
|
|
|
20
26
|
/** 运行或压缩中(Esc 才中断)。 */
|
|
21
27
|
busy(): boolean;
|
|
22
28
|
now(): number;
|
|
23
|
-
|
|
29
|
+
/** 底部提示;`ms` 是停留时间(缺省由调用方决定)。 */
|
|
30
|
+
showHint(text: string, ms?: number): void;
|
|
24
31
|
/** Ctrl+O 之后(消息区思考块跟着展开 / 折叠)。 */
|
|
25
32
|
onExpandToggle?(expanded: boolean): void;
|
|
33
|
+
/** Ctrl+G:切换底部信息行,返回切换后的布局。 */
|
|
34
|
+
onStatusLineToggle?(): "full" | "compact";
|
|
35
|
+
/**
|
|
36
|
+
* 循环到某模式前的确认(进入 Bypass 前弹确认框,permissions/bypass.ts);返回 false 时跳过该模式,
|
|
37
|
+
* 落到循环里的下一个。没有时直接切换。
|
|
38
|
+
*/
|
|
39
|
+
confirmMode?(mode: PermissionMode): boolean | Promise<boolean>;
|
|
40
|
+
/** Ctrl+V:粘贴剪贴板图片(W5-U)。 */
|
|
41
|
+
onPasteImage?(): void;
|
|
26
42
|
submit(text: string, via: "followUp"): void;
|
|
27
43
|
runCommand(line: string): void;
|
|
28
44
|
exit(code: number): void;
|
|
45
|
+
/** Esc 中断之后(参数:中断后输入框是否为空)。 */
|
|
46
|
+
onInterrupted?(editorWasEmpty: boolean): void;
|
|
47
|
+
/** 双击 Esc 的间隔(测试注入)。 */
|
|
48
|
+
doubleEscMs?: number;
|
|
29
49
|
}
|
|
30
50
|
/** 返回输入监听器:已处理返回 true,交给编辑器返回 false。 */
|
|
31
51
|
export declare function createKeyDispatch(deps: KeyDispatchDeps): (data: string) => boolean;
|