@armadra/agent 0.5.1 → 0.6.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 +203 -304
- package/CHANGELOG.zh-CN.md +462 -0
- package/README.md +408 -364
- package/README.zh-CN.md +705 -0
- package/dist/agent/session-plan.js +2 -2
- package/dist/agent/session-state.d.ts +3 -0
- package/dist/agent/session-state.js +20 -0
- package/dist/agent/session-subagent.d.ts +15 -1
- package/dist/agent/session-subagent.js +26 -3
- package/dist/agent/session-telemetry.d.ts +16 -2
- package/dist/agent/session-telemetry.js +29 -7
- package/dist/agent/session-tools.js +5 -2
- package/dist/agent/session-trace-writer.d.ts +27 -0
- package/dist/agent/session-trace-writer.js +253 -0
- package/dist/agent/session.d.ts +2 -0
- package/dist/agent/session.js +12 -0
- package/dist/agent/subagent-direct.d.ts +20 -0
- package/dist/agent/subagent-direct.js +76 -0
- package/dist/agent/subagent-registry.d.ts +8 -1
- package/dist/agent/subagent-registry.js +28 -1
- package/dist/agent/system-prompt.d.ts +3 -1
- package/dist/agent/system-prompt.js +3 -0
- package/dist/agent/tool-runner.d.ts +2 -1
- package/dist/agent/tool-runner.js +5 -4
- package/dist/agent/types-w6.d.ts +39 -0
- package/dist/agent/types-w6.js +4 -0
- package/dist/agent/types.d.ts +5 -2
- package/dist/agents/external.js +1 -1
- package/dist/agents/task-record.d.ts +74 -1
- package/dist/agents/task-record.js +100 -0
- package/dist/ai/apis/cache-params.js +2 -1
- package/dist/ai/apis/chatgpt-backend.d.ts +52 -0
- package/dist/ai/apis/chatgpt-backend.js +224 -0
- package/dist/ai/apis/chatgpt-rate-limits.d.ts +26 -0
- package/dist/ai/apis/chatgpt-rate-limits.js +91 -0
- package/dist/ai/apis/openai-responses-request.d.ts +2 -1
- package/dist/ai/apis/openai-responses-request.js +8 -2
- package/dist/ai/apis/openai-responses.d.ts +2 -0
- package/dist/ai/apis/openai-responses.js +51 -16
- package/dist/ai/overflow.d.ts +1 -1
- package/dist/ai/overflow.js +10 -7
- package/dist/ai/providers/auth.d.ts +15 -2
- package/dist/ai/providers/auth.js +69 -2
- package/dist/ai/providers/builtin.js +27 -0
- package/dist/ai/providers/catalog-data.js +1 -0
- package/dist/ai/providers/discovered-cache.d.ts +48 -0
- package/dist/ai/providers/discovered-cache.js +102 -0
- package/dist/ai/providers/enrich.js +2 -7
- package/dist/ai/providers/model-visibility.d.ts +33 -0
- package/dist/ai/providers/model-visibility.js +70 -0
- package/dist/ai/providers/models-dev-cache.js +15 -19
- package/dist/ai/providers/models-dev-snapshot.js +8 -7
- package/dist/ai/providers/models-dev.js +5 -15
- package/dist/ai/providers/registry.d.ts +2 -0
- package/dist/ai/providers/registry.js +6 -1
- package/dist/ai/providers/suggest.js +2 -16
- package/dist/ai/types.d.ts +27 -1
- package/dist/auth/chatgpt/backend-client.d.ts +26 -0
- package/dist/auth/chatgpt/backend-client.js +74 -0
- package/dist/auth/chatgpt/claims.d.ts +17 -0
- package/dist/auth/chatgpt/claims.js +46 -0
- package/dist/auth/chatgpt/cli.d.ts +35 -0
- package/dist/auth/chatgpt/cli.js +279 -0
- package/dist/auth/chatgpt/doctor.d.ts +17 -0
- package/dist/auth/chatgpt/doctor.js +36 -0
- package/dist/auth/chatgpt/host-id.d.ts +7 -0
- package/dist/auth/chatgpt/host-id.js +26 -0
- package/dist/auth/chatgpt/login.d.ts +30 -0
- package/dist/auth/chatgpt/login.js +130 -0
- package/dist/auth/chatgpt/presets.d.ts +66 -0
- package/dist/auth/chatgpt/presets.js +120 -0
- package/dist/auth/chatgpt/quota-text.d.ts +13 -0
- package/dist/auth/chatgpt/quota-text.js +36 -0
- package/dist/auth/oauth/browser.d.ts +12 -0
- package/dist/auth/oauth/browser.js +27 -0
- package/dist/auth/oauth/callback-server.d.ts +47 -0
- package/dist/auth/oauth/callback-server.js +147 -0
- package/dist/auth/oauth/flows.d.ts +62 -0
- package/dist/auth/oauth/flows.js +113 -0
- package/dist/auth/oauth/jwt.d.ts +24 -0
- package/dist/auth/oauth/jwt.js +81 -0
- package/dist/auth/oauth/live.d.ts +21 -0
- package/dist/auth/oauth/live.js +25 -0
- package/dist/auth/oauth/oidc.d.ts +26 -0
- package/dist/auth/oauth/oidc.js +72 -0
- package/dist/auth/oauth/pkce.d.ts +15 -0
- package/dist/auth/oauth/pkce.js +20 -0
- package/dist/auth/oauth/refresh.d.ts +35 -0
- package/dist/auth/oauth/refresh.js +129 -0
- package/dist/auth/oauth/token-client.d.ts +33 -0
- package/dist/auth/oauth/token-client.js +121 -0
- package/dist/auth/oauth/token-store.d.ts +23 -0
- package/dist/auth/oauth/token-store.js +125 -0
- package/dist/auth/testing/fake-oauth.d.ts +73 -0
- package/dist/auth/testing/fake-oauth.js +271 -0
- package/dist/auth/testing/refresh-child.d.ts +5 -0
- package/dist/auth/testing/refresh-child.js +16 -0
- package/dist/bundle/ama.cjs +26532 -11045
- package/dist/checkpoints/backend.js +6 -5
- package/dist/checkpoints/restore.js +3 -2
- package/dist/checkpoints/settings.js +2 -1
- package/dist/checkpoints/shadow-git.js +7 -6
- package/dist/checkpoints/shadow-restore.js +3 -2
- package/dist/checkpoints/tracker.js +4 -3
- package/dist/cli/args.d.ts +9 -2
- package/dist/cli/args.js +74 -27
- package/dist/cli/bootstrap.js +53 -31
- package/dist/cli/choice-prompt.js +8 -6
- package/dist/cli/codemode-notice.js +2 -2
- package/dist/cli/compose-agents.js +2 -1
- package/dist/cli/compose-extensions.js +2 -0
- package/dist/cli/compose-memory.d.ts +53 -0
- package/dist/cli/compose-memory.js +127 -0
- package/dist/cli/compose-providers.d.ts +6 -0
- package/dist/cli/compose-providers.js +38 -2
- package/dist/cli/compose-session.d.ts +5 -0
- package/dist/cli/compose-session.js +27 -13
- package/dist/cli/compose-store.d.ts +2 -0
- package/dist/cli/compose-store.js +9 -5
- package/dist/cli/compose.d.ts +2 -0
- package/dist/cli/compose.js +13 -5
- package/dist/cli/default-model.d.ts +0 -2
- package/dist/cli/default-model.js +5 -8
- package/dist/cli/deps.d.ts +5 -1
- package/dist/cli/exit-codes.d.ts +1 -1
- package/dist/cli/exit-codes.js +7 -16
- package/dist/cli/from-prompt.js +3 -2
- package/dist/cli/help-text.d.ts +2 -1
- package/dist/cli/help-text.js +5 -99
- package/dist/cli/main.d.ts +5 -0
- package/dist/cli/main.js +21 -2
- package/dist/cli/proxy.js +14 -9
- package/dist/cli/runtime.d.ts +5 -0
- package/dist/cli/startup-screen.js +20 -27
- package/dist/cli/startup-steps.js +6 -8
- package/dist/cli/subcommands/auth.d.ts +6 -3
- package/dist/cli/subcommands/auth.js +52 -22
- package/dist/cli/subcommands/config-set.d.ts +21 -0
- package/dist/cli/subcommands/config-set.js +145 -0
- package/dist/cli/subcommands/config.d.ts +2 -1
- package/dist/cli/subcommands/config.js +51 -37
- package/dist/cli/subcommands/doctor.d.ts +2 -1
- package/dist/cli/subcommands/doctor.js +97 -58
- package/dist/cli/subcommands/init.d.ts +1 -1
- package/dist/cli/subcommands/init.js +8 -7
- package/dist/cli/subcommands/memory.d.ts +18 -0
- package/dist/cli/subcommands/memory.js +189 -0
- package/dist/cli/subcommands/model-meta.js +11 -9
- package/dist/cli/subcommands/models-cache-probe.js +23 -20
- package/dist/cli/subcommands/models-discover.d.ts +4 -0
- package/dist/cli/subcommands/models-discover.js +60 -21
- package/dist/cli/subcommands/models-enable.d.ts +13 -0
- package/dist/cli/subcommands/models-enable.js +145 -0
- package/dist/cli/subcommands/models.d.ts +3 -1
- package/dist/cli/subcommands/models.js +39 -24
- package/dist/cli/subcommands/probe-runner.js +8 -7
- package/dist/cli/subcommands/providers-list.js +32 -21
- package/dist/cli/subcommands/providers-plan.js +24 -25
- package/dist/cli/subcommands/providers-probe.js +5 -6
- package/dist/cli/subcommands/providers.d.ts +1 -1
- package/dist/cli/subcommands/providers.js +45 -50
- package/dist/cli/subcommands/sessions-export.d.ts +1 -1
- package/dist/cli/subcommands/sessions-export.js +10 -9
- package/dist/cli/subcommands/sessions-search.d.ts +1 -1
- package/dist/cli/subcommands/sessions-search.js +11 -10
- package/dist/cli/subcommands/sessions-trace.d.ts +30 -0
- package/dist/cli/subcommands/sessions-trace.js +156 -0
- package/dist/cli/subcommands/sessions.d.ts +4 -3
- package/dist/cli/subcommands/sessions.js +40 -37
- package/dist/cli/subcommands/stats.d.ts +1 -1
- package/dist/cli/subcommands/stats.js +49 -30
- package/dist/cli/system-prompt-arg.js +3 -2
- package/dist/codemode/capability.js +3 -2
- package/dist/compaction/post-compact.d.ts +1 -0
- package/dist/compaction/post-compact.js +15 -1
- package/dist/compaction/prune-tier.d.ts +1 -1
- package/dist/compaction/prune-tier.js +3 -3
- package/dist/compaction/serialize.js +2 -1
- package/dist/config/auth-file.d.ts +12 -2
- package/dist/config/auth-file.js +32 -10
- package/dist/config/checker.js +12 -11
- package/dist/config/context-files.js +3 -2
- package/dist/config/edit.d.ts +106 -0
- package/dist/config/edit.js +350 -0
- package/dist/config/init.d.ts +4 -3
- package/dist/config/init.js +10 -18
- package/dist/config/json-schema.d.ts +2 -1
- package/dist/config/json-schema.js +102 -69
- package/dist/config/key-docs.d.ts +18 -7
- package/dist/config/key-docs.js +43 -128
- package/dist/config/load.js +7 -6
- package/dist/config/merge.d.ts +4 -1
- package/dist/config/merge.js +42 -22
- package/dist/config/paths.js +6 -5
- package/dist/config/profile.d.ts +5 -1
- package/dist/config/profile.js +7 -2
- package/dist/config/schema-w5.js +12 -4
- package/dist/config/schema-w6.d.ts +19 -0
- package/dist/config/schema-w6.js +115 -0
- package/dist/config/schema.js +34 -20
- package/dist/config/settings-registry.d.ts +81 -0
- package/dist/config/settings-registry.js +185 -0
- package/dist/config/types-w5.d.ts +7 -0
- package/dist/config/types-w5.js +2 -0
- package/dist/config/types-w6.d.ts +109 -0
- package/dist/config/types-w6.js +19 -0
- package/dist/config/types.d.ts +11 -8
- package/dist/config/types.js +1 -0
- package/dist/drivers/acp/client.js +1 -1
- package/dist/drivers/acp/driver.js +13 -8
- package/dist/drivers/agents.js +4 -3
- package/dist/drivers/base.js +3 -2
- package/dist/drivers/host-runners.js +2 -1
- package/dist/drivers/native/claude-stream.js +12 -11
- package/dist/drivers/native/codex-app-server.js +17 -12
- package/dist/drivers/native/oneshot.js +8 -7
- package/dist/drivers/pool.js +1 -1
- package/dist/drivers/runner.d.ts +3 -1
- package/dist/drivers/runner.js +68 -20
- package/dist/drivers/turn.js +1 -1
- package/dist/hooks/config.js +3 -2
- package/dist/hooks/protocol.js +18 -12
- package/dist/host/api-impl.js +11 -10
- package/dist/host/loader.js +9 -8
- package/dist/host/types.d.ts +3 -0
- package/dist/i18n/catalog.d.ts +2209 -0
- package/dist/i18n/catalog.js +72 -0
- package/dist/i18n/format.d.ts +21 -0
- package/dist/i18n/format.js +58 -0
- package/dist/i18n/index.d.ts +58 -0
- package/dist/i18n/index.js +72 -0
- package/dist/i18n/messages/agents.d.ts +84 -0
- package/dist/i18n/messages/agents.js +85 -0
- package/dist/i18n/messages/approval.d.ts +99 -0
- package/dist/i18n/messages/approval.js +100 -0
- package/dist/i18n/messages/auth.d.ts +189 -0
- package/dist/i18n/messages/auth.js +201 -0
- package/dist/i18n/messages/cli-args.d.ts +46 -0
- package/dist/i18n/messages/cli-args.js +46 -0
- package/dist/i18n/messages/cli-help.d.ts +12 -0
- package/dist/i18n/messages/cli-help.js +248 -0
- package/dist/i18n/messages/cli.d.ts +336 -0
- package/dist/i18n/messages/cli.js +311 -0
- package/dist/i18n/messages/config-keys.d.ts +293 -0
- package/dist/i18n/messages/config-keys.js +296 -0
- package/dist/i18n/messages/config.d.ts +508 -0
- package/dist/i18n/messages/config.js +241 -0
- package/dist/i18n/messages/drivers.d.ts +123 -0
- package/dist/i18n/messages/drivers.js +124 -0
- package/dist/i18n/messages/errors.d.ts +83 -0
- package/dist/i18n/messages/errors.js +171 -0
- package/dist/i18n/messages/interactive-line.d.ts +61 -0
- package/dist/i18n/messages/interactive-line.js +69 -0
- package/dist/i18n/messages/interactive-startup.d.ts +99 -0
- package/dist/i18n/messages/interactive-startup.js +100 -0
- package/dist/i18n/messages/interactive-view.d.ts +140 -0
- package/dist/i18n/messages/interactive-view.js +141 -0
- package/dist/i18n/messages/interactive.d.ts +489 -0
- package/dist/i18n/messages/interactive.js +248 -0
- package/dist/i18n/messages/memory.d.ts +123 -0
- package/dist/i18n/messages/memory.js +128 -0
- package/dist/i18n/messages/panels.d.ts +233 -0
- package/dist/i18n/messages/panels.js +232 -0
- package/dist/i18n/messages/permissions.d.ts +126 -0
- package/dist/i18n/messages/permissions.js +151 -0
- package/dist/i18n/messages/plan.d.ts +123 -0
- package/dist/i18n/messages/plan.js +124 -0
- package/dist/i18n/messages/print.d.ts +86 -0
- package/dist/i18n/messages/print.js +91 -0
- package/dist/i18n/messages/report.d.ts +391 -0
- package/dist/i18n/messages/report.js +490 -0
- package/dist/i18n/messages/rewind.d.ts +198 -0
- package/dist/i18n/messages/rewind.js +217 -0
- package/dist/i18n/messages/session.d.ts +230 -0
- package/dist/i18n/messages/session.js +258 -0
- package/dist/i18n/messages/settings.d.ts +355 -0
- package/dist/i18n/messages/settings.js +343 -0
- package/dist/i18n/messages/subcommands-config.d.ts +113 -0
- package/dist/i18n/messages/subcommands-config.js +129 -0
- package/dist/i18n/messages/subcommands-models.d.ts +34 -0
- package/dist/i18n/messages/subcommands-models.js +34 -0
- package/dist/i18n/messages/subcommands.d.ts +576 -0
- package/dist/i18n/messages/subcommands.js +477 -0
- package/dist/i18n/messages/trace.d.ts +243 -0
- package/dist/i18n/messages/trace.js +238 -0
- package/dist/i18n/types.d.ts +15 -0
- package/dist/i18n/types.js +7 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +2 -0
- package/dist/memory/edit.d.ts +24 -0
- package/dist/memory/edit.js +63 -0
- package/dist/memory/frontmatter.d.ts +37 -0
- package/dist/memory/frontmatter.js +79 -0
- package/dist/memory/index.d.ts +28 -0
- package/dist/memory/index.js +126 -0
- package/dist/memory/lock.d.ts +17 -0
- package/dist/memory/lock.js +62 -0
- package/dist/memory/paths.d.ts +57 -0
- package/dist/memory/paths.js +175 -0
- package/dist/memory/report.d.ts +36 -0
- package/dist/memory/report.js +86 -0
- package/dist/memory/runtime.d.ts +42 -0
- package/dist/memory/runtime.js +36 -0
- package/dist/memory/secrets.d.ts +8 -0
- package/dist/memory/secrets.js +27 -0
- package/dist/memory/section.d.ts +28 -0
- package/dist/memory/section.js +59 -0
- package/dist/memory/store.d.ts +70 -0
- package/dist/memory/store.js +284 -0
- package/dist/memory/tool.d.ts +31 -0
- package/dist/memory/tool.js +94 -0
- package/dist/modes/acp/acp-events.js +2 -1
- package/dist/modes/acp/acp-server.js +13 -12
- package/dist/modes/commands-core.d.ts +11 -0
- package/dist/modes/commands-core.js +93 -62
- package/dist/modes/image-input.js +20 -6
- package/dist/modes/interactive/agent-bar.d.ts +95 -0
- package/dist/modes/interactive/agent-bar.js +248 -0
- package/dist/modes/interactive/agent-panels.js +27 -26
- package/dist/modes/interactive/agent-transcript.d.ts +47 -0
- package/dist/modes/interactive/agent-transcript.js +191 -0
- package/dist/modes/interactive/agent-ui.d.ts +36 -1
- package/dist/modes/interactive/agent-ui.js +180 -14
- package/dist/modes/interactive/agent-view.d.ts +72 -0
- package/dist/modes/interactive/agent-view.js +281 -0
- package/dist/modes/interactive/approval-dialog.js +46 -34
- package/dist/modes/interactive/clipboard-paste.d.ts +2 -2
- package/dist/modes/interactive/clipboard-paste.js +9 -4
- package/dist/modes/interactive/commands.d.ts +22 -1
- package/dist/modes/interactive/commands.js +100 -49
- package/dist/modes/interactive/completion.js +2 -1
- package/dist/modes/interactive/config-panel.d.ts +70 -0
- package/dist/modes/interactive/config-panel.js +319 -0
- package/dist/modes/interactive/config-ui.d.ts +96 -0
- package/dist/modes/interactive/config-ui.js +397 -0
- package/dist/modes/interactive/confirm-dialog.js +6 -7
- package/dist/modes/interactive/event-notices.js +11 -9
- package/dist/modes/interactive/interactive-mode.d.ts +1 -1
- package/dist/modes/interactive/interactive-mode.js +21 -22
- package/dist/modes/interactive/key-dispatch.d.ts +12 -0
- package/dist/modes/interactive/key-dispatch.js +24 -9
- package/dist/modes/interactive/line/line-editor.js +2 -1
- package/dist/modes/interactive/line/line-mode.js +18 -7
- package/dist/modes/interactive/line/line-render.js +25 -24
- package/dist/modes/interactive/memory-panel.d.ts +64 -0
- package/dist/modes/interactive/memory-panel.js +221 -0
- package/dist/modes/interactive/message-view.d.ts +4 -2
- package/dist/modes/interactive/message-view.js +42 -33
- package/dist/modes/interactive/model-items.d.ts +45 -0
- package/dist/modes/interactive/model-items.js +134 -0
- package/dist/modes/interactive/model-picker.d.ts +57 -0
- package/dist/modes/interactive/model-picker.js +191 -0
- package/dist/modes/interactive/panels.js +39 -31
- package/dist/modes/interactive/pickers.d.ts +2 -1
- package/dist/modes/interactive/pickers.js +10 -6
- package/dist/modes/interactive/plan-command.d.ts +1 -1
- package/dist/modes/interactive/plan-command.js +24 -27
- package/dist/modes/interactive/plan-dialog.js +18 -17
- package/dist/modes/interactive/plan-flow.js +6 -5
- package/dist/modes/interactive/rewind-command.d.ts +1 -1
- package/dist/modes/interactive/rewind-command.js +18 -16
- package/dist/modes/interactive/rewind-flow.d.ts +0 -1
- package/dist/modes/interactive/rewind-flow.js +13 -14
- package/dist/modes/interactive/rewind-list.js +7 -6
- package/dist/modes/interactive/rewind-panel.js +40 -40
- package/dist/modes/interactive/rewind-text.d.ts +5 -3
- package/dist/modes/interactive/rewind-text.js +48 -38
- package/dist/modes/interactive/run-indicator.js +15 -12
- package/dist/modes/interactive/session-events.js +3 -2
- package/dist/modes/interactive/startup-header.js +22 -23
- package/dist/modes/interactive/startup-ui.d.ts +3 -9
- package/dist/modes/interactive/startup-ui.js +44 -88
- package/dist/modes/interactive/status-area.d.ts +2 -0
- package/dist/modes/interactive/status-area.js +8 -2
- package/dist/modes/interactive/status-bar.js +4 -3
- package/dist/modes/interactive/subagent-view.js +9 -7
- package/dist/modes/interactive/tasks-report.d.ts +6 -0
- package/dist/modes/interactive/tasks-report.js +28 -31
- package/dist/modes/interactive/terminal-setup.d.ts +9 -0
- package/dist/modes/interactive/terminal-setup.js +23 -0
- package/dist/modes/interactive/tool-summary.js +19 -17
- package/dist/modes/interactive/tool-view.js +7 -4
- package/dist/modes/interactive/trace-view.d.ts +89 -0
- package/dist/modes/interactive/trace-view.js +332 -0
- package/dist/modes/print/print-mode.js +14 -15
- package/dist/modes/rpc/commands.js +7 -3
- package/dist/modes/rpc/rpc-mode.js +9 -3
- package/dist/modes/session-report.d.ts +2 -0
- package/dist/modes/session-report.js +101 -105
- package/dist/modes/startup-ui-text.js +11 -6
- package/dist/permissions/bypass.d.ts +8 -10
- package/dist/permissions/bypass.js +19 -10
- package/dist/permissions/memory-class.d.ts +23 -0
- package/dist/permissions/memory-class.js +54 -0
- package/dist/permissions/modes.d.ts +3 -3
- package/dist/permissions/modes.js +21 -16
- package/dist/permissions/pipeline.d.ts +1 -1
- package/dist/permissions/pipeline.js +9 -2
- package/dist/permissions/preview.js +49 -42
- package/dist/permissions/rules.js +5 -2
- package/dist/permissions/types.d.ts +4 -0
- package/dist/plan/store.js +2 -1
- package/dist/rpc.d.ts +39 -1
- package/dist/rpc.js +3 -0
- package/dist/sandbox/bash.js +11 -8
- package/dist/sandbox/detect.js +14 -11
- package/dist/sdk.d.ts +17 -1
- package/dist/sdk.js +29 -7
- package/dist/session/export.js +31 -30
- package/dist/session/manager.d.ts +1 -1
- package/dist/session/manager.js +5 -3
- package/dist/session/reuse.js +5 -4
- package/dist/session/scan.js +3 -2
- package/dist/session/stats-aggregate.d.ts +3 -1
- package/dist/session/stats-aggregate.js +5 -1
- package/dist/session/stats-index.js +2 -1
- package/dist/session/stats-scan.d.ts +4 -1
- package/dist/session/stats-scan.js +6 -2
- package/dist/session/store.d.ts +11 -0
- package/dist/session/store.js +48 -1
- package/dist/session/types.d.ts +2 -0
- package/dist/skills/builtin.js +2 -1
- package/dist/tools/image-file.d.ts +26 -1
- package/dist/tools/image-file.js +55 -13
- package/dist/tools/presets.d.ts +14 -1
- package/dist/tools/presets.js +3 -3
- package/dist/tools/registry.js +1 -1
- package/dist/tools/truncate.d.ts +1 -1
- package/dist/tools/truncate.js +2 -2
- package/dist/tools/types.d.ts +17 -1
- package/dist/trace/build-index.d.ts +91 -0
- package/dist/trace/build-index.js +127 -0
- package/dist/trace/build-nodes.d.ts +24 -0
- package/dist/trace/build-nodes.js +279 -0
- package/dist/trace/build-util.d.ts +43 -0
- package/dist/trace/build-util.js +120 -0
- package/dist/trace/build.d.ts +82 -0
- package/dist/trace/build.js +382 -0
- package/dist/trace/detail.d.ts +35 -0
- package/dist/trace/detail.js +205 -0
- package/dist/trace/flatten.d.ts +69 -0
- package/dist/trace/flatten.js +173 -0
- package/dist/trace/format.d.ts +47 -0
- package/dist/trace/format.js +329 -0
- package/dist/trace/html-template.d.ts +19 -0
- package/dist/trace/html-template.js +150 -0
- package/dist/trace/html.d.ts +104 -0
- package/dist/trace/html.js +292 -0
- package/dist/trace/preview.d.ts +29 -0
- package/dist/trace/preview.js +59 -0
- package/dist/trace/query-session.d.ts +14 -0
- package/dist/trace/query-session.js +38 -0
- package/dist/trace/query.d.ts +55 -0
- package/dist/trace/query.js +188 -0
- package/dist/trace/session.d.ts +40 -0
- package/dist/trace/session.js +168 -0
- package/dist/trace/types.d.ts +243 -0
- package/dist/trace/types.js +13 -0
- package/dist/tui/components/editor-paste.d.ts +2 -0
- package/dist/tui/components/editor-paste.js +6 -3
- package/dist/tui/components/editor.js +2 -2
- package/dist/tui/components/loader.d.ts +3 -0
- package/dist/tui/components/loader.js +14 -0
- package/dist/tui/components/select-list.d.ts +2 -0
- package/dist/tui/components/select-list.js +7 -0
- package/dist/tui/components/settings-list.d.ts +61 -0
- package/dist/tui/components/settings-list.js +135 -0
- package/dist/tui/keybindings.d.ts +5 -0
- package/dist/tui/keybindings.js +17 -5
- package/dist/tui.d.ts +1 -0
- package/dist/tui.js +2 -0
- package/docs/en/host-api.md +167 -0
- package/docs/en/permissions.md +214 -0
- package/docs/en/providers.md +627 -0
- package/docs/en/rpc.md +361 -0
- package/docs/en/sessions.md +219 -0
- package/docs/en/tui.md +534 -0
- package/docs/host-api.md +18 -17
- package/docs/memory.md +172 -0
- package/docs/permissions.md +2 -2
- package/docs/providers.md +73 -1
- package/docs/rpc.md +31 -3
- package/docs/session-format.md +8 -2
- package/docs/sessions.md +29 -1
- package/docs/tui.md +140 -4
- package/package.json +8 -3
|
@@ -57,6 +57,8 @@ export class ProviderRegistry {
|
|
|
57
57
|
envBaseUrls = new Map();
|
|
58
58
|
/** baseUrl 指向非官方主机的内置供应商:接受目录外的 model id。 */
|
|
59
59
|
relayed = new Set();
|
|
60
|
+
/** 模型表只来自发现缓存的供应商:表外的 id 照样合成(与空表相同)。 */
|
|
61
|
+
openTables = new Set();
|
|
60
62
|
/** config 里写了自己 `channels` 的供应商(内置渠道不因改 baseUrl 作废)。 */
|
|
61
63
|
userChannels = new Set();
|
|
62
64
|
/** config 里写了供应商级 `api` 的供应商(单渠道回落时目录模型跟它走)。 */
|
|
@@ -344,6 +346,8 @@ export class ProviderRegistry {
|
|
|
344
346
|
const provider = this.providers.get(providerId);
|
|
345
347
|
if (!provider)
|
|
346
348
|
return;
|
|
349
|
+
if (source === "discovered" && provider.models.length === 0 && provider.requiresApiKey)
|
|
350
|
+
this.openTables.add(providerId);
|
|
347
351
|
for (const raw of models) {
|
|
348
352
|
this.raw.delete(`${providerId}/${raw.id}`);
|
|
349
353
|
const model = this.materialize(provider, { ...raw, provider: providerId });
|
|
@@ -408,7 +412,8 @@ export class ProviderRegistry {
|
|
|
408
412
|
const model = provider.models.find((m) => m.id === id);
|
|
409
413
|
if (model)
|
|
410
414
|
return { ok: true, model, provider };
|
|
411
|
-
const
|
|
415
|
+
const open = this.relayed.has(provider.id) || this.openTables.has(provider.id);
|
|
416
|
+
const relayed = provider.models.length === 0 || open;
|
|
412
417
|
if (synthesize && relayed && id.length > 0) {
|
|
413
418
|
const synthesized = this.synthesize(provider, id);
|
|
414
419
|
if (channel !== undefined && provider.channels?.some((c) => c.name === channel))
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* 候选排序:包含关系(`sonnet` ⊂ `claude-sonnet-5`)优先,其次按编辑距离;距离超过
|
|
5
5
|
* `max(2, ⌈长度 / 3⌉)` 的不算接近。只比较 id 本身(不含 `provider/` 前缀),大小写不敏感。
|
|
6
6
|
*/
|
|
7
|
+
import { msg } from "../../i18n/index.js";
|
|
7
8
|
/** Levenshtein 距离(插入 / 删除 / 替换各计 1)。 */
|
|
8
9
|
export function editDistance(a, b) {
|
|
9
10
|
if (a === b)
|
|
@@ -53,20 +54,5 @@ export function closest(needle, candidates, limit = 5, key = String) {
|
|
|
53
54
|
/** 解析失败的一行说明(不含前缀标签):`渠道不存在:x;该模型可用渠道:…` 等。 */
|
|
54
55
|
export function describeLookupFailure(ref, failure) {
|
|
55
56
|
const list = failure.candidates.slice(0, 20).join(", ");
|
|
56
|
-
|
|
57
|
-
case "channel_not_found":
|
|
58
|
-
return failure.candidates.length > 0
|
|
59
|
-
? `渠道不存在:${ref};该模型可用渠道:${list}`
|
|
60
|
-
: `渠道不存在:${ref};该模型没有可选渠道(去掉 @ 后缀)`;
|
|
61
|
-
case "provider_not_found":
|
|
62
|
-
return failure.candidates.length > 0
|
|
63
|
-
? `供应商不存在:${ref};最接近的供应商:${list}`
|
|
64
|
-
: `供应商不存在:${ref}(ama providers list 查看已配置的供应商)`;
|
|
65
|
-
case "ambiguous":
|
|
66
|
-
return `模型名有歧义:${ref};候选:${list}`;
|
|
67
|
-
default:
|
|
68
|
-
return failure.candidates.length > 0
|
|
69
|
-
? `模型不存在:${ref};最接近的模型:${list}`
|
|
70
|
-
: `模型不存在:${ref}(ama models list 查看可用模型)`;
|
|
71
|
-
}
|
|
57
|
+
return msg().errors.models.lookupFailure(ref, failure.reason, list, failure.candidates.length > 0);
|
|
72
58
|
}
|
package/dist/ai/types.d.ts
CHANGED
|
@@ -115,6 +115,8 @@ export interface Usage {
|
|
|
115
115
|
* 协议尚未解析该标记时缺省(第三波 §1.6,「值为 0」与「不报」由此区分)。
|
|
116
116
|
*/
|
|
117
117
|
cacheReported?: boolean;
|
|
118
|
+
/** [W6-C0] 订阅计费(ChatGPT 登录,W6-O):`cost` 为 0,统计单列「订阅」不折算美元。 */
|
|
119
|
+
billing?: "subscription";
|
|
118
120
|
}
|
|
119
121
|
export type StopReason = "stop" | "length" | "toolUse" | "aborted" | "error";
|
|
120
122
|
/** 工具声明(发给供应商的形状)。 */
|
|
@@ -230,6 +232,12 @@ export interface OpenAIResponsesCompat {
|
|
|
230
232
|
supportsStore: boolean;
|
|
231
233
|
/** [W5-C0] 端点私有的显式缓存字段:`volcengine` = 火山方舟 `caching: { type: "enabled" }`。 */
|
|
232
234
|
explicitCacheField?: "volcengine";
|
|
235
|
+
/** [W6-C0] ChatGPT 订阅后端(W6-O):决定请求体白名单、请求头与配额解析。 */
|
|
236
|
+
chatgptBackend?: "siwc" | "codex";
|
|
237
|
+
/** [W6-C0] 系统提示的放法:native(`instructions`)/ developer-message(codex flavor 400 回退)。 */
|
|
238
|
+
instructionsMode?: "native" | "developer-message";
|
|
239
|
+
/** [W6-C0] 工具放进 namespace(SIWC 待实测)。 */
|
|
240
|
+
toolsInNamespace?: boolean;
|
|
233
241
|
}
|
|
234
242
|
/**
|
|
235
243
|
* [W3-C0] 供应商不报缓存时的处理(第三波 §1.6):`auto` 按响应自动判定三态;`silent` /
|
|
@@ -390,6 +398,23 @@ export interface StreamOptions {
|
|
|
390
398
|
/** 观测 / 替换请求体:返回非 undefined 即替换。 */
|
|
391
399
|
onPayload?(payload: unknown): unknown;
|
|
392
400
|
onResponse?(status: number, headers: Headers): void;
|
|
401
|
+
/**
|
|
402
|
+
* [W6-O] 订阅配额更新(ChatGPT 后端的响应头 / `codex.rate_limits` / 429);会话层转成 `quota_update` 事件。
|
|
403
|
+
* 窗口时间为 epoch 毫秒,usedPercent 0–100。
|
|
404
|
+
*/
|
|
405
|
+
onQuota?(update: {
|
|
406
|
+
planType?: string;
|
|
407
|
+
primary?: {
|
|
408
|
+
usedPercent: number;
|
|
409
|
+
resetsAt?: number;
|
|
410
|
+
windowMinutes?: number;
|
|
411
|
+
};
|
|
412
|
+
secondary?: {
|
|
413
|
+
usedPercent: number;
|
|
414
|
+
resetsAt?: number;
|
|
415
|
+
windowMinutes?: number;
|
|
416
|
+
};
|
|
417
|
+
}): void;
|
|
393
418
|
}
|
|
394
419
|
export type AssistantEvent = {
|
|
395
420
|
type: "start";
|
|
@@ -452,7 +477,8 @@ export interface ApiImplementation<C = unknown> {
|
|
|
452
477
|
/** 推断缺省 compat。 */
|
|
453
478
|
detectCompat?(model: Model, provider: ProviderData): C;
|
|
454
479
|
}
|
|
455
|
-
|
|
480
|
+
/** [W6-C0] `oauth`:auth.json 的 OAuth 条目(W6-O)。 */
|
|
481
|
+
export type KeySource = "cli" | "auth-file" | "config" | "env" | "oauth" | "none";
|
|
456
482
|
/** 密钥只存在于 `apiKey` 字段,不进日志、会话、事件。 */
|
|
457
483
|
export interface ApiKeyResolution {
|
|
458
484
|
apiKey: string | undefined;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChatGPT 后端的只读查询([W6-O]):模型列表(`ama models discover chatgpt`)与 codex 的 `wham/usage`。
|
|
3
|
+
*
|
|
4
|
+
* - SIWC:`GET {base}/models`,只留 `visibility === "list"`(没有该字段的也留);
|
|
5
|
+
* - codex:`GET {base}/models?client_version=<ama 版本>`,`models[].slug`(同样按 visibility 筛);
|
|
6
|
+
* `GET https://chatgpt.com/backend-api/wham/usage`(由 codex base 推出),私有格式,解析失败返回 undefined。
|
|
7
|
+
* 只取 slug 与显示名,上下文窗口不猜。请求带 Bearer;codex 另带 `ChatGPT-Account-ID` 与 `originator`。
|
|
8
|
+
*/
|
|
9
|
+
import { type QuotaSnapshot } from "../../ai/apis/chatgpt-rate-limits.js";
|
|
10
|
+
import type { ChatGptFlavor } from "../../config/types-w6.js";
|
|
11
|
+
import type { FetchLike } from "../oauth/token-client.js";
|
|
12
|
+
export declare const BACKEND_TIMEOUT_MS = 15000;
|
|
13
|
+
export interface BackendAuth {
|
|
14
|
+
flavor: ChatGptFlavor;
|
|
15
|
+
accessToken: string;
|
|
16
|
+
accountId?: string | undefined;
|
|
17
|
+
originator?: string | undefined;
|
|
18
|
+
}
|
|
19
|
+
export interface DiscoveredModel {
|
|
20
|
+
id: string;
|
|
21
|
+
name?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function listChatGptModels(fetchFn: FetchLike, baseUrl: string, auth: BackendAuth): Promise<DiscoveredModel[]>;
|
|
24
|
+
export declare function usageUrl(codexBaseUrl: string): string;
|
|
25
|
+
/** codex 的配额;任何失败返回 undefined。 */
|
|
26
|
+
export declare function fetchCodexUsage(fetchFn: FetchLike, codexBaseUrl: string, auth: BackendAuth, timeoutMs?: number): Promise<QuotaSnapshot | undefined>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChatGPT 后端的只读查询([W6-O]):模型列表(`ama models discover chatgpt`)与 codex 的 `wham/usage`。
|
|
3
|
+
*
|
|
4
|
+
* - SIWC:`GET {base}/models`,只留 `visibility === "list"`(没有该字段的也留);
|
|
5
|
+
* - codex:`GET {base}/models?client_version=<ama 版本>`,`models[].slug`(同样按 visibility 筛);
|
|
6
|
+
* `GET https://chatgpt.com/backend-api/wham/usage`(由 codex base 推出),私有格式,解析失败返回 undefined。
|
|
7
|
+
* 只取 slug 与显示名,上下文窗口不猜。请求带 Bearer;codex 另带 `ChatGPT-Account-ID` 与 `originator`。
|
|
8
|
+
*/
|
|
9
|
+
import { parseUsagePayload } from "../../ai/apis/chatgpt-rate-limits.js";
|
|
10
|
+
import { AMA_VERSION } from "../../version.js";
|
|
11
|
+
import { DEFAULT_ORIGINATOR } from "./presets.js";
|
|
12
|
+
export const BACKEND_TIMEOUT_MS = 15_000;
|
|
13
|
+
function headers(auth) {
|
|
14
|
+
const out = {
|
|
15
|
+
authorization: `Bearer ${auth.accessToken}`,
|
|
16
|
+
accept: "application/json",
|
|
17
|
+
};
|
|
18
|
+
if (auth.flavor === "codex") {
|
|
19
|
+
if (auth.accountId !== undefined)
|
|
20
|
+
out["ChatGPT-Account-ID"] = auth.accountId;
|
|
21
|
+
out["originator"] = auth.originator ?? DEFAULT_ORIGINATOR;
|
|
22
|
+
}
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
function listed(item) {
|
|
26
|
+
const visibility = item["visibility"];
|
|
27
|
+
return visibility === undefined || visibility === "list";
|
|
28
|
+
}
|
|
29
|
+
export async function listChatGptModels(fetchFn, baseUrl, auth) {
|
|
30
|
+
const base = baseUrl.replace(/\/+$/, "");
|
|
31
|
+
const url = auth.flavor === "codex"
|
|
32
|
+
? `${base}/models?client_version=${encodeURIComponent(AMA_VERSION)}`
|
|
33
|
+
: `${base}/models`;
|
|
34
|
+
const response = await fetchFn(url, {
|
|
35
|
+
headers: headers(auth),
|
|
36
|
+
signal: AbortSignal.timeout(BACKEND_TIMEOUT_MS),
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok)
|
|
39
|
+
throw new Error(`${response.status} listing models from ${url}`);
|
|
40
|
+
const body = (await response.json());
|
|
41
|
+
const items = (Array.isArray(body.models) ? body.models : Array.isArray(body.data) ? body.data : [])
|
|
42
|
+
.filter((x) => typeof x === "object" && x !== null)
|
|
43
|
+
.filter(listed);
|
|
44
|
+
const out = [];
|
|
45
|
+
const seen = new Set();
|
|
46
|
+
for (const item of items) {
|
|
47
|
+
const id = item["slug"] ?? item["id"];
|
|
48
|
+
if (typeof id !== "string" || id === "" || seen.has(id))
|
|
49
|
+
continue;
|
|
50
|
+
seen.add(id);
|
|
51
|
+
const name = item["display_name"];
|
|
52
|
+
out.push(typeof name === "string" && name !== "" ? { id, name } : { id });
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
export function usageUrl(codexBaseUrl) {
|
|
57
|
+
const base = codexBaseUrl.replace(/\/+$/, "").replace(/\/codex$/, "");
|
|
58
|
+
return `${base}/wham/usage`;
|
|
59
|
+
}
|
|
60
|
+
/** codex 的配额;任何失败返回 undefined。 */
|
|
61
|
+
export async function fetchCodexUsage(fetchFn, codexBaseUrl, auth, timeoutMs = 5_000) {
|
|
62
|
+
try {
|
|
63
|
+
const response = await fetchFn(usageUrl(codexBaseUrl), {
|
|
64
|
+
headers: headers(auth),
|
|
65
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
66
|
+
});
|
|
67
|
+
if (!response.ok)
|
|
68
|
+
return undefined;
|
|
69
|
+
return parseUsagePayload(await response.json());
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* id_token 声明里的账户信息(R6 §1.2 账户 id 行)。[W6-O]
|
|
3
|
+
*
|
|
4
|
+
* codex:`https://api.openai.com/auth` 下的 `chatgpt_account_id` / `chatgpt_plan_type`;SIWC:以验签后的
|
|
5
|
+
* `sub` 作账户标识(官方文档),计划类型若有同样取 auth 声明。邮箱取 `email` 或 profile 声明。
|
|
6
|
+
*/
|
|
7
|
+
import type { JwtPayload } from "../oauth/jwt.js";
|
|
8
|
+
export interface ChatGptAccount {
|
|
9
|
+
accountId?: string;
|
|
10
|
+
planType?: string;
|
|
11
|
+
email?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function chatgptAccount(claims: JwtPayload | undefined, flavor: "siwc" | "codex"): ChatGptAccount;
|
|
14
|
+
/** 空格分隔的 scope 是否含 `required`。 */
|
|
15
|
+
export declare function hasScope(scope: string | undefined, required: string): boolean;
|
|
16
|
+
/** `a***@example.com`:status / doctor 用。 */
|
|
17
|
+
export declare function maskEmail(email: string | undefined): string | undefined;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* id_token 声明里的账户信息(R6 §1.2 账户 id 行)。[W6-O]
|
|
3
|
+
*
|
|
4
|
+
* codex:`https://api.openai.com/auth` 下的 `chatgpt_account_id` / `chatgpt_plan_type`;SIWC:以验签后的
|
|
5
|
+
* `sub` 作账户标识(官方文档),计划类型若有同样取 auth 声明。邮箱取 `email` 或 profile 声明。
|
|
6
|
+
*/
|
|
7
|
+
function obj(value) {
|
|
8
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
9
|
+
? value
|
|
10
|
+
: undefined;
|
|
11
|
+
}
|
|
12
|
+
function str(value) {
|
|
13
|
+
return typeof value === "string" && value !== "" ? value : undefined;
|
|
14
|
+
}
|
|
15
|
+
export function chatgptAccount(claims, flavor) {
|
|
16
|
+
if (claims === undefined)
|
|
17
|
+
return {};
|
|
18
|
+
const auth = obj(claims["https://api.openai.com/auth"]);
|
|
19
|
+
const profile = obj(claims["https://api.openai.com/profile"]);
|
|
20
|
+
const out = {};
|
|
21
|
+
const accountId = flavor === "codex"
|
|
22
|
+
? (str(auth?.["chatgpt_account_id"]) ?? str(claims["chatgpt_account_id"]))
|
|
23
|
+
: (str(claims["sub"]) ?? str(auth?.["chatgpt_account_id"]));
|
|
24
|
+
if (accountId !== undefined)
|
|
25
|
+
out.accountId = accountId;
|
|
26
|
+
const plan = str(auth?.["chatgpt_plan_type"]) ?? str(claims["chatgpt_plan_type"]);
|
|
27
|
+
if (plan !== undefined)
|
|
28
|
+
out.planType = plan;
|
|
29
|
+
const email = str(claims["email"]) ?? str(profile?.["email"]);
|
|
30
|
+
if (email !== undefined)
|
|
31
|
+
out.email = email;
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
/** 空格分隔的 scope 是否含 `required`。 */
|
|
35
|
+
export function hasScope(scope, required) {
|
|
36
|
+
return (scope ?? "").split(/[\s+]+/).includes(required);
|
|
37
|
+
}
|
|
38
|
+
/** `a***@example.com`:status / doctor 用。 */
|
|
39
|
+
export function maskEmail(email) {
|
|
40
|
+
if (email === undefined)
|
|
41
|
+
return undefined;
|
|
42
|
+
const at = email.indexOf("@");
|
|
43
|
+
if (at <= 0)
|
|
44
|
+
return "***";
|
|
45
|
+
return `${email.slice(0, 1)}***${email.slice(at)}`;
|
|
46
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ama auth login | logout | status chatgpt`(docs/wave6-plan.md §4.2、D16)。[W6-O]
|
|
3
|
+
*
|
|
4
|
+
* - login:flavor 取 `--flavor` > 用户级 `auth.chatgpt.flavor` > siwc;`--paste` / `--device`(只 codex)/ 缺省
|
|
5
|
+
* 浏览器;codex 首次在 TTY 下一次性确认「非官方、仅个人使用」(非 TTY 需 `--yes`),`acknowledgedAt` 入条目;
|
|
6
|
+
* 成功后在刷新锁下写 auth.json(0600)。
|
|
7
|
+
* 成功后查一次模型列表写发现缓存(`<dataDir>/models/discovered/chatgpt.json`,失败静默)。
|
|
8
|
+
* - logout:SIWC 先撤销 refresh token(失败照样删本地,提示到 ChatGPT 设置里断开);codex 只删本地;
|
|
9
|
+
* 同时删发现缓存。
|
|
10
|
+
* - status:flavor、计划、掩码邮箱、access token 剩余、needsLogin;codex 另查 `wham/usage` 显示配额。
|
|
11
|
+
*
|
|
12
|
+
* 输出里从不出现 token、code、账户 id;错误按码渲染(i18n),不回显响应原文。
|
|
13
|
+
*/
|
|
14
|
+
import { type ChatGptFlavor } from "../../config/types-w6.js";
|
|
15
|
+
import type { CliIo } from "../../cli/deps.js";
|
|
16
|
+
import { type BrowserOpener } from "../oauth/browser.js";
|
|
17
|
+
import type { FetchLike } from "../oauth/token-client.js";
|
|
18
|
+
export interface AuthCliDeps {
|
|
19
|
+
fetch?: FetchLike;
|
|
20
|
+
openBrowser?: BrowserOpener;
|
|
21
|
+
now?: () => number;
|
|
22
|
+
/** `--paste` 读回调 URL;缺省 `io.readStdin`(TTY 下一行不回显)。 */
|
|
23
|
+
readLine?: () => Promise<string>;
|
|
24
|
+
}
|
|
25
|
+
export interface AuthCliArgs {
|
|
26
|
+
positionals: string[];
|
|
27
|
+
values: Map<string, string>;
|
|
28
|
+
flags: Set<string>;
|
|
29
|
+
path: string;
|
|
30
|
+
}
|
|
31
|
+
/** AmaError → 本地化的一行(不含响应原文)。 */
|
|
32
|
+
export declare function loginErrorText(error: unknown, flavor: ChatGptFlavor): string;
|
|
33
|
+
export declare function runLogin(args: AuthCliArgs, io: CliIo, deps?: AuthCliDeps): Promise<number>;
|
|
34
|
+
export declare function runLogout(args: AuthCliArgs, io: CliIo, deps?: AuthCliDeps): Promise<number>;
|
|
35
|
+
export declare function runStatus(args: AuthCliArgs, io: CliIo, deps?: AuthCliDeps): Promise<number>;
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ama auth login | logout | status chatgpt`(docs/wave6-plan.md §4.2、D16)。[W6-O]
|
|
3
|
+
*
|
|
4
|
+
* - login:flavor 取 `--flavor` > 用户级 `auth.chatgpt.flavor` > siwc;`--paste` / `--device`(只 codex)/ 缺省
|
|
5
|
+
* 浏览器;codex 首次在 TTY 下一次性确认「非官方、仅个人使用」(非 TTY 需 `--yes`),`acknowledgedAt` 入条目;
|
|
6
|
+
* 成功后在刷新锁下写 auth.json(0600)。
|
|
7
|
+
* 成功后查一次模型列表写发现缓存(`<dataDir>/models/discovered/chatgpt.json`,失败静默)。
|
|
8
|
+
* - logout:SIWC 先撤销 refresh token(失败照样删本地,提示到 ChatGPT 设置里断开);codex 只删本地;
|
|
9
|
+
* 同时删发现缓存。
|
|
10
|
+
* - status:flavor、计划、掩码邮箱、access token 剩余、needsLogin;codex 另查 `wham/usage` 显示配额。
|
|
11
|
+
*
|
|
12
|
+
* 输出里从不出现 token、code、账户 id;错误按码渲染(i18n),不回显响应原文。
|
|
13
|
+
*/
|
|
14
|
+
import { isAmaError } from "../../errors.js";
|
|
15
|
+
import { describeAuthFile, readAuthFile } from "../../config/auth-file.js";
|
|
16
|
+
import { loadConfigFile } from "../../config/load.js";
|
|
17
|
+
import { CONFIG_FILE, resolveConfigDir, resolveDataDir } from "../../config/paths.js";
|
|
18
|
+
import { CHATGPT_FLAVORS, isOAuthEntry, } from "../../config/types-w6.js";
|
|
19
|
+
import { formatDuration, msg } from "../../i18n/index.js";
|
|
20
|
+
import { UsageError } from "../../cli/args.js";
|
|
21
|
+
import { ExitCode } from "../../cli/exit-codes.js";
|
|
22
|
+
import { openBrowser } from "../oauth/browser.js";
|
|
23
|
+
import { readOAuthEntry, withRefreshLock, writeOAuthEntry } from "../oauth/token-store.js";
|
|
24
|
+
import { clearDiscoveredCache, writeDiscoveredCache } from "../../ai/providers/discovered-cache.js";
|
|
25
|
+
import { fetchCodexUsage, listChatGptModels } from "./backend-client.js";
|
|
26
|
+
import { maskEmail } from "./claims.js";
|
|
27
|
+
import { loginChatGpt, revokeChatGpt } from "./login.js";
|
|
28
|
+
import { CHATGPT_PROVIDER_ID, chatgptBaseUrl } from "./presets.js";
|
|
29
|
+
import { quotaParts } from "./quota-text.js";
|
|
30
|
+
function userAuthConfig(io) {
|
|
31
|
+
try {
|
|
32
|
+
const path = `${resolveConfigDir({ env: io.env })}/${CONFIG_FILE}`;
|
|
33
|
+
return loadConfigFile("config", path)?.value.auth?.chatgpt;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function providerOf(args, action) {
|
|
40
|
+
const provider = args.positionals[1];
|
|
41
|
+
if (provider === undefined)
|
|
42
|
+
throw new UsageError(msg().auth.needProvider(action));
|
|
43
|
+
if (args.positionals.length > 2)
|
|
44
|
+
throw new UsageError(msg().auth.extraArgs(args.positionals.slice(2).join(" ")));
|
|
45
|
+
if (provider !== CHATGPT_PROVIDER_ID)
|
|
46
|
+
throw new UsageError(msg().auth.login.onlyChatgpt(provider));
|
|
47
|
+
return provider;
|
|
48
|
+
}
|
|
49
|
+
/** AmaError → 本地化的一行(不含响应原文)。 */
|
|
50
|
+
export function loginErrorText(error, flavor) {
|
|
51
|
+
const m = msg().auth.errors;
|
|
52
|
+
if (!isAmaError(error))
|
|
53
|
+
return error?.message ?? String(error);
|
|
54
|
+
const detail = (error.detail ?? {});
|
|
55
|
+
switch (error.code) {
|
|
56
|
+
case "oauth_ports_busy":
|
|
57
|
+
return m.portsBusy((detail.ports ?? []).join(" / "), flavor === "codex");
|
|
58
|
+
case "oauth_timeout":
|
|
59
|
+
return m.timeout;
|
|
60
|
+
case "oauth_denied":
|
|
61
|
+
return m.denied(detail.error ?? "error", flavor === "siwc");
|
|
62
|
+
case "oauth_state_mismatch":
|
|
63
|
+
return m.stateMismatch;
|
|
64
|
+
case "oauth_no_code":
|
|
65
|
+
return m.noCode;
|
|
66
|
+
case "oauth_invalid_token":
|
|
67
|
+
return m.invalidToken(detail.reason ?? "invalid");
|
|
68
|
+
case "oauth_scope_missing":
|
|
69
|
+
return m.scopeMissing(detail.scope ?? "chatgpt.tokens.use.direct");
|
|
70
|
+
case "oauth_no_client_id":
|
|
71
|
+
return m.noClientId;
|
|
72
|
+
case "oauth_no_account":
|
|
73
|
+
return m.noAccount;
|
|
74
|
+
case "oauth_device_unavailable":
|
|
75
|
+
return m.deviceUnavailable;
|
|
76
|
+
case "oauth_device_unsupported":
|
|
77
|
+
return msg().auth.login.deviceNeedsCodex;
|
|
78
|
+
case "oauth_http":
|
|
79
|
+
case "oauth_bad_response":
|
|
80
|
+
return m.http(error.message);
|
|
81
|
+
case "oauth_network":
|
|
82
|
+
return m.network(error.message);
|
|
83
|
+
case "auth_lock_timeout":
|
|
84
|
+
return m.lockTimeout;
|
|
85
|
+
case "aborted":
|
|
86
|
+
return m.aborted;
|
|
87
|
+
default:
|
|
88
|
+
return error.message;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function parseFlavor(raw, config) {
|
|
92
|
+
const value = raw ?? config?.flavor ?? "siwc";
|
|
93
|
+
if (!CHATGPT_FLAVORS.includes(value))
|
|
94
|
+
throw new UsageError(msg().auth.login.badFlavor(value));
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
function parsePort(raw) {
|
|
98
|
+
if (raw === undefined)
|
|
99
|
+
return undefined;
|
|
100
|
+
const port = Number(raw);
|
|
101
|
+
if (!Number.isInteger(port) || port < 0 || port > 65_535)
|
|
102
|
+
throw new UsageError(msg().auth.login.badPort(raw));
|
|
103
|
+
return port;
|
|
104
|
+
}
|
|
105
|
+
/** 确认输入两种语言都认(y / yes / 是 / 好),与界面语言无关。 */
|
|
106
|
+
function isYes(answer) {
|
|
107
|
+
return /^\s*(y|yes|\u662f|\u597d)\s*$/i.test(answer);
|
|
108
|
+
}
|
|
109
|
+
export async function runLogin(args, io, deps = {}) {
|
|
110
|
+
const m = msg().auth.login;
|
|
111
|
+
const provider = providerOf(args, "login");
|
|
112
|
+
const config = userAuthConfig(io);
|
|
113
|
+
const flavor = parseFlavor(args.values.get("flavor"), config);
|
|
114
|
+
const port = parsePort(args.values.get("port"));
|
|
115
|
+
if (args.flags.has("paste") && args.flags.has("device"))
|
|
116
|
+
throw new UsageError(m.pasteDevice);
|
|
117
|
+
const method = args.flags.has("device")
|
|
118
|
+
? "device"
|
|
119
|
+
: args.flags.has("paste")
|
|
120
|
+
? "paste"
|
|
121
|
+
: "browser";
|
|
122
|
+
if (method === "device" && flavor !== "codex")
|
|
123
|
+
throw new UsageError(m.deviceNeedsCodex);
|
|
124
|
+
const existing = readOAuthEntry(args.path, provider);
|
|
125
|
+
let acknowledgedAt;
|
|
126
|
+
if (flavor === "codex") {
|
|
127
|
+
acknowledgedAt = existing?.flavor === "codex" ? existing.acknowledgedAt : undefined;
|
|
128
|
+
if (acknowledgedAt === undefined) {
|
|
129
|
+
io.stderr(`${m.codexNotice}\n`);
|
|
130
|
+
if (!args.flags.has("yes")) {
|
|
131
|
+
if (!io.stdinIsTTY) {
|
|
132
|
+
io.stderr(`ama: ${m.codexNeedsYes}\n`);
|
|
133
|
+
return ExitCode.Usage;
|
|
134
|
+
}
|
|
135
|
+
io.stderr(m.codexConfirm);
|
|
136
|
+
const answer = await io.readStdin();
|
|
137
|
+
io.stderr("\n");
|
|
138
|
+
if (!isYes(answer)) {
|
|
139
|
+
io.stderr(`ama: ${m.cancelled}\n`);
|
|
140
|
+
return ExitCode.RuntimeError;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
acknowledgedAt = new Date((deps.now ?? Date.now)()).toISOString();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const onStep = (step) => {
|
|
147
|
+
if (step.kind === "open_url")
|
|
148
|
+
io.stderr(`${step.opened ? m.openedBrowser(step.url) : m.openUrl(step.url)}\n`);
|
|
149
|
+
else if (step.kind === "paste_prompt")
|
|
150
|
+
io.stderr(m.pastePrompt(step.url));
|
|
151
|
+
else
|
|
152
|
+
io.stderr(`${m.deviceCode(step.url, step.userCode)}\n`);
|
|
153
|
+
};
|
|
154
|
+
let entry;
|
|
155
|
+
try {
|
|
156
|
+
entry = await loginChatGpt({
|
|
157
|
+
flavor,
|
|
158
|
+
method,
|
|
159
|
+
noBrowser: args.flags.has("no-browser"),
|
|
160
|
+
dataDir: resolveDataDir({ env: io.env }),
|
|
161
|
+
env: io.env,
|
|
162
|
+
config,
|
|
163
|
+
entry: existing,
|
|
164
|
+
port,
|
|
165
|
+
acknowledgedAt,
|
|
166
|
+
deps: {
|
|
167
|
+
fetch: deps.fetch ?? fetch,
|
|
168
|
+
openBrowser: deps.openBrowser ?? openBrowser,
|
|
169
|
+
onStep,
|
|
170
|
+
readLine: async () => {
|
|
171
|
+
const line = await (deps.readLine ?? (() => io.readStdin()))();
|
|
172
|
+
if (io.stdinIsTTY)
|
|
173
|
+
io.stderr("\n");
|
|
174
|
+
return line;
|
|
175
|
+
},
|
|
176
|
+
pages: { success: m.pageSuccess, failure: m.pageFailure },
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
await withRefreshLock(args.path, async () => writeOAuthEntry(args.path, provider, entry));
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
io.stderr(`ama: ${loginErrorText(error, flavor)}\n`);
|
|
183
|
+
return ExitCode.RuntimeError;
|
|
184
|
+
}
|
|
185
|
+
io.stdout(`${m.loggedIn(flavor, entry.planType, maskEmail(entry.email), args.path)}\n`);
|
|
186
|
+
if (entry.planType === "free")
|
|
187
|
+
io.stdout(`${m.freePlanHint(entry.planType)}\n`);
|
|
188
|
+
if (flavor === "siwc")
|
|
189
|
+
io.stdout(`${m.siwcLimitHint}\n`);
|
|
190
|
+
const count = await cacheModels(io, entry, config, deps);
|
|
191
|
+
io.stdout(`${count === undefined ? m.modelHint : m.modelsCached(count)}\n`);
|
|
192
|
+
return ExitCode.Ok;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* 登录后查一次账户可用的模型(只读的模型列表接口,不消耗额度)并写发现缓存,`/model` 由此列出;
|
|
196
|
+
* 任何失败静默(返回 undefined,调用方改提示 `ama models discover chatgpt`)。
|
|
197
|
+
*/
|
|
198
|
+
async function cacheModels(io, entry, config, deps) {
|
|
199
|
+
try {
|
|
200
|
+
const models = await listChatGptModels(deps.fetch ?? fetch, chatgptBaseUrl(entry.flavor, io.env), {
|
|
201
|
+
flavor: entry.flavor,
|
|
202
|
+
accessToken: entry.accessToken,
|
|
203
|
+
accountId: entry.accountId,
|
|
204
|
+
originator: config?.originator,
|
|
205
|
+
});
|
|
206
|
+
if (models.length === 0)
|
|
207
|
+
return undefined;
|
|
208
|
+
const dataDir = resolveDataDir({ env: io.env });
|
|
209
|
+
writeDiscoveredCache(dataDir, CHATGPT_PROVIDER_ID, { models, flavor: entry.flavor });
|
|
210
|
+
return models.length;
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
export async function runLogout(args, io, deps = {}) {
|
|
217
|
+
const m = msg().auth.logout;
|
|
218
|
+
const provider = providerOf(args, "logout");
|
|
219
|
+
const entry = readOAuthEntry(args.path, provider);
|
|
220
|
+
if (entry === undefined) {
|
|
221
|
+
io.stderr(`${m.notLoggedIn(provider, args.path)}\n`);
|
|
222
|
+
return ExitCode.RuntimeError;
|
|
223
|
+
}
|
|
224
|
+
const revoked = entry.flavor === "siwc"
|
|
225
|
+
? await revokeChatGpt(deps.fetch ?? fetch, entry, { env: io.env, config: userAuthConfig(io) })
|
|
226
|
+
: undefined;
|
|
227
|
+
try {
|
|
228
|
+
await withRefreshLock(args.path, async () => writeOAuthEntry(args.path, provider, undefined));
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
io.stderr(`ama: ${loginErrorText(error, entry.flavor)}\n`);
|
|
232
|
+
return ExitCode.RuntimeError;
|
|
233
|
+
}
|
|
234
|
+
clearDiscoveredCache(resolveDataDir({ env: io.env }), provider);
|
|
235
|
+
const text = revoked === undefined
|
|
236
|
+
? m.local(provider, args.path)
|
|
237
|
+
: revoked
|
|
238
|
+
? m.revoked(provider, args.path)
|
|
239
|
+
: m.notRevoked(provider, args.path);
|
|
240
|
+
io.stdout(`${text}\n`);
|
|
241
|
+
return ExitCode.Ok;
|
|
242
|
+
}
|
|
243
|
+
export async function runStatus(args, io, deps = {}) {
|
|
244
|
+
const m = msg().auth.status;
|
|
245
|
+
if (args.positionals.length > 2)
|
|
246
|
+
throw new UsageError(msg().auth.extraArgs(args.positionals.slice(2).join(" ")));
|
|
247
|
+
const only = args.positionals[1];
|
|
248
|
+
const now = (deps.now ?? Date.now)();
|
|
249
|
+
const { file } = readAuthFile(args.path);
|
|
250
|
+
const entries = Object.entries(file.providers).filter((pair) => isOAuthEntry(pair[1]) && (only === undefined || pair[0] === only));
|
|
251
|
+
if (entries.length === 0) {
|
|
252
|
+
io.stdout(`${m.none(args.path)}\n`);
|
|
253
|
+
return ExitCode.Ok;
|
|
254
|
+
}
|
|
255
|
+
const summaries = new Map(describeAuthFile(file, now).map((s) => [s.provider, s]));
|
|
256
|
+
const config = userAuthConfig(io);
|
|
257
|
+
for (const [provider, entry] of entries) {
|
|
258
|
+
const summary = summaries.get(provider);
|
|
259
|
+
io.stdout(`${m.header(provider, msg().auth.oauthSummary(entry.flavor, entry.planType, entry.needsLogin === true), maskEmail(entry.email))}\n`);
|
|
260
|
+
const left = summary?.expiresIn ?? entry.expiresAt - now;
|
|
261
|
+
if (entry.needsLogin === true)
|
|
262
|
+
io.stdout(`${m.needsLogin(provider)}\n`);
|
|
263
|
+
else
|
|
264
|
+
io.stdout(`${left > 0 ? m.expiresIn(formatDuration(left)) : m.expired}\n`);
|
|
265
|
+
if (entry.flavor === "siwc")
|
|
266
|
+
io.stdout(`${m.quotaSiwc}\n`);
|
|
267
|
+
else if (entry.needsLogin !== true && left > 0) {
|
|
268
|
+
const quota = await fetchCodexUsage(deps.fetch ?? fetch, chatgptBaseUrl("codex", io.env), {
|
|
269
|
+
flavor: "codex",
|
|
270
|
+
accessToken: entry.accessToken,
|
|
271
|
+
accountId: entry.accountId,
|
|
272
|
+
originator: config?.originator,
|
|
273
|
+
});
|
|
274
|
+
const parts = quota === undefined ? undefined : quotaParts(quota, now);
|
|
275
|
+
io.stdout(`${parts === undefined ? m.quotaUnavailable : m.quota(parts)}\n`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return ExitCode.Ok;
|
|
279
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ama doctor` 的 OAuth 行([W6-O]):只读文件、不刷新 token;codex flavor 且 token 未过期时查一次
|
|
3
|
+
* `wham/usage`(3 s 超时,失败静默)显示配额,SIWC 只给查看位置。
|
|
4
|
+
*/
|
|
5
|
+
import type { ChatGptAuthConfig, OAuthAuthEntry } from "../../config/types-w6.js";
|
|
6
|
+
import type { FetchLike } from "../oauth/token-client.js";
|
|
7
|
+
export interface OAuthDoctorLines {
|
|
8
|
+
line: string;
|
|
9
|
+
quota?: string;
|
|
10
|
+
problem?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function oauthDoctorLines(provider: string, entry: OAuthAuthEntry, options?: {
|
|
13
|
+
now?: number;
|
|
14
|
+
fetch?: FetchLike;
|
|
15
|
+
env?: Readonly<Record<string, string | undefined>>;
|
|
16
|
+
config?: ChatGptAuthConfig | undefined;
|
|
17
|
+
}): Promise<OAuthDoctorLines>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ama doctor` 的 OAuth 行([W6-O]):只读文件、不刷新 token;codex flavor 且 token 未过期时查一次
|
|
3
|
+
* `wham/usage`(3 s 超时,失败静默)显示配额,SIWC 只给查看位置。
|
|
4
|
+
*/
|
|
5
|
+
import { formatDuration, msg } from "../../i18n/index.js";
|
|
6
|
+
import { fetchCodexUsage } from "./backend-client.js";
|
|
7
|
+
import { chatgptBaseUrl } from "./presets.js";
|
|
8
|
+
import { quotaParts } from "./quota-text.js";
|
|
9
|
+
export async function oauthDoctorLines(provider, entry, options = {}) {
|
|
10
|
+
const m = msg().auth;
|
|
11
|
+
const now = options.now ?? Date.now();
|
|
12
|
+
const left = entry.expiresAt - now;
|
|
13
|
+
const state = entry.needsLogin === true
|
|
14
|
+
? m.doctor.needsLogin
|
|
15
|
+
: left > 0
|
|
16
|
+
? m.doctor.valid(formatDuration(left))
|
|
17
|
+
: m.doctor.expired;
|
|
18
|
+
const out = { line: m.doctor.oauth(entry.flavor, entry.planType, state) };
|
|
19
|
+
if (entry.needsLogin === true) {
|
|
20
|
+
out.problem = m.doctor.relogin(provider);
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
if (entry.flavor === "siwc")
|
|
24
|
+
out.quota = m.status.quotaSiwc.trim();
|
|
25
|
+
else if (left > 0) {
|
|
26
|
+
const quota = await fetchCodexUsage(options.fetch ?? fetch, chatgptBaseUrl("codex", options.env), {
|
|
27
|
+
flavor: "codex",
|
|
28
|
+
accessToken: entry.accessToken,
|
|
29
|
+
accountId: entry.accountId,
|
|
30
|
+
originator: options.config?.originator,
|
|
31
|
+
}, 3_000);
|
|
32
|
+
const parts = quota === undefined ? undefined : quotaParts(quota, now);
|
|
33
|
+
out.quota = (parts === undefined ? m.status.quotaUnavailable : m.status.quota(parts)).trim();
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SIWC 的 `ext_agent_host_id`(docs/wave6-plan.md D16):每个安装稳定不变,存
|
|
3
|
+
* `<dataDir>/chatgpt-host.json`(0600,按安装、不随 dotfiles 同步),形如 `urn:uuid:…`。[W6-O]
|
|
4
|
+
*/
|
|
5
|
+
export declare const HOST_ID_FILE = "chatgpt-host.json";
|
|
6
|
+
export declare function hostIdPath(dataDir: string): string;
|
|
7
|
+
export declare function readOrCreateHostId(dataDir: string): string;
|