@armadra/agent 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +177 -304
- package/CHANGELOG.zh-CN.md +442 -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/enrich.js +2 -7
- 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/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 +33 -0
- package/dist/auth/chatgpt/cli.js +252 -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 +25928 -11144
- 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 +5 -0
- package/dist/cli/compose-providers.js +32 -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 +137 -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 +3 -0
- package/dist/cli/subcommands/models-discover.js +44 -21
- package/dist/cli/subcommands/models.d.ts +1 -1
- package/dist/cli/subcommands/models.js +29 -22
- 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 +101 -68
- 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 +3 -2
- 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 +78 -0
- package/dist/config/settings-registry.js +184 -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 +2169 -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 +187 -0
- package/dist/i18n/messages/auth.js +189 -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 +244 -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 +289 -0
- package/dist/i18n/messages/config-keys.js +292 -0
- package/dist/i18n/messages/config.d.ts +502 -0
- package/dist/i18n/messages/config.js +239 -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 +103 -0
- package/dist/i18n/messages/interactive-startup.js +104 -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 +493 -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 +190 -0
- package/dist/i18n/messages/panels.js +189 -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 +348 -0
- package/dist/i18n/messages/settings.js +336 -0
- package/dist/i18n/messages/subcommands-config.d.ts +111 -0
- package/dist/i18n/messages/subcommands-config.js +127 -0
- package/dist/i18n/messages/subcommands.d.ts +548 -0
- package/dist/i18n/messages/subcommands.js +474 -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 +19 -1
- package/dist/modes/interactive/commands.js +84 -40
- 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 +19 -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/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.js +38 -30
- 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/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 +625 -0
- package/docs/en/rpc.md +361 -0
- package/docs/en/sessions.md +219 -0
- package/docs/en/tui.md +527 -0
- package/docs/host-api.md +18 -17
- package/docs/memory.md +172 -0
- package/docs/permissions.md +2 -2
- package/docs/providers.md +67 -1
- package/docs/rpc.md +31 -3
- package/docs/session-format.md +8 -2
- package/docs/sessions.md +29 -1
- package/docs/tui.md +132 -3
- package/package.json +8 -3
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth 条目的存取与跨进程刷新锁(docs/wave6-plan.md §4.3、D15)。[W6-O]
|
|
3
|
+
*
|
|
4
|
+
* - 读:每次都从磁盘读(绕过 `ApiKeyResolver.fileCache`,长会话才能看到别的进程刷新后的 token);文件不存在 /
|
|
5
|
+
* 坏掉 / 不是 oauth 条目 → undefined;
|
|
6
|
+
* - 写:读-改-写 `auth.json` 整个文件,经 `writeAuthFile`(同目录临时文件 0600 → rename → chmod),其它条目原样保留;
|
|
7
|
+
* - 锁:`<auth.json>.lock`,`open(O_CREAT|O_EXCL)`(flag `wx`)写 `{ pid, at }`;等待 ≤ 15 s;锁文件超过 60 s 且
|
|
8
|
+
* pid 已死视为陈旧,删除后重试。取锁后由调用方**重读文件**再决定要不要刷新。
|
|
9
|
+
*/
|
|
10
|
+
import { closeSync, mkdirSync, openSync, readFileSync, statSync, unlinkSync, writeSync, } from "node:fs";
|
|
11
|
+
import { dirname } from "node:path";
|
|
12
|
+
import { writeAuthFile } from "../../config/auth-file.js";
|
|
13
|
+
import { CONFIG_FILE_VERSION } from "../../config/types.js";
|
|
14
|
+
import { isOAuthEntry } from "../../config/types-w6.js";
|
|
15
|
+
import { AmaError } from "../../errors.js";
|
|
16
|
+
export const LOCK_WAIT_MS = 15_000;
|
|
17
|
+
export const LOCK_STALE_MS = 60_000;
|
|
18
|
+
const LOCK_POLL_MS = 50;
|
|
19
|
+
function readRaw(path) {
|
|
20
|
+
try {
|
|
21
|
+
const value = JSON.parse(readFileSync(path, "utf8"));
|
|
22
|
+
return typeof value === "object" && value !== null && typeof value.providers === "object"
|
|
23
|
+
? value
|
|
24
|
+
: undefined;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function readOAuthEntry(path, provider) {
|
|
31
|
+
const entry = readRaw(path)?.providers?.[provider];
|
|
32
|
+
return isOAuthEntry(entry) ? entry : undefined;
|
|
33
|
+
}
|
|
34
|
+
/** 写入(`undefined` 删除)该供应商的条目,其余条目不动。 */
|
|
35
|
+
export function writeOAuthEntry(path, provider, entry) {
|
|
36
|
+
const file = readRaw(path) ?? { version: CONFIG_FILE_VERSION, providers: {} };
|
|
37
|
+
const providers = { ...file.providers };
|
|
38
|
+
if (entry === undefined)
|
|
39
|
+
delete providers[provider];
|
|
40
|
+
else
|
|
41
|
+
providers[provider] = entry;
|
|
42
|
+
writeAuthFile(path, { ...file, version: file.version ?? CONFIG_FILE_VERSION, providers });
|
|
43
|
+
}
|
|
44
|
+
export function lockPath(authFile) {
|
|
45
|
+
return `${authFile}.lock`;
|
|
46
|
+
}
|
|
47
|
+
function pidAlive(pid) {
|
|
48
|
+
try {
|
|
49
|
+
process.kill(pid, 0);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
return error.code === "EPERM";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** 锁文件陈旧:超过 60 s 且写锁的进程已不在。 */
|
|
57
|
+
export function isStaleLock(path, now = Date.now()) {
|
|
58
|
+
let age;
|
|
59
|
+
let pid;
|
|
60
|
+
try {
|
|
61
|
+
age = now - statSync(path).mtimeMs;
|
|
62
|
+
const value = JSON.parse(readFileSync(path, "utf8"));
|
|
63
|
+
pid = typeof value.pid === "number" ? value.pid : undefined;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// 读不到内容(正在写或已删):只按时间判断
|
|
67
|
+
try {
|
|
68
|
+
age = now - statSync(path).mtimeMs;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return age > LOCK_STALE_MS && (pid === undefined || !pidAlive(pid));
|
|
75
|
+
}
|
|
76
|
+
function tryAcquire(path) {
|
|
77
|
+
try {
|
|
78
|
+
const fd = openSync(path, "wx", 0o600);
|
|
79
|
+
try {
|
|
80
|
+
writeSync(fd, JSON.stringify({ pid: process.pid, at: new Date().toISOString() }));
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
closeSync(fd);
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (error.code === "EEXIST")
|
|
89
|
+
return false;
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/** 在 `auth.json.lock` 下执行 `fn`;等不到锁抛 `auth_lock_timeout`。 */
|
|
94
|
+
export async function withRefreshLock(authFile, fn, options = {}) {
|
|
95
|
+
const path = lockPath(authFile);
|
|
96
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
97
|
+
const deadline = Date.now() + (options.waitMs ?? LOCK_WAIT_MS);
|
|
98
|
+
for (;;) {
|
|
99
|
+
if (tryAcquire(path))
|
|
100
|
+
break;
|
|
101
|
+
if (isStaleLock(path)) {
|
|
102
|
+
try {
|
|
103
|
+
unlinkSync(path);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// 别人先删了
|
|
107
|
+
}
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (Date.now() >= deadline)
|
|
111
|
+
throw new AmaError("auth_lock_timeout", `timed out waiting for ${path}`);
|
|
112
|
+
await new Promise((r) => setTimeout(r, LOCK_POLL_MS + Math.floor(Math.random() * LOCK_POLL_MS)));
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
return await fn();
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
try {
|
|
119
|
+
unlinkSync(path);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// 已被当成陈旧锁删掉
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 测试用 fake OAuth / ChatGPT 后端(docs/wave6-plan.md §4.6)。`node:http` 随机端口;不进 bundle。
|
|
3
|
+
*
|
|
4
|
+
* OAuth:authorize(记参数、302 回 redirect_uri;SIWC 注册时带签发的 client_id 与 scope)、token(校验 PKCE;
|
|
5
|
+
* 授权码 / 刷新;刷新轮换,旧 refresh token 再用 → `refresh_token_reused`)、deviceauth、discovery + JWKS
|
|
6
|
+
* (现场生成 RSA 密钥对)、revoke。后端:`/v1/responses`、`/codex/responses`、`/v1/models`、`/codex/models`、
|
|
7
|
+
* `/wham/usage`,按脚本回放。
|
|
8
|
+
*/
|
|
9
|
+
export interface RecordedRequest {
|
|
10
|
+
method: string;
|
|
11
|
+
path: string;
|
|
12
|
+
headers: Record<string, string | string[] | undefined>;
|
|
13
|
+
body: string;
|
|
14
|
+
query: URLSearchParams;
|
|
15
|
+
}
|
|
16
|
+
export interface ScriptedResponse {
|
|
17
|
+
status?: number;
|
|
18
|
+
headers?: Record<string, string>;
|
|
19
|
+
/** SSE 事件(JSON 对象)或原始文本。 */
|
|
20
|
+
events?: unknown[];
|
|
21
|
+
body?: unknown;
|
|
22
|
+
}
|
|
23
|
+
export interface FakeOAuthOptions {
|
|
24
|
+
/** SIWC 注册时签发的 id。 */
|
|
25
|
+
issuedClientId?: string;
|
|
26
|
+
/** 回调与 token 响应里的 scope;缺省含 chatgpt.tokens.use.direct。 */
|
|
27
|
+
scope?: string;
|
|
28
|
+
accessTtlS?: number;
|
|
29
|
+
/** 改 id_token 声明(坏 nonce 等)。 */
|
|
30
|
+
idTokenClaims?: (claims: Record<string, unknown>) => Record<string, unknown>;
|
|
31
|
+
/** 用另一把钥签 id_token(验签失败)。 */
|
|
32
|
+
wrongKey?: boolean;
|
|
33
|
+
/** 刷新响应延迟(并发测试)。 */
|
|
34
|
+
refreshDelayMs?: number;
|
|
35
|
+
/** 刷新直接失败的错误码。 */
|
|
36
|
+
refreshError?: string;
|
|
37
|
+
/** 设备码轮询先返回几次 403。 */
|
|
38
|
+
devicePending?: number;
|
|
39
|
+
marker?: string;
|
|
40
|
+
}
|
|
41
|
+
export declare class FakeOAuthServer {
|
|
42
|
+
readonly options: FakeOAuthOptions;
|
|
43
|
+
readonly requests: RecordedRequest[];
|
|
44
|
+
readonly responses: ScriptedResponse[];
|
|
45
|
+
readonly revoked: string[];
|
|
46
|
+
refreshCalls: number;
|
|
47
|
+
exchangeCalls: number;
|
|
48
|
+
issuer: string;
|
|
49
|
+
private server;
|
|
50
|
+
private readonly key;
|
|
51
|
+
private readonly otherKey;
|
|
52
|
+
private readonly codes;
|
|
53
|
+
private current;
|
|
54
|
+
private readonly used;
|
|
55
|
+
private seq;
|
|
56
|
+
private devicePolls;
|
|
57
|
+
constructor(options?: FakeOAuthOptions);
|
|
58
|
+
start(): Promise<string>;
|
|
59
|
+
stop(): Promise<void>;
|
|
60
|
+
get marker(): string;
|
|
61
|
+
/** 预置一个可刷新的 refresh token(不经登录)。 */
|
|
62
|
+
seedRefreshToken(token: string, clientId: string): void;
|
|
63
|
+
private next;
|
|
64
|
+
idToken(claims: Record<string, unknown>): string;
|
|
65
|
+
private tokens;
|
|
66
|
+
private get scope();
|
|
67
|
+
private handle;
|
|
68
|
+
private backend;
|
|
69
|
+
}
|
|
70
|
+
/** 一段最小的成功 SSE(一个文本块)。 */
|
|
71
|
+
export declare function completedEvents(text: string, extra?: unknown[]): unknown[];
|
|
72
|
+
/** 跟随 302 打到本地回调(代替浏览器)。 */
|
|
73
|
+
export declare function followAuthorize(url: string): Promise<void>;
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 测试用 fake OAuth / ChatGPT 后端(docs/wave6-plan.md §4.6)。`node:http` 随机端口;不进 bundle。
|
|
3
|
+
*
|
|
4
|
+
* OAuth:authorize(记参数、302 回 redirect_uri;SIWC 注册时带签发的 client_id 与 scope)、token(校验 PKCE;
|
|
5
|
+
* 授权码 / 刷新;刷新轮换,旧 refresh token 再用 → `refresh_token_reused`)、deviceauth、discovery + JWKS
|
|
6
|
+
* (现场生成 RSA 密钥对)、revoke。后端:`/v1/responses`、`/codex/responses`、`/v1/models`、`/codex/models`、
|
|
7
|
+
* `/wham/usage`,按脚本回放。
|
|
8
|
+
*/
|
|
9
|
+
import { createHash, generateKeyPairSync, randomBytes, sign } from "node:crypto";
|
|
10
|
+
import { createServer } from "node:http";
|
|
11
|
+
function b64url(value) {
|
|
12
|
+
return Buffer.from(JSON.stringify(value)).toString("base64url");
|
|
13
|
+
}
|
|
14
|
+
export class FakeOAuthServer {
|
|
15
|
+
options;
|
|
16
|
+
requests = [];
|
|
17
|
+
responses = [];
|
|
18
|
+
revoked = [];
|
|
19
|
+
refreshCalls = 0;
|
|
20
|
+
exchangeCalls = 0;
|
|
21
|
+
issuer = "";
|
|
22
|
+
server;
|
|
23
|
+
key;
|
|
24
|
+
otherKey;
|
|
25
|
+
codes = new Map();
|
|
26
|
+
current = new Map(); // refresh token → client id
|
|
27
|
+
used = new Set();
|
|
28
|
+
seq = 0;
|
|
29
|
+
devicePolls = 0;
|
|
30
|
+
constructor(options = {}) {
|
|
31
|
+
this.options = options;
|
|
32
|
+
this.key = generateKeyPairSync("rsa", { modulusLength: 2048 });
|
|
33
|
+
this.otherKey = generateKeyPairSync("rsa", { modulusLength: 2048 }).privateKey;
|
|
34
|
+
}
|
|
35
|
+
async start() {
|
|
36
|
+
this.server = createServer((req, res) => void this.handle(req, res));
|
|
37
|
+
await new Promise((resolve) => this.server?.listen(0, "127.0.0.1", resolve));
|
|
38
|
+
const address = this.server.address();
|
|
39
|
+
const port = typeof address === "object" && address !== null ? address.port : 0;
|
|
40
|
+
this.issuer = `http://127.0.0.1:${port}`;
|
|
41
|
+
return this.issuer;
|
|
42
|
+
}
|
|
43
|
+
async stop() {
|
|
44
|
+
this.server?.closeAllConnections();
|
|
45
|
+
await new Promise((resolve) => this.server?.close(resolve));
|
|
46
|
+
}
|
|
47
|
+
get marker() {
|
|
48
|
+
return this.options.marker ?? "MARK";
|
|
49
|
+
}
|
|
50
|
+
/** 预置一个可刷新的 refresh token(不经登录)。 */
|
|
51
|
+
seedRefreshToken(token, clientId) {
|
|
52
|
+
this.current.set(token, clientId);
|
|
53
|
+
}
|
|
54
|
+
next(prefix) {
|
|
55
|
+
this.seq++;
|
|
56
|
+
return `${prefix}-${this.seq}-${this.marker}-${randomBytes(4).toString("hex")}`;
|
|
57
|
+
}
|
|
58
|
+
idToken(claims) {
|
|
59
|
+
const header = { alg: "RS256", kid: "k1", typ: "JWT" };
|
|
60
|
+
const final = this.options.idTokenClaims ? this.options.idTokenClaims(claims) : claims;
|
|
61
|
+
const input = `${b64url(header)}.${b64url(final)}`;
|
|
62
|
+
const key = this.options.wrongKey ? this.otherKey : this.key.privateKey;
|
|
63
|
+
return `${input}.${sign("sha256", Buffer.from(input), key).toString("base64url")}`;
|
|
64
|
+
}
|
|
65
|
+
tokens(clientId, nonce) {
|
|
66
|
+
const refresh = this.next("rt");
|
|
67
|
+
this.current.set(refresh, clientId);
|
|
68
|
+
const now = Math.floor(Date.now() / 1000);
|
|
69
|
+
return {
|
|
70
|
+
access_token: this.next("at"),
|
|
71
|
+
refresh_token: refresh,
|
|
72
|
+
id_token: this.idToken({
|
|
73
|
+
iss: this.issuer,
|
|
74
|
+
aud: clientId,
|
|
75
|
+
sub: "user-sub-1",
|
|
76
|
+
nonce,
|
|
77
|
+
exp: now + 3600,
|
|
78
|
+
iat: now,
|
|
79
|
+
email: "alice@example.com",
|
|
80
|
+
"https://api.openai.com/auth": { chatgpt_account_id: "acct-1", chatgpt_plan_type: "plus" },
|
|
81
|
+
}),
|
|
82
|
+
token_type: "Bearer",
|
|
83
|
+
expires_in: this.options.accessTtlS ?? 3600,
|
|
84
|
+
scope: this.scope,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
get scope() {
|
|
88
|
+
return (this.options.scope ??
|
|
89
|
+
"openid profile email offline_access resource.invoke chatgpt.tokens.use.direct");
|
|
90
|
+
}
|
|
91
|
+
async handle(req, res) {
|
|
92
|
+
const chunks = [];
|
|
93
|
+
for await (const chunk of req)
|
|
94
|
+
chunks.push(chunk);
|
|
95
|
+
const body = Buffer.concat(chunks).toString("utf8");
|
|
96
|
+
const url = new URL(req.url ?? "/", this.issuer);
|
|
97
|
+
const record = {
|
|
98
|
+
method: req.method ?? "GET",
|
|
99
|
+
path: url.pathname,
|
|
100
|
+
headers: req.headers,
|
|
101
|
+
body,
|
|
102
|
+
query: url.searchParams,
|
|
103
|
+
};
|
|
104
|
+
this.requests.push(record);
|
|
105
|
+
const json = (status, value, headers = {}) => {
|
|
106
|
+
res.writeHead(status, { "content-type": "application/json", ...headers });
|
|
107
|
+
res.end(JSON.stringify(value));
|
|
108
|
+
};
|
|
109
|
+
const params = () => String(req.headers["content-type"]).includes("json")
|
|
110
|
+
? JSON.parse(body || "{}")
|
|
111
|
+
: Object.fromEntries(new URLSearchParams(body));
|
|
112
|
+
switch (url.pathname) {
|
|
113
|
+
case "/.well-known/openid-configuration":
|
|
114
|
+
return json(200, {
|
|
115
|
+
issuer: this.issuer,
|
|
116
|
+
jwks_uri: `${this.issuer}/jwks`,
|
|
117
|
+
revocation_endpoint: `${this.issuer}/revoke`,
|
|
118
|
+
});
|
|
119
|
+
case "/jwks":
|
|
120
|
+
return json(200, {
|
|
121
|
+
keys: [
|
|
122
|
+
{
|
|
123
|
+
...this.key.publicKey.export({ format: "jwk" }),
|
|
124
|
+
kid: "k1",
|
|
125
|
+
use: "sig",
|
|
126
|
+
alg: "RS256",
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
});
|
|
130
|
+
case "/api/accounts/authorize":
|
|
131
|
+
case "/oauth/authorize": {
|
|
132
|
+
const q = url.searchParams;
|
|
133
|
+
const code = this.next("code");
|
|
134
|
+
const registering = q.get("client_id") === "dynamic_agent_client";
|
|
135
|
+
const clientId = registering
|
|
136
|
+
? (this.options.issuedClientId ?? "oaiapp_issued")
|
|
137
|
+
: (q.get("client_id") ?? "");
|
|
138
|
+
this.codes.set(code, {
|
|
139
|
+
challenge: q.get("code_challenge") ?? "",
|
|
140
|
+
nonce: q.get("nonce") ?? "",
|
|
141
|
+
clientId,
|
|
142
|
+
redirectUri: q.get("redirect_uri") ?? "",
|
|
143
|
+
});
|
|
144
|
+
const back = new URL(q.get("redirect_uri") ?? "");
|
|
145
|
+
back.searchParams.set("code", code);
|
|
146
|
+
back.searchParams.set("state", q.get("state") ?? "");
|
|
147
|
+
if (url.pathname.startsWith("/api/")) {
|
|
148
|
+
if (registering)
|
|
149
|
+
back.searchParams.set("client_id", clientId);
|
|
150
|
+
back.searchParams.set("scope", this.scope);
|
|
151
|
+
}
|
|
152
|
+
res.writeHead(302, { location: back.toString() }).end();
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
case "/api/accounts/oauth/token":
|
|
156
|
+
case "/oauth/token": {
|
|
157
|
+
const p = params();
|
|
158
|
+
if (p["grant_type"] === "authorization_code") {
|
|
159
|
+
this.exchangeCalls++;
|
|
160
|
+
const saved = this.codes.get(p["code"] ?? "");
|
|
161
|
+
if (!saved)
|
|
162
|
+
return json(400, { error: "invalid_grant" });
|
|
163
|
+
const challenge = createHash("sha256")
|
|
164
|
+
.update(p["code_verifier"] ?? "")
|
|
165
|
+
.digest("base64url");
|
|
166
|
+
if (challenge !== saved.challenge)
|
|
167
|
+
return json(400, { error: "invalid_grant" });
|
|
168
|
+
if (p["redirect_uri"] !== saved.redirectUri)
|
|
169
|
+
return json(400, { error: "invalid_grant" });
|
|
170
|
+
if (p["client_id"] !== saved.clientId)
|
|
171
|
+
return json(400, { error: "invalid_client" });
|
|
172
|
+
this.codes.delete(p["code"] ?? "");
|
|
173
|
+
return json(200, this.tokens(saved.clientId, saved.nonce));
|
|
174
|
+
}
|
|
175
|
+
if (p["grant_type"] === "refresh_token") {
|
|
176
|
+
this.refreshCalls++;
|
|
177
|
+
if (this.options.refreshDelayMs)
|
|
178
|
+
await new Promise((r) => setTimeout(r, this.options.refreshDelayMs));
|
|
179
|
+
if (this.options.refreshError)
|
|
180
|
+
return json(400, { error: this.options.refreshError });
|
|
181
|
+
const token = p["refresh_token"] ?? "";
|
|
182
|
+
if (this.used.has(token))
|
|
183
|
+
return json(400, { error: "refresh_token_reused" });
|
|
184
|
+
const clientId = this.current.get(token);
|
|
185
|
+
if (clientId === undefined)
|
|
186
|
+
return json(400, { error: "invalid_grant" });
|
|
187
|
+
this.used.add(token);
|
|
188
|
+
this.current.delete(token);
|
|
189
|
+
const out = this.tokens(clientId, "");
|
|
190
|
+
delete out["id_token"];
|
|
191
|
+
return json(200, out);
|
|
192
|
+
}
|
|
193
|
+
return json(400, { error: "unsupported_grant_type" });
|
|
194
|
+
}
|
|
195
|
+
case "/api/accounts/deviceauth/usercode":
|
|
196
|
+
return json(200, { device_auth_id: "dev-1", user_code: "ABCD-1234", interval: "1" });
|
|
197
|
+
case "/api/accounts/deviceauth/token": {
|
|
198
|
+
this.devicePolls++;
|
|
199
|
+
if (this.devicePolls <= (this.options.devicePending ?? 1))
|
|
200
|
+
return json(403, { error: "authorization_pending" });
|
|
201
|
+
const code = this.next("code");
|
|
202
|
+
const verifier = "device-verifier-0123456789abcdef0123456789abcdef";
|
|
203
|
+
this.codes.set(code, {
|
|
204
|
+
challenge: createHash("sha256").update(verifier).digest("base64url"),
|
|
205
|
+
nonce: "",
|
|
206
|
+
clientId: "app_EMoamEEZ73f0CkXaXp7hrann",
|
|
207
|
+
redirectUri: `${this.issuer}/deviceauth/callback`,
|
|
208
|
+
});
|
|
209
|
+
return json(200, {
|
|
210
|
+
authorization_code: code,
|
|
211
|
+
code_verifier: verifier,
|
|
212
|
+
code_challenge: "x",
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
case "/revoke":
|
|
216
|
+
this.revoked.push(params()["token"] ?? "");
|
|
217
|
+
res.writeHead(200).end();
|
|
218
|
+
return;
|
|
219
|
+
default:
|
|
220
|
+
return this.backend(res);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
backend(res) {
|
|
224
|
+
const scripted = this.responses.shift() ?? { events: completedEvents("ok") };
|
|
225
|
+
const status = scripted.status ?? 200;
|
|
226
|
+
if (scripted.events === undefined || status !== 200) {
|
|
227
|
+
res.writeHead(status, { "content-type": "application/json", ...scripted.headers });
|
|
228
|
+
res.end(JSON.stringify(scripted.body ?? {}));
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
res.writeHead(200, { "content-type": "text/event-stream", ...scripted.headers });
|
|
232
|
+
for (const event of scripted.events) {
|
|
233
|
+
const data = typeof event === "string" ? event : JSON.stringify(event);
|
|
234
|
+
res.write(`data: ${data}\n\n`);
|
|
235
|
+
}
|
|
236
|
+
res.end();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/** 一段最小的成功 SSE(一个文本块)。 */
|
|
240
|
+
export function completedEvents(text, extra = []) {
|
|
241
|
+
return [
|
|
242
|
+
{ type: "response.created", response: { id: "resp_1" } },
|
|
243
|
+
...extra,
|
|
244
|
+
{
|
|
245
|
+
type: "response.output_item.added",
|
|
246
|
+
output_index: 0,
|
|
247
|
+
item: { type: "message", id: "msg_1" },
|
|
248
|
+
},
|
|
249
|
+
{ type: "response.output_text.delta", output_index: 0, delta: text },
|
|
250
|
+
{
|
|
251
|
+
type: "response.output_item.done",
|
|
252
|
+
output_index: 0,
|
|
253
|
+
item: { type: "message", id: "msg_1", content: [{ type: "output_text", text }] },
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
type: "response.completed",
|
|
257
|
+
response: {
|
|
258
|
+
id: "resp_1",
|
|
259
|
+
status: "completed",
|
|
260
|
+
usage: { input_tokens: 10, output_tokens: 2, input_tokens_details: { cached_tokens: 4 } },
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
];
|
|
264
|
+
}
|
|
265
|
+
/** 跟随 302 打到本地回调(代替浏览器)。 */
|
|
266
|
+
export async function followAuthorize(url) {
|
|
267
|
+
const res = await fetch(url, { redirect: "manual" });
|
|
268
|
+
const location = res.headers.get("location");
|
|
269
|
+
if (location)
|
|
270
|
+
await fetch(location);
|
|
271
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 并发刷新测试的子进程入口(esbuild 打包后由 `node` 运行):对同一 auth.json 取一次新鲜条目,
|
|
3
|
+
* 只把 access token 的 SHA-256 打到 stdout(token 原文不进测试输出)。
|
|
4
|
+
*/
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
import { freshOAuthEntry } from "../oauth/refresh.js";
|
|
7
|
+
const [authFile, provider] = process.argv.slice(2);
|
|
8
|
+
freshOAuthEntry(authFile ?? "", provider ?? "chatgpt").then((entry) => {
|
|
9
|
+
const hash = createHash("sha256")
|
|
10
|
+
.update(entry?.accessToken ?? "")
|
|
11
|
+
.digest("hex");
|
|
12
|
+
process.stdout.write(`${hash}\n`);
|
|
13
|
+
}, (error) => {
|
|
14
|
+
process.stdout.write(`error ${error.code ?? "unknown"}\n`);
|
|
15
|
+
process.exitCode = 1;
|
|
16
|
+
});
|