@iislee/opencodex 2.11.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 +225 -0
- package/assets/architecture.png +0 -0
- package/assets/banner.png +0 -0
- package/assets/claude-code-models.gif +0 -0
- package/assets/codex-app-picker.png +0 -0
- package/bin/ocx.mjs +451 -0
- package/bin/package-main.mjs +9 -0
- package/gui/dist/assets/index-DTpMHS4F.js +67 -0
- package/gui/dist/assets/index-ZNVDE3C7.css +1 -0
- package/gui/dist/favicon.png +0 -0
- package/gui/dist/icons.svg +24 -0
- package/gui/dist/index.html +25 -0
- package/gui/dist/logo.png +0 -0
- package/gui/dist/provider-icons/alibaba-color.svg +1 -0
- package/gui/dist/provider-icons/antigravity-color.svg +1 -0
- package/gui/dist/provider-icons/antigravity.svg +1 -0
- package/gui/dist/provider-icons/claude-color.svg +1 -0
- package/gui/dist/provider-icons/claude.svg +1 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -0
- package/gui/dist/provider-icons/copilot.svg +1 -0
- package/gui/dist/provider-icons/cursor-color.svg +2 -0
- package/gui/dist/provider-icons/cursor.svg +2 -0
- package/gui/dist/provider-icons/deepseek-color.svg +1 -0
- package/gui/dist/provider-icons/discord.svg +1 -0
- package/gui/dist/provider-icons/firepass-color.svg +1 -0
- package/gui/dist/provider-icons/fireworks-color.svg +1 -0
- package/gui/dist/provider-icons/gemini-color.svg +1 -0
- package/gui/dist/provider-icons/gemini.svg +1 -0
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
- package/gui/dist/provider-icons/grok-color.svg +1 -0
- package/gui/dist/provider-icons/grok.svg +1 -0
- package/gui/dist/provider-icons/groq-color.svg +1 -0
- package/gui/dist/provider-icons/huggingface-color.svg +1 -0
- package/gui/dist/provider-icons/kimi-color.svg +1 -0
- package/gui/dist/provider-icons/kiro-color.svg +15 -0
- package/gui/dist/provider-icons/kiro.svg +14 -0
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
- package/gui/dist/provider-icons/mistral-color.svg +1 -0
- package/gui/dist/provider-icons/moonshot-color.svg +1 -0
- package/gui/dist/provider-icons/nvidia-color.svg +1 -0
- package/gui/dist/provider-icons/ollama-color.svg +1 -0
- package/gui/dist/provider-icons/openai.svg +1 -0
- package/gui/dist/provider-icons/opencode.svg +1 -0
- package/gui/dist/provider-icons/openrouter-color.svg +1 -0
- package/gui/dist/provider-icons/pi.svg +21 -0
- package/gui/dist/provider-icons/qianfan-color.svg +1 -0
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
- package/gui/dist/provider-icons/telegram.svg +1 -0
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/vllm-color.svg +1 -0
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
- package/package.json +102 -0
- package/src/AGENTS.md +28 -0
- package/src/adapters/anthropic-image-guard.ts +251 -0
- package/src/adapters/anthropic-image-normalize.ts +518 -0
- package/src/adapters/anthropic.ts +1003 -0
- package/src/adapters/azure.ts +36 -0
- package/src/adapters/base.ts +72 -0
- package/src/adapters/client-fingerprint.ts +59 -0
- package/src/adapters/cursor/arg-codec.ts +38 -0
- package/src/adapters/cursor/arg-normalize.ts +104 -0
- package/src/adapters/cursor/cursor-errors.ts +165 -0
- package/src/adapters/cursor/discovery.ts +276 -0
- package/src/adapters/cursor/effort-map.ts +127 -0
- package/src/adapters/cursor/exec-policy.ts +88 -0
- package/src/adapters/cursor/framing.ts +211 -0
- package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
- package/src/adapters/cursor/kv-store.ts +52 -0
- package/src/adapters/cursor/live-models.ts +153 -0
- package/src/adapters/cursor/live-smoke-gate.ts +41 -0
- package/src/adapters/cursor/live-transport.ts +1214 -0
- package/src/adapters/cursor/mcp-config.ts +42 -0
- package/src/adapters/cursor/mcp-manager.ts +333 -0
- package/src/adapters/cursor/message-mapper.ts +49 -0
- package/src/adapters/cursor/native-exec-common.ts +55 -0
- package/src/adapters/cursor/native-exec-desktop.ts +184 -0
- package/src/adapters/cursor/native-exec-fs.ts +329 -0
- package/src/adapters/cursor/native-exec-mcp.ts +153 -0
- package/src/adapters/cursor/native-exec-network.ts +43 -0
- package/src/adapters/cursor/native-exec-shell.ts +548 -0
- package/src/adapters/cursor/native-exec-tools.ts +118 -0
- package/src/adapters/cursor/native-exec.ts +576 -0
- package/src/adapters/cursor/protobuf-events.ts +563 -0
- package/src/adapters/cursor/protobuf-request.ts +714 -0
- package/src/adapters/cursor/request-builder.ts +255 -0
- package/src/adapters/cursor/thread-continuity.ts +67 -0
- package/src/adapters/cursor/tool-definitions.ts +505 -0
- package/src/adapters/cursor/transport-retry.ts +132 -0
- package/src/adapters/cursor/transport.ts +57 -0
- package/src/adapters/cursor/types.ts +52 -0
- package/src/adapters/cursor.ts +196 -0
- package/src/adapters/google-antigravity-replay.ts +303 -0
- package/src/adapters/google-antigravity-wire.ts +108 -0
- package/src/adapters/google-errors.ts +85 -0
- package/src/adapters/google-http.ts +100 -0
- package/src/adapters/google-tool-schema.ts +173 -0
- package/src/adapters/google-truncation.ts +13 -0
- package/src/adapters/google-wire-compiler.ts +232 -0
- package/src/adapters/google.ts +758 -0
- package/src/adapters/identity.ts +44 -0
- package/src/adapters/image.ts +23 -0
- package/src/adapters/kiro-constants.ts +16 -0
- package/src/adapters/kiro-errors.ts +197 -0
- package/src/adapters/kiro-events.ts +179 -0
- package/src/adapters/kiro-images.ts +129 -0
- package/src/adapters/kiro-retry.ts +312 -0
- package/src/adapters/kiro-thinking.ts +96 -0
- package/src/adapters/kiro-tool-fallback.ts +36 -0
- package/src/adapters/kiro-tools.ts +215 -0
- package/src/adapters/kiro-truncation.ts +33 -0
- package/src/adapters/kiro-wire.ts +129 -0
- package/src/adapters/kiro.ts +1898 -0
- package/src/adapters/mimo-free.ts +263 -0
- package/src/adapters/openai-chat.ts +1005 -0
- package/src/adapters/openai-responses.ts +1137 -0
- package/src/adapters/run-turn-queue.ts +114 -0
- package/src/adapters/tool-catalog-nudge.ts +71 -0
- package/src/adapters/upstream-http-error.ts +48 -0
- package/src/bridge.ts +1619 -0
- package/src/chat/inbound.ts +295 -0
- package/src/chat/outbound.ts +765 -0
- package/src/claude/agents-inject.ts +243 -0
- package/src/claude/alias.ts +149 -0
- package/src/claude/auth-detect.ts +229 -0
- package/src/claude/auth-mode-migration.ts +32 -0
- package/src/claude/auth-mode.ts +62 -0
- package/src/claude/context-windows.ts +189 -0
- package/src/claude/desktop-3p-guard.ts +35 -0
- package/src/claude/desktop-3p-paths.ts +84 -0
- package/src/claude/desktop-3p.ts +381 -0
- package/src/claude/desktop-health.ts +26 -0
- package/src/claude/desktop-profile.ts +263 -0
- package/src/claude/gateway-cache.ts +70 -0
- package/src/claude/inbound-debug.ts +163 -0
- package/src/claude/inbound.ts +509 -0
- package/src/claude/model-info.ts +151 -0
- package/src/claude/outbound.ts +872 -0
- package/src/cli/access.ts +108 -0
- package/src/cli/account-api.ts +268 -0
- package/src/cli/account-auth.ts +223 -0
- package/src/cli/account-extended.ts +350 -0
- package/src/cli/account.ts +275 -0
- package/src/cli/agent-driven.ts +70 -0
- package/src/cli/agent.ts +184 -0
- package/src/cli/catalog-prewarm.ts +27 -0
- package/src/cli/claude-desktop.ts +188 -0
- package/src/cli/claude.ts +286 -0
- package/src/cli/codex-shim-autorestore.ts +45 -0
- package/src/cli/combo.ts +119 -0
- package/src/cli/config-command.ts +145 -0
- package/src/cli/debug.ts +228 -0
- package/src/cli/doctor.ts +930 -0
- package/src/cli/export-command.ts +187 -0
- package/src/cli/help.ts +354 -0
- package/src/cli/index.ts +1113 -0
- package/src/cli/init.ts +224 -0
- package/src/cli/integrations.ts +142 -0
- package/src/cli/interactive-confirm.ts +133 -0
- package/src/cli/internal-dispatch.ts +20 -0
- package/src/cli/models-runtime.ts +212 -0
- package/src/cli/models.ts +336 -0
- package/src/cli/observe.ts +117 -0
- package/src/cli/opencode.ts +586 -0
- package/src/cli/pi.ts +188 -0
- package/src/cli/provider-runtime.ts +162 -0
- package/src/cli/provider.ts +463 -0
- package/src/cli/runtime-api.ts +325 -0
- package/src/cli/star-prompt.ts +155 -0
- package/src/cli/status-oauth.ts +78 -0
- package/src/cli/status.ts +321 -0
- package/src/cli/sync-cloud.ts +283 -0
- package/src/cli/system-command.ts +112 -0
- package/src/cli/tray-proxy.ts +52 -0
- package/src/cli/v2.ts +173 -0
- package/src/cli.ts +10 -0
- package/src/clients/config-export.ts +377 -0
- package/src/clients/effective-status.ts +385 -0
- package/src/clients/probes/agy.ts +55 -0
- package/src/clients/probes/cc-switch.ts +110 -0
- package/src/clients/probes/claude.ts +90 -0
- package/src/clients/probes/codex.ts +125 -0
- package/src/clients/probes/grok.ts +29 -0
- package/src/clients/probes/opencode.ts +109 -0
- package/src/clients/probes/paseo.ts +55 -0
- package/src/clients/probes/pi.ts +55 -0
- package/src/cloud/onedrive-auth.ts +666 -0
- package/src/cloud/onedrive-graph.ts +108 -0
- package/src/cloud/settings.ts +75 -0
- package/src/cloud/sync.ts +212 -0
- package/src/cloud/types.ts +56 -0
- package/src/cloud/vault.ts +89 -0
- package/src/codex/account-id.ts +34 -0
- package/src/codex/account-label.ts +34 -0
- package/src/codex/account-lifecycle.ts +55 -0
- package/src/codex/account-namespace-match.ts +63 -0
- package/src/codex/account-namespaces.ts +149 -0
- package/src/codex/account-pause.ts +20 -0
- package/src/codex/account-runtime-state.ts +31 -0
- package/src/codex/account-store.ts +517 -0
- package/src/codex/account-usability.ts +20 -0
- package/src/codex/app-server-processes.ts +756 -0
- package/src/codex/auth-api.ts +1540 -0
- package/src/codex/auth-collision.ts +107 -0
- package/src/codex/auth-context.ts +352 -0
- package/src/codex/autostart-health.ts +149 -0
- package/src/codex/catalog/aggregation.ts +378 -0
- package/src/codex/catalog/bundled.ts +251 -0
- package/src/codex/catalog/effort.ts +355 -0
- package/src/codex/catalog/metadata.ts +180 -0
- package/src/codex/catalog/parsing.ts +456 -0
- package/src/codex/catalog/provider-fetch.ts +902 -0
- package/src/codex/catalog/sync.ts +620 -0
- package/src/codex/catalog.ts +12 -0
- package/src/codex/data/upstream-models.json +830 -0
- package/src/codex/exec-invocation.ts +22 -0
- package/src/codex/features.ts +969 -0
- package/src/codex/history-migration-guardian.ts +102 -0
- package/src/codex/history-provider.ts +776 -0
- package/src/codex/home.ts +206 -0
- package/src/codex/inject.ts +799 -0
- package/src/codex/injected-marker.ts +72 -0
- package/src/codex/journal.ts +163 -0
- package/src/codex/main-account-cache.ts +32 -0
- package/src/codex/main-account.ts +40 -0
- package/src/codex/model-cache.ts +227 -0
- package/src/codex/paths.ts +65 -0
- package/src/codex/plugins-doctor.ts +242 -0
- package/src/codex/pool-rotation.ts +225 -0
- package/src/codex/project-config-warnings.ts +411 -0
- package/src/codex/quota.ts +411 -0
- package/src/codex/refresh.ts +53 -0
- package/src/codex/routing.ts +1477 -0
- package/src/codex/runtime.ts +538 -0
- package/src/codex/shim.ts +1189 -0
- package/src/codex/subagent-defaults.ts +550 -0
- package/src/codex/subagent-model-fallback.ts +469 -0
- package/src/codex/sync.ts +130 -0
- package/src/codex/warmup.ts +192 -0
- package/src/codex/websocket-registry.ts +100 -0
- package/src/combos/failover.ts +140 -0
- package/src/combos/index.ts +41 -0
- package/src/combos/request.ts +62 -0
- package/src/combos/resolve.ts +232 -0
- package/src/combos/types.ts +326 -0
- package/src/config.ts +2356 -0
- package/src/generated/jawcode-model-metadata.ts +104 -0
- package/src/github/star-state.ts +203 -0
- package/src/grok/inject.ts +545 -0
- package/src/grok/status.ts +121 -0
- package/src/grok/sync.ts +103 -0
- package/src/grok/usage-hook/report.mjs +348 -0
- package/src/grok/usage-hook.ts +278 -0
- package/src/images/artifacts.ts +516 -0
- package/src/images/fulfill-video.ts +163 -0
- package/src/images/fulfill.ts +149 -0
- package/src/images/index.ts +4 -0
- package/src/images/loop.ts +829 -0
- package/src/images/plan.ts +133 -0
- package/src/images/synthetic-tool.ts +133 -0
- package/src/images/types.ts +41 -0
- package/src/images/xai-client.ts +141 -0
- package/src/images/xai-video-client.ts +163 -0
- package/src/index.ts +22 -0
- package/src/lib/abort.ts +146 -0
- package/src/lib/admin-secrets.ts +25 -0
- package/src/lib/admission.ts +83 -0
- package/src/lib/app-owned-memory-stores.ts +173 -0
- package/src/lib/app-owned-memory.ts +265 -0
- package/src/lib/bounded-body.ts +202 -0
- package/src/lib/bun-binary-validator.d.mts +3 -0
- package/src/lib/bun-binary-validator.mjs +18 -0
- package/src/lib/bun-runtime.ts +71 -0
- package/src/lib/bun-stream-caps.ts +126 -0
- package/src/lib/config-ownership.ts +360 -0
- package/src/lib/crash-guard.ts +344 -0
- package/src/lib/debug-log-buffer.ts +83 -0
- package/src/lib/debug-settings.ts +108 -0
- package/src/lib/debug.ts +31 -0
- package/src/lib/destination-policy.ts +316 -0
- package/src/lib/errors.ts +364 -0
- package/src/lib/eventstream-decoder.ts +253 -0
- package/src/lib/gcp-adc.ts +341 -0
- package/src/lib/injection-debug-log.ts +58 -0
- package/src/lib/open-url.ts +25 -0
- package/src/lib/pinned-http.ts +151 -0
- package/src/lib/privacy.ts +20 -0
- package/src/lib/process-control.ts +165 -0
- package/src/lib/provider-outbound.ts +170 -0
- package/src/lib/provider-url.ts +14 -0
- package/src/lib/proxy-env.ts +18 -0
- package/src/lib/redact.ts +105 -0
- package/src/lib/retry-after.ts +55 -0
- package/src/lib/service-secrets.ts +25 -0
- package/src/lib/shadow-call.ts +30 -0
- package/src/lib/sidecar-tracker.ts +52 -0
- package/src/lib/sse-decoder.ts +323 -0
- package/src/lib/state-store-registrations.ts +109 -0
- package/src/lib/state-store-sweeper.ts +184 -0
- package/src/lib/test-home-guard.ts +90 -0
- package/src/lib/token-estimate.ts +69 -0
- package/src/lib/translator-budget.ts +356 -0
- package/src/lib/upstream-retry.ts +239 -0
- package/src/lib/win-exec.ts +115 -0
- package/src/lib/win-paths.ts +68 -0
- package/src/lib/windows-elevation.ts +705 -0
- package/src/lib/windows-secret-acl.ts +514 -0
- package/src/lib/winsw.ts +375 -0
- package/src/oauth/anthropic-routing.ts +594 -0
- package/src/oauth/anthropic.ts +177 -0
- package/src/oauth/callback-server.ts +294 -0
- package/src/oauth/chatgpt.ts +150 -0
- package/src/oauth/cursor.ts +211 -0
- package/src/oauth/github-copilot.ts +428 -0
- package/src/oauth/google-antigravity.ts +230 -0
- package/src/oauth/health.ts +399 -0
- package/src/oauth/index.ts +1174 -0
- package/src/oauth/key-providers.ts +108 -0
- package/src/oauth/kimi.ts +213 -0
- package/src/oauth/kiro-credentials.ts +726 -0
- package/src/oauth/kiro.ts +577 -0
- package/src/oauth/local-token-detect.ts +121 -0
- package/src/oauth/log.ts +48 -0
- package/src/oauth/login-cli.ts +163 -0
- package/src/oauth/pkce.ts +15 -0
- package/src/oauth/store.ts +630 -0
- package/src/oauth/token-guardian.ts +303 -0
- package/src/oauth/types.ts +62 -0
- package/src/oauth/xai.ts +241 -0
- package/src/pi/extensions.ts +72 -0
- package/src/pi/home.ts +42 -0
- package/src/pi/index.ts +40 -0
- package/src/pi/models.ts +278 -0
- package/src/pi/packages.ts +219 -0
- package/src/pi/settings.ts +365 -0
- package/src/pi/status.ts +68 -0
- package/src/pi/sync.ts +75 -0
- package/src/providers/alibaba-region-backup.ts +75 -0
- package/src/providers/alibaba-region-migration.ts +156 -0
- package/src/providers/alibaba-region-startup.ts +36 -0
- package/src/providers/antigravity-models.ts +205 -0
- package/src/providers/api-keys.ts +140 -0
- package/src/providers/base-url-choices.ts +64 -0
- package/src/providers/context-cap.ts +65 -0
- package/src/providers/derive.ts +339 -0
- package/src/providers/free-directory.ts +184 -0
- package/src/providers/github-copilot-transport.ts +56 -0
- package/src/providers/key-failover.ts +203 -0
- package/src/providers/kiro-models.ts +67 -0
- package/src/providers/label.ts +19 -0
- package/src/providers/model-discovery.ts +356 -0
- package/src/providers/openai-sidecar.ts +175 -0
- package/src/providers/openai-tier-startup.ts +27 -0
- package/src/providers/openai-tiers.ts +301 -0
- package/src/providers/openai-virtual-models.ts +82 -0
- package/src/providers/openrouter-routing.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +150 -0
- package/src/providers/quota.ts +1260 -0
- package/src/providers/registry.ts +1600 -0
- package/src/providers/slug-codec.ts +67 -0
- package/src/providers/xai-transport.ts +141 -0
- package/src/reasoning-effort.ts +135 -0
- package/src/responses/compaction.ts +117 -0
- package/src/responses/parser.ts +656 -0
- package/src/responses/reasoning-envelope.ts +52 -0
- package/src/responses/schema.ts +159 -0
- package/src/responses/spill-store.ts +394 -0
- package/src/responses/state.ts +895 -0
- package/src/responses/tool-groups.ts +19 -0
- package/src/router.ts +425 -0
- package/src/server/adapter-resolve.ts +80 -0
- package/src/server/auth-cors.ts +530 -0
- package/src/server/chat-completions.ts +368 -0
- package/src/server/claude-messages.ts +914 -0
- package/src/server/effort-policy.ts +172 -0
- package/src/server/gui-static.ts +123 -0
- package/src/server/image-retry.ts +42 -0
- package/src/server/images.ts +476 -0
- package/src/server/index.ts +1126 -0
- package/src/server/lifecycle.ts +227 -0
- package/src/server/live.ts +598 -0
- package/src/server/management/agent-settings-routes.ts +1169 -0
- package/src/server/management/api-access.ts +141 -0
- package/src/server/management/api-key-usage.ts +167 -0
- package/src/server/management/body.ts +35 -0
- package/src/server/management/clients-routes.ts +63 -0
- package/src/server/management/cloud-sync-routes.ts +266 -0
- package/src/server/management/combo-routes.ts +220 -0
- package/src/server/management/config-routes.ts +422 -0
- package/src/server/management/context.ts +31 -0
- package/src/server/management/logs-usage-routes.ts +707 -0
- package/src/server/management/model-routes.ts +525 -0
- package/src/server/management/oauth-account-routes.ts +563 -0
- package/src/server/management/provider-routes.ts +556 -0
- package/src/server/management/shared.ts +277 -0
- package/src/server/management/sidebar-routes.ts +90 -0
- package/src/server/management/system-restart.ts +179 -0
- package/src/server/management/system-routes.ts +117 -0
- package/src/server/management/usage-summary-cache.ts +86 -0
- package/src/server/management-api.ts +215 -0
- package/src/server/management-auth.ts +267 -0
- package/src/server/memory-watchdog.ts +156 -0
- package/src/server/port-reclaim.ts +307 -0
- package/src/server/ports.ts +116 -0
- package/src/server/proxy-liveness.ts +201 -0
- package/src/server/relay-eager.ts +313 -0
- package/src/server/relay.ts +1049 -0
- package/src/server/request-decompress.ts +132 -0
- package/src/server/request-log-conversation.ts +168 -0
- package/src/server/request-log.ts +1046 -0
- package/src/server/responses/collaboration.ts +354 -0
- package/src/server/responses/compact.ts +384 -0
- package/src/server/responses/core.ts +2758 -0
- package/src/server/responses/encrypted-payload.ts +308 -0
- package/src/server/responses/fetch-helpers.ts +157 -0
- package/src/server/responses/passthrough-error.ts +78 -0
- package/src/server/responses/terminal-guard.ts +230 -0
- package/src/server/responses/upstream-error.ts +48 -0
- package/src/server/responses-image-gen-repair.ts +132 -0
- package/src/server/responses-item-id-repair.ts +224 -0
- package/src/server/responses.ts +9 -0
- package/src/server/search.ts +136 -0
- package/src/server/sse-payload-rewrite.ts +175 -0
- package/src/server/startup-action-control.ts +308 -0
- package/src/server/startup-health-cache.ts +113 -0
- package/src/server/system-env.ts +413 -0
- package/src/server/windows-tcp-drop.ts +184 -0
- package/src/server/windows-tray-control.ts +41 -0
- package/src/server/ws-bridge.ts +471 -0
- package/src/service.ts +2554 -0
- package/src/stall-timeout.ts +20 -0
- package/src/storage/cleanup-job.ts +57 -0
- package/src/storage/cleanup.ts +3085 -0
- package/src/storage/policy-job.ts +457 -0
- package/src/storage/policy-scheduler.ts +40 -0
- package/src/storage/policy-worker.ts +59 -0
- package/src/storage/policy.ts +527 -0
- package/src/storage/restore-job.ts +299 -0
- package/src/storage/restore-worker.ts +58 -0
- package/src/storage/scanner.ts +238 -0
- package/src/storage/storage-mutation-coordinator.ts +139 -0
- package/src/storage/worker-lifecycle.ts +215 -0
- package/src/tray/assets/opencodex-tray-offline.ico +0 -0
- package/src/tray/assets/opencodex-tray-online.ico +0 -0
- package/src/tray/assets/opencodex-tray-warning.ico +0 -0
- package/src/tray/assets/opencodex-tray.png +0 -0
- package/src/tray/windows-tray.ps1 +290 -0
- package/src/tray/windows.ts +730 -0
- package/src/types.ts +1237 -0
- package/src/update/badge.ts +72 -0
- package/src/update/index.ts +407 -0
- package/src/update/job.ts +1520 -0
- package/src/update/notify.ts +257 -0
- package/src/update/npm-invocation.d.mts +23 -0
- package/src/update/npm-invocation.mjs +94 -0
- package/src/update/tray-update-plan.d.mts +18 -0
- package/src/update/tray-update-plan.mjs +38 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/debug.ts +97 -0
- package/src/usage/expected-prices.ts +164 -0
- package/src/usage/log.ts +658 -0
- package/src/usage/summary.ts +585 -0
- package/src/usage/totals.ts +14 -0
- package/src/vision/anthropic-describe.ts +185 -0
- package/src/vision/describe.ts +125 -0
- package/src/vision/index.ts +467 -0
- package/src/web-search/anthropic-executor.ts +189 -0
- package/src/web-search/executor.ts +105 -0
- package/src/web-search/format-result.ts +89 -0
- package/src/web-search/index.ts +196 -0
- package/src/web-search/loop.ts +664 -0
- package/src/web-search/parse.ts +220 -0
- package/src/web-search/progress-stream.ts +342 -0
- package/src/web-search/synthetic-tool.ts +47 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { durableBunRuntime } from "../lib/bun-runtime";
|
|
2
|
+
import { codexAutoStartEnabled, getConfigPath, getPidPath, readConfigDiagnostics, readPid, readRuntimePort, type RuntimePortState } from "../config";
|
|
3
|
+
import { diagnoseCodexBundledPlugins, type CodexPluginsDiagnostic } from "../codex/plugins-doctor";
|
|
4
|
+
import { findLiveProxy, isOpencodexHealthz, probeHostname } from "../server/proxy-liveness";
|
|
5
|
+
import type { OcxConfig } from "../types";
|
|
6
|
+
import { diagnoseService, serviceLogPath } from "../service";
|
|
7
|
+
import { collectStartupHealth, type StartupHealth } from "../codex/autostart-health";
|
|
8
|
+
import { getCodexRoutingKind } from "../codex/inject";
|
|
9
|
+
import { diagnoseCodexShim } from "../codex/shim";
|
|
10
|
+
import { displayCodexRuntimePath, effortClampAppliesToRuntime, loadLastEffortClamp, resolveCodexRuntime } from "../codex/runtime";
|
|
11
|
+
import { redactSecretString, redactUserPath } from "../lib/redact";
|
|
12
|
+
import { collectOrcaCodexHomeDiagnostic, type OrcaCodexHomeDiagnostic } from "../codex/home";
|
|
13
|
+
import { grokFenceEndpointDrift, readGrokStatus } from "../grok/status";
|
|
14
|
+
|
|
15
|
+
type HealthCheck = {
|
|
16
|
+
ok: boolean;
|
|
17
|
+
url: string;
|
|
18
|
+
message: string;
|
|
19
|
+
label: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type CliStatusJson = {
|
|
23
|
+
schemaVersion: 1;
|
|
24
|
+
proxy: {
|
|
25
|
+
running: boolean;
|
|
26
|
+
pid: number | null;
|
|
27
|
+
health: {
|
|
28
|
+
ok: boolean;
|
|
29
|
+
url: string;
|
|
30
|
+
message: string;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
dashboard: { url: string };
|
|
34
|
+
listen: {
|
|
35
|
+
port: number;
|
|
36
|
+
hostname: string | null;
|
|
37
|
+
source: "runtime" | "config";
|
|
38
|
+
};
|
|
39
|
+
paths: {
|
|
40
|
+
config: string;
|
|
41
|
+
pid: string;
|
|
42
|
+
runtime: string;
|
|
43
|
+
};
|
|
44
|
+
runtime: {
|
|
45
|
+
source: string;
|
|
46
|
+
overrideEnv?: string;
|
|
47
|
+
};
|
|
48
|
+
codexAutostart: boolean;
|
|
49
|
+
startup: StartupHealth;
|
|
50
|
+
defaultProvider: string | null;
|
|
51
|
+
config: {
|
|
52
|
+
source: "default" | "file" | "fallback";
|
|
53
|
+
error: string | null;
|
|
54
|
+
};
|
|
55
|
+
service: { summary: string };
|
|
56
|
+
codexShim: { summary: string };
|
|
57
|
+
codexPlugins: CodexPluginsDiagnostic;
|
|
58
|
+
codexRuntime: {
|
|
59
|
+
path: string;
|
|
60
|
+
version: string | null;
|
|
61
|
+
source: string;
|
|
62
|
+
newerAvailable: { path: string; version: string | null } | null;
|
|
63
|
+
warning: string | null;
|
|
64
|
+
catalogClamp: {
|
|
65
|
+
active: boolean;
|
|
66
|
+
removedEfforts: string[];
|
|
67
|
+
runtimeVersion: string | null;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
codexHome: OrcaCodexHomeDiagnostic;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export type CliStatusView = {
|
|
74
|
+
json: CliStatusJson;
|
|
75
|
+
proxyLabel: string;
|
|
76
|
+
healthLabel: string;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
export type ListenTarget = {
|
|
81
|
+
port: number;
|
|
82
|
+
hostname?: string;
|
|
83
|
+
source: "runtime" | "config";
|
|
84
|
+
healthUrl: string;
|
|
85
|
+
dashboardUrl: string;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export function selectListenTarget(
|
|
89
|
+
config: Pick<OcxConfig, "port" | "hostname">,
|
|
90
|
+
pid: number | null,
|
|
91
|
+
runtimePort: RuntimePortState | null,
|
|
92
|
+
): ListenTarget {
|
|
93
|
+
const currentRuntimePort = pid && runtimePort?.pid === pid ? runtimePort : null;
|
|
94
|
+
const port = currentRuntimePort ? currentRuntimePort.port : config.port ?? 10100;
|
|
95
|
+
const hostname = currentRuntimePort ? currentRuntimePort.hostname : config.hostname;
|
|
96
|
+
return {
|
|
97
|
+
port,
|
|
98
|
+
hostname,
|
|
99
|
+
source: currentRuntimePort ? "runtime" : "config",
|
|
100
|
+
healthUrl: `http://${probeHostname(hostname)}:${port}/healthz`,
|
|
101
|
+
dashboardUrl: `http://localhost:${port}/`,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Prefer live result (including authoritative null pid) over the on-disk pid file. */
|
|
106
|
+
export function resolveStatusPid(
|
|
107
|
+
live: { pid: number | null } | null,
|
|
108
|
+
pidFile: number | null,
|
|
109
|
+
): number | null {
|
|
110
|
+
return live ? live.pid : pidFile;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function checkProxyHealth(target: ListenTarget): Promise<HealthCheck> {
|
|
114
|
+
const url = target.healthUrl;
|
|
115
|
+
const controller = new AbortController();
|
|
116
|
+
const timer = setTimeout(() => controller.abort(), 800);
|
|
117
|
+
try {
|
|
118
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
119
|
+
if (!response.ok) {
|
|
120
|
+
const message = `returned HTTP ${response.status}`;
|
|
121
|
+
return { ok: false, url, message, label: `${url} ${message}` };
|
|
122
|
+
}
|
|
123
|
+
const body = await response.json().catch(() => null) as { service?: unknown; status?: unknown; version?: unknown; uptime?: unknown } | null;
|
|
124
|
+
if (!isOpencodexHealthz(body)) {
|
|
125
|
+
const message = "responded, but not an opencodex proxy";
|
|
126
|
+
return { ok: false, url, message, label: `${url} ${message}` };
|
|
127
|
+
}
|
|
128
|
+
const version = typeof body?.version === "string" ? ` v${body.version}` : "";
|
|
129
|
+
const uptime = typeof body?.uptime === "number" ? `, uptime ${Math.round(body.uptime)}s` : "";
|
|
130
|
+
const message = `ok${version}${uptime}`;
|
|
131
|
+
return { ok: true, url, message, label: `${url} ${message}` };
|
|
132
|
+
} catch (error) {
|
|
133
|
+
const reason = error instanceof Error && error.name === "AbortError" ? "timed out" : "unreachable";
|
|
134
|
+
return { ok: false, url, message: reason, label: `${url} ${reason}` };
|
|
135
|
+
} finally {
|
|
136
|
+
clearTimeout(timer);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export async function collectStatus(): Promise<CliStatusView> {
|
|
141
|
+
const configDiagnostics = readConfigDiagnostics();
|
|
142
|
+
const config = configDiagnostics.config;
|
|
143
|
+
// Prefer identity-verified liveness (runtime-port + /healthz) over ocx.pid alone (#618).
|
|
144
|
+
// Pass the already-resolved diagnostics config so findLiveProxy does not re-load and
|
|
145
|
+
// warn on malformed config.json (status --json must stay stderr-clean).
|
|
146
|
+
const live = await findLiveProxy({
|
|
147
|
+
configFn: () => ({ port: config.port, hostname: config.hostname }),
|
|
148
|
+
});
|
|
149
|
+
const pidFile = readPid();
|
|
150
|
+
// Preserve an authoritative null from orphan/legacy liveness — do not restore pidFile.
|
|
151
|
+
const pid = resolveStatusPid(live, pidFile);
|
|
152
|
+
const listen = live
|
|
153
|
+
? {
|
|
154
|
+
port: live.port,
|
|
155
|
+
hostname: live.hostname,
|
|
156
|
+
source: live.source,
|
|
157
|
+
healthUrl: `http://${probeHostname(live.hostname)}:${live.port}/healthz`,
|
|
158
|
+
dashboardUrl: `http://localhost:${live.port}/`,
|
|
159
|
+
}
|
|
160
|
+
: selectListenTarget(config, pidFile, pidFile ? readRuntimePort(pidFile) : null);
|
|
161
|
+
// findLiveProxy already identity-probed /healthz; avoid a second fetch that can race.
|
|
162
|
+
const health = live
|
|
163
|
+
? {
|
|
164
|
+
ok: true,
|
|
165
|
+
url: listen.healthUrl,
|
|
166
|
+
message: `ok (pid ${live.pid ?? "unknown"})`,
|
|
167
|
+
label: `${listen.healthUrl} ok (live)`,
|
|
168
|
+
}
|
|
169
|
+
: await checkProxyHealth(listen);
|
|
170
|
+
const bunRuntime = durableBunRuntime();
|
|
171
|
+
const service = diagnoseService();
|
|
172
|
+
// A service can be registered and still not serve: the manager reports the job
|
|
173
|
+
// either way. `live` was already identity-probed a few lines above, so cross-check
|
|
174
|
+
// rather than print registration as if it were service.
|
|
175
|
+
const serviceSummary = service.installed && !live
|
|
176
|
+
? `${service.summary} — registered but NOT serving; see ${serviceLogPath()} and re-run 'ocx service install'`
|
|
177
|
+
: service.summary;
|
|
178
|
+
const codexShim = diagnoseCodexShim();
|
|
179
|
+
const codexShimSummary = codexShim.summary;
|
|
180
|
+
const startup = collectStartupHealth(config, {
|
|
181
|
+
service,
|
|
182
|
+
shim: codexShim,
|
|
183
|
+
routingKind: getCodexRoutingKind(),
|
|
184
|
+
});
|
|
185
|
+
const codexPlugins = diagnoseCodexBundledPlugins();
|
|
186
|
+
const resolvedRuntime = (() => {
|
|
187
|
+
try {
|
|
188
|
+
return resolveCodexRuntime();
|
|
189
|
+
} catch (error) {
|
|
190
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
191
|
+
const redacted = redactUserPath(redactSecretString(message)).slice(0, 160);
|
|
192
|
+
return {
|
|
193
|
+
runtime: { command: "codex", version: null, source: "fallback" as const },
|
|
194
|
+
failures: [{
|
|
195
|
+
command: "codex",
|
|
196
|
+
source: "fallback" as const,
|
|
197
|
+
reason: `resolve threw: ${redacted}`,
|
|
198
|
+
}],
|
|
199
|
+
replacedConfigured: undefined,
|
|
200
|
+
newerAvailable: undefined,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
})();
|
|
204
|
+
const lastClamp = loadLastEffortClamp();
|
|
205
|
+
const clampActive = effortClampAppliesToRuntime(lastClamp, resolvedRuntime.runtime);
|
|
206
|
+
const codexHome = collectOrcaCodexHomeDiagnostic();
|
|
207
|
+
const warningParts: string[] = [];
|
|
208
|
+
if (
|
|
209
|
+
resolvedRuntime.replacedConfigured
|
|
210
|
+
&& resolvedRuntime.replacedConfigured.from.command !== resolvedRuntime.runtime.command
|
|
211
|
+
) {
|
|
212
|
+
warningParts.push(
|
|
213
|
+
`Preferred Codex runtime is unavailable; using ${displayCodexRuntimePath(resolvedRuntime.runtime.command)} instead. Run ocx doctor for diagnosis and recovery.`,
|
|
214
|
+
);
|
|
215
|
+
} else if (
|
|
216
|
+
resolvedRuntime.runtime.source === "fallback"
|
|
217
|
+
&& resolvedRuntime.failures.length > 0
|
|
218
|
+
&& !resolvedRuntime.runtime.version
|
|
219
|
+
) {
|
|
220
|
+
const detail = resolvedRuntime.failures[0]?.reason;
|
|
221
|
+
warningParts.push(
|
|
222
|
+
detail
|
|
223
|
+
? `No validated Codex runtime found (${detail}); falling back to \`codex\`. Run ocx doctor for diagnosis and recovery.`
|
|
224
|
+
: "No validated Codex runtime found; falling back to `codex`. Run ocx doctor for diagnosis and recovery.",
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
if (resolvedRuntime.newerAvailable) {
|
|
228
|
+
warningParts.push("OpenCodex is using an older Codex binary. Run ocx doctor for diagnosis and recovery.");
|
|
229
|
+
}
|
|
230
|
+
if (clampActive) {
|
|
231
|
+
warningParts.push(
|
|
232
|
+
`Catalog clamp removed: ${lastClamp!.removedEfforts.join(", ")}. Run ocx doctor for diagnosis and recovery.`,
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
// A Grok fence naming a port we are not listening on is invisible everywhere else:
|
|
236
|
+
// grok retries the refused connection on its own side, so no request — and therefore
|
|
237
|
+
// no log line — ever reaches us. Surface it here, where the live port is already known.
|
|
238
|
+
const grokDrift = (() => {
|
|
239
|
+
try {
|
|
240
|
+
return grokFenceEndpointDrift(readGrokStatus(), health.ok ? listen.port : undefined);
|
|
241
|
+
} catch {
|
|
242
|
+
return null; // reading grok's config must never break `ocx status`
|
|
243
|
+
}
|
|
244
|
+
})();
|
|
245
|
+
if (grokDrift) {
|
|
246
|
+
warningParts.push(
|
|
247
|
+
`Grok Build config points at port ${grokDrift.fencePort}, but the proxy is on `
|
|
248
|
+
+ `${grokDrift.livePort}; grok turns will retry against a closed port. Run 'ocx ensure' to repoint it.`,
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
const codexRuntime = {
|
|
252
|
+
path: displayCodexRuntimePath(resolvedRuntime.runtime.command),
|
|
253
|
+
version: resolvedRuntime.runtime.version,
|
|
254
|
+
source: resolvedRuntime.runtime.source,
|
|
255
|
+
newerAvailable: resolvedRuntime.newerAvailable
|
|
256
|
+
? {
|
|
257
|
+
path: displayCodexRuntimePath(resolvedRuntime.newerAvailable.command),
|
|
258
|
+
version: resolvedRuntime.newerAvailable.version,
|
|
259
|
+
}
|
|
260
|
+
: null,
|
|
261
|
+
warning: warningParts.length > 0 ? warningParts.join(" ") : null,
|
|
262
|
+
catalogClamp: {
|
|
263
|
+
active: clampActive,
|
|
264
|
+
removedEfforts: clampActive ? (lastClamp?.removedEfforts ?? []) : [],
|
|
265
|
+
runtimeVersion: clampActive ? (lastClamp?.runtimeVersion ?? null) : null,
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
const proxyLabel = live
|
|
269
|
+
? `running (PID ${live.pid ?? pid ?? "unknown"})`
|
|
270
|
+
: pid && health.ok
|
|
271
|
+
? `running (PID ${pid})`
|
|
272
|
+
: pid
|
|
273
|
+
? `PID file points to PID ${pid}, but health check failed`
|
|
274
|
+
: health.ok
|
|
275
|
+
? "reachable, but PID file is missing or stale"
|
|
276
|
+
: "not running";
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
proxyLabel,
|
|
280
|
+
healthLabel: health.label,
|
|
281
|
+
json: {
|
|
282
|
+
schemaVersion: 1,
|
|
283
|
+
proxy: {
|
|
284
|
+
running: Boolean(live) || Boolean(pid && health.ok),
|
|
285
|
+
pid: live?.pid ?? pid,
|
|
286
|
+
health: {
|
|
287
|
+
ok: health.ok,
|
|
288
|
+
url: health.url,
|
|
289
|
+
message: health.message,
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
dashboard: { url: listen.dashboardUrl },
|
|
293
|
+
listen: {
|
|
294
|
+
port: listen.port,
|
|
295
|
+
hostname: listen.hostname ?? null,
|
|
296
|
+
source: listen.source,
|
|
297
|
+
},
|
|
298
|
+
paths: {
|
|
299
|
+
config: getConfigPath(),
|
|
300
|
+
pid: getPidPath(),
|
|
301
|
+
runtime: bunRuntime.path,
|
|
302
|
+
},
|
|
303
|
+
runtime: {
|
|
304
|
+
source: bunRuntime.source,
|
|
305
|
+
...(bunRuntime.source === "override" ? { overrideEnv: bunRuntime.overrideEnv } : {}),
|
|
306
|
+
},
|
|
307
|
+
codexAutostart: codexAutoStartEnabled(config),
|
|
308
|
+
startup,
|
|
309
|
+
defaultProvider: typeof config.defaultProvider === "string" ? config.defaultProvider : null,
|
|
310
|
+
config: {
|
|
311
|
+
source: configDiagnostics.source,
|
|
312
|
+
error: configDiagnostics.error,
|
|
313
|
+
},
|
|
314
|
+
service: { summary: serviceSummary },
|
|
315
|
+
codexShim: { summary: codexShimSummary },
|
|
316
|
+
codexPlugins,
|
|
317
|
+
codexRuntime,
|
|
318
|
+
codexHome,
|
|
319
|
+
},
|
|
320
|
+
};
|
|
321
|
+
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ocx sync-cloud — OneDrive cloud backup/restore for OpenCodex local state.
|
|
3
|
+
*/
|
|
4
|
+
import { openUrl } from "../lib/open-url";
|
|
5
|
+
import {
|
|
6
|
+
clearOneDriveToken,
|
|
7
|
+
fetchOneDriveAccountEmail,
|
|
8
|
+
loginWithBrowserLoopback,
|
|
9
|
+
pollDeviceCodeToken,
|
|
10
|
+
readOneDriveToken,
|
|
11
|
+
startDeviceCodeLogin,
|
|
12
|
+
writeOneDriveToken,
|
|
13
|
+
} from "../cloud/onedrive-auth";
|
|
14
|
+
import { remoteSyncRootDescription } from "../cloud/onedrive-graph";
|
|
15
|
+
import { pullFromOneDrive, pushToOneDrive, readRemoteManifest } from "../cloud/sync";
|
|
16
|
+
import {
|
|
17
|
+
getDeviceName,
|
|
18
|
+
getOrCreateDeviceId,
|
|
19
|
+
readCloudSyncSettings,
|
|
20
|
+
resolveClientId,
|
|
21
|
+
writeCloudSyncSettings,
|
|
22
|
+
} from "../cloud/settings";
|
|
23
|
+
import { CliUsageError, printData, rejectArgs, runCliAction, takeFlag, takeOption } from "./runtime-api";
|
|
24
|
+
|
|
25
|
+
const USAGE = `Usage:
|
|
26
|
+
ocx sync-cloud login [--client-id <id>] [--device] [--json]
|
|
27
|
+
ocx sync-cloud logout [--json]
|
|
28
|
+
ocx sync-cloud status [--json]
|
|
29
|
+
ocx sync-cloud set-client-id <id> [--secret <secret>] [--json]
|
|
30
|
+
ocx sync-cloud push [--passphrase <p>] [--include-usage] [--no-vault] [--json]
|
|
31
|
+
ocx sync-cloud pull --yes [--passphrase <p>] [--include-usage] [--json]
|
|
32
|
+
|
|
33
|
+
Microsoft OneDrive sync for ~/.opencodex (config + optional encrypted auth vault).
|
|
34
|
+
Default login is browser loopback PKCE.
|
|
35
|
+
If Azure requires client_secret (AADSTS70002), pass --secret or set OPENCODEX_MS_CLIENT_SECRET.
|
|
36
|
+
|
|
37
|
+
Environment:
|
|
38
|
+
OPENCODEX_MS_CLIENT_ID Microsoft application (client) ID
|
|
39
|
+
OPENCODEX_MS_CLIENT_SECRET Optional client secret (confidential/Web apps)
|
|
40
|
+
OPENCODEX_MS_AUTHORITY common | consumers | organizations (default consumers)
|
|
41
|
+
OPENCODEX_MS_LOOPBACK_PORT Default 18765 — register http://localhost:<port> in Azure`;
|
|
42
|
+
|
|
43
|
+
function readPassphrase(args: string[]): string | undefined {
|
|
44
|
+
const fromFlag = takeOption(args, "--passphrase");
|
|
45
|
+
if (fromFlag) return fromFlag;
|
|
46
|
+
return process.env.OPENCODEX_SYNC_PASSPHRASE?.trim() || undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function handleLogin(argv: string[]): Promise<void> {
|
|
50
|
+
const args = [...argv];
|
|
51
|
+
const wantsJson = takeFlag(args, "--json");
|
|
52
|
+
const useDevice = takeFlag(args, "--device");
|
|
53
|
+
const clientIdFlag = takeOption(args, "--client-id");
|
|
54
|
+
rejectArgs(args, USAGE);
|
|
55
|
+
const clientId = resolveClientId(clientIdFlag ?? undefined);
|
|
56
|
+
|
|
57
|
+
// Persist client id for later refresh/login
|
|
58
|
+
const settings = readCloudSyncSettings();
|
|
59
|
+
writeCloudSyncSettings({ ...settings, clientId });
|
|
60
|
+
|
|
61
|
+
let store;
|
|
62
|
+
if (useDevice) {
|
|
63
|
+
const start = await startDeviceCodeLogin(clientId);
|
|
64
|
+
if (wantsJson) {
|
|
65
|
+
console.log(JSON.stringify({
|
|
66
|
+
mode: "device",
|
|
67
|
+
userCode: start.userCode,
|
|
68
|
+
verificationUri: start.verificationUri,
|
|
69
|
+
verificationUriComplete: start.verificationUriComplete,
|
|
70
|
+
message: start.message,
|
|
71
|
+
expiresIn: start.expiresIn,
|
|
72
|
+
msAuthority: start.authority,
|
|
73
|
+
}, null, 2));
|
|
74
|
+
} else {
|
|
75
|
+
console.log("\n☁️ OneDrive login (Microsoft device code)\n");
|
|
76
|
+
console.log(` 1. Open: ${start.verificationUri}`);
|
|
77
|
+
console.log(` 2. Enter code: ${start.userCode}`);
|
|
78
|
+
if (start.verificationUriComplete) {
|
|
79
|
+
console.log(` Or open: ${start.verificationUriComplete}`);
|
|
80
|
+
}
|
|
81
|
+
console.log(`\n ${start.message}\n`);
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
openUrl(start.verificationUriComplete || start.verificationUri);
|
|
85
|
+
} catch { /* optional */ }
|
|
86
|
+
store = await pollDeviceCodeToken(
|
|
87
|
+
clientId,
|
|
88
|
+
start.deviceCode,
|
|
89
|
+
start.interval,
|
|
90
|
+
start.expiresIn,
|
|
91
|
+
msg => { if (!wantsJson) console.log(` ${msg}`); },
|
|
92
|
+
start.authority,
|
|
93
|
+
);
|
|
94
|
+
} else {
|
|
95
|
+
if (!wantsJson) {
|
|
96
|
+
console.log("\n☁️ OneDrive login (browser loopback PKCE)\n");
|
|
97
|
+
console.log(" Azure app needs: Mobile and desktop platform + redirect http://localhost");
|
|
98
|
+
console.log(" Opening browser…\n");
|
|
99
|
+
}
|
|
100
|
+
store = await loginWithBrowserLoopback(clientId, undefined, info => {
|
|
101
|
+
if (wantsJson) {
|
|
102
|
+
console.log(JSON.stringify({ mode: "browser", authUrl: info.authUrl, redirectUri: info.redirectUri }, null, 2));
|
|
103
|
+
} else {
|
|
104
|
+
console.log(` Auth URL: ${info.authUrl}`);
|
|
105
|
+
console.log(` Redirect: ${info.redirectUri}\n`);
|
|
106
|
+
}
|
|
107
|
+
try { openUrl(info.authUrl); } catch { /* optional */ }
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const email = await fetchOneDriveAccountEmail(store.accessToken);
|
|
112
|
+
if (email) {
|
|
113
|
+
store.account = email;
|
|
114
|
+
writeOneDriveToken(store);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (wantsJson) {
|
|
118
|
+
console.log(JSON.stringify({ ok: true, account: email ?? null, remoteRoot: remoteSyncRootDescription() }, null, 2));
|
|
119
|
+
} else {
|
|
120
|
+
console.log(`\n✅ Logged in to OneDrive${email ? ` as ${email}` : ""}.`);
|
|
121
|
+
console.log(` Remote folder: ${remoteSyncRootDescription()}`);
|
|
122
|
+
console.log(` Next: ocx sync-cloud push --passphrase 'your-secret-passphrase'`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function handleLogout(argv: string[]): Promise<void> {
|
|
127
|
+
const args = [...argv];
|
|
128
|
+
const wantsJson = takeFlag(args, "--json");
|
|
129
|
+
rejectArgs(args, USAGE);
|
|
130
|
+
clearOneDriveToken();
|
|
131
|
+
printData({ ok: true }, wantsJson, ["Logged out of OneDrive (local token removed)."]);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function handleStatus(argv: string[]): Promise<void> {
|
|
135
|
+
const args = [...argv];
|
|
136
|
+
const wantsJson = takeFlag(args, "--json");
|
|
137
|
+
rejectArgs(args, USAGE);
|
|
138
|
+
const settings = readCloudSyncSettings();
|
|
139
|
+
const token = readOneDriveToken();
|
|
140
|
+
let remote: Awaited<ReturnType<typeof readRemoteManifest>> | null = null;
|
|
141
|
+
let remoteError: string | undefined;
|
|
142
|
+
if (token) {
|
|
143
|
+
try {
|
|
144
|
+
remote = await readRemoteManifest();
|
|
145
|
+
} catch (e) {
|
|
146
|
+
remoteError = e instanceof Error ? e.message : String(e);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const payload = {
|
|
150
|
+
clientId: settings.clientId ?? process.env.OPENCODEX_MS_CLIENT_ID ?? null,
|
|
151
|
+
loggedIn: Boolean(token),
|
|
152
|
+
account: token?.account ?? null,
|
|
153
|
+
deviceId: getOrCreateDeviceId(),
|
|
154
|
+
deviceName: getDeviceName(),
|
|
155
|
+
lastSyncAt: settings.lastSyncAt ?? null,
|
|
156
|
+
lastSyncDirection: settings.lastSyncDirection ?? null,
|
|
157
|
+
remoteRoot: remoteSyncRootDescription(),
|
|
158
|
+
remoteManifest: remote,
|
|
159
|
+
remoteError: remoteError ?? null,
|
|
160
|
+
};
|
|
161
|
+
if (wantsJson) {
|
|
162
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
console.log("\n☁️ Cloud sync (OneDrive)\n");
|
|
166
|
+
console.log(` Client ID: ${payload.clientId ?? "(not set — ocx sync-cloud set-client-id …)"}`);
|
|
167
|
+
console.log(` Logged in: ${payload.loggedIn ? "yes" : "no"}`);
|
|
168
|
+
if (payload.account) console.log(` Account: ${payload.account}`);
|
|
169
|
+
console.log(` Device: ${payload.deviceName} (${payload.deviceId})`);
|
|
170
|
+
console.log(` Remote: ${payload.remoteRoot}`);
|
|
171
|
+
console.log(` Last sync: ${payload.lastSyncAt ?? "never"} ${payload.lastSyncDirection ? `(${payload.lastSyncDirection})` : ""}`);
|
|
172
|
+
if (remote) {
|
|
173
|
+
console.log(` Remote at: ${remote.updatedAt} from ${remote.deviceName}`);
|
|
174
|
+
console.log(` Remote files:${remote.files.join(", ")}`);
|
|
175
|
+
console.log(` Has vault: ${remote.hasVault ? "yes" : "no"}`);
|
|
176
|
+
} else if (remoteError) {
|
|
177
|
+
console.log(` Remote: error — ${remoteError}`);
|
|
178
|
+
} else if (payload.loggedIn) {
|
|
179
|
+
console.log(" Remote: (no manifest yet — push first)");
|
|
180
|
+
}
|
|
181
|
+
console.log();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async function handleSetClientId(argv: string[]): Promise<void> {
|
|
185
|
+
const args = [...argv];
|
|
186
|
+
const wantsJson = takeFlag(args, "--json");
|
|
187
|
+
const secret = takeOption(args, "--secret");
|
|
188
|
+
const id = args.shift()?.trim();
|
|
189
|
+
rejectArgs(args, USAGE);
|
|
190
|
+
if (!id) throw new CliUsageError("client id is required", USAGE);
|
|
191
|
+
const settings = readCloudSyncSettings();
|
|
192
|
+
const next = { ...settings, clientId: id };
|
|
193
|
+
if (secret !== undefined) {
|
|
194
|
+
const s = secret.trim();
|
|
195
|
+
if (s) next.clientSecret = s;
|
|
196
|
+
else delete next.clientSecret;
|
|
197
|
+
}
|
|
198
|
+
writeCloudSyncSettings(next);
|
|
199
|
+
printData(
|
|
200
|
+
{ ok: true, clientId: id, hasClientSecret: Boolean(next.clientSecret) },
|
|
201
|
+
wantsJson,
|
|
202
|
+
[
|
|
203
|
+
`Saved Microsoft client_id (${id.slice(0, 8)}…)`
|
|
204
|
+
+ (next.clientSecret ? " + client secret." : "."),
|
|
205
|
+
],
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async function handlePush(argv: string[]): Promise<void> {
|
|
210
|
+
const args = [...argv];
|
|
211
|
+
const wantsJson = takeFlag(args, "--json");
|
|
212
|
+
const includeUsage = takeFlag(args, "--include-usage");
|
|
213
|
+
const noVault = takeFlag(args, "--no-vault");
|
|
214
|
+
const passphrase = readPassphrase(args);
|
|
215
|
+
rejectArgs(args, USAGE);
|
|
216
|
+
// Ensure client id exists for refresh path
|
|
217
|
+
resolveClientId();
|
|
218
|
+
const result = await pushToOneDrive({
|
|
219
|
+
passphrase: noVault ? undefined : passphrase,
|
|
220
|
+
includeUsage,
|
|
221
|
+
includeVault: !noVault && Boolean(passphrase),
|
|
222
|
+
});
|
|
223
|
+
if (wantsJson) {
|
|
224
|
+
console.log(JSON.stringify({ ok: true, ...result }, null, 2));
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
console.log("\n✅ Pushed to OneDrive");
|
|
228
|
+
console.log(` ${result.remoteRoot}`);
|
|
229
|
+
console.log(` Files: ${result.files.join(", ")}`);
|
|
230
|
+
console.log(` Vault: ${result.hasVault ? "yes (encrypted)" : "no"}`);
|
|
231
|
+
console.log(` At: ${result.updatedAt}\n`);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function handlePull(argv: string[]): Promise<void> {
|
|
235
|
+
const args = [...argv];
|
|
236
|
+
const wantsJson = takeFlag(args, "--json");
|
|
237
|
+
const yes = takeFlag(args, "--yes");
|
|
238
|
+
const includeUsage = takeFlag(args, "--include-usage");
|
|
239
|
+
const passphrase = readPassphrase(args);
|
|
240
|
+
rejectArgs(args, USAGE);
|
|
241
|
+
resolveClientId();
|
|
242
|
+
const result = await pullFromOneDrive({ yes, passphrase, includeUsage });
|
|
243
|
+
if (wantsJson) {
|
|
244
|
+
console.log(JSON.stringify({ ok: true, ...result }, null, 2));
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
console.log("\n✅ Pulled from OneDrive");
|
|
248
|
+
console.log(` ${result.remoteRoot}`);
|
|
249
|
+
console.log(` Applied: ${result.files.join(", ")}`);
|
|
250
|
+
console.log(` Vault restored: ${result.hasVault ? "yes" : "no"}`);
|
|
251
|
+
console.log(` Remote timestamp: ${result.updatedAt}\n`);
|
|
252
|
+
console.log(" Tip: run `ocx sync` to refresh Codex catalog after config pull.\n");
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export async function handleSyncCloudCommand(argv: string[]): Promise<number> {
|
|
256
|
+
return runCliAction(async () => {
|
|
257
|
+
const args = [...argv];
|
|
258
|
+
const sub = (args.shift() ?? "").toLowerCase();
|
|
259
|
+
if (!sub || sub === "help" || sub === "--help" || sub === "-h") {
|
|
260
|
+
console.log(USAGE);
|
|
261
|
+
console.log(`
|
|
262
|
+
Azure app registration (once):
|
|
263
|
+
1. https://portal.azure.com → Microsoft Entra ID → App registrations → New
|
|
264
|
+
2. Name: OpenCodex Sync (any)
|
|
265
|
+
3. Supported account types: personal + work/school
|
|
266
|
+
4. Authentication → Advanced → Allow public client flows = Yes
|
|
267
|
+
5. API permissions → Microsoft Graph delegated:
|
|
268
|
+
User.Read, Files.ReadWrite, offline_access
|
|
269
|
+
6. Copy Application (client) ID → ocx sync-cloud set-client-id <id>
|
|
270
|
+
`);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (sub === "login") return handleLogin(args);
|
|
274
|
+
if (sub === "logout") return handleLogout(args);
|
|
275
|
+
if (sub === "status") return handleStatus(args);
|
|
276
|
+
if (sub === "set-client-id") return handleSetClientId(args);
|
|
277
|
+
if (sub === "push") return handlePush(args);
|
|
278
|
+
if (sub === "pull") return handlePull(args);
|
|
279
|
+
throw new CliUsageError(`unknown sync-cloud subcommand: ${sub}`, USAGE);
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export const SYNC_CLOUD_USAGE = USAGE;
|