mixdog 1.2.5 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSES/simple-icons-CC0-1.0.txt +30 -0
- package/NOTICE.md +19 -0
- package/package.json +4 -1
- package/scripts/check-model-recommendations.mjs +89 -0
- package/scripts/gate-local.mjs +7 -0
- package/scripts/lib/gate-scheduler.mjs +2 -2
- package/scripts/lib/isolated-test-env.mjs +16 -0
- package/scripts/lib/run-node-tests.mjs +5 -14
- package/scripts/provider-pingpong-live.mjs +9 -9
- package/src/agents/advisor/AGENT.md +4 -4
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/reviewer/AGENT.md +5 -4
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +17 -0
- package/src/defaults/skills/browser-use/SKILL.md +7 -1
- package/src/defaults/skills/computer-use/SKILL.md +3 -1
- package/src/defaults/skills/memory-management/SKILL.md +4 -1
- package/src/defaults/skills/setup/references/actions.md +11 -4
- package/src/defaults/skills/setup-guide/SKILL.md +175 -0
- package/src/defaults/skills/setup-guide/model-recommendations.json +333 -0
- package/src/defaults/skills/visualize/SKILL.md +3 -2
- package/src/lib/rules-builder.cjs +56 -7
- package/src/output-styles/common.md +22 -6
- package/src/output-styles/detailed.md +7 -5
- package/src/output-styles/minimal.md +7 -3
- package/src/output-styles/simple.md +2 -3
- package/src/rules/agent/AGENT.md +7 -1
- package/src/rules/agent-mode/AGENT_MODE.md +24 -0
- package/src/rules/agent-mode/MIXY.md +21 -0
- package/src/rules/agent-mode/ROUTINE.md +6 -0
- package/src/rules/lead/LEAD.md +9 -4
- package/src/rules/shared/10-tool-workflow.md +2 -1
- package/src/rules/shared/60-verification.md +4 -5
- package/src/rules/shared/70-delivery.md +3 -0
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -1
- package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +86 -0
- package/src/runtime/agent/orchestrator/config.mjs +6 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +77 -14
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +182 -13
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +5 -3
- package/src/runtime/agent/orchestrator/internal-agents.mjs +10 -0
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +215 -0
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +58 -64
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +10 -1
- package/src/runtime/agent/orchestrator/mcp/client.mjs +122 -15
- package/src/runtime/agent/orchestrator/mcp/oauth-account.mjs +97 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +2 -3
- package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +49 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +59 -9
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +32 -7
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +45 -6
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +195 -6
- package/src/runtime/agent/orchestrator/mcp/server-connectors.mjs +17 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +41 -19
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +11 -5
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/catalog-deadline.mjs +163 -0
- package/src/runtime/agent/orchestrator/providers/catalog-failures.mjs +34 -0
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +38 -14
- package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +100 -26
- package/src/runtime/agent/orchestrator/providers/lib/send-callbacks.mjs +24 -0
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +49 -4
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +0 -7
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +17 -12
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +11 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +45 -16
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-connect.mjs +196 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +74 -9
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-login.mjs +194 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-tokens.mjs +353 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +293 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +33 -100
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +23 -14
- package/src/runtime/agent/orchestrator/providers/registry.mjs +41 -27
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +98 -4
- package/src/runtime/agent/orchestrator/runtime-core/context-status-shape.mjs +4 -0
- package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +6 -4
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +15 -8
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +12 -6
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +32 -5
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +50 -20
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/agent-home.d.mts +4 -0
- package/src/runtime/agent/orchestrator/session/agent-home.mjs +33 -0
- package/src/runtime/agent/orchestrator/session/agent-mode.mjs +62 -0
- package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +15 -3
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +31 -0
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +241 -0
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +162 -0
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +641 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +74 -13
- package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +102 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +8 -2
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +165 -0
- package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +95 -0
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +221 -0
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +195 -0
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +167 -0
- package/src/runtime/agent/orchestrator/session/lifecycle-scan.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +39 -2
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +82 -33
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +11 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +5 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +13 -3
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +6 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/manager/pending-lifecycle-epoch.mjs +0 -8
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +10 -7
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +62 -22
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +44 -16
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -5
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +23 -1
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +81 -34
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +39 -4
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -5
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +55 -8
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +58 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +24 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +32 -5
- package/src/runtime/agent/orchestrator/session/request-fork.mjs +47 -0
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +70 -0
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +277 -0
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/side-question.mjs +5 -43
- package/src/runtime/agent/orchestrator/session/store/fs-probe.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +73 -6
- package/src/runtime/agent/orchestrator/session/store/load-session.mjs +40 -0
- package/src/runtime/agent/orchestrator/session/store/save-fault.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-header.mjs +36 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +258 -43
- package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +325 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +84 -21
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -12
- package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +46 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +46 -30
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +0 -4
- package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +144 -45
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +32 -13
- package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +364 -38
- package/src/runtime/agent/orchestrator/session/store.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/task-wait-control.mjs +43 -12
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +23 -6
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +44 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -6
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +13 -7
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/benign-exit.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +40 -7
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +37 -34
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +0 -4
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -0
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +29 -27
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/find-files-tool.mjs +28 -11
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +12 -3
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +203 -101
- package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +90 -41
- package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +17 -1
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-delivery.mjs +199 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +12 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +165 -39
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +25 -13
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +113 -5
- package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +7 -6
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +19 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-line-collector.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +25 -7
- package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-render.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +12 -5
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +61 -22
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +32 -8
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +193 -19
- package/src/runtime/agent/orchestrator/tools/builtin/shell-direct-exe.mjs +57 -7
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +123 -32
- package/src/runtime/agent/orchestrator/tools/builtin/shell-lossless-compact.mjs +26 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +13 -28
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +90 -11
- package/src/runtime/agent/orchestrator/tools/builtin/wait-budgets.mjs +23 -0
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +54 -10
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +22 -28
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +11 -7
- package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +126 -9
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +15 -6
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +64 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +10 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promotion-results.mjs +13 -3
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +104 -55
- package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +7 -2
- package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +39 -23
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
- package/src/runtime/attachments/office-extract.mjs +11 -9
- package/src/runtime/browser-bridge/client.mjs +24 -0
- package/src/runtime/channels/lib/scheduler.mjs +40 -12
- package/src/runtime/channels/lib/schedules-db.mjs +71 -12
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +36 -16
- package/src/runtime/channels/lib/webhook.mjs +0 -1
- package/src/runtime/channels/lib/webhooks-db.mjs +100 -10
- package/src/runtime/channels/lib/worker-main.mjs +17 -20
- package/src/runtime/computer-bridge/client.mjs +28 -1
- package/src/runtime/connectors/gmail-app-password.mjs +690 -0
- package/src/runtime/connectors/google-mcp.mjs +446 -0
- package/src/runtime/memory/lib/core-memory-access.mjs +69 -0
- package/src/runtime/memory/lib/core-memory-file.mjs +16 -8
- package/src/runtime/memory/lib/core-memory-index.mjs +15 -9
- package/src/runtime/memory/lib/core-memory-management.mjs +10 -4
- package/src/runtime/memory/lib/core-memory-store.mjs +53 -30
- package/src/runtime/memory/lib/core-memory-uniqueness.mjs +10 -6
- package/src/runtime/memory/lib/embedding-tokenizer.mjs +32 -18
- package/src/runtime/memory/lib/http-router/session-routes.mjs +3 -2
- package/src/runtime/memory/lib/memory-action-handlers/core-actions.mjs +44 -14
- package/src/runtime/memory/lib/memory-schema/core-and-meta.mjs +11 -0
- package/src/runtime/memory/lib/memory.mjs +7 -1
- package/src/runtime/memory/lib/query-core-recall.mjs +9 -1
- package/src/runtime/memory/lib/query-hybrid-search.mjs +2 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -1
- package/src/runtime/memory/lib/tool-call-handler.mjs +9 -5
- package/src/runtime/memory/tool-defs.mjs +5 -0
- package/src/runtime/office/authoring/pptx-script-normalize.mjs +11 -8
- package/src/runtime/office/core/tabular.mjs +1 -1
- package/src/runtime/office/design/library/design-template-inspect.mjs +7 -4
- package/src/runtime/office/portable/docx-formatting.mjs +1 -1
- package/src/runtime/office/portable/docx-runs.mjs +1 -1
- package/src/runtime/office/portable/docx-tracked-edits.mjs +2 -2
- package/src/runtime/office/portable/portable-docx-edits.mjs +11 -10
- package/src/runtime/office/portable/portable-docx-operations.mjs +21 -17
- package/src/runtime/office/portable/portable-docx-parts.mjs +15 -9
- package/src/runtime/office/portable/portable-docx-styles.mjs +4 -1
- package/src/runtime/office/portable/portable-docx-xml.mjs +9 -9
- package/src/runtime/office/portable/portable-opc.mjs +27 -13
- package/src/runtime/office/portable/portable-pivot.mjs +3 -3
- package/src/runtime/office/portable/portable-pptx-chart.mjs +3 -3
- package/src/runtime/office/portable/portable-pptx-charts.mjs +24 -18
- package/src/runtime/office/portable/portable-pptx-core.mjs +5 -5
- package/src/runtime/office/portable/portable-pptx-deck.mjs +8 -4
- package/src/runtime/office/portable/portable-pptx-package.mjs +7 -4
- package/src/runtime/office/portable/portable-pptx-shapes.mjs +18 -9
- package/src/runtime/office/portable/portable-sheet-parts.mjs +9 -3
- package/src/runtime/office/portable/portable-sheet-xml.mjs +5 -5
- package/src/runtime/office/portable/portable-xlsx-charts.mjs +4 -1
- package/src/runtime/office/portable/portable-xlsx-drawings.mjs +10 -6
- package/src/runtime/office/portable/portable-xlsx-operations.mjs +8 -5
- package/src/runtime/office/portable/portable-xlsx-pivot-ops.mjs +1 -1
- package/src/runtime/office/portable/portable-xlsx-reference-shift.mjs +11 -7
- package/src/runtime/office/portable/portable-xlsx-sheet-edits.mjs +6 -3
- package/src/runtime/office/portable/portable-xml.mjs +1 -1
- package/src/runtime/shared/agent-avatar-sprites.mjs +445 -0
- package/src/runtime/shared/agent-avatar.d.mts +64 -0
- package/src/runtime/shared/agent-avatar.mjs +320 -0
- package/src/runtime/shared/agent-route-config.d.mts +3 -0
- package/src/runtime/shared/agent-route-config.mjs +16 -0
- package/src/runtime/shared/atomic-file.mjs +36 -14
- package/src/runtime/shared/background-tasks.mjs +60 -20
- package/src/runtime/shared/child-spawn-gate.mjs +26 -16
- package/src/runtime/shared/config.mjs +8 -11
- package/src/runtime/shared/connector-accounts.mjs +15 -0
- package/src/runtime/shared/connector-catalog.d.mts +52 -0
- package/src/runtime/shared/connector-catalog.mjs +230 -0
- package/src/runtime/shared/connector-triggers.d.mts +3 -0
- package/src/runtime/shared/connector-triggers.mjs +43 -0
- package/src/runtime/shared/file-lock.mjs +7 -1
- package/src/runtime/shared/file-permissions-worker.mjs +38 -0
- package/src/runtime/shared/file-permissions.d.mts +19 -4
- package/src/runtime/shared/file-permissions.mjs +310 -4
- package/src/runtime/shared/git-runner-worker.mjs +6 -78
- package/src/runtime/shared/google-oauth-client.mjs +24 -0
- package/src/runtime/shared/held-request-host.d.mts +12 -0
- package/src/runtime/shared/held-request-host.mjs +71 -0
- package/src/runtime/shared/llm/http-agent.mjs +7 -3
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +10 -0
- package/src/runtime/shared/llm/usage-accounting.mjs +2 -0
- package/src/runtime/shared/llm/usage-ledger-import.mjs +32 -3
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +12 -5
- package/src/runtime/shared/llm/usage-ledger-worker.mjs +1 -1
- package/src/runtime/shared/llm/usage-ledger.mjs +20 -5
- package/src/runtime/shared/memory-snapshot.mjs +5 -1
- package/src/runtime/shared/notify-trace.mjs +8 -1
- package/src/runtime/shared/plain-preview.d.mts +1 -0
- package/src/runtime/shared/plain-preview.mjs +28 -0
- package/src/runtime/shared/pristine-execution-contract.json +5 -1
- package/src/runtime/shared/process-runner-worker.mjs +7 -0
- package/src/runtime/shared/process-runner.mjs +38 -0
- package/src/runtime/shared/provider-accounts.mjs +2 -1
- package/src/runtime/shared/provider-api-key.mjs +0 -1
- package/src/runtime/shared/read-row-numbers.mjs +1 -1
- package/src/runtime/shared/resource-admission.mjs +60 -18
- package/src/runtime/shared/routine-limits.d.mts +11 -0
- package/src/runtime/shared/routine-limits.mjs +21 -0
- package/src/runtime/shared/routine-trigger.d.mts +10 -0
- package/src/runtime/shared/routine-trigger.mjs +44 -0
- package/src/runtime/shared/run-child.mjs +84 -0
- package/src/runtime/shared/schedule-model-ref.mjs +9 -10
- package/src/runtime/shared/session-activity-signal.mjs +23 -0
- package/src/runtime/shared/shell-output-summary.mjs +23 -0
- package/src/runtime/shared/singleton-owner.mjs +126 -42
- package/src/runtime/shared/slow-span.mjs +4 -12
- package/src/runtime/shared/statusline/statusline-segments.mjs +13 -1
- package/src/runtime/shared/tool-output-limit.mjs +4 -2
- package/src/runtime/shared/tool-output-marker.mjs +58 -0
- package/src/runtime/shared/transcript-metadata.mjs +10 -0
- package/src/runtime/shared/turn-changes.mjs +0 -8
- package/src/runtime/shared/usage-readout-totals.mjs +56 -0
- package/src/runtime/shared/user-data-guard.mjs +131 -34
- package/src/runtime/shared/worktrees/activity-gate.mjs +33 -8
- package/src/runtime/shared/worktrees/git-head.mjs +20 -2
- package/src/runtime/shared/worktrees/lock.mjs +3 -2
- package/src/runtime/terminal-bridge/tool-defs.mjs +1 -1
- package/src/runtime/tidy/runners/biome.mjs +3 -1
- package/src/runtime/tidy/shadow.mjs +2 -1
- package/src/runtime/web-search/index.mjs +5 -7
- package/src/runtime/web-search/lib/formatter.mjs +42 -6
- package/src/runtime/web-search/tool-defs.mjs +6 -1
- package/src/session-runtime/agent-home-delivery.mjs +459 -0
- package/src/session-runtime/agent-profile-changes.mjs +21 -0
- package/src/session-runtime/agent-room-delivery.mjs +92 -0
- package/src/session-runtime/agent-task-sessions.mjs +200 -0
- package/src/session-runtime/boot/apis.mjs +50 -18
- package/src/session-runtime/boot/facade.mjs +5 -8
- package/src/session-runtime/boot/infrastructure.mjs +28 -17
- package/src/session-runtime/boot/tools.mjs +3 -0
- package/src/session-runtime/channel-config-api.mjs +53 -5
- package/src/session-runtime/cwd-plugins/core-memory-context.mjs +36 -20
- package/src/session-runtime/cwd-plugins/plugin-status.mjs +6 -1
- package/src/session-runtime/held-requests.mjs +228 -0
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +121 -0
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -1
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +31 -2
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +31 -2
- package/src/session-runtime/internal-tool-executor.mjs +2 -0
- package/src/session-runtime/lifecycle/session-catalog.mjs +9 -0
- package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +4 -3
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +11 -4
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +3 -3
- package/src/session-runtime/lifecycle/shared.mjs +25 -2
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +2 -0
- package/src/session-runtime/lifecycle/teardown.mjs +5 -2
- package/src/session-runtime/lifecycle-api.mjs +3 -1
- package/src/session-runtime/mcp-glue/server-catalog.mjs +8 -0
- package/src/session-runtime/mcp-glue/server-input.mjs +3 -0
- package/src/session-runtime/mcp-oauth-login.mjs +112 -15
- package/src/session-runtime/model-route/set-route.mjs +14 -3
- package/src/session-runtime/owned-automation-run.mjs +229 -0
- package/src/session-runtime/provider-auth/login.mjs +10 -6
- package/src/session-runtime/provider-auth/setup.mjs +19 -2
- package/src/session-runtime/provider-catalog-cache.mjs +101 -25
- package/src/session-runtime/provider-models/catalog-load.mjs +14 -3
- package/src/session-runtime/provider-models/row-hydration.mjs +4 -0
- package/src/session-runtime/provider-models.mjs +76 -10
- package/src/session-runtime/provider-readiness.mjs +4 -0
- package/src/session-runtime/resource-api.mjs +5 -0
- package/src/session-runtime/resource-mcp-api.mjs +107 -13
- package/src/session-runtime/resource-skills-api.mjs +12 -0
- package/src/session-runtime/room-member-gate.mjs +48 -0
- package/src/session-runtime/routine-home-turn.mjs +156 -0
- package/src/session-runtime/routine-owner.mjs +48 -0
- package/src/session-runtime/schedule-session-run.mjs +30 -64
- package/src/session-runtime/services/agent-tool/close-flow.mjs +2 -1
- package/src/session-runtime/services/agent-tool/helpers.mjs +10 -0
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +10 -2
- package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +13 -4
- package/src/session-runtime/services/agent-tool/notify.mjs +15 -4
- package/src/session-runtime/services/agent-tool/restart-notify.mjs +134 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -1
- package/src/session-runtime/services/agent-tool/spawn-flow/deferred-spawn.mjs +2 -1
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +19 -4
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +2 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -1
- package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +8 -3
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +4 -0
- package/src/session-runtime/services/agent-tool/worker-index.mjs +44 -10
- package/src/session-runtime/services/agent-tool.mjs +20 -0
- package/src/session-runtime/services/channel-admin.mjs +93 -24
- package/src/session-runtime/services/memory-access.mjs +37 -0
- package/src/session-runtime/services/provider-admin.mjs +166 -59
- package/src/session-runtime/services/schedule-access.mjs +91 -0
- package/src/session-runtime/services/usage-dashboard-model.mjs +2 -2
- package/src/session-runtime/services/usage-dashboard.mjs +27 -69
- package/src/session-runtime/session-create/session-options.mjs +34 -7
- package/src/session-runtime/session-hooks.mjs +16 -8
- package/src/session-runtime/setup-tool/executor.mjs +68 -6
- package/src/session-runtime/setup-tool/extended-actions.mjs +72 -14
- package/src/session-runtime/setup-tool/settings-contract.mjs +8 -6
- package/src/session-runtime/setup-tool/tool-defs.mjs +8 -0
- package/src/session-runtime/skills-api.mjs +16 -1
- package/src/session-runtime/tool-policy-refresh.mjs +238 -29
- package/src/session-runtime/turn/session-ops.mjs +10 -3
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +11 -2
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +3 -0
- package/src/session-runtime/usage-stats-api.mjs +6 -1
- package/src/session-runtime/webhook-session-run.mjs +49 -67
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +239 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +556 -22
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +11 -1
- package/src/session-runtime/workflow-agents-api.mjs +4 -1
- package/src/standalone/channel-transport/http-routes.mjs +10 -9
- package/src/standalone/daemon-agent-control.mjs +1 -8
- package/src/standalone/daemon-desktop-runtime.mjs +20 -7
- package/src/standalone/daemon-owner.mjs +117 -25
- package/src/standalone/daemon-session-control.mjs +11 -2
- package/src/standalone/daemon.mjs +61 -17
- package/src/standalone/session-call-cache.mjs +6 -0
- package/src/standalone/session-protocol.mjs +28 -1
- package/src/standalone/session-service/retention/busy.mjs +7 -2
- package/src/standalone/session-service/session-calls/session-turns.mjs +9 -0
- package/src/standalone/session-service.mjs +19 -0
- package/src/standalone/session-transport/routes.mjs +7 -6
- package/src/tui/app/model-options.mjs +39 -2
- package/src/tui/app/model-picker.mjs +16 -2
- package/src/tui/app/provider-setup-picker.mjs +1 -2
- package/src/tui/app/slash-commands.mjs +20 -0
- package/src/tui/dist/index.mjs +487 -128
- package/src/tui/session/context-state.mjs +6 -1
- package/src/tui/session/notice-surface.mjs +35 -4
- package/src/tui/session/notice-text.mjs +0 -1
- package/src/tui/session/queue-helpers.mjs +2 -1
- package/src/tui/session/session-api/extensions.mjs +4 -0
- package/src/tui/session/session-api/intake/submission.mjs +12 -13
- package/src/tui/session/session-api/integrations.mjs +9 -5
- package/src/tui/session/session-api/lifecycle/session-reset.mjs +13 -3
- package/src/tui/session/session-api/lifecycle.mjs +17 -1
- package/src/tui/session/session-api/routes.mjs +48 -3
- package/src/tui/session/session-flow/drain.mjs +20 -3
- package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -1
- package/src/tui/session/session-flow/queue/take-entries.mjs +3 -2
- package/src/tui/session/session-flow/steering.mjs +104 -24
- package/src/tui/session/session-flow.mjs +2 -0
- package/src/tui/session/tool-approval.mjs +26 -5
- package/src/tui/session/transcript-intake.mjs +6 -2
- package/src/tui/session/transcript-spill.mjs +5 -1
- package/src/tui/session/tui-steering-persist.mjs +65 -42
- package/src/tui/session/turn-live-call.mjs +56 -0
- package/src/tui/session/turn-stream.mjs +33 -0
- package/src/tui/session/turn.mjs +50 -7
- package/src/ui/statusline.mjs +1 -6
- package/src/ui/streaming-markdown-heal.mjs +24 -7
- package/src/vendor/statusline/bin/statusline-route.mjs +0 -1
- package/src/vendor/statusline/src/gateway/route-meta.mjs +0 -1
- package/src/workflows/default/WORKFLOW.md +9 -13
- package/src/session-runtime/automation-agents.mjs +0 -94
- package/src/session-runtime/automation-workflow.mjs +0 -59
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
scrubOAuthSecrets,
|
|
26
26
|
} from './lib/oauth-token-utils.mjs';
|
|
27
27
|
import { createOAuthPkce, parseOAuthCodeInput } from './lib/oauth-pkce.mjs';
|
|
28
|
+
import { OAUTH_PAGE_CONTENT_TYPE, oauthErrorHtml, oauthSuccessHtml } from './lib/oauth-page.mjs';
|
|
28
29
|
|
|
29
30
|
const SIGN_IN_EXPIRED_PREFIX = 'Anthropic sign-in expired. Sign in again from Providers.';
|
|
30
31
|
|
|
@@ -66,8 +67,6 @@ const OAUTH_CALLBACK_PATH = '/callback';
|
|
|
66
67
|
const OAUTH_REDIRECT_URI = `http://${OAUTH_CALLBACK_HOST}:${OAUTH_CALLBACK_PORT}${OAUTH_CALLBACK_PATH}`;
|
|
67
68
|
const OAUTH_MANUAL_REDIRECT_URI =
|
|
68
69
|
process.env.ANTHROPIC_OAUTH_MANUAL_REDIRECT_URI || 'https://platform.claude.com/oauth/code/callback';
|
|
69
|
-
const OAUTH_SUCCESS_REDIRECT_URL =
|
|
70
|
-
process.env.ANTHROPIC_OAUTH_SUCCESS_REDIRECT_URL || 'https://platform.claude.com/oauth/code/success?app=claude-code';
|
|
71
70
|
const OAUTH_LOGIN_TIMEOUT_MS = 5 * 60_000;
|
|
72
71
|
const OAUTH_TOKEN_TIMEOUT_MS = 30_000;
|
|
73
72
|
|
|
@@ -110,7 +109,7 @@ function _loadCredentialsFile(path) {
|
|
|
110
109
|
}
|
|
111
110
|
|
|
112
111
|
// The token endpoint names the signed-in account next to the tokens.
|
|
113
|
-
|
|
112
|
+
function identityFromTokenResponse(json) {
|
|
114
113
|
return normalizeAccountIdentity({
|
|
115
114
|
id: json?.account?.uuid,
|
|
116
115
|
email: json?.account?.email_address,
|
|
@@ -210,6 +209,7 @@ export function describeAnthropicOAuthCredentials() {
|
|
|
210
209
|
return {
|
|
211
210
|
...oauthCredentialStatus({ hasRefresh, expiresAt, detail, refreshSkewMs: TOKEN_REFRESH_SKEW_MS }),
|
|
212
211
|
...accountIdentityFields(creds.identity),
|
|
212
|
+
plan: creds.subscriptionType || null,
|
|
213
213
|
};
|
|
214
214
|
} catch (err) {
|
|
215
215
|
return {
|
|
@@ -570,9 +570,11 @@ function _parseOAuthCodeInput(input) {
|
|
|
570
570
|
return parseOAuthCodeInput(input, { allowHashState: true });
|
|
571
571
|
}
|
|
572
572
|
|
|
573
|
-
async function exchangeAuthorizationCode({ pkce, code, state, redirectUri }) {
|
|
573
|
+
async function exchangeAuthorizationCode({ pkce, code, state, redirectUri, signal = null }) {
|
|
574
|
+
signal?.throwIfAborted();
|
|
574
575
|
const cleanCode = String(code || '').trim();
|
|
575
576
|
if (!cleanCode) throw new Error('[anthropic-oauth] authorization code is required');
|
|
577
|
+
const timeoutSignal = AbortSignal.timeout(OAUTH_TOKEN_TIMEOUT_MS);
|
|
576
578
|
const tokenRes = await fetch(TOKEN_URL, {
|
|
577
579
|
method: 'POST',
|
|
578
580
|
headers: tokenEndpointHeaders(),
|
|
@@ -585,7 +587,7 @@ async function exchangeAuthorizationCode({ pkce, code, state, redirectUri }) {
|
|
|
585
587
|
state,
|
|
586
588
|
}),
|
|
587
589
|
redirect: 'error',
|
|
588
|
-
signal: AbortSignal.
|
|
590
|
+
signal: signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal,
|
|
589
591
|
dispatcher: getLlmDispatcher(),
|
|
590
592
|
});
|
|
591
593
|
if (!tokenRes.ok) {
|
|
@@ -605,6 +607,8 @@ async function exchangeAuthorizationCode({ pkce, code, state, redirectUri }) {
|
|
|
605
607
|
const expiresAt = expiresAtFromTokenResponse(json);
|
|
606
608
|
const scopes = _oauthParseScopeField(json?.scope);
|
|
607
609
|
const identity = identityFromTokenResponse(json);
|
|
610
|
+
// A cancelled login never stores the account it was exchanging.
|
|
611
|
+
signal?.throwIfAborted();
|
|
608
612
|
const credPath = _oauthCredentialsWritePath();
|
|
609
613
|
const raw = _updateCredentialsFile(credPath, (current) => {
|
|
610
614
|
const base = current && typeof current === 'object' ? current : {};
|
|
@@ -664,14 +668,33 @@ export async function beginOAuthLogin({ openBrowserFn = null, openBrowser = true
|
|
|
664
668
|
}
|
|
665
669
|
};
|
|
666
670
|
|
|
671
|
+
const controller = new AbortController();
|
|
667
672
|
let server = null;
|
|
668
673
|
let timeout = null;
|
|
669
674
|
let finish = null;
|
|
675
|
+
let exchangePromise = null;
|
|
676
|
+
// Browser and manual callbacks share one exchange: an authorization code is
|
|
677
|
+
// spent once, and a duplicate joins the first instead of failing the login.
|
|
678
|
+
const acceptCode = (code, redirectUri) => {
|
|
679
|
+
if (exchangePromise) return exchangePromise;
|
|
680
|
+
controller.signal.throwIfAborted();
|
|
681
|
+
// The browser deadline ends when a code arrives; the exchange has its own.
|
|
682
|
+
if (timeout) clearTimeout(timeout);
|
|
683
|
+
timeout = null;
|
|
684
|
+
exchangePromise = exchangeAuthorizationCode({ pkce, code, state, redirectUri, signal: controller.signal });
|
|
685
|
+
exchangePromise.then(
|
|
686
|
+
(tokens) => finish(tokens),
|
|
687
|
+
(error) => finish(null, error instanceof Error ? error : new Error(String(error)))
|
|
688
|
+
);
|
|
689
|
+
return exchangePromise;
|
|
690
|
+
};
|
|
670
691
|
const waitForCallback = new Promise((resolve, reject) => {
|
|
671
692
|
let settled = false;
|
|
672
693
|
finish = (value, error = null) => {
|
|
673
694
|
if (settled) return;
|
|
674
695
|
settled = true;
|
|
696
|
+
// Work arriving after the login settled (or was cancelled) is rejected.
|
|
697
|
+
controller.abort();
|
|
675
698
|
if (timeout) clearTimeout(timeout);
|
|
676
699
|
try {
|
|
677
700
|
server?.close();
|
|
@@ -691,20 +714,20 @@ export async function beginOAuthLogin({ openBrowserFn = null, openBrowser = true
|
|
|
691
714
|
const code = u.searchParams.get('code');
|
|
692
715
|
if (!code || u.searchParams.get('state') !== state) {
|
|
693
716
|
// Reject this request only; the valid callback may still arrive.
|
|
694
|
-
res.writeHead(400);
|
|
695
|
-
res.end('
|
|
717
|
+
res.writeHead(400, { 'Content-Type': OAUTH_PAGE_CONTENT_TYPE });
|
|
718
|
+
res.end(oauthErrorHtml('The sign-in callback was invalid or did not match this login.'));
|
|
696
719
|
return;
|
|
697
720
|
}
|
|
721
|
+
// The login settles (and its server closes) before this answer is sent,
|
|
722
|
+
// so the connection must not stay open to the closed login's handler.
|
|
698
723
|
try {
|
|
699
|
-
|
|
700
|
-
res.writeHead(
|
|
701
|
-
res.end();
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
res.
|
|
706
|
-
res.end(`Claude login failed: ${error.message}`);
|
|
707
|
-
finish(null, error);
|
|
724
|
+
await acceptCode(code, OAUTH_REDIRECT_URI);
|
|
725
|
+
res.writeHead(200, { 'Content-Type': OAUTH_PAGE_CONTENT_TYPE, Connection: 'close' });
|
|
726
|
+
res.end(oauthSuccessHtml('Claude'));
|
|
727
|
+
} catch {
|
|
728
|
+
// The shared exchange reports its error through waitForCallback.
|
|
729
|
+
res.writeHead(500, { 'Content-Type': OAUTH_PAGE_CONTENT_TYPE, Connection: 'close' });
|
|
730
|
+
res.end(oauthErrorHtml('Claude could not complete the token exchange.'));
|
|
708
731
|
}
|
|
709
732
|
});
|
|
710
733
|
timeout = setTimeout(() => finish(null), OAUTH_LOGIN_TIMEOUT_MS);
|
|
@@ -730,10 +753,9 @@ export async function beginOAuthLogin({ openBrowserFn = null, openBrowser = true
|
|
|
730
753
|
completeCode: async (input) => {
|
|
731
754
|
const parsed = _parseOAuthCodeInput(input);
|
|
732
755
|
if (parsed.state && parsed.state !== state) throw new Error('[anthropic-oauth] OAuth state mismatch');
|
|
756
|
+
if (!String(parsed.code || '').trim()) throw new Error('[anthropic-oauth] authorization code is required');
|
|
733
757
|
const redirectUri = parsed.redirectUri || (parsed.state ? OAUTH_MANUAL_REDIRECT_URI : OAUTH_REDIRECT_URI);
|
|
734
|
-
|
|
735
|
-
finish?.(tokens);
|
|
736
|
-
return tokens;
|
|
758
|
+
return await acceptCode(parsed.code, redirectUri);
|
|
737
759
|
},
|
|
738
760
|
cancel: () => {
|
|
739
761
|
finish?.(null);
|
|
@@ -448,7 +448,8 @@ export class AnthropicOAuthProvider {
|
|
|
448
448
|
// a hard 400. Pairing here closes the gap regardless of caller.
|
|
449
449
|
messages = sanitizeToolPairs(messages);
|
|
450
450
|
const opts = sendOpts || {};
|
|
451
|
-
const { onStageChange, onStreamDelta, onToolCall, onTextDelta, onTextReset } =
|
|
451
|
+
const { onStageChange, onStreamDelta, onToolCall, onTextDelta, onTextReset, onStreamItemStart } =
|
|
452
|
+
streamCallbacks(opts);
|
|
452
453
|
const externalSignal = opts.signal || null;
|
|
453
454
|
// Test seam: lets the retry harness drive stream outcomes without a
|
|
454
455
|
// live OAuth session.
|
|
@@ -610,7 +611,7 @@ export class AnthropicOAuthProvider {
|
|
|
610
611
|
midState,
|
|
611
612
|
onTextDelta,
|
|
612
613
|
knownToolNames,
|
|
613
|
-
{ relayProgressUpdates: body.thinking?.display === 'updates' }
|
|
614
|
+
{ relayProgressUpdates: body.thinking?.display === 'updates', onStreamItemStart }
|
|
614
615
|
);
|
|
615
616
|
try {
|
|
616
617
|
controller?.abort?.('Anthropic SSE complete');
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
NATIVE_SERVER_TOOL_RESULT_BLOCK_TYPES,
|
|
9
9
|
} from '../../lib/anthropic-native-blocks.mjs';
|
|
10
10
|
import { parseAnthropicFallbackBlock } from '../../anthropic-server-fallback.mjs';
|
|
11
|
+
import { reportStreamItemStart } from '../../lib/send-callbacks.mjs';
|
|
11
12
|
|
|
12
13
|
// Detach the provider payload from the parser's event object without altering
|
|
13
14
|
// any field (opaque server-tool result payloads must round-trip byte-exact).
|
|
@@ -19,7 +20,7 @@ function cloneNativeBlock(block) {
|
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
export function createContentBlockStart({ turn, blocks, state, progress, seedText }) {
|
|
23
|
+
export function createContentBlockStart({ turn, blocks, state, progress, seedText, onStreamItemStart }) {
|
|
23
24
|
const seedThinkingBlock = (index, block) => {
|
|
24
25
|
if (block.type === 'redacted_thinking') {
|
|
25
26
|
// Opaque redacted payload: real reasoning content, exposed as a block.
|
|
@@ -59,6 +60,8 @@ export function createContentBlockStart({ turn, blocks, state, progress, seedTex
|
|
|
59
60
|
name: block.name || '',
|
|
60
61
|
inputJson: '',
|
|
61
62
|
});
|
|
63
|
+
// The call opened; its input still streams before onToolCall.
|
|
64
|
+
reportStreamItemStart(onStreamItemStart, { kind: 'tool' });
|
|
62
65
|
}
|
|
63
66
|
if (block?.type === 'text') {
|
|
64
67
|
// Seed the ordered text slot. An empty block still needs its slot (it
|
|
@@ -19,6 +19,7 @@ export function createTurnEvents({
|
|
|
19
19
|
onToolCall,
|
|
20
20
|
relayProgressUpdates,
|
|
21
21
|
labels,
|
|
22
|
+
onStreamItemStart,
|
|
22
23
|
}) {
|
|
23
24
|
const { onMessageStart, onMessageDelta, onMessageStop } = createMessageEvents({ turn, blocks, state });
|
|
24
25
|
const onContentBlockDelta = createContentBlockDelta({
|
|
@@ -38,6 +39,7 @@ export function createTurnEvents({
|
|
|
38
39
|
state,
|
|
39
40
|
progress,
|
|
40
41
|
seedText: onContentBlockDelta.seedText,
|
|
42
|
+
onStreamItemStart,
|
|
41
43
|
}),
|
|
42
44
|
onContentBlockDelta,
|
|
43
45
|
onContentBlockStop: createContentBlockStop({ turn, blocks, state, leak, progress, onToolCall, labels }),
|
|
@@ -24,6 +24,7 @@ import { OAUTH_STREAM_LABELS } from './lib/anthropic-stream-labels.mjs';
|
|
|
24
24
|
* @param {Iterable<string>} [deps.knownToolNames]
|
|
25
25
|
* @param {boolean} [deps.relayProgressUpdates] request used thinking.display "updates"
|
|
26
26
|
* @param {{ display: string, tag: string }} [deps.labels] provider name for errors and stderr lines
|
|
27
|
+
* @param {(detail: object) => void} [deps.onStreamItemStart] a client tool_use block opened
|
|
27
28
|
*/
|
|
28
29
|
export function createAnthropicSseTurn({
|
|
29
30
|
state,
|
|
@@ -33,6 +34,7 @@ export function createAnthropicSseTurn({
|
|
|
33
34
|
knownToolNames,
|
|
34
35
|
relayProgressUpdates = false,
|
|
35
36
|
labels = OAUTH_STREAM_LABELS,
|
|
37
|
+
onStreamItemStart = null,
|
|
36
38
|
}) {
|
|
37
39
|
const progress = (kind) => {
|
|
38
40
|
try {
|
|
@@ -64,6 +66,7 @@ export function createAnthropicSseTurn({
|
|
|
64
66
|
onToolCall,
|
|
65
67
|
relayProgressUpdates,
|
|
66
68
|
labels,
|
|
69
|
+
onStreamItemStart,
|
|
67
70
|
});
|
|
68
71
|
const outcome = createTurnOutcome({ turn, blocks, state, labels });
|
|
69
72
|
|
|
@@ -186,7 +186,7 @@ export async function parseSSEStream(
|
|
|
186
186
|
state,
|
|
187
187
|
onTextDelta,
|
|
188
188
|
knownToolNames,
|
|
189
|
-
{ relayProgressUpdates = false, labels = OAUTH_STREAM_LABELS } = {}
|
|
189
|
+
{ relayProgressUpdates = false, labels = OAUTH_STREAM_LABELS, onStreamItemStart = null } = {}
|
|
190
190
|
) {
|
|
191
191
|
// Anthropic/Claude parity: every received SSE byte proves transport
|
|
192
192
|
// activity, including comment and named ping keepalives. Content kinds
|
|
@@ -208,6 +208,7 @@ export async function parseSSEStream(
|
|
|
208
208
|
knownToolNames,
|
|
209
209
|
relayProgressUpdates,
|
|
210
210
|
labels,
|
|
211
|
+
onStreamItemStart,
|
|
211
212
|
});
|
|
212
213
|
const watchdogs = createAnthropicSseWatchdogs({
|
|
213
214
|
state,
|
|
@@ -162,7 +162,8 @@ export class AnthropicProvider {
|
|
|
162
162
|
});
|
|
163
163
|
this.fastModeBetaHeaderLatched = fastModeLatched;
|
|
164
164
|
|
|
165
|
-
const { onStageChange, onStreamDelta, onToolCall, onTextDelta, onTextReset } =
|
|
165
|
+
const { onStageChange, onStreamDelta, onToolCall, onTextDelta, onTextReset, onStreamItemStart } =
|
|
166
|
+
streamCallbacks(opts);
|
|
166
167
|
|
|
167
168
|
// No absolute wall-clock cap on streaming generation: a stream still
|
|
168
169
|
// emitting SSE deltas must not be killed by a fixed total-lifetime timer.
|
|
@@ -288,6 +289,7 @@ export class AnthropicProvider {
|
|
|
288
289
|
{
|
|
289
290
|
relayProgressUpdates: params.thinking?.display === 'updates',
|
|
290
291
|
labels: { display: 'Anthropic', tag: this.name },
|
|
292
|
+
onStreamItemStart,
|
|
291
293
|
}
|
|
292
294
|
);
|
|
293
295
|
try {
|
|
@@ -36,8 +36,7 @@ import {
|
|
|
36
36
|
|
|
37
37
|
const ONBOARD_INTERVAL_MS = 1_000;
|
|
38
38
|
const CALLBACK_FAILURE_HTML = oauthErrorHtml(
|
|
39
|
-
'Antigravity sign-in was not completed.'
|
|
40
|
-
'Return to Mixdog for the error details and any account verification link.'
|
|
39
|
+
'Antigravity sign-in was not completed. Return to Mixdog for the error details and any account verification link.'
|
|
41
40
|
);
|
|
42
41
|
|
|
43
42
|
function extractProjectId(payload) {
|
|
@@ -219,7 +218,12 @@ async function provisionProject(context, tierId) {
|
|
|
219
218
|
}
|
|
220
219
|
|
|
221
220
|
/** Resolve account eligibility and return the project from a fresh status load. */
|
|
222
|
-
export async function discoverProject(
|
|
221
|
+
export async function discoverProject(accessToken, options = {}) {
|
|
222
|
+
return (await discoverAccount(accessToken, options)).projectId;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** Project plus the account's tier id (paid tier first), from the same status load. */
|
|
226
|
+
export async function discoverAccount(
|
|
223
227
|
accessToken,
|
|
224
228
|
{ fetchFn = fetch, onProgress = null, signal = null, email = '' } = {}
|
|
225
229
|
) {
|
|
@@ -236,7 +240,8 @@ export async function discoverProject(
|
|
|
236
240
|
const refreshed = await loadProjectState(context);
|
|
237
241
|
const projectId = extractProjectId(refreshed);
|
|
238
242
|
if (!projectId) throw new Error('[antigravity-oauth] loadCodeAssist did not return a cloudaicompanionProject');
|
|
239
|
-
|
|
243
|
+
const tierId = refreshed.paidTier?.id || refreshed.currentTier?.id;
|
|
244
|
+
return { projectId, tierId: typeof tierId === 'string' ? tierId : '' };
|
|
240
245
|
}
|
|
241
246
|
|
|
242
247
|
export async function exchangeAuthorizationCode({ code, verifier, fetchFn = fetch, onProgress = null, signal = null }) {
|
|
@@ -268,12 +273,13 @@ export async function exchangeAuthorizationCode({ code, verifier, fetchFn = fetc
|
|
|
268
273
|
throw new Error('[antigravity-oauth] token exchange response missing access_token or refresh_token');
|
|
269
274
|
}
|
|
270
275
|
const { email, userId } = await fetchAccountInfo(json.access_token, { fetchFn, signal });
|
|
271
|
-
const projectId = await
|
|
276
|
+
const { projectId, tierId } = await discoverAccount(json.access_token, { fetchFn, onProgress, signal, email });
|
|
272
277
|
const tokens = {
|
|
273
278
|
access_token: json.access_token,
|
|
274
279
|
refresh_token: json.refresh_token,
|
|
275
280
|
expires_at: typeof json.expires_in === 'number' ? Date.now() + json.expires_in * 1000 : 0,
|
|
276
281
|
project_id: projectId,
|
|
282
|
+
tier_id: tierId,
|
|
277
283
|
email,
|
|
278
284
|
user_id: userId,
|
|
279
285
|
};
|
|
@@ -204,6 +204,7 @@ export function loadTokens() {
|
|
|
204
204
|
refresh_token: String(raw.refresh_token),
|
|
205
205
|
expires_at: _normalizeExpiresAt(raw.expires_at ?? raw.expiresAt),
|
|
206
206
|
project_id: String(raw.project_id || raw.projectId || ''),
|
|
207
|
+
tier_id: String(raw.tier_id || ''),
|
|
207
208
|
email: String(raw.email || ''),
|
|
208
209
|
user_id: String(raw.user_id || raw.userId || ''),
|
|
209
210
|
source: 'own',
|
|
@@ -222,6 +223,7 @@ export function saveTokens(tokens) {
|
|
|
222
223
|
refresh_token: tokens.refresh_token,
|
|
223
224
|
expires_at: tokens.expires_at || 0,
|
|
224
225
|
project_id: tokens.project_id || tokens.projectId || '',
|
|
226
|
+
tier_id: tokens.tier_id || '',
|
|
225
227
|
email: tokens.email || '',
|
|
226
228
|
user_id: tokens.user_id || tokens.userId || '',
|
|
227
229
|
},
|
|
@@ -274,6 +276,7 @@ export function describeAntigravityOAuthCredentials() {
|
|
|
274
276
|
...accountIdentityFields({ id: tokens.user_id, email: tokens.email }),
|
|
275
277
|
email: tokens.email || '',
|
|
276
278
|
projectId: tokens.project_id || '',
|
|
279
|
+
plan: tokens.tier_id || null,
|
|
277
280
|
};
|
|
278
281
|
} catch {
|
|
279
282
|
return credentialsNotSet();
|
|
@@ -340,6 +343,7 @@ export function refreshTokens({ fetchFn = fetch } = {}) {
|
|
|
340
343
|
refresh_token: json.refresh_token || current.refresh_token,
|
|
341
344
|
expires_at: typeof json.expires_in === 'number' ? Date.now() + json.expires_in * 1000 : 0,
|
|
342
345
|
project_id: current.project_id,
|
|
346
|
+
tier_id: current.tier_id,
|
|
343
347
|
email: current.email,
|
|
344
348
|
user_id: current.user_id,
|
|
345
349
|
};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// Bounded, single-flight, cancellable provider catalog work, shared by the
|
|
2
|
+
// registry's catalog refreshes and the session runtime's shared catalog.
|
|
3
|
+
//
|
|
4
|
+
// - Deadline: a caller waits at most `timeoutMs` and then gets an ETIMEDOUT
|
|
5
|
+
// error entry instead of the provider's answer, so one hung provider cannot
|
|
6
|
+
// hold a catalog read or a startup/forced refresh.
|
|
7
|
+
// - Cancellation: on that deadline the operation's AbortSignal fires; a
|
|
8
|
+
// provider whose listModels honors `{ signal }` stops its work there.
|
|
9
|
+
// - Single flight: per provider at most one operation is pending in this
|
|
10
|
+
// process. A caller that finds one of its own kind joins it (with its own
|
|
11
|
+
// deadline); one that finds the other kind (a refresh vs a model list)
|
|
12
|
+
// waits for it inside its deadline before starting its own. An operation
|
|
13
|
+
// leaves the table only when the underlying work settles, not when a
|
|
14
|
+
// caller gives up, so repeated timed-out reads never pile up work; once an
|
|
15
|
+
// operation overran one deadline, later callers fail fast on it instead of
|
|
16
|
+
// each waiting out another deadline, until it settles.
|
|
17
|
+
// - Generations: one auth/account generation spans refreshes and lists alike
|
|
18
|
+
// (bumpProviderCatalogGeneration). Work of the other kind pending from an
|
|
19
|
+
// older generation, or from an older provider instance, never blocks or
|
|
20
|
+
// fails a caller of the newer one: that caller starts afresh. Same-kind
|
|
21
|
+
// work is never joined across generations, instances or a caller-supplied
|
|
22
|
+
// `epoch` (the catalog revision a list belongs to) either, unless it
|
|
23
|
+
// stalled (below).
|
|
24
|
+
// - Stalled work: an operation that overran its deadline (its signal fired)
|
|
25
|
+
// and still has not settled ignores cancellation. Until it settles, that
|
|
26
|
+
// provider name is not asked again for the same kind, not by a newer
|
|
27
|
+
// generation, epoch or provider instance: callers get an ETIMEDOUT entry
|
|
28
|
+
// marked `stalled` at once. Otherwise every account change, catalog
|
|
29
|
+
// revision or registry rebuild would leave one more never-ending call
|
|
30
|
+
// behind in the provider. Superseded calls can only overlap inside one
|
|
31
|
+
// deadline window, before any of them stalls.
|
|
32
|
+
import { clearProviderCatalogFailures, recordProviderCatalogOutcome } from './catalog-failures.mjs';
|
|
33
|
+
|
|
34
|
+
export const PROVIDER_CATALOG_TIMEOUT_MS = 4_000;
|
|
35
|
+
|
|
36
|
+
/** name -> the latest op started for that provider (either kind). */
|
|
37
|
+
const pendingOps = new Map();
|
|
38
|
+
/** `${kind}\0${name}` -> Set of the unsettled ops of that kind, of any
|
|
39
|
+
* generation, epoch or provider instance; emptied sets are removed. */
|
|
40
|
+
const runningOps = new Map();
|
|
41
|
+
/** `${kind}\0${name}` -> sequence number of the latest op started of that kind. */
|
|
42
|
+
const latestOpSeq = new Map();
|
|
43
|
+
let opSeq = 0;
|
|
44
|
+
let generation = 0;
|
|
45
|
+
|
|
46
|
+
const runKey = (name, kind) => `${kind}\0${name}`;
|
|
47
|
+
|
|
48
|
+
/** Opens a new auth/account generation for every provider's catalog work. */
|
|
49
|
+
export function bumpProviderCatalogGeneration() {
|
|
50
|
+
generation += 1;
|
|
51
|
+
// Failures of the previous account say nothing about the new one.
|
|
52
|
+
clearProviderCatalogFailures();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Provider names with catalog work still pending (diagnostics and tests). */
|
|
56
|
+
export function pendingProviderCatalogOps() {
|
|
57
|
+
return [...pendingOps.keys()];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** `{ name, kind }` of every operation that ignored its deadline's abort and
|
|
61
|
+
* is still unsettled (diagnostics and tests). */
|
|
62
|
+
export function stalledProviderCatalogOps() {
|
|
63
|
+
return [...runningOps.values()]
|
|
64
|
+
.flatMap((ops) => [...ops])
|
|
65
|
+
.filter((op) => op.timedOut)
|
|
66
|
+
.map(({ name, kind }) => ({ name, kind }));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const isStalled = (name, kind) => [...(runningOps.get(runKey(name, kind)) || [])].some((op) => op.timedOut);
|
|
70
|
+
|
|
71
|
+
function startOp(name, provider, kind, run, epoch, opGeneration) {
|
|
72
|
+
const controller = new AbortController();
|
|
73
|
+
const settled = Promise.resolve()
|
|
74
|
+
.then(() => run(controller.signal))
|
|
75
|
+
.then(
|
|
76
|
+
(value) => ({ value }),
|
|
77
|
+
(error) => ({ error })
|
|
78
|
+
);
|
|
79
|
+
const seq = ++opSeq;
|
|
80
|
+
const op = { name, provider, kind, epoch, generation: opGeneration, seq, controller, settled, done: false };
|
|
81
|
+
const key = runKey(name, kind);
|
|
82
|
+
latestOpSeq.set(key, seq);
|
|
83
|
+
const running = runningOps.get(key) || new Set();
|
|
84
|
+
running.add(op);
|
|
85
|
+
runningOps.set(key, running);
|
|
86
|
+
pendingOps.set(name, op);
|
|
87
|
+
void settled.then(() => {
|
|
88
|
+
op.done = true;
|
|
89
|
+
if (pendingOps.get(name) === op) pendingOps.delete(name);
|
|
90
|
+
running.delete(op);
|
|
91
|
+
if (running.size === 0 && runningOps.get(key) === running) runningOps.delete(key);
|
|
92
|
+
});
|
|
93
|
+
return op;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function timeoutError(message) {
|
|
97
|
+
const error = new Error(message);
|
|
98
|
+
error.code = 'ETIMEDOUT';
|
|
99
|
+
return error;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Resolves `{ value }`, `{ error }`, or `{ error, timedOut: true }`; never rejects.
|
|
103
|
+
* The outcome is also kept as the provider's latest catalog failure (or
|
|
104
|
+
* recovery) for views that explain an empty list (catalog-failures.mjs),
|
|
105
|
+
* but only while it is current: a caller of a superseded generation, or one
|
|
106
|
+
* answered by an op that a newer op of its kind replaced, publishes nothing. */
|
|
107
|
+
export async function boundedProviderCatalogOp(op) {
|
|
108
|
+
const callerGeneration = generation;
|
|
109
|
+
const answered = { op: null };
|
|
110
|
+
const outcome = await runBoundedOp(op, callerGeneration, answered);
|
|
111
|
+
const currentOp = !answered.op || latestOpSeq.get(runKey(op.name, op.kind)) === answered.op.seq;
|
|
112
|
+
if (callerGeneration === generation && currentOp) recordProviderCatalogOutcome(op.name, outcome.error);
|
|
113
|
+
return outcome;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function runBoundedOp(
|
|
117
|
+
{ name, provider, kind, run, timeoutMs = PROVIDER_CATALOG_TIMEOUT_MS, epoch = 0 },
|
|
118
|
+
callerGeneration,
|
|
119
|
+
answered
|
|
120
|
+
) {
|
|
121
|
+
let timer = null;
|
|
122
|
+
let watched = null;
|
|
123
|
+
const deadline = new Promise((resolve) => {
|
|
124
|
+
timer = setTimeout(() => {
|
|
125
|
+
const error = timeoutError(`provider "${name}" catalog ${kind} did not finish within ${timeoutMs}ms`);
|
|
126
|
+
if (watched) {
|
|
127
|
+
// Stalled until it settles: an op that honors the abort settles (and
|
|
128
|
+
// leaves the table) a few microtasks later, one that ignores it stays.
|
|
129
|
+
watched.timedOut = true;
|
|
130
|
+
watched.controller.abort(error);
|
|
131
|
+
}
|
|
132
|
+
resolve({ error, timedOut: true });
|
|
133
|
+
}, timeoutMs);
|
|
134
|
+
});
|
|
135
|
+
try {
|
|
136
|
+
for (;;) {
|
|
137
|
+
let op = pendingOps.get(name);
|
|
138
|
+
const superseded =
|
|
139
|
+
!op || op.provider !== provider || op.generation < callerGeneration || (op.kind === kind && op.epoch !== epoch);
|
|
140
|
+
if (superseded) {
|
|
141
|
+
if (isStalled(name, kind)) {
|
|
142
|
+
const error = timeoutError(`provider "${name}" catalog ${kind} ignored its deadline and is still pending`);
|
|
143
|
+
return { error, timedOut: true, stalled: true };
|
|
144
|
+
}
|
|
145
|
+
op = startOp(name, provider, kind, run, epoch, callerGeneration);
|
|
146
|
+
} else if (op.timedOut) {
|
|
147
|
+
// Already overran a deadline and still not settled: fail fast instead
|
|
148
|
+
// of making every later caller wait out another deadline for it.
|
|
149
|
+
const error = timeoutError(`provider "${name}" catalog ${op.kind} is still pending after its deadline`);
|
|
150
|
+
return { error, timedOut: true };
|
|
151
|
+
}
|
|
152
|
+
watched = op;
|
|
153
|
+
if (op.kind === kind) {
|
|
154
|
+
answered.op = op;
|
|
155
|
+
return await Promise.race([op.settled, deadline]);
|
|
156
|
+
}
|
|
157
|
+
const outcome = await Promise.race([op.settled.then(() => null), deadline]);
|
|
158
|
+
if (outcome) return outcome;
|
|
159
|
+
}
|
|
160
|
+
} finally {
|
|
161
|
+
clearTimeout(timer);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// The latest catalog failure of each provider, kept so a view that lists a
|
|
2
|
+
// provider's models can say WHY the list is empty (expired key, spent credits,
|
|
3
|
+
// timeout) instead of showing a silent 0/0. Cleared by the provider's next
|
|
4
|
+
// answer and by an account change.
|
|
5
|
+
import { safeErrorDetails } from '../../../shared/error-presentation.mjs';
|
|
6
|
+
import { providerErrorKind } from './provider-error-kind.mjs';
|
|
7
|
+
|
|
8
|
+
const MESSAGE_LIMIT = 300;
|
|
9
|
+
const failures = new Map();
|
|
10
|
+
|
|
11
|
+
/** Records a provider's catalog failure (`error`) or its recovery (no error). */
|
|
12
|
+
export function recordProviderCatalogOutcome(name, error) {
|
|
13
|
+
if (!error) {
|
|
14
|
+
failures.delete(name);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const reason = typeof error.providerError?.message === 'string' ? error.providerError.message : '';
|
|
18
|
+
const text = safeErrorDetails(reason ? `${error.message}: ${reason}` : error.message);
|
|
19
|
+
failures.set(name, {
|
|
20
|
+
// Plain text, never a JSON envelope: describeError reads the kind below.
|
|
21
|
+
message: text.replace(/\s+/g, ' ').slice(0, MESSAGE_LIMIT),
|
|
22
|
+
errorKind: providerErrorKind(error),
|
|
23
|
+
at: Date.now(),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** `{ message, errorKind, at }` of the provider's latest failure, or null. */
|
|
28
|
+
export function providerCatalogFailure(name) {
|
|
29
|
+
return failures.get(name) ?? null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function clearProviderCatalogFailures() {
|
|
33
|
+
failures.clear();
|
|
34
|
+
}
|
|
@@ -4,7 +4,7 @@ import { createRemoteVersionSource } from './npm-cli-version.mjs';
|
|
|
4
4
|
// documented version endpoint; the official installer script embeds the
|
|
5
5
|
// current build (…/lab/<build>/…), parsed best-effort. Any format change or
|
|
6
6
|
// failure falls back to the floor.
|
|
7
|
-
export const CURSOR_CLIENT_VERSION_FLOOR = 'cli-2026.10.
|
|
7
|
+
export const CURSOR_CLIENT_VERSION_FLOOR = 'cli-2026.10.19-6bbf2c4';
|
|
8
8
|
const BUILD_PATTERN = /downloads\.cursor\.com\/lab\/(\d{4}\.\d{2}\.\d{2}-[0-9a-f]{6,40})\//;
|
|
9
9
|
export const CURSOR_INSTALL_URL = 'https://cursor.com/install';
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ import { createServer } from 'node:http';
|
|
|
4
4
|
import { randomBytes } from 'node:crypto';
|
|
5
5
|
import { getLlmDispatcher } from '../../../shared/llm/http-agent.mjs';
|
|
6
6
|
import { createOAuthPkce, parseOAuthCodeInput } from './lib/oauth-pkce.mjs';
|
|
7
|
-
import { OAUTH_PAGE_CONTENT_TYPE, oauthSuccessHtml } from './lib/oauth-page.mjs';
|
|
7
|
+
import { OAUTH_PAGE_CONTENT_TYPE, oauthErrorHtml, oauthSuccessHtml } from './lib/oauth-page.mjs';
|
|
8
8
|
import { emailFromJwts } from './lib/oauth-token-utils.mjs';
|
|
9
9
|
import {
|
|
10
10
|
CLIENT_ID,
|
|
@@ -26,7 +26,8 @@ export function generatePKCE() {
|
|
|
26
26
|
return createOAuthPkce();
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
export async function exchangeAuthorizationCode({ discovery, pkce, code }) {
|
|
29
|
+
export async function exchangeAuthorizationCode({ discovery, pkce, code, signal = null }) {
|
|
30
|
+
signal?.throwIfAborted();
|
|
30
31
|
const cleanCode = String(code || '').trim();
|
|
31
32
|
if (!cleanCode) throw new Error('[grok-oauth] authorization code is required');
|
|
32
33
|
const tokenRes = await fetch(discovery.token_endpoint, {
|
|
@@ -47,7 +48,9 @@ export async function exchangeAuthorizationCode({ discovery, pkce, code }) {
|
|
|
47
48
|
// Secret-bearing (authorization code + verifier): refuse
|
|
48
49
|
// redirects so they can't be replayed to an untrusted host.
|
|
49
50
|
redirect: 'error',
|
|
50
|
-
signal:
|
|
51
|
+
signal: signal
|
|
52
|
+
? AbortSignal.any([signal, AbortSignal.timeout(TOKEN_TIMEOUT_MS)])
|
|
53
|
+
: AbortSignal.timeout(TOKEN_TIMEOUT_MS),
|
|
51
54
|
dispatcher: getLlmDispatcher(),
|
|
52
55
|
});
|
|
53
56
|
if (!tokenRes.ok) {
|
|
@@ -72,6 +75,8 @@ export async function exchangeAuthorizationCode({ discovery, pkce, code }) {
|
|
|
72
75
|
? { email: emailFromJwts(json.id_token, json.access_token) }
|
|
73
76
|
: {}),
|
|
74
77
|
};
|
|
78
|
+
// A cancelled login never stores the account it was exchanging.
|
|
79
|
+
signal?.throwIfAborted();
|
|
75
80
|
saveTokens(tokens);
|
|
76
81
|
return tokens;
|
|
77
82
|
}
|
|
@@ -96,11 +101,30 @@ export async function beginOAuthLogin({ openBrowser = true } = {}) {
|
|
|
96
101
|
let server = null;
|
|
97
102
|
let timeout = null;
|
|
98
103
|
let finish = null;
|
|
104
|
+
let exchangePromise = null;
|
|
105
|
+
const controller = new AbortController();
|
|
106
|
+
// Browser and manual callbacks share one exchange: an authorization code is
|
|
107
|
+
// single-use, and a duplicate must not settle the login before the first.
|
|
108
|
+
const acceptCode = (code) => {
|
|
109
|
+
if (exchangePromise) return exchangePromise;
|
|
110
|
+
controller.signal.throwIfAborted();
|
|
111
|
+
// The browser deadline ends when a code arrives; the exchange has its own.
|
|
112
|
+
if (timeout) clearTimeout(timeout);
|
|
113
|
+
timeout = null;
|
|
114
|
+
exchangePromise = exchangeAuthorizationCode({ discovery, pkce, code, signal: controller.signal });
|
|
115
|
+
exchangePromise.then(
|
|
116
|
+
(tokens) => finish(tokens),
|
|
117
|
+
(err) => finish(null, err instanceof Error ? err : new Error(String(err)))
|
|
118
|
+
);
|
|
119
|
+
return exchangePromise;
|
|
120
|
+
};
|
|
99
121
|
const waitForCallback = new Promise((resolve, reject) => {
|
|
100
122
|
let settled = false;
|
|
101
123
|
finish = (value, error = null) => {
|
|
102
124
|
if (settled) return;
|
|
103
125
|
settled = true;
|
|
126
|
+
// Work arriving after the login settled (or was cancelled) is rejected.
|
|
127
|
+
controller.abort();
|
|
104
128
|
if (timeout) clearTimeout(timeout);
|
|
105
129
|
try {
|
|
106
130
|
server?.close();
|
|
@@ -120,17 +144,18 @@ export async function beginOAuthLogin({ openBrowser = true } = {}) {
|
|
|
120
144
|
const code = u.searchParams.get('code');
|
|
121
145
|
if (!code || u.searchParams.get('state') !== state) {
|
|
122
146
|
// Reject this request only; the valid callback may still arrive.
|
|
123
|
-
res.writeHead(400);
|
|
124
|
-
res.end('
|
|
147
|
+
res.writeHead(400, { 'Content-Type': OAUTH_PAGE_CONTENT_TYPE });
|
|
148
|
+
res.end(oauthErrorHtml('The sign-in callback was invalid or did not match this login.'));
|
|
125
149
|
return;
|
|
126
150
|
}
|
|
127
|
-
res.writeHead(200, { 'Content-Type': OAUTH_PAGE_CONTENT_TYPE });
|
|
128
|
-
res.end(oauthSuccessHtml('Grok'));
|
|
129
151
|
try {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
152
|
+
await acceptCode(code);
|
|
153
|
+
res.writeHead(200, { 'Content-Type': OAUTH_PAGE_CONTENT_TYPE });
|
|
154
|
+
res.end(oauthSuccessHtml('Grok'));
|
|
155
|
+
} catch {
|
|
156
|
+
// The shared exchange reports its error through waitForCallback.
|
|
157
|
+
res.writeHead(500, { 'Content-Type': OAUTH_PAGE_CONTENT_TYPE });
|
|
158
|
+
res.end(oauthErrorHtml('Grok could not complete the token exchange.'));
|
|
134
159
|
}
|
|
135
160
|
});
|
|
136
161
|
timeout = setTimeout(() => finish(null), LOGIN_TIMEOUT_MS);
|
|
@@ -161,9 +186,8 @@ export async function beginOAuthLogin({ openBrowser = true } = {}) {
|
|
|
161
186
|
completeCode: async (input) => {
|
|
162
187
|
const parsed = parseOAuthCodeInput(input, { allowHashState: true });
|
|
163
188
|
if (parsed.state && parsed.state !== state) throw new Error('[grok-oauth] OAuth state mismatch');
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
return tokens;
|
|
189
|
+
if (!parsed.code) throw new Error('[grok-oauth] authorization code is required');
|
|
190
|
+
return await acceptCode(parsed.code);
|
|
167
191
|
},
|
|
168
192
|
cancel: () => {
|
|
169
193
|
finish?.(null);
|