@armadra/agent 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +257 -0
- package/README.md +263 -95
- package/THIRD_PARTY_NOTICES.md +34 -0
- package/dist/acp.d.ts +18 -0
- package/dist/acp.js +19 -0
- package/dist/agent/limits.d.ts +38 -0
- package/dist/agent/limits.js +127 -0
- package/dist/agent/loop-guard.d.ts +38 -0
- package/dist/agent/loop-guard.js +95 -0
- package/dist/agent/loop.d.ts +4 -0
- package/dist/agent/loop.js +7 -0
- package/dist/agent/prompt-rules.d.ts +12 -0
- package/dist/agent/prompt-rules.js +18 -0
- package/dist/agent/reminders.d.ts +59 -0
- package/dist/agent/reminders.js +327 -0
- package/dist/agent/retry.d.ts +1 -1
- package/dist/agent/retry.js +2 -1
- package/dist/agent/session-cache.d.ts +5 -0
- package/dist/agent/session-cache.js +18 -2
- package/dist/agent/session-classifier.d.ts +18 -0
- package/dist/agent/session-classifier.js +105 -0
- package/dist/agent/session-compaction.d.ts +35 -6
- package/dist/agent/session-compaction.js +157 -31
- package/dist/agent/session-core.d.ts +40 -1
- package/dist/agent/session-extensions.d.ts +61 -0
- package/dist/agent/session-extensions.js +129 -0
- package/dist/agent/session-images.d.ts +23 -0
- package/dist/agent/session-images.js +97 -0
- package/dist/agent/session-plan.d.ts +21 -0
- package/dist/agent/session-plan.js +524 -0
- package/dist/agent/session-rewind.d.ts +81 -0
- package/dist/agent/session-rewind.js +354 -0
- package/dist/agent/session-run.d.ts +28 -1
- package/dist/agent/session-run.js +157 -6
- package/dist/agent/session-settings.d.ts +49 -0
- package/dist/agent/session-settings.js +95 -0
- package/dist/agent/session-subagent.d.ts +36 -24
- package/dist/agent/session-subagent.js +259 -129
- package/dist/agent/session-sync.d.ts +10 -3
- package/dist/agent/session-sync.js +37 -8
- package/dist/agent/session-telemetry.d.ts +39 -0
- package/dist/agent/session-telemetry.js +231 -0
- package/dist/agent/session-tools.js +63 -3
- package/dist/agent/session.d.ts +33 -29
- package/dist/agent/session.js +91 -126
- package/dist/agent/subagent-registry.d.ts +91 -0
- package/dist/agent/subagent-registry.js +494 -0
- package/dist/agent/system-prompt.d.ts +6 -3
- package/dist/agent/system-prompt.js +7 -2
- package/dist/agent/tool-runner.d.ts +8 -1
- package/dist/agent/tool-runner.js +72 -6
- package/dist/agent/types-w5.d.ts +192 -0
- package/dist/agent/types-w5.js +10 -0
- package/dist/agent/types.d.ts +55 -4
- package/dist/agent/types.js +2 -0
- package/dist/agent/worktree.d.ts +36 -0
- package/dist/agent/worktree.js +86 -0
- package/dist/agents/builtin.d.ts +14 -0
- package/dist/agents/builtin.js +39 -0
- package/dist/agents/catalog.d.ts +43 -0
- package/dist/agents/catalog.js +82 -0
- package/dist/agents/discover.d.ts +35 -0
- package/dist/agents/discover.js +83 -0
- package/dist/agents/external.d.ts +82 -0
- package/dist/agents/external.js +326 -0
- package/dist/agents/parse.d.ts +18 -0
- package/dist/agents/parse.js +116 -0
- package/dist/agents/result.d.ts +32 -0
- package/dist/agents/result.js +67 -0
- package/dist/agents/task-control.d.ts +17 -0
- package/dist/agents/task-control.js +17 -0
- package/dist/agents/task-record.d.ts +78 -0
- package/dist/agents/task-record.js +141 -0
- package/dist/agents/types.d.ts +46 -0
- package/dist/agents/types.js +8 -0
- package/dist/ai/apis/anthropic-compat.d.ts +36 -0
- package/dist/ai/apis/anthropic-compat.js +92 -0
- package/dist/ai/apis/anthropic-messages.js +3 -2
- package/dist/ai/apis/anthropic-request.d.ts +7 -6
- package/dist/ai/apis/anthropic-request.js +10 -28
- package/dist/ai/apis/cache-params.d.ts +11 -2
- package/dist/ai/apis/cache-params.js +25 -6
- package/dist/ai/apis/google-generative-ai.js +3 -2
- package/dist/ai/apis/openai-compat.d.ts +4 -1
- package/dist/ai/apis/openai-compat.js +8 -1
- package/dist/ai/apis/openai-completions.js +3 -2
- package/dist/ai/apis/openai-responses.js +3 -2
- package/dist/ai/http.d.ts +28 -6
- package/dist/ai/http.js +41 -8
- package/dist/ai/image-limits.d.ts +45 -0
- package/dist/ai/image-limits.js +68 -0
- package/dist/ai/providers/builtin.d.ts +18 -6
- package/dist/ai/providers/builtin.js +135 -6
- package/dist/ai/providers/catalog-data.js +17 -13
- package/dist/ai/providers/catalog.d.ts +60 -7
- package/dist/ai/providers/catalog.js +197 -38
- package/dist/ai/providers/channels.d.ts +33 -3
- package/dist/ai/providers/channels.js +108 -7
- package/dist/ai/providers/enrich.d.ts +6 -3
- package/dist/ai/providers/enrich.js +19 -4
- package/dist/ai/providers/models-dev-cache.d.ts +28 -24
- package/dist/ai/providers/models-dev-cache.js +92 -78
- package/dist/ai/providers/models-dev-data.d.ts +7 -0
- package/dist/ai/providers/models-dev-data.js +32 -0
- package/dist/ai/providers/models-dev-snapshot.d.ts +50 -0
- package/dist/ai/providers/models-dev-snapshot.js +137 -0
- package/dist/ai/providers/models-dev.d.ts +51 -10
- package/dist/ai/providers/models-dev.js +132 -39
- package/dist/ai/providers/registry.d.ts +28 -11
- package/dist/ai/providers/registry.js +112 -65
- package/dist/ai/providers/suggest.d.ts +18 -0
- package/dist/ai/providers/suggest.js +72 -0
- package/dist/ai/sse.d.ts +6 -2
- package/dist/ai/sse.js +22 -2
- package/dist/ai/types.d.ts +37 -4
- package/dist/ai/types.js +5 -0
- package/dist/bundle/ama.cjs +41979 -21147
- package/dist/checkpoints/backend.d.ts +61 -0
- package/dist/checkpoints/backend.js +135 -0
- package/dist/checkpoints/blobs.d.ts +60 -0
- package/dist/checkpoints/blobs.js +203 -0
- package/dist/checkpoints/gc.d.ts +47 -0
- package/dist/checkpoints/gc.js +144 -0
- package/dist/checkpoints/git-head.d.ts +15 -0
- package/dist/checkpoints/git-head.js +89 -0
- package/dist/checkpoints/index.d.ts +17 -0
- package/dist/checkpoints/index.js +17 -0
- package/dist/checkpoints/replay.d.ts +48 -0
- package/dist/checkpoints/replay.js +154 -0
- package/dist/checkpoints/restore.d.ts +86 -0
- package/dist/checkpoints/restore.js +263 -0
- package/dist/checkpoints/settings.d.ts +14 -0
- package/dist/checkpoints/settings.js +23 -0
- package/dist/checkpoints/shadow-git.d.ts +108 -0
- package/dist/checkpoints/shadow-git.js +491 -0
- package/dist/checkpoints/shadow-restore.d.ts +25 -0
- package/dist/checkpoints/shadow-restore.js +128 -0
- package/dist/checkpoints/tracker.d.ts +64 -0
- package/dist/checkpoints/tracker.js +192 -0
- package/dist/checkpoints/types.d.ts +99 -0
- package/dist/checkpoints/types.js +12 -0
- package/dist/cli/args.d.ts +26 -7
- package/dist/cli/args.js +75 -82
- package/dist/cli/bootstrap.js +40 -4
- package/dist/cli/codemode-notice.d.ts +21 -0
- package/dist/cli/codemode-notice.js +56 -0
- package/dist/cli/compose-agents.d.ts +27 -0
- package/dist/cli/compose-agents.js +111 -0
- package/dist/cli/compose-extensions.d.ts +29 -0
- package/dist/cli/compose-extensions.js +44 -0
- package/dist/cli/compose-session.d.ts +8 -0
- package/dist/cli/compose-session.js +76 -2
- package/dist/cli/compose-store.d.ts +1 -1
- package/dist/cli/compose-store.js +3 -1
- package/dist/cli/compose.d.ts +17 -4
- package/dist/cli/compose.js +60 -14
- package/dist/cli/default-model.d.ts +38 -1
- package/dist/cli/default-model.js +96 -9
- package/dist/cli/deps.d.ts +42 -0
- package/dist/cli/exit-codes.d.ts +12 -0
- package/dist/cli/exit-codes.js +15 -0
- package/dist/cli/fake-visibility.d.ts +13 -0
- package/dist/cli/fake-visibility.js +26 -0
- package/dist/cli/from-prompt.d.ts +18 -0
- package/dist/cli/from-prompt.js +49 -0
- package/dist/cli/help-text.d.ts +4 -0
- package/dist/cli/help-text.js +102 -0
- package/dist/cli/main.d.ts +9 -2
- package/dist/cli/main.js +77 -3
- package/dist/cli/proxy.d.ts +51 -0
- package/dist/cli/proxy.js +135 -0
- package/dist/cli/startup-screen.d.ts +29 -0
- package/dist/cli/startup-screen.js +51 -2
- package/dist/cli/startup-steps.d.ts +1 -1
- package/dist/cli/startup-steps.js +21 -13
- package/dist/cli/subcommands/config.d.ts +22 -3
- package/dist/cli/subcommands/config.js +119 -21
- package/dist/cli/subcommands/context.js +4 -1
- package/dist/cli/subcommands/doctor.js +33 -1
- package/dist/cli/subcommands/init.js +2 -1
- package/dist/cli/subcommands/models-discover.d.ts +15 -9
- package/dist/cli/subcommands/models-discover.js +58 -52
- package/dist/cli/subcommands/models.d.ts +2 -0
- package/dist/cli/subcommands/models.js +33 -14
- package/dist/cli/subcommands/probe-runner.d.ts +96 -0
- package/dist/cli/subcommands/probe-runner.js +264 -0
- package/dist/cli/subcommands/providers-probe.d.ts +34 -0
- package/dist/cli/subcommands/providers-probe.js +87 -0
- package/dist/cli/subcommands/providers.d.ts +3 -2
- package/dist/cli/subcommands/providers.js +53 -51
- package/dist/cli/subcommands/sessions-export.d.ts +10 -0
- package/dist/cli/subcommands/sessions-export.js +59 -0
- package/dist/cli/subcommands/sessions-search.d.ts +13 -0
- package/dist/cli/subcommands/sessions-search.js +103 -0
- package/dist/cli/subcommands/sessions.d.ts +6 -3
- package/dist/cli/subcommands/sessions.js +58 -3
- package/dist/cli/subcommands/stats.d.ts +17 -0
- package/dist/cli/subcommands/stats.js +198 -0
- package/dist/cli/system-prompt-arg.d.ts +11 -0
- package/dist/cli/system-prompt-arg.js +34 -0
- package/dist/codemode/capability.d.ts +24 -7
- package/dist/codemode/capability.js +38 -10
- package/dist/codemode/host-side.d.ts +14 -0
- package/dist/codemode/host-side.js +24 -1
- package/dist/codemode/modes.d.ts +4 -11
- package/dist/codemode/modes.js +5 -27
- package/dist/codemode/tool.d.ts +18 -14
- package/dist/codemode/tool.js +76 -31
- package/dist/compaction/breaker.d.ts +25 -9
- package/dist/compaction/breaker.js +47 -17
- package/dist/compaction/estimate.d.ts +11 -3
- package/dist/compaction/estimate.js +64 -22
- package/dist/compaction/image-budget.d.ts +45 -0
- package/dist/compaction/image-budget.js +115 -0
- package/dist/compaction/post-compact.d.ts +38 -0
- package/dist/compaction/post-compact.js +152 -0
- package/dist/compaction/protect.d.ts +27 -0
- package/dist/compaction/protect.js +56 -0
- package/dist/compaction/prune-tier.d.ts +58 -12
- package/dist/compaction/prune-tier.js +120 -54
- package/dist/compaction/summarize-tier.d.ts +23 -4
- package/dist/compaction/summarize-tier.js +100 -29
- package/dist/config/checker.d.ts +28 -0
- package/dist/config/checker.js +97 -0
- package/dist/config/init.d.ts +6 -2
- package/dist/config/init.js +12 -5
- package/dist/config/json-schema.d.ts +1 -0
- package/dist/config/json-schema.js +98 -4
- package/dist/config/key-docs.d.ts +22 -0
- package/dist/config/key-docs.js +174 -0
- package/dist/config/merge.d.ts +12 -9
- package/dist/config/merge.js +102 -13
- package/dist/config/profile.d.ts +2 -0
- package/dist/config/profile.js +2 -0
- package/dist/config/schema-w5.d.ts +18 -0
- package/dist/config/schema-w5.js +109 -0
- package/dist/config/schema.d.ts +5 -9
- package/dist/config/schema.js +91 -118
- package/dist/config/types-w5.d.ts +118 -0
- package/dist/config/types-w5.js +20 -0
- package/dist/config/types.d.ts +84 -7
- package/dist/config/types.js +29 -1
- package/dist/drivers/acp/client.d.ts +57 -0
- package/dist/drivers/acp/client.js +160 -0
- package/dist/drivers/acp/driver.d.ts +31 -0
- package/dist/drivers/acp/driver.js +274 -0
- package/dist/drivers/acp/testing/fake-agent-main.d.ts +5 -0
- package/dist/drivers/acp/testing/fake-agent-main.js +7 -0
- package/dist/drivers/acp/testing/fake-agent.d.ts +27 -0
- package/dist/drivers/acp/testing/fake-agent.js +211 -0
- package/dist/drivers/acp/types.d.ts +285 -0
- package/dist/drivers/acp/types.js +36 -0
- package/dist/drivers/agents.d.ts +58 -0
- package/dist/drivers/agents.js +142 -0
- package/dist/drivers/base.d.ts +35 -0
- package/dist/drivers/base.js +59 -0
- package/dist/drivers/catalog.d.ts +46 -0
- package/dist/drivers/catalog.js +167 -0
- package/dist/drivers/env.d.ts +20 -0
- package/dist/drivers/env.js +46 -0
- package/dist/drivers/host-runners.d.ts +18 -0
- package/dist/drivers/host-runners.js +45 -0
- package/dist/drivers/jsonrpc.d.ts +58 -0
- package/dist/drivers/jsonrpc.js +180 -0
- package/dist/drivers/native/claude-normalize.d.ts +46 -0
- package/dist/drivers/native/claude-normalize.js +106 -0
- package/dist/drivers/native/claude-stream.d.ts +29 -0
- package/dist/drivers/native/claude-stream.js +456 -0
- package/dist/drivers/native/codex-app-server.d.ts +26 -0
- package/dist/drivers/native/codex-app-server.js +407 -0
- package/dist/drivers/native/codex-normalize.d.ts +38 -0
- package/dist/drivers/native/codex-normalize.js +124 -0
- package/dist/drivers/native/oneshot.d.ts +28 -0
- package/dist/drivers/native/oneshot.js +312 -0
- package/dist/drivers/permissions.d.ts +40 -0
- package/dist/drivers/permissions.js +92 -0
- package/dist/drivers/pids.d.ts +32 -0
- package/dist/drivers/pids.js +93 -0
- package/dist/drivers/pool.d.ts +28 -0
- package/dist/drivers/pool.js +96 -0
- package/dist/drivers/probe.d.ts +47 -0
- package/dist/drivers/probe.js +172 -0
- package/dist/drivers/process.d.ts +48 -0
- package/dist/drivers/process.js +100 -0
- package/dist/drivers/runner.d.ts +61 -0
- package/dist/drivers/runner.js +388 -0
- package/dist/drivers/store.d.ts +49 -0
- package/dist/drivers/store.js +91 -0
- package/dist/drivers/turn.d.ts +41 -0
- package/dist/drivers/turn.js +99 -0
- package/dist/drivers/types.d.ts +122 -0
- package/dist/drivers/types.js +11 -0
- package/dist/git/info.d.ts +75 -0
- package/dist/git/info.js +191 -0
- package/dist/hooks/protocol.js +6 -1
- package/dist/hooks/types.d.ts +10 -1
- package/dist/hooks/types.js +2 -0
- package/dist/host/api-impl.d.ts +7 -0
- package/dist/host/api-impl.js +15 -0
- package/dist/host/types.d.ts +24 -2
- package/dist/host/types.js +4 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -0
- package/dist/modes/acp/acp-events.d.ts +46 -0
- package/dist/modes/acp/acp-events.js +233 -0
- package/dist/modes/acp/acp-mode.d.ts +17 -0
- package/dist/modes/acp/acp-mode.js +47 -0
- package/dist/modes/acp/acp-server.d.ts +79 -0
- package/dist/modes/acp/acp-server.js +315 -0
- package/dist/modes/commands-core.d.ts +7 -1
- package/dist/modes/commands-core.js +61 -5
- package/dist/modes/image-input.d.ts +12 -4
- package/dist/modes/image-input.js +22 -5
- package/dist/modes/interactive/agent-panels.d.ts +14 -0
- package/dist/modes/interactive/agent-panels.js +103 -0
- package/dist/modes/interactive/agent-ui.d.ts +73 -0
- package/dist/modes/interactive/agent-ui.js +234 -0
- package/dist/modes/interactive/approval-dialog.d.ts +40 -7
- package/dist/modes/interactive/approval-dialog.js +192 -35
- package/dist/modes/interactive/approval-merge.d.ts +41 -0
- package/dist/modes/interactive/approval-merge.js +89 -0
- package/dist/modes/interactive/clipboard-paste.d.ts +18 -0
- package/dist/modes/interactive/clipboard-paste.js +28 -0
- package/dist/modes/interactive/commands.d.ts +20 -3
- package/dist/modes/interactive/commands.js +75 -16
- package/dist/modes/interactive/double-esc.d.ts +20 -0
- package/dist/modes/interactive/double-esc.js +34 -0
- package/dist/modes/interactive/event-notices.d.ts +32 -0
- package/dist/modes/interactive/event-notices.js +79 -0
- package/dist/modes/interactive/external-editor.d.ts +16 -0
- package/dist/modes/interactive/external-editor.js +39 -0
- package/dist/modes/interactive/interactive-mode.d.ts +16 -2
- package/dist/modes/interactive/interactive-mode.js +184 -202
- package/dist/modes/interactive/key-dispatch.d.ts +18 -2
- package/dist/modes/interactive/key-dispatch.js +53 -6
- package/dist/modes/interactive/line/line-mode.d.ts +3 -1
- package/dist/modes/interactive/line/line-mode.js +28 -9
- package/dist/modes/interactive/line/line-render.d.ts +6 -1
- package/dist/modes/interactive/line/line-render.js +66 -8
- package/dist/modes/interactive/message-view.d.ts +49 -10
- package/dist/modes/interactive/message-view.js +262 -46
- package/dist/modes/interactive/panels.d.ts +35 -0
- package/dist/modes/interactive/panels.js +157 -0
- package/dist/modes/interactive/pickers.d.ts +23 -2
- package/dist/modes/interactive/pickers.js +48 -15
- package/dist/modes/interactive/plan-command.d.ts +40 -0
- package/dist/modes/interactive/plan-command.js +129 -0
- package/dist/modes/interactive/plan-dialog.d.ts +98 -0
- package/dist/modes/interactive/plan-dialog.js +290 -0
- package/dist/modes/interactive/plan-flow.d.ts +34 -0
- package/dist/modes/interactive/plan-flow.js +98 -0
- package/dist/modes/interactive/rewind-command.d.ts +31 -0
- package/dist/modes/interactive/rewind-command.js +106 -0
- package/dist/modes/interactive/rewind-flow.d.ts +37 -0
- package/dist/modes/interactive/rewind-flow.js +151 -0
- package/dist/modes/interactive/rewind-list.d.ts +36 -0
- package/dist/modes/interactive/rewind-list.js +123 -0
- package/dist/modes/interactive/rewind-panel.d.ts +77 -0
- package/dist/modes/interactive/rewind-panel.js +309 -0
- package/dist/modes/interactive/rewind-text.d.ts +40 -0
- package/dist/modes/interactive/rewind-text.js +139 -0
- package/dist/modes/interactive/run-indicator.d.ts +51 -0
- package/dist/modes/interactive/run-indicator.js +189 -0
- package/dist/modes/interactive/session-events.d.ts +24 -0
- package/dist/modes/interactive/session-events.js +96 -0
- package/dist/modes/interactive/startup-header.d.ts +40 -0
- package/dist/modes/interactive/startup-header.js +169 -0
- package/dist/modes/interactive/status-area.d.ts +73 -0
- package/dist/modes/interactive/status-area.js +190 -0
- package/dist/modes/interactive/status-bar.d.ts +107 -16
- package/dist/modes/interactive/status-bar.js +306 -81
- package/dist/modes/interactive/status-line.d.ts +33 -0
- package/dist/modes/interactive/status-line.js +113 -0
- package/dist/modes/interactive/subagent-view.d.ts +56 -0
- package/dist/modes/interactive/subagent-view.js +154 -0
- package/dist/modes/interactive/tasks-report.d.ts +27 -0
- package/dist/modes/interactive/tasks-report.js +114 -0
- package/dist/modes/interactive/tool-summary.d.ts +46 -0
- package/dist/modes/interactive/tool-summary.js +218 -0
- package/dist/modes/interactive/tool-view.d.ts +58 -15
- package/dist/modes/interactive/tool-view.js +233 -145
- package/dist/modes/print/print-mode.d.ts +40 -4
- package/dist/modes/print/print-mode.js +161 -8
- package/dist/modes/rpc/commands.d.ts +9 -0
- package/dist/modes/rpc/commands.js +49 -0
- package/dist/modes/rpc/rpc-mode.js +7 -1
- package/dist/modes/session-report.d.ts +11 -0
- package/dist/modes/session-report.js +48 -1
- package/dist/permissions/auto-safe.d.ts +65 -0
- package/dist/permissions/auto-safe.js +547 -0
- package/dist/permissions/classifier.d.ts +68 -0
- package/dist/permissions/classifier.js +186 -0
- package/dist/permissions/dangerous.d.ts +5 -0
- package/dist/permissions/dangerous.js +1 -1
- package/dist/permissions/modes.d.ts +30 -0
- package/dist/permissions/modes.js +78 -0
- package/dist/permissions/pipeline.d.ts +72 -6
- package/dist/permissions/pipeline.js +306 -11
- package/dist/permissions/protected.d.ts +19 -0
- package/dist/permissions/protected.js +74 -0
- package/dist/permissions/readonly-bash.d.ts +30 -0
- package/dist/permissions/readonly-bash.js +118 -0
- package/dist/permissions/rules.js +3 -0
- package/dist/permissions/types.d.ts +92 -3
- package/dist/permissions/types.js +3 -0
- package/dist/plan/compose.d.ts +9 -0
- package/dist/plan/compose.js +19 -0
- package/dist/plan/controller.d.ts +71 -0
- package/dist/plan/controller.js +27 -0
- package/dist/plan/done-markers.d.ts +17 -0
- package/dist/plan/done-markers.js +51 -0
- package/dist/plan/extract.d.ts +29 -0
- package/dist/plan/extract.js +160 -0
- package/dist/plan/prompts.d.ts +36 -0
- package/dist/plan/prompts.js +89 -0
- package/dist/plan/store.d.ts +37 -0
- package/dist/plan/store.js +90 -0
- package/dist/rpc.d.ts +58 -2
- package/dist/rpc.js +7 -0
- package/dist/sandbox/bash.d.ts +74 -0
- package/dist/sandbox/bash.js +126 -0
- package/dist/sandbox/detect.d.ts +48 -0
- package/dist/sandbox/detect.js +149 -0
- package/dist/sandbox/index.d.ts +5 -0
- package/dist/sandbox/index.js +5 -0
- package/dist/sandbox/profile.d.ts +33 -0
- package/dist/sandbox/profile.js +76 -0
- package/dist/sandbox/wrap.d.ts +29 -0
- package/dist/sandbox/wrap.js +117 -0
- package/dist/sdk.d.ts +42 -5
- package/dist/sdk.js +34 -4
- package/dist/session/export.d.ts +32 -0
- package/dist/session/export.js +187 -0
- package/dist/session/redact.d.ts +15 -0
- package/dist/session/redact.js +55 -0
- package/dist/session/reuse.d.ts +33 -0
- package/dist/session/reuse.js +86 -0
- package/dist/session/scan.d.ts +34 -0
- package/dist/session/scan.js +140 -0
- package/dist/session/search.d.ts +52 -0
- package/dist/session/search.js +211 -0
- package/dist/session/stats-aggregate.d.ts +63 -0
- package/dist/session/stats-aggregate.js +163 -0
- package/dist/session/stats-index.d.ts +26 -0
- package/dist/session/stats-index.js +91 -0
- package/dist/session/stats-scan.d.ts +54 -0
- package/dist/session/stats-scan.js +236 -0
- package/dist/session/types.d.ts +3 -1
- package/dist/session/types.js +1 -0
- package/dist/skills/builtin.d.ts +31 -0
- package/dist/skills/builtin.js +109 -0
- package/dist/skills/discover.d.ts +2 -1
- package/dist/skills/index-prompt.js +5 -8
- package/dist/tools/background-jobs.d.ts +71 -0
- package/dist/tools/background-jobs.js +198 -0
- package/dist/tools/bash.d.ts +53 -1
- package/dist/tools/bash.js +158 -7
- package/dist/tools/clipboard-image.d.ts +44 -0
- package/dist/tools/clipboard-image.js +148 -0
- package/dist/tools/edit.d.ts +2 -0
- package/dist/tools/edit.js +18 -3
- package/dist/tools/image-file.d.ts +38 -3
- package/dist/tools/image-file.js +81 -10
- package/dist/tools/image-resize.d.ts +58 -0
- package/dist/tools/image-resize.js +97 -0
- package/dist/tools/presets.d.ts +40 -8
- package/dist/tools/presets.js +65 -19
- package/dist/tools/read.d.ts +5 -2
- package/dist/tools/read.js +13 -10
- package/dist/tools/registry.d.ts +7 -1
- package/dist/tools/registry.js +27 -4
- package/dist/tools/task-ctl.d.ts +22 -0
- package/dist/tools/task-ctl.js +116 -0
- package/dist/tools/task.d.ts +22 -10
- package/dist/tools/task.js +66 -26
- package/dist/tools/todo.d.ts +22 -2
- package/dist/tools/todo.js +58 -14
- package/dist/tools/truncate.d.ts +15 -0
- package/dist/tools/truncate.js +25 -0
- package/dist/tools/types.d.ts +113 -0
- package/dist/tools/types.js +5 -0
- package/dist/tools/write.js +3 -0
- package/dist/tui/component.d.ts +8 -2
- package/dist/tui/component.js +3 -1
- package/dist/tui/components/box.d.ts +6 -1
- package/dist/tui/components/box.js +16 -6
- package/dist/tui/components/card.d.ts +23 -0
- package/dist/tui/components/card.js +37 -0
- package/dist/tui/components/editor-history.d.ts +6 -0
- package/dist/tui/components/editor-history.js +45 -0
- package/dist/tui/components/editor-paste.d.ts +1 -1
- package/dist/tui/components/editor-paste.js +4 -4
- package/dist/tui/components/editor.d.ts +11 -5
- package/dist/tui/components/editor.js +52 -58
- package/dist/tui/components/key-value.d.ts +3 -0
- package/dist/tui/components/key-value.js +16 -6
- package/dist/tui/components/loader.d.ts +37 -7
- package/dist/tui/components/loader.js +84 -21
- package/dist/tui/components/markdown.d.ts +5 -1
- package/dist/tui/components/markdown.js +45 -21
- package/dist/tui/components/meter.d.ts +3 -3
- package/dist/tui/components/meter.js +13 -11
- package/dist/tui/components/select-list.d.ts +23 -1
- package/dist/tui/components/select-list.js +76 -13
- package/dist/tui/glyphs.d.ts +72 -0
- package/dist/tui/glyphs.js +118 -0
- package/dist/tui/keybindings.d.ts +5 -0
- package/dist/tui/keybindings.js +5 -0
- package/dist/tui/theme.d.ts +30 -6
- package/dist/tui/theme.js +103 -17
- package/dist/tui.d.ts +4 -2
- package/dist/tui.js +3 -1
- package/docs/acp.md +78 -0
- package/docs/agents.md +250 -0
- package/docs/codemode.md +28 -10
- package/docs/hooks.md +36 -32
- package/docs/permissions.md +212 -0
- package/docs/plan.md +107 -0
- package/docs/providers.md +261 -62
- package/docs/rewind-plan.md +181 -0
- package/docs/rpc.md +127 -40
- package/docs/sandbox.md +215 -0
- package/docs/session-format.md +43 -22
- package/docs/sessions.md +174 -0
- package/docs/tui-design.md +751 -0
- package/docs/tui.md +260 -64
- package/package.json +15 -2
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 按影子提交恢复代码(docs/rewind-plan.md §6)。[RW-D]
|
|
3
|
+
*
|
|
4
|
+
* 1. 把当前工作区写成树,与目标提交做 `diff-tree`:只处理有差异的文件,被忽略的文件不在两边的树里,不会被碰。
|
|
5
|
+
* 目标里有、当前树里没有但磁盘上还在的文件(现在被忽略了)跳过。
|
|
6
|
+
* 2. 每个差异文件交给 `restore.ts` 的 `restoreFile`,冲突与安全检查语义与 tools 模式相同:
|
|
7
|
+
* - 「已知」= 当前内容等于最近一个影子提交里的内容,或等于 ama 最后写入的、最近检查点记录的;
|
|
8
|
+
* 其余视为回合外的改动(冲突),缺省跳过。
|
|
9
|
+
* - 父目录应为 `realpath(cwd)/<相对目录>`(路径上有符号链接目录 → parent_moved)。
|
|
10
|
+
* - 目标是符号链接 / 子模块 → not_regular;目标 blob 超过 maxFileBytes → too_large。
|
|
11
|
+
* - 权限只在可执行位与目标不同时调整(git 只记 644 / 755),新建文件按目标的可执行位。
|
|
12
|
+
* 3. edit / write 跟踪的文件不在影子树里(cwd 外、被忽略)时,按 tools 的记录恢复。
|
|
13
|
+
*/
|
|
14
|
+
import { lstat, realpath } from "node:fs/promises";
|
|
15
|
+
import { isAbsolute, join } from "node:path";
|
|
16
|
+
import { DEFAULT_MAX_FILE_BYTES, hashBytes, keyToPath } from "./blobs.js";
|
|
17
|
+
import { latestCheckpoint } from "./replay.js";
|
|
18
|
+
import { emptyCodeResult, restoreCheckpoint, restoreFile, settleFile, } from "./restore.js";
|
|
19
|
+
import { MODE_ABSENT, MODE_EXECUTABLE, MODE_GITLINK, MODE_SYMLINK, } from "./shadow-git.js";
|
|
20
|
+
const IS_WINDOWS = process.platform === "win32";
|
|
21
|
+
/** 文件顺序上最后一个带影子提交的检查点。 */
|
|
22
|
+
export function latestShadowCommit(state) {
|
|
23
|
+
for (let i = state.order.length - 1; i >= 0; i--) {
|
|
24
|
+
const commit = state.byUserEntry.get(state.order[i])?.shadowCommit;
|
|
25
|
+
if (commit !== undefined)
|
|
26
|
+
return commit;
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
/** 目标检查点没有影子提交、或提交已不在影子仓库里时抛错(调用方回退到 tools)。 */
|
|
31
|
+
export async function restoreFromShadow(options) {
|
|
32
|
+
const { repo } = options;
|
|
33
|
+
const target = options.target.shadowCommit;
|
|
34
|
+
if (target === undefined)
|
|
35
|
+
throw new Error("检查点没有影子提交");
|
|
36
|
+
if (!(await repo.hasCommit(target)))
|
|
37
|
+
throw new Error(`影子提交 ${target.slice(0, 12)} 不存在`);
|
|
38
|
+
const maxBytes = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
|
|
39
|
+
const current = await repo.currentTree();
|
|
40
|
+
const changes = (await repo.diff(target, current)).filter((c) => c.oldMode !== MODE_GITLINK && c.newMode !== MODE_GITLINK);
|
|
41
|
+
const baseline = latestShadowCommit(options.state);
|
|
42
|
+
const changedSinceBaseline = baseline === undefined ? undefined : new Set((await repo.diff(baseline, current)).map(pathOf));
|
|
43
|
+
const blobs = await repo.readBlobs(changes.filter((c) => isRegularMode(c.oldMode)).map((c) => c.oldOid), maxBytes);
|
|
44
|
+
const realCwd = await realpath(options.cwd);
|
|
45
|
+
const latest = latestCheckpoint(options.state);
|
|
46
|
+
const result = emptyCodeResult();
|
|
47
|
+
const touched = [];
|
|
48
|
+
for (const change of changes) {
|
|
49
|
+
const key = change.path;
|
|
50
|
+
const abs = keyToPath(options.cwd, key);
|
|
51
|
+
const record = await targetRecord(change, abs, realCwd, blobs);
|
|
52
|
+
if (record === undefined)
|
|
53
|
+
continue;
|
|
54
|
+
const known = new Set();
|
|
55
|
+
const written = options.lastWritten?.get(abs);
|
|
56
|
+
if (written !== undefined)
|
|
57
|
+
known.add(written);
|
|
58
|
+
const latestRecord = latest?.files[key];
|
|
59
|
+
if (latestRecord !== undefined && latestRecord.skipped === undefined) {
|
|
60
|
+
known.add(latestRecord.blob);
|
|
61
|
+
}
|
|
62
|
+
const content = record.blob === null ? undefined : blobs.get(change.oldOid);
|
|
63
|
+
await settleFile(result, touched, key, abs, options, () => restoreFile(abs, record, {
|
|
64
|
+
dataDir: options.dataDir,
|
|
65
|
+
...(options.dryRun !== undefined ? { dryRun: options.dryRun } : {}),
|
|
66
|
+
...(options.onConflict !== undefined ? { onConflict: options.onConflict } : {}),
|
|
67
|
+
maxDiff: options.maxDiffBytes ?? maxBytes,
|
|
68
|
+
isKnown: (hash) => (changedSinceBaseline !== undefined && !changedSinceBaseline.has(key)) || known.has(hash),
|
|
69
|
+
load: async () => content,
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
// edit / write 跟踪、但不在影子树里的文件(cwd 外、被忽略):按 tools 的记录恢复
|
|
73
|
+
const covered = new Set([...(await repo.paths(target)), ...(await repo.paths(current))]);
|
|
74
|
+
const rest = [...options.state.earliest.keys()].filter((k) => isAbsolute(k) || !covered.has(k));
|
|
75
|
+
if (rest.length > 0) {
|
|
76
|
+
const extra = await restoreCheckpoint({ ...options, keys: rest });
|
|
77
|
+
merge(result, extra.result);
|
|
78
|
+
touched.push(...extra.touched);
|
|
79
|
+
}
|
|
80
|
+
return { result, touched };
|
|
81
|
+
}
|
|
82
|
+
function pathOf(change) {
|
|
83
|
+
return change.path;
|
|
84
|
+
}
|
|
85
|
+
function isRegularMode(mode) {
|
|
86
|
+
return mode.startsWith("100");
|
|
87
|
+
}
|
|
88
|
+
/** 目标提交里这个路径应有的状态;undefined = 不处理。 */
|
|
89
|
+
async function targetRecord(change, abs, realCwd, blobs) {
|
|
90
|
+
const slash = change.path.lastIndexOf("/");
|
|
91
|
+
const realParentDir = slash < 0 ? realCwd : join(realCwd, ...change.path.slice(0, slash).split("/"));
|
|
92
|
+
const info = await lstat(abs).catch(() => undefined);
|
|
93
|
+
if (change.newMode === MODE_ABSENT && info !== undefined) {
|
|
94
|
+
// 当前树里没有、磁盘上却有:现在被忽略了(或读不了),不碰
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
if (change.oldMode === MODE_ABSENT)
|
|
98
|
+
return { blob: null, realParentDir };
|
|
99
|
+
if (change.oldMode === MODE_SYMLINK || !isRegularMode(change.oldMode)) {
|
|
100
|
+
return { blob: null, skipped: "not_regular" };
|
|
101
|
+
}
|
|
102
|
+
const bytes = blobs.get(change.oldOid);
|
|
103
|
+
if (bytes === undefined)
|
|
104
|
+
return { blob: null, skipped: "too_large" };
|
|
105
|
+
const record = { blob: hashBytes(bytes), size: bytes.length, realParentDir };
|
|
106
|
+
const executable = change.oldMode === MODE_EXECUTABLE;
|
|
107
|
+
if (!IS_WINDOWS) {
|
|
108
|
+
if (info === undefined || !info.isFile())
|
|
109
|
+
record.mode = executable ? 0o755 : 0o644;
|
|
110
|
+
else {
|
|
111
|
+
const mode = info.mode & 0o7777;
|
|
112
|
+
const isExec = (mode & 0o111) !== 0;
|
|
113
|
+
if (isExec !== executable) {
|
|
114
|
+
record.mode = executable ? mode | ((mode & 0o444) >> 2) : mode & ~0o111;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return record;
|
|
119
|
+
}
|
|
120
|
+
function merge(into, from) {
|
|
121
|
+
into.restored.push(...from.restored);
|
|
122
|
+
into.deleted.push(...from.deleted);
|
|
123
|
+
into.conflicts.push(...from.conflicts);
|
|
124
|
+
into.skipped.push(...from.skipped);
|
|
125
|
+
into.failed.push(...from.failed);
|
|
126
|
+
into.insertions += from.insertions;
|
|
127
|
+
into.deletions += from.deletions;
|
|
128
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 检查点运行时状态(docs/rewind-plan.md §1.3、§2)。[RW-A]
|
|
3
|
+
*
|
|
4
|
+
* - `beforeWrite`:文件在任何检查点里都没出现过 → 备份当前内容、追加 `ama.checkpoint-track`、
|
|
5
|
+
* 加入已跟踪;出现过则什么都不做。失败只 warn,不抛(检查点是辅助,不能让编辑失败)。
|
|
6
|
+
* - `afterWrite`:记 `lastWritten`(ama 最后写入内容的 sha256,冲突检测用;只在内存)。
|
|
7
|
+
* - `snapshot(userEntryId)`:新回合用户消息落盘后,对每个已跟踪文件按 §2 第一行的规则重拍,追加
|
|
8
|
+
* `ama.checkpoint`。沿用判断:size / mode 与上一条一致且 mtime 早于记录时间减去
|
|
9
|
+
* `MTIME_GRANULARITY_MS`(文件系统时间戳粒度的余量);否则算哈希,相同仍沿用。
|
|
10
|
+
* - 只经注入的 `append(customType, data)` 写条目,不依赖会话实现。
|
|
11
|
+
*/
|
|
12
|
+
import { type LoadedCheckpoints } from "./replay.js";
|
|
13
|
+
import { type CheckpointData, type CheckpointHooks } from "./types.js";
|
|
14
|
+
/** mtime 粒度余量(FAT 2 s;其它文件系统更细)。 */
|
|
15
|
+
export declare const MTIME_GRANULARITY_MS = 2000;
|
|
16
|
+
export interface CheckpointTrackerOptions {
|
|
17
|
+
cwd: string;
|
|
18
|
+
dataDir: string;
|
|
19
|
+
/** 缺省 5 MiB。 */
|
|
20
|
+
maxFileBytes?: number;
|
|
21
|
+
/** 追加 custom 条目(`ama.checkpoint` / `ama.checkpoint-track`)。 */
|
|
22
|
+
append(customType: string, data: unknown): void;
|
|
23
|
+
/** 当前回合的用户消息 id;不给时用最近一次 `snapshot` 的 id。 */
|
|
24
|
+
currentTurn?(): string | undefined;
|
|
25
|
+
warn?(message: string): void;
|
|
26
|
+
/** 从会话条目重放的状态(`loadCheckpoints`);缺省为空。 */
|
|
27
|
+
initial?: LoadedCheckpoints;
|
|
28
|
+
/** 测试用。 */
|
|
29
|
+
now?(): number;
|
|
30
|
+
/** 测试用:读 HEAD(缺省 `readGitHead`)。 */
|
|
31
|
+
readHead?(cwd: string): Promise<{
|
|
32
|
+
head: string;
|
|
33
|
+
branch?: string;
|
|
34
|
+
} | undefined>;
|
|
35
|
+
}
|
|
36
|
+
export declare class CheckpointTracker implements CheckpointHooks {
|
|
37
|
+
readonly state: LoadedCheckpoints;
|
|
38
|
+
/** ama 最后一次写入后的内容哈希(绝对路径 → sha256)。 */
|
|
39
|
+
readonly lastWritten: Map<string, string>;
|
|
40
|
+
private readonly cwd;
|
|
41
|
+
private readonly dataDir;
|
|
42
|
+
private readonly maxFileBytes;
|
|
43
|
+
private readonly options;
|
|
44
|
+
private readonly inflight;
|
|
45
|
+
/** 记录的真实时间(键 → 毫秒);覆盖条目时间(条目时间晚于读取,不能用于沿用判断以外)。 */
|
|
46
|
+
private readonly recordedAt;
|
|
47
|
+
private lastSnapshotId;
|
|
48
|
+
constructor(options: CheckpointTrackerOptions);
|
|
49
|
+
/** 已跟踪文件的绝对路径。 */
|
|
50
|
+
get trackedFiles(): ReadonlySet<string>;
|
|
51
|
+
isTracked(absolutePath: string): boolean;
|
|
52
|
+
private now;
|
|
53
|
+
private warn;
|
|
54
|
+
private currentTurn;
|
|
55
|
+
beforeWrite(absolutePath: string): Promise<void>;
|
|
56
|
+
private track;
|
|
57
|
+
afterWrite(absolutePath: string, content: Uint8Array | string): void;
|
|
58
|
+
/** 新回合:重拍全部已跟踪文件,追加 `ama.checkpoint`,返回它。`extra.shadowCommit` 来自影子 git。 */
|
|
59
|
+
snapshot(userEntryId: string, extra?: {
|
|
60
|
+
shadowCommit?: string;
|
|
61
|
+
}): Promise<CheckpointData>;
|
|
62
|
+
private snapshotFile;
|
|
63
|
+
}
|
|
64
|
+
export declare function createCheckpointTracker(options: CheckpointTrackerOptions): CheckpointTracker;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 检查点运行时状态(docs/rewind-plan.md §1.3、§2)。[RW-A]
|
|
3
|
+
*
|
|
4
|
+
* - `beforeWrite`:文件在任何检查点里都没出现过 → 备份当前内容、追加 `ama.checkpoint-track`、
|
|
5
|
+
* 加入已跟踪;出现过则什么都不做。失败只 warn,不抛(检查点是辅助,不能让编辑失败)。
|
|
6
|
+
* - `afterWrite`:记 `lastWritten`(ama 最后写入内容的 sha256,冲突检测用;只在内存)。
|
|
7
|
+
* - `snapshot(userEntryId)`:新回合用户消息落盘后,对每个已跟踪文件按 §2 第一行的规则重拍,追加
|
|
8
|
+
* `ama.checkpoint`。沿用判断:size / mode 与上一条一致且 mtime 早于记录时间减去
|
|
9
|
+
* `MTIME_GRANULARITY_MS`(文件系统时间戳粒度的余量);否则算哈希,相同仍沿用。
|
|
10
|
+
* - 只经注入的 `append(customType, data)` 写条目,不依赖会话实现。
|
|
11
|
+
*/
|
|
12
|
+
import { lstat, readFile } from "node:fs/promises";
|
|
13
|
+
import { readGitHead } from "./git-head.js";
|
|
14
|
+
import { DEFAULT_MAX_FILE_BYTES, hashBytes, isNotFound, keyToPath, pathKey, putBlob, realParentOf, recordFile, } from "./blobs.js";
|
|
15
|
+
import { applyCheckpoint, applyTrack, emptyCheckpoints } from "./replay.js";
|
|
16
|
+
import { CHECKPOINT_CUSTOM_TYPE, CHECKPOINT_TRACK_CUSTOM_TYPE, } from "./types.js";
|
|
17
|
+
/** mtime 粒度余量(FAT 2 s;其它文件系统更细)。 */
|
|
18
|
+
export const MTIME_GRANULARITY_MS = 2_000;
|
|
19
|
+
export class CheckpointTracker {
|
|
20
|
+
state;
|
|
21
|
+
/** ama 最后一次写入后的内容哈希(绝对路径 → sha256)。 */
|
|
22
|
+
lastWritten = new Map();
|
|
23
|
+
cwd;
|
|
24
|
+
dataDir;
|
|
25
|
+
maxFileBytes;
|
|
26
|
+
options;
|
|
27
|
+
inflight = new Map();
|
|
28
|
+
/** 记录的真实时间(键 → 毫秒);覆盖条目时间(条目时间晚于读取,不能用于沿用判断以外)。 */
|
|
29
|
+
recordedAt = new Map();
|
|
30
|
+
lastSnapshotId;
|
|
31
|
+
constructor(options) {
|
|
32
|
+
this.options = options;
|
|
33
|
+
this.cwd = options.cwd;
|
|
34
|
+
this.dataDir = options.dataDir;
|
|
35
|
+
this.maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
|
|
36
|
+
this.state = options.initial ?? emptyCheckpoints();
|
|
37
|
+
this.lastSnapshotId = this.state.order[this.state.order.length - 1];
|
|
38
|
+
}
|
|
39
|
+
/** 已跟踪文件的绝对路径。 */
|
|
40
|
+
get trackedFiles() {
|
|
41
|
+
return new Set([...this.state.earliest.keys()].map((key) => keyToPath(this.cwd, key)));
|
|
42
|
+
}
|
|
43
|
+
isTracked(absolutePath) {
|
|
44
|
+
return this.state.earliest.has(pathKey(this.cwd, absolutePath));
|
|
45
|
+
}
|
|
46
|
+
now() {
|
|
47
|
+
return this.options.now?.() ?? Date.now();
|
|
48
|
+
}
|
|
49
|
+
warn(message) {
|
|
50
|
+
this.options.warn?.(message);
|
|
51
|
+
}
|
|
52
|
+
currentTurn() {
|
|
53
|
+
return this.options.currentTurn !== undefined
|
|
54
|
+
? this.options.currentTurn()
|
|
55
|
+
: this.lastSnapshotId;
|
|
56
|
+
}
|
|
57
|
+
async beforeWrite(absolutePath) {
|
|
58
|
+
const key = pathKey(this.cwd, absolutePath);
|
|
59
|
+
if (this.state.earliest.has(key))
|
|
60
|
+
return;
|
|
61
|
+
const pending = this.inflight.get(key);
|
|
62
|
+
if (pending !== undefined)
|
|
63
|
+
return pending;
|
|
64
|
+
const work = this.track(key, absolutePath).finally(() => this.inflight.delete(key));
|
|
65
|
+
this.inflight.set(key, work);
|
|
66
|
+
return work;
|
|
67
|
+
}
|
|
68
|
+
async track(key, absolutePath) {
|
|
69
|
+
try {
|
|
70
|
+
const { record, at } = await recordFile(absolutePath, {
|
|
71
|
+
dataDir: this.dataDir,
|
|
72
|
+
maxFileBytes: this.maxFileBytes,
|
|
73
|
+
});
|
|
74
|
+
if (this.state.earliest.has(key))
|
|
75
|
+
return;
|
|
76
|
+
const turn = this.currentTurn();
|
|
77
|
+
if (turn !== undefined) {
|
|
78
|
+
const data = { v: 1, userEntryId: turn, path: key, record };
|
|
79
|
+
this.options.append(CHECKPOINT_TRACK_CUSTOM_TYPE, data);
|
|
80
|
+
applyTrack(this.state, data, at);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// 没有回合(宿主未接 snapshot):只在内存里跟踪,下一次 snapshot 会把它收进检查点。
|
|
84
|
+
this.state.earliest.set(key, record);
|
|
85
|
+
this.state.latest.set(key, { record, at });
|
|
86
|
+
}
|
|
87
|
+
this.recordedAt.set(key, at);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
this.warn(`检查点:备份 ${key} 失败(${describe(error)}),本次写入不可回滚`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
afterWrite(absolutePath, content) {
|
|
94
|
+
try {
|
|
95
|
+
this.lastWritten.set(absolutePath, hashBytes(content));
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
this.warn(`检查点:记录 ${absolutePath} 的写入失败(${describe(error)})`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/** 新回合:重拍全部已跟踪文件,追加 `ama.checkpoint`,返回它。`extra.shadowCommit` 来自影子 git。 */
|
|
102
|
+
async snapshot(userEntryId, extra = {}) {
|
|
103
|
+
this.lastSnapshotId = userEntryId;
|
|
104
|
+
const files = {};
|
|
105
|
+
const times = new Map();
|
|
106
|
+
for (const key of [...this.state.earliest.keys()]) {
|
|
107
|
+
const previous = this.state.latest.get(key);
|
|
108
|
+
const prev = previous === undefined
|
|
109
|
+
? undefined
|
|
110
|
+
: { record: previous.record, at: this.recordedAt.get(key) ?? previous.at };
|
|
111
|
+
try {
|
|
112
|
+
const next = await this.snapshotFile(keyToPath(this.cwd, key), prev);
|
|
113
|
+
files[key] = next.record;
|
|
114
|
+
times.set(key, next.at);
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
this.warn(`检查点:快照 ${key} 失败(${describe(error)}),该文件回滚到此处时用更早的记录`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const data = { v: 1, userEntryId, files };
|
|
121
|
+
if (extra.shadowCommit !== undefined)
|
|
122
|
+
data.shadowCommit = extra.shadowCommit;
|
|
123
|
+
try {
|
|
124
|
+
const git = await (this.options.readHead ?? readGitHead)(this.cwd);
|
|
125
|
+
if (git !== undefined)
|
|
126
|
+
data.git = git;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// 读不到 HEAD 不影响检查点
|
|
130
|
+
}
|
|
131
|
+
this.options.append(CHECKPOINT_CUSTOM_TYPE, data);
|
|
132
|
+
applyCheckpoint(this.state, data, this.now());
|
|
133
|
+
for (const [key, at] of times)
|
|
134
|
+
this.recordedAt.set(key, at);
|
|
135
|
+
return data;
|
|
136
|
+
}
|
|
137
|
+
async snapshotFile(absolutePath, prev) {
|
|
138
|
+
const at = this.now();
|
|
139
|
+
let info;
|
|
140
|
+
try {
|
|
141
|
+
info = await lstat(absolutePath);
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
if (!isNotFound(error))
|
|
145
|
+
throw error;
|
|
146
|
+
if (prev !== undefined && prev.record.blob === null && prev.record.skipped === undefined)
|
|
147
|
+
return prev;
|
|
148
|
+
const realParentDir = await realParentOf(absolutePath);
|
|
149
|
+
return {
|
|
150
|
+
record: { blob: null, ...(realParentDir !== undefined ? { realParentDir } : {}) },
|
|
151
|
+
at,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
if (!info.isFile()) {
|
|
155
|
+
if (prev?.record.skipped === "not_regular")
|
|
156
|
+
return prev;
|
|
157
|
+
return { record: { blob: null, skipped: "not_regular" }, at };
|
|
158
|
+
}
|
|
159
|
+
const mode = info.mode & 0o7777;
|
|
160
|
+
const p = prev?.record;
|
|
161
|
+
const sameMeta = p !== undefined && p.blob !== null && p.size === info.size && p.mode === mode;
|
|
162
|
+
if (sameMeta && prev !== undefined && info.mtimeMs <= prev.at - MTIME_GRANULARITY_MS)
|
|
163
|
+
return prev;
|
|
164
|
+
const realParentDir = await realParentOf(absolutePath);
|
|
165
|
+
const base = {
|
|
166
|
+
mode,
|
|
167
|
+
size: info.size,
|
|
168
|
+
...(realParentDir !== undefined ? { realParentDir } : {}),
|
|
169
|
+
};
|
|
170
|
+
if (info.size > this.maxFileBytes) {
|
|
171
|
+
if (p?.skipped === "too_large" && p.size === info.size && p.mode === mode)
|
|
172
|
+
return prev;
|
|
173
|
+
return { record: { blob: null, ...base, skipped: "too_large" }, at };
|
|
174
|
+
}
|
|
175
|
+
const bytes = await readFile(absolutePath);
|
|
176
|
+
const hash = hashBytes(bytes);
|
|
177
|
+
if (p !== undefined &&
|
|
178
|
+
p.blob === hash &&
|
|
179
|
+
p.mode === mode &&
|
|
180
|
+
p.realParentDir === realParentDir) {
|
|
181
|
+
return { record: p, at };
|
|
182
|
+
}
|
|
183
|
+
await putBlob(this.dataDir, bytes, hash);
|
|
184
|
+
return { record: { blob: hash, ...base, size: bytes.length }, at };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
export function createCheckpointTracker(options) {
|
|
188
|
+
return new CheckpointTracker(options);
|
|
189
|
+
}
|
|
190
|
+
function describe(error) {
|
|
191
|
+
return error instanceof Error ? error.message : String(error);
|
|
192
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 检查点与回滚契约(docs/rewind-plan.md §1、§3)。契约文件,实现归 RW-A(`src/checkpoints/**`)
|
|
3
|
+
* 与 RW-B(`src/agent/session-rewind.ts`)。
|
|
4
|
+
*
|
|
5
|
+
* - 会话条目两类,均为 `custom`(不进上下文):`ama.checkpoint`(新回合的用户消息之后)与
|
|
6
|
+
* `ama.checkpoint-track`(回合中途第一次碰某文件,补进本回合检查点)。
|
|
7
|
+
* - 备份按内容 sha256 存 `<dataDir>/file-history/blobs/<前 2 位>/<全长>`,会话只记哈希。
|
|
8
|
+
* - 路径键:cwd 内为相对路径(`/` 分隔),cwd 外为绝对路径。
|
|
9
|
+
*/
|
|
10
|
+
import type { ImageBlock } from "../ai/types.js";
|
|
11
|
+
export declare const CHECKPOINT_CUSTOM_TYPE = "ama.checkpoint";
|
|
12
|
+
export declare const CHECKPOINT_TRACK_CUSTOM_TYPE = "ama.checkpoint-track";
|
|
13
|
+
export declare const REWIND_NOTE_CUSTOM_TYPE = "ama.rewind-note";
|
|
14
|
+
export type CheckpointMode = "tools" | "shadow-git" | "off";
|
|
15
|
+
export interface FileRecord {
|
|
16
|
+
/** 内容 sha256;null = 当时文件不存在(回滚时删除)。 */
|
|
17
|
+
blob: string | null;
|
|
18
|
+
/** 普通文件的权限位。 */
|
|
19
|
+
mode?: number;
|
|
20
|
+
size?: number;
|
|
21
|
+
/** 记录时父目录的 realpath;恢复时校验没被移动。 */
|
|
22
|
+
realParentDir?: string;
|
|
23
|
+
/** 记录时取不到内容的原因;回滚时报告「无法恢复」。 */
|
|
24
|
+
skipped?: "too_large" | "not_regular";
|
|
25
|
+
}
|
|
26
|
+
export interface CheckpointData {
|
|
27
|
+
v: 1;
|
|
28
|
+
/** 这个检查点属于哪条用户消息:记的是「这条消息发出前」的状态。 */
|
|
29
|
+
userEntryId: string;
|
|
30
|
+
files: Record<string, FileRecord>;
|
|
31
|
+
/** 直接读 .git/HEAD 得到;cwd 不在 git 仓库里时省略。 */
|
|
32
|
+
git?: {
|
|
33
|
+
head: string;
|
|
34
|
+
branch?: string;
|
|
35
|
+
};
|
|
36
|
+
/** `checkpoints.mode: "shadow-git"` 时的影子仓库提交 id(RW-D)。 */
|
|
37
|
+
shadowCommit?: string;
|
|
38
|
+
}
|
|
39
|
+
export interface CheckpointTrackData {
|
|
40
|
+
v: 1;
|
|
41
|
+
userEntryId: string;
|
|
42
|
+
path: string;
|
|
43
|
+
record: FileRecord;
|
|
44
|
+
}
|
|
45
|
+
/** 交给工具的接口:edit / write 写文件前后各调一次。可选——宿主或内存会话没有时为 undefined。 */
|
|
46
|
+
export interface CheckpointHooks {
|
|
47
|
+
/** 写之前:文件第一次被跟踪时备份当前内容。失败只记 warn,不抛。 */
|
|
48
|
+
beforeWrite(absolutePath: string): Promise<void>;
|
|
49
|
+
/** 写之后:记下 ama 最后写入的内容(冲突检测用)。 */
|
|
50
|
+
afterWrite(absolutePath: string, content: Uint8Array | string): void;
|
|
51
|
+
}
|
|
52
|
+
export type RewindMode = "both" | "conversation" | "code";
|
|
53
|
+
export interface RewindPoint {
|
|
54
|
+
entryId: string;
|
|
55
|
+
text: string;
|
|
56
|
+
timestamp: number;
|
|
57
|
+
/** 没有检查点(内存会话、检查点关闭、超出保留数)时只能仅对话。 */
|
|
58
|
+
hasCheckpoint: boolean;
|
|
59
|
+
}
|
|
60
|
+
export interface RewindRequest {
|
|
61
|
+
entryId: string;
|
|
62
|
+
mode: RewindMode;
|
|
63
|
+
/** 只返回预览,不改任何东西。 */
|
|
64
|
+
dryRun?: boolean;
|
|
65
|
+
/** 冲突文件的处理;缺省 skip。 */
|
|
66
|
+
onConflict?: "skip" | "overwrite";
|
|
67
|
+
}
|
|
68
|
+
export type RewindSkipReason = "symlink" | "hardlink" | "not_regular" | "parent_moved" | "too_large" | "backup_missing";
|
|
69
|
+
export interface CodeRestoreResult {
|
|
70
|
+
restored: string[];
|
|
71
|
+
deleted: string[];
|
|
72
|
+
/** 冲突文件:skip 时未动,overwrite 时已覆盖。 */
|
|
73
|
+
conflicts: string[];
|
|
74
|
+
skipped: {
|
|
75
|
+
path: string;
|
|
76
|
+
reason: RewindSkipReason;
|
|
77
|
+
}[];
|
|
78
|
+
failed: {
|
|
79
|
+
path: string;
|
|
80
|
+
message: string;
|
|
81
|
+
}[];
|
|
82
|
+
insertions: number;
|
|
83
|
+
deletions: number;
|
|
84
|
+
}
|
|
85
|
+
export interface RewindResult {
|
|
86
|
+
conversation?: {
|
|
87
|
+
leafId: string | null;
|
|
88
|
+
draft: {
|
|
89
|
+
text: string;
|
|
90
|
+
images?: ImageBlock[];
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
code?: CodeRestoreResult;
|
|
94
|
+
/** 记录的 HEAD 与当前不同时给出;只提示,不操作 git。 */
|
|
95
|
+
gitHint?: {
|
|
96
|
+
recordedHead: string;
|
|
97
|
+
currentHead: string;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 检查点与回滚契约(docs/rewind-plan.md §1、§3)。契约文件,实现归 RW-A(`src/checkpoints/**`)
|
|
3
|
+
* 与 RW-B(`src/agent/session-rewind.ts`)。
|
|
4
|
+
*
|
|
5
|
+
* - 会话条目两类,均为 `custom`(不进上下文):`ama.checkpoint`(新回合的用户消息之后)与
|
|
6
|
+
* `ama.checkpoint-track`(回合中途第一次碰某文件,补进本回合检查点)。
|
|
7
|
+
* - 备份按内容 sha256 存 `<dataDir>/file-history/blobs/<前 2 位>/<全长>`,会话只记哈希。
|
|
8
|
+
* - 路径键:cwd 内为相对路径(`/` 分隔),cwd 外为绝对路径。
|
|
9
|
+
*/
|
|
10
|
+
export const CHECKPOINT_CUSTOM_TYPE = "ama.checkpoint";
|
|
11
|
+
export const CHECKPOINT_TRACK_CUSTOM_TYPE = "ama.checkpoint-track";
|
|
12
|
+
export const REWIND_NOTE_CUSTOM_TYPE = "ama.rewind-note";
|
package/dist/cli/args.d.ts
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* 手写参数解析(设计 §11.1 第 2 步、§12.10、§13)。[B5]
|
|
3
3
|
*
|
|
4
4
|
* - 支持 `--opt value` 与 `--opt=value`;`--` 之后全部作为提示文本;可重复的参数累加。
|
|
5
|
+
* - 位置参数 `-`:`-p` 一直等 stdin 到 EOF(有提示参数时也不设首字节超时)。
|
|
5
6
|
* - 子命令只在第一个参数是 `auth / sessions / models / providers / doctor / config / init` 时识别,
|
|
6
7
|
* 其余参数原样交给子命令。
|
|
7
|
-
* - 互斥:`-p` 与 `--mode rpc`;`--continue` / `--resume` / `--session-id` / `--fork` 两两互斥;
|
|
8
|
+
* - 互斥:`-p` 与 `--mode rpc / acp`;`--continue` / `--resume` / `--session-id` / `--fork` 两两互斥;
|
|
8
9
|
* `--trust` 与 `--no-trust`;`--api-key` 需要 `--model`;`--output-format` 需要 `-p`。
|
|
9
10
|
* - `--resume [id]`:下一个参数形如会话 id(无空白、不以 `-` 开头)才被当作 id;
|
|
10
11
|
* 否则仍作为提示文本。显式写法 `--resume=<id>`。
|
|
@@ -12,9 +13,9 @@
|
|
|
12
13
|
*/
|
|
13
14
|
import { AmaError } from "../errors.js";
|
|
14
15
|
import type { ModelThinkingLevel } from "../ai/types.js";
|
|
15
|
-
import type
|
|
16
|
-
import type
|
|
17
|
-
export declare const SUBCOMMANDS: readonly ["auth", "sessions", "models", "providers", "doctor", "config", "init"];
|
|
16
|
+
import { type PermissionMode } from "../permissions/types.js";
|
|
17
|
+
import { type CodemodeMode, type ToolsPreset } from "../config/types.js";
|
|
18
|
+
export declare const SUBCOMMANDS: readonly ["auth", "sessions", "models", "providers", "doctor", "config", "init", "stats"];
|
|
18
19
|
export type SubcommandName = (typeof SUBCOMMANDS)[number];
|
|
19
20
|
export type OutputFormat = "text" | "json" | "stream-json";
|
|
20
21
|
export type QuietStartup = "normal" | "header" | "silent";
|
|
@@ -42,8 +43,8 @@ export interface ParsedArgs {
|
|
|
42
43
|
sessionDir?: string;
|
|
43
44
|
print: boolean;
|
|
44
45
|
outputFormat?: OutputFormat;
|
|
45
|
-
/** `--mode rpc
|
|
46
|
-
mode?: "rpc";
|
|
46
|
+
/** `--mode rpc`;[W5-C0] `--mode acp`(ACP 服务端,W5-E 实现前报「尚未实现」)。 */
|
|
47
|
+
mode?: "rpc" | "acp";
|
|
47
48
|
noTui: boolean;
|
|
48
49
|
tuiMode?: "regular";
|
|
49
50
|
quietStartup?: QuietStartup;
|
|
@@ -55,8 +56,26 @@ export interface ParsedArgs {
|
|
|
55
56
|
toolsPreset?: ToolsPreset;
|
|
56
57
|
/** `--codemode`:覆盖 config `codemode.mode`。 */
|
|
57
58
|
codemode?: CodemodeMode;
|
|
59
|
+
/** `--no-session`:会话只在内存里,不写会话文件。 */
|
|
60
|
+
noSession: boolean;
|
|
61
|
+
/** `--system-prompt <文本|@文件>`:缺省追加进系统提示的 rules 节。 */
|
|
62
|
+
systemPrompt?: string;
|
|
63
|
+
/** `--system-prompt-mode`:append(缺省)| replace(替换开头的 preamble)。 */
|
|
64
|
+
systemPromptMode?: "append" | "replace";
|
|
65
|
+
/** `--max-turns N`(只用于 -p):一次运行最多 N 轮(模型请求 + 工具执行算一轮)。 */
|
|
66
|
+
maxTurns?: number;
|
|
67
|
+
/** [W5-C0] `--max-cost USD`:一次运行的美元上限(W5-H2 实现前只透传并提示未生效)。 */
|
|
68
|
+
maxCostUsd?: number;
|
|
69
|
+
/** [W5-C0] `--agent-dir <目录>`(可重复):子 Agent 定义目录(W5-G 实现前只透传)。 */
|
|
70
|
+
agentDirs?: string[];
|
|
71
|
+
/** 位置参数 `-`(只用于 -p):一直等 stdin 到 EOF,不设首字节超时。 */
|
|
72
|
+
stdin: boolean;
|
|
73
|
+
/** `--no-stdin`(只用于 -p):不读 stdin。 */
|
|
74
|
+
noStdin: boolean;
|
|
58
75
|
/** `--image <文件>`(可重复,只用于 -p):随首条提示发送的图片。 */
|
|
59
76
|
images: string[];
|
|
77
|
+
/** `--from <会话 id>[#编号]`:用旧会话的一条用户消息作为提示(cli/from-prompt.ts)。 */
|
|
78
|
+
from?: string;
|
|
60
79
|
/** 位置参数拼成的提示(空格连接)。 */
|
|
61
80
|
prompt?: string;
|
|
62
81
|
/** 原始位置参数。 */
|
|
@@ -73,7 +92,7 @@ export type ParseResult = {
|
|
|
73
92
|
export declare class UsageError extends AmaError {
|
|
74
93
|
constructor(message: string);
|
|
75
94
|
}
|
|
76
|
-
export
|
|
95
|
+
export { HELP_TEXT } from "./help-text.js";
|
|
77
96
|
export declare function emptyArgs(): ParsedArgs;
|
|
78
97
|
/** 解析 argv(不含 node 与脚本路径);用法错误抛 UsageError(退出码 2)。 */
|
|
79
98
|
export declare function parseArgs(argv: readonly string[]): ParseResult;
|