@iislee/opencodex 2.31.0 → 2.35.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 +3 -3
- package/bin/ocx.mjs +99 -70
- package/gui/dist/assets/index-Be1sDpWw.css +1 -0
- package/gui/dist/assets/index-D4OKgUV4.js +114 -0
- package/gui/dist/index.html +2 -2
- package/package.json +3 -1
- package/src/adapters/anthropic.ts +104 -15
- package/src/adapters/base.ts +29 -1
- package/src/adapters/command-code.ts +42 -6
- package/src/adapters/cursor/call-id.ts +44 -0
- package/src/adapters/cursor/catalog.ts +541 -0
- package/src/adapters/cursor/checkpoint-store.ts +15 -10
- package/src/adapters/cursor/cursor-errors.ts +15 -0
- package/src/adapters/cursor/discovery.ts +69 -18
- package/src/adapters/cursor/effort-map.ts +79 -1
- package/src/adapters/cursor/envelope-echo.ts +290 -0
- package/src/adapters/cursor/live-models.ts +7 -2
- package/src/adapters/cursor/live-transport.ts +14 -0
- package/src/adapters/cursor/message-mapper.ts +4 -1
- package/src/adapters/cursor/native-exec-desktop.ts +23 -0
- package/src/adapters/cursor/native-exec-fs.ts +2 -2
- package/src/adapters/cursor/native-exec-network.ts +1 -1
- package/src/adapters/cursor/native-exec-shell.ts +5 -2
- package/src/adapters/cursor/native-exec.ts +20 -0
- package/src/adapters/cursor/protobuf-request.ts +68 -14
- package/src/adapters/cursor/request-builder.ts +40 -10
- package/src/adapters/cursor/tool-definitions.ts +14 -4
- package/src/adapters/cursor/tool-result-normalize.ts +28 -5
- package/src/adapters/cursor/types.ts +20 -0
- package/src/adapters/cursor.ts +209 -38
- package/src/adapters/exec-tool-result-normalize.ts +99 -0
- package/src/adapters/google-antigravity-replay.ts +173 -25
- package/src/adapters/google-antigravity-wire.ts +5 -0
- package/src/adapters/google-errors.ts +44 -12
- package/src/adapters/google.ts +136 -24
- package/src/adapters/image.ts +1 -1
- package/src/adapters/kiro-constants.ts +27 -0
- package/src/adapters/kiro-tools.ts +55 -16
- package/src/adapters/kiro.ts +182 -23
- package/src/adapters/openai-chat.ts +300 -242
- package/src/adapters/openai-responses.ts +353 -27
- package/src/adapters/run-turn-queue.ts +36 -1
- package/src/adapters/tool-catalog-nudge.ts +4 -3
- package/src/adapters/xai-tool-schema.ts +436 -0
- package/src/adapters/xai-web-search.ts +17 -16
- package/src/bridge.ts +90 -37
- package/src/chat/inbound.ts +14 -1
- package/src/chat/outbound.ts +15 -7
- package/src/claude/agents-inject.ts +8 -1
- package/src/claude/context-windows.ts +16 -9
- package/src/claude/outbound.ts +24 -11
- package/src/cli/access.ts +46 -3
- package/src/cli/account-api.ts +116 -19
- package/src/cli/account-extended.ts +262 -29
- package/src/cli/account-main.ts +12 -12
- package/src/cli/account.ts +69 -15
- package/src/cli/agent.ts +8 -1
- package/src/cli/alias.ts +66 -0
- package/src/cli/capabilities-command.ts +94 -0
- package/src/cli/capabilities.ts +496 -0
- package/src/cli/claude-desktop.ts +31 -11
- package/src/cli/claude.ts +26 -1
- package/src/cli/dispatch.ts +256 -28
- package/src/cli/doctor.ts +126 -14
- package/src/cli/help.ts +17 -6
- package/src/cli/index.ts +39 -9
- package/src/cli/init.ts +1 -0
- package/src/cli/inspect.ts +230 -0
- package/src/cli/models-runtime.ts +95 -0
- package/src/cli/models.ts +26 -10
- package/src/cli/observe.ts +31 -8
- package/src/cli/provider-runtime.ts +16 -2
- package/src/cli/provider.ts +2 -1
- package/src/cli/registry.ts +49 -10
- package/src/cli/runtime-api.ts +51 -7
- package/src/cli/status.ts +41 -1
- package/src/cli/storage.ts +234 -0
- package/src/cli/system-command.ts +16 -0
- package/src/cli/system-restart-client.ts +1 -1
- package/src/cli/usage-report.ts +184 -0
- package/src/cli/v2.ts +34 -10
- package/src/cli/version-skew.ts +46 -0
- package/src/clients/config-export.ts +85 -3
- package/src/clients/effective-status.ts +30 -2
- package/src/clients/probes/cline.ts +81 -0
- package/src/codex/account-label.ts +21 -0
- package/src/codex/account-pause.ts +2 -1
- package/src/codex/account-priority.ts +3 -2
- package/src/codex/app-server-processes.ts +83 -7
- package/src/codex/auth-api.ts +50 -10
- package/src/codex/auth-context.ts +21 -18
- package/src/codex/autostart-health.ts +16 -0
- package/src/codex/catalog/aggregation.ts +18 -0
- package/src/codex/catalog/effort.ts +18 -3
- package/src/codex/catalog/metadata.ts +27 -1
- package/src/codex/catalog/native-models.ts +5 -2
- package/src/codex/catalog/parsing.ts +72 -27
- package/src/codex/catalog/provider-fetch.ts +187 -31
- package/src/codex/catalog/sync.ts +131 -5
- package/src/codex/catalog.ts +1 -1
- package/src/codex/codex-write-lock.ts +3 -1
- package/src/codex/convergence-types.ts +1 -1
- package/src/codex/convergence.ts +27 -2
- package/src/codex/desired-state.ts +2 -2
- package/src/codex/desktop-app-restart.ts +355 -0
- package/src/codex/history-job.ts +32 -3
- package/src/codex/history-manifest.ts +112 -0
- package/src/codex/history-migration-guardian.ts +5 -5
- package/src/codex/history-provider.ts +825 -247
- package/src/codex/history-worker.ts +8 -5
- package/src/codex/inject-coordination.ts +83 -0
- package/src/codex/inject.ts +63 -22
- package/src/codex/injected-marker.ts +1 -1
- package/src/codex/internal/history-writer.ts +4 -3
- package/src/codex/log-guard/inspect.ts +22 -4
- package/src/codex/model-entitlements.ts +9 -2
- package/src/codex/native-profile-startup.ts +157 -27
- package/src/codex/native-residue.ts +26 -33
- package/src/codex/prompt-layers.ts +371 -25
- package/src/codex/prompt-text-probe.ts +238 -0
- package/src/codex/quota.ts +91 -10
- package/src/codex/routing.ts +9 -0
- package/src/codex/shim.ts +56 -3
- package/src/codex/subagent-model-fallback.ts +104 -25
- package/src/codex/transition-state.ts +116 -8
- package/src/combos/failover.ts +27 -0
- package/src/combos/types.ts +10 -0
- package/src/compatibility/index.ts +26 -0
- package/src/compatibility/manifest.ts +253 -0
- package/src/compatibility/openai-responses.ts +121 -0
- package/src/config/atomic-write.ts +219 -0
- package/src/config/paths.ts +40 -0
- package/src/config/process-state.ts +309 -0
- package/src/config/provider-validation.ts +177 -0
- package/src/config/rebase-provenance.ts +68 -0
- package/src/config.ts +206 -824
- package/src/generated/compatibility-version.json +373 -213
- package/src/images/loop.ts +5 -4
- package/src/images/plan.ts +5 -4
- package/src/integrations/ownership-policy.ts +160 -0
- package/src/integrations/ownership.ts +46 -2
- package/src/integrations/registry.ts +7 -0
- package/src/integrations/state.ts +79 -7
- package/src/integrations/writer.ts +26 -2
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +1 -1
- package/src/lab/fabric/producer-child.ts +1 -1
- package/src/lib/admin-secrets.ts +24 -0
- package/src/lib/bounded-body.ts +14 -2
- package/src/lib/config-ownership.ts +20 -0
- package/src/lib/errors.ts +36 -3
- package/src/lib/package-tree-integrity.ts +101 -0
- package/src/lib/process-control.ts +2 -1
- package/src/lib/service-secrets.ts +15 -0
- package/src/lib/tool-argument-integers.ts +56 -5
- package/src/oauth/callback-server.ts +22 -2
- package/src/oauth/cline.ts +203 -0
- package/src/oauth/generic-account-failover.ts +231 -0
- package/src/oauth/health.ts +1 -1
- package/src/oauth/index.ts +65 -6
- package/src/oauth/key-providers.ts +10 -1
- package/src/oauth/kimi.ts +9 -1
- package/src/oauth/kiro.ts +45 -0
- package/src/oauth/local-token-detect.ts +2 -0
- package/src/oauth/open-browser-choice.ts +26 -0
- package/src/oauth/store.ts +14 -5
- package/src/oauth/types.ts +15 -0
- package/src/providers/auto-compact-budget.ts +65 -0
- package/src/providers/command-code-efforts.ts +38 -6
- package/src/providers/context-cap.ts +4 -3
- package/src/providers/default-aliases.ts +65 -0
- package/src/providers/derive.ts +28 -0
- package/src/providers/fastwire.ts +7 -1
- package/src/providers/label.ts +34 -1
- package/src/providers/model-presets.ts +119 -0
- package/src/providers/new-model-policy.ts +146 -0
- package/src/providers/provider-id-rewrite.ts +2 -1
- package/src/providers/quota.ts +65 -7
- package/src/providers/registry.ts +184 -69
- package/src/providers/slug-codec.ts +52 -0
- package/src/providers/xai-transport.ts +21 -0
- package/src/reasoning-effort.ts +19 -2
- package/src/responses/apply-patch-envelope.ts +63 -0
- package/src/responses/code-mode-helper-compat.ts +50 -0
- package/src/responses/custom-tool-compat.ts +157 -39
- package/src/responses/namespace-tool-compat.ts +84 -4
- package/src/responses/parser.ts +7 -2
- package/src/responses/reasoning-replay-cache.ts +81 -3
- package/src/responses/schema.ts +5 -1
- package/src/responses/state.ts +94 -4
- package/src/responses/thought-signature-replay.ts +17 -0
- package/src/responses/turn-termination.ts +107 -0
- package/src/router.ts +40 -2
- package/src/routing/analytics.ts +1 -0
- package/src/routing/quota.ts +10 -0
- package/src/server/auth-cors.ts +27 -7
- package/src/server/chat-completions.ts +24 -16
- package/src/server/chat-native-sse.ts +3 -3
- package/src/server/chat-native.ts +30 -11
- package/src/server/claude-messages.ts +1 -1
- package/src/server/index.ts +179 -32
- package/src/server/lifecycle.ts +52 -1
- package/src/server/local-management-read-client.ts +1 -1
- package/src/server/local-provider-reload-client.ts +1 -1
- package/src/server/management/agent-settings-routes.ts +45 -23
- package/src/server/management/codex-prompt-routes.ts +570 -0
- package/src/server/management/combo-routes.ts +2 -1
- package/src/server/management/config-routes.ts +59 -12
- package/src/server/management/context.ts +10 -1
- package/src/server/management/logs-usage-routes.ts +30 -24
- package/src/server/management/model-routes.ts +274 -4
- package/src/server/management/model-rows.ts +4 -0
- package/src/server/management/native-integration-routes.ts +2 -1
- package/src/server/management/oauth-account-routes.ts +10 -4
- package/src/server/management/provider-capability-config.ts +1 -1
- package/src/server/management/provider-routes.ts +81 -11
- package/src/server/management/route-registry.ts +332 -0
- package/src/server/management/routing-profile-routes.ts +2 -2
- package/src/server/management/system-restart.ts +1 -1
- package/src/server/management-api.ts +18 -16
- package/src/server/port-reclaim.ts +1 -1
- package/src/server/proxy-liveness.ts +29 -5
- package/src/server/relay-eager.ts +147 -20
- package/src/server/relay.ts +251 -19
- package/src/server/request-log-conversation.ts +51 -0
- package/src/server/request-log.ts +70 -16
- package/src/server/responses/codex-auth-error.ts +55 -0
- package/src/server/responses/collaboration.ts +37 -3
- package/src/server/responses/combo-stream-preflight.ts +178 -0
- package/src/server/responses/compact.ts +6 -21
- package/src/server/responses/core.ts +810 -208
- package/src/server/responses/empty-completion-guard.ts +63 -6
- package/src/server/responses/fetch-helpers.ts +17 -102
- package/src/server/responses/input-admission.ts +3 -1
- package/src/server/responses/passthrough-error.ts +33 -9
- package/src/server/responses/responses-field-backfill.ts +105 -13
- package/src/server/responses/ws-upstream.ts +75 -2
- package/src/server/responses-custom-tool-repair.ts +87 -6
- package/src/server/responses-terminal-repair.ts +25 -4
- package/src/server/responses-undeclared-tool-guard.ts +241 -18
- package/src/server/sse-frame-buffer.ts +31 -4
- package/src/server/ws-bridge.ts +14 -2
- package/src/service.ts +42 -4
- package/src/storage/policy-job.ts +14 -4
- package/src/storage/policy.ts +88 -23
- package/src/types/config.ts +66 -0
- package/src/types/provider.ts +69 -0
- package/src/types/request.ts +17 -4
- package/src/types/tools.ts +116 -11
- package/src/types.ts +3 -1
- package/src/update/index.ts +5 -4
- package/src/update/job.ts +3 -1
- package/src/update/transactional-install.mjs +8 -1
- package/src/usage/expected-prices.ts +43 -24
- package/src/usage/log.ts +63 -12
- package/src/usage/summary.ts +211 -8
- package/src/vision/describe.ts +18 -13
- package/src/web-search/exa-executor.ts +40 -9
- package/src/web-search/executor.ts +10 -3
- package/src/web-search/loop.ts +5 -4
- package/gui/dist/assets/index-BF38heuV.js +0 -104
- package/gui/dist/assets/index-DMiI18Kv.css +0 -1
|
@@ -63,6 +63,7 @@ export async function listManagementModelRows(config: OcxConfig): Promise<Manage
|
|
|
63
63
|
disabled: disabled.has(`${selector}/${slug}`) || disabled.has(slug),
|
|
64
64
|
contextWindow: undefined,
|
|
65
65
|
maxInputTokens: undefined,
|
|
66
|
+
autoCompactTokenLimit: undefined,
|
|
66
67
|
})))
|
|
67
68
|
: [];
|
|
68
69
|
const native: ManagementModelRow[] = [...nativeRows, ...accountNativeRows].map(row => {
|
|
@@ -82,6 +83,9 @@ export async function listManagementModelRows(config: OcxConfig): Promise<Manage
|
|
|
82
83
|
// 1.05M). Dropping it here made /api/models describe a native row as if the whole
|
|
83
84
|
// window were usable as input, which is the claim the measurement disproved.
|
|
84
85
|
...(row.maxInputTokens !== undefined ? { maxInputTokens: row.maxInputTokens } : {}),
|
|
86
|
+
...(row.autoCompactTokenLimit !== undefined
|
|
87
|
+
? { autoCompactTokenLimit: row.autoCompactTokenLimit }
|
|
88
|
+
: {}),
|
|
85
89
|
};
|
|
86
90
|
});
|
|
87
91
|
const customModels: ManagementModelRow[] = (config.customModels ?? []).map(cm => {
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
* Design of record: devlog/_fin/260803_integrations_toggle_all/030 (routes),
|
|
18
18
|
* 011 (Claude Code), 012 (Grok).
|
|
19
19
|
*/
|
|
20
|
-
import { loadConfig,
|
|
20
|
+
import { loadConfig, saveConfigPreservingClaudeCode } from "../../config";
|
|
21
|
+
import { readRuntimePort } from "../../config/process-state";
|
|
21
22
|
import { desktopVisibleNativeSlugs, filterCatalogVisibleModels, nativeContextLimits, nativeOpenAiContextWindow, visibleNativeSlugs } from "../../codex/catalog";
|
|
22
23
|
import { providerContextCap } from "../../providers/context-cap";
|
|
23
24
|
import { OPENAI_CODEX_PROVIDER_ID } from "../../providers/openai-tiers";
|
|
@@ -136,7 +136,7 @@ export async function handleOauthAccountRoutes(ctx: ManagementContext): Promise<
|
|
|
136
136
|
// the provider's loopback callback server (inside this process) captures the redirect in the
|
|
137
137
|
// background, then the credential is persisted. The GUI opens the URL and polls /api/oauth/status.
|
|
138
138
|
if (url.pathname === "/api/oauth/login" && req.method === "POST") {
|
|
139
|
-
const body = await readManagementJsonBodyOr(req, {}) as { provider?: string; addAccount?: boolean; accountId?: string; reauth?: boolean };
|
|
139
|
+
const body = await readManagementJsonBodyOr(req, {}) as { provider?: string; addAccount?: boolean; accountId?: string; reauth?: boolean; openBrowser?: unknown };
|
|
140
140
|
const provider = (body.provider ?? "").trim().toLowerCase();
|
|
141
141
|
if (!isPublicOAuthProvider(provider)) return jsonResponse({ error: "unknown oauth provider" }, 400);
|
|
142
142
|
const namespaceCollision = codexAccountNamespaceProviderCollisionError(config.codexAccountNamespaces, provider);
|
|
@@ -167,9 +167,15 @@ export async function handleOauthAccountRoutes(ctx: ManagementContext): Promise<
|
|
|
167
167
|
reconcileLiveStateStores();
|
|
168
168
|
},
|
|
169
169
|
});
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
170
|
+
// Open the browser server-side (the proxy runs on the user's machine) — the GUI's
|
|
171
|
+
// window.open is popup-blocked because it runs after an await, not a direct click.
|
|
172
|
+
//
|
|
173
|
+
// The operator can decline, which is the only way to finish a login in a
|
|
174
|
+
// browser profile other than the OS default, or on a different machine
|
|
175
|
+
// than the proxy. Declining changes nothing else: the URL is still
|
|
176
|
+
// returned below and every login surface renders it with a copy button.
|
|
177
|
+
const { shouldOpenBrowserForLogin } = await import("../../oauth/open-browser-choice");
|
|
178
|
+
if (authUrl && !deviceCode && shouldOpenBrowserForLogin(body.openBrowser, config)) {
|
|
173
179
|
const { openUrl } = await import("../../lib/open-url");
|
|
174
180
|
openUrl(authUrl);
|
|
175
181
|
}
|
|
@@ -36,7 +36,7 @@ import { ProviderOutboundPolicyError, providerOutboundGet, providerOutboundPost,
|
|
|
36
36
|
import { fetchCursorUsableModels } from "../../adapters/cursor/live-models";
|
|
37
37
|
import { parseAntigravityAvailableModels } from "../../providers/antigravity-models";
|
|
38
38
|
import { enrichProviderFromCatalog, listKeyLoginProviders } from "../../oauth/key-providers";
|
|
39
|
-
import { deriveProviderPresets, enrichProviderFromRegistry } from "../../providers/derive";
|
|
39
|
+
import { deriveProviderPresets, enrichProviderFromRegistry, providerConfigSeed } from "../../providers/derive";
|
|
40
40
|
import { effectiveGoogleMode, providerCodexAccountMode, providerMatchesRegistryTransport } from "../../providers/registry";
|
|
41
41
|
import {
|
|
42
42
|
extractModelEnvelopeRows,
|
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
getProviderLiveModelCount,
|
|
60
60
|
} from "../../codex/model-cache";
|
|
61
61
|
import { DEFAULT_PROVIDER_CONTEXT_CAP, globalContextCapValue, providerContextCap, providerContextCaps, setAllProviderContextCaps, setGlobalContextCapValue, setProviderContextCap } from "../../providers/context-cap";
|
|
62
|
+
import { modelAutoCompactTokenLimitsConfigError } from "../../providers/auto-compact-budget";
|
|
62
63
|
import { resolveCodexHomeDir } from "../../codex/home";
|
|
63
64
|
import { readUsageEntries } from "../../usage/log";
|
|
64
65
|
import { getUsageDebugLogEntries } from "../../usage/debug";
|
|
@@ -271,6 +272,29 @@ function applyProviderPatchFields(
|
|
|
271
272
|
}
|
|
272
273
|
touched = true;
|
|
273
274
|
}
|
|
275
|
+
if (Object.hasOwn(rawBody, "modelAutoCompactTokenLimits")) {
|
|
276
|
+
const value = rawBody.modelAutoCompactTokenLimits;
|
|
277
|
+
const error = modelAutoCompactTokenLimitsConfigError(value, {
|
|
278
|
+
allowTombstones: true,
|
|
279
|
+
requireNativeIds: name === "openai",
|
|
280
|
+
});
|
|
281
|
+
if (error) return { error };
|
|
282
|
+
if (value === null) {
|
|
283
|
+
delete next.modelAutoCompactTokenLimits;
|
|
284
|
+
} else {
|
|
285
|
+
const budgets: Record<string, number> = Object.assign(
|
|
286
|
+
Object.create(null) as Record<string, number>,
|
|
287
|
+
next.modelAutoCompactTokenLimits ?? {},
|
|
288
|
+
);
|
|
289
|
+
for (const [model, budget] of Object.entries(value as Record<string, number | null>)) {
|
|
290
|
+
if (budget === null) delete budgets[model];
|
|
291
|
+
else budgets[model] = budget;
|
|
292
|
+
}
|
|
293
|
+
if (Object.keys(budgets).length > 0) next.modelAutoCompactTokenLimits = budgets;
|
|
294
|
+
else delete next.modelAutoCompactTokenLimits;
|
|
295
|
+
}
|
|
296
|
+
touched = true;
|
|
297
|
+
}
|
|
274
298
|
if (Object.hasOwn(rawBody, "modelSupportsServiceTier")) {
|
|
275
299
|
const value = rawBody.modelSupportsServiceTier;
|
|
276
300
|
if (value === null) {
|
|
@@ -374,6 +398,28 @@ function applyProviderPatchFields(
|
|
|
374
398
|
return { next, touched, editorTouched, enablingOpenAi, headersTouched };
|
|
375
399
|
}
|
|
376
400
|
|
|
401
|
+
/** Validate the canonical OpenAI soft-budget overlay against a fresh registry seed. */
|
|
402
|
+
function canonicalOpenAiBudgetPatchError(
|
|
403
|
+
provider: OcxProviderConfig,
|
|
404
|
+
rawBody: Record<string, unknown>,
|
|
405
|
+
keys: string[],
|
|
406
|
+
config: OcxConfig,
|
|
407
|
+
): string | null {
|
|
408
|
+
if (!isCanonicalOpenAiForwardProvider(provider)) {
|
|
409
|
+
return "provider openai must be the canonical built-in provider";
|
|
410
|
+
}
|
|
411
|
+
const entry = getProviderRegistryEntry("openai");
|
|
412
|
+
if (!entry) return "provider openai registry seed is unavailable";
|
|
413
|
+
const seed = providerConfigSeed(entry);
|
|
414
|
+
if (provider.codexAccountMode !== undefined) seed.codexAccountMode = provider.codexAccountMode;
|
|
415
|
+
if (provider.modelAutoCompactTokenLimits !== undefined) {
|
|
416
|
+
seed.modelAutoCompactTokenLimits = { ...provider.modelAutoCompactTokenLimits };
|
|
417
|
+
}
|
|
418
|
+
const applied = applyProviderPatchFields("openai", seed, rawBody, keys, config);
|
|
419
|
+
if ("error" in applied) return applied.error;
|
|
420
|
+
return providerManagementConfigError("openai", applied.next);
|
|
421
|
+
}
|
|
422
|
+
|
|
377
423
|
export async function handleProviderRoutes(ctx: ManagementContext): Promise<Response | null> {
|
|
378
424
|
const { req, url, config, deps, principal, convergeCodexCatalog, syncClaudeAgentDefsBestEffort } = ctx;
|
|
379
425
|
|
|
@@ -410,6 +456,7 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
|
|
|
410
456
|
models: p.models ?? [],
|
|
411
457
|
contextWindow: p.contextWindow,
|
|
412
458
|
modelContextWindows: p.modelContextWindows,
|
|
459
|
+
modelAutoCompactTokenLimits: p.modelAutoCompactTokenLimits,
|
|
413
460
|
modelSupportsServiceTier: p.modelSupportsServiceTier,
|
|
414
461
|
noStructuredOutputModels: p.noStructuredOutputModels,
|
|
415
462
|
upstreamHttpVersion: p.upstreamHttpVersion,
|
|
@@ -541,6 +588,7 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
|
|
|
541
588
|
// call can never fire.
|
|
542
589
|
const submittedContextWindow = Object.hasOwn(prov, "contextWindow");
|
|
543
590
|
const submittedModelContextWindows = Object.hasOwn(prov, "modelContextWindows");
|
|
591
|
+
const submittedModelAutoCompactTokenLimits = Object.hasOwn(prov, "modelAutoCompactTokenLimits");
|
|
544
592
|
const submittedRequestPacing = Object.hasOwn(prov, "requestPacing");
|
|
545
593
|
enrichProviderFromCatalog(name, prov);
|
|
546
594
|
const { saveConfigPreservingClaudeCode: save } = await import("../../config");
|
|
@@ -553,6 +601,12 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
|
|
|
553
601
|
// erase hand-edited per-model prices from Logs/Usage estimates.
|
|
554
602
|
const existingCosts = config.providers[name]?.modelCosts;
|
|
555
603
|
if (existingCosts && !prov.modelCosts) prov.modelCosts = existingCosts;
|
|
604
|
+
// And to the per-provider account-failover opt-out (#2568d). `ProviderPayload` has no
|
|
605
|
+
// member for it either, so an add/edit save structurally cannot carry it — and dropping it
|
|
606
|
+
// silently ENABLES rotation, because activation is presence-driven once the knob is gone.
|
|
607
|
+
// An overwrite must not spend a second subscription account's quota as a side effect.
|
|
608
|
+
const existingFailover = config.providers[name]?.oauthAccountFailover;
|
|
609
|
+
if (existingFailover && !prov.oauthAccountFailover) prov.oauthAccountFailover = existingFailover;
|
|
556
610
|
// ...and to hand-edited context windows. `ProviderPayload` (gui/src/provider-payload.ts)
|
|
557
611
|
// has no member for either field, so the add/edit form structurally cannot send them:
|
|
558
612
|
// absence in the request means "not carried", never "the user deleted it". Deletion goes
|
|
@@ -573,6 +627,11 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
|
|
|
573
627
|
? { ...existing.modelContextWindows, ...(prov.modelContextWindows ?? {}) }
|
|
574
628
|
: { ...existing.modelContextWindows };
|
|
575
629
|
}
|
|
630
|
+
if (existing?.modelAutoCompactTokenLimits) {
|
|
631
|
+
prov.modelAutoCompactTokenLimits = submittedModelAutoCompactTokenLimits
|
|
632
|
+
? { ...existing.modelAutoCompactTokenLimits, ...(prov.modelAutoCompactTokenLimits ?? {}) }
|
|
633
|
+
: { ...existing.modelAutoCompactTokenLimits };
|
|
634
|
+
}
|
|
576
635
|
config.providers[name] = stripRegistryOnlyStaticHeaders(name, prov);
|
|
577
636
|
if (body.setDefault === true) config.defaultProvider = name;
|
|
578
637
|
save(config);
|
|
@@ -596,6 +655,9 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
|
|
|
596
655
|
const keys = Object.keys(rawBody);
|
|
597
656
|
const hasMode = Object.hasOwn(rawBody, "codexAccountMode");
|
|
598
657
|
const hasSetDefault = Object.hasOwn(rawBody, "setDefault");
|
|
658
|
+
const canonicalBudgetOnly = name === "openai"
|
|
659
|
+
&& keys.length === 1
|
|
660
|
+
&& keys[0] === "modelAutoCompactTokenLimits";
|
|
599
661
|
|
|
600
662
|
// codexAccountMode keeps its dedicated side-effect path (quota cache clear, thread map
|
|
601
663
|
// clear, pool prime) and is mutually exclusive with every other patch field.
|
|
@@ -658,12 +720,16 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
|
|
|
658
720
|
|
|
659
721
|
const pacingOnly = keys.every(key => key === "requestPacing");
|
|
660
722
|
if (applied.editorTouched && !pacingOnly) {
|
|
661
|
-
const providerError =
|
|
723
|
+
const providerError = canonicalBudgetOnly
|
|
724
|
+
? canonicalOpenAiBudgetPatchError(next, rawBody, keys, config)
|
|
725
|
+
: providerManagementConfigError(name, next);
|
|
662
726
|
if (providerError) return jsonResponse({ error: providerError }, 400);
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
727
|
+
if (!canonicalBudgetOnly) {
|
|
728
|
+
const serviceTierError = providerServiceTierConfigError(name, next);
|
|
729
|
+
if (serviceTierError) return jsonResponse({ error: serviceTierError }, 400);
|
|
730
|
+
const resolvedError = await providerDestinationResolvedError(name, next);
|
|
731
|
+
if (resolvedError) return jsonResponse({ error: resolvedError }, 400);
|
|
732
|
+
}
|
|
667
733
|
} else if (applied.enablingOpenAi) {
|
|
668
734
|
// Same DNS gate as POST: Clash fake-IP only. Never honor a persisted
|
|
669
735
|
// allowPrivateNetwork on this path — it must not bypass the built-in guard.
|
|
@@ -687,15 +753,19 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
|
|
|
687
753
|
return;
|
|
688
754
|
}
|
|
689
755
|
if (replay.editorTouched && !pacingOnly) {
|
|
690
|
-
const syncError =
|
|
756
|
+
const syncError = canonicalBudgetOnly
|
|
757
|
+
? canonicalOpenAiBudgetPatchError(replay.next, rawBody, keys, config)
|
|
758
|
+
: providerManagementConfigError(name, replay.next);
|
|
691
759
|
if (syncError) {
|
|
692
760
|
replayError = syncError;
|
|
693
761
|
return;
|
|
694
762
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
763
|
+
if (!canonicalBudgetOnly) {
|
|
764
|
+
const serviceTierError = providerServiceTierConfigError(name, replay.next);
|
|
765
|
+
if (serviceTierError) {
|
|
766
|
+
replayError = serviceTierError;
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
699
769
|
}
|
|
700
770
|
} else if (replay.enablingOpenAi && !isCanonicalOpenAiForwardProvider(replay.next)) {
|
|
701
771
|
replayError = "provider openai must be the canonical built-in provider";
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declared inventory of every reachable management route.
|
|
3
|
+
*
|
|
4
|
+
* DECLARED, not harvested. A grep cannot see this surface: 18 routes are registered
|
|
5
|
+
* through a regex, an `endsWith`, a `pathname.slice`, a prefix decode, a path constant, or a
|
|
6
|
+
* negated `pathname !== "…"` guard, and two of those are live routes whose only textual
|
|
7
|
+
* trace is the negated form. For `GET /api/storage` an equality scan finds solely the dead
|
|
8
|
+
* shadowed copy in `logs-usage-routes.ts` and never the live one.
|
|
9
|
+
*
|
|
10
|
+
* This module is pure DATA and must stay that way. It is imported by
|
|
11
|
+
* `src/server/management-api.ts`, which `tests/core-lab-boundary.test.ts` protects: a user
|
|
12
|
+
* with one provider and no Lab must execute no Lab code. Route paths are strings, so
|
|
13
|
+
* declaring `/api/lab/status` here creates no module edge. Never import a handler, and
|
|
14
|
+
* never import anything from `src/lab/`. The `module` field names the owning file as text
|
|
15
|
+
* for exactly this reason.
|
|
16
|
+
*
|
|
17
|
+
* Reconciliation lives in `tests/management-route-registry.test.ts`, which resolves
|
|
18
|
+
* `(method, path)` pairs from source and fails loudly on a route whose method it cannot
|
|
19
|
+
* determine. Adding a route without declaring it here fails that test.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Why a route has no CLI verb. Every value is a claim about the route that a reviewer
|
|
26
|
+
* can check, not a way to quiet the parity test.
|
|
27
|
+
*/
|
|
28
|
+
export type ExemptionReason =
|
|
29
|
+
/** Requires a dashboard browser session. Includes the user-consent star boundary. */
|
|
30
|
+
| "session-only"
|
|
31
|
+
/** Deliberately returns 405; there is nothing to drive. */
|
|
32
|
+
| "disabled"
|
|
33
|
+
/** Gated on a process-scoped capability principal, not an operator action. */
|
|
34
|
+
| "capability-principal"
|
|
35
|
+
/** A test seam, not an operator capability. */
|
|
36
|
+
| "test-seam"
|
|
37
|
+
/** The CLI reaches the same data through a local transport instead of HTTP. */
|
|
38
|
+
| "local-transport"
|
|
39
|
+
/** Unreachable in the live dispatch order; delete rather than expose. */
|
|
40
|
+
| "dead"
|
|
41
|
+
/**
|
|
42
|
+
* A verb is owed but belongs to a later work-phase. BOUNDED: requires `owner` and
|
|
43
|
+
* `ownerDoc`, and the parity test asserts that tracked doc exists and names the route.
|
|
44
|
+
* The doc is deliberately a repository file rather than the goalplan, which is
|
|
45
|
+
* gitignored -- a test reading machine-local state passes here and finds nothing in CI.
|
|
46
|
+
*/
|
|
47
|
+
| "deferred-verb";
|
|
48
|
+
|
|
49
|
+
export interface RouteExemption {
|
|
50
|
+
readonly reason: ExemptionReason;
|
|
51
|
+
/** Free text; required, because an exemption nobody justified is how a gate erodes. */
|
|
52
|
+
readonly why: string;
|
|
53
|
+
/** Work-phase that owes the verb. Required for `deferred-verb`. */
|
|
54
|
+
readonly owner?: string;
|
|
55
|
+
/** Tracked doc naming the route. Required for `deferred-verb`. */
|
|
56
|
+
readonly ownerDoc?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** How a route is registered, for routes an equality scan cannot see. */
|
|
60
|
+
export type NonLiteralMechanism =
|
|
61
|
+
| "negated-guard"
|
|
62
|
+
| "path-constant"
|
|
63
|
+
| "prefix-decode"
|
|
64
|
+
| "slice"
|
|
65
|
+
| "ends-with"
|
|
66
|
+
| "regex";
|
|
67
|
+
|
|
68
|
+
export interface ManagementRoute {
|
|
69
|
+
readonly method: HttpMethod;
|
|
70
|
+
readonly path: string;
|
|
71
|
+
/** Owning source file, repo-relative without the `src/` prefix or `.ts` suffix. */
|
|
72
|
+
readonly module: string;
|
|
73
|
+
readonly mutates: boolean;
|
|
74
|
+
/** Set when the route is not recoverable from an equality scan of its own file. */
|
|
75
|
+
readonly mechanism?: NonLiteralMechanism;
|
|
76
|
+
readonly exempt?: RouteExemption;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
/** Every reachable management route. */
|
|
81
|
+
export const MANAGEMENT_ROUTES: readonly ManagementRoute[] = [
|
|
82
|
+
// server/management-api
|
|
83
|
+
{ method: "POST", path: "/api/stop", module: "server/management-api", mutates: true },
|
|
84
|
+
// codex/auth-api
|
|
85
|
+
{ method: "DELETE", path: "/api/codex-auth/accounts", module: "codex/auth-api", mutates: true },
|
|
86
|
+
{ method: "GET", path: "/api/codex-auth/accounts", module: "codex/auth-api", mutates: false },
|
|
87
|
+
{ method: "GET", path: "/api/codex-auth/active", module: "codex/auth-api", mutates: false },
|
|
88
|
+
{ method: "GET", path: "/api/codex-auth/login-status", module: "codex/auth-api", mutates: false },
|
|
89
|
+
{ method: "GET", path: "/api/codex-auth/quota", module: "codex/auth-api", mutates: false },
|
|
90
|
+
{ method: "GET", path: "/api/codex-auth/reset-credits", module: "codex/auth-api", mutates: false },
|
|
91
|
+
{ method: "PATCH", path: "/api/codex-auth/pool-strategy", module: "codex/auth-api", mutates: true },
|
|
92
|
+
{ method: "POST", path: "/api/codex-auth/accounts", module: "codex/auth-api", mutates: true },
|
|
93
|
+
{ method: "POST", path: "/api/codex-auth/accounts/clear-cooldown", module: "codex/auth-api", mutates: true },
|
|
94
|
+
{ method: "POST", path: "/api/codex-auth/login", module: "codex/auth-api", mutates: true },
|
|
95
|
+
{ method: "POST", path: "/api/codex-auth/login/cancel", module: "codex/auth-api", mutates: true },
|
|
96
|
+
{ method: "POST", path: "/api/codex-auth/login/code", module: "codex/auth-api", mutates: true },
|
|
97
|
+
{ method: "POST", path: "/api/codex-auth/reset-credits/consume", module: "codex/auth-api", mutates: true },
|
|
98
|
+
{ method: "PUT", path: "/api/codex-auth/accounts/alias", module: "codex/auth-api", mutates: true },
|
|
99
|
+
{ method: "PUT", path: "/api/codex-auth/accounts/pause", module: "codex/auth-api", mutates: true },
|
|
100
|
+
{ method: "PUT", path: "/api/codex-auth/accounts/pause-exhausted", module: "codex/auth-api", mutates: true },
|
|
101
|
+
{ method: "PUT", path: "/api/codex-auth/accounts/priority", module: "codex/auth-api", mutates: true },
|
|
102
|
+
{ method: "PUT", path: "/api/codex-auth/active", module: "codex/auth-api", mutates: true },
|
|
103
|
+
{ method: "PUT", path: "/api/codex-auth/auto-switch", module: "codex/auth-api", mutates: true },
|
|
104
|
+
{ method: "PUT", path: "/api/codex-auth/failover", module: "codex/auth-api", mutates: true },
|
|
105
|
+
{ method: "PUT", path: "/api/codex-auth/pool-strategy", module: "codex/auth-api", mutates: true },
|
|
106
|
+
// codex/native-profile-api
|
|
107
|
+
{ method: "GET", path: "/api/native-main-profiles", module: "codex/native-profile-api", mutates: false },
|
|
108
|
+
{ method: "GET", path: "/api/native-main-profiles/doctor", module: "codex/native-profile-api", mutates: false },
|
|
109
|
+
{ method: "POST", path: "/api/native-main-profiles/recover", module: "codex/native-profile-api", mutates: true },
|
|
110
|
+
{ method: "POST", path: "/api/native-main-profiles/register", module: "codex/native-profile-api", mutates: true },
|
|
111
|
+
{ method: "POST", path: "/api/native-main-profiles/stage", module: "codex/native-profile-api", mutates: true },
|
|
112
|
+
{ method: "POST", path: "/api/native-main-profiles/stage/cancel", module: "codex/native-profile-api", mutates: true },
|
|
113
|
+
{ method: "POST", path: "/api/native-main-profiles/stage/finish", module: "codex/native-profile-api", mutates: true },
|
|
114
|
+
{ method: "POST", path: "/api/native-main-profiles/stage/heartbeat", module: "codex/native-profile-api", mutates: true },
|
|
115
|
+
{ method: "POST", path: "/api/native-main-profiles/switch", module: "codex/native-profile-api", mutates: true },
|
|
116
|
+
// server/management/agent-settings-routes
|
|
117
|
+
{ method: "GET", path: "/api/claude-code", module: "server/management/agent-settings-routes", mutates: false },
|
|
118
|
+
{ method: "GET", path: "/api/claude-desktop", module: "server/management/agent-settings-routes", mutates: false },
|
|
119
|
+
{ method: "GET", path: "/api/claude-desktop/status", module: "server/management/agent-settings-routes", mutates: false },
|
|
120
|
+
{ method: "GET", path: "/api/codex-auth/features/default-mode-request-user-input", module: "server/management/agent-settings-routes", mutates: false },
|
|
121
|
+
{ method: "GET", path: "/api/effort-caps", module: "server/management/agent-settings-routes", mutates: false },
|
|
122
|
+
{ method: "GET", path: "/api/grok", module: "server/management/agent-settings-routes", mutates: false },
|
|
123
|
+
{ method: "GET", path: "/api/injection-model", module: "server/management/agent-settings-routes", mutates: false },
|
|
124
|
+
{ method: "GET", path: "/api/pi", module: "server/management/agent-settings-routes", mutates: false },
|
|
125
|
+
{ method: "GET", path: "/api/pi/extensions", module: "server/management/agent-settings-routes", mutates: false },
|
|
126
|
+
{ method: "GET", path: "/api/pi/packages", module: "server/management/agent-settings-routes", mutates: false },
|
|
127
|
+
{ method: "GET", path: "/api/pi/settings", module: "server/management/agent-settings-routes", mutates: false },
|
|
128
|
+
{ method: "GET", path: "/api/subagent-model-fallback", module: "server/management/agent-settings-routes", mutates: false },
|
|
129
|
+
{ method: "GET", path: "/api/subagent-models", module: "server/management/agent-settings-routes", mutates: false },
|
|
130
|
+
{ method: "GET", path: "/api/v2", module: "server/management/agent-settings-routes", mutates: false },
|
|
131
|
+
{ method: "POST", path: "/api/claude-desktop/apply", module: "server/management/agent-settings-routes", mutates: true },
|
|
132
|
+
{ method: "POST", path: "/api/grok/apply", module: "server/management/agent-settings-routes", mutates: true },
|
|
133
|
+
{ method: "POST", path: "/api/pi/apply", module: "server/management/agent-settings-routes", mutates: true },
|
|
134
|
+
{ method: "POST", path: "/api/pi/packages/install", module: "server/management/agent-settings-routes", mutates: true },
|
|
135
|
+
{ method: "POST", path: "/api/pi/packages/remove", module: "server/management/agent-settings-routes", mutates: true },
|
|
136
|
+
{ method: "POST", path: "/api/pi/remove", module: "server/management/agent-settings-routes", mutates: true },
|
|
137
|
+
{ method: "PUT", path: "/api/claude-code", module: "server/management/agent-settings-routes", mutates: true },
|
|
138
|
+
{ method: "PUT", path: "/api/claude-desktop", module: "server/management/agent-settings-routes", mutates: true },
|
|
139
|
+
{ method: "PUT", path: "/api/codex-auth/features/default-mode-request-user-input", module: "server/management/agent-settings-routes", mutates: true },
|
|
140
|
+
{ method: "PUT", path: "/api/effort-caps", module: "server/management/agent-settings-routes", mutates: true },
|
|
141
|
+
{ method: "PUT", path: "/api/grok/selection", module: "server/management/agent-settings-routes", mutates: true },
|
|
142
|
+
{ method: "PUT", path: "/api/injection-model", module: "server/management/agent-settings-routes", mutates: true },
|
|
143
|
+
{ method: "PUT", path: "/api/pi/settings", module: "server/management/agent-settings-routes", mutates: true },
|
|
144
|
+
{ method: "PUT", path: "/api/subagent-model-fallback", module: "server/management/agent-settings-routes", mutates: true },
|
|
145
|
+
{ method: "PUT", path: "/api/subagent-models", module: "server/management/agent-settings-routes", mutates: true },
|
|
146
|
+
{ method: "PUT", path: "/api/v2", module: "server/management/agent-settings-routes", mutates: true },
|
|
147
|
+
// server/management/clients-routes
|
|
148
|
+
{ method: "GET", path: "/api/clients/status", module: "server/management/clients-routes", mutates: false },
|
|
149
|
+
// server/management/cloud-sync-routes
|
|
150
|
+
{ method: "GET", path: "/api/cloud-sync/status", module: "server/management/cloud-sync-routes", mutates: false },
|
|
151
|
+
{ method: "POST", path: "/api/cloud-sync/client-id", module: "server/management/cloud-sync-routes", mutates: true },
|
|
152
|
+
{ method: "POST", path: "/api/cloud-sync/login/poll", module: "server/management/cloud-sync-routes", mutates: true },
|
|
153
|
+
{ method: "POST", path: "/api/cloud-sync/login/start", module: "server/management/cloud-sync-routes", mutates: true },
|
|
154
|
+
{ method: "POST", path: "/api/cloud-sync/logout", module: "server/management/cloud-sync-routes", mutates: true },
|
|
155
|
+
{ method: "POST", path: "/api/cloud-sync/pull", module: "server/management/cloud-sync-routes", mutates: true },
|
|
156
|
+
{ method: "POST", path: "/api/cloud-sync/push", module: "server/management/cloud-sync-routes", mutates: true },
|
|
157
|
+
// server/management/codex-prompt-routes
|
|
158
|
+
{ method: "GET", path: "/api/codex-prompt", module: "server/management/codex-prompt-routes", mutates: false },
|
|
159
|
+
{ method: "GET", path: "/api/codex-prompt/text", module: "server/management/codex-prompt-routes", mutates: false },
|
|
160
|
+
{ method: "POST", path: "/api/codex-prompt/adopt", module: "server/management/codex-prompt-routes", mutates: true, exempt: { reason: "session-only", why: "Prompt adoption requires the gui-session principal (codex-prompt-routes.ts:298)." } },
|
|
161
|
+
{ method: "POST", path: "/api/codex-prompt/repair", module: "server/management/codex-prompt-routes", mutates: true, exempt: { reason: "session-only", why: "Prompt repair requires the gui-session principal (codex-prompt-routes.ts:298)." } },
|
|
162
|
+
{ method: "PUT", path: "/api/codex-prompt/base", module: "server/management/codex-prompt-routes", mutates: true, exempt: { reason: "session-only", why: "Base prompt write requires the gui-session principal (codex-prompt-routes.ts:298)." } },
|
|
163
|
+
{ method: "PUT", path: "/api/codex-prompt/base/select", module: "server/management/codex-prompt-routes", mutates: true, exempt: { reason: "session-only", why: "Base prompt selection requires the gui-session principal (codex-prompt-routes.ts:298)." } },
|
|
164
|
+
{ method: "PUT", path: "/api/codex-prompt/custom", module: "server/management/codex-prompt-routes", mutates: true, exempt: { reason: "session-only", why: "Custom prompt write requires the gui-session principal (codex-prompt-routes.ts:298)." } },
|
|
165
|
+
{ method: "PUT", path: "/api/codex-prompt/toggle", module: "server/management/codex-prompt-routes", mutates: true, exempt: { reason: "session-only", why: "Prompt toggle requires the gui-session principal (codex-prompt-routes.ts:298)." } },
|
|
166
|
+
// server/management/combo-routes
|
|
167
|
+
{ method: "DELETE", path: "/api/combos", module: "server/management/combo-routes", mutates: true },
|
|
168
|
+
{ method: "GET", path: "/api/combos", module: "server/management/combo-routes", mutates: false },
|
|
169
|
+
{ method: "PUT", path: "/api/combos", module: "server/management/combo-routes", mutates: true },
|
|
170
|
+
// server/management/config-routes
|
|
171
|
+
{ method: "GET", path: "/api/config", module: "server/management/config-routes", mutates: false },
|
|
172
|
+
{ method: "GET", path: "/api/diagnostics/project-config", module: "server/management/config-routes", mutates: false },
|
|
173
|
+
{ method: "GET", path: "/api/settings", module: "server/management/config-routes", mutates: false },
|
|
174
|
+
{ method: "GET", path: "/api/shadow-call-settings", module: "server/management/config-routes", mutates: false },
|
|
175
|
+
{ method: "GET", path: "/api/sidecar-settings", module: "server/management/config-routes", mutates: false },
|
|
176
|
+
{ method: "GET", path: "/api/startup-health", module: "server/management/config-routes", mutates: false },
|
|
177
|
+
{ method: "GET", path: "/api/update/check", module: "server/management/config-routes", mutates: false },
|
|
178
|
+
{ method: "GET", path: "/api/update/status", module: "server/management/config-routes", mutates: false },
|
|
179
|
+
{ method: "GET", path: "/api/windows-tray", module: "server/management/config-routes", mutates: false },
|
|
180
|
+
{ method: "POST", path: "/api/startup-action", module: "server/management/config-routes", mutates: true },
|
|
181
|
+
{ method: "POST", path: "/api/sync", module: "server/management/config-routes", mutates: true },
|
|
182
|
+
{ method: "POST", path: "/api/update/run", module: "server/management/config-routes", mutates: true },
|
|
183
|
+
{ method: "POST", path: "/api/windows-tray", module: "server/management/config-routes", mutates: true },
|
|
184
|
+
{ method: "PUT", path: "/api/config", module: "server/management/config-routes", mutates: true, exempt: { reason: "disabled", why: "Returns 405 by design; provider changes go through POST /api/providers." } },
|
|
185
|
+
{ method: "PUT", path: "/api/settings", module: "server/management/config-routes", mutates: true },
|
|
186
|
+
{ method: "PUT", path: "/api/shadow-call-settings", module: "server/management/config-routes", mutates: true },
|
|
187
|
+
{ method: "PUT", path: "/api/sidecar-settings", module: "server/management/config-routes", mutates: true },
|
|
188
|
+
// server/management/integration-routes
|
|
189
|
+
{ method: "GET", path: "/api/client-integrations", module: "server/management/integration-routes", mutates: false },
|
|
190
|
+
{ method: "GET", path: "/api/client-integrations/journal", module: "server/management/integration-routes", mutates: false },
|
|
191
|
+
{ method: "POST", path: "/api/client-integrations/restore", module: "server/management/integration-routes", mutates: true },
|
|
192
|
+
// server/management/lab-automation-routes
|
|
193
|
+
{ method: "GET", path: "/api/lab/automation", module: "server/management/lab-automation-routes", mutates: false, exempt: { reason: "local-transport", why: "ocx lab reads the same rows from the local SQLite projection; src/cli/lab.ts imports ../lab/query directly and never fetches /api/lab." } },
|
|
194
|
+
{ method: "GET", path: "/api/lab/automation/runs", module: "server/management/lab-automation-routes", mutates: false, exempt: { reason: "local-transport", why: "ocx lab reads the same rows from the local SQLite projection; src/cli/lab.ts imports ../lab/query directly and never fetches /api/lab." } },
|
|
195
|
+
{ method: "POST", path: "/api/lab/automation/run", module: "server/management/lab-automation-routes", mutates: true, exempt: { reason: "deferred-verb", why: "Lab automation run has no CLI verb yet. A local SQLite read cannot drive it, so local-transport does not apply.", owner: "wp7", ownerDoc: "devlog/_plan/260828_ocx_agentic_control/060_phase_gui_parity.md" } },
|
|
196
|
+
{ method: "PUT", path: "/api/lab/automation", module: "server/management/lab-automation-routes", mutates: true, exempt: { reason: "deferred-verb", why: "Lab automation config update has no CLI verb yet. A local SQLite read cannot drive it, so local-transport does not apply.", owner: "wp7", ownerDoc: "devlog/_plan/260828_ocx_agentic_control/060_phase_gui_parity.md" } },
|
|
197
|
+
// server/management/lab-routes
|
|
198
|
+
{ method: "GET", path: "/api/lab/artifacts", module: "server/management/lab-routes", mutates: false, exempt: { reason: "local-transport", why: "ocx lab reads the same rows from the local SQLite projection; src/cli/lab.ts imports ../lab/query directly and never fetches /api/lab." } },
|
|
199
|
+
{ method: "GET", path: "/api/lab/catalog", module: "server/management/lab-routes", mutates: false, exempt: { reason: "local-transport", why: "ocx lab reads the same rows from the local SQLite projection; src/cli/lab.ts imports ../lab/query directly and never fetches /api/lab." } },
|
|
200
|
+
{ method: "GET", path: "/api/lab/events", module: "server/management/lab-routes", mutates: false, exempt: { reason: "local-transport", why: "ocx lab reads the same rows from the local SQLite projection; src/cli/lab.ts imports ../lab/query directly and never fetches /api/lab." } },
|
|
201
|
+
{ method: "GET", path: "/api/lab/observations", module: "server/management/lab-routes", mutates: false, exempt: { reason: "local-transport", why: "ocx lab reads the same rows from the local SQLite projection; src/cli/lab.ts imports ../lab/query directly and never fetches /api/lab." } },
|
|
202
|
+
{ method: "GET", path: "/api/lab/production-signals", module: "server/management/lab-routes", mutates: false, exempt: { reason: "local-transport", why: "ocx lab reads the same rows from the local SQLite projection; src/cli/lab.ts imports ../lab/query directly and never fetches /api/lab." } },
|
|
203
|
+
{ method: "GET", path: "/api/lab/public/community", module: "server/management/lab-routes", mutates: false, exempt: { reason: "local-transport", why: "ocx lab reads the same rows from the local SQLite projection; src/cli/lab.ts imports ../lab/query directly and never fetches /api/lab." } },
|
|
204
|
+
{ method: "GET", path: "/api/lab/status", module: "server/management/lab-routes", mutates: false, exempt: { reason: "local-transport", why: "ocx lab reads the same rows from the local SQLite projection; src/cli/lab.ts imports ../lab/query directly and never fetches /api/lab." } },
|
|
205
|
+
{ method: "GET", path: "/api/lab/subjects", module: "server/management/lab-routes", mutates: false, exempt: { reason: "local-transport", why: "ocx lab reads the same rows from the local SQLite projection; src/cli/lab.ts imports ../lab/query directly and never fetches /api/lab." } },
|
|
206
|
+
{ method: "GET", path: "/api/lab/verdicts", module: "server/management/lab-routes", mutates: false, exempt: { reason: "local-transport", why: "ocx lab reads the same rows from the local SQLite projection; src/cli/lab.ts imports ../lab/query directly and never fetches /api/lab." } },
|
|
207
|
+
{ method: "POST", path: "/api/lab/public/community/import", module: "server/management/lab-routes", mutates: true, exempt: { reason: "deferred-verb", why: "Community evidence import has no CLI verb yet. A local SQLite read cannot drive it, so local-transport does not apply.", owner: "wp7", ownerDoc: "devlog/_plan/260828_ocx_agentic_control/060_phase_gui_parity.md" } },
|
|
208
|
+
{ method: "POST", path: "/api/lab/public/export", module: "server/management/lab-routes", mutates: true, exempt: { reason: "deferred-verb", why: "Public evidence export has no CLI verb yet. A local SQLite read cannot drive it, so local-transport does not apply.", owner: "wp7", ownerDoc: "devlog/_plan/260828_ocx_agentic_control/060_phase_gui_parity.md" } },
|
|
209
|
+
{ method: "POST", path: "/api/lab/public/preview", module: "server/management/lab-routes", mutates: true, exempt: { reason: "deferred-verb", why: "Public evidence preview has no CLI verb yet. A local SQLite read cannot drive it, so local-transport does not apply.", owner: "wp7", ownerDoc: "devlog/_plan/260828_ocx_agentic_control/060_phase_gui_parity.md" } },
|
|
210
|
+
{ method: "POST", path: "/api/lab/public/verify", module: "server/management/lab-routes", mutates: true, exempt: { reason: "deferred-verb", why: "Public evidence verification has no CLI verb yet. A local SQLite read cannot drive it, so local-transport does not apply.", owner: "wp7", ownerDoc: "devlog/_plan/260828_ocx_agentic_control/060_phase_gui_parity.md" } },
|
|
211
|
+
// server/management/logs-usage-routes
|
|
212
|
+
{ method: "GET", path: "/api/claude/inbound-debug", module: "server/management/logs-usage-routes", mutates: false },
|
|
213
|
+
{ method: "GET", path: "/api/debug", module: "server/management/logs-usage-routes", mutates: false },
|
|
214
|
+
{ method: "GET", path: "/api/debug/injection-logs", module: "server/management/logs-usage-routes", mutates: false },
|
|
215
|
+
{ method: "GET", path: "/api/debug/logs", module: "server/management/logs-usage-routes", mutates: false },
|
|
216
|
+
{ method: "GET", path: "/api/debug/usage-logs", module: "server/management/logs-usage-routes", mutates: false },
|
|
217
|
+
{ method: "GET", path: "/api/logs", module: "server/management/logs-usage-routes", mutates: false },
|
|
218
|
+
{ method: "GET", path: "/api/storage/cleanup-policy", module: "server/management/logs-usage-routes", mutates: false },
|
|
219
|
+
{ method: "GET", path: "/api/storage/cleanup-policy/test-stream", module: "server/management/logs-usage-routes", mutates: false, exempt: { reason: "test-seam", why: "Opt-in streaming seam declared at src/storage/policy-job.ts:71." } },
|
|
220
|
+
{ method: "GET", path: "/api/storage/trash", module: "server/management/logs-usage-routes", mutates: false },
|
|
221
|
+
{ method: "GET", path: "/api/storage/trash/restore/test-stream", module: "server/management/logs-usage-routes", mutates: false, exempt: { reason: "test-seam", why: "Opt-in streaming seam declared at src/storage/restore-job.ts:34." } },
|
|
222
|
+
{ method: "GET", path: "/api/usage", module: "server/management/logs-usage-routes", mutates: false },
|
|
223
|
+
{ method: "POST", path: "/api/storage/cleanup", module: "server/management/logs-usage-routes", mutates: true },
|
|
224
|
+
{ method: "POST", path: "/api/storage/cleanup-policy/run", module: "server/management/logs-usage-routes", mutates: true },
|
|
225
|
+
{ method: "POST", path: "/api/storage/cleanup/preview", module: "server/management/logs-usage-routes", mutates: true },
|
|
226
|
+
{ method: "POST", path: "/api/storage/trash/restore", module: "server/management/logs-usage-routes", mutates: true },
|
|
227
|
+
{ method: "POST", path: "/api/usage/ingest", module: "server/management/logs-usage-routes", mutates: true },
|
|
228
|
+
{ method: "PUT", path: "/api/debug", module: "server/management/logs-usage-routes", mutates: true },
|
|
229
|
+
{ method: "PUT", path: "/api/storage/cleanup-policy", module: "server/management/logs-usage-routes", mutates: true },
|
|
230
|
+
// server/management/model-routes
|
|
231
|
+
{ method: "GET", path: "/api/aliases", module: "server/management/model-routes", mutates: false },
|
|
232
|
+
{ method: "GET", path: "/api/catalog", module: "server/management/model-routes", mutates: false },
|
|
233
|
+
{ method: "GET", path: "/api/client-config", module: "server/management/model-routes", mutates: false },
|
|
234
|
+
{ method: "GET", path: "/api/custom-models", module: "server/management/model-routes", mutates: false },
|
|
235
|
+
{ method: "GET", path: "/api/model-discovery", module: "server/management/model-routes", mutates: false },
|
|
236
|
+
{ method: "GET", path: "/api/model-presets", module: "server/management/model-routes", mutates: false },
|
|
237
|
+
{ method: "GET", path: "/api/models", module: "server/management/model-routes", mutates: false },
|
|
238
|
+
{ method: "GET", path: "/api/selected-models", module: "server/management/model-routes", mutates: false },
|
|
239
|
+
{ method: "POST", path: "/api/custom-models", module: "server/management/model-routes", mutates: true },
|
|
240
|
+
{ method: "POST", path: "/api/model-discovery/acknowledge", module: "server/management/model-routes", mutates: true },
|
|
241
|
+
{ method: "PUT", path: "/api/default-aliases", module: "server/management/model-routes", mutates: true },
|
|
242
|
+
{ method: "PUT", path: "/api/disabled-models", module: "server/management/model-routes", mutates: true },
|
|
243
|
+
{ method: "PUT", path: "/api/model-discovery", module: "server/management/model-routes", mutates: true },
|
|
244
|
+
{ method: "PUT", path: "/api/model-presets", module: "server/management/model-routes", mutates: true },
|
|
245
|
+
{ method: "PUT", path: "/api/model-visibility", module: "server/management/model-routes", mutates: true },
|
|
246
|
+
{ method: "PUT", path: "/api/selected-models", module: "server/management/model-routes", mutates: true },
|
|
247
|
+
// server/management/native-integration-routes
|
|
248
|
+
{ method: "GET", path: "/api/native-integrations", module: "server/management/native-integration-routes", mutates: false },
|
|
249
|
+
{ method: "PUT", path: "/api/native-integrations/claude", module: "server/management/native-integration-routes", mutates: true },
|
|
250
|
+
{ method: "PUT", path: "/api/native-integrations/claude-desktop", module: "server/management/native-integration-routes", mutates: true },
|
|
251
|
+
{ method: "PUT", path: "/api/native-integrations/codex", module: "server/management/native-integration-routes", mutates: true },
|
|
252
|
+
{ method: "PUT", path: "/api/native-integrations/grok", module: "server/management/native-integration-routes", mutates: true },
|
|
253
|
+
// server/management/oauth-account-routes
|
|
254
|
+
{ method: "DELETE", path: "/api/keys", module: "server/management/oauth-account-routes", mutates: true },
|
|
255
|
+
{ method: "DELETE", path: "/api/oauth/accounts", module: "server/management/oauth-account-routes", mutates: true },
|
|
256
|
+
{ method: "DELETE", path: "/api/providers/keys", module: "server/management/oauth-account-routes", mutates: true },
|
|
257
|
+
{ method: "GET", path: "/api/key-providers", module: "server/management/oauth-account-routes", mutates: false },
|
|
258
|
+
{ method: "GET", path: "/api/keys", module: "server/management/oauth-account-routes", mutates: false },
|
|
259
|
+
{ method: "GET", path: "/api/oauth/accounts", module: "server/management/oauth-account-routes", mutates: false },
|
|
260
|
+
{ method: "GET", path: "/api/oauth/accounts/pool", module: "server/management/oauth-account-routes", mutates: false },
|
|
261
|
+
{ method: "GET", path: "/api/oauth/providers", module: "server/management/oauth-account-routes", mutates: false },
|
|
262
|
+
{ method: "GET", path: "/api/oauth/status", module: "server/management/oauth-account-routes", mutates: false },
|
|
263
|
+
{ method: "GET", path: "/api/providers/keys", module: "server/management/oauth-account-routes", mutates: false },
|
|
264
|
+
{ method: "PATCH", path: "/api/keys", module: "server/management/oauth-account-routes", mutates: true },
|
|
265
|
+
{ method: "PATCH", path: "/api/oauth/accounts/pool", module: "server/management/oauth-account-routes", mutates: true },
|
|
266
|
+
{ method: "POST", path: "/api/keys", module: "server/management/oauth-account-routes", mutates: true },
|
|
267
|
+
{ method: "POST", path: "/api/oauth/accounts/clear-cooldown", module: "server/management/oauth-account-routes", mutates: true },
|
|
268
|
+
{ method: "POST", path: "/api/oauth/accounts/import", module: "server/management/oauth-account-routes", mutates: true },
|
|
269
|
+
{ method: "POST", path: "/api/oauth/login", module: "server/management/oauth-account-routes", mutates: true },
|
|
270
|
+
{ method: "POST", path: "/api/oauth/login/cancel", module: "server/management/oauth-account-routes", mutates: true },
|
|
271
|
+
{ method: "POST", path: "/api/oauth/login/code", module: "server/management/oauth-account-routes", mutates: true },
|
|
272
|
+
{ method: "POST", path: "/api/oauth/logout", module: "server/management/oauth-account-routes", mutates: true },
|
|
273
|
+
{ method: "POST", path: "/api/providers/keys", module: "server/management/oauth-account-routes", mutates: true },
|
|
274
|
+
{ method: "PUT", path: "/api/oauth/accounts/active", module: "server/management/oauth-account-routes", mutates: true },
|
|
275
|
+
{ method: "PUT", path: "/api/oauth/accounts/alias", module: "server/management/oauth-account-routes", mutates: true },
|
|
276
|
+
{ method: "PUT", path: "/api/oauth/accounts/pool", module: "server/management/oauth-account-routes", mutates: true },
|
|
277
|
+
{ method: "PUT", path: "/api/providers/keys/active", module: "server/management/oauth-account-routes", mutates: true },
|
|
278
|
+
{ method: "PUT", path: "/api/providers/keys/alias", module: "server/management/oauth-account-routes", mutates: true },
|
|
279
|
+
// server/management/provider-routes
|
|
280
|
+
{ method: "DELETE", path: "/api/providers", module: "server/management/provider-routes", mutates: true },
|
|
281
|
+
{ method: "GET", path: "/api/provider-context-caps", module: "server/management/provider-routes", mutates: false },
|
|
282
|
+
{ method: "GET", path: "/api/provider-presets", module: "server/management/provider-routes", mutates: false },
|
|
283
|
+
{ method: "GET", path: "/api/provider-quotas", module: "server/management/provider-routes", mutates: false },
|
|
284
|
+
{ method: "GET", path: "/api/provider-request-pacing", module: "server/management/provider-routes", mutates: false },
|
|
285
|
+
{ method: "GET", path: "/api/providers", module: "server/management/provider-routes", mutates: false },
|
|
286
|
+
{ method: "PATCH", path: "/api/providers", module: "server/management/provider-routes", mutates: true },
|
|
287
|
+
{ method: "POST", path: "/api/providers", module: "server/management/provider-routes", mutates: true },
|
|
288
|
+
{ method: "POST", path: "/api/providers/refresh-models", module: "server/management/provider-routes", mutates: true },
|
|
289
|
+
{ method: "POST", path: "/api/providers/test", module: "server/management/provider-routes", mutates: true },
|
|
290
|
+
{ method: "PUT", path: "/api/provider-context-caps", module: "server/management/provider-routes", mutates: true },
|
|
291
|
+
// server/management/request-history-routes
|
|
292
|
+
{ method: "GET", path: "/api/request-history", module: "server/management/request-history-routes", mutates: false },
|
|
293
|
+
// server/management/routing-analytics-routes
|
|
294
|
+
// server/management/routing-profile-routes
|
|
295
|
+
{ method: "DELETE", path: "/api/routing-profiles", module: "server/management/routing-profile-routes", mutates: true },
|
|
296
|
+
{ method: "GET", path: "/api/routing-profiles", module: "server/management/routing-profile-routes", mutates: false },
|
|
297
|
+
{ method: "POST", path: "/api/routing-profiles/dry-run", module: "server/management/routing-profile-routes", mutates: true },
|
|
298
|
+
{ method: "PUT", path: "/api/routing-profiles", module: "server/management/routing-profile-routes", mutates: true },
|
|
299
|
+
// server/management/sidebar-routes
|
|
300
|
+
{ method: "GET", path: "/api/github/star", module: "server/management/sidebar-routes", mutates: false },
|
|
301
|
+
{ method: "GET", path: "/api/update/badge", module: "server/management/sidebar-routes", mutates: false },
|
|
302
|
+
{ method: "POST", path: "/api/github/star", module: "server/management/sidebar-routes", mutates: true, exempt: { reason: "session-only", why: "User-consent boundary in AGENTS_INSTALL.md: starring spends the user's identity. Must never gain a CLI verb." } },
|
|
303
|
+
// server/management/storage-log-guard-routes
|
|
304
|
+
{ method: "GET", path: "/api/storage/codex-logs", module: "server/management/storage-log-guard-routes", mutates: false },
|
|
305
|
+
{ method: "POST", path: "/api/storage/codex-logs/compact", module: "server/management/storage-log-guard-routes", mutates: true },
|
|
306
|
+
{ method: "POST", path: "/api/storage/codex-logs/protect", module: "server/management/storage-log-guard-routes", mutates: true },
|
|
307
|
+
{ method: "POST", path: "/api/storage/codex-logs/repair", module: "server/management/storage-log-guard-routes", mutates: true },
|
|
308
|
+
{ method: "POST", path: "/api/storage/codex-logs/unprotect", module: "server/management/storage-log-guard-routes", mutates: true },
|
|
309
|
+
// server/management/system-routes
|
|
310
|
+
{ method: "GET", path: "/api/system/memory", module: "server/management/system-routes", mutates: false },
|
|
311
|
+
{ method: "GET", path: "/api/system/windows-replace-retries", module: "server/management/system-routes", mutates: false },
|
|
312
|
+
{ method: "POST", path: "/api/system/restart", module: "server/management/system-routes", mutates: true },
|
|
313
|
+
// --- Routes an equality scan of their own file cannot see (18). ---
|
|
314
|
+
// Each carries `mechanism`; the reconciliation test counts these separately.
|
|
315
|
+
{ method: "GET", path: "/api/storage", module: "server/management/storage-log-guard-routes", mutates: false, mechanism: "negated-guard" },
|
|
316
|
+
{ method: "GET", path: "/api/routing-analytics", module: "server/management/routing-analytics-routes", mutates: false, mechanism: "negated-guard" },
|
|
317
|
+
{ method: "GET", path: "/api/system/codex-app-server", module: "server/management/system-routes", mutates: false, mechanism: "path-constant" },
|
|
318
|
+
{ method: "POST", path: "/api/system/codex-restart", module: "server/management/system-routes", mutates: true, mechanism: "path-constant" },
|
|
319
|
+
{ method: "POST", path: "/api/providers/reload", module: "server/management/provider-routes", mutates: true, mechanism: "path-constant", exempt: { reason: "capability-principal", why: "Gated on the local-provider-reload-capability principal (provider-routes.ts:467), not an operator action." } },
|
|
320
|
+
{ method: "GET", path: "/api/client-integrations/{clientId}", module: "server/management/integration-routes", mutates: false, mechanism: "prefix-decode" },
|
|
321
|
+
{ method: "PUT", path: "/api/client-integrations/{clientId}", module: "server/management/integration-routes", mutates: true, mechanism: "prefix-decode" },
|
|
322
|
+
{ method: "GET", path: "/api/request-history/{id}", module: "server/management/request-history-routes", mutates: false, mechanism: "slice" },
|
|
323
|
+
{ method: "GET", path: "/api/request-history/{id}/route-decision", module: "server/management/request-history-routes", mutates: false, mechanism: "ends-with" },
|
|
324
|
+
{ method: "PUT", path: "/api/providers/{provider}/alias", module: "server/management/model-routes", mutates: true, mechanism: "regex" },
|
|
325
|
+
{ method: "PUT", path: "/api/providers/{provider}/model-aliases", module: "server/management/model-routes", mutates: true, mechanism: "regex" },
|
|
326
|
+
{ method: "PUT", path: "/api/custom-models/{id}", module: "server/management/model-routes", mutates: true, mechanism: "regex" },
|
|
327
|
+
{ method: "DELETE", path: "/api/custom-models/{id}", module: "server/management/model-routes", mutates: true, mechanism: "regex" },
|
|
328
|
+
{ method: "GET", path: "/api/lab/subjects/{id}", module: "server/management/lab-routes", mutates: false, mechanism: "regex", exempt: { reason: "local-transport", why: "ocx lab reads the same rows from the local SQLite projection; src/cli/lab.ts imports ../lab/query directly and never fetches /api/lab." } },
|
|
329
|
+
{ method: "GET", path: "/api/lab/events/{id}", module: "server/management/lab-routes", mutates: false, mechanism: "regex", exempt: { reason: "local-transport", why: "ocx lab reads the same rows from the local SQLite projection; src/cli/lab.ts imports ../lab/query directly and never fetches /api/lab." } },
|
|
330
|
+
{ method: "GET", path: "/api/lab/artifacts/{digest}", module: "server/management/lab-routes", mutates: false, mechanism: "regex", exempt: { reason: "local-transport", why: "ocx lab reads the same rows from the local SQLite projection; src/cli/lab.ts imports ../lab/query directly and never fetches /api/lab." } },
|
|
331
|
+
{ method: "POST", path: "/api/lab/automation/runs/{id}/cancel", module: "server/management/lab-automation-routes", mutates: true, mechanism: "regex", exempt: { reason: "deferred-verb", why: "Lab automation run cancellation has no CLI verb yet. A local SQLite read cannot drive it, so local-transport does not apply.", owner: "wp7", ownerDoc: "devlog/_plan/260828_ocx_agentic_control/060_phase_gui_parity.md" } },
|
|
332
|
+
];
|