@armadra/agent 0.0.0-stage → 0.2.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 +22 -0
- package/LICENSE +21 -0
- package/README.md +426 -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 +511 -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 +118 -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 +104 -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 +484 -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 +303 -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 +102 -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/registry.d.ts +83 -0
- package/dist/ai/providers/registry.js +305 -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 +428 -0
- package/dist/ai/types.js +19 -0
- package/dist/bundle/ama-sandbox.cjs +324 -0
- package/dist/bundle/ama.cjs +25770 -0
- package/dist/bundle.d.ts +9 -0
- package/dist/bundle.js +15 -0
- package/dist/cli/args.d.ts +82 -0
- package/dist/cli/args.js +381 -0
- package/dist/cli/bootstrap.d.ts +18 -0
- package/dist/cli/bootstrap.js +398 -0
- package/dist/cli/compose-providers.d.ts +37 -0
- package/dist/cli/compose-providers.js +104 -0
- package/dist/cli/compose-session.d.ts +69 -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 +106 -0
- package/dist/cli/compose.js +206 -0
- package/dist/cli/default-model.d.ts +16 -0
- package/dist/cli/default-model.js +24 -0
- package/dist/cli/deps.d.ts +205 -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 +26 -0
- package/dist/cli/main.js +165 -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 +197 -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 +44 -0
- package/dist/cli/subcommands/config.js +201 -0
- package/dist/cli/subcommands/context.d.ts +21 -0
- package/dist/cli/subcommands/context.js +41 -0
- package/dist/cli/subcommands/doctor.d.ts +11 -0
- package/dist/cli/subcommands/doctor.js +246 -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 +40 -0
- package/dist/cli/subcommands/models-discover.js +204 -0
- package/dist/cli/subcommands/models.d.ts +40 -0
- package/dist/cli/subcommands/models.js +144 -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/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 +413 -0
- package/dist/config/trust.d.ts +42 -0
- package/dist/config/trust.js +122 -0
- package/dist/config/types.d.ts +172 -0
- package/dist/config/types.js +27 -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/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 +202 -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 +487 -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 +216 -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 +28 -0
- package/dist/modes/interactive/startup-ui.js +238 -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 +15 -0
- package/dist/modes/print/print-mode.js +96 -0
- package/dist/modes/rpc/commands.d.ts +40 -0
- package/dist/modes/rpc/commands.js +258 -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 +171 -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 +180 -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 +199 -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/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 +28 -0
- package/dist/tools/read.js +181 -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 +316 -0
- package/docs/rpc.md +253 -0
- package/docs/session-format.md +119 -0
- package/docs/tui.md +168 -0
- package/package.json +101 -4
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 磁盘配置文件形状(设计 §3.5、§7.3、§10.2、§10.3、§12.10)。[B0] 契约文件。
|
|
3
|
+
*
|
|
4
|
+
* 补全与偏差:§1.2 把这些类型放在 config/schema.ts(B5),但 Runtime(cli/runtime.ts,B0)
|
|
5
|
+
* 与 SDK 的 `CreateSessionOptions.config` 都要引用 `AmaConfig`,而 B5 与 B6 并行开工,
|
|
6
|
+
* 所以形状在这里定死;config/schema.ts 只做校验并可再导出这些类型。
|
|
7
|
+
* hooks.json 的形状是 `HookConfig`(hooks/types.ts)。
|
|
8
|
+
* (W3-C0)第三波:`cache` 段(§1.12,只认用户级 / profile);`ModelConfig` / `ModelOverride`
|
|
9
|
+
* 允许模型级 `api`(§2.3,同一中转的模型走不同协议),由 W3-B12 在注册表里生效。
|
|
10
|
+
*/
|
|
11
|
+
import type { WarmingMode } from "../ai/cache/types.js";
|
|
12
|
+
import type { Api, AuthHeader, CacheRetention, Model, ModelThinkingLevel, ProviderCompat } from "../ai/types.js";
|
|
13
|
+
import type { PermissionMode } from "../permissions/types.js";
|
|
14
|
+
export declare const CONFIG_FILE_VERSION: 1;
|
|
15
|
+
/**
|
|
16
|
+
* 自定义模型条目;缺省 maxTokens 8192、reasoning false、input ["text"],不猜 contextWindow。
|
|
17
|
+
* `api` 缺省沿用供应商的协议。
|
|
18
|
+
*/
|
|
19
|
+
export type ModelConfig = Partial<Omit<Model, "id" | "provider">> & {
|
|
20
|
+
id: string;
|
|
21
|
+
};
|
|
22
|
+
/** 只改元数据的覆盖项(含模型级 `api`)。 */
|
|
23
|
+
export type ModelOverride = Partial<Omit<Model, "id" | "provider">> & {
|
|
24
|
+
id: string;
|
|
25
|
+
};
|
|
26
|
+
export interface ProviderConfig {
|
|
27
|
+
name?: string;
|
|
28
|
+
/** 自定义供应商缺省 openai-completions。 */
|
|
29
|
+
api?: Api;
|
|
30
|
+
baseUrl?: string;
|
|
31
|
+
/** 支持 "$ENV_NAME"、"${ENV_NAME}"、"!command";"$$" 转义。 */
|
|
32
|
+
apiKey?: string;
|
|
33
|
+
envKeys?: string[];
|
|
34
|
+
authHeader?: AuthHeader;
|
|
35
|
+
headers?: Record<string, string>;
|
|
36
|
+
compat?: ProviderCompat;
|
|
37
|
+
requiresApiKey?: boolean;
|
|
38
|
+
models?: ModelConfig[];
|
|
39
|
+
modelOverrides?: ModelOverride[];
|
|
40
|
+
}
|
|
41
|
+
export interface PermissionConfig {
|
|
42
|
+
mode?: PermissionMode;
|
|
43
|
+
allow?: string[];
|
|
44
|
+
deny?: string[];
|
|
45
|
+
/**
|
|
46
|
+
* 内置 deny 表(`.git/**` 写、`.ssh/**` 读写):缺省 true 全部启用;false 全部移除;
|
|
47
|
+
* 数组 = 要移除的规则原文。放宽项,只认用户级 / profile,项目级忽略并 warning。
|
|
48
|
+
*/
|
|
49
|
+
builtinDeny?: boolean | string[];
|
|
50
|
+
}
|
|
51
|
+
export interface CompactionConfig {
|
|
52
|
+
enabled?: boolean;
|
|
53
|
+
reserveTokens?: number;
|
|
54
|
+
keepRecentTokens?: number;
|
|
55
|
+
}
|
|
56
|
+
export interface RetryConfig {
|
|
57
|
+
enabled?: boolean;
|
|
58
|
+
maxRetries?: number;
|
|
59
|
+
baseDelayMs?: number;
|
|
60
|
+
maxDelayMs?: number;
|
|
61
|
+
}
|
|
62
|
+
/** 工具预设(设计 §5.6):模型直接看到的工具集合。 */
|
|
63
|
+
export type ToolsPreset = "default" | "minimal" | "codemode" | "coordinator";
|
|
64
|
+
/** 从严到宽:项目级只能把预设改成不比当前更宽的那个(coordinator 最严,codemode 最宽)。 */
|
|
65
|
+
export declare const TOOLS_PRESETS_STRICT_FIRST: readonly ToolsPreset[];
|
|
66
|
+
export interface ToolsConfig {
|
|
67
|
+
/** 缺省 `default`;命令行 `--tools-preset`。 */
|
|
68
|
+
preset?: ToolsPreset;
|
|
69
|
+
/**
|
|
70
|
+
* 在预设上微调(设计 §5.6):`+name` 加、`-name` 去;不带前缀的名字整组替换预设的内置工具。
|
|
71
|
+
* 只认用户级 / profile(项目级忽略并 warning)。
|
|
72
|
+
*/
|
|
73
|
+
default?: string[];
|
|
74
|
+
maxToolResultChars?: number;
|
|
75
|
+
bashTimeoutMs?: number;
|
|
76
|
+
disabled?: string[];
|
|
77
|
+
}
|
|
78
|
+
/** codemode 调用方式(设计 §5.5):off 不注册;on 全部工具 + codemode;only 只有 codemode。 */
|
|
79
|
+
export type CodemodeMode = "off" | "on" | "only";
|
|
80
|
+
export declare const CODEMODE_MODES: readonly CodemodeMode[];
|
|
81
|
+
export interface CodemodeConfig {
|
|
82
|
+
/** 命令行 `--codemode`;项目级只接受 "off"。 */
|
|
83
|
+
mode?: CodemodeMode;
|
|
84
|
+
/** `codemode` 描述里内联工具声明的总预算(估算 token,缺省 3 000),超出只列名字。 */
|
|
85
|
+
inlineBudget?: number;
|
|
86
|
+
/** true:运行时 Node 的权限模型不隔离网络(Node 22 / 24)时直接禁用 codemode。 */
|
|
87
|
+
requireStrict?: boolean;
|
|
88
|
+
}
|
|
89
|
+
export interface HooksSettings {
|
|
90
|
+
timeoutMs?: number;
|
|
91
|
+
}
|
|
92
|
+
export interface UiConfig {
|
|
93
|
+
theme?: "dark" | "light";
|
|
94
|
+
markdown?: boolean;
|
|
95
|
+
showThinking?: "full" | "collapsed" | "hidden";
|
|
96
|
+
/** 第一期只有 regular(§12.10)。 */
|
|
97
|
+
tuiMode?: "regular";
|
|
98
|
+
quietStartup?: "normal" | "header" | "silent";
|
|
99
|
+
}
|
|
100
|
+
export interface SkillsConfig {
|
|
101
|
+
dirs?: string[];
|
|
102
|
+
}
|
|
103
|
+
export declare const CACHE_RETENTIONS: readonly CacheRetention[];
|
|
104
|
+
/**
|
|
105
|
+
* 缓存(第三波 §1.12)。整段只认用户级 / profile,项目级忽略并 warning(同 `permission.allow`);
|
|
106
|
+
* 环境变量 `AMA_CACHE_WARMING` / `AMA_CACHE_RETENTION` 覆盖对应项。
|
|
107
|
+
*/
|
|
108
|
+
export interface CacheConfig {
|
|
109
|
+
/** off | streaming | idle,缺省 streaming。 */
|
|
110
|
+
warming?: WarmingMode;
|
|
111
|
+
/** none | short | long,缺省 short。 */
|
|
112
|
+
retention?: CacheRetention;
|
|
113
|
+
/** 保温的最低期望节省(美元),缺省 0.05。 */
|
|
114
|
+
minSavingsUsd?: number;
|
|
115
|
+
/** 转录 / 消息区的未命中与上下文余量提示,缺省 true(统计面板不受影响)。 */
|
|
116
|
+
missNotices?: boolean;
|
|
117
|
+
/** 子会话(task)也保温,缺省 false。 */
|
|
118
|
+
warmSubagents?: boolean;
|
|
119
|
+
}
|
|
120
|
+
export declare const DEFAULT_CACHE_CONFIG: Readonly<Required<CacheConfig>>;
|
|
121
|
+
/** config.json(用户级 / 项目级 / profile.config 同形状;项目级只接受受限字段,§10.2)。 */
|
|
122
|
+
export interface AmaConfig {
|
|
123
|
+
version: typeof CONFIG_FILE_VERSION;
|
|
124
|
+
/** `provider/model-id`。 */
|
|
125
|
+
defaultModel?: string;
|
|
126
|
+
thinkingLevel?: ModelThinkingLevel;
|
|
127
|
+
providers?: Record<string, ProviderConfig>;
|
|
128
|
+
permission?: PermissionConfig;
|
|
129
|
+
compaction?: CompactionConfig;
|
|
130
|
+
retry?: RetryConfig;
|
|
131
|
+
tools?: ToolsConfig;
|
|
132
|
+
codemode?: CodemodeConfig;
|
|
133
|
+
hooks?: HooksSettings;
|
|
134
|
+
ui?: UiConfig;
|
|
135
|
+
skills?: SkillsConfig;
|
|
136
|
+
cache?: CacheConfig;
|
|
137
|
+
}
|
|
138
|
+
/** auth.json(0600)。 */
|
|
139
|
+
export interface AuthFile {
|
|
140
|
+
version: typeof CONFIG_FILE_VERSION;
|
|
141
|
+
providers: Record<string, {
|
|
142
|
+
apiKey: string;
|
|
143
|
+
env?: Record<string, string>;
|
|
144
|
+
baseUrl?: string;
|
|
145
|
+
}>;
|
|
146
|
+
}
|
|
147
|
+
/** profile.json(宿主用,§10.3;与 Armadra 文档 B §2.4 一致);路径必须是绝对路径,不含密钥。 */
|
|
148
|
+
export interface ProfileFile {
|
|
149
|
+
version: typeof CONFIG_FILE_VERSION;
|
|
150
|
+
host?: string;
|
|
151
|
+
instructions?: string[];
|
|
152
|
+
skillDirs?: string[];
|
|
153
|
+
promptDirs?: string[];
|
|
154
|
+
hooksFile?: string;
|
|
155
|
+
authFile?: string;
|
|
156
|
+
/** false:key 只来自 authFile,不读环境变量(§11.2)。 */
|
|
157
|
+
authEnv?: boolean;
|
|
158
|
+
sessionDir?: string;
|
|
159
|
+
config?: string;
|
|
160
|
+
trustProject?: boolean;
|
|
161
|
+
}
|
|
162
|
+
export interface TrustEntry {
|
|
163
|
+
path: string;
|
|
164
|
+
trusted: boolean;
|
|
165
|
+
/** ISO 8601。 */
|
|
166
|
+
at: string;
|
|
167
|
+
}
|
|
168
|
+
/** trust.json(只在用户级目录)。 */
|
|
169
|
+
export interface TrustFile {
|
|
170
|
+
version: typeof CONFIG_FILE_VERSION;
|
|
171
|
+
entries: TrustEntry[];
|
|
172
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 磁盘配置文件形状(设计 §3.5、§7.3、§10.2、§10.3、§12.10)。[B0] 契约文件。
|
|
3
|
+
*
|
|
4
|
+
* 补全与偏差:§1.2 把这些类型放在 config/schema.ts(B5),但 Runtime(cli/runtime.ts,B0)
|
|
5
|
+
* 与 SDK 的 `CreateSessionOptions.config` 都要引用 `AmaConfig`,而 B5 与 B6 并行开工,
|
|
6
|
+
* 所以形状在这里定死;config/schema.ts 只做校验并可再导出这些类型。
|
|
7
|
+
* hooks.json 的形状是 `HookConfig`(hooks/types.ts)。
|
|
8
|
+
* (W3-C0)第三波:`cache` 段(§1.12,只认用户级 / profile);`ModelConfig` / `ModelOverride`
|
|
9
|
+
* 允许模型级 `api`(§2.3,同一中转的模型走不同协议),由 W3-B12 在注册表里生效。
|
|
10
|
+
*/
|
|
11
|
+
export const CONFIG_FILE_VERSION = 1;
|
|
12
|
+
/** 从严到宽:项目级只能把预设改成不比当前更宽的那个(coordinator 最严,codemode 最宽)。 */
|
|
13
|
+
export const TOOLS_PRESETS_STRICT_FIRST = [
|
|
14
|
+
"coordinator",
|
|
15
|
+
"minimal",
|
|
16
|
+
"default",
|
|
17
|
+
"codemode",
|
|
18
|
+
];
|
|
19
|
+
export const CODEMODE_MODES = ["off", "on", "only"];
|
|
20
|
+
export const CACHE_RETENTIONS = ["none", "short", "long"];
|
|
21
|
+
export const DEFAULT_CACHE_CONFIG = Object.freeze({
|
|
22
|
+
warming: "streaming",
|
|
23
|
+
retention: "short",
|
|
24
|
+
minSavingsUsd: 0.05,
|
|
25
|
+
missNotices: true,
|
|
26
|
+
warmSubagents: false,
|
|
27
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 写配置文件(第三波 §2.3,`ama models discover --write` 用)。[W3-B12]
|
|
3
|
+
*
|
|
4
|
+
* 2 空格缩进 + 换行结尾;目标已存在时先复制为 `<path>.bak`(`backup` 缺省 true)并沿用原文件
|
|
5
|
+
* 权限;先写同目录临时文件再 rename,中途失败不会留下半个 config.json。
|
|
6
|
+
*/
|
|
7
|
+
import type { AmaConfig } from "./types.js";
|
|
8
|
+
export declare function writeConfigFile(path: string, config: AmaConfig, options?: {
|
|
9
|
+
backup?: boolean;
|
|
10
|
+
}): void;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 写配置文件(第三波 §2.3,`ama models discover --write` 用)。[W3-B12]
|
|
3
|
+
*
|
|
4
|
+
* 2 空格缩进 + 换行结尾;目标已存在时先复制为 `<path>.bak`(`backup` 缺省 true)并沿用原文件
|
|
5
|
+
* 权限;先写同目录临时文件再 rename,中途失败不会留下半个 config.json。
|
|
6
|
+
*/
|
|
7
|
+
import { chmodSync, copyFileSync, mkdirSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { dirname } from "node:path";
|
|
9
|
+
export function writeConfigFile(path, config, options = {}) {
|
|
10
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
11
|
+
let mode;
|
|
12
|
+
try {
|
|
13
|
+
mode = statSync(path).mode & 0o777;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
mode = undefined;
|
|
17
|
+
}
|
|
18
|
+
if (mode !== undefined && options.backup !== false)
|
|
19
|
+
copyFileSync(path, `${path}.bak`);
|
|
20
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
21
|
+
writeFileSync(tmp, `${JSON.stringify(config, null, 2)}\n`, { mode: mode ?? 0o644 });
|
|
22
|
+
if (mode !== undefined)
|
|
23
|
+
chmodSync(tmp, mode);
|
|
24
|
+
renameSync(tmp, path);
|
|
25
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 共享错误类型(设计 §2「错误」)。[B0] 契约文件。
|
|
3
|
+
*
|
|
4
|
+
* 补全说明:设计只给出 `class AmaError extends Error { code; exitCode?; detail? }` 与
|
|
5
|
+
* `StartupError`,未指定文件位置。各层(ai / agent / tools / config / cli)都要抛它,
|
|
6
|
+
* 而 ai 是最底层、不得 import 上层,所以放在 src 根,由 B0 所有。
|
|
7
|
+
* `exitCode` 用数字而不是 `ExitCode` 类型,避免底层模块反向依赖 cli/。
|
|
8
|
+
*/
|
|
9
|
+
/** 已知错误码;实现可以使用其它字符串,但下列码的语义固定。 */
|
|
10
|
+
export type KnownErrorCode = "no_api_key" | "busy" | "aborted" | "invalid_arguments" | "schema_violation" | "model_not_found" | "provider_not_found" | "tool_not_found" | "tool_exists" | "config_invalid" | "profile_invalid" | "session_not_found" | "session_corrupt" | "host_load_failed" | "host_version_mismatch" | "hook_failed" | "not_implemented";
|
|
11
|
+
export type ErrorCode = KnownErrorCode | (string & {});
|
|
12
|
+
export interface AmaErrorOptions {
|
|
13
|
+
exitCode?: number;
|
|
14
|
+
detail?: unknown;
|
|
15
|
+
cause?: unknown;
|
|
16
|
+
}
|
|
17
|
+
export declare class AmaError extends Error {
|
|
18
|
+
readonly code: ErrorCode;
|
|
19
|
+
readonly exitCode: number | undefined;
|
|
20
|
+
readonly detail: unknown;
|
|
21
|
+
constructor(code: ErrorCode, message: string, options?: AmaErrorOptions);
|
|
22
|
+
}
|
|
23
|
+
/** 启动序列(§11.1)中的错误;`exitCode` 必填,取值见 cli/exit-codes.ts。 */
|
|
24
|
+
export declare class StartupError extends AmaError {
|
|
25
|
+
readonly exitCode: number;
|
|
26
|
+
constructor(code: ErrorCode, message: string, exitCode: number, options?: AmaErrorOptions);
|
|
27
|
+
}
|
|
28
|
+
export declare function isAmaError(value: unknown): value is AmaError;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 共享错误类型(设计 §2「错误」)。[B0] 契约文件。
|
|
3
|
+
*
|
|
4
|
+
* 补全说明:设计只给出 `class AmaError extends Error { code; exitCode?; detail? }` 与
|
|
5
|
+
* `StartupError`,未指定文件位置。各层(ai / agent / tools / config / cli)都要抛它,
|
|
6
|
+
* 而 ai 是最底层、不得 import 上层,所以放在 src 根,由 B0 所有。
|
|
7
|
+
* `exitCode` 用数字而不是 `ExitCode` 类型,避免底层模块反向依赖 cli/。
|
|
8
|
+
*/
|
|
9
|
+
export class AmaError extends Error {
|
|
10
|
+
code;
|
|
11
|
+
exitCode;
|
|
12
|
+
detail;
|
|
13
|
+
constructor(code, message, options = {}) {
|
|
14
|
+
super(message, options.cause === undefined ? undefined : { cause: options.cause });
|
|
15
|
+
this.name = "AmaError";
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.exitCode = options.exitCode;
|
|
18
|
+
this.detail = options.detail;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** 启动序列(§11.1)中的错误;`exitCode` 必填,取值见 cli/exit-codes.ts。 */
|
|
22
|
+
export class StartupError extends AmaError {
|
|
23
|
+
constructor(code, message, exitCode, options = {}) {
|
|
24
|
+
super(code, message, { ...options, exitCode });
|
|
25
|
+
this.name = "StartupError";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function isAmaError(value) {
|
|
29
|
+
return value instanceof AmaError;
|
|
30
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 命令式 Hook 的发现与合并(设计 §6.1「配置位置与合并」「信任边界」)。[B5]
|
|
3
|
+
*
|
|
4
|
+
* - 三层:`<configDir>/hooks.json`(user)→ profile `hooksFile`(profile,视同用户级)→
|
|
5
|
+
* `<cwd>/.ama/hooks.json`(project,需信任);事件数组按此顺序**拼接**,不覆盖。
|
|
6
|
+
* - 未信任时项目级跳过(`skippedProject` 交给 doctor / 状态栏提示)。
|
|
7
|
+
* - 语法 / 字段错误抛 StartupError(退出码 3);非法 matcher 同样按字段错误处理。
|
|
8
|
+
*/
|
|
9
|
+
import type { HookConfig, HookEvent, HookSource } from "./types.js";
|
|
10
|
+
export declare const DEFAULT_HOOK_TIMEOUT_MS = 60000;
|
|
11
|
+
/** 展平后的一条 Hook 命令。 */
|
|
12
|
+
export interface LoadedHook {
|
|
13
|
+
event: HookEvent;
|
|
14
|
+
matcher?: string;
|
|
15
|
+
command: string;
|
|
16
|
+
timeoutMs: number;
|
|
17
|
+
source: HookSource;
|
|
18
|
+
/** 来源文件(SDK 为 "sdk")。 */
|
|
19
|
+
file: string;
|
|
20
|
+
/** 全局配置顺序(additionalContext 拼接顺序)。 */
|
|
21
|
+
order: number;
|
|
22
|
+
}
|
|
23
|
+
export interface HookLayer {
|
|
24
|
+
source: HookSource;
|
|
25
|
+
file: string;
|
|
26
|
+
config: HookConfig;
|
|
27
|
+
}
|
|
28
|
+
export declare function clampTimeout(value: number | undefined, fallback: number): number;
|
|
29
|
+
/** 把若干层按顺序展平;`defaultTimeoutMs` 来自 config.hooks.timeoutMs。 */
|
|
30
|
+
export declare function flattenHookLayers(layers: readonly HookLayer[], defaultTimeoutMs?: number): LoadedHook[];
|
|
31
|
+
export interface LoadHookConfigsInput {
|
|
32
|
+
configDir: string;
|
|
33
|
+
cwd: string;
|
|
34
|
+
/** profile.hooksFile(必须存在)。 */
|
|
35
|
+
profileHooksFile?: string | undefined;
|
|
36
|
+
trusted: boolean;
|
|
37
|
+
/** config.hooks.timeoutMs。 */
|
|
38
|
+
defaultTimeoutMs?: number | undefined;
|
|
39
|
+
}
|
|
40
|
+
export interface LoadHookConfigsResult {
|
|
41
|
+
hooks: LoadedHook[];
|
|
42
|
+
layers: HookLayer[];
|
|
43
|
+
/** 项目级存在但因未信任被跳过的文件。 */
|
|
44
|
+
skippedProject?: string;
|
|
45
|
+
warnings: string[];
|
|
46
|
+
}
|
|
47
|
+
export declare function loadHookConfigs(input: LoadHookConfigsInput): LoadHookConfigsResult;
|
|
48
|
+
/** SDK 传入的 HookConfig(视同用户级,不经过信任)。 */
|
|
49
|
+
export declare function hooksFromConfig(config: HookConfig, defaultTimeoutMs?: number): LoadedHook[];
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 命令式 Hook 的发现与合并(设计 §6.1「配置位置与合并」「信任边界」)。[B5]
|
|
3
|
+
*
|
|
4
|
+
* - 三层:`<configDir>/hooks.json`(user)→ profile `hooksFile`(profile,视同用户级)→
|
|
5
|
+
* `<cwd>/.ama/hooks.json`(project,需信任);事件数组按此顺序**拼接**,不覆盖。
|
|
6
|
+
* - 未信任时项目级跳过(`skippedProject` 交给 doctor / 状态栏提示)。
|
|
7
|
+
* - 语法 / 字段错误抛 StartupError(退出码 3);非法 matcher 同样按字段错误处理。
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
10
|
+
import { StartupError } from "../errors.js";
|
|
11
|
+
import { loadConfigFile } from "../config/load.js";
|
|
12
|
+
import { HOOKS_FILE, projectFile, userFile } from "../config/paths.js";
|
|
13
|
+
import { HOOK_TIMEOUT_MAX_MS } from "../config/schema.js";
|
|
14
|
+
import { checkMatcher } from "./matcher.js";
|
|
15
|
+
import { HOOK_EVENTS } from "./types.js";
|
|
16
|
+
export const DEFAULT_HOOK_TIMEOUT_MS = 60_000;
|
|
17
|
+
export function clampTimeout(value, fallback) {
|
|
18
|
+
const v = value ?? fallback;
|
|
19
|
+
return Math.min(Math.max(1, Math.floor(v)), HOOK_TIMEOUT_MAX_MS);
|
|
20
|
+
}
|
|
21
|
+
/** 把若干层按顺序展平;`defaultTimeoutMs` 来自 config.hooks.timeoutMs。 */
|
|
22
|
+
export function flattenHookLayers(layers, defaultTimeoutMs = DEFAULT_HOOK_TIMEOUT_MS) {
|
|
23
|
+
const hooks = [];
|
|
24
|
+
let order = 0;
|
|
25
|
+
for (const layer of layers) {
|
|
26
|
+
for (const event of HOOK_EVENTS) {
|
|
27
|
+
for (const group of layer.config.hooks[event] ?? []) {
|
|
28
|
+
for (const command of group.hooks) {
|
|
29
|
+
const hook = {
|
|
30
|
+
event,
|
|
31
|
+
command: command.command,
|
|
32
|
+
timeoutMs: clampTimeout(command.timeoutMs, defaultTimeoutMs),
|
|
33
|
+
source: layer.source,
|
|
34
|
+
file: layer.file,
|
|
35
|
+
order: order++,
|
|
36
|
+
};
|
|
37
|
+
if (group.matcher !== undefined)
|
|
38
|
+
hook.matcher = group.matcher;
|
|
39
|
+
hooks.push(hook);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return hooks;
|
|
45
|
+
}
|
|
46
|
+
function validateMatchers(file, config) {
|
|
47
|
+
const problems = [];
|
|
48
|
+
for (const event of HOOK_EVENTS) {
|
|
49
|
+
(config.hooks[event] ?? []).forEach((group, index) => {
|
|
50
|
+
const error = checkMatcher(group.matcher);
|
|
51
|
+
if (error !== undefined)
|
|
52
|
+
problems.push(`hooks.${event}[${index}].matcher: ${error}`);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
if (problems.length > 0) {
|
|
56
|
+
throw new StartupError("config_invalid", `配置文件无效:\n ${problems.map((p) => `${file}: ${p}`).join("\n ")}`, 3);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function readLayer(source, file, required) {
|
|
60
|
+
const loaded = loadConfigFile("hooks", file, { required });
|
|
61
|
+
if (loaded === undefined)
|
|
62
|
+
return undefined;
|
|
63
|
+
validateMatchers(file, loaded.value);
|
|
64
|
+
return { source, file, config: loaded.value };
|
|
65
|
+
}
|
|
66
|
+
export function loadHookConfigs(input) {
|
|
67
|
+
const layers = [];
|
|
68
|
+
const warnings = [];
|
|
69
|
+
const user = readLayer("user", userFile(input, HOOKS_FILE), false);
|
|
70
|
+
if (user !== undefined)
|
|
71
|
+
layers.push(user);
|
|
72
|
+
if (input.profileHooksFile !== undefined) {
|
|
73
|
+
const profile = readLayer("profile", input.profileHooksFile, true);
|
|
74
|
+
if (profile !== undefined)
|
|
75
|
+
layers.push(profile);
|
|
76
|
+
}
|
|
77
|
+
const projectPath = projectFile(input.cwd, HOOKS_FILE);
|
|
78
|
+
let skippedProject;
|
|
79
|
+
if (input.trusted) {
|
|
80
|
+
const project = readLayer("project", projectPath, false);
|
|
81
|
+
if (project !== undefined)
|
|
82
|
+
layers.push(project);
|
|
83
|
+
}
|
|
84
|
+
else if (existsSync(projectPath)) {
|
|
85
|
+
// 未信任时不解析内容(不让不可信文件的语法错误阻断启动),只看存在性。
|
|
86
|
+
skippedProject = projectPath;
|
|
87
|
+
warnings.push(`${projectPath}: 项目未信任,跳过项目级 Hook(用 --trust 或在交互模式确认信任)`);
|
|
88
|
+
}
|
|
89
|
+
const result = {
|
|
90
|
+
hooks: flattenHookLayers(layers, input.defaultTimeoutMs ?? DEFAULT_HOOK_TIMEOUT_MS),
|
|
91
|
+
layers,
|
|
92
|
+
warnings,
|
|
93
|
+
};
|
|
94
|
+
if (skippedProject !== undefined)
|
|
95
|
+
result.skippedProject = skippedProject;
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
/** SDK 传入的 HookConfig(视同用户级,不经过信任)。 */
|
|
99
|
+
export function hooksFromConfig(config, defaultTimeoutMs = DEFAULT_HOOK_TIMEOUT_MS) {
|
|
100
|
+
validateMatchers("sdk", config);
|
|
101
|
+
return flattenHookLayers([{ source: "sdk", file: "sdk", config }], defaultTimeoutMs);
|
|
102
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HookDispatcher:实现 HookDispatcherApi(设计 §6.1、§6.3)。[B5]
|
|
3
|
+
*
|
|
4
|
+
* AgentSession(B2)在各钩子点调用 `run(event, payload, signal?, context?)`;公共字段(sessionId、
|
|
5
|
+
* cwd、model、permissionMode、depth、host…)由构造时给的 `context()` 每次现取,再由第 4 参数
|
|
6
|
+
* 按次覆盖(子 Agent 的 depth / sessionId / sessionFile)。每条 Hook 执行后回调
|
|
7
|
+
* `onExecuted`(bootstrap 把它接到宿主事件 `hook_executed`)。matcher 只在 Pre/PostToolUse 生效。
|
|
8
|
+
*/
|
|
9
|
+
import type { LoadedHook } from "./config.js";
|
|
10
|
+
import { type RunHookOptions } from "./runner.js";
|
|
11
|
+
import type { HookCommonContext, HookContextOverrides, HookDispatcherApi, HookEvent, HookEventPayload, HookInput, HookNotification, HookOutcome, HookRunResult, HookSource } from "./types.js";
|
|
12
|
+
export type { HookCommonContext } from "./types.js";
|
|
13
|
+
export type HookExecutor = (hooks: readonly LoadedHook[], input: HookInput, options: RunHookOptions) => Promise<HookRunResult[]>;
|
|
14
|
+
export interface HookDispatcherOptions {
|
|
15
|
+
hooks: readonly LoadedHook[];
|
|
16
|
+
context: () => HookCommonContext;
|
|
17
|
+
/** 每条 Hook 结束后(含超时)回调;异常被吞掉。 */
|
|
18
|
+
onExecuted?: (result: HookRunResult) => void;
|
|
19
|
+
/** 合并后的 warning(Hook 失败、超时、冲突的 updatedInput)。 */
|
|
20
|
+
onWarning?: (message: string) => void;
|
|
21
|
+
/** 测试注入;缺省为子进程 runner。 */
|
|
22
|
+
executor?: HookExecutor;
|
|
23
|
+
/** 额外环境变量。 */
|
|
24
|
+
env?: Readonly<Record<string, string | undefined>>;
|
|
25
|
+
}
|
|
26
|
+
export declare class HookDispatcher implements HookDispatcherApi {
|
|
27
|
+
private readonly byEvent;
|
|
28
|
+
private readonly options;
|
|
29
|
+
constructor(options: HookDispatcherOptions);
|
|
30
|
+
private matching;
|
|
31
|
+
has(event: HookEvent, toolName?: string): boolean;
|
|
32
|
+
run(event: HookEvent, payload: HookEventPayload, signal?: AbortSignal, context?: HookContextOverrides): Promise<HookOutcome>;
|
|
33
|
+
/** Notification 投递:纯通知,不等待结果、不抛错。 */
|
|
34
|
+
notify(notification: HookNotification): void;
|
|
35
|
+
list(): readonly {
|
|
36
|
+
event: HookEvent;
|
|
37
|
+
matcher?: string;
|
|
38
|
+
command: string;
|
|
39
|
+
source: HookSource;
|
|
40
|
+
}[];
|
|
41
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HookDispatcher:实现 HookDispatcherApi(设计 §6.1、§6.3)。[B5]
|
|
3
|
+
*
|
|
4
|
+
* AgentSession(B2)在各钩子点调用 `run(event, payload, signal?, context?)`;公共字段(sessionId、
|
|
5
|
+
* cwd、model、permissionMode、depth、host…)由构造时给的 `context()` 每次现取,再由第 4 参数
|
|
6
|
+
* 按次覆盖(子 Agent 的 depth / sessionId / sessionFile)。每条 Hook 执行后回调
|
|
7
|
+
* `onExecuted`(bootstrap 把它接到宿主事件 `hook_executed`)。matcher 只在 Pre/PostToolUse 生效。
|
|
8
|
+
*/
|
|
9
|
+
import { compileMatcher } from "./matcher.js";
|
|
10
|
+
import { emptyOutcome, mergeResults } from "./protocol.js";
|
|
11
|
+
import { runHooks } from "./runner.js";
|
|
12
|
+
/** 用 `overrides` 里值不为 undefined 的键覆盖 `base`。 */
|
|
13
|
+
function withOverrides(base, overrides) {
|
|
14
|
+
if (overrides === undefined)
|
|
15
|
+
return base;
|
|
16
|
+
const merged = { ...base };
|
|
17
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
18
|
+
if (value !== undefined)
|
|
19
|
+
merged[key] = value;
|
|
20
|
+
}
|
|
21
|
+
return merged;
|
|
22
|
+
}
|
|
23
|
+
const TOOL_EVENTS = new Set(["PreToolUse", "PostToolUse"]);
|
|
24
|
+
export class HookDispatcher {
|
|
25
|
+
byEvent = new Map();
|
|
26
|
+
options;
|
|
27
|
+
constructor(options) {
|
|
28
|
+
this.options = options;
|
|
29
|
+
const sorted = [...options.hooks].sort((a, b) => a.order - b.order);
|
|
30
|
+
for (const hook of sorted) {
|
|
31
|
+
const list = this.byEvent.get(hook.event) ?? [];
|
|
32
|
+
list.push({
|
|
33
|
+
hook,
|
|
34
|
+
matcher: compileMatcher(hook.matcher),
|
|
35
|
+
nameMatcher: compileMatcher(hook.matcher, true),
|
|
36
|
+
});
|
|
37
|
+
this.byEvent.set(hook.event, list);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
matching(event, toolName, toolInput) {
|
|
41
|
+
const list = this.byEvent.get(event) ?? [];
|
|
42
|
+
if (!TOOL_EVENTS.has(event))
|
|
43
|
+
return list.map((c) => c.hook);
|
|
44
|
+
if (toolName === undefined)
|
|
45
|
+
return list.map((c) => c.hook);
|
|
46
|
+
return list.filter((c) => c.matcher(toolName, toolInput)).map((c) => c.hook);
|
|
47
|
+
}
|
|
48
|
+
has(event, toolName) {
|
|
49
|
+
const list = this.byEvent.get(event) ?? [];
|
|
50
|
+
if (list.length === 0)
|
|
51
|
+
return false;
|
|
52
|
+
if (!TOOL_EVENTS.has(event) || toolName === undefined)
|
|
53
|
+
return true;
|
|
54
|
+
// 不知道输入时只按工具名判断(括号参数视为可能匹配)。
|
|
55
|
+
return list.some((c) => c.nameMatcher(toolName, undefined));
|
|
56
|
+
}
|
|
57
|
+
async run(event, payload, signal, context) {
|
|
58
|
+
const hooks = this.matching(event, payload.toolName, payload.toolInput);
|
|
59
|
+
if (hooks.length === 0)
|
|
60
|
+
return emptyOutcome();
|
|
61
|
+
const common = withOverrides(this.options.context(), context);
|
|
62
|
+
const input = { ...common, ...payload, hookEventName: event };
|
|
63
|
+
const executor = this.options.executor ?? runHooks;
|
|
64
|
+
const runOptions = { cwd: common.cwd, signal };
|
|
65
|
+
if (this.options.env !== undefined)
|
|
66
|
+
runOptions.env = this.options.env;
|
|
67
|
+
const results = await executor(hooks, input, runOptions);
|
|
68
|
+
for (const result of results) {
|
|
69
|
+
try {
|
|
70
|
+
this.options.onExecuted?.(result);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// 观察者异常不影响 Hook 结论
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const outcome = mergeResults(results);
|
|
77
|
+
for (const warning of outcome.warnings)
|
|
78
|
+
this.options.onWarning?.(warning);
|
|
79
|
+
return outcome;
|
|
80
|
+
}
|
|
81
|
+
/** Notification 投递:纯通知,不等待结果、不抛错。 */
|
|
82
|
+
notify(notification) {
|
|
83
|
+
if (!this.has("Notification"))
|
|
84
|
+
return;
|
|
85
|
+
void this.run("Notification", { notification }).catch(() => undefined);
|
|
86
|
+
}
|
|
87
|
+
list() {
|
|
88
|
+
const all = [];
|
|
89
|
+
for (const list of this.byEvent.values())
|
|
90
|
+
all.push(...list.map((c) => c.hook));
|
|
91
|
+
return all
|
|
92
|
+
.sort((a, b) => a.order - b.order)
|
|
93
|
+
.map((hook) => {
|
|
94
|
+
const item = {
|
|
95
|
+
event: hook.event,
|
|
96
|
+
command: hook.command,
|
|
97
|
+
source: hook.source,
|
|
98
|
+
};
|
|
99
|
+
if (hook.matcher !== undefined)
|
|
100
|
+
item.matcher = hook.matcher;
|
|
101
|
+
return item;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook matcher(设计 §6.1「matcher」)。[B5]
|
|
3
|
+
*
|
|
4
|
+
* 语法:缺省 / 空串 / `*` 匹配全部;`bash` 精确;`write|edit` 多选;`canvas_*` glob;
|
|
5
|
+
* `bash(git push*)` 先匹配工具名,再对参数文本做 glob;`/regex/flags` 对工具名做正则。
|
|
6
|
+
* 括号内的文本:bash → `input.command`;文件类工具 → `input.path`(或 `file_path`);
|
|
7
|
+
* 其它工具 → 输入 JSON 文本。`|` 只在括号外分隔候选。只在 Pre/PostToolUse 生效。
|
|
8
|
+
*/
|
|
9
|
+
export type ToolMatcher = (toolName: string, input: unknown) => boolean;
|
|
10
|
+
/** glob → 正则:`*` 任意字符串(含 `/`),`?` 单个字符,其余字面量。 */
|
|
11
|
+
export declare function globToRegExp(glob: string): RegExp;
|
|
12
|
+
/** 括号外的 `|` 切分。 */
|
|
13
|
+
export declare function splitAlternatives(matcher: string): string[];
|
|
14
|
+
/** 括号内 glob 匹配的参数文本。 */
|
|
15
|
+
export declare function argumentText(toolName: string, input: unknown): string;
|
|
16
|
+
/**
|
|
17
|
+
* 编译 matcher;语法错误(非法正则)抛 Error。
|
|
18
|
+
* `nameOnly`:忽略括号参数,只看工具名(输入未知时判断「可能匹配」)。
|
|
19
|
+
*/
|
|
20
|
+
export declare function compileMatcher(matcher: string | undefined, nameOnly?: boolean): ToolMatcher;
|
|
21
|
+
/** 校验 matcher 语法;返回错误信息或 undefined。 */
|
|
22
|
+
export declare function checkMatcher(matcher: string | undefined): string | undefined;
|