@armadra/agent 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +174 -1
- package/README.md +201 -82
- package/THIRD_PARTY_NOTICES.md +34 -0
- package/dist/acp.d.ts +18 -0
- package/dist/acp.js +19 -0
- package/dist/agent/limits.d.ts +38 -0
- package/dist/agent/limits.js +127 -0
- package/dist/agent/loop-guard.d.ts +38 -0
- package/dist/agent/loop-guard.js +95 -0
- package/dist/agent/loop.d.ts +4 -0
- package/dist/agent/loop.js +7 -0
- package/dist/agent/prompt-rules.d.ts +12 -0
- package/dist/agent/prompt-rules.js +18 -0
- package/dist/agent/reminders.d.ts +59 -0
- package/dist/agent/reminders.js +327 -0
- package/dist/agent/session-cache.d.ts +5 -0
- package/dist/agent/session-cache.js +17 -1
- package/dist/agent/session-classifier.d.ts +1 -1
- package/dist/agent/session-classifier.js +3 -1
- package/dist/agent/session-compaction.d.ts +35 -6
- package/dist/agent/session-compaction.js +157 -31
- package/dist/agent/session-core.d.ts +27 -1
- package/dist/agent/session-extensions.d.ts +61 -0
- package/dist/agent/session-extensions.js +129 -0
- package/dist/agent/session-images.d.ts +23 -0
- package/dist/agent/session-images.js +97 -0
- package/dist/agent/session-plan.d.ts +21 -0
- package/dist/agent/session-plan.js +524 -0
- package/dist/agent/session-rewind.d.ts +81 -0
- package/dist/agent/session-rewind.js +354 -0
- package/dist/agent/session-run.d.ts +28 -1
- package/dist/agent/session-run.js +157 -6
- package/dist/agent/session-settings.d.ts +49 -0
- package/dist/agent/session-settings.js +95 -0
- package/dist/agent/session-subagent.d.ts +36 -24
- package/dist/agent/session-subagent.js +259 -129
- package/dist/agent/session-sync.d.ts +10 -3
- package/dist/agent/session-sync.js +37 -8
- package/dist/agent/session-telemetry.d.ts +39 -0
- package/dist/agent/session-telemetry.js +231 -0
- package/dist/agent/session-tools.js +40 -1
- package/dist/agent/session.d.ts +30 -29
- package/dist/agent/session.js +79 -123
- package/dist/agent/subagent-registry.d.ts +91 -0
- package/dist/agent/subagent-registry.js +494 -0
- package/dist/agent/system-prompt.d.ts +6 -3
- package/dist/agent/system-prompt.js +7 -2
- package/dist/agent/tool-runner.d.ts +8 -1
- package/dist/agent/tool-runner.js +57 -4
- package/dist/agent/types-w5.d.ts +192 -0
- package/dist/agent/types-w5.js +10 -0
- package/dist/agent/types.d.ts +47 -4
- package/dist/agent/types.js +2 -0
- package/dist/agent/worktree.d.ts +36 -0
- package/dist/agent/worktree.js +86 -0
- package/dist/agents/builtin.d.ts +14 -0
- package/dist/agents/builtin.js +39 -0
- package/dist/agents/catalog.d.ts +43 -0
- package/dist/agents/catalog.js +82 -0
- package/dist/agents/discover.d.ts +35 -0
- package/dist/agents/discover.js +83 -0
- package/dist/agents/external.d.ts +82 -0
- package/dist/agents/external.js +326 -0
- package/dist/agents/parse.d.ts +18 -0
- package/dist/agents/parse.js +116 -0
- package/dist/agents/result.d.ts +32 -0
- package/dist/agents/result.js +67 -0
- package/dist/agents/task-control.d.ts +17 -0
- package/dist/agents/task-control.js +17 -0
- package/dist/agents/task-record.d.ts +78 -0
- package/dist/agents/task-record.js +141 -0
- package/dist/agents/types.d.ts +46 -0
- package/dist/agents/types.js +8 -0
- package/dist/ai/apis/anthropic-compat.d.ts +36 -0
- package/dist/ai/apis/anthropic-compat.js +92 -0
- package/dist/ai/apis/anthropic-request.d.ts +7 -6
- package/dist/ai/apis/anthropic-request.js +10 -28
- package/dist/ai/apis/cache-params.d.ts +11 -2
- package/dist/ai/apis/cache-params.js +25 -6
- package/dist/ai/apis/openai-compat.d.ts +4 -1
- package/dist/ai/apis/openai-compat.js +8 -1
- package/dist/ai/image-limits.d.ts +45 -0
- package/dist/ai/image-limits.js +68 -0
- package/dist/ai/providers/builtin.d.ts +18 -6
- package/dist/ai/providers/builtin.js +135 -6
- package/dist/ai/providers/catalog-data.js +17 -13
- package/dist/ai/providers/catalog.d.ts +60 -7
- package/dist/ai/providers/catalog.js +197 -38
- package/dist/ai/providers/channels.d.ts +33 -3
- package/dist/ai/providers/channels.js +108 -7
- package/dist/ai/providers/enrich.d.ts +6 -3
- package/dist/ai/providers/enrich.js +19 -4
- package/dist/ai/providers/models-dev-cache.d.ts +28 -24
- package/dist/ai/providers/models-dev-cache.js +92 -78
- package/dist/ai/providers/models-dev-data.d.ts +7 -0
- package/dist/ai/providers/models-dev-data.js +32 -0
- package/dist/ai/providers/models-dev-snapshot.d.ts +50 -0
- package/dist/ai/providers/models-dev-snapshot.js +137 -0
- package/dist/ai/providers/models-dev.d.ts +51 -10
- package/dist/ai/providers/models-dev.js +132 -39
- package/dist/ai/providers/registry.d.ts +20 -10
- package/dist/ai/providers/registry.js +82 -43
- package/dist/ai/types.d.ts +28 -2
- package/dist/ai/types.js +5 -0
- package/dist/bundle/ama.cjs +36203 -20499
- package/dist/checkpoints/backend.d.ts +61 -0
- package/dist/checkpoints/backend.js +135 -0
- package/dist/checkpoints/blobs.d.ts +60 -0
- package/dist/checkpoints/blobs.js +203 -0
- package/dist/checkpoints/gc.d.ts +47 -0
- package/dist/checkpoints/gc.js +144 -0
- package/dist/checkpoints/git-head.d.ts +15 -0
- package/dist/checkpoints/git-head.js +89 -0
- package/dist/checkpoints/index.d.ts +17 -0
- package/dist/checkpoints/index.js +17 -0
- package/dist/checkpoints/replay.d.ts +48 -0
- package/dist/checkpoints/replay.js +154 -0
- package/dist/checkpoints/restore.d.ts +86 -0
- package/dist/checkpoints/restore.js +263 -0
- package/dist/checkpoints/settings.d.ts +14 -0
- package/dist/checkpoints/settings.js +23 -0
- package/dist/checkpoints/shadow-git.d.ts +108 -0
- package/dist/checkpoints/shadow-git.js +491 -0
- package/dist/checkpoints/shadow-restore.d.ts +25 -0
- package/dist/checkpoints/shadow-restore.js +128 -0
- package/dist/checkpoints/tracker.d.ts +64 -0
- package/dist/checkpoints/tracker.js +192 -0
- package/dist/checkpoints/types.d.ts +99 -0
- package/dist/checkpoints/types.js +12 -0
- package/dist/cli/args.d.ts +8 -4
- package/dist/cli/args.js +17 -97
- package/dist/cli/bootstrap.js +13 -1
- package/dist/cli/codemode-notice.d.ts +3 -2
- package/dist/cli/codemode-notice.js +3 -2
- package/dist/cli/compose-agents.d.ts +27 -0
- package/dist/cli/compose-agents.js +111 -0
- package/dist/cli/compose-extensions.d.ts +29 -0
- package/dist/cli/compose-extensions.js +44 -0
- package/dist/cli/compose-session.d.ts +3 -0
- package/dist/cli/compose-session.js +47 -4
- package/dist/cli/compose.d.ts +3 -0
- package/dist/cli/compose.js +33 -6
- package/dist/cli/deps.d.ts +6 -0
- package/dist/cli/exit-codes.d.ts +10 -0
- package/dist/cli/exit-codes.js +12 -0
- package/dist/cli/help-text.d.ts +4 -0
- package/dist/cli/help-text.js +102 -0
- package/dist/cli/startup-screen.js +5 -3
- package/dist/cli/startup-steps.js +7 -1
- package/dist/cli/subcommands/config.d.ts +4 -1
- package/dist/cli/subcommands/config.js +17 -6
- package/dist/cli/subcommands/doctor.js +21 -0
- package/dist/cli/subcommands/models-discover.js +5 -6
- package/dist/cli/subcommands/models.d.ts +2 -0
- package/dist/cli/subcommands/models.js +33 -14
- package/dist/cli/subcommands/providers.js +5 -6
- package/dist/cli/subcommands/sessions.d.ts +3 -1
- package/dist/cli/subcommands/sessions.js +36 -2
- package/dist/codemode/capability.d.ts +24 -7
- package/dist/codemode/capability.js +38 -10
- package/dist/codemode/host-side.d.ts +14 -0
- package/dist/codemode/host-side.js +24 -1
- package/dist/codemode/tool.d.ts +1 -1
- package/dist/codemode/tool.js +6 -4
- package/dist/compaction/breaker.d.ts +25 -9
- package/dist/compaction/breaker.js +47 -17
- package/dist/compaction/estimate.d.ts +11 -3
- package/dist/compaction/estimate.js +64 -22
- package/dist/compaction/image-budget.d.ts +45 -0
- package/dist/compaction/image-budget.js +115 -0
- package/dist/compaction/post-compact.d.ts +38 -0
- package/dist/compaction/post-compact.js +152 -0
- package/dist/compaction/protect.d.ts +27 -0
- package/dist/compaction/protect.js +56 -0
- package/dist/compaction/prune-tier.d.ts +58 -12
- package/dist/compaction/prune-tier.js +120 -54
- package/dist/compaction/summarize-tier.d.ts +23 -4
- package/dist/compaction/summarize-tier.js +100 -29
- package/dist/config/checker.d.ts +28 -0
- package/dist/config/checker.js +97 -0
- package/dist/config/json-schema.js +63 -2
- package/dist/config/key-docs.js +72 -3
- package/dist/config/merge.d.ts +5 -3
- package/dist/config/merge.js +81 -7
- package/dist/config/profile.d.ts +2 -0
- package/dist/config/profile.js +2 -0
- package/dist/config/schema-w5.d.ts +18 -0
- package/dist/config/schema-w5.js +109 -0
- package/dist/config/schema.d.ts +5 -9
- package/dist/config/schema.js +68 -114
- package/dist/config/types-w5.d.ts +118 -0
- package/dist/config/types-w5.js +20 -0
- package/dist/config/types.d.ts +50 -1
- package/dist/config/types.js +12 -0
- package/dist/drivers/acp/client.d.ts +57 -0
- package/dist/drivers/acp/client.js +160 -0
- package/dist/drivers/acp/driver.d.ts +31 -0
- package/dist/drivers/acp/driver.js +274 -0
- package/dist/drivers/acp/testing/fake-agent-main.d.ts +5 -0
- package/dist/drivers/acp/testing/fake-agent-main.js +7 -0
- package/dist/drivers/acp/testing/fake-agent.d.ts +27 -0
- package/dist/drivers/acp/testing/fake-agent.js +211 -0
- package/dist/drivers/acp/types.d.ts +285 -0
- package/dist/drivers/acp/types.js +36 -0
- package/dist/drivers/agents.d.ts +58 -0
- package/dist/drivers/agents.js +142 -0
- package/dist/drivers/base.d.ts +35 -0
- package/dist/drivers/base.js +59 -0
- package/dist/drivers/catalog.d.ts +46 -0
- package/dist/drivers/catalog.js +167 -0
- package/dist/drivers/env.d.ts +20 -0
- package/dist/drivers/env.js +46 -0
- package/dist/drivers/host-runners.d.ts +18 -0
- package/dist/drivers/host-runners.js +45 -0
- package/dist/drivers/jsonrpc.d.ts +58 -0
- package/dist/drivers/jsonrpc.js +180 -0
- package/dist/drivers/native/claude-normalize.d.ts +46 -0
- package/dist/drivers/native/claude-normalize.js +106 -0
- package/dist/drivers/native/claude-stream.d.ts +29 -0
- package/dist/drivers/native/claude-stream.js +456 -0
- package/dist/drivers/native/codex-app-server.d.ts +26 -0
- package/dist/drivers/native/codex-app-server.js +407 -0
- package/dist/drivers/native/codex-normalize.d.ts +38 -0
- package/dist/drivers/native/codex-normalize.js +124 -0
- package/dist/drivers/native/oneshot.d.ts +28 -0
- package/dist/drivers/native/oneshot.js +312 -0
- package/dist/drivers/permissions.d.ts +40 -0
- package/dist/drivers/permissions.js +92 -0
- package/dist/drivers/pids.d.ts +32 -0
- package/dist/drivers/pids.js +93 -0
- package/dist/drivers/pool.d.ts +28 -0
- package/dist/drivers/pool.js +96 -0
- package/dist/drivers/probe.d.ts +47 -0
- package/dist/drivers/probe.js +172 -0
- package/dist/drivers/process.d.ts +48 -0
- package/dist/drivers/process.js +100 -0
- package/dist/drivers/runner.d.ts +61 -0
- package/dist/drivers/runner.js +388 -0
- package/dist/drivers/store.d.ts +49 -0
- package/dist/drivers/store.js +91 -0
- package/dist/drivers/turn.d.ts +41 -0
- package/dist/drivers/turn.js +99 -0
- package/dist/drivers/types.d.ts +122 -0
- package/dist/drivers/types.js +11 -0
- package/dist/git/info.d.ts +75 -0
- package/dist/git/info.js +191 -0
- package/dist/hooks/protocol.js +6 -1
- package/dist/hooks/types.d.ts +10 -1
- package/dist/hooks/types.js +2 -0
- package/dist/host/api-impl.d.ts +7 -0
- package/dist/host/api-impl.js +15 -0
- package/dist/host/types.d.ts +24 -2
- package/dist/host/types.js +4 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -0
- package/dist/modes/acp/acp-events.d.ts +46 -0
- package/dist/modes/acp/acp-events.js +233 -0
- package/dist/modes/acp/acp-mode.d.ts +17 -0
- package/dist/modes/acp/acp-mode.js +47 -0
- package/dist/modes/acp/acp-server.d.ts +79 -0
- package/dist/modes/acp/acp-server.js +315 -0
- package/dist/modes/commands-core.d.ts +7 -1
- package/dist/modes/commands-core.js +55 -0
- package/dist/modes/image-input.d.ts +12 -4
- package/dist/modes/image-input.js +22 -5
- package/dist/modes/interactive/agent-panels.d.ts +14 -0
- package/dist/modes/interactive/agent-panels.js +103 -0
- package/dist/modes/interactive/agent-ui.d.ts +73 -0
- package/dist/modes/interactive/agent-ui.js +234 -0
- package/dist/modes/interactive/approval-dialog.d.ts +21 -4
- package/dist/modes/interactive/approval-dialog.js +98 -20
- package/dist/modes/interactive/approval-merge.d.ts +41 -0
- package/dist/modes/interactive/approval-merge.js +89 -0
- package/dist/modes/interactive/clipboard-paste.d.ts +18 -0
- package/dist/modes/interactive/clipboard-paste.js +28 -0
- package/dist/modes/interactive/commands.d.ts +9 -1
- package/dist/modes/interactive/commands.js +19 -0
- package/dist/modes/interactive/double-esc.d.ts +20 -0
- package/dist/modes/interactive/double-esc.js +34 -0
- package/dist/modes/interactive/event-notices.d.ts +32 -0
- package/dist/modes/interactive/event-notices.js +79 -0
- package/dist/modes/interactive/external-editor.d.ts +16 -0
- package/dist/modes/interactive/external-editor.js +39 -0
- package/dist/modes/interactive/interactive-mode.d.ts +14 -1
- package/dist/modes/interactive/interactive-mode.js +134 -136
- package/dist/modes/interactive/key-dispatch.d.ts +16 -2
- package/dist/modes/interactive/key-dispatch.js +49 -1
- package/dist/modes/interactive/line/line-mode.d.ts +2 -1
- package/dist/modes/interactive/line/line-mode.js +22 -5
- package/dist/modes/interactive/line/line-render.d.ts +2 -1
- package/dist/modes/interactive/line/line-render.js +40 -4
- package/dist/modes/interactive/message-view.d.ts +1 -1
- package/dist/modes/interactive/message-view.js +24 -2
- package/dist/modes/interactive/panels.d.ts +18 -1
- package/dist/modes/interactive/panels.js +19 -5
- package/dist/modes/interactive/plan-command.d.ts +40 -0
- package/dist/modes/interactive/plan-command.js +129 -0
- package/dist/modes/interactive/plan-dialog.d.ts +98 -0
- package/dist/modes/interactive/plan-dialog.js +290 -0
- package/dist/modes/interactive/plan-flow.d.ts +34 -0
- package/dist/modes/interactive/plan-flow.js +98 -0
- package/dist/modes/interactive/rewind-command.d.ts +31 -0
- package/dist/modes/interactive/rewind-command.js +106 -0
- package/dist/modes/interactive/rewind-flow.d.ts +37 -0
- package/dist/modes/interactive/rewind-flow.js +151 -0
- package/dist/modes/interactive/rewind-list.d.ts +36 -0
- package/dist/modes/interactive/rewind-list.js +123 -0
- package/dist/modes/interactive/rewind-panel.d.ts +77 -0
- package/dist/modes/interactive/rewind-panel.js +309 -0
- package/dist/modes/interactive/rewind-text.d.ts +40 -0
- package/dist/modes/interactive/rewind-text.js +139 -0
- package/dist/modes/interactive/session-events.d.ts +24 -0
- package/dist/modes/interactive/session-events.js +96 -0
- package/dist/modes/interactive/status-area.d.ts +73 -0
- package/dist/modes/interactive/status-area.js +190 -0
- package/dist/modes/interactive/status-bar.d.ts +99 -11
- package/dist/modes/interactive/status-bar.js +273 -90
- package/dist/modes/interactive/status-line.d.ts +33 -0
- package/dist/modes/interactive/status-line.js +113 -0
- package/dist/modes/interactive/subagent-view.d.ts +56 -0
- package/dist/modes/interactive/subagent-view.js +154 -0
- package/dist/modes/interactive/tasks-report.d.ts +27 -0
- package/dist/modes/interactive/tasks-report.js +114 -0
- package/dist/modes/interactive/tool-view.d.ts +12 -2
- package/dist/modes/interactive/tool-view.js +34 -4
- package/dist/modes/print/print-mode.d.ts +13 -4
- package/dist/modes/print/print-mode.js +56 -12
- package/dist/modes/rpc/commands.d.ts +9 -0
- package/dist/modes/rpc/commands.js +44 -0
- package/dist/modes/rpc/rpc-mode.js +7 -1
- package/dist/modes/session-report.d.ts +11 -0
- package/dist/modes/session-report.js +48 -1
- package/dist/permissions/auto-safe.d.ts +5 -0
- package/dist/permissions/auto-safe.js +18 -0
- package/dist/permissions/classifier.d.ts +4 -0
- package/dist/permissions/classifier.js +2 -0
- package/dist/permissions/modes.js +1 -1
- package/dist/permissions/pipeline.d.ts +43 -4
- package/dist/permissions/pipeline.js +114 -9
- package/dist/permissions/readonly-bash.d.ts +30 -0
- package/dist/permissions/readonly-bash.js +118 -0
- package/dist/permissions/types.d.ts +42 -0
- package/dist/plan/compose.d.ts +9 -0
- package/dist/plan/compose.js +19 -0
- package/dist/plan/controller.d.ts +71 -0
- package/dist/plan/controller.js +27 -0
- package/dist/plan/done-markers.d.ts +17 -0
- package/dist/plan/done-markers.js +51 -0
- package/dist/plan/extract.d.ts +29 -0
- package/dist/plan/extract.js +160 -0
- package/dist/plan/prompts.d.ts +36 -0
- package/dist/plan/prompts.js +89 -0
- package/dist/plan/store.d.ts +37 -0
- package/dist/plan/store.js +90 -0
- package/dist/rpc.d.ts +58 -2
- package/dist/rpc.js +7 -0
- package/dist/sandbox/bash.d.ts +74 -0
- package/dist/sandbox/bash.js +126 -0
- package/dist/sandbox/detect.d.ts +48 -0
- package/dist/sandbox/detect.js +149 -0
- package/dist/sandbox/index.d.ts +5 -0
- package/dist/sandbox/index.js +5 -0
- package/dist/sandbox/profile.d.ts +33 -0
- package/dist/sandbox/profile.js +76 -0
- package/dist/sandbox/wrap.d.ts +29 -0
- package/dist/sandbox/wrap.js +117 -0
- package/dist/sdk.d.ts +33 -2
- package/dist/sdk.js +24 -2
- package/dist/session/types.d.ts +3 -1
- package/dist/session/types.js +1 -0
- package/dist/skills/builtin.d.ts +31 -0
- package/dist/skills/builtin.js +109 -0
- package/dist/skills/discover.d.ts +2 -1
- package/dist/skills/index-prompt.js +5 -8
- package/dist/tools/background-jobs.d.ts +71 -0
- package/dist/tools/background-jobs.js +198 -0
- package/dist/tools/bash.d.ts +53 -1
- package/dist/tools/bash.js +158 -7
- package/dist/tools/clipboard-image.d.ts +44 -0
- package/dist/tools/clipboard-image.js +148 -0
- package/dist/tools/edit.d.ts +2 -0
- package/dist/tools/edit.js +18 -3
- package/dist/tools/image-file.d.ts +38 -3
- package/dist/tools/image-file.js +81 -10
- package/dist/tools/image-resize.d.ts +58 -0
- package/dist/tools/image-resize.js +97 -0
- package/dist/tools/presets.d.ts +7 -2
- package/dist/tools/presets.js +11 -4
- package/dist/tools/read.d.ts +5 -2
- package/dist/tools/read.js +13 -10
- package/dist/tools/registry.d.ts +7 -1
- package/dist/tools/registry.js +27 -4
- package/dist/tools/task-ctl.d.ts +22 -0
- package/dist/tools/task-ctl.js +116 -0
- package/dist/tools/task.d.ts +22 -10
- package/dist/tools/task.js +66 -26
- package/dist/tools/todo.d.ts +22 -2
- package/dist/tools/todo.js +58 -14
- package/dist/tools/truncate.d.ts +15 -0
- package/dist/tools/truncate.js +25 -0
- package/dist/tools/types.d.ts +113 -0
- package/dist/tools/types.js +5 -0
- package/dist/tools/write.js +3 -0
- package/dist/tui/glyphs.d.ts +4 -0
- package/dist/tui/glyphs.js +4 -0
- package/dist/tui/keybindings.d.ts +5 -0
- package/dist/tui/keybindings.js +5 -0
- package/docs/acp.md +78 -0
- package/docs/agents.md +250 -0
- package/docs/codemode.md +12 -8
- package/docs/hooks.md +26 -22
- package/docs/permissions.md +77 -13
- package/docs/plan.md +107 -0
- package/docs/providers.md +228 -52
- package/docs/rewind-plan.md +181 -0
- package/docs/rpc.md +92 -5
- package/docs/sandbox.md +215 -0
- package/docs/session-format.md +41 -21
- package/docs/sessions.md +41 -1
- package/docs/tui-design.md +751 -0
- package/docs/tui.md +125 -6
- package/package.json +13 -2
|
@@ -11,30 +11,38 @@
|
|
|
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 { effectiveCodemodeMode } from "../../tools/presets.js";
|
|
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";
|
|
28
31
|
import { onTerminationSignals } from "../shared.js";
|
|
32
|
+
import { AgentUi } from "./agent-ui.js";
|
|
29
33
|
import { ApprovalDialogBroker, approvalOutcomeText } from "./approval-dialog.js";
|
|
34
|
+
import { mergingBroker } from "./approval-merge.js";
|
|
30
35
|
import { ALL_COMMANDS, runInteractiveCommand } from "./commands.js";
|
|
31
36
|
import { InteractiveCompletion } from "./completion.js";
|
|
32
37
|
import { createKeyDispatch } from "./key-dispatch.js";
|
|
33
38
|
import { MessageView, exitSummaryLines } from "./message-view.js";
|
|
34
39
|
import { openPicker } from "./pickers.js";
|
|
40
|
+
import { createRewindFlow } from "./rewind-flow.js";
|
|
35
41
|
import { StartupHeader } from "./startup-header.js";
|
|
36
42
|
import { QueueView, RunIndicator } from "./run-indicator.js";
|
|
37
|
-
import {
|
|
43
|
+
import { StatusArea, statusLineSlash } from "./status-area.js";
|
|
44
|
+
import { createSessionEventHandler } from "./session-events.js";
|
|
45
|
+
import { SubagentTracker } from "./subagent-view.js";
|
|
38
46
|
import { ToolTracker } from "./tool-view.js";
|
|
39
47
|
const HINT_MS = 2500;
|
|
40
48
|
const EDITOR_PLACEHOLDER = "输入消息,/ 命令,@ 文件,Shift+Enter 换行";
|
|
@@ -51,17 +59,6 @@ function loadKeys(runtime, warn) {
|
|
|
51
59
|
warn(`keybindings.json:${w}`);
|
|
52
60
|
return new Keybindings(parsed.overrides);
|
|
53
61
|
}
|
|
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
62
|
export function runInteractiveMode(runtime, context, options = {}) {
|
|
66
63
|
const terminal = options.terminal ?? processTerminal();
|
|
67
64
|
const ui = runtime.config.ui ?? {};
|
|
@@ -83,12 +80,14 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
83
80
|
...(ui.markdown !== undefined ? { markdown: ui.markdown } : {}),
|
|
84
81
|
...(ui.compact === true ? { compact: true } : {}),
|
|
85
82
|
});
|
|
83
|
+
const subagents = new SubagentTracker(now);
|
|
86
84
|
const tools = new ToolTracker({
|
|
87
85
|
theme,
|
|
88
86
|
cwd: session.state.cwd,
|
|
89
87
|
getTool: (name) => session.getTools().find((tool) => tool.name === name),
|
|
90
88
|
now,
|
|
91
89
|
spinner: () => loader.frame,
|
|
90
|
+
subagent: (toolCallId) => subagents.forToolCall(toolCallId),
|
|
92
91
|
});
|
|
93
92
|
const queueView = new QueueView(theme);
|
|
94
93
|
const loaderSlot = new Container();
|
|
@@ -100,19 +99,17 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
100
99
|
...(options.spinnerIntervalMs !== undefined ? { intervalMs: options.spinnerIntervalMs } : {}),
|
|
101
100
|
});
|
|
102
101
|
loader.onFrame(() => tools.tick());
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
const area = new StatusArea({
|
|
103
|
+
runtime,
|
|
104
|
+
theme,
|
|
106
105
|
session: () => session,
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
sandboxStrict: () => (sandboxStrict ??= detectSandboxCapability().strict),
|
|
115
|
-
}, theme);
|
|
106
|
+
now,
|
|
107
|
+
render: () => tui.requestRender(),
|
|
108
|
+
redraw: () => tui.forceFullRedraw(),
|
|
109
|
+
env,
|
|
110
|
+
...(options.statusLine !== undefined ? { layout: options.statusLine } : {}),
|
|
111
|
+
});
|
|
112
|
+
const { hint, bar: status } = area;
|
|
116
113
|
const historyFile = options.historyFile === false
|
|
117
114
|
? undefined
|
|
118
115
|
: (options.historyFile ?? join(runtime.paths.dataDir, "history"));
|
|
@@ -139,6 +136,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
139
136
|
tui.addChild(loaderSlot);
|
|
140
137
|
tui.addChild(editor);
|
|
141
138
|
tui.addChild(hint);
|
|
139
|
+
tui.addChild(area.rate);
|
|
142
140
|
tui.addChild(status);
|
|
143
141
|
// ---- 小工具 ---------------------------------------------------------------
|
|
144
142
|
let finished = false;
|
|
@@ -149,7 +147,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
149
147
|
view.addNotice(level, text);
|
|
150
148
|
render();
|
|
151
149
|
};
|
|
152
|
-
const showHint = (text) => {
|
|
150
|
+
const showHint = (text, ms = HINT_MS) => {
|
|
153
151
|
hint.setText(text === "" ? "" : theme.fg("dim", text));
|
|
154
152
|
if (hintTimer !== undefined)
|
|
155
153
|
clearTimeout(hintTimer);
|
|
@@ -158,7 +156,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
158
156
|
hintTimer = setTimeout(() => {
|
|
159
157
|
hint.setText("");
|
|
160
158
|
render();
|
|
161
|
-
},
|
|
159
|
+
}, ms);
|
|
162
160
|
hintTimer.unref?.();
|
|
163
161
|
}
|
|
164
162
|
render();
|
|
@@ -170,88 +168,18 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
170
168
|
render();
|
|
171
169
|
};
|
|
172
170
|
// ---- 会话事件 -------------------------------------------------------------
|
|
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
|
-
};
|
|
171
|
+
const onEvent = createSessionEventHandler({
|
|
172
|
+
view,
|
|
173
|
+
tools,
|
|
174
|
+
status,
|
|
175
|
+
area,
|
|
176
|
+
agentUi: () => agentUi,
|
|
177
|
+
indicator,
|
|
178
|
+
session: () => session,
|
|
179
|
+
setQueue,
|
|
180
|
+
notice,
|
|
181
|
+
render,
|
|
182
|
+
});
|
|
255
183
|
let unsubscribe = session.subscribe(onEvent);
|
|
256
184
|
const startupLevel = startupScreenLevel(runtime);
|
|
257
185
|
const home = env["HOME"] ?? env["USERPROFILE"];
|
|
@@ -282,7 +210,8 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
282
210
|
tools.clear();
|
|
283
211
|
replay();
|
|
284
212
|
setQueue([], []);
|
|
285
|
-
|
|
213
|
+
area.rebind();
|
|
214
|
+
agentUi.attach(next);
|
|
286
215
|
indicator.reset();
|
|
287
216
|
if (next instanceof AgentSessionImpl)
|
|
288
217
|
next.announceStart(reason);
|
|
@@ -292,12 +221,20 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
292
221
|
* 空闲时发提示。agent_settled 之后会话周期还要一个微任务才结束,所以先 waitForIdle;
|
|
293
222
|
* 仍然撞上运行中(极少)就排到本轮之后。
|
|
294
223
|
*/
|
|
224
|
+
let draftImages = [];
|
|
225
|
+
const resize = runtime.config.images?.resize;
|
|
226
|
+
const imageResize = resize !== undefined ? { resize } : {};
|
|
295
227
|
const startPrompt = (text) => {
|
|
296
228
|
const target = session;
|
|
229
|
+
const carried = draftImages;
|
|
230
|
+
draftImages = [];
|
|
297
231
|
void target
|
|
298
232
|
.waitForIdle()
|
|
299
233
|
.then(async () => {
|
|
300
|
-
const images =
|
|
234
|
+
const images = [
|
|
235
|
+
...carried,
|
|
236
|
+
...(await promptImages(text, [], target.state.cwd, sessionModel(runtime.providers, target), imageResize)),
|
|
237
|
+
];
|
|
301
238
|
return target.prompt(text, images.length > 0 ? { images } : {});
|
|
302
239
|
})
|
|
303
240
|
.catch((error) => {
|
|
@@ -312,6 +249,38 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
312
249
|
render();
|
|
313
250
|
});
|
|
314
251
|
};
|
|
252
|
+
/** 对话换了路径(/tree、回滚):重画消息区。内容可能缩到视口顶以上,差分画不对,整屏重画。 */
|
|
253
|
+
const reloadView = () => {
|
|
254
|
+
resetView();
|
|
255
|
+
tools.clear();
|
|
256
|
+
replay();
|
|
257
|
+
status.refresh();
|
|
258
|
+
area.refreshGit();
|
|
259
|
+
tui.forceFullRedraw();
|
|
260
|
+
};
|
|
261
|
+
const setDraft = (draft) => {
|
|
262
|
+
editor.setText(draft.text);
|
|
263
|
+
draftImages = [...(draft.images ?? [])];
|
|
264
|
+
render();
|
|
265
|
+
};
|
|
266
|
+
const pickerHost = {
|
|
267
|
+
theme,
|
|
268
|
+
keybindings: keys,
|
|
269
|
+
showOverlay: (c, o) => tui.showOverlay(c, o),
|
|
270
|
+
columns: () => terminal.columns,
|
|
271
|
+
rows: () => terminal.rows,
|
|
272
|
+
};
|
|
273
|
+
const rewind = createRewindFlow({
|
|
274
|
+
...pickerHost,
|
|
275
|
+
session: () => session,
|
|
276
|
+
now,
|
|
277
|
+
render,
|
|
278
|
+
notice,
|
|
279
|
+
hint: (text) => showHint(text),
|
|
280
|
+
reload: reloadView,
|
|
281
|
+
setDraft,
|
|
282
|
+
editorEmpty: () => editor.isEmpty(),
|
|
283
|
+
});
|
|
315
284
|
const commandUi = {
|
|
316
285
|
runtime,
|
|
317
286
|
session: () => session,
|
|
@@ -320,12 +289,9 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
320
289
|
rebind(next, request.kind === "new" ? "new" : request.kind === "fork" ? "fork" : "resume");
|
|
321
290
|
return next;
|
|
322
291
|
},
|
|
323
|
-
pick: (spec) => openPicker(
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
showOverlay: (c, o) => tui.showOverlay(c, o),
|
|
327
|
-
columns: () => terminal.columns,
|
|
328
|
-
}, spec),
|
|
292
|
+
pick: (spec) => openPicker(pickerHost, spec),
|
|
293
|
+
rewind: () => rewind.open(),
|
|
294
|
+
setDraft,
|
|
329
295
|
notice,
|
|
330
296
|
panel: (component) => {
|
|
331
297
|
view.add(component);
|
|
@@ -339,17 +305,14 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
339
305
|
render();
|
|
340
306
|
},
|
|
341
307
|
prompt: (text) => startPrompt(text),
|
|
342
|
-
reload:
|
|
343
|
-
resetView();
|
|
344
|
-
tools.clear();
|
|
345
|
-
replay();
|
|
346
|
-
status.refresh();
|
|
347
|
-
render();
|
|
348
|
-
},
|
|
308
|
+
reload: reloadView,
|
|
349
309
|
exit: (code) => exit(code),
|
|
350
310
|
now,
|
|
311
|
+
extra: (name, args) => agentUi.command(name, args),
|
|
351
312
|
};
|
|
352
|
-
const runCommand = (line) =>
|
|
313
|
+
const runCommand = (line) => (statusLineSlash(area, line, notice)
|
|
314
|
+
? Promise.resolve(true)
|
|
315
|
+
: runInteractiveCommand(line, commandUi)).finally(() => {
|
|
353
316
|
status.refresh();
|
|
354
317
|
render();
|
|
355
318
|
});
|
|
@@ -385,16 +348,15 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
385
348
|
now,
|
|
386
349
|
showHint,
|
|
387
350
|
onExpandToggle: (expanded) => view.setThinkingExpanded(expanded),
|
|
351
|
+
onStatusLineToggle: () => area.toggle(),
|
|
352
|
+
onPasteImage: () => void agentUi.paste(),
|
|
388
353
|
submit: (text, via) => submit(text, via),
|
|
389
354
|
runCommand: (line) => void runCommand(line),
|
|
390
355
|
exit: (code) => exit(code),
|
|
356
|
+
onInterrupted: (empty) => void rewind.afterInterrupt(empty),
|
|
391
357
|
}));
|
|
392
358
|
// ---- 晚绑定 ---------------------------------------------------------------
|
|
393
|
-
const
|
|
394
|
-
theme,
|
|
395
|
-
keybindings: keys,
|
|
396
|
-
cwd: session.state.cwd,
|
|
397
|
-
permissionMode: () => session.state.permissionMode,
|
|
359
|
+
const overlayHooks = {
|
|
398
360
|
showOverlay: (component) => tui.showOverlay(component, { anchor: "bottom" }),
|
|
399
361
|
onOpen: () => {
|
|
400
362
|
editor.disableSubmit = true;
|
|
@@ -406,12 +368,44 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
406
368
|
tools.setAwaiting(false);
|
|
407
369
|
indicator.setApproval(false);
|
|
408
370
|
},
|
|
371
|
+
};
|
|
372
|
+
const agentUi = new AgentUi({
|
|
373
|
+
theme,
|
|
374
|
+
tui,
|
|
375
|
+
editor,
|
|
376
|
+
tools: () => tools,
|
|
377
|
+
subagents,
|
|
378
|
+
session: () => session,
|
|
379
|
+
dataDir: runtime.paths.dataDir,
|
|
380
|
+
env,
|
|
381
|
+
now,
|
|
382
|
+
notice,
|
|
383
|
+
panel: (component) => commandUi.panel?.(component),
|
|
384
|
+
pick: (spec) => openPicker(pickerHost, spec),
|
|
385
|
+
hint: (text) => showHint(text),
|
|
386
|
+
render,
|
|
387
|
+
switchSession: (request) => commandUi.switchSession(request),
|
|
388
|
+
prompt: (text) => startPrompt(text),
|
|
389
|
+
dialog: { theme, keybindings: keys, ...overlayHooks },
|
|
390
|
+
displayPath: (path) => tildePath(path, home),
|
|
391
|
+
...(options.clipboard !== undefined ? { clipboard: options.clipboard } : {}),
|
|
392
|
+
});
|
|
393
|
+
const taskAgent = (taskId) => taskRegistryView(session.state.sessionId)?.get(taskId)?.agent;
|
|
394
|
+
const broker = mergingBroker(new ApprovalDialogBroker({
|
|
395
|
+
theme,
|
|
396
|
+
keybindings: keys,
|
|
397
|
+
cwd: session.state.cwd,
|
|
398
|
+
permissionMode: () => session.state.permissionMode,
|
|
399
|
+
taskAgent,
|
|
400
|
+
externalRunner: (agent) => agentUi.merge.externalRunner(agent),
|
|
401
|
+
...overlayHooks,
|
|
409
402
|
report: (request, outcome) => {
|
|
410
403
|
if (outcome === "deny" || outcome === "cancelled") {
|
|
411
|
-
|
|
404
|
+
const text = approvalOutcomeText(request, outcome, taskAgent);
|
|
405
|
+
notice(outcome === "deny" ? "info" : "warn", text);
|
|
412
406
|
}
|
|
413
407
|
},
|
|
414
|
-
});
|
|
408
|
+
}), agentUi.merge, (request) => notice("info", `${approvalOutcomeText(request, "allow", taskAgent)}(随上一次确认)`));
|
|
415
409
|
// ---- 启动与退出 -----------------------------------------------------------
|
|
416
410
|
let offSignals = () => undefined;
|
|
417
411
|
function exit(code) {
|
|
@@ -421,11 +415,13 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
421
415
|
if (hintTimer !== undefined)
|
|
422
416
|
clearTimeout(hintTimer);
|
|
423
417
|
loader.stop();
|
|
418
|
+
area.dispose();
|
|
424
419
|
// 退出摘要留在回滚里;输入框、状态栏等底部区域撤掉,屏幕停在摘要下面
|
|
425
420
|
view.addExitSummary(exitSummaryLines(session.getStats(), now() - startedAt, theme));
|
|
426
421
|
tui.clear();
|
|
427
422
|
tui.addChild(view);
|
|
428
423
|
offSignals();
|
|
424
|
+
agentUi.detach();
|
|
429
425
|
runtime.approvals.setUiBroker(undefined);
|
|
430
426
|
runtime.notifier.set(undefined);
|
|
431
427
|
tui.stop();
|
|
@@ -456,6 +452,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
456
452
|
}
|
|
457
453
|
runtime.approvals.setUiBroker(broker);
|
|
458
454
|
runtime.notifier.set((message, level) => notice(level, message));
|
|
455
|
+
agentUi.attach(session);
|
|
459
456
|
offSignals = onTerminationSignals((code) => exit(code));
|
|
460
457
|
tui.setFocus(editor);
|
|
461
458
|
options.onReady?.({
|
|
@@ -464,6 +461,7 @@ export function runInteractiveMode(runtime, context, options = {}) {
|
|
|
464
461
|
view,
|
|
465
462
|
tools,
|
|
466
463
|
status,
|
|
464
|
+
area,
|
|
467
465
|
session: () => session,
|
|
468
466
|
exit,
|
|
469
467
|
});
|
|
@@ -3,7 +3,12 @@
|
|
|
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";
|
|
9
14
|
import type { Editor, Keybindings } from "../../tui.js";
|
|
@@ -20,12 +25,21 @@ export interface KeyDispatchDeps {
|
|
|
20
25
|
/** 运行或压缩中(Esc 才中断)。 */
|
|
21
26
|
busy(): boolean;
|
|
22
27
|
now(): number;
|
|
23
|
-
|
|
28
|
+
/** 底部提示;`ms` 是停留时间(缺省由调用方决定)。 */
|
|
29
|
+
showHint(text: string, ms?: number): void;
|
|
24
30
|
/** Ctrl+O 之后(消息区思考块跟着展开 / 折叠)。 */
|
|
25
31
|
onExpandToggle?(expanded: boolean): void;
|
|
32
|
+
/** Ctrl+G:切换底部信息行,返回切换后的布局。 */
|
|
33
|
+
onStatusLineToggle?(): "full" | "compact";
|
|
34
|
+
/** Ctrl+V:粘贴剪贴板图片(W5-U)。 */
|
|
35
|
+
onPasteImage?(): void;
|
|
26
36
|
submit(text: string, via: "followUp"): void;
|
|
27
37
|
runCommand(line: string): void;
|
|
28
38
|
exit(code: number): void;
|
|
39
|
+
/** Esc 中断之后(参数:中断后输入框是否为空)。 */
|
|
40
|
+
onInterrupted?(editorWasEmpty: boolean): void;
|
|
41
|
+
/** 双击 Esc 的间隔(测试注入)。 */
|
|
42
|
+
doubleEscMs?: number;
|
|
29
43
|
}
|
|
30
44
|
/** 返回输入监听器:已处理返回 true,交给编辑器返回 false。 */
|
|
31
45
|
export declare function createKeyDispatch(deps: KeyDispatchDeps): (data: string) => boolean;
|
|
@@ -3,15 +3,46 @@
|
|
|
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 { ExitCode } from "../../cli/exit-codes.js";
|
|
9
14
|
import { nextCycleMode, permissionModeLabel } from "../../permissions/modes.js";
|
|
15
|
+
import { DOUBLE_ESC_HINT_MS, DoubleEscape } from "./double-esc.js";
|
|
16
|
+
import { statusLineText } from "./status-area.js";
|
|
10
17
|
const DOUBLE_CTRL_C_MS = 1500;
|
|
11
18
|
/** 返回输入监听器:已处理返回 true,交给编辑器返回 false。 */
|
|
12
19
|
export function createKeyDispatch(deps) {
|
|
13
20
|
const { keys, editor, tools, status } = deps;
|
|
14
21
|
let ctrlCArmedAt = Number.NEGATIVE_INFINITY;
|
|
22
|
+
const esc = new DoubleEscape(deps.doubleEscMs);
|
|
23
|
+
const doubleEscape = () => {
|
|
24
|
+
switch (esc.press(deps.now(), editor.isEmpty())) {
|
|
25
|
+
case "arm-rewind":
|
|
26
|
+
deps.showHint("再按 Esc 回滚", DOUBLE_ESC_HINT_MS);
|
|
27
|
+
return;
|
|
28
|
+
case "arm-clear":
|
|
29
|
+
deps.showHint("再按 Esc 清空", DOUBLE_ESC_HINT_MS);
|
|
30
|
+
return;
|
|
31
|
+
case "rewind":
|
|
32
|
+
deps.showHint("");
|
|
33
|
+
deps.runCommand("/rewind");
|
|
34
|
+
return;
|
|
35
|
+
case "clear": {
|
|
36
|
+
// 记进输入历史再清空:↑ 可取回
|
|
37
|
+
const text = editor.getExpandedText();
|
|
38
|
+
if (text.trim() !== "")
|
|
39
|
+
editor.addToHistory(text);
|
|
40
|
+
editor.clear();
|
|
41
|
+
deps.showHint("已清空输入 · ↑ 取回");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
15
46
|
const interrupt = () => {
|
|
16
47
|
const session = deps.session();
|
|
17
48
|
const queued = session.clearQueue();
|
|
@@ -48,6 +79,8 @@ export function createKeyDispatch(deps) {
|
|
|
48
79
|
if (deps.inactive())
|
|
49
80
|
return false;
|
|
50
81
|
const is = (action) => keys.matches(data, action);
|
|
82
|
+
if (!is("app.rewind"))
|
|
83
|
+
esc.reset();
|
|
51
84
|
if (is("app.clear")) {
|
|
52
85
|
if (!editor.isEmpty()) {
|
|
53
86
|
editor.clear();
|
|
@@ -65,8 +98,14 @@ export function createKeyDispatch(deps) {
|
|
|
65
98
|
}
|
|
66
99
|
ctrlCArmedAt = Number.NEGATIVE_INFINITY;
|
|
67
100
|
if (is("app.interrupt") && !editor.isCompletionOpen && deps.busy()) {
|
|
101
|
+
esc.reset();
|
|
68
102
|
interrupt();
|
|
69
103
|
deps.showHint("已中断");
|
|
104
|
+
deps.onInterrupted?.(editor.isEmpty());
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
if (is("app.rewind") && !editor.isCompletionOpen && !deps.busy()) {
|
|
108
|
+
doubleEscape();
|
|
70
109
|
return true;
|
|
71
110
|
}
|
|
72
111
|
if (is("app.exit") && editor.isEmpty()) {
|
|
@@ -101,6 +140,15 @@ export function createKeyDispatch(deps) {
|
|
|
101
140
|
deps.runCommand("/thinking");
|
|
102
141
|
return true;
|
|
103
142
|
}
|
|
143
|
+
if (is("app.paste.image") && deps.onPasteImage !== undefined) {
|
|
144
|
+
deps.onPasteImage();
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
if (is("app.statusLine.toggle") && deps.onStatusLineToggle !== undefined) {
|
|
148
|
+
const mode = deps.onStatusLineToggle();
|
|
149
|
+
deps.showHint(statusLineText(mode));
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
104
152
|
return false;
|
|
105
153
|
};
|
|
106
154
|
}
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* 问句之前逐行打印执行前预览(`request.preview`,W3-B9a-2)。
|
|
7
7
|
* - 否则(管道):逐行读 stdin,每行依次执行(等上一条运行结束);没有审批 UI,ask → deny。
|
|
8
8
|
* 模型错误在运行结束时只打印一次(重试中只显示 ↻);有运行最终失败时退出码 1。
|
|
9
|
-
* - 斜杠命令走 commands-core(与 B7 同一语义),`pick`
|
|
9
|
+
* - 斜杠命令走 commands-core(与 B7 同一语义),`pick` 退化为列出候选;`/rewind` 列编号、
|
|
10
|
+
* `/rewind <n> …` 执行,回到的单行原消息放回编辑行。
|
|
10
11
|
*/
|
|
11
12
|
import type { ModeContext } from "../../../cli/deps.js";
|
|
12
13
|
import type { Runtime } from "../../../cli/runtime.js";
|
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
* 问句之前逐行打印执行前预览(`request.preview`,W3-B9a-2)。
|
|
7
7
|
* - 否则(管道):逐行读 stdin,每行依次执行(等上一条运行结束);没有审批 UI,ask → deny。
|
|
8
8
|
* 模型错误在运行结束时只打印一次(重试中只显示 ↻);有运行最终失败时退出码 1。
|
|
9
|
-
* - 斜杠命令走 commands-core(与 B7 同一语义),`pick`
|
|
9
|
+
* - 斜杠命令走 commands-core(与 B7 同一语义),`pick` 退化为列出候选;`/rewind` 列编号、
|
|
10
|
+
* `/rewind <n> …` 执行,回到的单行原消息放回编辑行。
|
|
10
11
|
*/
|
|
11
12
|
import { promptImages, sessionModel } from "../../image-input.js";
|
|
13
|
+
import { taskRegistryView } from "../../../agent/subagent-registry.js";
|
|
12
14
|
import { currentSession, switchSession } from "../../../cli/compose-session.js";
|
|
13
15
|
import { ExitCode } from "../../../cli/exit-codes.js";
|
|
14
16
|
import { previewDisplayLines } from "../../../permissions/preview.js";
|
|
@@ -64,8 +66,21 @@ export async function runLineMode(runtime, context, options = {}) {
|
|
|
64
66
|
await prompt(session, result.text);
|
|
65
67
|
else if (result.kind === "pick")
|
|
66
68
|
out(`${await pickHint(result.what, runtime, session)}\n`);
|
|
67
|
-
else
|
|
68
|
-
|
|
69
|
+
else {
|
|
70
|
+
if (result.message !== undefined)
|
|
71
|
+
out(`${result.message}\n`);
|
|
72
|
+
// /rewind 回到某条消息之前:单行原消息放回编辑行(多行只在输出里给出)
|
|
73
|
+
const draft = result.draft?.text;
|
|
74
|
+
if (editor !== undefined && draft !== undefined && !draft.includes("\n")) {
|
|
75
|
+
editor.buffer = draft;
|
|
76
|
+
editor.cursor = draft.length;
|
|
77
|
+
}
|
|
78
|
+
// /plan approve 开了新回合:跑完再收下一行(与直接发提示一致)
|
|
79
|
+
if (result.wait === true) {
|
|
80
|
+
await session.waitForIdle();
|
|
81
|
+
printer.endLine();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
69
84
|
}
|
|
70
85
|
catch (error) {
|
|
71
86
|
printer.endLine();
|
|
@@ -75,7 +90,8 @@ export async function runLineMode(runtime, context, options = {}) {
|
|
|
75
90
|
return undefined;
|
|
76
91
|
};
|
|
77
92
|
const prompt = async (target, text) => {
|
|
78
|
-
const
|
|
93
|
+
const resize = runtime.config.images?.resize;
|
|
94
|
+
const images = await promptImages(text, [], target.state.cwd, sessionModel(runtime.providers, target), resize !== undefined ? { resize } : {});
|
|
79
95
|
await target.prompt(text, images.length > 0 ? { images } : {});
|
|
80
96
|
printer.endLine();
|
|
81
97
|
};
|
|
@@ -95,7 +111,8 @@ export async function runLineMode(runtime, context, options = {}) {
|
|
|
95
111
|
return resolve(undefined);
|
|
96
112
|
signal.addEventListener("abort", () => resolve(undefined), { once: true });
|
|
97
113
|
const preview = previewDisplayLines(request.preview).map((l) => ` ${l}\n`);
|
|
98
|
-
|
|
114
|
+
const question = approvalQuestion(request, (taskId) => taskRegistryView(session.state.sessionId)?.get(taskId)?.agent);
|
|
115
|
+
void ed.ask(`\n${preview.join("")}${question}`, "n").then((answer) => {
|
|
99
116
|
resolve(answer === "y" ? "allow" : answer === "a" ? "allow_session" : "deny");
|
|
100
117
|
if (!busy)
|
|
101
118
|
ed.render();
|
|
@@ -6,9 +6,10 @@ import type { AgentSession, SessionEvent } from "../../../agent/types.js";
|
|
|
6
6
|
import type { Runtime } from "../../../cli/runtime.js";
|
|
7
7
|
import type { ApprovalRequest } from "../../../permissions/types.js";
|
|
8
8
|
import type { CommandResult } from "../../commands-core.js";
|
|
9
|
+
import { type TaskAgentLookup } from "../approval-dialog.js";
|
|
9
10
|
/** 工具参数的一行摘要(第一个常见字段,折叠换行、截到 80 字符)。 */
|
|
10
11
|
export declare function argsSummary(args: unknown): string;
|
|
11
|
-
export declare function approvalQuestion(request: ApprovalRequest): string;
|
|
12
|
+
export declare function approvalQuestion(request: ApprovalRequest, taskAgent?: TaskAgentLookup): string;
|
|
12
13
|
/** [W3-C2] 缓存提示的开关(line 模式由 runLineMode 传入)。 */
|
|
13
14
|
export interface EventPrinterOptions {
|
|
14
15
|
/** `cache.missNotices`(每次现取,切换会话后跟随新会话);缺省 true。 */
|