@armadra/agent 0.0.0-stage → 0.3.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 +37 -0
- package/LICENSE +21 -0
- package/README.md +470 -2
- package/dist/agent/agent.d.ts +56 -0
- package/dist/agent/agent.js +129 -0
- package/dist/agent/loop.d.ts +51 -0
- package/dist/agent/loop.js +158 -0
- package/dist/agent/queue.d.ts +25 -0
- package/dist/agent/queue.js +55 -0
- package/dist/agent/retry.d.ts +22 -0
- package/dist/agent/retry.js +92 -0
- package/dist/agent/schema.d.ts +27 -0
- package/dist/agent/schema.js +186 -0
- package/dist/agent/session-cache.d.ts +100 -0
- package/dist/agent/session-cache.js +514 -0
- package/dist/agent/session-compaction.d.ts +49 -0
- package/dist/agent/session-compaction.js +251 -0
- package/dist/agent/session-core.d.ts +103 -0
- package/dist/agent/session-core.js +7 -0
- package/dist/agent/session-run.d.ts +55 -0
- package/dist/agent/session-run.js +246 -0
- package/dist/agent/session-state.d.ts +39 -0
- package/dist/agent/session-state.js +119 -0
- package/dist/agent/session-subagent.d.ts +54 -0
- package/dist/agent/session-subagent.js +157 -0
- package/dist/agent/session-sync.d.ts +20 -0
- package/dist/agent/session-sync.js +111 -0
- package/dist/agent/session-tools.d.ts +24 -0
- package/dist/agent/session-tools.js +277 -0
- package/dist/agent/session.d.ts +117 -0
- package/dist/agent/session.js +485 -0
- package/dist/agent/system-prompt.d.ts +49 -0
- package/dist/agent/system-prompt.js +121 -0
- package/dist/agent/tool-runner.d.ts +64 -0
- package/dist/agent/tool-runner.js +309 -0
- package/dist/agent/transform.d.ts +26 -0
- package/dist/agent/transform.js +171 -0
- package/dist/agent/types.d.ts +378 -0
- package/dist/agent/types.js +21 -0
- package/dist/ai/apis/anthropic-messages.d.ts +26 -0
- package/dist/ai/apis/anthropic-messages.js +214 -0
- package/dist/ai/apis/anthropic-request.d.ts +42 -0
- package/dist/ai/apis/anthropic-request.js +282 -0
- package/dist/ai/apis/api.d.ts +28 -0
- package/dist/ai/apis/api.js +102 -0
- package/dist/ai/apis/cache-params.d.ts +48 -0
- package/dist/ai/apis/cache-params.js +163 -0
- package/dist/ai/apis/google-generative-ai.d.ts +32 -0
- package/dist/ai/apis/google-generative-ai.js +249 -0
- package/dist/ai/apis/google-request.d.ts +40 -0
- package/dist/ai/apis/google-request.js +255 -0
- package/dist/ai/apis/openai-compat.d.ts +35 -0
- package/dist/ai/apis/openai-compat.js +142 -0
- package/dist/ai/apis/openai-completions.d.ts +28 -0
- package/dist/ai/apis/openai-completions.js +246 -0
- package/dist/ai/apis/openai-request.d.ts +35 -0
- package/dist/ai/apis/openai-request.js +303 -0
- package/dist/ai/apis/openai-responses-request.d.ts +52 -0
- package/dist/ai/apis/openai-responses-request.js +266 -0
- package/dist/ai/apis/openai-responses.d.ts +28 -0
- package/dist/ai/apis/openai-responses.js +304 -0
- package/dist/ai/apis/shared.d.ts +56 -0
- package/dist/ai/apis/shared.js +179 -0
- package/dist/ai/cache/economics.d.ts +24 -0
- package/dist/ai/cache/economics.js +69 -0
- package/dist/ai/cache/fingerprint.d.ts +17 -0
- package/dist/ai/cache/fingerprint.js +39 -0
- package/dist/ai/cache/miss.d.ts +49 -0
- package/dist/ai/cache/miss.js +96 -0
- package/dist/ai/cache/reporting.d.ts +39 -0
- package/dist/ai/cache/reporting.js +103 -0
- package/dist/ai/cache/types.d.ts +94 -0
- package/dist/ai/cache/types.js +19 -0
- package/dist/ai/cache/warmer.d.ts +94 -0
- package/dist/ai/cache/warmer.js +224 -0
- package/dist/ai/context.d.ts +35 -0
- package/dist/ai/context.js +114 -0
- package/dist/ai/cost.d.ts +21 -0
- package/dist/ai/cost.js +60 -0
- package/dist/ai/event-stream.d.ts +33 -0
- package/dist/ai/event-stream.js +101 -0
- package/dist/ai/fake/fake-provider.d.ts +68 -0
- package/dist/ai/fake/fake-provider.js +278 -0
- package/dist/ai/fake/fake-script.d.ts +69 -0
- package/dist/ai/fake/fake-script.js +142 -0
- package/dist/ai/http.d.ts +54 -0
- package/dist/ai/http.js +212 -0
- package/dist/ai/json-partial.d.ts +17 -0
- package/dist/ai/json-partial.js +243 -0
- package/dist/ai/overflow.d.ts +22 -0
- package/dist/ai/overflow.js +61 -0
- package/dist/ai/providers/auth.d.ts +71 -0
- package/dist/ai/providers/auth.js +202 -0
- package/dist/ai/providers/builtin.d.ts +23 -0
- package/dist/ai/providers/builtin.js +148 -0
- package/dist/ai/providers/catalog-data.d.ts +5 -0
- package/dist/ai/providers/catalog-data.js +19 -0
- package/dist/ai/providers/catalog.d.ts +28 -0
- package/dist/ai/providers/catalog.js +166 -0
- package/dist/ai/providers/channels.d.ts +51 -0
- package/dist/ai/providers/channels.js +96 -0
- package/dist/ai/providers/enrich.d.ts +34 -0
- package/dist/ai/providers/enrich.js +86 -0
- package/dist/ai/providers/models-dev-cache.d.ts +53 -0
- package/dist/ai/providers/models-dev-cache.js +147 -0
- package/dist/ai/providers/models-dev.d.ts +99 -0
- package/dist/ai/providers/models-dev.js +315 -0
- package/dist/ai/providers/registry.d.ts +114 -0
- package/dist/ai/providers/registry.js +458 -0
- package/dist/ai/sse.d.ts +32 -0
- package/dist/ai/sse.js +140 -0
- package/dist/ai/thinking.d.ts +42 -0
- package/dist/ai/thinking.js +101 -0
- package/dist/ai/types.d.ts +448 -0
- package/dist/ai/types.js +19 -0
- package/dist/bundle/ama-sandbox.cjs +324 -0
- package/dist/bundle/ama.cjs +27837 -0
- package/dist/bundle.d.ts +9 -0
- package/dist/bundle.js +15 -0
- package/dist/cli/args.d.ts +85 -0
- package/dist/cli/args.js +408 -0
- package/dist/cli/bootstrap.d.ts +18 -0
- package/dist/cli/bootstrap.js +399 -0
- package/dist/cli/compose-providers.d.ts +37 -0
- package/dist/cli/compose-providers.js +107 -0
- package/dist/cli/compose-session.d.ts +72 -0
- package/dist/cli/compose-session.js +370 -0
- package/dist/cli/compose-store.d.ts +24 -0
- package/dist/cli/compose-store.js +125 -0
- package/dist/cli/compose.d.ts +108 -0
- package/dist/cli/compose.js +221 -0
- package/dist/cli/default-model.d.ts +16 -0
- package/dist/cli/default-model.js +24 -0
- package/dist/cli/deps.d.ts +207 -0
- package/dist/cli/deps.js +12 -0
- package/dist/cli/exit-codes.d.ts +29 -0
- package/dist/cli/exit-codes.js +40 -0
- package/dist/cli/main.d.ts +27 -0
- package/dist/cli/main.js +177 -0
- package/dist/cli/runtime.d.ts +90 -0
- package/dist/cli/runtime.js +8 -0
- package/dist/cli/startup-screen.d.ts +15 -0
- package/dist/cli/startup-screen.js +56 -0
- package/dist/cli/startup-steps.d.ts +35 -0
- package/dist/cli/startup-steps.js +202 -0
- package/dist/cli/subcommands/auth.d.ts +12 -0
- package/dist/cli/subcommands/auth.js +91 -0
- package/dist/cli/subcommands/config.d.ts +53 -0
- package/dist/cli/subcommands/config.js +277 -0
- package/dist/cli/subcommands/context.d.ts +21 -0
- package/dist/cli/subcommands/context.js +42 -0
- package/dist/cli/subcommands/doctor.d.ts +11 -0
- package/dist/cli/subcommands/doctor.js +246 -0
- package/dist/cli/subcommands/init.d.ts +6 -0
- package/dist/cli/subcommands/init.js +22 -0
- package/dist/cli/subcommands/model-meta.d.ts +16 -0
- package/dist/cli/subcommands/model-meta.js +54 -0
- package/dist/cli/subcommands/models-cache-probe.d.ts +34 -0
- package/dist/cli/subcommands/models-cache-probe.js +190 -0
- package/dist/cli/subcommands/models-discover.d.ts +46 -0
- package/dist/cli/subcommands/models-discover.js +232 -0
- package/dist/cli/subcommands/models.d.ts +40 -0
- package/dist/cli/subcommands/models.js +152 -0
- package/dist/cli/subcommands/providers-list.d.ts +8 -0
- package/dist/cli/subcommands/providers-list.js +97 -0
- package/dist/cli/subcommands/providers-plan.d.ts +79 -0
- package/dist/cli/subcommands/providers-plan.js +215 -0
- package/dist/cli/subcommands/providers.d.ts +27 -0
- package/dist/cli/subcommands/providers.js +433 -0
- package/dist/cli/subcommands/sessions.d.ts +11 -0
- package/dist/cli/subcommands/sessions.js +100 -0
- package/dist/codemode/capability.d.ts +37 -0
- package/dist/codemode/capability.js +55 -0
- package/dist/codemode/declarations.d.ts +44 -0
- package/dist/codemode/declarations.js +111 -0
- package/dist/codemode/host-side.d.ts +59 -0
- package/dist/codemode/host-side.js +253 -0
- package/dist/codemode/modes.d.ts +23 -0
- package/dist/codemode/modes.js +40 -0
- package/dist/codemode/protocol.d.ts +91 -0
- package/dist/codemode/protocol.js +114 -0
- package/dist/codemode/sandbox-entry.d.ts +25 -0
- package/dist/codemode/sandbox-entry.js +323 -0
- package/dist/codemode/store.d.ts +26 -0
- package/dist/codemode/store.js +53 -0
- package/dist/codemode/tool.d.ts +105 -0
- package/dist/codemode/tool.js +283 -0
- package/dist/compaction/branch-summary.d.ts +30 -0
- package/dist/compaction/branch-summary.js +79 -0
- package/dist/compaction/breaker.d.ts +32 -0
- package/dist/compaction/breaker.js +65 -0
- package/dist/compaction/cut-point.d.ts +23 -0
- package/dist/compaction/cut-point.js +70 -0
- package/dist/compaction/estimate.d.ts +30 -0
- package/dist/compaction/estimate.js +114 -0
- package/dist/compaction/prune-tier.d.ts +31 -0
- package/dist/compaction/prune-tier.js +83 -0
- package/dist/compaction/serialize.d.ts +20 -0
- package/dist/compaction/serialize.js +115 -0
- package/dist/compaction/summarize-tier.d.ts +111 -0
- package/dist/compaction/summarize-tier.js +305 -0
- package/dist/config/auth-file.d.ts +39 -0
- package/dist/config/auth-file.js +92 -0
- package/dist/config/context-files.d.ts +30 -0
- package/dist/config/context-files.js +77 -0
- package/dist/config/init.d.ts +30 -0
- package/dist/config/init.js +92 -0
- package/dist/config/json-schema.d.ts +14 -0
- package/dist/config/json-schema.js +182 -0
- package/dist/config/load.d.ts +45 -0
- package/dist/config/load.js +97 -0
- package/dist/config/merge.d.ts +73 -0
- package/dist/config/merge.js +248 -0
- package/dist/config/paths.d.ts +38 -0
- package/dist/config/paths.js +108 -0
- package/dist/config/profile.d.ts +27 -0
- package/dist/config/profile.js +65 -0
- package/dist/config/schema.d.ts +34 -0
- package/dist/config/schema.js +476 -0
- package/dist/config/trust.d.ts +42 -0
- package/dist/config/trust.js +122 -0
- package/dist/config/types.d.ts +190 -0
- package/dist/config/types.js +29 -0
- package/dist/config/write.d.ts +10 -0
- package/dist/config/write.js +25 -0
- package/dist/errors.d.ts +28 -0
- package/dist/errors.js +30 -0
- package/dist/hooks/config.d.ts +49 -0
- package/dist/hooks/config.js +102 -0
- package/dist/hooks/dispatcher.d.ts +41 -0
- package/dist/hooks/dispatcher.js +104 -0
- package/dist/hooks/matcher.d.ts +22 -0
- package/dist/hooks/matcher.js +108 -0
- package/dist/hooks/protocol.d.ts +33 -0
- package/dist/hooks/protocol.js +240 -0
- package/dist/hooks/runner.d.ts +30 -0
- package/dist/hooks/runner.js +143 -0
- package/dist/hooks/types.d.ts +147 -0
- package/dist/hooks/types.js +20 -0
- package/dist/host/api-impl.d.ts +75 -0
- package/dist/host/api-impl.js +173 -0
- package/dist/host/loader.d.ts +31 -0
- package/dist/host/loader.js +147 -0
- package/dist/host/types.d.ts +169 -0
- package/dist/host/types.js +14 -0
- package/dist/host.d.ts +5 -0
- package/dist/host.js +4 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +28 -0
- package/dist/modes/commands-core.d.ts +44 -0
- package/dist/modes/commands-core.js +171 -0
- package/dist/modes/image-input.d.ts +27 -0
- package/dist/modes/image-input.js +78 -0
- package/dist/modes/interactive/approval-dialog.d.ts +48 -0
- package/dist/modes/interactive/approval-dialog.js +202 -0
- package/dist/modes/interactive/commands.d.ts +41 -0
- package/dist/modes/interactive/commands.js +201 -0
- package/dist/modes/interactive/completion.d.ts +53 -0
- package/dist/modes/interactive/completion.js +157 -0
- package/dist/modes/interactive/interactive-mode.d.ts +46 -0
- package/dist/modes/interactive/interactive-mode.js +491 -0
- package/dist/modes/interactive/key-dispatch.d.ts +29 -0
- package/dist/modes/interactive/key-dispatch.js +107 -0
- package/dist/modes/interactive/line/line-editor.d.ts +50 -0
- package/dist/modes/interactive/line/line-editor.js +232 -0
- package/dist/modes/interactive/line/line-mode.d.ts +20 -0
- package/dist/modes/interactive/line/line-mode.js +218 -0
- package/dist/modes/interactive/line/line-render.d.ts +35 -0
- package/dist/modes/interactive/line/line-render.js +171 -0
- package/dist/modes/interactive/line/paste-state.d.ts +26 -0
- package/dist/modes/interactive/line/paste-state.js +72 -0
- package/dist/modes/interactive/message-view.d.ts +77 -0
- package/dist/modes/interactive/message-view.js +269 -0
- package/dist/modes/interactive/pickers.d.ts +42 -0
- package/dist/modes/interactive/pickers.js +115 -0
- package/dist/modes/interactive/startup-ui.d.ts +33 -0
- package/dist/modes/interactive/startup-ui.js +268 -0
- package/dist/modes/interactive/status-bar.d.ts +48 -0
- package/dist/modes/interactive/status-bar.js +139 -0
- package/dist/modes/interactive/tool-view.d.ts +95 -0
- package/dist/modes/interactive/tool-view.js +344 -0
- package/dist/modes/print/json-event.d.ts +15 -0
- package/dist/modes/print/json-event.js +39 -0
- package/dist/modes/print/print-mode.d.ts +17 -0
- package/dist/modes/print/print-mode.js +107 -0
- package/dist/modes/rpc/commands.d.ts +40 -0
- package/dist/modes/rpc/commands.js +263 -0
- package/dist/modes/rpc/jsonl.d.ts +16 -0
- package/dist/modes/rpc/jsonl.js +55 -0
- package/dist/modes/rpc/rpc-mode.d.ts +22 -0
- package/dist/modes/rpc/rpc-mode.js +153 -0
- package/dist/modes/session-report.d.ts +55 -0
- package/dist/modes/session-report.js +278 -0
- package/dist/modes/shared.d.ts +13 -0
- package/dist/modes/shared.js +52 -0
- package/dist/modes/startup-ui-text.d.ts +16 -0
- package/dist/modes/startup-ui-text.js +103 -0
- package/dist/permissions/broker.d.ts +47 -0
- package/dist/permissions/broker.js +107 -0
- package/dist/permissions/dangerous.d.ts +47 -0
- package/dist/permissions/dangerous.js +370 -0
- package/dist/permissions/pipeline.d.ts +51 -0
- package/dist/permissions/pipeline.js +181 -0
- package/dist/permissions/preview.d.ts +43 -0
- package/dist/permissions/preview.js +463 -0
- package/dist/permissions/rules.d.ts +58 -0
- package/dist/permissions/rules.js +249 -0
- package/dist/permissions/types.d.ts +100 -0
- package/dist/permissions/types.js +18 -0
- package/dist/rpc.d.ts +173 -0
- package/dist/rpc.js +13 -0
- package/dist/sdk.d.ts +98 -0
- package/dist/sdk.js +195 -0
- package/dist/session/manager.d.ts +70 -0
- package/dist/session/manager.js +278 -0
- package/dist/session/migrate.d.ts +19 -0
- package/dist/session/migrate.js +53 -0
- package/dist/session/projection.d.ts +50 -0
- package/dist/session/projection.js +184 -0
- package/dist/session/store.d.ts +47 -0
- package/dist/session/store.js +210 -0
- package/dist/session/tree.d.ts +21 -0
- package/dist/session/tree.js +88 -0
- package/dist/session/types.d.ts +201 -0
- package/dist/session/types.js +18 -0
- package/dist/skills/discover.d.ts +60 -0
- package/dist/skills/discover.js +160 -0
- package/dist/skills/expand.d.ts +35 -0
- package/dist/skills/expand.js +46 -0
- package/dist/skills/frontmatter.d.ts +27 -0
- package/dist/skills/frontmatter.js +157 -0
- package/dist/skills/index-prompt.d.ts +13 -0
- package/dist/skills/index-prompt.js +42 -0
- package/dist/skills/templates.d.ts +52 -0
- package/dist/skills/templates.js +177 -0
- package/dist/tools/bash.d.ts +49 -0
- package/dist/tools/bash.js +222 -0
- package/dist/tools/edit-fuzzy.d.ts +36 -0
- package/dist/tools/edit-fuzzy.js +129 -0
- package/dist/tools/edit.d.ts +38 -0
- package/dist/tools/edit.js +241 -0
- package/dist/tools/file-mutex.d.ts +8 -0
- package/dist/tools/file-mutex.js +29 -0
- package/dist/tools/glob.d.ts +44 -0
- package/dist/tools/glob.js +217 -0
- package/dist/tools/grep.d.ts +39 -0
- package/dist/tools/grep.js +179 -0
- package/dist/tools/ignore.d.ts +40 -0
- package/dist/tools/ignore.js +174 -0
- package/dist/tools/image-file.d.ts +31 -0
- package/dist/tools/image-file.js +114 -0
- package/dist/tools/ls.d.ts +21 -0
- package/dist/tools/ls.js +96 -0
- package/dist/tools/output-accumulator.d.ts +48 -0
- package/dist/tools/output-accumulator.js +106 -0
- package/dist/tools/paths.d.ts +20 -0
- package/dist/tools/paths.js +58 -0
- package/dist/tools/presets.d.ts +71 -0
- package/dist/tools/presets.js +128 -0
- package/dist/tools/process-tree.d.ts +35 -0
- package/dist/tools/process-tree.js +125 -0
- package/dist/tools/read.d.ts +24 -0
- package/dist/tools/read.js +132 -0
- package/dist/tools/registry.d.ts +43 -0
- package/dist/tools/registry.js +106 -0
- package/dist/tools/shell.d.ts +38 -0
- package/dist/tools/shell.js +91 -0
- package/dist/tools/task.d.ts +29 -0
- package/dist/tools/task.js +107 -0
- package/dist/tools/todo.d.ts +28 -0
- package/dist/tools/todo.js +107 -0
- package/dist/tools/truncate.d.ts +44 -0
- package/dist/tools/truncate.js +175 -0
- package/dist/tools/types.d.ts +135 -0
- package/dist/tools/types.js +19 -0
- package/dist/tools/write.d.ts +20 -0
- package/dist/tools/write.js +84 -0
- package/dist/tui/ansi.d.ts +29 -0
- package/dist/tui/ansi.js +420 -0
- package/dist/tui/component.d.ts +38 -0
- package/dist/tui/component.js +13 -0
- package/dist/tui/components/box.d.ts +26 -0
- package/dist/tui/components/box.js +65 -0
- package/dist/tui/components/container.d.ts +14 -0
- package/dist/tui/components/container.js +39 -0
- package/dist/tui/components/editor-buffer.d.ts +67 -0
- package/dist/tui/components/editor-buffer.js +300 -0
- package/dist/tui/components/editor-paste.d.ts +29 -0
- package/dist/tui/components/editor-paste.js +64 -0
- package/dist/tui/components/editor.d.ts +114 -0
- package/dist/tui/components/editor.js +530 -0
- package/dist/tui/components/key-value.d.ts +29 -0
- package/dist/tui/components/key-value.js +48 -0
- package/dist/tui/components/loader.d.ts +35 -0
- package/dist/tui/components/loader.js +71 -0
- package/dist/tui/components/markdown.d.ts +90 -0
- package/dist/tui/components/markdown.js +462 -0
- package/dist/tui/components/meter.d.ts +29 -0
- package/dist/tui/components/meter.js +47 -0
- package/dist/tui/components/overlay.d.ts +24 -0
- package/dist/tui/components/overlay.js +52 -0
- package/dist/tui/components/select-list.d.ts +57 -0
- package/dist/tui/components/select-list.js +179 -0
- package/dist/tui/components/spacer.d.ts +11 -0
- package/dist/tui/components/spacer.js +16 -0
- package/dist/tui/components/text.d.ts +30 -0
- package/dist/tui/components/text.js +65 -0
- package/dist/tui/keybindings.d.ts +66 -0
- package/dist/tui/keybindings.js +120 -0
- package/dist/tui/keys.d.ts +38 -0
- package/dist/tui/keys.js +275 -0
- package/dist/tui/stdin-buffer.d.ts +41 -0
- package/dist/tui/stdin-buffer.js +206 -0
- package/dist/tui/terminal.d.ts +79 -0
- package/dist/tui/terminal.js +153 -0
- package/dist/tui/theme.d.ts +31 -0
- package/dist/tui/theme.js +199 -0
- package/dist/tui/tui.d.ts +103 -0
- package/dist/tui/tui.js +363 -0
- package/dist/tui/vt-screen.d.ts +46 -0
- package/dist/tui/vt-screen.js +251 -0
- package/dist/tui.d.ts +30 -0
- package/dist/tui.js +31 -0
- package/dist/version.d.ts +8 -0
- package/dist/version.js +24 -0
- package/docs/codemode.md +102 -0
- package/docs/hooks.md +196 -0
- package/docs/host-api.md +161 -0
- package/docs/providers.md +531 -0
- package/docs/rpc.md +253 -0
- package/docs/session-format.md +119 -0
- package/docs/tui.md +170 -0
- package/package.json +101 -4
package/dist/cli/main.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* bin 入口(设计 §11.1 第 1–2 步)。[B5]
|
|
4
|
+
*
|
|
5
|
+
* - 设 `AMA=1`、`AI_AGENT=ama`;直接执行时装 `uncaughtException` / `unhandledRejection` →
|
|
6
|
+
* stderr 一行 + 退出码 1;SIGINT / SIGTERM 交给当前模式。
|
|
7
|
+
* - `--version` / `--help` 短路;子命令 `auth / sessions / models / providers / doctor / config /
|
|
8
|
+
* init` 分派后返回;其余命令启动前若配置目录不存在则静默初始化(`AMA_NO_INIT=1` 关闭);
|
|
9
|
+
* 其余交给 `runCli()`(bootstrap → 模式)。
|
|
10
|
+
* - 运行时实现(RuntimeDeps):`MainOptions.deps` > `registerRuntimeDeps()` > 组装根
|
|
11
|
+
* `createRuntimeDeps()`(cli/compose.ts,动态 import)。
|
|
12
|
+
* - 签名 `main(argv): Promise<number>` 与「直接执行才自动运行」判定保持不变:
|
|
13
|
+
* src/bundle.ts 显式调用 `main()`。
|
|
14
|
+
*/
|
|
15
|
+
import { realpathSync } from "node:fs";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
import { AMA_VERSION } from "../version.js";
|
|
18
|
+
import { parseArgs } from "./args.js";
|
|
19
|
+
import { reportError, runCli } from "./bootstrap.js";
|
|
20
|
+
import { ExitCode } from "./exit-codes.js";
|
|
21
|
+
import { runAuth } from "./subcommands/auth.js";
|
|
22
|
+
import { runConfig } from "./subcommands/config.js";
|
|
23
|
+
import { runDoctor } from "./subcommands/doctor.js";
|
|
24
|
+
import { runModels } from "./subcommands/models.js";
|
|
25
|
+
import { runProviders } from "./subcommands/providers.js";
|
|
26
|
+
import { runInit } from "./subcommands/init.js";
|
|
27
|
+
import { autoInitConfigDir } from "../config/init.js";
|
|
28
|
+
import { resolveConfigDir } from "../config/paths.js";
|
|
29
|
+
import { runSessions } from "./subcommands/sessions.js";
|
|
30
|
+
let registeredDeps;
|
|
31
|
+
/** 集成批次注入运行时实现(B1 / B2 / B3 / B6 / B7)。 */
|
|
32
|
+
export function registerRuntimeDeps(deps) {
|
|
33
|
+
registeredDeps = deps;
|
|
34
|
+
}
|
|
35
|
+
/** 读 stdin 全部内容;TTY 下只读一行且不回显(auth set)。 */
|
|
36
|
+
export function readStdinDefault() {
|
|
37
|
+
const stdin = process.stdin;
|
|
38
|
+
if (!stdin.isTTY) {
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
const chunks = [];
|
|
41
|
+
stdin.on("data", (chunk) => chunks.push(chunk));
|
|
42
|
+
stdin.once("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
43
|
+
stdin.once("error", reject);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return new Promise((resolve) => {
|
|
47
|
+
let line = "";
|
|
48
|
+
stdin.setRawMode(true);
|
|
49
|
+
stdin.resume();
|
|
50
|
+
const onData = (chunk) => {
|
|
51
|
+
for (const ch of chunk.toString("utf8")) {
|
|
52
|
+
if (ch === "\r" || ch === "\n" || ch === "\u0004") {
|
|
53
|
+
stdin.off("data", onData);
|
|
54
|
+
stdin.setRawMode(false);
|
|
55
|
+
stdin.pause();
|
|
56
|
+
resolve(line);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (ch === "\u0003") {
|
|
60
|
+
stdin.off("data", onData);
|
|
61
|
+
stdin.setRawMode(false);
|
|
62
|
+
stdin.pause();
|
|
63
|
+
resolve("");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (ch === "\u007f" || ch === "\b")
|
|
67
|
+
line = line.slice(0, -1);
|
|
68
|
+
else
|
|
69
|
+
line += ch;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
stdin.on("data", onData);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
export function defaultIo() {
|
|
76
|
+
return {
|
|
77
|
+
stdout: (text) => void process.stdout.write(text),
|
|
78
|
+
stderr: (text) => void process.stderr.write(text),
|
|
79
|
+
stdinIsTTY: process.stdin.isTTY === true,
|
|
80
|
+
stdoutIsTTY: process.stdout.isTTY === true,
|
|
81
|
+
env: process.env,
|
|
82
|
+
cwd: process.cwd(),
|
|
83
|
+
readStdin: readStdinDefault,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
let hooksInstalled = false;
|
|
87
|
+
function installProcessHooks(io) {
|
|
88
|
+
if (hooksInstalled)
|
|
89
|
+
return;
|
|
90
|
+
hooksInstalled = true;
|
|
91
|
+
const fatal = (error) => {
|
|
92
|
+
const message = error instanceof Error ? (error.stack ?? error.message) : String(error);
|
|
93
|
+
io.stderr(`ama: 未捕获的异常:${message.split("\n")[0] ?? ""}\n`);
|
|
94
|
+
process.exit(ExitCode.RuntimeError);
|
|
95
|
+
};
|
|
96
|
+
process.on("uncaughtException", fatal);
|
|
97
|
+
process.on("unhandledRejection", fatal);
|
|
98
|
+
}
|
|
99
|
+
export async function main(argv, options = {}) {
|
|
100
|
+
const io = { ...defaultIo(), ...options.io };
|
|
101
|
+
process.env["AMA"] = "1";
|
|
102
|
+
process.env["AI_AGENT"] = "ama";
|
|
103
|
+
const [first] = argv;
|
|
104
|
+
if (argv.length === 1 && (first === "--version" || first === "-v")) {
|
|
105
|
+
io.stdout(`${AMA_VERSION}\n`);
|
|
106
|
+
return ExitCode.Ok;
|
|
107
|
+
}
|
|
108
|
+
if (options.processHooks !== false)
|
|
109
|
+
installProcessHooks(io);
|
|
110
|
+
// 缺省装配走动态 import:--version / auth 不加载运行时实现(bundle 里同样内联)。
|
|
111
|
+
// io 交给组装根决定启动期问答(迷你 TUI / 文本 / 不问);--no-tui 在解析后才知道。
|
|
112
|
+
let noTui = false;
|
|
113
|
+
const resolveDeps = async () => options.deps ??
|
|
114
|
+
registeredDeps ??
|
|
115
|
+
(await import("./compose.js")).createRuntimeDeps({
|
|
116
|
+
env: io.env,
|
|
117
|
+
io,
|
|
118
|
+
noTui,
|
|
119
|
+
});
|
|
120
|
+
try {
|
|
121
|
+
const parsed = parseArgs(argv);
|
|
122
|
+
if (parsed.kind !== "subcommand")
|
|
123
|
+
noTui = parsed.args.noTui;
|
|
124
|
+
const informational = parsed.kind === "run" ? parsed.args.help || parsed.args.version : parsed.name === "init";
|
|
125
|
+
if (!informational)
|
|
126
|
+
autoInitConfigDir(resolveConfigDir({ env: io.env }), io.env);
|
|
127
|
+
if (parsed.kind === "subcommand") {
|
|
128
|
+
switch (parsed.name) {
|
|
129
|
+
case "auth":
|
|
130
|
+
return await runAuth(parsed.argv, io);
|
|
131
|
+
case "sessions":
|
|
132
|
+
return await runSessions(parsed.argv, io, await resolveDeps());
|
|
133
|
+
case "models":
|
|
134
|
+
return await runModels(parsed.argv, io, await resolveDeps());
|
|
135
|
+
case "providers":
|
|
136
|
+
return await runProviders(parsed.argv, io, await resolveDeps());
|
|
137
|
+
case "doctor":
|
|
138
|
+
return await runDoctor(parsed.argv, io, await resolveDeps());
|
|
139
|
+
case "config":
|
|
140
|
+
return await runConfig(parsed.argv, io, await resolveDeps());
|
|
141
|
+
case "init":
|
|
142
|
+
return runInit(parsed.argv, io);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (parsed.args.version) {
|
|
146
|
+
io.stdout(`${AMA_VERSION}\n`);
|
|
147
|
+
return ExitCode.Ok;
|
|
148
|
+
}
|
|
149
|
+
if (parsed.args.help)
|
|
150
|
+
return runCli(argv, undefined, io);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
return reportError(error, io);
|
|
154
|
+
}
|
|
155
|
+
return runCli(argv, await resolveDeps(), io);
|
|
156
|
+
}
|
|
157
|
+
function isDirectRun() {
|
|
158
|
+
if (typeof __AMA_BUNDLED__ !== "undefined" && __AMA_BUNDLED__)
|
|
159
|
+
return false;
|
|
160
|
+
const entry = process.argv[1];
|
|
161
|
+
if (entry === undefined)
|
|
162
|
+
return false;
|
|
163
|
+
try {
|
|
164
|
+
return realpathSync(entry) === realpathSync(fileURLToPath(import.meta.url));
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (isDirectRun()) {
|
|
171
|
+
main(process.argv.slice(2)).then((code) => {
|
|
172
|
+
process.exitCode = code;
|
|
173
|
+
}, (error) => {
|
|
174
|
+
process.stderr.write(`ama: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
175
|
+
process.exitCode = ExitCode.RuntimeError;
|
|
176
|
+
});
|
|
177
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime:bootstrap(§11.1 第 5–14 步)的产物,各模式与 SDK `createRuntime()` 共用。
|
|
3
|
+
* [B0] 契约文件,组装归 B5(cli/bootstrap.ts),消费者是 B6 / B7。
|
|
4
|
+
*
|
|
5
|
+
* 补全说明:设计只列了字段名(config、providers、session、hooks、host、permission、tools),
|
|
6
|
+
* 这里补全为各批次的最小接口类型(`*Api`),不依赖任何实现文件。
|
|
7
|
+
*/
|
|
8
|
+
import type { Model, ModelThinkingLevel, ProviderRegistryApi } from "../ai/types.js";
|
|
9
|
+
import type { AgentSession } from "../agent/types.js";
|
|
10
|
+
import type { AmaConfig } from "../config/types.js";
|
|
11
|
+
import type { HookDispatcherApi } from "../hooks/types.js";
|
|
12
|
+
import type { ApprovalBroker, HostAdapterHandle, HostMode, InstructionSource } from "../host/types.js";
|
|
13
|
+
import type { PermissionPipelineApi } from "../permissions/types.js";
|
|
14
|
+
import type { SessionManagerApi } from "../session/types.js";
|
|
15
|
+
import type { ToolRegistryApi } from "../tools/types.js";
|
|
16
|
+
export type RuntimeMode = HostMode;
|
|
17
|
+
export interface ResolvedPaths {
|
|
18
|
+
/** 用户级配置目录(`AMA_CONFIG_DIR` / XDG / `%APPDATA%\ama`)。 */
|
|
19
|
+
configDir: string;
|
|
20
|
+
/** 数据目录(`AMA_DATA_DIR` / `~/.local/share/ama`)。 */
|
|
21
|
+
dataDir: string;
|
|
22
|
+
/** `--session-dir` > profile > `<dataDir>/sessions`。 */
|
|
23
|
+
sessionDir: string;
|
|
24
|
+
/** 会话 cwd。 */
|
|
25
|
+
cwd: string;
|
|
26
|
+
}
|
|
27
|
+
export interface TrustState {
|
|
28
|
+
trusted: boolean;
|
|
29
|
+
/** 决策来源。 */
|
|
30
|
+
source: "flag" | "trust-file" | "prompt" | "profile" | "default";
|
|
31
|
+
/** 命中 trust.json 的祖先目录。 */
|
|
32
|
+
matchedPath?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface LoadedResources {
|
|
35
|
+
/** AGENTS.md 等,外层在前。 */
|
|
36
|
+
contextFiles: readonly {
|
|
37
|
+
path: string;
|
|
38
|
+
content: string;
|
|
39
|
+
}[];
|
|
40
|
+
/** 发现的 Skill(name → SKILL.md 绝对路径)。 */
|
|
41
|
+
skills: readonly {
|
|
42
|
+
name: string;
|
|
43
|
+
description: string;
|
|
44
|
+
location: string;
|
|
45
|
+
}[];
|
|
46
|
+
/** 提示模板(命令名 → 文件)。 */
|
|
47
|
+
prompts: readonly {
|
|
48
|
+
name: string;
|
|
49
|
+
path: string;
|
|
50
|
+
}[];
|
|
51
|
+
instructions: readonly InstructionSource[];
|
|
52
|
+
}
|
|
53
|
+
/** UI 通知:交互模式显示在 TUI,rpc 模式转成事件。 */
|
|
54
|
+
export type UiNotify = (message: string, level: "info" | "warn" | "error") => void;
|
|
55
|
+
/** 模式层晚绑定的审批 UI(B6 / B7 在界面就绪后设置)。 */
|
|
56
|
+
export interface RuntimeApprovals {
|
|
57
|
+
/**
|
|
58
|
+
* 设置 UI broker:排在宿主 broker 之后,宿主不作答(返回 undefined)时由它询问用户;
|
|
59
|
+
* undefined = 撤下(回到无人值守处理)。组装出的会话每次审批现取,设置立即生效。
|
|
60
|
+
*/
|
|
61
|
+
setUiBroker(broker: ApprovalBroker | undefined): void;
|
|
62
|
+
}
|
|
63
|
+
/** 模式层晚绑定的通知出口:宿主 `ui.notify` 转到这里;undefined 恢复为写 stderr。 */
|
|
64
|
+
export interface RuntimeNotifier {
|
|
65
|
+
set(fn?: UiNotify): void;
|
|
66
|
+
}
|
|
67
|
+
export interface Runtime {
|
|
68
|
+
readonly mode: RuntimeMode;
|
|
69
|
+
readonly paths: ResolvedPaths;
|
|
70
|
+
/** 合并后的有效配置。 */
|
|
71
|
+
readonly config: AmaConfig;
|
|
72
|
+
readonly trust: TrustState;
|
|
73
|
+
readonly resources: LoadedResources;
|
|
74
|
+
readonly providers: ProviderRegistryApi;
|
|
75
|
+
readonly model: Model;
|
|
76
|
+
readonly thinkingLevel: ModelThinkingLevel;
|
|
77
|
+
readonly sessionManager: SessionManagerApi;
|
|
78
|
+
readonly session: AgentSession;
|
|
79
|
+
readonly hooks: HookDispatcherApi;
|
|
80
|
+
/** 未激活宿主适配器时为 undefined。 */
|
|
81
|
+
readonly host: HostAdapterHandle | undefined;
|
|
82
|
+
readonly permission: PermissionPipelineApi;
|
|
83
|
+
readonly tools: ToolRegistryApi;
|
|
84
|
+
readonly approvals: RuntimeApprovals;
|
|
85
|
+
readonly notifier: RuntimeNotifier;
|
|
86
|
+
/** 启动期收集的 warning(被忽略的放宽项、文件读错等)。 */
|
|
87
|
+
readonly warnings: readonly string[];
|
|
88
|
+
/** 发 session_shutdown、SessionEnd Hook、适配器 dispose;幂等。 */
|
|
89
|
+
dispose(reason?: "exit" | "new" | "switch"): Promise<void>;
|
|
90
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 启动画面参数与内容(设计 §12.10)。[B5]
|
|
3
|
+
*
|
|
4
|
+
* 档位来源:`--quiet-startup` > 项目 / profile / 用户 config 的 `ui.quietStartup`(合并后)>
|
|
5
|
+
* 有 profile 时缺省 `header` > `normal`。这里只产出纯文本行,着色与布局由界面(B7 / B6 line)负责。
|
|
6
|
+
* - normal:标题行 + 模型 / 信任 / 已加载资源清单 / 警告数
|
|
7
|
+
* - header:只有标题行(版本与按键提示)
|
|
8
|
+
* - silent:不输出
|
|
9
|
+
*/
|
|
10
|
+
import type { Runtime } from "./runtime.js";
|
|
11
|
+
export type StartupScreenLevel = "normal" | "header" | "silent";
|
|
12
|
+
export declare function startupScreenLevel(runtime: Pick<Runtime, "config">): StartupScreenLevel;
|
|
13
|
+
export declare function headerLine(): string;
|
|
14
|
+
export type StartupScreenRuntime = Pick<Runtime, "config" | "trust" | "resources" | "model" | "thinkingLevel" | "hooks" | "host" | "paths" | "warnings">;
|
|
15
|
+
export declare function buildStartupScreen(runtime: StartupScreenRuntime, level?: StartupScreenLevel): string[];
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 启动画面参数与内容(设计 §12.10)。[B5]
|
|
3
|
+
*
|
|
4
|
+
* 档位来源:`--quiet-startup` > 项目 / profile / 用户 config 的 `ui.quietStartup`(合并后)>
|
|
5
|
+
* 有 profile 时缺省 `header` > `normal`。这里只产出纯文本行,着色与布局由界面(B7 / B6 line)负责。
|
|
6
|
+
* - normal:标题行 + 模型 / 信任 / 已加载资源清单 / 警告数
|
|
7
|
+
* - header:只有标题行(版本与按键提示)
|
|
8
|
+
* - silent:不输出
|
|
9
|
+
*/
|
|
10
|
+
import { AMA_VERSION } from "../version.js";
|
|
11
|
+
export function startupScreenLevel(runtime) {
|
|
12
|
+
return runtime.config.ui?.quietStartup ?? "normal";
|
|
13
|
+
}
|
|
14
|
+
export function headerLine() {
|
|
15
|
+
return `ama ${AMA_VERSION} · Enter 发送 · Esc 中断 · Ctrl+C 两次退出 · /help 命令`;
|
|
16
|
+
}
|
|
17
|
+
function trustText(runtime) {
|
|
18
|
+
const { trusted, source, matchedPath } = runtime.trust;
|
|
19
|
+
const from = source === "flag"
|
|
20
|
+
? "命令行"
|
|
21
|
+
: source === "trust-file"
|
|
22
|
+
? `trust.json${matchedPath === undefined ? "" : ` ${matchedPath}`}`
|
|
23
|
+
: source === "prompt"
|
|
24
|
+
? "本次确认"
|
|
25
|
+
: source === "profile"
|
|
26
|
+
? "profile"
|
|
27
|
+
: "缺省";
|
|
28
|
+
return `${trusted ? "已信任" : "未信任"}(${from})`;
|
|
29
|
+
}
|
|
30
|
+
export function buildStartupScreen(runtime, level = startupScreenLevel(runtime)) {
|
|
31
|
+
if (level === "silent")
|
|
32
|
+
return [];
|
|
33
|
+
const lines = [headerLine()];
|
|
34
|
+
if (level === "header")
|
|
35
|
+
return lines;
|
|
36
|
+
const { resources } = runtime;
|
|
37
|
+
lines.push(`模型:${runtime.model.provider}/${runtime.model.id} · 思考 ${runtime.thinkingLevel}`);
|
|
38
|
+
lines.push(`目录:${runtime.paths.cwd} · ${trustText(runtime)}`);
|
|
39
|
+
if (resources.contextFiles.length > 0) {
|
|
40
|
+
lines.push(`上下文:${resources.contextFiles.map((f) => f.path).join(", ")}`);
|
|
41
|
+
}
|
|
42
|
+
if (resources.skills.length > 0) {
|
|
43
|
+
lines.push(`Skill:${resources.skills.map((s) => s.name).join(", ")}`);
|
|
44
|
+
}
|
|
45
|
+
if (resources.prompts.length > 0) {
|
|
46
|
+
lines.push(`提示模板:${resources.prompts.map((p) => `/${p.name}`).join(" ")}`);
|
|
47
|
+
}
|
|
48
|
+
const hooks = runtime.hooks.list();
|
|
49
|
+
if (hooks.length > 0)
|
|
50
|
+
lines.push(`Hook:${hooks.length} 条`);
|
|
51
|
+
if (runtime.host !== undefined)
|
|
52
|
+
lines.push(`宿主:${runtime.host.adapter.id}`);
|
|
53
|
+
if (runtime.warnings.length > 0)
|
|
54
|
+
lines.push(`警告:${runtime.warnings.length} 条(ama doctor 查看)`);
|
|
55
|
+
return lines;
|
|
56
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 启动序列的单步辅助(设计 §11.1):错误映射、模式判定、profile 合并、会话请求、
|
|
3
|
+
* 模型与思考级别解析、工具过滤、指令文件。[B5] 由 cli/bootstrap.ts 编排。
|
|
4
|
+
*/
|
|
5
|
+
import type { Model, ModelThinkingLevel, ProviderData, ProviderRegistryApi } from "../ai/types.js";
|
|
6
|
+
import type { AgentSession } from "../agent/types.js";
|
|
7
|
+
import type { ProfileOptions } from "../config/profile.js";
|
|
8
|
+
import { AmaError } from "../errors.js";
|
|
9
|
+
import type { InstructionSource } from "../host/types.js";
|
|
10
|
+
import type { SessionEntry, SessionManagerApi } from "../session/types.js";
|
|
11
|
+
import { type ParsedArgs } from "./args.js";
|
|
12
|
+
import type { CliIo, RuntimeDeps, SessionAssembly, SessionRequest } from "./deps.js";
|
|
13
|
+
import type { Runtime, RuntimeMode } from "./runtime.js";
|
|
14
|
+
/** 把非 StartupError 包成指定退出码;StartupError / UsageError 原样透传。 */
|
|
15
|
+
export declare function step<T>(exitCode: number, label: string, fn: () => T | Promise<T>): Promise<T>;
|
|
16
|
+
export declare function toStartupError(error: unknown, exitCode: number, label: string): AmaError;
|
|
17
|
+
/** 第 4 步。 */
|
|
18
|
+
export declare function decideMode(args: ParsedArgs, io: Pick<CliIo, "stdinIsTTY" | "stdoutIsTTY" | "env">): RuntimeMode;
|
|
19
|
+
/** 第 3 步:profile 字段等价于参数,命令行显式参数优先。 */
|
|
20
|
+
export declare function applyProfile(args: ParsedArgs, profile: ProfileOptions): ParsedArgs;
|
|
21
|
+
export declare function sessionRequestOf(args: ParsedArgs): SessionRequest | "pick";
|
|
22
|
+
export declare function sourceOf(request: SessionRequest, manager: SessionManagerApi): SessionAssembly["source"];
|
|
23
|
+
export declare function lastEntry(manager: SessionManagerApi, predicate: (entry: SessionEntry) => boolean): SessionEntry | undefined;
|
|
24
|
+
export interface ModelChoice {
|
|
25
|
+
model: Model;
|
|
26
|
+
provider: ProviderData;
|
|
27
|
+
}
|
|
28
|
+
/** 第 11 步:解析模型与 key。 */
|
|
29
|
+
export declare function resolveModel(args: ParsedArgs, registry: ProviderRegistryApi, manager: SessionManagerApi, defaultModel: string | undefined, deps: RuntimeDeps, interactive: boolean): Promise<ModelChoice>;
|
|
30
|
+
export declare function thinkingOf(args: ParsedArgs, manager: SessionManagerApi, fallback: ModelThinkingLevel | undefined): ModelThinkingLevel;
|
|
31
|
+
/** 第 12 步之后:`--tools` / `--exclude-tools`(宿主工具注册后再校验,宿主工具名也可用)。 */
|
|
32
|
+
export declare function applyToolFilters(args: ParsedArgs, runtimeTools: Runtime["tools"]): void;
|
|
33
|
+
export declare function instructionSources(paths: readonly string[], cwd: string): InstructionSource[];
|
|
34
|
+
/** 宿主 `messages.sendUser` 的缺省实现:运行中 steer,空闲时 prompt;origin 原样落盘到 user 消息。 */
|
|
35
|
+
export declare function defaultSendUser(session: AgentSession, text: string, origin?: string): Promise<"started" | "queued">;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 启动序列的单步辅助(设计 §11.1):错误映射、模式判定、profile 合并、会话请求、
|
|
3
|
+
* 模型与思考级别解析、工具过滤、指令文件。[B5] 由 cli/bootstrap.ts 编排。
|
|
4
|
+
*/
|
|
5
|
+
import { formatModelRef } from "../ai/providers/channels.js";
|
|
6
|
+
import { statSync } from "node:fs";
|
|
7
|
+
import { isAbsolute, resolve } from "node:path";
|
|
8
|
+
import { AmaError, StartupError, isAmaError } from "../errors.js";
|
|
9
|
+
import { UsageError } from "./args.js";
|
|
10
|
+
import { pickDefaultModel } from "./default-model.js";
|
|
11
|
+
import { ExitCode } from "./exit-codes.js";
|
|
12
|
+
/** 把非 StartupError 包成指定退出码;StartupError / UsageError 原样透传。 */
|
|
13
|
+
export async function step(exitCode, label, fn) {
|
|
14
|
+
try {
|
|
15
|
+
return await fn();
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
throw toStartupError(error, exitCode, label);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const CODE_EXIT = {
|
|
22
|
+
session_not_found: ExitCode.Session,
|
|
23
|
+
session_corrupt: ExitCode.Session,
|
|
24
|
+
model_not_found: ExitCode.NoModel,
|
|
25
|
+
provider_not_found: ExitCode.NoModel,
|
|
26
|
+
no_api_key: ExitCode.NoModel,
|
|
27
|
+
config_invalid: ExitCode.Config,
|
|
28
|
+
profile_invalid: ExitCode.Config,
|
|
29
|
+
tool_not_found: ExitCode.Usage,
|
|
30
|
+
host_load_failed: ExitCode.HostOrHook,
|
|
31
|
+
host_version_mismatch: ExitCode.HostVersion,
|
|
32
|
+
hook_failed: ExitCode.HostOrHook,
|
|
33
|
+
};
|
|
34
|
+
export function toStartupError(error, exitCode, label) {
|
|
35
|
+
if (error instanceof StartupError || error instanceof UsageError)
|
|
36
|
+
return error;
|
|
37
|
+
if (isAmaError(error)) {
|
|
38
|
+
const mapped = error.exitCode ?? CODE_EXIT[error.code] ?? exitCode;
|
|
39
|
+
return new StartupError(error.code, error.message, mapped, { cause: error });
|
|
40
|
+
}
|
|
41
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
42
|
+
return new StartupError("startup_failed", `${label}:${message}`, exitCode, { cause: error });
|
|
43
|
+
}
|
|
44
|
+
/** 第 4 步。 */
|
|
45
|
+
export function decideMode(args, io) {
|
|
46
|
+
if (args.mode === "rpc")
|
|
47
|
+
return "rpc";
|
|
48
|
+
if (args.print)
|
|
49
|
+
return "print";
|
|
50
|
+
if (args.noTui || !io.stdinIsTTY || !io.stdoutIsTTY || io.env["TERM"] === "dumb")
|
|
51
|
+
return "line";
|
|
52
|
+
return "interactive";
|
|
53
|
+
}
|
|
54
|
+
/** 第 3 步:profile 字段等价于参数,命令行显式参数优先。 */
|
|
55
|
+
export function applyProfile(args, profile) {
|
|
56
|
+
const merged = { ...args };
|
|
57
|
+
if (merged.host === undefined && profile.host !== undefined)
|
|
58
|
+
merged.host = profile.host;
|
|
59
|
+
if (merged.authFile === undefined && profile.authFile !== undefined)
|
|
60
|
+
merged.authFile = profile.authFile;
|
|
61
|
+
if (merged.sessionDir === undefined && profile.sessionDir !== undefined)
|
|
62
|
+
merged.sessionDir = profile.sessionDir;
|
|
63
|
+
if (merged.trust === undefined && profile.trustProject)
|
|
64
|
+
merged.trust = true;
|
|
65
|
+
merged.instructions = [...profile.instructions, ...args.instructions];
|
|
66
|
+
merged.skillDirs = [...args.skillDirs, ...profile.skillDirs];
|
|
67
|
+
return merged;
|
|
68
|
+
}
|
|
69
|
+
export function sessionRequestOf(args) {
|
|
70
|
+
if (args.continue)
|
|
71
|
+
return { kind: "continue" };
|
|
72
|
+
if (args.resume)
|
|
73
|
+
return args.resumeId === undefined ? "pick" : { kind: "resume", id: args.resumeId };
|
|
74
|
+
if (args.sessionId !== undefined)
|
|
75
|
+
return { kind: "session-id", id: args.sessionId };
|
|
76
|
+
if (args.fork !== undefined)
|
|
77
|
+
return { kind: "fork", id: args.fork };
|
|
78
|
+
return { kind: "new" };
|
|
79
|
+
}
|
|
80
|
+
export function sourceOf(request, manager) {
|
|
81
|
+
if (request.kind === "fork")
|
|
82
|
+
return "fork";
|
|
83
|
+
if (request.kind === "new")
|
|
84
|
+
return "startup";
|
|
85
|
+
return manager.entries().length > 0 ? "resume" : "startup";
|
|
86
|
+
}
|
|
87
|
+
export function lastEntry(manager, predicate) {
|
|
88
|
+
const branch = manager.branch();
|
|
89
|
+
for (let i = branch.length - 1; i >= 0; i--) {
|
|
90
|
+
const entry = branch[i];
|
|
91
|
+
if (entry !== undefined && predicate(entry))
|
|
92
|
+
return entry;
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
/** 第 11 步:解析模型与 key。 */
|
|
97
|
+
export async function resolveModel(args, registry, manager, defaultModel, deps, interactive) {
|
|
98
|
+
if (args.provider !== undefined && args.model === undefined) {
|
|
99
|
+
throw new UsageError(`--provider ${args.provider} 需要同时给出 --model(不回退到该供应商的缺省模型)`);
|
|
100
|
+
}
|
|
101
|
+
const lookup = (ref, label) => {
|
|
102
|
+
const found = registry.findModel(ref);
|
|
103
|
+
if (found.ok)
|
|
104
|
+
return { model: found.model, provider: found.provider };
|
|
105
|
+
const hint = found.candidates.length > 0 ? `;候选:${found.candidates.slice(0, 20).join(", ")}` : "";
|
|
106
|
+
const what = found.reason === "provider_not_found"
|
|
107
|
+
? "供应商不存在"
|
|
108
|
+
: found.reason === "ambiguous"
|
|
109
|
+
? "模型名有歧义"
|
|
110
|
+
: "模型不存在";
|
|
111
|
+
throw new StartupError("model_not_found", `${label}${what}:${ref}${hint}`, ExitCode.NoModel);
|
|
112
|
+
};
|
|
113
|
+
let choice;
|
|
114
|
+
if (args.model !== undefined) {
|
|
115
|
+
const ref = args.provider !== undefined && !args.model.includes("/")
|
|
116
|
+
? `${args.provider}/${args.model}`
|
|
117
|
+
: args.model;
|
|
118
|
+
choice = lookup(ref, "");
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const change = lastEntry(manager, (e) => e.type === "model_change");
|
|
122
|
+
if (change?.type === "model_change") {
|
|
123
|
+
const found = registry.findModel(formatModelRef({
|
|
124
|
+
provider: change.provider,
|
|
125
|
+
id: change.modelId,
|
|
126
|
+
...(change.channel !== undefined ? { channel: change.channel } : {}),
|
|
127
|
+
}));
|
|
128
|
+
if (found.ok)
|
|
129
|
+
choice = { model: found.model, provider: found.provider };
|
|
130
|
+
}
|
|
131
|
+
if (choice === undefined && defaultModel !== undefined)
|
|
132
|
+
choice = lookup(defaultModel, "config.defaultModel ");
|
|
133
|
+
if (choice === undefined) {
|
|
134
|
+
const picked = await pickDefaultModel(registry);
|
|
135
|
+
if (picked !== undefined)
|
|
136
|
+
choice = { model: picked.model, provider: picked.provider };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const pick = async (reason) => {
|
|
140
|
+
const picked = interactive ? await deps.ui?.pickModel?.(registry, reason) : undefined;
|
|
141
|
+
if (picked === undefined)
|
|
142
|
+
throw new StartupError("no_api_key", reason, ExitCode.NoModel);
|
|
143
|
+
return lookup(picked, "");
|
|
144
|
+
};
|
|
145
|
+
if (choice === undefined) {
|
|
146
|
+
return pick("没有可用模型:用 `ama auth set <provider>` 保存 key,或设置对应环境变量,或 --model 指定");
|
|
147
|
+
}
|
|
148
|
+
if (choice.provider.requiresApiKey) {
|
|
149
|
+
const key = await registry.resolveApiKey(choice.provider.id);
|
|
150
|
+
if (key.apiKey === undefined) {
|
|
151
|
+
const envs = choice.provider.envKeys.length > 0
|
|
152
|
+
? `,或设置环境变量 ${choice.provider.envKeys.join(" / ")}`
|
|
153
|
+
: "";
|
|
154
|
+
return pick(`供应商 ${choice.provider.id} 没有 API key:运行 \`ama auth set ${choice.provider.id}\`${envs}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return choice;
|
|
158
|
+
}
|
|
159
|
+
export function thinkingOf(args, manager, fallback) {
|
|
160
|
+
if (args.thinking !== undefined)
|
|
161
|
+
return args.thinking;
|
|
162
|
+
const change = lastEntry(manager, (e) => e.type === "thinking_level_change");
|
|
163
|
+
if (change?.type === "thinking_level_change")
|
|
164
|
+
return change.thinkingLevel;
|
|
165
|
+
return fallback ?? "medium";
|
|
166
|
+
}
|
|
167
|
+
/** 第 12 步之后:`--tools` / `--exclude-tools`(宿主工具注册后再校验,宿主工具名也可用)。 */
|
|
168
|
+
export function applyToolFilters(args, runtimeTools) {
|
|
169
|
+
const unknown = [...(args.tools ?? []), ...(args.excludeTools ?? [])].filter((n) => runtimeTools.get(n) === undefined);
|
|
170
|
+
if (unknown.length > 0) {
|
|
171
|
+
throw new UsageError(`未知工具:${unknown.join(", ")}(可用:${runtimeTools.list().join(", ")})`);
|
|
172
|
+
}
|
|
173
|
+
if (args.tools !== undefined)
|
|
174
|
+
runtimeTools.setActive(args.tools);
|
|
175
|
+
for (const name of args.excludeTools ?? [])
|
|
176
|
+
runtimeTools.disable(name);
|
|
177
|
+
}
|
|
178
|
+
export function instructionSources(paths, cwd) {
|
|
179
|
+
return paths.map((p) => {
|
|
180
|
+
const abs = isAbsolute(p) ? p : resolve(cwd, p);
|
|
181
|
+
let ok = false;
|
|
182
|
+
try {
|
|
183
|
+
ok = statSync(abs).isFile();
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
ok = false;
|
|
187
|
+
}
|
|
188
|
+
if (!ok)
|
|
189
|
+
throw new StartupError("config_invalid", `--instructions 文件不存在:${abs}`, ExitCode.Config);
|
|
190
|
+
return { kind: "file", path: abs };
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
/** 宿主 `messages.sendUser` 的缺省实现:运行中 steer,空闲时 prompt;origin 原样落盘到 user 消息。 */
|
|
194
|
+
export async function defaultSendUser(session, text, origin) {
|
|
195
|
+
const tagged = origin !== undefined ? { origin } : {};
|
|
196
|
+
if (session.state.isStreaming) {
|
|
197
|
+
await session.steer(text, tagged);
|
|
198
|
+
return "queued";
|
|
199
|
+
}
|
|
200
|
+
void session.prompt(text, { streamingBehavior: "steer", ...tagged }).catch(() => undefined);
|
|
201
|
+
return "started";
|
|
202
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ama auth set|list|remove <provider>`(设计 §3.5、§16.2 B5 验收)。[B5]
|
|
3
|
+
*
|
|
4
|
+
* - set:key 从 stdin 读取(TTY 下不回显),不经命令行参数,避免进 shell 历史;写 auth.json 0600。
|
|
5
|
+
* - list:只列供应商与 key 形态(字面量 / `!command` / `$ENV` 引用),从不输出 key。
|
|
6
|
+
* - `--auth-file <path>` 改变目标文件(缺省 `<configDir>/auth.json`)。
|
|
7
|
+
*/
|
|
8
|
+
import type { CliIo } from "../deps.js";
|
|
9
|
+
export declare const AUTH_USAGE = "\u7528\u6CD5\uFF1Aama auth set <provider> [--auth-file <\u6587\u4EF6>] \u4ECE stdin \u8BFB\u53D6 key\n ama auth list [--auth-file <\u6587\u4EF6>]\n ama auth remove <provider> [--auth-file <\u6587\u4EF6>]\n";
|
|
10
|
+
/** 取第一行并去掉首尾空白;stdin 为空返回 ""。 */
|
|
11
|
+
export declare function extractKey(raw: string): string;
|
|
12
|
+
export declare function runAuth(argv: readonly string[], io: CliIo): Promise<number>;
|