@bitkyc08/opencodex 2.12.0 → 2.13.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/README.md +1 -1
- package/gui/dist/assets/index-BHldBl6_.js +76 -0
- package/gui/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +15 -0
- package/src/adapters/google-antigravity-replay.ts +269 -5
- package/src/adapters/openai-chat.ts +25 -18
- package/src/adapters/openai-responses.ts +63 -17
- package/src/bridge.ts +11 -5
- package/src/claude/inbound.ts +24 -3
- package/src/cli/account-api.ts +2 -0
- package/src/cli/account-extended.ts +262 -1
- package/src/cli/account.ts +3 -1
- package/src/cli/dispatch.ts +532 -0
- package/src/cli/doctor.ts +26 -21
- package/src/cli/help.ts +9 -278
- package/src/cli/index.ts +45 -506
- package/src/cli/lab.ts +171 -65
- package/src/cli/registry.ts +384 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/status.ts +9 -2
- package/src/cli/v2.ts +37 -2
- package/src/codex/account-label.ts +14 -1
- package/src/codex/account-store.ts +12 -1
- package/src/codex/admission.ts +2 -1
- package/src/codex/auth-api.ts +3 -2
- package/src/codex/catalog/metadata.ts +6 -4
- package/src/codex/catalog/parsing.ts +31 -7
- package/src/codex/catalog/provider-fetch.ts +2 -1
- package/src/codex/catalog/sync.ts +65 -11
- package/src/codex/features.ts +437 -31
- package/src/codex/history-job.ts +6 -11
- package/src/codex/history-provider.ts +10 -9
- package/src/codex/inject.ts +14 -1
- package/src/codex/native-profile-startup.ts +49 -3
- package/src/codex/native-residue.ts +14 -2
- package/src/codex/paths.ts +75 -1
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/shim.ts +876 -16
- package/src/codex/sync.ts +27 -2
- package/src/config.ts +148 -10
- package/src/generated/compatibility-version.json +2572 -0
- package/src/images/loop.ts +1 -1
- package/src/lab/artifacts/sanitize.ts +3 -3
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +480 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/types.ts +23 -0
- package/src/lab/events/types.ts +2 -1
- package/src/lab/events/validate.ts +2 -1
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +454 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +2 -0
- package/src/lab/ledger/store.ts +173 -0
- package/src/lab/live/executor.ts +29 -4
- package/src/lab/live/transport.ts +3 -1
- package/src/lab/observe/from-conformance.ts +12 -57
- package/src/lab/observe/from-live.ts +9 -1
- package/src/lab/paths.ts +74 -9
- package/src/lab/projection/schema.ts +14 -1
- package/src/lab/projection/verdicts.ts +89 -53
- package/src/lab/projection/verification.ts +83 -3
- package/src/lab/query/catalog.ts +34 -5
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +11 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/subject/installation-salt.ts +24 -4
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +2 -1
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/windows-elevation.ts +8 -1
- package/src/lib/windows-user-principal.ts +62 -2
- package/src/lib/winsw.ts +8 -2
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic.ts +12 -1
- package/src/oauth/callback-server.ts +8 -2
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/google-antigravity.ts +27 -0
- package/src/oauth/health.ts +12 -48
- package/src/oauth/index.ts +122 -0
- package/src/oauth/kimi.ts +16 -2
- package/src/oauth/nous.ts +749 -0
- package/src/oauth/store.ts +56 -3
- package/src/providers/codex-capacity.ts +1 -0
- package/src/providers/registry.ts +161 -16
- package/src/responses/custom-tool-compat.ts +182 -0
- package/src/responses/parser.ts +22 -0
- package/src/responses/reasoning-replay-cache.ts +168 -11
- package/src/responses/schema.ts +1 -1
- package/src/router.ts +5 -20
- package/src/routing/capability.ts +9 -3
- package/src/routing/compatibility/assemble.ts +159 -0
- package/src/routing/compatibility/behavior.ts +224 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/evaluator.ts +27 -32
- package/src/routing/profile.ts +118 -4
- package/src/routing/trace.ts +82 -28
- package/src/server/auth-cors.ts +7 -0
- package/src/server/background-lifecycle.ts +20 -7
- package/src/server/chat-completions.ts +2 -2
- package/src/server/claude-messages.ts +6 -3
- package/src/server/direct-local-http.ts +343 -0
- package/src/server/index.ts +80 -18
- package/src/server/lifecycle.ts +12 -4
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/management/agent-settings-routes.ts +27 -3
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +13 -0
- package/src/server/management/logs-usage-routes.ts +1 -0
- package/src/server/management/oauth-account-routes.ts +57 -1
- package/src/server/management/provider-routes.ts +16 -0
- package/src/server/management/routing-profile-routes.ts +12 -24
- package/src/server/management-api.ts +2 -0
- package/src/server/management-auth.ts +68 -3
- package/src/server/proxy-liveness.ts +3 -2
- package/src/server/request-decompress.ts +9 -3
- package/src/server/request-log.ts +53 -4
- package/src/server/responses/collaboration.ts +93 -17
- package/src/server/responses/compact.ts +3 -0
- package/src/server/responses/core.ts +202 -15
- package/src/server/responses/policy-fallback.ts +1 -0
- package/src/server/responses-custom-tool-repair.ts +280 -0
- package/src/server/responses-terminal-repair.ts +342 -0
- package/src/server/startup-action-control.ts +8 -1
- package/src/service.ts +278 -12
- package/src/types.ts +49 -3
- package/src/usage/expected-prices.ts +30 -0
- package/src/usage/log.ts +30 -4
- package/src/usage/summary.ts +153 -2
- package/src/web-search/loop.ts +1 -1
- package/gui/dist/assets/index-Cw1_mxO8.js +0 -70
- package/src/cli/internal-dispatch.ts +0 -20
package/src/oauth/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { getAccountCredential, getAccountSet, removeAccount, saveAccountCredenti
|
|
|
8
8
|
import { loginXai, refreshXaiToken, XAI_LOCAL_CLI_DETACH_WARNING, XaiTokenRequestError } from "./xai";
|
|
9
9
|
import { ANTHROPIC_OAUTH_BETA, AnthropicTokenError, loginAnthropic, refreshAnthropicToken } from "./anthropic";
|
|
10
10
|
import { loginKimi, refreshKimiToken } from "./kimi";
|
|
11
|
+
import { loginNous, NousTokenError, refreshNousToken, clearNousRefreshIntent, RefreshIntentIOError } from "./nous";
|
|
11
12
|
import { loginChatGPT, refreshChatGPTToken } from "./chatgpt";
|
|
12
13
|
import { loginAntigravity, refreshAntigravityToken } from "./google-antigravity";
|
|
13
14
|
import { loginCursor, refreshCursorToken } from "./cursor";
|
|
@@ -194,6 +195,22 @@ export const OAUTH_PROVIDERS: Record<string, OAuthProviderDef> = {
|
|
|
194
195
|
providerConfig: oauthConfig("kimi"),
|
|
195
196
|
defaultModel: oauthDefaultModel("kimi"),
|
|
196
197
|
},
|
|
198
|
+
nous: {
|
|
199
|
+
// Nous Portal device-grant login (RFC 8628) against portal.nousresearch.com.
|
|
200
|
+
// The access token is the per-request inference JWT (scope inference:invoke).
|
|
201
|
+
// Refresh tokens are single-use and rotated server-side on every refresh:
|
|
202
|
+
// keep background refresh lazy-only (the default) so concurrent refreshes
|
|
203
|
+
// cannot trip the Portal's token-reuse revocation.
|
|
204
|
+
login: (ctrl) => loginNous(ctrl),
|
|
205
|
+
refresh: (rt, signal) => refreshNousToken(rt, signal),
|
|
206
|
+
providerConfig: oauthConfig("nous"),
|
|
207
|
+
defaultModel: oauthDefaultModel("nous"),
|
|
208
|
+
// Single-use rotating refresh tokens must never be background-refreshed
|
|
209
|
+
// proactively: concurrent refreshes would trip the Portal's reuse
|
|
210
|
+
// revocation. Anchor the lazy-only default explicitly so it cannot be
|
|
211
|
+
// silently overridden to proactive.
|
|
212
|
+
defaultRefreshPolicy: "lazy-only",
|
|
213
|
+
},
|
|
197
214
|
kiro: {
|
|
198
215
|
login: (ctrl, opts) => loginKiro(ctrl, { forceLogin: opts?.forceLogin }),
|
|
199
216
|
refresh: (rt, signal, credential) => refreshKiroToken(rt, signal, credential),
|
|
@@ -436,6 +453,11 @@ function terminal(error:unknown):boolean{
|
|
|
436
453
|
if(error instanceof XaiTokenRequestError)return ["invalid_grant","refresh_token_reused","revoked_token"].includes(error.oauthError??"");
|
|
437
454
|
if(error instanceof AnthropicTokenError)return (error.httpStatus===400||error.httpStatus===401)&&["invalid_grant","refresh_token_reused","revoked","revoked_token","refresh_token_revoked"].includes(error.oauthError??"");
|
|
438
455
|
if(error instanceof KiroTokenRefreshError)return (error.httpStatus===400||error.httpStatus===401)&&error.oauthError!==undefined;
|
|
456
|
+
if(error instanceof NousTokenError)return error.terminal===true||["invalid_grant","refresh_token_reused","revoked","revoked_token","expired_token"].includes(error.oauthError??"");
|
|
457
|
+
// Local durable-write/read/cleanup failures are operational, not credential
|
|
458
|
+
// death: the provider credential was never rejected or consumed. Never mark
|
|
459
|
+
// the account needsReauth for broken local persistence infrastructure.
|
|
460
|
+
if (error instanceof RefreshIntentIOError) return false;
|
|
439
461
|
return isTerminalRefreshError(error);
|
|
440
462
|
}
|
|
441
463
|
function authoritative(stored:OAuthCredentials,active:boolean,now:()=>number):OAuthCredentials{if(stored.source!=="local-cli")return stored;const disk=detectGrokCliToken();if(!disk)return stored;const allowed=isSameGrokIdentity(stored,disk)||(active&&!hasComparableGrokIdentity(stored,disk));return allowed&&shouldAdoptGrokGeneration(stored,disk,now(),REFRESH_SKEW_MS)?disk:stored;}
|
|
@@ -459,6 +481,47 @@ function newerClaudeCredential(stored: OAuthCredentials, now: number): OAuthCred
|
|
|
459
481
|
return credentialGeneration(disk) !== credentialGeneration(stored) ? disk : undefined;
|
|
460
482
|
}
|
|
461
483
|
|
|
484
|
+
/**
|
|
485
|
+
* Preserve an already-rotated Nous refresh token (RT-B) after a terminal refresh
|
|
486
|
+
* error (e.g. the returned access JWT lacked `inference:invoke`). The unusable
|
|
487
|
+
* access token is NOT persisted as valid: the recovery credential carries an
|
|
488
|
+
* empty access placeholder with a past expiry so it can never be routed, and the
|
|
489
|
+
* account is marked needsReauth by the caller. Generation-safe: a concurrent
|
|
490
|
+
* newer write wins and is never overwritten.
|
|
491
|
+
*/
|
|
492
|
+
async function preserveNousRotatedRefresh(
|
|
493
|
+
provider: string,
|
|
494
|
+
accountId: string,
|
|
495
|
+
rotatedRefresh: string,
|
|
496
|
+
expectedGeneration: string,
|
|
497
|
+
previous: OAuthCredentials,
|
|
498
|
+
): Promise<{ kind: "persisted"; generation: string } | { kind: "superseded" } | { kind: "failed" }> {
|
|
499
|
+
try {
|
|
500
|
+
const recovery: OAuthCredentials = {
|
|
501
|
+
refresh: rotatedRefresh,
|
|
502
|
+
// Never persist the unusable access token: an empty placeholder with a
|
|
503
|
+
// past expiry can never be observed as a valid credential.
|
|
504
|
+
access: "",
|
|
505
|
+
expires: 0,
|
|
506
|
+
...(previous.accountId ? { accountId: previous.accountId } : {}),
|
|
507
|
+
...(previous.email ? { email: previous.email } : {}),
|
|
508
|
+
...(previous.source ? { source: previous.source } : {}),
|
|
509
|
+
};
|
|
510
|
+
const outcome = await mergeAccountCredential(provider, accountId, recovery, { expectedGeneration });
|
|
511
|
+
if (outcome.superseded) return { kind: "superseded" };
|
|
512
|
+
// Return the exact generation this write produced, so the caller never
|
|
513
|
+
// re-reads the store (a concurrent writer could otherwise supply a different
|
|
514
|
+
// credential generation and be marked needsReauth by mistake).
|
|
515
|
+
return { kind: "persisted", generation: credentialGeneration(recovery) };
|
|
516
|
+
} catch (error) {
|
|
517
|
+
// A store-mutation busy outcome is transient and retryable; surface it
|
|
518
|
+
// unchanged so the caller can retry rather than treating it as a permanent
|
|
519
|
+
// RT-B persistence failure.
|
|
520
|
+
if (error instanceof OAuthMutationBusyError) throw error;
|
|
521
|
+
return { kind: "failed" };
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
462
525
|
export async function refreshAnthropicAccountWithLock(
|
|
463
526
|
provider: string,
|
|
464
527
|
accountId: string,
|
|
@@ -572,10 +635,69 @@ export async function refreshGenericAccountWithLock(
|
|
|
572
635
|
throw new OAuthLoginRequiredError(provider);
|
|
573
636
|
}
|
|
574
637
|
logOAuthEvent("OAuth credentials rotated and persisted", { provider, accountId });
|
|
638
|
+
// Best-effort bookkeeping cleanup: the rotated credential is already
|
|
639
|
+
// durably persisted. A failure to unlink the old-token intent file
|
|
640
|
+
// (EACCES/EPERM/EBUSY/EROFS) must not turn a committed rotation into a
|
|
641
|
+
// failed refresh. The stale intent keys the OLD token, which is no longer
|
|
642
|
+
// stored, so leaving it behind blocks nothing and is safe. It must also
|
|
643
|
+
// never route through the generic refresh error path (no needsReauth).
|
|
644
|
+
if (provider === "nous") {
|
|
645
|
+
try {
|
|
646
|
+
clearNousRefreshIntent(stored.refresh);
|
|
647
|
+
} catch (cleanupErr) {
|
|
648
|
+
logOAuthEvent("OAuth refresh intent cleanup failed (non-fatal)", {
|
|
649
|
+
provider,
|
|
650
|
+
accountId,
|
|
651
|
+
cause: cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr),
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
}
|
|
575
655
|
return fresh.access;
|
|
576
656
|
} catch (error) {
|
|
577
657
|
if (error instanceof OAuthMutationBusyError) throw error;
|
|
578
658
|
if (!terminal(error)) throw error;
|
|
659
|
+
// Nous-specific failure-atomicity: a terminal refresh error that carries
|
|
660
|
+
// an already-issued rotated refresh token (e.g. the access JWT lacked the
|
|
661
|
+
// required `inference:invoke` scope) means the server consumed RT-A and
|
|
662
|
+
// issued RT-B. RT-B must be preserved generation-safely BEFORE forcing
|
|
663
|
+
// reauthentication; discarding it would lose the only usable refresh
|
|
664
|
+
// material and force a full re-auth for no reason.
|
|
665
|
+
if (provider === "nous" && error instanceof NousTokenError) {
|
|
666
|
+
const rotated = error.getRotatedRefresh();
|
|
667
|
+
if (rotated !== undefined && rotated !== stored.refresh) {
|
|
668
|
+
const outcome = await preserveNousRotatedRefresh(
|
|
669
|
+
provider,
|
|
670
|
+
accountId,
|
|
671
|
+
rotated,
|
|
672
|
+
generation,
|
|
673
|
+
stored,
|
|
674
|
+
);
|
|
675
|
+
if (outcome.kind === "persisted") {
|
|
676
|
+
// RT-A's intent is cleared only after RT-B is durably persisted;
|
|
677
|
+
// cleanup itself stays best-effort (a stale RT-A intent keys a token
|
|
678
|
+
// that is no longer stored).
|
|
679
|
+
try {
|
|
680
|
+
clearNousRefreshIntent(stored.refresh);
|
|
681
|
+
} catch (cleanupErr) {
|
|
682
|
+
logOAuthEvent("OAuth refresh intent cleanup failed (non-fatal)", {
|
|
683
|
+
provider,
|
|
684
|
+
accountId,
|
|
685
|
+
cause: cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr),
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
// Mark exactly the generation this write produced — never a
|
|
689
|
+
// credential written by a concurrent login between the merge and
|
|
690
|
+
// this step.
|
|
691
|
+
await markAccountNeedsReauthIfGeneration(provider, accountId, outcome.generation, writerGeneration);
|
|
692
|
+
} else {
|
|
693
|
+
// RT-B persistence failed or a newer generation superseded it:
|
|
694
|
+
// never clear RT-A's intent (RT-A was consumed), and mark the old
|
|
695
|
+
// generation needsReauth (a no-op if a newer generation won).
|
|
696
|
+
await markAccountNeedsReauthIfGeneration(provider, accountId, generation, writerGeneration);
|
|
697
|
+
}
|
|
698
|
+
throw new OAuthLoginRequiredError(provider);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
579
701
|
await markAccountNeedsReauthIfGeneration(provider, accountId, generation, writerGeneration);
|
|
580
702
|
throw new OAuthLoginRequiredError(provider);
|
|
581
703
|
}
|
package/src/oauth/kimi.ts
CHANGED
|
@@ -151,7 +151,21 @@ async function requestDeviceAuthorization(): Promise<{
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
function parseTokenPayload(payload: TokenResponse, refreshFallback?: string): OAuthCredentials {
|
|
154
|
-
|
|
154
|
+
// Number.isFinite is required here: typeof NaN === "number", so the type check
|
|
155
|
+
// alone would let a NaN expires_in through and produce a never-refreshing expiry.
|
|
156
|
+
// Negative durations would stamp an already-past expiry — also malformed.
|
|
157
|
+
// The computed timestamp itself must also stay finite: Number.MAX_VALUE passes
|
|
158
|
+
// Number.isFinite but overflows to Infinity once multiplied by 1000.
|
|
159
|
+
if (
|
|
160
|
+
!payload.access_token
|
|
161
|
+
|| typeof payload.expires_in !== "number"
|
|
162
|
+
|| !Number.isFinite(payload.expires_in)
|
|
163
|
+
|| payload.expires_in < 0
|
|
164
|
+
) {
|
|
165
|
+
throw new Error("Kimi token response missing required fields");
|
|
166
|
+
}
|
|
167
|
+
const expires = Date.now() + payload.expires_in * 1000 - OAUTH_EXPIRY_SKEW_MS;
|
|
168
|
+
if (!Number.isFinite(expires)) {
|
|
155
169
|
throw new Error("Kimi token response missing required fields");
|
|
156
170
|
}
|
|
157
171
|
const refresh = payload.refresh_token ?? refreshFallback;
|
|
@@ -160,7 +174,7 @@ function parseTokenPayload(payload: TokenResponse, refreshFallback?: string): OA
|
|
|
160
174
|
return {
|
|
161
175
|
access: payload.access_token,
|
|
162
176
|
refresh,
|
|
163
|
-
expires
|
|
177
|
+
expires,
|
|
164
178
|
...identity,
|
|
165
179
|
};
|
|
166
180
|
}
|