@armadra/agent 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +184 -1
- package/README.md +202 -83
- package/THIRD_PARTY_NOTICES.md +34 -0
- package/dist/acp.d.ts +18 -0
- package/dist/acp.js +19 -0
- package/dist/agent/limits.d.ts +38 -0
- package/dist/agent/limits.js +127 -0
- package/dist/agent/loop-guard.d.ts +38 -0
- package/dist/agent/loop-guard.js +95 -0
- package/dist/agent/loop.d.ts +4 -0
- package/dist/agent/loop.js +7 -0
- package/dist/agent/prompt-rules.d.ts +12 -0
- package/dist/agent/prompt-rules.js +18 -0
- package/dist/agent/reminders.d.ts +59 -0
- package/dist/agent/reminders.js +327 -0
- package/dist/agent/session-cache.d.ts +5 -0
- package/dist/agent/session-cache.js +17 -1
- package/dist/agent/session-classifier.d.ts +1 -1
- package/dist/agent/session-classifier.js +3 -1
- package/dist/agent/session-compaction.d.ts +35 -6
- package/dist/agent/session-compaction.js +157 -31
- package/dist/agent/session-core.d.ts +27 -1
- package/dist/agent/session-extensions.d.ts +61 -0
- package/dist/agent/session-extensions.js +129 -0
- package/dist/agent/session-images.d.ts +23 -0
- package/dist/agent/session-images.js +97 -0
- package/dist/agent/session-plan.d.ts +21 -0
- package/dist/agent/session-plan.js +524 -0
- package/dist/agent/session-rewind.d.ts +81 -0
- package/dist/agent/session-rewind.js +354 -0
- package/dist/agent/session-run.d.ts +28 -1
- package/dist/agent/session-run.js +157 -6
- package/dist/agent/session-settings.d.ts +49 -0
- package/dist/agent/session-settings.js +95 -0
- package/dist/agent/session-subagent.d.ts +36 -24
- package/dist/agent/session-subagent.js +259 -129
- package/dist/agent/session-sync.d.ts +10 -3
- package/dist/agent/session-sync.js +37 -8
- package/dist/agent/session-telemetry.d.ts +39 -0
- package/dist/agent/session-telemetry.js +231 -0
- package/dist/agent/session-tools.js +40 -1
- package/dist/agent/session.d.ts +30 -29
- package/dist/agent/session.js +79 -123
- package/dist/agent/subagent-registry.d.ts +91 -0
- package/dist/agent/subagent-registry.js +494 -0
- package/dist/agent/system-prompt.d.ts +6 -3
- package/dist/agent/system-prompt.js +7 -2
- package/dist/agent/tool-runner.d.ts +8 -1
- package/dist/agent/tool-runner.js +57 -4
- package/dist/agent/types-w5.d.ts +192 -0
- package/dist/agent/types-w5.js +10 -0
- package/dist/agent/types.d.ts +47 -4
- package/dist/agent/types.js +2 -0
- package/dist/agent/worktree.d.ts +36 -0
- package/dist/agent/worktree.js +86 -0
- package/dist/agents/builtin.d.ts +14 -0
- package/dist/agents/builtin.js +39 -0
- package/dist/agents/catalog.d.ts +43 -0
- package/dist/agents/catalog.js +82 -0
- package/dist/agents/discover.d.ts +35 -0
- package/dist/agents/discover.js +83 -0
- package/dist/agents/external.d.ts +82 -0
- package/dist/agents/external.js +326 -0
- package/dist/agents/parse.d.ts +18 -0
- package/dist/agents/parse.js +116 -0
- package/dist/agents/result.d.ts +32 -0
- package/dist/agents/result.js +67 -0
- package/dist/agents/task-control.d.ts +17 -0
- package/dist/agents/task-control.js +17 -0
- package/dist/agents/task-record.d.ts +78 -0
- package/dist/agents/task-record.js +141 -0
- package/dist/agents/types.d.ts +46 -0
- package/dist/agents/types.js +8 -0
- package/dist/ai/apis/anthropic-compat.d.ts +36 -0
- package/dist/ai/apis/anthropic-compat.js +92 -0
- package/dist/ai/apis/anthropic-request.d.ts +7 -6
- package/dist/ai/apis/anthropic-request.js +10 -28
- package/dist/ai/apis/cache-params.d.ts +11 -2
- package/dist/ai/apis/cache-params.js +25 -6
- package/dist/ai/apis/openai-compat.d.ts +4 -1
- package/dist/ai/apis/openai-compat.js +8 -1
- package/dist/ai/image-limits.d.ts +45 -0
- package/dist/ai/image-limits.js +68 -0
- package/dist/ai/providers/builtin.d.ts +18 -6
- package/dist/ai/providers/builtin.js +135 -6
- package/dist/ai/providers/catalog-data.js +17 -13
- package/dist/ai/providers/catalog.d.ts +60 -7
- package/dist/ai/providers/catalog.js +197 -38
- package/dist/ai/providers/channels.d.ts +33 -3
- package/dist/ai/providers/channels.js +108 -7
- package/dist/ai/providers/enrich.d.ts +6 -3
- package/dist/ai/providers/enrich.js +19 -4
- package/dist/ai/providers/models-dev-cache.d.ts +28 -24
- package/dist/ai/providers/models-dev-cache.js +92 -78
- package/dist/ai/providers/models-dev-data.d.ts +7 -0
- package/dist/ai/providers/models-dev-data.js +32 -0
- package/dist/ai/providers/models-dev-snapshot.d.ts +50 -0
- package/dist/ai/providers/models-dev-snapshot.js +137 -0
- package/dist/ai/providers/models-dev.d.ts +51 -10
- package/dist/ai/providers/models-dev.js +132 -39
- package/dist/ai/providers/registry.d.ts +20 -10
- package/dist/ai/providers/registry.js +82 -43
- package/dist/ai/types.d.ts +28 -2
- package/dist/ai/types.js +5 -0
- package/dist/bundle/ama.cjs +37605 -21619
- package/dist/checkpoints/backend.d.ts +61 -0
- package/dist/checkpoints/backend.js +135 -0
- package/dist/checkpoints/blobs.d.ts +60 -0
- package/dist/checkpoints/blobs.js +203 -0
- package/dist/checkpoints/gc.d.ts +47 -0
- package/dist/checkpoints/gc.js +144 -0
- package/dist/checkpoints/git-head.d.ts +15 -0
- package/dist/checkpoints/git-head.js +89 -0
- package/dist/checkpoints/index.d.ts +17 -0
- package/dist/checkpoints/index.js +17 -0
- package/dist/checkpoints/replay.d.ts +48 -0
- package/dist/checkpoints/replay.js +154 -0
- package/dist/checkpoints/restore.d.ts +86 -0
- package/dist/checkpoints/restore.js +263 -0
- package/dist/checkpoints/settings.d.ts +14 -0
- package/dist/checkpoints/settings.js +23 -0
- package/dist/checkpoints/shadow-git.d.ts +108 -0
- package/dist/checkpoints/shadow-git.js +491 -0
- package/dist/checkpoints/shadow-restore.d.ts +25 -0
- package/dist/checkpoints/shadow-restore.js +128 -0
- package/dist/checkpoints/tracker.d.ts +64 -0
- package/dist/checkpoints/tracker.js +192 -0
- package/dist/checkpoints/types.d.ts +99 -0
- package/dist/checkpoints/types.js +12 -0
- package/dist/cli/args.d.ts +8 -4
- package/dist/cli/args.js +17 -97
- package/dist/cli/bootstrap.js +13 -1
- package/dist/cli/choice-prompt.d.ts +58 -0
- package/dist/cli/choice-prompt.js +140 -0
- package/dist/cli/codemode-notice.d.ts +3 -2
- package/dist/cli/codemode-notice.js +3 -2
- package/dist/cli/compose-agents.d.ts +27 -0
- package/dist/cli/compose-agents.js +111 -0
- package/dist/cli/compose-extensions.d.ts +29 -0
- package/dist/cli/compose-extensions.js +44 -0
- package/dist/cli/compose-session.d.ts +3 -0
- package/dist/cli/compose-session.js +47 -4
- package/dist/cli/compose.d.ts +3 -0
- package/dist/cli/compose.js +33 -6
- package/dist/cli/deps.d.ts +6 -0
- package/dist/cli/exit-codes.d.ts +10 -0
- package/dist/cli/exit-codes.js +12 -0
- package/dist/cli/help-text.d.ts +4 -0
- package/dist/cli/help-text.js +102 -0
- package/dist/cli/startup-screen.js +5 -3
- package/dist/cli/startup-steps.js +7 -1
- package/dist/cli/subcommands/config.d.ts +4 -1
- package/dist/cli/subcommands/config.js +17 -6
- package/dist/cli/subcommands/doctor.js +21 -0
- package/dist/cli/subcommands/models-cache-probe.d.ts +1 -1
- package/dist/cli/subcommands/models-cache-probe.js +3 -12
- package/dist/cli/subcommands/models-discover.js +5 -6
- package/dist/cli/subcommands/models.d.ts +2 -0
- package/dist/cli/subcommands/models.js +33 -14
- package/dist/cli/subcommands/providers.d.ts +1 -1
- package/dist/cli/subcommands/providers.js +8 -15
- package/dist/cli/subcommands/sessions.d.ts +3 -1
- package/dist/cli/subcommands/sessions.js +36 -2
- package/dist/codemode/capability.d.ts +24 -7
- package/dist/codemode/capability.js +38 -10
- package/dist/codemode/host-side.d.ts +14 -0
- package/dist/codemode/host-side.js +24 -1
- package/dist/codemode/tool.d.ts +1 -1
- package/dist/codemode/tool.js +6 -4
- package/dist/compaction/breaker.d.ts +25 -9
- package/dist/compaction/breaker.js +47 -17
- package/dist/compaction/estimate.d.ts +11 -3
- package/dist/compaction/estimate.js +64 -22
- package/dist/compaction/image-budget.d.ts +45 -0
- package/dist/compaction/image-budget.js +115 -0
- package/dist/compaction/post-compact.d.ts +38 -0
- package/dist/compaction/post-compact.js +152 -0
- package/dist/compaction/protect.d.ts +27 -0
- package/dist/compaction/protect.js +56 -0
- package/dist/compaction/prune-tier.d.ts +58 -12
- package/dist/compaction/prune-tier.js +120 -54
- package/dist/compaction/summarize-tier.d.ts +23 -4
- package/dist/compaction/summarize-tier.js +100 -29
- package/dist/config/checker.d.ts +28 -0
- package/dist/config/checker.js +97 -0
- package/dist/config/json-schema.js +63 -2
- package/dist/config/key-docs.js +72 -3
- package/dist/config/merge.d.ts +5 -3
- package/dist/config/merge.js +81 -7
- package/dist/config/profile.d.ts +2 -0
- package/dist/config/profile.js +2 -0
- package/dist/config/schema-w5.d.ts +18 -0
- package/dist/config/schema-w5.js +109 -0
- package/dist/config/schema.d.ts +5 -9
- package/dist/config/schema.js +68 -114
- package/dist/config/types-w5.d.ts +118 -0
- package/dist/config/types-w5.js +20 -0
- package/dist/config/types.d.ts +50 -1
- package/dist/config/types.js +12 -0
- package/dist/drivers/acp/client.d.ts +57 -0
- package/dist/drivers/acp/client.js +160 -0
- package/dist/drivers/acp/driver.d.ts +31 -0
- package/dist/drivers/acp/driver.js +274 -0
- package/dist/drivers/acp/testing/fake-agent-main.d.ts +5 -0
- package/dist/drivers/acp/testing/fake-agent-main.js +7 -0
- package/dist/drivers/acp/testing/fake-agent.d.ts +27 -0
- package/dist/drivers/acp/testing/fake-agent.js +211 -0
- package/dist/drivers/acp/types.d.ts +285 -0
- package/dist/drivers/acp/types.js +36 -0
- package/dist/drivers/agents.d.ts +58 -0
- package/dist/drivers/agents.js +142 -0
- package/dist/drivers/base.d.ts +35 -0
- package/dist/drivers/base.js +59 -0
- package/dist/drivers/catalog.d.ts +46 -0
- package/dist/drivers/catalog.js +167 -0
- package/dist/drivers/env.d.ts +20 -0
- package/dist/drivers/env.js +46 -0
- package/dist/drivers/host-runners.d.ts +18 -0
- package/dist/drivers/host-runners.js +45 -0
- package/dist/drivers/jsonrpc.d.ts +58 -0
- package/dist/drivers/jsonrpc.js +180 -0
- package/dist/drivers/native/claude-normalize.d.ts +46 -0
- package/dist/drivers/native/claude-normalize.js +106 -0
- package/dist/drivers/native/claude-stream.d.ts +29 -0
- package/dist/drivers/native/claude-stream.js +456 -0
- package/dist/drivers/native/codex-app-server.d.ts +26 -0
- package/dist/drivers/native/codex-app-server.js +407 -0
- package/dist/drivers/native/codex-normalize.d.ts +38 -0
- package/dist/drivers/native/codex-normalize.js +124 -0
- package/dist/drivers/native/oneshot.d.ts +28 -0
- package/dist/drivers/native/oneshot.js +312 -0
- package/dist/drivers/permissions.d.ts +40 -0
- package/dist/drivers/permissions.js +92 -0
- package/dist/drivers/pids.d.ts +32 -0
- package/dist/drivers/pids.js +93 -0
- package/dist/drivers/pool.d.ts +28 -0
- package/dist/drivers/pool.js +96 -0
- package/dist/drivers/probe.d.ts +47 -0
- package/dist/drivers/probe.js +172 -0
- package/dist/drivers/process.d.ts +48 -0
- package/dist/drivers/process.js +100 -0
- package/dist/drivers/runner.d.ts +61 -0
- package/dist/drivers/runner.js +388 -0
- package/dist/drivers/store.d.ts +49 -0
- package/dist/drivers/store.js +91 -0
- package/dist/drivers/turn.d.ts +41 -0
- package/dist/drivers/turn.js +99 -0
- package/dist/drivers/types.d.ts +122 -0
- package/dist/drivers/types.js +11 -0
- package/dist/git/info.d.ts +75 -0
- package/dist/git/info.js +191 -0
- package/dist/hooks/protocol.js +6 -1
- package/dist/hooks/types.d.ts +10 -1
- package/dist/hooks/types.js +2 -0
- package/dist/host/api-impl.d.ts +7 -0
- package/dist/host/api-impl.js +15 -0
- package/dist/host/types.d.ts +24 -2
- package/dist/host/types.js +4 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -0
- package/dist/modes/acp/acp-events.d.ts +46 -0
- package/dist/modes/acp/acp-events.js +233 -0
- package/dist/modes/acp/acp-mode.d.ts +17 -0
- package/dist/modes/acp/acp-mode.js +47 -0
- package/dist/modes/acp/acp-server.d.ts +79 -0
- package/dist/modes/acp/acp-server.js +315 -0
- package/dist/modes/commands-core.d.ts +13 -1
- package/dist/modes/commands-core.js +64 -0
- package/dist/modes/image-input.d.ts +12 -4
- package/dist/modes/image-input.js +22 -5
- package/dist/modes/interactive/agent-panels.d.ts +14 -0
- package/dist/modes/interactive/agent-panels.js +103 -0
- package/dist/modes/interactive/agent-ui.d.ts +73 -0
- package/dist/modes/interactive/agent-ui.js +234 -0
- package/dist/modes/interactive/approval-dialog.d.ts +21 -4
- package/dist/modes/interactive/approval-dialog.js +98 -20
- package/dist/modes/interactive/approval-merge.d.ts +41 -0
- package/dist/modes/interactive/approval-merge.js +89 -0
- package/dist/modes/interactive/clipboard-paste.d.ts +18 -0
- package/dist/modes/interactive/clipboard-paste.js +28 -0
- package/dist/modes/interactive/commands.d.ts +12 -1
- package/dist/modes/interactive/commands.js +31 -1
- package/dist/modes/interactive/confirm-dialog.d.ts +49 -0
- package/dist/modes/interactive/confirm-dialog.js +121 -0
- package/dist/modes/interactive/double-esc.d.ts +20 -0
- package/dist/modes/interactive/double-esc.js +34 -0
- package/dist/modes/interactive/event-notices.d.ts +32 -0
- package/dist/modes/interactive/event-notices.js +79 -0
- package/dist/modes/interactive/external-editor.d.ts +16 -0
- package/dist/modes/interactive/external-editor.js +39 -0
- package/dist/modes/interactive/interactive-mode.d.ts +14 -1
- package/dist/modes/interactive/interactive-mode.js +140 -136
- package/dist/modes/interactive/key-dispatch.d.ts +22 -2
- package/dist/modes/interactive/key-dispatch.js +66 -7
- package/dist/modes/interactive/line/line-mode.d.ts +4 -1
- package/dist/modes/interactive/line/line-mode.js +31 -5
- package/dist/modes/interactive/line/line-render.d.ts +2 -1
- package/dist/modes/interactive/line/line-render.js +40 -4
- package/dist/modes/interactive/message-view.d.ts +1 -1
- package/dist/modes/interactive/message-view.js +24 -2
- package/dist/modes/interactive/panels.d.ts +18 -1
- package/dist/modes/interactive/panels.js +19 -5
- package/dist/modes/interactive/plan-command.d.ts +40 -0
- package/dist/modes/interactive/plan-command.js +129 -0
- package/dist/modes/interactive/plan-dialog.d.ts +98 -0
- package/dist/modes/interactive/plan-dialog.js +290 -0
- package/dist/modes/interactive/plan-flow.d.ts +34 -0
- package/dist/modes/interactive/plan-flow.js +98 -0
- package/dist/modes/interactive/rewind-command.d.ts +31 -0
- package/dist/modes/interactive/rewind-command.js +106 -0
- package/dist/modes/interactive/rewind-flow.d.ts +37 -0
- package/dist/modes/interactive/rewind-flow.js +151 -0
- package/dist/modes/interactive/rewind-list.d.ts +36 -0
- package/dist/modes/interactive/rewind-list.js +123 -0
- package/dist/modes/interactive/rewind-panel.d.ts +77 -0
- package/dist/modes/interactive/rewind-panel.js +309 -0
- package/dist/modes/interactive/rewind-text.d.ts +40 -0
- package/dist/modes/interactive/rewind-text.js +139 -0
- package/dist/modes/interactive/session-events.d.ts +24 -0
- package/dist/modes/interactive/session-events.js +96 -0
- package/dist/modes/interactive/startup-ui.js +5 -1
- package/dist/modes/interactive/status-area.d.ts +73 -0
- package/dist/modes/interactive/status-area.js +190 -0
- package/dist/modes/interactive/status-bar.d.ts +99 -11
- package/dist/modes/interactive/status-bar.js +273 -90
- package/dist/modes/interactive/status-line.d.ts +33 -0
- package/dist/modes/interactive/status-line.js +113 -0
- package/dist/modes/interactive/subagent-view.d.ts +56 -0
- package/dist/modes/interactive/subagent-view.js +154 -0
- package/dist/modes/interactive/tasks-report.d.ts +27 -0
- package/dist/modes/interactive/tasks-report.js +114 -0
- package/dist/modes/interactive/tool-view.d.ts +12 -2
- package/dist/modes/interactive/tool-view.js +34 -4
- package/dist/modes/print/print-mode.d.ts +13 -4
- package/dist/modes/print/print-mode.js +56 -12
- package/dist/modes/rpc/commands.d.ts +9 -0
- package/dist/modes/rpc/commands.js +44 -0
- package/dist/modes/rpc/rpc-mode.js +7 -1
- package/dist/modes/session-report.d.ts +11 -0
- package/dist/modes/session-report.js +48 -1
- package/dist/permissions/auto-safe.d.ts +5 -0
- package/dist/permissions/auto-safe.js +18 -0
- package/dist/permissions/bypass.d.ts +32 -0
- package/dist/permissions/bypass.js +36 -0
- package/dist/permissions/classifier.d.ts +4 -0
- package/dist/permissions/classifier.js +2 -0
- package/dist/permissions/modes.js +1 -1
- package/dist/permissions/pipeline.d.ts +43 -4
- package/dist/permissions/pipeline.js +114 -9
- package/dist/permissions/readonly-bash.d.ts +30 -0
- package/dist/permissions/readonly-bash.js +118 -0
- package/dist/permissions/types.d.ts +42 -0
- package/dist/plan/compose.d.ts +9 -0
- package/dist/plan/compose.js +19 -0
- package/dist/plan/controller.d.ts +71 -0
- package/dist/plan/controller.js +27 -0
- package/dist/plan/done-markers.d.ts +17 -0
- package/dist/plan/done-markers.js +51 -0
- package/dist/plan/extract.d.ts +29 -0
- package/dist/plan/extract.js +160 -0
- package/dist/plan/prompts.d.ts +36 -0
- package/dist/plan/prompts.js +89 -0
- package/dist/plan/store.d.ts +37 -0
- package/dist/plan/store.js +90 -0
- package/dist/rpc.d.ts +58 -2
- package/dist/rpc.js +7 -0
- package/dist/sandbox/bash.d.ts +74 -0
- package/dist/sandbox/bash.js +126 -0
- package/dist/sandbox/detect.d.ts +48 -0
- package/dist/sandbox/detect.js +149 -0
- package/dist/sandbox/index.d.ts +5 -0
- package/dist/sandbox/index.js +5 -0
- package/dist/sandbox/profile.d.ts +33 -0
- package/dist/sandbox/profile.js +76 -0
- package/dist/sandbox/wrap.d.ts +29 -0
- package/dist/sandbox/wrap.js +117 -0
- package/dist/sdk.d.ts +33 -2
- package/dist/sdk.js +24 -2
- package/dist/session/types.d.ts +3 -1
- package/dist/session/types.js +1 -0
- package/dist/skills/builtin.d.ts +31 -0
- package/dist/skills/builtin.js +109 -0
- package/dist/skills/discover.d.ts +2 -1
- package/dist/skills/index-prompt.js +5 -8
- package/dist/tools/background-jobs.d.ts +71 -0
- package/dist/tools/background-jobs.js +198 -0
- package/dist/tools/bash.d.ts +53 -1
- package/dist/tools/bash.js +158 -7
- package/dist/tools/clipboard-image.d.ts +44 -0
- package/dist/tools/clipboard-image.js +148 -0
- package/dist/tools/edit.d.ts +2 -0
- package/dist/tools/edit.js +18 -3
- package/dist/tools/image-file.d.ts +38 -3
- package/dist/tools/image-file.js +81 -10
- package/dist/tools/image-resize.d.ts +58 -0
- package/dist/tools/image-resize.js +97 -0
- package/dist/tools/presets.d.ts +7 -2
- package/dist/tools/presets.js +11 -4
- package/dist/tools/read.d.ts +5 -2
- package/dist/tools/read.js +13 -10
- package/dist/tools/registry.d.ts +7 -1
- package/dist/tools/registry.js +27 -4
- package/dist/tools/task-ctl.d.ts +22 -0
- package/dist/tools/task-ctl.js +116 -0
- package/dist/tools/task.d.ts +22 -10
- package/dist/tools/task.js +66 -26
- package/dist/tools/todo.d.ts +22 -2
- package/dist/tools/todo.js +58 -14
- package/dist/tools/truncate.d.ts +15 -0
- package/dist/tools/truncate.js +25 -0
- package/dist/tools/types.d.ts +113 -0
- package/dist/tools/types.js +5 -0
- package/dist/tools/write.js +3 -0
- package/dist/tui/glyphs.d.ts +4 -0
- package/dist/tui/glyphs.js +4 -0
- package/dist/tui/keybindings.d.ts +6 -1
- package/dist/tui/keybindings.js +6 -1
- package/docs/acp.md +78 -0
- package/docs/agents.md +250 -0
- package/docs/codemode.md +12 -8
- package/docs/hooks.md +26 -22
- package/docs/permissions.md +78 -13
- package/docs/plan.md +107 -0
- package/docs/providers.md +228 -52
- package/docs/rewind-plan.md +181 -0
- package/docs/rpc.md +92 -5
- package/docs/sandbox.md +215 -0
- package/docs/session-format.md +41 -21
- package/docs/sessions.md +41 -1
- package/docs/tui-design.md +751 -0
- package/docs/tui.md +179 -21
- package/package.json +13 -2
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
* (字段缺失或恒 0);其余(读到一点、只有写入)→ `inconclusive`(粒度或 TTL 问题)。
|
|
8
8
|
*
|
|
9
9
|
* 计费动作:执行前打印预估(两次 × `--tokens` × 目录输入价,无价 `$?`);非 TTY 必须 `--yes`
|
|
10
|
-
* (否则退出 2),TTY
|
|
10
|
+
* (否则退出 2),TTY 下方向键选一次「继续 / 取消」(choice-prompt.ts)。`--json` 时预估写 stderr,stdout 只有一个结果对象。
|
|
11
11
|
* 协议层不保留原始响应,「usage 字段」列的是该协议解析时读取的字段名。
|
|
12
12
|
*/
|
|
13
|
-
import { createInterface } from "node:readline/promises";
|
|
14
13
|
import { priceTokens } from "../../ai/cost.js";
|
|
15
14
|
import { UsageError } from "../args.js";
|
|
15
|
+
import { confirmContinue } from "../choice-prompt.js";
|
|
16
16
|
import { ExitCode } from "../exit-codes.js";
|
|
17
17
|
export const PROBE_DEFAULT_TOKENS = 2048;
|
|
18
18
|
export const PROBE_DEFAULT_GAP_MS = 3000;
|
|
@@ -78,15 +78,6 @@ function intOption(ctx, name, fallback, min) {
|
|
|
78
78
|
throw new UsageError(`--${name} 应为不小于 ${min} 的整数`);
|
|
79
79
|
return value;
|
|
80
80
|
}
|
|
81
|
-
async function confirm() {
|
|
82
|
-
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
83
|
-
try {
|
|
84
|
-
return /^y(es)?$/i.test((await rl.question("继续?[y/N] ")).trim());
|
|
85
|
-
}
|
|
86
|
-
finally {
|
|
87
|
-
rl.close();
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
81
|
function sampleLine(index, s) {
|
|
91
82
|
const field = s.cacheReported === undefined ? "?" : s.cacheReported ? "有" : "无";
|
|
92
83
|
return `#${index} input ${s.input} · cacheRead ${s.cacheRead} · cacheWrite ${s.cacheWrite} · 缓存字段 ${field}`;
|
|
@@ -122,7 +113,7 @@ async function run(ctx) {
|
|
|
122
113
|
io.stderr("ama: cache-probe 会发两次计费请求,非交互环境需加 --yes\n");
|
|
123
114
|
return ExitCode.Usage;
|
|
124
115
|
}
|
|
125
|
-
if (!(await
|
|
116
|
+
if (!(await confirmContinue({ env: io.env }))) {
|
|
126
117
|
io.stderr("ama: 已取消\n");
|
|
127
118
|
return ExitCode.Ok;
|
|
128
119
|
}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
import { authHeaders, mergeHeaders } from "../../ai/http.js";
|
|
21
21
|
import { discoverLocalModels, materializeModel } from "../../ai/providers/registry.js";
|
|
22
22
|
import { withCustomDefaults } from "../../ai/providers/catalog.js";
|
|
23
|
-
import {
|
|
23
|
+
import { describeModelsDev, loadModelsDevIndex } from "../../ai/providers/models-dev-cache.js";
|
|
24
24
|
import { matchLabel, modelsDevFields } from "../../ai/providers/models-dev.js";
|
|
25
25
|
import { existsSync } from "node:fs";
|
|
26
26
|
import { loadConfigFile } from "../../config/load.js";
|
|
@@ -173,15 +173,14 @@ async function run(ctx) {
|
|
|
173
173
|
}
|
|
174
174
|
const configured = new Map(provider.models.map((m) => [m.id, m]));
|
|
175
175
|
io.stdout(`${provider.id}:发现 ${found.length} 个模型(${modelsUrl(provider)})\n`);
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
io.stderr(`ama: 警告:${md.warning}\n`);
|
|
176
|
+
// models.dev 只读本地(快照 ⊕ `ama models refresh` 的覆盖),不联网。
|
|
177
|
+
const mdIndex = loadModelsDevIndex(ctx.level.dataDir);
|
|
178
|
+
io.stdout(`${describeModelsDev(ctx.level.dataDir)}\n`);
|
|
180
179
|
const noTools = new Set();
|
|
181
180
|
const unmatched = new Set();
|
|
182
181
|
for (const model of found) {
|
|
183
182
|
const known = configured.get(model.id);
|
|
184
|
-
const match =
|
|
183
|
+
const match = mdIndex.match(model.id);
|
|
185
184
|
const fields = match !== undefined ? modelsDevFields(match.model) : undefined;
|
|
186
185
|
if (fields?.toolCall === false)
|
|
187
186
|
noTools.add(model.id);
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* [W3-C0] 子命令分派改为动作表 `MODELS_ACTIONS`(第三波 §1.11 / §2.3):新动作(C2 的
|
|
8
8
|
* `cache-probe`、B12 的 `discover`)各写在自己的文件里,这里只加一行表项;用法文本、
|
|
9
9
|
* 选项表与必填位置参数都从表里来。
|
|
10
|
+
*
|
|
11
|
+
* [W5-M1] `refresh`:models.dev 显式刷新(`refresh-catalog` 保留为别名)。
|
|
10
12
|
*/
|
|
11
13
|
import type { ProviderRegistryApi } from "../../ai/types.js";
|
|
12
14
|
import type { CliIo, RuntimeDeps } from "../deps.js";
|
|
@@ -7,9 +7,12 @@
|
|
|
7
7
|
* [W3-C0] 子命令分派改为动作表 `MODELS_ACTIONS`(第三波 §1.11 / §2.3):新动作(C2 的
|
|
8
8
|
* `cache-probe`、B12 的 `discover`)各写在自己的文件里,这里只加一行表项;用法文本、
|
|
9
9
|
* 选项表与必填位置参数都从表里来。
|
|
10
|
+
*
|
|
11
|
+
* [W5-M1] `refresh`:models.dev 显式刷新(`refresh-catalog` 保留为别名)。
|
|
10
12
|
*/
|
|
11
13
|
import { formatModelRef, modelRefOf } from "../../ai/providers/channels.js";
|
|
12
14
|
import { describeRefresh, modelsDevCachePath, refreshModelsDev, } from "../../ai/providers/models-dev-cache.js";
|
|
15
|
+
import { snapshotMeta } from "../../ai/providers/models-dev-snapshot.js";
|
|
13
16
|
import { parseSubArgs, UsageError } from "../args.js";
|
|
14
17
|
import { ExitCode } from "../exit-codes.js";
|
|
15
18
|
import { buildRegistry, loadUserLevel } from "./context.js";
|
|
@@ -78,6 +81,34 @@ async function check(io, registry, ref) {
|
|
|
78
81
|
io.stdout(`${shown} 可用(${model.api},${ms} ms,stopReason ${message.stopReason})\n`);
|
|
79
82
|
return ExitCode.Ok;
|
|
80
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* `ama models refresh [--provider <id>[,<id>…]]`:显式联网拉 models.dev,按内置快照的清单裁剪,
|
|
86
|
+
* 写用户级覆盖 `<dataDir>/models-dev.json`(docs/providers.md「模型元数据」)。启动与其它命令不联网。
|
|
87
|
+
*/
|
|
88
|
+
const REFRESH_ACTION = {
|
|
89
|
+
usage: "ama models refresh [--provider <id>[,<id>…]]",
|
|
90
|
+
valueOptions: ["provider"],
|
|
91
|
+
run: async (ctx) => {
|
|
92
|
+
const only = ctx.values.get("provider");
|
|
93
|
+
const providers = only
|
|
94
|
+
?.split(",")
|
|
95
|
+
.map((p) => p.trim())
|
|
96
|
+
.filter(Boolean);
|
|
97
|
+
ctx.io.stdout(`内置快照:${snapshotMeta().fetchedAt};正在拉取 models.dev…\n`);
|
|
98
|
+
const result = await refreshModelsDev({
|
|
99
|
+
dataDir: ctx.level.dataDir,
|
|
100
|
+
env: ctx.io.env,
|
|
101
|
+
...(providers !== undefined && providers.length > 0 ? { providers } : {}),
|
|
102
|
+
});
|
|
103
|
+
if (result.warning !== undefined)
|
|
104
|
+
ctx.io.stderr(`ama: ${result.warning}\n`);
|
|
105
|
+
ctx.io.stdout(`${describeRefresh(result)}\n`);
|
|
106
|
+
if (result.status === "failed")
|
|
107
|
+
return ExitCode.RuntimeError;
|
|
108
|
+
ctx.io.stdout(`已写入 ${modelsDevCachePath(ctx.level.dataDir)}\n`);
|
|
109
|
+
return ExitCode.Ok;
|
|
110
|
+
},
|
|
111
|
+
};
|
|
81
112
|
/** 动作表:键是子命令名,顺序即用法文本顺序。 */
|
|
82
113
|
export const MODELS_ACTIONS = Object.freeze({
|
|
83
114
|
list: {
|
|
@@ -92,20 +123,8 @@ export const MODELS_ACTIONS = Object.freeze({
|
|
|
92
123
|
},
|
|
93
124
|
discover: DISCOVER_ACTION,
|
|
94
125
|
"cache-probe": CACHE_PROBE_ACTION,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
run: async (ctx) => {
|
|
98
|
-
const result = await refreshModelsDev({
|
|
99
|
-
dataDir: ctx.level.dataDir,
|
|
100
|
-
env: ctx.io.env,
|
|
101
|
-
force: true,
|
|
102
|
-
});
|
|
103
|
-
ctx.io.stdout(`${describeRefresh(result)}\n${modelsDevCachePath(ctx.level.dataDir)}\n`);
|
|
104
|
-
if (result.warning !== undefined)
|
|
105
|
-
ctx.io.stderr(`ama: 警告:${result.warning}\n`);
|
|
106
|
-
return result.status === "unavailable" ? ExitCode.RuntimeError : ExitCode.Ok;
|
|
107
|
-
},
|
|
108
|
-
},
|
|
126
|
+
refresh: REFRESH_ACTION,
|
|
127
|
+
"refresh-catalog": { ...REFRESH_ACTION, usage: "ama models refresh-catalog(refresh 的旧名)" },
|
|
109
128
|
});
|
|
110
129
|
export const MODELS_USAGE = `用法:${Object.values(MODELS_ACTIONS)
|
|
111
130
|
.map((a) => a.usage)
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - list / channels:供应商 → 渠道 → 模型数与 key 来源(从不显示 key)。remove:删配置与 auth.json 条目。
|
|
9
9
|
*
|
|
10
10
|
* 计费:`--probe` 每模型每渠道一次最小请求(并发执行,见到首个流事件即判可用并断开,见
|
|
11
|
-
* probe-runner.ts);执行前打印预估,TTY
|
|
11
|
+
* probe-runner.ts);执行前打印预估,TTY 下方向键选「继续 / 取消」(choice-prompt.ts,y / n 直选),非 TTY 必须 `--yes`。
|
|
12
12
|
*/
|
|
13
13
|
import type { AmaConfig } from "../../config/types.js";
|
|
14
14
|
import type { CliIo, RuntimeDeps } from "../deps.js";
|
|
@@ -8,17 +8,17 @@
|
|
|
8
8
|
* - list / channels:供应商 → 渠道 → 模型数与 key 来源(从不显示 key)。remove:删配置与 auth.json 条目。
|
|
9
9
|
*
|
|
10
10
|
* 计费:`--probe` 每模型每渠道一次最小请求(并发执行,见到首个流事件即判可用并断开,见
|
|
11
|
-
* probe-runner.ts);执行前打印预估,TTY
|
|
11
|
+
* probe-runner.ts);执行前打印预估,TTY 下方向键选「继续 / 取消」(choice-prompt.ts,y / n 直选),非 TTY 必须 `--yes`。
|
|
12
12
|
*/
|
|
13
13
|
import { existsSync } from "node:fs";
|
|
14
|
-
import {
|
|
15
|
-
import { describeRefresh, refreshModelsDev } from "../../ai/providers/models-dev-cache.js";
|
|
14
|
+
import { describeModelsDev, loadModelsDevIndex } from "../../ai/providers/models-dev-cache.js";
|
|
16
15
|
import { modelsDevFields } from "../../ai/providers/models-dev.js";
|
|
17
16
|
import { PROVIDER_ID_PATTERN, setAuthKey } from "../../config/auth-file.js";
|
|
18
17
|
import { loadConfigFile } from "../../config/load.js";
|
|
19
18
|
import { CONFIG_FILE_VERSION } from "../../config/types.js";
|
|
20
19
|
import { writeConfigFile } from "../../config/write.js";
|
|
21
20
|
import { parseSubArgs, UsageError } from "../args.js";
|
|
21
|
+
import { confirmContinue } from "../choice-prompt.js";
|
|
22
22
|
import { pickByPrice } from "../default-model.js";
|
|
23
23
|
import { ExitCode } from "../exit-codes.js";
|
|
24
24
|
import { extractKey } from "./auth.js";
|
|
@@ -76,13 +76,7 @@ export function userConfig(level) {
|
|
|
76
76
|
}
|
|
77
77
|
async function confirm(io, question) {
|
|
78
78
|
io.stderr(question);
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
return /^y(es)?$/i.test((await rl.question("继续?[y/N] ")).trim());
|
|
82
|
-
}
|
|
83
|
-
finally {
|
|
84
|
-
rl.close();
|
|
85
|
-
}
|
|
79
|
+
return confirmContinue({ env: io.env });
|
|
86
80
|
}
|
|
87
81
|
/** --yes / TTY 确认;非 TTY 且没有 --yes 返回 false 并提示(调用方退出 2)。 */
|
|
88
82
|
async function approved(ctx, what) {
|
|
@@ -260,17 +254,16 @@ async function add(ctx, id, refresh) {
|
|
|
260
254
|
return ExitCode.RuntimeError;
|
|
261
255
|
}
|
|
262
256
|
io.stdout(`${id}:发现 ${listed.length} 个模型(${target.url})\n`);
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
io.stderr(`ama: 警告:${md.warning}\n`);
|
|
257
|
+
// models.dev 只读本地(快照 ⊕ `ama models refresh` 的覆盖),不联网。
|
|
258
|
+
const mdIndex = loadModelsDevIndex(level.dataDir);
|
|
259
|
+
io.stdout(`${describeModelsDev(level.dataDir)}\n`);
|
|
267
260
|
io.stdout(`候选渠道:${candidates.map((c) => `${c.name}(${c.api} ${c.baseUrl})`).join(" · ")}\n`);
|
|
268
261
|
const existingIds = new Set((existing?.models ?? []).map((m) => m.id));
|
|
269
262
|
const result = await plan(ctx, {
|
|
270
263
|
id,
|
|
271
264
|
candidates,
|
|
272
265
|
listed,
|
|
273
|
-
index:
|
|
266
|
+
index: mdIndex,
|
|
274
267
|
existingIds,
|
|
275
268
|
apiKey: key.apiKey,
|
|
276
269
|
registry,
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
* - list [--all]:缺省只列当前目录的会话;`--all` 列全部。
|
|
6
6
|
* - show <id>:头信息 + 条目类型统计 + 首条提示 + 用户消息编号(`--from <id>#<编号>` 复用)。
|
|
7
7
|
* - search / export:见 sessions-search.ts、sessions-export.ts(只读扫描,不经会话存储)。
|
|
8
|
-
* - prune [--older-than <天>] [--dry-run]:缺省 30 天,移到 trash
|
|
8
|
+
* - prune [--older-than <天>] [--dry-run]:缺省 30 天,移到 trash(不删除);之后清理检查点备份
|
|
9
|
+
* (未被任何会话引用且超过 1 天的 blob,docs/rewind-plan.md §1.4)与超过 7 天的剪贴板图片
|
|
10
|
+
* (`<数据目录>/clipboard/`,W5-I),`--dry-run` 时只报告。
|
|
9
11
|
*/
|
|
10
12
|
import type { CliIo, RuntimeDeps } from "../deps.js";
|
|
11
13
|
export declare const SESSIONS_USAGE = "\u7528\u6CD5\uFF1Aama sessions list [--all] [--session-dir <\u76EE\u5F55>]\n ama sessions show <id> [--session-dir <\u76EE\u5F55>]\n ama sessions prune [--older-than <\u5929>] [--dry-run] [--all] [--session-dir <\u76EE\u5F55>]\n ama sessions search <\u5173\u952E\u8BCD|/\u6B63\u5219/> [--all] [--role user|assistant|tool] [--since 7d] [--limit N]\n ama sessions export <id> [--format md|json|jsonl] [--output <\u6587\u4EF6>] [--branch leaf|all]\n";
|
|
@@ -5,13 +5,17 @@
|
|
|
5
5
|
* - list [--all]:缺省只列当前目录的会话;`--all` 列全部。
|
|
6
6
|
* - show <id>:头信息 + 条目类型统计 + 首条提示 + 用户消息编号(`--from <id>#<编号>` 复用)。
|
|
7
7
|
* - search / export:见 sessions-search.ts、sessions-export.ts(只读扫描,不经会话存储)。
|
|
8
|
-
* - prune [--older-than <天>] [--dry-run]:缺省 30 天,移到 trash
|
|
8
|
+
* - prune [--older-than <天>] [--dry-run]:缺省 30 天,移到 trash(不删除);之后清理检查点备份
|
|
9
|
+
* (未被任何会话引用且超过 1 天的 blob,docs/rewind-plan.md §1.4)与超过 7 天的剪贴板图片
|
|
10
|
+
* (`<数据目录>/clipboard/`,W5-I),`--dry-run` 时只报告。
|
|
9
11
|
*/
|
|
10
|
-
import { resolve } from "node:path";
|
|
12
|
+
import { join, resolve } from "node:path";
|
|
13
|
+
import { formatBytes, gcBlobs } from "../../checkpoints/gc.js";
|
|
11
14
|
import { expandHome, resolveDataDir } from "../../config/paths.js";
|
|
12
15
|
import { parseSubArgs, UsageError } from "../args.js";
|
|
13
16
|
import { ExitCode } from "../exit-codes.js";
|
|
14
17
|
import { numberUserMessages } from "../../session/reuse.js";
|
|
18
|
+
import { gcClipboardImages } from "../../tools/clipboard-image.js";
|
|
15
19
|
import { runSessionsExport } from "./sessions-export.js";
|
|
16
20
|
import { runSessionsSearch } from "./sessions-search.js";
|
|
17
21
|
export const SESSIONS_USAGE = `用法:ama sessions list [--all] [--session-dir <目录>]
|
|
@@ -109,12 +113,42 @@ export async function runSessions(argv, io, deps) {
|
|
|
109
113
|
for (const file of moved)
|
|
110
114
|
io.stdout(`${dryRun ? "将移到 trash" : "已移到 trash"}:${file}\n`);
|
|
111
115
|
io.stdout(`${moved.length} 个会话${dryRun ? "(演练,未改动)" : ""}\n`);
|
|
116
|
+
await pruneFileHistory(io, sessionDir, dryRun);
|
|
117
|
+
await pruneClipboard(io, dryRun);
|
|
112
118
|
return ExitCode.Ok;
|
|
113
119
|
}
|
|
114
120
|
default:
|
|
115
121
|
throw new UsageError(`未知的 sessions 子命令:${action}`);
|
|
116
122
|
}
|
|
117
123
|
}
|
|
124
|
+
/** 检查点备份 GC:扫描本次的会话目录、缺省会话目录与登记过的目录。失败只提示,不影响 prune。 */
|
|
125
|
+
async function pruneFileHistory(io, sessionDir, dryRun) {
|
|
126
|
+
const dataDir = resolveDataDir({ env: io.env });
|
|
127
|
+
try {
|
|
128
|
+
const result = await gcBlobs({
|
|
129
|
+
dataDir,
|
|
130
|
+
sessionRoots: [sessionDir, join(dataDir, "sessions")],
|
|
131
|
+
dryRun,
|
|
132
|
+
});
|
|
133
|
+
if (result.removed.length === 0)
|
|
134
|
+
return;
|
|
135
|
+
io.stdout(`file-history:${dryRun ? "将清除" : "已清除"} ${result.removed.length} 个未引用的备份(${formatBytes(result.removedBytes)})\n`);
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
io.stderr(`ama: file-history 清理跳过(${error instanceof Error ? error.message : String(error)})\n`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/** [W5-I] `<数据目录>/clipboard/` 超过 7 天的剪贴板图片。失败只提示。 */
|
|
142
|
+
async function pruneClipboard(io, dryRun) {
|
|
143
|
+
try {
|
|
144
|
+
const removed = await gcClipboardImages(resolveDataDir({ env: io.env }), { dryRun });
|
|
145
|
+
if (removed.length > 0)
|
|
146
|
+
io.stdout(`clipboard:${dryRun ? "将清除" : "已清除"} ${removed.length} 个超过 7 天的剪贴板图片\n`);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
io.stderr(`ama: clipboard 清理跳过(${error instanceof Error ? error.message : String(error)})\n`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
118
152
|
function notWired(io, what) {
|
|
119
153
|
io.stderr(`ama: ${what} 尚未装配(会话存储由集成批次注入)\n`);
|
|
120
154
|
return ExitCode.RuntimeError;
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 沙箱能力探测(设计 §5.5 沙箱第 4
|
|
2
|
+
* 沙箱能力探测(设计 §5.5 沙箱第 4 条;docs/sandbox.md「探测与降级」)。[B10][S2]
|
|
3
3
|
*
|
|
4
4
|
* Node 的权限模型(`--permission`)在 Node ≥ 25 同时拒绝网络;Node 22 / 24 只管文件、子进程、
|
|
5
|
-
* worker 与 addon,不管网络——脚本若逃出 `vm`
|
|
6
|
-
* -
|
|
7
|
-
* - Node
|
|
8
|
-
*
|
|
5
|
+
* worker 与 addon,不管网络——脚本若逃出 `vm` 就能联网。子进程另外经操作系统沙箱(macOS
|
|
6
|
+
* sandbox-exec、Linux bwrap / unshare,src/sandbox)启动时,网络由内核拒绝。所以:
|
|
7
|
+
* - Node ≥ 25 → `strict`(OS 沙箱可用时叠加,纵深防御);
|
|
8
|
+
* - Node 22 / 24 + 可用的 OS 沙箱 → `strict`(子进程必须经 OS 沙箱启动);
|
|
9
|
+
* - Node 22 / 24 且没有 OS 沙箱 → 仍可用,但工具描述与状态栏标注「网络未隔离」;
|
|
10
|
+
* `codemode.requireStrict: true` 时直接禁用 codemode 工具并 warning(`codemodeAvailability`)。
|
|
9
11
|
*
|
|
10
|
-
*
|
|
12
|
+
* 能力在进程内只探测一次(OS 沙箱探针有缓存),同一环境下描述与权限类字节稳定。状态栏直接调用
|
|
13
|
+
* `detectSandboxCapability()`(不经宿主 status);组装根先用 `configureOsSandbox` 记下 `sandbox.enabled`。
|
|
11
14
|
*/
|
|
15
|
+
import type { SandboxConfig } from "../config/types.js";
|
|
16
|
+
import { type OsSandboxStatus } from "../sandbox/detect.js";
|
|
12
17
|
export interface SandboxCapability {
|
|
13
18
|
/** 权限模型同时隔离文件、子进程与网络。 */
|
|
14
19
|
strict: boolean;
|
|
@@ -18,12 +23,24 @@ export interface SandboxCapability {
|
|
|
18
23
|
reason: string;
|
|
19
24
|
/** 运行时支持的权限开关:Node ≥ 22.13 / 23.5 为 `--permission`,更早为 `--experimental-permission`。 */
|
|
20
25
|
permissionFlag: "--permission" | "--experimental-permission";
|
|
26
|
+
/** 操作系统沙箱(`kind: none` 表示没有);codemode 子进程经它启动。 */
|
|
27
|
+
os: OsSandboxStatus;
|
|
21
28
|
}
|
|
22
29
|
export declare const NETWORK_NOT_ISOLATED = "network not isolated";
|
|
23
30
|
export declare function parseNodeMajor(version: string): number;
|
|
24
31
|
/** `--permission` 在 Node 22.13 / 23.5 之后才是稳定名字;之前只有 `--experimental-permission`。 */
|
|
25
32
|
export declare function permissionFlagFor(allowedFlags?: ReadonlySet<string>): SandboxCapability["permissionFlag"];
|
|
26
|
-
|
|
33
|
+
/**
|
|
34
|
+
* 运行时的沙箱能力。`os` 缺省:不传 `nodeVersion` 时用进程内缓存的探测结果(`osSandboxStatus()`);
|
|
35
|
+
* 传了假设的 Node 版本(测试、展示)时不探测,按没有 OS 沙箱算,需要时显式传入。
|
|
36
|
+
*/
|
|
37
|
+
export declare function detectSandboxCapability(nodeVersion?: string, allowedFlags?: ReadonlySet<string>, os?: OsSandboxStatus): SandboxCapability;
|
|
38
|
+
/** 按配置的 `sandbox.enabled`(缺省 auto)得到运行时能力。 */
|
|
39
|
+
export declare function sandboxCapabilityFor(config: {
|
|
40
|
+
sandbox?: SandboxConfig;
|
|
41
|
+
}): SandboxCapability;
|
|
42
|
+
/** strict 是否依赖 OS 沙箱(Node 22 / 24):此时子进程必须经 OS 沙箱启动,包装不了就报错。 */
|
|
43
|
+
export declare function strictNeedsOsSandbox(capability: Pick<SandboxCapability, "strict" | "nodeMajor">): boolean;
|
|
27
44
|
export type CodemodeAvailability = {
|
|
28
45
|
available: true;
|
|
29
46
|
capability: SandboxCapability;
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 沙箱能力探测(设计 §5.5 沙箱第 4
|
|
2
|
+
* 沙箱能力探测(设计 §5.5 沙箱第 4 条;docs/sandbox.md「探测与降级」)。[B10][S2]
|
|
3
3
|
*
|
|
4
4
|
* Node 的权限模型(`--permission`)在 Node ≥ 25 同时拒绝网络;Node 22 / 24 只管文件、子进程、
|
|
5
|
-
* worker 与 addon,不管网络——脚本若逃出 `vm`
|
|
6
|
-
* -
|
|
7
|
-
* - Node
|
|
8
|
-
*
|
|
5
|
+
* worker 与 addon,不管网络——脚本若逃出 `vm` 就能联网。子进程另外经操作系统沙箱(macOS
|
|
6
|
+
* sandbox-exec、Linux bwrap / unshare,src/sandbox)启动时,网络由内核拒绝。所以:
|
|
7
|
+
* - Node ≥ 25 → `strict`(OS 沙箱可用时叠加,纵深防御);
|
|
8
|
+
* - Node 22 / 24 + 可用的 OS 沙箱 → `strict`(子进程必须经 OS 沙箱启动);
|
|
9
|
+
* - Node 22 / 24 且没有 OS 沙箱 → 仍可用,但工具描述与状态栏标注「网络未隔离」;
|
|
10
|
+
* `codemode.requireStrict: true` 时直接禁用 codemode 工具并 warning(`codemodeAvailability`)。
|
|
9
11
|
*
|
|
10
|
-
*
|
|
12
|
+
* 能力在进程内只探测一次(OS 沙箱探针有缓存),同一环境下描述与权限类字节稳定。状态栏直接调用
|
|
13
|
+
* `detectSandboxCapability()`(不经宿主 status);组装根先用 `configureOsSandbox` 记下 `sandbox.enabled`。
|
|
11
14
|
*/
|
|
15
|
+
import { NO_OS_SANDBOX, osSandboxStatus } from "../sandbox/detect.js";
|
|
12
16
|
export const NETWORK_NOT_ISOLATED = "network not isolated";
|
|
13
17
|
export function parseNodeMajor(version) {
|
|
14
18
|
const major = Number.parseInt(version.replace(/^v/, "").split(".")[0] ?? "", 10);
|
|
@@ -18,8 +22,13 @@ export function parseNodeMajor(version) {
|
|
|
18
22
|
export function permissionFlagFor(allowedFlags = process.allowedNodeEnvironmentFlags) {
|
|
19
23
|
return allowedFlags.has("--permission") ? "--permission" : "--experimental-permission";
|
|
20
24
|
}
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
/**
|
|
26
|
+
* 运行时的沙箱能力。`os` 缺省:不传 `nodeVersion` 时用进程内缓存的探测结果(`osSandboxStatus()`);
|
|
27
|
+
* 传了假设的 Node 版本(测试、展示)时不探测,按没有 OS 沙箱算,需要时显式传入。
|
|
28
|
+
*/
|
|
29
|
+
export function detectSandboxCapability(nodeVersion, allowedFlags, os) {
|
|
30
|
+
const osStatus = os ?? (nodeVersion === undefined ? osSandboxStatus() : NO_OS_SANDBOX);
|
|
31
|
+
const nodeMajor = parseNodeMajor(nodeVersion ?? process.versions.node);
|
|
23
32
|
const permissionFlag = permissionFlagFor(allowedFlags);
|
|
24
33
|
if (nodeMajor >= 25) {
|
|
25
34
|
return {
|
|
@@ -27,6 +36,16 @@ export function detectSandboxCapability(nodeVersion = process.versions.node, all
|
|
|
27
36
|
nodeMajor,
|
|
28
37
|
reason: `Node ${nodeMajor}: the permission model blocks file access, child processes and network`,
|
|
29
38
|
permissionFlag,
|
|
39
|
+
os: osStatus,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (osStatus.isolatesNetwork) {
|
|
43
|
+
return {
|
|
44
|
+
strict: true,
|
|
45
|
+
nodeMajor,
|
|
46
|
+
reason: `Node ${nodeMajor}: the OS sandbox (${osStatus.kind}) blocks network; the permission model blocks file access and child processes`,
|
|
47
|
+
permissionFlag,
|
|
48
|
+
os: osStatus,
|
|
30
49
|
};
|
|
31
50
|
}
|
|
32
51
|
return {
|
|
@@ -34,8 +53,17 @@ export function detectSandboxCapability(nodeVersion = process.versions.node, all
|
|
|
34
53
|
nodeMajor,
|
|
35
54
|
reason: `Node ${nodeMajor}: ${NETWORK_NOT_ISOLATED} (the permission model blocks file access and child processes only)`,
|
|
36
55
|
permissionFlag,
|
|
56
|
+
os: osStatus,
|
|
37
57
|
};
|
|
38
58
|
}
|
|
59
|
+
/** 按配置的 `sandbox.enabled`(缺省 auto)得到运行时能力。 */
|
|
60
|
+
export function sandboxCapabilityFor(config) {
|
|
61
|
+
return detectSandboxCapability(undefined, undefined, osSandboxStatus(config.sandbox?.enabled ?? "auto"));
|
|
62
|
+
}
|
|
63
|
+
/** strict 是否依赖 OS 沙箱(Node 22 / 24):此时子进程必须经 OS 沙箱启动,包装不了就报错。 */
|
|
64
|
+
export function strictNeedsOsSandbox(capability) {
|
|
65
|
+
return capability.strict && capability.nodeMajor < 25;
|
|
66
|
+
}
|
|
39
67
|
/** `requireStrict` 且运行时不是 strict → 禁用并给出 warning;非 strict 但允许 → 可用并提示。 */
|
|
40
68
|
export function codemodeAvailability(requireStrict, capability = detectSandboxCapability()) {
|
|
41
69
|
if (capability.strict)
|
|
@@ -44,12 +72,12 @@ export function codemodeAvailability(requireStrict, capability = detectSandboxCa
|
|
|
44
72
|
return {
|
|
45
73
|
available: false,
|
|
46
74
|
capability,
|
|
47
|
-
warning: `codemode 已禁用:Node ${capability.nodeMajor}
|
|
75
|
+
warning: `codemode 已禁用:Node ${capability.nodeMajor} 的权限模型不隔离网络,也没有可用的操作系统沙箱(${capability.os.detail};codemode.requireStrict 为 true;Node ≥ 25 或 macOS sandbox-exec / Linux bwrap 可隔离)`,
|
|
48
76
|
};
|
|
49
77
|
}
|
|
50
78
|
return {
|
|
51
79
|
available: true,
|
|
52
80
|
capability,
|
|
53
|
-
warning: `codemode:Node ${capability.nodeMajor}
|
|
81
|
+
warning: `codemode:Node ${capability.nodeMajor} 下网络未隔离(没有可用的操作系统沙箱:${capability.os.detail};要求隔离可设 codemode.requireStrict)`,
|
|
54
82
|
};
|
|
55
83
|
}
|
|
@@ -12,7 +12,13 @@
|
|
|
12
12
|
* (完整门禁);名字是 `codemode` 直接拒绝。脚本结束时 abort 仍在跑的调用。
|
|
13
13
|
* - 超时:父进程计时,到点杀子进程树(POSIX 进程组 / Windows taskkill);外层 abort:先发
|
|
14
14
|
* `abort`,宽限后杀树。
|
|
15
|
+
* - OS 沙箱(docs/sandbox.md):有可用的 sandbox-exec / bwrap / unshare 时,整条命令行经它启动,拒绝
|
|
16
|
+
* 网络与一切写入(`CODEMODE_OS_POLICY`;子进程本来就没有写权限)。Node 22 / 24 的 strict 依赖这一层
|
|
17
|
+
* (`requireOsSandbox`),包装不了就报错,不裸跑;Node ≥ 25 是叠加的纵深防御。
|
|
15
18
|
*/
|
|
19
|
+
import { type OsSandboxStatus } from "../sandbox/detect.js";
|
|
20
|
+
import type { OsSandboxPolicy } from "../sandbox/profile.js";
|
|
21
|
+
import { type WrappedCommand } from "../sandbox/wrap.js";
|
|
16
22
|
import { type SandboxCapability } from "./capability.js";
|
|
17
23
|
import { type ScriptOptions, type StoreSnapshot, type ToolDecl } from "./protocol.js";
|
|
18
24
|
/** 父进程累积的输出上限(字符);超出后丢弃中段(给模型的再按 max_output_tokens 截)。 */
|
|
@@ -23,6 +29,10 @@ export declare const ABORT_GRACE_MS = 500;
|
|
|
23
29
|
export declare function resolveSandboxEntry(moduleUrl?: string): string | undefined;
|
|
24
30
|
/** 子进程参数(不含可执行文件)。 */
|
|
25
31
|
export declare function sandboxArgs(entry: string, capability?: Pick<SandboxCapability, "permissionFlag">): string[];
|
|
32
|
+
/** codemode 子进程的 OS 沙箱策略:拒绝网络,任何位置都不可写。 */
|
|
33
|
+
export declare const CODEMODE_OS_POLICY: OsSandboxPolicy;
|
|
34
|
+
/** 完整命令行:`<node> <sandboxArgs>`,有 OS 沙箱时再经它包装。 */
|
|
35
|
+
export declare function sandboxCommand(nodePath: string, args: readonly string[], os: Pick<OsSandboxStatus, "kind" | "path">): WrappedCommand;
|
|
26
36
|
/** 子进程环境:空;Electron 下以 Node 方式运行同一可执行文件;Windows 保留 SystemRoot。 */
|
|
27
37
|
export declare function sandboxEnv(versions?: NodeJS.ProcessVersions, platform?: NodeJS.Platform, parentEnv?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
28
38
|
export interface SandboxRunRequest {
|
|
@@ -39,6 +49,10 @@ export interface SandboxRunRequest {
|
|
|
39
49
|
/** 缺省 process.execPath。 */
|
|
40
50
|
nodePath?: string;
|
|
41
51
|
capability?: Pick<SandboxCapability, "permissionFlag">;
|
|
52
|
+
/** 缺省 osSandboxStatus()(进程内缓存的探测结果)。 */
|
|
53
|
+
os?: Pick<OsSandboxStatus, "kind" | "path">;
|
|
54
|
+
/** true:必须经 OS 沙箱启动(Node 22 / 24 的 strict 依赖它),包装不了直接失败。 */
|
|
55
|
+
requireOsSandbox?: boolean;
|
|
42
56
|
}
|
|
43
57
|
export interface SandboxRunResult {
|
|
44
58
|
ok: boolean;
|
|
@@ -12,11 +12,16 @@
|
|
|
12
12
|
* (完整门禁);名字是 `codemode` 直接拒绝。脚本结束时 abort 仍在跑的调用。
|
|
13
13
|
* - 超时:父进程计时,到点杀子进程树(POSIX 进程组 / Windows taskkill);外层 abort:先发
|
|
14
14
|
* `abort`,宽限后杀树。
|
|
15
|
+
* - OS 沙箱(docs/sandbox.md):有可用的 sandbox-exec / bwrap / unshare 时,整条命令行经它启动,拒绝
|
|
16
|
+
* 网络与一切写入(`CODEMODE_OS_POLICY`;子进程本来就没有写权限)。Node 22 / 24 的 strict 依赖这一层
|
|
17
|
+
* (`requireOsSandbox`),包装不了就报错,不裸跑;Node ≥ 25 是叠加的纵深防御。
|
|
15
18
|
*/
|
|
16
19
|
import { spawn } from "node:child_process";
|
|
17
20
|
import { existsSync, realpathSync } from "node:fs";
|
|
18
21
|
import { dirname, join } from "node:path";
|
|
19
22
|
import { fileURLToPath } from "node:url";
|
|
23
|
+
import { osSandboxStatus } from "../sandbox/detect.js";
|
|
24
|
+
import { wrapCommand } from "../sandbox/wrap.js";
|
|
20
25
|
import { killProcessTree, trackProcessGroup, untrackProcessGroup } from "../tools/process-tree.js";
|
|
21
26
|
import { detectSandboxCapability } from "./capability.js";
|
|
22
27
|
import { LineSplitter, SANDBOX_MAIN_FLAG, decodeChildLine, encodeLine, } from "./protocol.js";
|
|
@@ -49,6 +54,15 @@ export function sandboxArgs(entry, capability = detectSandboxCapability()) {
|
|
|
49
54
|
SANDBOX_MAIN_FLAG,
|
|
50
55
|
];
|
|
51
56
|
}
|
|
57
|
+
/** codemode 子进程的 OS 沙箱策略:拒绝网络,任何位置都不可写。 */
|
|
58
|
+
export const CODEMODE_OS_POLICY = Object.freeze({
|
|
59
|
+
network: "deny",
|
|
60
|
+
writable: Object.freeze([]),
|
|
61
|
+
});
|
|
62
|
+
/** 完整命令行:`<node> <sandboxArgs>`,有 OS 沙箱时再经它包装。 */
|
|
63
|
+
export function sandboxCommand(nodePath, args, os) {
|
|
64
|
+
return wrapCommand(os, nodePath, args, CODEMODE_OS_POLICY);
|
|
65
|
+
}
|
|
52
66
|
/** 子进程环境:空;Electron 下以 Node 方式运行同一可执行文件;Windows 保留 SystemRoot。 */
|
|
53
67
|
export function sandboxEnv(versions = process.versions, platform = process.platform, parentEnv = process.env) {
|
|
54
68
|
const env = {};
|
|
@@ -82,8 +96,17 @@ export async function runSandbox(request) {
|
|
|
82
96
|
if (request.signal.aborted) {
|
|
83
97
|
return { ...base, ok: false, error: "Script aborted", aborted: true, elapsedMs: 0 };
|
|
84
98
|
}
|
|
99
|
+
const command = sandboxCommand(request.nodePath ?? process.execPath, sandboxArgs(entry, request.capability), request.os ?? osSandboxStatus());
|
|
100
|
+
if (request.requireOsSandbox === true && !command.networkDenied) {
|
|
101
|
+
return {
|
|
102
|
+
...base,
|
|
103
|
+
ok: false,
|
|
104
|
+
error: "codemode sandbox requires an OS sandbox to isolate network, but none is available",
|
|
105
|
+
elapsedMs: 0,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
85
108
|
const isWindows = process.platform === "win32";
|
|
86
|
-
const child = spawn(
|
|
109
|
+
const child = spawn(command.command, command.args, {
|
|
87
110
|
env: sandboxEnv(),
|
|
88
111
|
stdio: ["pipe", "pipe", "pipe"],
|
|
89
112
|
detached: !isWindows,
|
package/dist/codemode/tool.d.ts
CHANGED
|
@@ -88,7 +88,7 @@ export declare const CODEMODE_ONLY_GUIDELINE = "read, edit, write, bash and the
|
|
|
88
88
|
export declare function createCodemodeTool(options: CodemodeToolOptions): ToolDefinition<CodemodeInput>;
|
|
89
89
|
/** 组装根用:从 ToolFactoryContext 的形状取所需(避免 codemode → cli 的依赖)。 */
|
|
90
90
|
export interface CodemodeFactoryContext {
|
|
91
|
-
config: Pick<AmaConfig, "tools" | "codemode">;
|
|
91
|
+
config: Pick<AmaConfig, "tools" | "codemode" | "sandbox">;
|
|
92
92
|
registry: {
|
|
93
93
|
list(): readonly string[];
|
|
94
94
|
get(name: string): ToolDefinition | undefined;
|
package/dist/codemode/tool.js
CHANGED
|
@@ -20,7 +20,7 @@ import { mkdirSync, writeFileSync } from "node:fs";
|
|
|
20
20
|
import { tmpdir } from "node:os";
|
|
21
21
|
import { join } from "node:path";
|
|
22
22
|
import { codemodeCallableFilter, resolveCodemodeMode } from "../tools/presets.js";
|
|
23
|
-
import { codemodeAvailability, detectSandboxCapability, } from "./capability.js";
|
|
23
|
+
import { codemodeAvailability, detectSandboxCapability, sandboxCapabilityFor, strictNeedsOsSandbox, } from "./capability.js";
|
|
24
24
|
import { BASH_RESULT_DECLARATION, DEFAULT_INLINE_BUDGET, buildDeclarationBlock, toolDeclaration, } from "./declarations.js";
|
|
25
25
|
import { runSandbox } from "./host-side.js";
|
|
26
26
|
import { parseOptionsLine } from "./protocol.js";
|
|
@@ -189,8 +189,8 @@ export function createCodemodeTool(options) {
|
|
|
189
189
|
},
|
|
190
190
|
required: ["script"],
|
|
191
191
|
},
|
|
192
|
-
// 网络隔离(Node ≥ 25
|
|
193
|
-
// 类(default 模式免审批);不隔离网络时脚本逃出 vm 就能联网,仍按 execute。
|
|
192
|
+
// 网络隔离(Node ≥ 25,或 OS 沙箱)时脚本只能经 tools.* 做事,每次内层调用各自过权限:codemode
|
|
193
|
+
// 本身按 read 类(default 模式免审批);不隔离网络时脚本逃出 vm 就能联网,仍按 execute。
|
|
194
194
|
permission: capability.strict ? "read" : "execute",
|
|
195
195
|
executionMode: "sequential",
|
|
196
196
|
promptSnippet: options.exclusive === true
|
|
@@ -218,6 +218,8 @@ export function createCodemodeTool(options) {
|
|
|
218
218
|
tools,
|
|
219
219
|
store: readStore(ctx.session),
|
|
220
220
|
signal: ctx.signal,
|
|
221
|
+
os: capability.os,
|
|
222
|
+
requireOsSandbox: strictNeedsOsSandbox(capability),
|
|
221
223
|
...(options.entry !== undefined ? { entry: options.entry } : {}),
|
|
222
224
|
...(options.nodePath !== undefined ? { nodePath: options.nodePath } : {}),
|
|
223
225
|
callTool: async (name, args, signal) => {
|
|
@@ -280,7 +282,7 @@ export function createCodemodeTool(options) {
|
|
|
280
282
|
*/
|
|
281
283
|
export function codemodeToolFactory(overrides = {}) {
|
|
282
284
|
return (ctx) => {
|
|
283
|
-
const capability = overrides.capability ??
|
|
285
|
+
const capability = overrides.capability ?? sandboxCapabilityFor(ctx.config);
|
|
284
286
|
const mode = resolveCodemodeMode(ctx.config, capability.strict).mode;
|
|
285
287
|
if (mode === "off")
|
|
286
288
|
return undefined;
|
|
@@ -1,31 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 压缩熔断(设计 §9
|
|
2
|
+
* 压缩熔断(设计 §9「熔断」,wave5 §8.2 C5)。[B2][W5-H1]
|
|
3
3
|
*
|
|
4
4
|
* - 无 `contextWindow` 或配置关闭 → 自动压缩关闭(手动 /compact 仍可用)。
|
|
5
|
-
* -
|
|
6
|
-
*
|
|
5
|
+
* - 不再限制「每 run 档二 ≤ 1 次」(单提示长任务需要多次摘要);改为两种跳闸:
|
|
6
|
+
* - 连续 3 次摘要失败;
|
|
7
|
+
* - 快速回填:连续 3 次摘要都在上一次摘要后不到 3 回合就又需要摘要(压缩不动、越压越满)。
|
|
8
|
+
* 跳闸后关闭自动压缩直到 `reset()`(例如用户手动压缩成功)。
|
|
9
|
+
* - 固定前缀(system + 工具表)已超过预算:摘要无济于事,直接告警、不再尝试(`prefix_overflow`,
|
|
10
|
+
* 由调用方每次检查时更新)。
|
|
11
|
+
* - 「nothing to compact」不计失败(调用方不调 `recordSummary`)。
|
|
7
12
|
* - 溢出恢复:压缩后估算仍 > 0.8 × window → 不重试。
|
|
8
13
|
*/
|
|
9
|
-
export declare const
|
|
10
|
-
|
|
14
|
+
export declare const MAX_CONSECUTIVE_FAILURES = 3;
|
|
15
|
+
/** 上一次摘要后不到这么多回合又需要摘要,记一次快速回填。 */
|
|
16
|
+
export declare const RAPID_REFILL_TURNS = 3;
|
|
17
|
+
export declare const MAX_RAPID_REFILLS = 3;
|
|
11
18
|
export declare const RETRY_AFTER_COMPACTION_RATIO = 0.8;
|
|
12
|
-
export type BreakerBlockReason = "disabled" | "no_window" | "tripped" | "
|
|
19
|
+
export type BreakerBlockReason = "disabled" | "no_window" | "tripped" | "rapid_refill" | "prefix_overflow";
|
|
13
20
|
export declare class CompactionBreaker {
|
|
14
|
-
private summariesThisRun;
|
|
15
21
|
private consecutiveFailures;
|
|
22
|
+
private rapidRefills;
|
|
23
|
+
private turn;
|
|
24
|
+
private lastSummaryTurn;
|
|
25
|
+
private prefixOverflow;
|
|
16
26
|
private enabled;
|
|
17
27
|
private contextWindow;
|
|
18
28
|
constructor(enabled: boolean, contextWindow: number | undefined);
|
|
19
29
|
configure(enabled: boolean, contextWindow: number | undefined): void;
|
|
30
|
+
/** 连续失败或快速回填跳闸(溢出恢复也不再尝试)。 */
|
|
20
31
|
get tripped(): boolean;
|
|
21
|
-
/**
|
|
32
|
+
/** 自动压缩整体是否开启。 */
|
|
22
33
|
get autoEnabled(): boolean;
|
|
34
|
+
/** 新 run 开始(会话在 agent_start 时调用);不再重置任何计数,保留以兼容调用点。 */
|
|
23
35
|
startRun(): void;
|
|
36
|
+
/** 每次请求前的阈值检查调用一次:回合计数(快速回填按它判断)。 */
|
|
37
|
+
tick(): void;
|
|
38
|
+
/** 固定前缀是否已超预算(调用方每次准备摘要前更新)。 */
|
|
39
|
+
setPrefixOverflow(overflow: boolean): void;
|
|
24
40
|
/** 自动档二能否执行;不能则给出原因。 */
|
|
25
41
|
blockReason(): BreakerBlockReason | undefined;
|
|
26
42
|
canSummarize(): boolean;
|
|
27
43
|
recordSummary(success: boolean): void;
|
|
28
|
-
/**
|
|
44
|
+
/** 手动压缩成功等场景:清零全部计数。 */
|
|
29
45
|
reset(): void;
|
|
30
46
|
/** 溢出恢复后是否值得重试。 */
|
|
31
47
|
shouldRetryAfterCompaction(tokensAfter: number): boolean;
|