agent-control-plane 0.1.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/LICENSE +21 -0
- package/README.md +589 -0
- package/SKILL.md +149 -0
- package/assets/workflow-catalog.json +57 -0
- package/bin/audit-issue-routing.sh +74 -0
- package/bin/issue-resource-class.sh +58 -0
- package/bin/label-follow-up-issues.sh +114 -0
- package/bin/pr-risk.sh +532 -0
- package/bin/sync-pr-labels.sh +112 -0
- package/hooks/heartbeat-hooks.sh +573 -0
- package/hooks/issue-reconcile-hooks.sh +217 -0
- package/hooks/pr-reconcile-hooks.sh +225 -0
- package/npm/bin/agent-control-plane.js +1984 -0
- package/npm/public-bin/agent-control-plane +3 -0
- package/package.json +61 -0
- package/tools/bin/agent-cleanup-worktree +247 -0
- package/tools/bin/agent-github-update-labels +66 -0
- package/tools/bin/agent-init-worktree +216 -0
- package/tools/bin/agent-project-archive-run +52 -0
- package/tools/bin/agent-project-capture-worker +46 -0
- package/tools/bin/agent-project-catch-up-merged-prs +137 -0
- package/tools/bin/agent-project-cleanup-session +244 -0
- package/tools/bin/agent-project-detached-launch +107 -0
- package/tools/bin/agent-project-heartbeat-loop +2347 -0
- package/tools/bin/agent-project-open-issue-worktree +89 -0
- package/tools/bin/agent-project-open-pr-worktree +80 -0
- package/tools/bin/agent-project-publish-issue-pr +349 -0
- package/tools/bin/agent-project-reconcile-issue-session +1128 -0
- package/tools/bin/agent-project-reconcile-pr-session +1005 -0
- package/tools/bin/agent-project-retry-state +147 -0
- package/tools/bin/agent-project-run-claude-session +657 -0
- package/tools/bin/agent-project-run-codex-resilient +718 -0
- package/tools/bin/agent-project-run-codex-session +316 -0
- package/tools/bin/agent-project-run-kilo-session +27 -0
- package/tools/bin/agent-project-run-openclaw-session +984 -0
- package/tools/bin/agent-project-run-opencode-session +27 -0
- package/tools/bin/agent-project-sync-anchor-repo +128 -0
- package/tools/bin/agent-project-worker-status +143 -0
- package/tools/bin/audit-agent-worktrees.sh +310 -0
- package/tools/bin/audit-issue-routing.sh +11 -0
- package/tools/bin/audit-retained-layout.sh +58 -0
- package/tools/bin/audit-retained-overlap.sh +135 -0
- package/tools/bin/audit-retained-worktrees.sh +228 -0
- package/tools/bin/branch-verification-guard.sh +351 -0
- package/tools/bin/capture-worker.sh +18 -0
- package/tools/bin/check-skill-contracts.sh +324 -0
- package/tools/bin/cleanup-worktree.sh +44 -0
- package/tools/bin/codex-quota +31 -0
- package/tools/bin/create-follow-up-issue.sh +114 -0
- package/tools/bin/dashboard-launchd-bootstrap.sh +38 -0
- package/tools/bin/flow-config-lib.sh +2127 -0
- package/tools/bin/flow-resident-worker-lib.sh +683 -0
- package/tools/bin/flow-runtime-doctor.sh +97 -0
- package/tools/bin/flow-shell-lib.sh +266 -0
- package/tools/bin/heartbeat-recovery-preflight.sh +106 -0
- package/tools/bin/heartbeat-safe-auto.sh +551 -0
- package/tools/bin/install-dashboard-launchd.sh +152 -0
- package/tools/bin/install-project-launchd.sh +219 -0
- package/tools/bin/issue-publish-scope-guard.sh +242 -0
- package/tools/bin/issue-requires-local-workspace-install.sh +31 -0
- package/tools/bin/issue-resource-class.sh +12 -0
- package/tools/bin/kick-scheduler.sh +75 -0
- package/tools/bin/label-follow-up-issues.sh +14 -0
- package/tools/bin/new-pr-worktree.sh +50 -0
- package/tools/bin/new-worktree.sh +49 -0
- package/tools/bin/pr-risk.sh +12 -0
- package/tools/bin/prepare-worktree.sh +140 -0
- package/tools/bin/profile-activate.sh +109 -0
- package/tools/bin/profile-adopt.sh +219 -0
- package/tools/bin/profile-smoke.sh +461 -0
- package/tools/bin/project-init.sh +189 -0
- package/tools/bin/project-launchd-bootstrap.sh +54 -0
- package/tools/bin/project-remove.sh +155 -0
- package/tools/bin/project-runtime-supervisor.sh +56 -0
- package/tools/bin/project-runtimectl.sh +586 -0
- package/tools/bin/provider-cooldown-state.sh +166 -0
- package/tools/bin/publish-issue-worker.sh +31 -0
- package/tools/bin/reconcile-issue-worker.sh +34 -0
- package/tools/bin/reconcile-pr-worker.sh +34 -0
- package/tools/bin/record-verification.sh +71 -0
- package/tools/bin/render-architecture-infographics.sh +110 -0
- package/tools/bin/render-dashboard-demo-media.sh +333 -0
- package/tools/bin/render-dashboard-snapshot.py +16 -0
- package/tools/bin/render-flow-config.sh +86 -0
- package/tools/bin/retry-state.sh +31 -0
- package/tools/bin/reuse-issue-worktree.sh +75 -0
- package/tools/bin/run-codex-bypass.sh +3 -0
- package/tools/bin/run-codex-safe.sh +3 -0
- package/tools/bin/run-codex-task.sh +231 -0
- package/tools/bin/scaffold-profile.sh +374 -0
- package/tools/bin/serve-dashboard.sh +5 -0
- package/tools/bin/split-retained-slice.sh +124 -0
- package/tools/bin/start-issue-worker.sh +796 -0
- package/tools/bin/start-pr-fix-worker.sh +458 -0
- package/tools/bin/start-pr-merge-repair-worker.sh +8 -0
- package/tools/bin/start-pr-review-worker.sh +227 -0
- package/tools/bin/start-resident-issue-loop.sh +908 -0
- package/tools/bin/sync-agent-repo.sh +52 -0
- package/tools/bin/sync-dependency-baseline.sh +247 -0
- package/tools/bin/sync-pr-labels.sh +12 -0
- package/tools/bin/sync-recurring-issue-checklist.sh +274 -0
- package/tools/bin/sync-shared-agent-home.sh +214 -0
- package/tools/bin/sync-vscode-workspace.sh +157 -0
- package/tools/bin/test-smoke.sh +63 -0
- package/tools/bin/uninstall-project-launchd.sh +55 -0
- package/tools/bin/update-github-labels.sh +14 -0
- package/tools/bin/worker-status.sh +19 -0
- package/tools/bin/workflow-catalog.sh +77 -0
- package/tools/dashboard/app.js +286 -0
- package/tools/dashboard/dashboard_snapshot.py +466 -0
- package/tools/dashboard/index.html +41 -0
- package/tools/dashboard/server.py +64 -0
- package/tools/dashboard/styles.css +351 -0
- package/tools/templates/issue-prompt-template.md +109 -0
- package/tools/templates/pr-fix-template.md +120 -0
- package/tools/templates/pr-merge-repair-template.md +91 -0
- package/tools/templates/pr-review-template.md +62 -0
- package/tools/templates/scheduled-issue-prompt-template.md +62 -0
- package/tools/tests/test-agent-control-plane-npm-cli.sh +279 -0
- package/tools/tests/test-agent-github-update-labels-falls-back-to-repository-id.sh +56 -0
- package/tools/tests/test-agent-project-claude-session-wrapper-clears-stale-sandbox-artifacts.sh +89 -0
- package/tools/tests/test-agent-project-claude-session-wrapper-does-not-retry-provider-quota.sh +82 -0
- package/tools/tests/test-agent-project-claude-session-wrapper-retries-transient-failures.sh +90 -0
- package/tools/tests/test-agent-project-claude-session-wrapper-times-out.sh +73 -0
- package/tools/tests/test-agent-project-claude-session-wrapper.sh +103 -0
- package/tools/tests/test-agent-project-cleanup-session-orphan-fallback.sh +90 -0
- package/tools/tests/test-agent-project-cleanup-session-skip-worktree-cleanup.sh +90 -0
- package/tools/tests/test-agent-project-codex-live-thread-persist.sh +76 -0
- package/tools/tests/test-agent-project-codex-recovery.sh +731 -0
- package/tools/tests/test-agent-project-codex-session-wrapper-clears-stale-sandbox-artifacts.sh +105 -0
- package/tools/tests/test-agent-project-codex-session-wrapper.sh +97 -0
- package/tools/tests/test-agent-project-open-pr-worktree-config-prefix.sh +81 -0
- package/tools/tests/test-agent-project-openclaw-session-wrapper-clears-stale-sandbox-artifacts.sh +109 -0
- package/tools/tests/test-agent-project-openclaw-session-wrapper-infers-blocked-result-contract.sh +89 -0
- package/tools/tests/test-agent-project-openclaw-session-wrapper-recovers-literal-env-artifacts.sh +113 -0
- package/tools/tests/test-agent-project-openclaw-session-wrapper-recovers-version-mismatch.sh +135 -0
- package/tools/tests/test-agent-project-openclaw-session-wrapper-resident.sh +179 -0
- package/tools/tests/test-agent-project-openclaw-session-wrapper-reuses-existing-agent-after-add-race.sh +119 -0
- package/tools/tests/test-agent-project-openclaw-session-wrapper-terminates-rate-limit-hang.sh +91 -0
- package/tools/tests/test-agent-project-openclaw-session-wrapper.sh +117 -0
- package/tools/tests/test-agent-project-publish-issue-pr-prunes-stale-worktree-entry.sh +148 -0
- package/tools/tests/test-agent-project-publish-issue-pr-reads-archived-session.sh +146 -0
- package/tools/tests/test-agent-project-publish-issue-pr-recovers-final-head.sh +145 -0
- package/tools/tests/test-agent-project-publish-issue-pr-reuses-existing-worktree.sh +147 -0
- package/tools/tests/test-agent-project-reconcile-failure-reason.sh +456 -0
- package/tools/tests/test-agent-project-reconcile-issue-archived-session-fallback.sh +96 -0
- package/tools/tests/test-agent-project-reconcile-issue-before-blocked.sh +90 -0
- package/tools/tests/test-agent-project-reconcile-issue-host-verification-recovery-uses-recovered-worktree.sh +212 -0
- package/tools/tests/test-agent-project-reconcile-issue-host-verification-recovery.sh +207 -0
- package/tools/tests/test-agent-project-reconcile-issue-provider-quota-schedules-provider-cooldown.sh +101 -0
- package/tools/tests/test-agent-project-reconcile-issue-session-backfills-lane-metadata-from-worker-key.sh +113 -0
- package/tools/tests/test-agent-project-reconcile-issue-session-clears-stale-failed-summary.sh +117 -0
- package/tools/tests/test-agent-project-reconcile-issue-session-initializes-shared-agent-home.sh +55 -0
- package/tools/tests/test-agent-project-reconcile-issue-session-normalizes-runner-state.sh +125 -0
- package/tools/tests/test-agent-project-reconcile-issue-session-records-invalid-contract-summary.sh +118 -0
- package/tools/tests/test-agent-project-reconcile-issue-session-skips-duplicate-blocked-comment.sh +144 -0
- package/tools/tests/test-agent-project-reconcile-issue-session-standardizes-no-commits-blocker.sh +145 -0
- package/tools/tests/test-agent-project-reconcile-issue-session-synthesizes-blocked-comment.sh +139 -0
- package/tools/tests/test-agent-project-reconcile-pr-blocked-host-recovery.sh +242 -0
- package/tools/tests/test-agent-project-reconcile-pr-guard-blocked-no-commit.sh +142 -0
- package/tools/tests/test-agent-project-reconcile-pr-provider-quota-schedules-provider-cooldown.sh +106 -0
- package/tools/tests/test-agent-project-reconcile-pr-session-initializes-shared-agent-home.sh +66 -0
- package/tools/tests/test-agent-project-reconcile-pr-updated-branch-noop.sh +129 -0
- package/tools/tests/test-audit-agent-worktrees-active-launch-skips-git-inspection.sh +69 -0
- package/tools/tests/test-audit-agent-worktrees-broken-worktree.sh +43 -0
- package/tools/tests/test-audit-agent-worktrees-pending-launch-owner.sh +46 -0
- package/tools/tests/test-audit-agent-worktrees-unreconciled-owner.sh +79 -0
- package/tools/tests/test-audit-issue-routing-managed-branch-globs.sh +56 -0
- package/tools/tests/test-branch-verification-guard-generated-artifacts.sh +72 -0
- package/tools/tests/test-branch-verification-guard-targeted-coverage.sh +125 -0
- package/tools/tests/test-codex-quota-manager-failure-driven-rotation.sh +178 -0
- package/tools/tests/test-codex-quota-wrapper.sh +37 -0
- package/tools/tests/test-contribution-docs.sh +18 -0
- package/tools/tests/test-control-plane-dashboard-runtime-smoke.sh +343 -0
- package/tools/tests/test-create-follow-up-issue.sh +73 -0
- package/tools/tests/test-dashboard-launchd-bootstrap.sh +55 -0
- package/tools/tests/test-flow-export-execution-env-exports-repo-id.sh +30 -0
- package/tools/tests/test-flow-export-github-cli-auth-env-prefers-git-credential.sh +48 -0
- package/tools/tests/test-flow-github-api-repo-fallback-preserves-input.sh +85 -0
- package/tools/tests/test-flow-github-api-repo-prefers-explicit-repository-id.sh +60 -0
- package/tools/tests/test-flow-github-issue-list-falls-back-to-repository-id.sh +64 -0
- package/tools/tests/test-flow-github-pr-list-falls-back-to-repository-id.sh +77 -0
- package/tools/tests/test-flow-resident-can-reuse-does-not-leak-metadata.sh +52 -0
- package/tools/tests/test-flow-resident-reap-stale-controllers.sh +63 -0
- package/tools/tests/test-flow-resolve-codex-quota-tools.sh +104 -0
- package/tools/tests/test-flow-runtime-doctor-profile-selection.sh +27 -0
- package/tools/tests/test-heartbeat-codex-pr-linked-issue-exclusion.sh +79 -0
- package/tools/tests/test-heartbeat-hooks-enqueue-resident-issue-for-idle-controller.sh +115 -0
- package/tools/tests/test-heartbeat-hooks-enqueue-resident-issue-for-live-lane-controller.sh +117 -0
- package/tools/tests/test-heartbeat-hooks-start-resident-issue-loop-claude.sh +96 -0
- package/tools/tests/test-heartbeat-hooks-start-resident-issue-loop-codex.sh +96 -0
- package/tools/tests/test-heartbeat-hooks-start-resident-issue-loop.sh +96 -0
- package/tools/tests/test-heartbeat-loop-auth-wait-does-not-consume-capacity.sh +170 -0
- package/tools/tests/test-heartbeat-loop-blocked-recovery-lane.sh +201 -0
- package/tools/tests/test-heartbeat-loop-blocked-recovery-vs-pr-reservation.sh +201 -0
- package/tools/tests/test-heartbeat-loop-idle-resident-controller-does-not-block-launches.sh +160 -0
- package/tools/tests/test-heartbeat-loop-pr-launch-dedup.sh +133 -0
- package/tools/tests/test-heartbeat-loop-provider-cooldown-suppresses-launches.sh +157 -0
- package/tools/tests/test-heartbeat-loop-reaps-stale-resident-controller.sh +181 -0
- package/tools/tests/test-heartbeat-loop-waiting-provider-resident-controller-does-not-block-launches.sh +160 -0
- package/tools/tests/test-heartbeat-ready-issues-blocked-recovery.sh +134 -0
- package/tools/tests/test-heartbeat-safe-auto-dynamic-concurrency.sh +162 -0
- package/tools/tests/test-heartbeat-safe-auto-no-tmux-sessions.sh +136 -0
- package/tools/tests/test-heartbeat-safe-auto-openclaw-skips-codex-quota.sh +139 -0
- package/tools/tests/test-heartbeat-safe-auto-quota-health-signal.sh +119 -0
- package/tools/tests/test-heartbeat-safe-auto-stale-shared-loop-pid-does-not-skip.sh +140 -0
- package/tools/tests/test-heartbeat-safe-auto-static-capacity-without-quota-cache.sh +142 -0
- package/tools/tests/test-heartbeat-safe-auto-zero-healthy-pools.sh +141 -0
- package/tools/tests/test-heartbeat-sync-issue-labels-empty-schedule.sh +65 -0
- package/tools/tests/test-heartbeat-sync-open-agent-prs-terminal-clears-running.sh +179 -0
- package/tools/tests/test-install-dashboard-launchd.sh +78 -0
- package/tools/tests/test-install-project-launchd-adds-tool-paths.sh +87 -0
- package/tools/tests/test-install-project-launchd.sh +110 -0
- package/tools/tests/test-issue-local-workspace-install-policy.sh +81 -0
- package/tools/tests/test-issue-publish-scope-guard-docs-signal.sh +70 -0
- package/tools/tests/test-issue-reconcile-hooks-success-clears-blocked.sh +36 -0
- package/tools/tests/test-kick-scheduler-requires-explicit-profile.sh +47 -0
- package/tools/tests/test-label-follow-up-issues-falls-back-to-repository-id.sh +132 -0
- package/tools/tests/test-manual-operator-entrypoints-require-explicit-profile.sh +64 -0
- package/tools/tests/test-package-funding-metadata.sh +21 -0
- package/tools/tests/test-package-public-metadata.sh +62 -0
- package/tools/tests/test-placeholder-worker-adapters.sh +38 -0
- package/tools/tests/test-pr-reconcile-hooks-refreshes-recurring-issue-checklist.sh +110 -0
- package/tools/tests/test-pr-risk-cohesive-mobile-locale-scope.sh +70 -0
- package/tools/tests/test-pr-risk-fix-label-semantics.sh +114 -0
- package/tools/tests/test-pr-risk-local-first-no-checks.sh +70 -0
- package/tools/tests/test-prepare-worktree-simple-repo-baseline.sh +67 -0
- package/tools/tests/test-profile-activate.sh +33 -0
- package/tools/tests/test-profile-adopt-allow-missing-repo.sh +68 -0
- package/tools/tests/test-profile-adopt-skip-workspace-sync-missing-file.sh +61 -0
- package/tools/tests/test-profile-adopt-syncs-anchor-and-workspace.sh +90 -0
- package/tools/tests/test-profile-smoke-collision.sh +44 -0
- package/tools/tests/test-profile-smoke-invalid-claude-config.sh +31 -0
- package/tools/tests/test-profile-smoke-invalid-provider-pool.sh +68 -0
- package/tools/tests/test-profile-smoke-repo-slug-mismatch.sh +36 -0
- package/tools/tests/test-profile-smoke.sh +45 -0
- package/tools/tests/test-project-init-force-and-skip-sync.sh +61 -0
- package/tools/tests/test-project-init-repo-slug-mismatch.sh +29 -0
- package/tools/tests/test-project-init.sh +66 -0
- package/tools/tests/test-project-launchd-bootstrap.sh +66 -0
- package/tools/tests/test-project-remove.sh +150 -0
- package/tools/tests/test-project-runtime-supervisor.sh +47 -0
- package/tools/tests/test-project-runtimectl-launchd.sh +115 -0
- package/tools/tests/test-project-runtimectl-missing-profile.sh +54 -0
- package/tools/tests/test-project-runtimectl-start-falls-back-to-bootstrap.sh +108 -0
- package/tools/tests/test-project-runtimectl-status-reports-supervisor-as-heartbeat-parent.sh +95 -0
- package/tools/tests/test-project-runtimectl-status-supervisor-running.sh +59 -0
- package/tools/tests/test-project-runtimectl-stop-cancels-pending-kick.sh +85 -0
- package/tools/tests/test-project-runtimectl-stop-clears-running-labels.sh +78 -0
- package/tools/tests/test-project-runtimectl.sh +212 -0
- package/tools/tests/test-provider-cooldown-state-prefers-runtime-worker-context.sh +39 -0
- package/tools/tests/test-provider-cooldown-state.sh +59 -0
- package/tools/tests/test-public-repo-docs.sh +159 -0
- package/tools/tests/test-reconcile-pr-worker-acp-config-routing.sh +75 -0
- package/tools/tests/test-render-dashboard-snapshot.sh +149 -0
- package/tools/tests/test-render-flow-config-demo-profile.sh +36 -0
- package/tools/tests/test-render-flow-config-provider-pool-fallback.sh +81 -0
- package/tools/tests/test-render-flow-config.sh +52 -0
- package/tools/tests/test-run-codex-task-claude-routing.sh +125 -0
- package/tools/tests/test-run-codex-task-codex-resident-routing.sh +108 -0
- package/tools/tests/test-run-codex-task-kilo-routing.sh +98 -0
- package/tools/tests/test-run-codex-task-openclaw-resident-routing.sh +117 -0
- package/tools/tests/test-run-codex-task-openclaw-routing.sh +113 -0
- package/tools/tests/test-run-codex-task-opencode-routing.sh +98 -0
- package/tools/tests/test-run-codex-task-provider-pool-fallback-routing.sh +146 -0
- package/tools/tests/test-scaffold-profile.sh +108 -0
- package/tools/tests/test-serve-dashboard.sh +93 -0
- package/tools/tests/test-start-issue-worker-blocked-context.sh +129 -0
- package/tools/tests/test-start-issue-worker-blocks-complete-recurring-checklist.sh +189 -0
- package/tools/tests/test-start-issue-worker-local-install-routing.sh +157 -0
- package/tools/tests/test-start-issue-worker-profile-template-routing.sh +149 -0
- package/tools/tests/test-start-issue-worker-recurring-resident-reuse-codex.sh +212 -0
- package/tools/tests/test-start-issue-worker-recurring-resident-reuse.sh +219 -0
- package/tools/tests/test-start-issue-worker-renders-verification-snippet.sh +155 -0
- package/tools/tests/test-start-issue-worker-resident-reuse-falls-back-to-new-worktree.sh +199 -0
- package/tools/tests/test-start-pr-fix-worker-host-blocker-context.sh +275 -0
- package/tools/tests/test-start-resident-issue-loop-adopts-next-recurring-issue.sh +185 -0
- package/tools/tests/test-start-resident-issue-loop-clears-pending-while-waiting-due.sh +152 -0
- package/tools/tests/test-start-resident-issue-loop-consumes-queued-lease.sh +186 -0
- package/tools/tests/test-start-resident-issue-loop-fails-over-provider-pool.sh +212 -0
- package/tools/tests/test-start-resident-issue-loop-immediate-cycles.sh +148 -0
- package/tools/tests/test-start-resident-issue-loop-waits-for-provider.sh +194 -0
- package/tools/tests/test-start-resident-issue-loop-waits-for-terminal-reconcile-status.sh +198 -0
- package/tools/tests/test-start-resident-issue-loop-yields-to-live-lane-controller.sh +145 -0
- package/tools/tests/test-sync-pr-labels-fix-lane-uses-repair-queued.sh +67 -0
- package/tools/tests/test-sync-recurring-issue-checklist-backfills-workflow-complete-blocker.sh +70 -0
- package/tools/tests/test-sync-recurring-issue-checklist.sh +95 -0
- package/tools/tests/test-sync-shared-agent-home-local-source-root.sh +66 -0
- package/tools/tests/test-sync-shared-agent-home-preserves-unrelated-workflow-catalog-skill.sh +47 -0
- package/tools/tests/test-test-smoke.sh +86 -0
- package/tools/tests/test-uninstall-project-launchd.sh +37 -0
- package/tools/tests/test-update-github-labels-prefers-sibling-helper.sh +49 -0
- package/tools/tests/test-workflow-catalog.sh +43 -0
- package/tools/vendor/codex-quota/LICENSE +21 -0
- package/tools/vendor/codex-quota/README.md +459 -0
- package/tools/vendor/codex-quota/codex-quota.js +261 -0
- package/tools/vendor/codex-quota/lib/claude-accounts.js +226 -0
- package/tools/vendor/codex-quota/lib/claude-oauth.js +174 -0
- package/tools/vendor/codex-quota/lib/claude-tokens.js +471 -0
- package/tools/vendor/codex-quota/lib/claude-usage.js +929 -0
- package/tools/vendor/codex-quota/lib/codex-accounts.js +205 -0
- package/tools/vendor/codex-quota/lib/codex-tokens.js +326 -0
- package/tools/vendor/codex-quota/lib/codex-usage.js +32 -0
- package/tools/vendor/codex-quota/lib/color.js +72 -0
- package/tools/vendor/codex-quota/lib/constants.js +57 -0
- package/tools/vendor/codex-quota/lib/container.js +143 -0
- package/tools/vendor/codex-quota/lib/display.js +1111 -0
- package/tools/vendor/codex-quota/lib/fs.js +63 -0
- package/tools/vendor/codex-quota/lib/handlers.js +2060 -0
- package/tools/vendor/codex-quota/lib/jwt.js +33 -0
- package/tools/vendor/codex-quota/lib/oauth.js +486 -0
- package/tools/vendor/codex-quota/lib/paths.js +34 -0
- package/tools/vendor/codex-quota/lib/prompts.js +44 -0
- package/tools/vendor/codex-quota/lib/sync.js +1438 -0
- package/tools/vendor/codex-quota/lib/token-match.js +96 -0
- package/tools/vendor/codex-quota-manager/scripts/auto-switch.sh +500 -0
- package/tools/vendor/codex-quota-manager/scripts/batch-add.sh +123 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
# codex-quota
|
|
2
|
+
|
|
3
|
+
Multi-account manager for OpenAI Codex CLI and OpenCode. Add, switch, list, and remove accounts with OAuth browser authentication. Seamlessly switch between both tools with shared credentials.
|
|
4
|
+
|
|
5
|
+
Zero dependencies - uses Node.js built-ins only.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g codex-quota
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or with bun:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun add -g codex-quota
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
After installation, both `codex-quota` and `cq` commands are available.
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Add a new account (opens browser for OAuth)
|
|
25
|
+
codex-quota codex add personal
|
|
26
|
+
|
|
27
|
+
# Add a Claude credential (interactive)
|
|
28
|
+
codex-quota claude add work
|
|
29
|
+
|
|
30
|
+
# Check quota for all accounts
|
|
31
|
+
codex-quota
|
|
32
|
+
|
|
33
|
+
# Switch active Codex account
|
|
34
|
+
codex-quota codex switch personal
|
|
35
|
+
|
|
36
|
+
# Switch Claude credentials
|
|
37
|
+
codex-quota claude switch work
|
|
38
|
+
|
|
39
|
+
# Sync activeLabel to CLI auth files
|
|
40
|
+
codex-quota codex sync
|
|
41
|
+
codex-quota claude sync
|
|
42
|
+
|
|
43
|
+
# Preview sync without writing files
|
|
44
|
+
codex-quota codex sync --dry-run
|
|
45
|
+
codex-quota claude sync --dry-run
|
|
46
|
+
|
|
47
|
+
# List accounts
|
|
48
|
+
codex-quota codex list
|
|
49
|
+
codex-quota claude list
|
|
50
|
+
|
|
51
|
+
# Remove an account
|
|
52
|
+
codex-quota codex remove old-account
|
|
53
|
+
codex-quota claude remove old-account
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Commands
|
|
57
|
+
|
|
58
|
+
Run `codex-quota` with no namespace to check combined Codex + Claude usage.
|
|
59
|
+
|
|
60
|
+
### codex quota
|
|
61
|
+
|
|
62
|
+
Check usage quota for Codex accounts.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
codex-quota codex quota # All Codex accounts
|
|
66
|
+
codex-quota codex quota personal # Specific account
|
|
67
|
+
codex-quota codex quota --json # JSON output
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### claude quota
|
|
71
|
+
|
|
72
|
+
Check usage quota for Claude accounts.
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
codex-quota claude quota # All Claude accounts
|
|
76
|
+
codex-quota claude quota work # Specific credential
|
|
77
|
+
codex-quota claude quota --json # JSON output
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### codex add
|
|
81
|
+
|
|
82
|
+
Add a new Codex account via OAuth browser authentication.
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
codex-quota codex add # Label derived from email
|
|
86
|
+
codex-quota codex add work # With explicit label
|
|
87
|
+
codex-quota codex add --no-browser # Print URL (for SSH/headless)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### claude add
|
|
91
|
+
|
|
92
|
+
Add a Claude credential interactively.
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
codex-quota claude add # Prompt for label + credentials
|
|
96
|
+
codex-quota claude add work # With explicit label
|
|
97
|
+
codex-quota claude add work --json # JSON output
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### codex switch
|
|
101
|
+
|
|
102
|
+
Switch the active account for Codex CLI, OpenCode, and pi.
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
codex-quota codex switch personal
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
When you run `codex switch`:
|
|
109
|
+
|
|
110
|
+
1. **Codex CLI** - Updates `~/.codex/auth.json` with the selected account tokens
|
|
111
|
+
2. **OpenCode** - If `~/.local/share/opencode/auth.json` exists, updates the `openai` provider entry
|
|
112
|
+
3. **pi** - If `~/.pi/agent/auth.json` exists, updates the `openai-codex` provider entry
|
|
113
|
+
|
|
114
|
+
It also updates `activeLabel` in `~/.codex-accounts.json` when available.
|
|
115
|
+
|
|
116
|
+
### claude switch
|
|
117
|
+
|
|
118
|
+
Switch Claude Code, OpenCode, and pi to a stored Claude credential.
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
codex-quota claude switch work
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
This updates `activeLabel` in `~/.claude-accounts.json` when available. OAuth-based
|
|
125
|
+
credentials are required to update CLI auth files.
|
|
126
|
+
|
|
127
|
+
### codex list
|
|
128
|
+
|
|
129
|
+
List all Codex accounts from all sources with status indicators.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
codex-quota codex list
|
|
133
|
+
codex-quota codex list --json
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Output shows:
|
|
137
|
+
- `*` = active account (from `activeLabel`)
|
|
138
|
+
- `~` = CLI auth account when it diverges from `activeLabel`
|
|
139
|
+
- Email, plan type, token expiry
|
|
140
|
+
- Source file for each account
|
|
141
|
+
|
|
142
|
+
If CLI auth diverges from the tracked `activeLabel`, `list` and `quota` print a warning and
|
|
143
|
+
suggest `codex-quota codex sync` to realign.
|
|
144
|
+
|
|
145
|
+
### claude list
|
|
146
|
+
|
|
147
|
+
List Claude credentials from `CLAUDE_ACCOUNTS` or `~/.claude-accounts.json`.
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
codex-quota claude list
|
|
151
|
+
codex-quota claude list --json
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Output shows:
|
|
155
|
+
- `*` = active account (from `activeLabel`)
|
|
156
|
+
- Source file for each credential
|
|
157
|
+
|
|
158
|
+
For OAuth-based accounts, `list` and `quota` warn when stored tokens diverge from the
|
|
159
|
+
`activeLabel` account. Session-key-only accounts are skipped.
|
|
160
|
+
|
|
161
|
+
### codex remove
|
|
162
|
+
|
|
163
|
+
Remove a Codex account from storage.
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
codex-quota codex remove old-account
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Note: Accounts from `CODEX_ACCOUNTS` env var cannot be removed via CLI.
|
|
170
|
+
|
|
171
|
+
### claude remove
|
|
172
|
+
|
|
173
|
+
Remove a Claude credential from storage.
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
codex-quota claude remove old-account
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Note: Accounts from `CLAUDE_ACCOUNTS` env var cannot be removed via CLI.
|
|
180
|
+
|
|
181
|
+
### codex sync
|
|
182
|
+
|
|
183
|
+
Sync the `activeLabel` Codex account to CLI auth files.
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
codex-quota codex sync
|
|
187
|
+
codex-quota codex sync --dry-run
|
|
188
|
+
codex-quota codex sync --json
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
This updates:
|
|
192
|
+
1. `~/.codex/auth.json`
|
|
193
|
+
2. `~/.local/share/opencode/auth.json` (if it exists)
|
|
194
|
+
3. `~/.pi/agent/auth.json` (if it exists)
|
|
195
|
+
|
|
196
|
+
### claude sync
|
|
197
|
+
|
|
198
|
+
Sync the `activeLabel` Claude account to CLI auth files.
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
codex-quota claude sync
|
|
202
|
+
codex-quota claude sync --dry-run
|
|
203
|
+
codex-quota claude sync --json
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Only OAuth-based Claude accounts can be synced. Session-key-only accounts are skipped with
|
|
207
|
+
a warning.
|
|
208
|
+
|
|
209
|
+
## Options
|
|
210
|
+
|
|
211
|
+
| Option | Description |
|
|
212
|
+
|--------|-------------|
|
|
213
|
+
| `--json` | Output in JSON format |
|
|
214
|
+
| `--dry-run` | Preview sync without writing files |
|
|
215
|
+
| `--no-browser` | Print auth URL instead of opening browser |
|
|
216
|
+
| `--no-color` | Disable colored output |
|
|
217
|
+
| `--version, -v` | Show version number |
|
|
218
|
+
| `--help, -h` | Show help |
|
|
219
|
+
|
|
220
|
+
## Account Sources
|
|
221
|
+
|
|
222
|
+
Accounts are loaded from these locations (in order). Read/write indicates whether the CLI
|
|
223
|
+
reads from or writes to each path.
|
|
224
|
+
|
|
225
|
+
| Source | Purpose | Read | Write |
|
|
226
|
+
|--------|---------|------|-------|
|
|
227
|
+
| `CODEX_ACCOUNTS` env var | JSON array of accounts | Yes | No |
|
|
228
|
+
| `~/.codex-accounts.json` | Primary multi-account file (shared with OpenCode) | Yes | Yes (`add`, `remove`) |
|
|
229
|
+
| `~/.opencode/openai-codex-auth-accounts.json` | OpenCode accounts | Yes | No |
|
|
230
|
+
| `~/.codex/auth.json` | Codex CLI single-account (label `codex-cli`) | Yes | Yes (`switch`) |
|
|
231
|
+
| `~/.local/share/opencode/auth.json` | OpenCode auth file (`openai` provider) | No | Yes (`switch` if it exists) |
|
|
232
|
+
| `~/.pi/agent/auth.json` | pi auth file (`openai-codex` provider) | No | Yes (`switch` if it exists) |
|
|
233
|
+
|
|
234
|
+
New accounts added via `codex-quota codex add` are saved to `~/.codex-accounts.json`, which is
|
|
235
|
+
shared with OpenCode.
|
|
236
|
+
|
|
237
|
+
Claude sources (in order):
|
|
238
|
+
|
|
239
|
+
| Source | Purpose | Read | Write |
|
|
240
|
+
|--------|---------|------|-------|
|
|
241
|
+
| `CLAUDE_ACCOUNTS` env var | JSON array of credentials | Yes | No |
|
|
242
|
+
| `~/.claude-accounts.json` | Claude multi-account file | Yes | Yes (`add`, `remove`) |
|
|
243
|
+
| `~/.claude/.credentials.json` | Claude Code credentials | Yes | Yes (`switch`, `sync`) |
|
|
244
|
+
| `~/.local/share/opencode/auth.json` | OpenCode auth file (`anthropic` provider) | No | Yes (`switch`, `sync` if it exists) |
|
|
245
|
+
| `~/.pi/agent/auth.json` | pi auth file (`anthropic` provider) | No | Yes (`switch`, `sync` if it exists) |
|
|
246
|
+
|
|
247
|
+
## Multi-Account JSON Schema
|
|
248
|
+
|
|
249
|
+
File: `~/.codex-accounts.json`
|
|
250
|
+
|
|
251
|
+
```json
|
|
252
|
+
{
|
|
253
|
+
"schemaVersion": 1,
|
|
254
|
+
"activeLabel": "personal",
|
|
255
|
+
"accounts": [
|
|
256
|
+
{
|
|
257
|
+
"label": "personal",
|
|
258
|
+
"accountId": "chatgpt-account-uuid",
|
|
259
|
+
"access": "access-token",
|
|
260
|
+
"refresh": "refresh-token",
|
|
261
|
+
"idToken": "id-token-or-null",
|
|
262
|
+
"expires": 1234567890000
|
|
263
|
+
}
|
|
264
|
+
]
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
| Field | Type | Description |
|
|
269
|
+
|-------|------|-------------|
|
|
270
|
+
| `schemaVersion` | number | Schema version marker (root field) |
|
|
271
|
+
| `activeLabel` | string\|null | Active account label (root field) |
|
|
272
|
+
| `label` | string | Unique identifier for the account |
|
|
273
|
+
| `accountId` | string | ChatGPT account UUID |
|
|
274
|
+
| `access` | string | OAuth access token |
|
|
275
|
+
| `refresh` | string | OAuth refresh token |
|
|
276
|
+
| `idToken` | string\|null | OAuth ID token (optional, for email extraction) |
|
|
277
|
+
| `expires` | number | Token expiry timestamp in milliseconds |
|
|
278
|
+
|
|
279
|
+
Root-level fields are preserved on write; unknown root fields are kept intact.
|
|
280
|
+
|
|
281
|
+
Claude multi-account files (`~/.claude-accounts.json`) use the same root fields
|
|
282
|
+
(`schemaVersion`, `activeLabel`) and store account entries that include a
|
|
283
|
+
`sessionKey` or OAuth tokens.
|
|
284
|
+
|
|
285
|
+
## OAuth Flow
|
|
286
|
+
|
|
287
|
+
The `codex add` command uses OAuth 2.0 with PKCE for secure browser authentication:
|
|
288
|
+
|
|
289
|
+
1. Generates PKCE code verifier and challenge
|
|
290
|
+
2. Starts local callback server on `http://127.0.0.1:1455`
|
|
291
|
+
3. Opens browser to OpenAI authorization page
|
|
292
|
+
4. User authenticates in browser
|
|
293
|
+
5. Callback server receives authorization code
|
|
294
|
+
6. Exchanges code for tokens using PKCE verifier
|
|
295
|
+
7. Saves tokens to `~/.codex-accounts.json`
|
|
296
|
+
|
|
297
|
+
### Headless/SSH Mode
|
|
298
|
+
|
|
299
|
+
In SSH sessions or headless environments (detected via `SSH_CLIENT`, `SSH_TTY`, or missing `DISPLAY`), the auth URL is printed instead of opening a browser:
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
codex-quota codex add --no-browser
|
|
303
|
+
# Prints: Open this URL in your browser: https://auth.openai.com/authorize?...
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Copy the URL to a browser on another machine, complete authentication, and the callback will be received by the local server.
|
|
307
|
+
|
|
308
|
+
## Troubleshooting
|
|
309
|
+
|
|
310
|
+
### Port 1455 in use
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
Error: Port 1455 is in use. Close other codex-quota instances and retry.
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Another process is using port 1455. Check for:
|
|
317
|
+
- Other `codex-quota codex add` commands running
|
|
318
|
+
- OpenCode or Codex CLI auth processes
|
|
319
|
+
|
|
320
|
+
Find and kill the process:
|
|
321
|
+
```bash
|
|
322
|
+
lsof -i :1455
|
|
323
|
+
kill <pid>
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### SSH/Headless authentication
|
|
327
|
+
|
|
328
|
+
If browser doesn't open in SSH session:
|
|
329
|
+
|
|
330
|
+
1. Use `--no-browser` flag: `codex-quota codex add --no-browser`
|
|
331
|
+
2. Copy the printed URL to a browser on another machine
|
|
332
|
+
3. Complete authentication in browser
|
|
333
|
+
4. The callback is received by the server running over SSH
|
|
334
|
+
|
|
335
|
+
### Token refresh failures
|
|
336
|
+
|
|
337
|
+
If token refresh fails:
|
|
338
|
+
```
|
|
339
|
+
Error: Failed to refresh token. Re-authenticate with 'codex-quota codex add'.
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
The refresh token may have expired. Add the account again:
|
|
343
|
+
```bash
|
|
344
|
+
codex-quota codex remove expired-account
|
|
345
|
+
codex-quota codex add new-label
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Environment variable accounts
|
|
349
|
+
|
|
350
|
+
Accounts from `CODEX_ACCOUNTS` env var cannot be removed via CLI:
|
|
351
|
+
```
|
|
352
|
+
Error: Cannot remove account from CODEX_ACCOUNTS env var. Modify the env var directly.
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Edit your shell configuration to remove the account from the env var.
|
|
356
|
+
|
|
357
|
+
## JSON Output
|
|
358
|
+
|
|
359
|
+
All commands support `--json` for scripting:
|
|
360
|
+
|
|
361
|
+
```bash
|
|
362
|
+
# Quota (combined)
|
|
363
|
+
codex-quota --json
|
|
364
|
+
# {"codex":[{"label":"personal","email":"user@example.com","usage":{...}}],"claude":[...]}
|
|
365
|
+
|
|
366
|
+
# List (Codex)
|
|
367
|
+
codex-quota codex list --json
|
|
368
|
+
# {"accounts":[{"label":"personal","isActive":true,"email":"...","source":"..."}]}
|
|
369
|
+
|
|
370
|
+
# Add (Codex, success)
|
|
371
|
+
codex-quota codex add work --json
|
|
372
|
+
# {"success":true,"label":"work","email":"user@example.com","accountId":"...","source":"~/.codex-accounts.json"}
|
|
373
|
+
|
|
374
|
+
# Switch (Codex)
|
|
375
|
+
codex-quota codex switch personal --json
|
|
376
|
+
# {"success":true,"label":"personal","email":"...","authPath":"~/.codex/auth.json"}
|
|
377
|
+
|
|
378
|
+
# Sync (Codex)
|
|
379
|
+
codex-quota codex sync --json
|
|
380
|
+
# {"success":true,"activeLabel":"work","updated":["~/.codex/auth.json",...],"skipped":[...]}
|
|
381
|
+
|
|
382
|
+
# Errors include structured data
|
|
383
|
+
codex-quota codex switch nonexistent --json
|
|
384
|
+
# {"success":false,"error":"Account not found","availableLabels":["personal","work"]}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
## Claude Code Usage (Optional)
|
|
388
|
+
|
|
389
|
+
Use the `claude` namespace to check Claude usage alongside OpenAI quotas:
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
codex-quota claude quota
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
If multiple Claude accounts are configured, each account is fetched and displayed separately.
|
|
396
|
+
|
|
397
|
+
To add a Claude credential interactively:
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
codex-quota claude add
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
This uses your local Claude session to call:
|
|
404
|
+
- `https://claude.ai/api/organizations`
|
|
405
|
+
- `https://claude.ai/api/organizations/{orgId}/usage`
|
|
406
|
+
- `https://claude.ai/api/organizations/{orgId}/overage_spend_limit`
|
|
407
|
+
- `https://claude.ai/api/account`
|
|
408
|
+
|
|
409
|
+
Authentication sources (in order):
|
|
410
|
+
1. `CLAUDE_ACCOUNTS` env var (JSON array or `{ accounts: [...] }`)
|
|
411
|
+
2. `~/.claude-accounts.json` (multi-account format)
|
|
412
|
+
3. Browser cookies (Chromium/Chrome) to read `sessionKey` and `lastActiveOrg`
|
|
413
|
+
4. `~/.claude/.credentials.json` OAuth `accessToken`
|
|
414
|
+
|
|
415
|
+
Multi-account format (Claude):
|
|
416
|
+
```json
|
|
417
|
+
{
|
|
418
|
+
"accounts": [
|
|
419
|
+
{
|
|
420
|
+
"label": "personal",
|
|
421
|
+
"sessionKey": "sk-ant-oat...",
|
|
422
|
+
"cfClearance": "cf_clearance...",
|
|
423
|
+
"oauthToken": "claude-ai-access-token",
|
|
424
|
+
"orgId": "org_uuid_optional"
|
|
425
|
+
}
|
|
426
|
+
]
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Notes:
|
|
431
|
+
- Only `label` plus one of `sessionKey` or `oauthToken` is required.
|
|
432
|
+
- `cfClearance`, `orgId`, and `cookies` are optional.
|
|
433
|
+
|
|
434
|
+
Environment overrides:
|
|
435
|
+
- `CLAUDE_ACCOUNTS` to supply multi-account JSON directly
|
|
436
|
+
- `CLAUDE_CREDENTIALS_PATH` to point to a different credentials file
|
|
437
|
+
- `CLAUDE_COOKIE_DB_PATH` to point to a specific Chromium/Chrome Cookies DB
|
|
438
|
+
|
|
439
|
+
Codex overrides:
|
|
440
|
+
- `CODEX_ACCOUNTS` to supply multi-account JSON directly (read-only)
|
|
441
|
+
- `CODEX_AUTH_PATH` to point to a different Codex CLI auth file
|
|
442
|
+
- `XDG_DATA_HOME` to relocate OpenCode auth paths
|
|
443
|
+
- `PI_AUTH_PATH` to point to a different pi auth file
|
|
444
|
+
|
|
445
|
+
Notes:
|
|
446
|
+
- On Linux, cookie access requires `sqlite3` and `secret-tool` (libsecret) to decrypt cookies.
|
|
447
|
+
- For best results, keep `claude.ai` logged in within your Chromium/Chrome profile.
|
|
448
|
+
|
|
449
|
+
## Releasing
|
|
450
|
+
|
|
451
|
+
- Run `bun test` and `bun run preflight` before publishing.
|
|
452
|
+
- Bump version with `bun pm version patch|minor|major`.
|
|
453
|
+
- Dry-run the package with `bun run release:pack`.
|
|
454
|
+
- Publish with `bun run release:publish` (local publish, no provenance).
|
|
455
|
+
- Ensure the git working tree is clean.
|
|
456
|
+
|
|
457
|
+
## License
|
|
458
|
+
|
|
459
|
+
MIT
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Standalone Codex quota checker for multiple OAuth accounts
|
|
5
|
+
* Zero dependencies - uses Node.js built-ins only
|
|
6
|
+
*
|
|
7
|
+
* This is a thin entry point. All logic lives in lib/ modules.
|
|
8
|
+
* Barrel re-exports below maintain backward compatibility for tests and consumers.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { realpathSync } from "node:fs";
|
|
12
|
+
|
|
13
|
+
// ─── Imports from lib modules ────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
import { PRIMARY_CMD, MULTI_ACCOUNT_PATHS, CODEX_CLI_AUTH_PATH, CLAUDE_MULTI_ACCOUNT_PATHS } from "./lib/constants.js";
|
|
16
|
+
import { GREEN, RED, YELLOW, setNoColorFlag, supportsColor, colorize, getPackageVersion } from "./lib/color.js";
|
|
17
|
+
import { decodeJWT, extractAccountId, extractProfile } from "./lib/jwt.js";
|
|
18
|
+
import {
|
|
19
|
+
printHelp, printHelpCodex, printHelpClaude,
|
|
20
|
+
printHelpAdd, printHelpCodexReauth, printHelpSwitch, printHelpCodexSync,
|
|
21
|
+
printHelpList, printHelpRemove, printHelpQuota,
|
|
22
|
+
printHelpClaudeAdd, printHelpClaudeReauth, printHelpClaudeSwitch, printHelpClaudeSync,
|
|
23
|
+
printHelpClaudeList, printHelpClaudeRemove, printHelpClaudeQuota,
|
|
24
|
+
} from "./lib/display.js";
|
|
25
|
+
import { handleCodex, handleClaude, handleQuota } from "./lib/handlers.js";
|
|
26
|
+
|
|
27
|
+
// ─── Main ────────────────────────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
async function main() {
|
|
30
|
+
const args = process.argv.slice(2);
|
|
31
|
+
|
|
32
|
+
// Parse flags
|
|
33
|
+
const flags = {
|
|
34
|
+
json: args.includes("--json"),
|
|
35
|
+
noBrowser: args.includes("--no-browser"),
|
|
36
|
+
noColor: args.includes("--no-color"),
|
|
37
|
+
oauth: args.includes("--oauth"),
|
|
38
|
+
manual: args.includes("--manual"),
|
|
39
|
+
dryRun: args.includes("--dry-run"),
|
|
40
|
+
local: args.includes("--local"),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Set global noColorFlag for supportsColor() function
|
|
44
|
+
setNoColorFlag(flags.noColor);
|
|
45
|
+
|
|
46
|
+
const legacyFlagUsed = args.includes("--claude") || args.includes("--codex");
|
|
47
|
+
if (legacyFlagUsed) {
|
|
48
|
+
console.error(colorize("Error: --claude/--codex flags were replaced by namespaces.", RED));
|
|
49
|
+
console.error(`Use '${PRIMARY_CMD} claude' or '${PRIMARY_CMD} codex' instead.`);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Extract non-flag arguments
|
|
54
|
+
const nonFlagArgs = args.filter(a => !a.startsWith("--") && a !== "-h");
|
|
55
|
+
const firstArg = nonFlagArgs[0];
|
|
56
|
+
const namespace = firstArg === "codex" || firstArg === "claude" ? firstArg : null;
|
|
57
|
+
const namespaceArgs = namespace ? nonFlagArgs.slice(1) : nonFlagArgs;
|
|
58
|
+
const subcommand = namespace ? namespaceArgs[0] : null;
|
|
59
|
+
|
|
60
|
+
// Handle --version flag
|
|
61
|
+
if (args.includes("--version") || args.includes("-v")) {
|
|
62
|
+
console.log(getPackageVersion());
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const legacyCommands = ["add", "reauth", "switch", "list", "remove", "quota", "sync"];
|
|
67
|
+
if (!namespace && firstArg && legacyCommands.includes(firstArg)) {
|
|
68
|
+
console.error(colorize(`Error: '${firstArg}' now requires a namespace.`, RED));
|
|
69
|
+
console.error(`Use '${PRIMARY_CMD} codex ${firstArg}' or '${PRIMARY_CMD} claude ${firstArg}'.`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Handle --help: show main help or subcommand-specific help
|
|
74
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
75
|
+
if (!namespace) {
|
|
76
|
+
printHelp();
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (namespace === "codex") {
|
|
80
|
+
switch (subcommand) {
|
|
81
|
+
case "add": printHelpAdd(); break;
|
|
82
|
+
case "reauth": printHelpCodexReauth(); break;
|
|
83
|
+
case "switch": printHelpSwitch(); break;
|
|
84
|
+
case "sync": printHelpCodexSync(); break;
|
|
85
|
+
case "list": printHelpList(); break;
|
|
86
|
+
case "remove": printHelpRemove(); break;
|
|
87
|
+
case "quota": printHelpQuota(); break;
|
|
88
|
+
default: printHelpCodex(); break;
|
|
89
|
+
}
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
switch (subcommand) {
|
|
93
|
+
case "add": printHelpClaudeAdd(); break;
|
|
94
|
+
case "reauth": printHelpClaudeReauth(); break;
|
|
95
|
+
case "switch": printHelpClaudeSwitch(); break;
|
|
96
|
+
case "sync": printHelpClaudeSync(); break;
|
|
97
|
+
case "list": printHelpClaudeList(); break;
|
|
98
|
+
case "remove": printHelpClaudeRemove(); break;
|
|
99
|
+
case "quota": printHelpClaudeQuota(); break;
|
|
100
|
+
default: printHelpClaude(); break;
|
|
101
|
+
}
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Route to appropriate handler based on subcommand
|
|
106
|
+
if (namespace === "codex") {
|
|
107
|
+
await handleCodex(namespaceArgs, flags);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (namespace === "claude") {
|
|
111
|
+
await handleClaude(namespaceArgs, flags);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Default behavior: run combined quota command
|
|
116
|
+
await handleQuota(nonFlagArgs, flags, "all");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Only run main() when executed directly (not imported for testing)
|
|
120
|
+
function getResolvedArgv1() {
|
|
121
|
+
try {
|
|
122
|
+
const arg = process.argv[1];
|
|
123
|
+
if (!arg) return null;
|
|
124
|
+
return realpathSync(arg);
|
|
125
|
+
} catch {
|
|
126
|
+
return process.argv[1] || null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const resolvedArgv1 = getResolvedArgv1();
|
|
130
|
+
const isMain = resolvedArgv1 && (
|
|
131
|
+
import.meta.url === `file://${resolvedArgv1}` ||
|
|
132
|
+
import.meta.url === `file://${process.argv[1]}`
|
|
133
|
+
);
|
|
134
|
+
if (isMain) {
|
|
135
|
+
main().catch(e => {
|
|
136
|
+
console.error(e.message);
|
|
137
|
+
process.exit(1);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ─── Barrel re-exports for backward compatibility (tests + external consumers) ──
|
|
142
|
+
|
|
143
|
+
// Account loading functions
|
|
144
|
+
export {
|
|
145
|
+
loadAccountsFromEnv,
|
|
146
|
+
loadAccountsFromFile,
|
|
147
|
+
loadAccountFromCodexCli,
|
|
148
|
+
loadAllAccounts,
|
|
149
|
+
loadAllAccountsNoDedup,
|
|
150
|
+
findAccountByLabel,
|
|
151
|
+
getAllLabels,
|
|
152
|
+
isValidAccount,
|
|
153
|
+
} from "./lib/codex-accounts.js";
|
|
154
|
+
|
|
155
|
+
export {
|
|
156
|
+
loadClaudeAccountsFromEnv,
|
|
157
|
+
loadClaudeAccountsFromFile,
|
|
158
|
+
loadClaudeAccounts,
|
|
159
|
+
isValidClaudeAccount,
|
|
160
|
+
} from "./lib/claude-accounts.js";
|
|
161
|
+
|
|
162
|
+
// Deduplication functions
|
|
163
|
+
export { deduplicateAccountsByEmail } from "./lib/codex-accounts.js";
|
|
164
|
+
export { deduplicateClaudeOAuthAccounts } from "./lib/claude-usage.js";
|
|
165
|
+
|
|
166
|
+
// Claude OAuth functions
|
|
167
|
+
export {
|
|
168
|
+
loadClaudeOAuthFromClaudeCode,
|
|
169
|
+
loadClaudeOAuthFromOpenCode,
|
|
170
|
+
loadClaudeOAuthFromEnv,
|
|
171
|
+
loadAllClaudeOAuthAccounts,
|
|
172
|
+
fetchClaudeOAuthUsage,
|
|
173
|
+
fetchClaudeOAuthUsageForAccount,
|
|
174
|
+
} from "./lib/claude-usage.js";
|
|
175
|
+
|
|
176
|
+
export {
|
|
177
|
+
ensureFreshClaudeOAuthToken,
|
|
178
|
+
persistClaudeOAuthTokens,
|
|
179
|
+
refreshClaudeToken,
|
|
180
|
+
} from "./lib/claude-tokens.js";
|
|
181
|
+
|
|
182
|
+
export {
|
|
183
|
+
ensureFreshToken,
|
|
184
|
+
persistOpenAiOAuthTokens,
|
|
185
|
+
} from "./lib/codex-tokens.js";
|
|
186
|
+
|
|
187
|
+
// OAuth PKCE utilities
|
|
188
|
+
export {
|
|
189
|
+
generatePKCE,
|
|
190
|
+
generateState,
|
|
191
|
+
buildAuthUrl,
|
|
192
|
+
checkPortAvailable,
|
|
193
|
+
isHeadlessEnvironment,
|
|
194
|
+
openBrowser,
|
|
195
|
+
startCallbackServer,
|
|
196
|
+
exchangeCodeForTokens,
|
|
197
|
+
} from "./lib/oauth.js";
|
|
198
|
+
|
|
199
|
+
// Claude OAuth browser flow
|
|
200
|
+
export {
|
|
201
|
+
buildClaudeAuthUrl,
|
|
202
|
+
parseClaudeCodeState,
|
|
203
|
+
exchangeClaudeCodeForTokens,
|
|
204
|
+
handleClaudeOAuthFlow,
|
|
205
|
+
} from "./lib/claude-oauth.js";
|
|
206
|
+
|
|
207
|
+
// JWT utilities
|
|
208
|
+
export { decodeJWT, extractAccountId, extractProfile } from "./lib/jwt.js";
|
|
209
|
+
|
|
210
|
+
// Divergence helpers (for testing)
|
|
211
|
+
export {
|
|
212
|
+
detectCodexDivergence,
|
|
213
|
+
detectClaudeDivergence,
|
|
214
|
+
findFresherOpenAiOAuthStore,
|
|
215
|
+
findFresherClaudeOAuthStore,
|
|
216
|
+
readOpencodeOpenAiOauthStore,
|
|
217
|
+
readPiOpenAiOauthStore,
|
|
218
|
+
readCodexCliOpenAiOauthStore,
|
|
219
|
+
getActiveAccountId,
|
|
220
|
+
getActiveAccountInfo,
|
|
221
|
+
handleCodexSync,
|
|
222
|
+
handleClaudeSync,
|
|
223
|
+
} from "./lib/sync.js";
|
|
224
|
+
|
|
225
|
+
// Display helpers (for testing)
|
|
226
|
+
export {
|
|
227
|
+
shortenPath,
|
|
228
|
+
formatExpiryStatus,
|
|
229
|
+
normalizePercentUsed,
|
|
230
|
+
parseClaudeUtilizationWindow,
|
|
231
|
+
drawBox,
|
|
232
|
+
printHelp,
|
|
233
|
+
printHelpAdd,
|
|
234
|
+
printHelpCodexReauth,
|
|
235
|
+
printHelpClaude,
|
|
236
|
+
printHelpClaudeAdd,
|
|
237
|
+
printHelpClaudeReauth,
|
|
238
|
+
printHelpClaudeSync,
|
|
239
|
+
printHelpSwitch,
|
|
240
|
+
printHelpCodexSync,
|
|
241
|
+
printHelpList,
|
|
242
|
+
printHelpRemove,
|
|
243
|
+
printHelpQuota,
|
|
244
|
+
} from "./lib/display.js";
|
|
245
|
+
|
|
246
|
+
// Subcommand handlers (for testing)
|
|
247
|
+
export {
|
|
248
|
+
handleSwitch,
|
|
249
|
+
handleCodexReauth,
|
|
250
|
+
handleRemove,
|
|
251
|
+
handleClaudeAdd,
|
|
252
|
+
handleClaudeReauth,
|
|
253
|
+
handleClaudeSwitch,
|
|
254
|
+
handleClaudeRemove,
|
|
255
|
+
} from "./lib/handlers.js";
|
|
256
|
+
|
|
257
|
+
// Color utilities
|
|
258
|
+
export { supportsColor, colorize, setNoColorFlag } from "./lib/color.js";
|
|
259
|
+
|
|
260
|
+
// Constants (for testing)
|
|
261
|
+
export { MULTI_ACCOUNT_PATHS, CODEX_CLI_AUTH_PATH, PRIMARY_CMD, CLAUDE_MULTI_ACCOUNT_PATHS } from "./lib/constants.js";
|