@yansigit/opencodex 2.36.1-dev.20260829.48 → 2.36.1
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/gui/dist/assets/{ApiKeys-LOOFiZfv.js → ApiKeys-CsmNyf4I.js} +1 -1
- package/gui/dist/assets/{Claude-BwKzpXe3.js → Claude-B4sHsGTD.js} +1 -1
- package/gui/dist/assets/{CodexSet-B5qi9KeE.js → CodexSet-BuAQ4YQn.js} +1 -1
- package/gui/dist/assets/{FileIntegrationPage-B0sUef6W.js → FileIntegrationPage-BC65sEaS.js} +1 -1
- package/gui/dist/assets/{Grok-bsb4n-f4.js → Grok-DNJWlISf.js} +1 -1
- package/gui/dist/assets/{Integrations-CSMwFDvM.js → Integrations-vGJshFZK.js} +2 -2
- package/gui/dist/assets/{IntegrationsOverview-CTORdKJA.js → IntegrationsOverview-DYMkDFHE.js} +1 -1
- package/gui/dist/assets/{Logs-BWYbfELf.js → Logs-Coc7_RPP.js} +1 -1
- package/gui/dist/assets/{Models-CexEtdT1.js → Models-CKVT8Meb.js} +1 -1
- package/gui/dist/assets/{NumberStepper-BapSFQnW.js → NumberStepper-Dug4wR8n.js} +1 -1
- package/gui/dist/assets/{Providers-BwUFeAgA.js → Providers-DyaCHRWL.js} +1 -1
- package/gui/dist/assets/{RestoreDialog-CD8piq90.js → RestoreDialog-BpuvVU2w.js} +1 -1
- package/gui/dist/assets/{Startup-BgX731C2.js → Startup-DAUQqNEN.js} +1 -1
- package/gui/dist/assets/{Storage-Bgq7HphP.js → Storage-DfP95SlJ.js} +1 -1
- package/gui/dist/assets/{Subagents-ChxItbeF.js → Subagents-CMNsZLfk.js} +1 -1
- package/gui/dist/assets/{Usage-BkylzP50.js → Usage-ESFRfBMO.js} +1 -1
- package/gui/dist/assets/{codex-stale-banner-D4gvSWnO.js → codex-stale-banner-W4FhikN7.js} +1 -1
- package/gui/dist/assets/{data-surface-BtO3lwam.js → data-surface-B8PX8rjm.js} +1 -1
- package/gui/dist/assets/{data-surface-pCXChiBf.js → data-surface-CETFXqiA.js} +1 -1
- package/gui/dist/assets/{index-CNopOid3.js → index-DHQHBRhb.js} +3 -3
- package/gui/dist/assets/{model-display-CiUpg8T9.js → model-display-OBTJhQwT.js} +1 -1
- package/gui/dist/assets/{provider-payload-b2jlS-On.js → provider-payload-CJRJUn7w.js} +1 -1
- package/gui/dist/assets/{section-tabs-BP7gEPK6.js → section-tabs-B8sLMiz6.js} +1 -1
- package/gui/dist/assets/shared-DI18-uF7.js +69 -0
- package/gui/dist/index.html +2 -2
- package/package.json +3 -1
- package/src/adapters/base.ts +26 -0
- package/src/adapters/cursor/catalog.ts +541 -0
- package/src/adapters/cursor/cursor-errors.ts +15 -0
- package/src/adapters/cursor/discovery.ts +34 -41
- package/src/adapters/cursor/envelope-echo.ts +128 -0
- package/src/adapters/cursor/request-builder.ts +19 -12
- package/src/adapters/cursor/tool-definitions.ts +2 -1
- package/src/adapters/cursor/tool-result-normalize.ts +23 -31
- package/src/adapters/cursor.ts +21 -2
- package/src/adapters/exec-tool-result-normalize.ts +99 -0
- package/src/adapters/google-antigravity-replay.ts +71 -2
- package/src/adapters/google.ts +19 -4
- package/src/adapters/kiro-constants.ts +12 -0
- package/src/adapters/kiro.ts +128 -11
- package/src/adapters/openai-chat.ts +16 -2
- package/src/adapters/openai-responses.ts +15 -2
- package/src/adapters/tool-catalog-nudge.ts +2 -1
- package/src/adapters/xai-web-search.ts +10 -14
- package/src/claude/outbound.ts +14 -3
- package/src/cli/access.ts +46 -3
- package/src/cli/account-api.ts +93 -16
- package/src/cli/account-extended.ts +262 -36
- package/src/cli/account-main.ts +12 -12
- package/src/cli/account.ts +40 -10
- package/src/cli/agent.ts +8 -1
- package/src/cli/capabilities-command.ts +94 -0
- package/src/cli/capabilities.ts +535 -0
- package/src/cli/claude-desktop.ts +31 -11
- package/src/cli/dispatch.ts +195 -27
- package/src/cli/doctor.ts +100 -1
- package/src/cli/help.ts +11 -2
- package/src/cli/index.ts +19 -3
- package/src/cli/inspect.ts +230 -0
- package/src/cli/observe.ts +11 -3
- package/src/cli/registry.ts +34 -2
- package/src/cli/runtime-api.ts +51 -7
- package/src/cli/status.ts +16 -0
- package/src/cli/storage.ts +234 -0
- package/src/cli/system-command.ts +16 -0
- package/src/cli/usage-report.ts +52 -2
- package/src/cli/version-skew.ts +46 -0
- package/src/codex/account-label.ts +21 -0
- package/src/codex/catalog/provider-fetch.ts +4 -0
- package/src/codex/transition-state.ts +12 -3
- package/src/compatibility/openai-responses.ts +9 -1
- package/src/generated/compatibility-version.json +94 -58
- package/src/integrations/ownership-policy.ts +24 -5
- package/src/integrations/ownership.ts +36 -2
- package/src/integrations/state.ts +40 -7
- package/src/integrations/writer.ts +21 -3
- package/src/lib/admin-secrets.ts +24 -0
- package/src/lib/errors.ts +25 -1
- package/src/lib/service-secrets.ts +15 -0
- package/src/oauth/store.ts +16 -6
- package/src/providers/label.ts +34 -1
- package/src/responses/turn-termination.ts +107 -0
- package/src/server/management/logs-usage-routes.ts +5 -27
- package/src/server/management/route-registry.ts +317 -0
- package/src/server/proxy-liveness.ts +27 -4
- package/src/server/request-log.ts +37 -17
- package/src/server/responses/core.ts +80 -4
- package/src/server/responses/policy-fallback.ts +1 -1
- package/src/service.ts +34 -0
- package/src/storage/policy-job.ts +14 -4
- package/src/storage/policy.ts +79 -33
- package/src/usage/log.ts +32 -6
- package/src/usage/summary.ts +22 -34
- package/gui/dist/assets/shared-BdYGV-yJ.js +0 -69
|
@@ -0,0 +1,317 @@
|
|
|
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/providers/test", module: "server/management-api", mutates: true },
|
|
84
|
+
{ method: "POST", path: "/api/stop", module: "server/management-api", mutates: true },
|
|
85
|
+
// codex/auth-api
|
|
86
|
+
{ method: "DELETE", path: "/api/codex-auth/accounts", module: "codex/auth-api", mutates: true },
|
|
87
|
+
{ method: "GET", path: "/api/codex-auth/accounts", module: "codex/auth-api", mutates: false },
|
|
88
|
+
{ method: "GET", path: "/api/codex-auth/active", module: "codex/auth-api", mutates: false },
|
|
89
|
+
{ method: "GET", path: "/api/codex-auth/login-status", module: "codex/auth-api", mutates: false },
|
|
90
|
+
{ method: "GET", path: "/api/codex-auth/quota", module: "codex/auth-api", mutates: false },
|
|
91
|
+
{ method: "GET", path: "/api/codex-auth/reset-credits", module: "codex/auth-api", mutates: false },
|
|
92
|
+
{ method: "PATCH", path: "/api/codex-auth/pool-strategy", module: "codex/auth-api", mutates: true },
|
|
93
|
+
{ method: "POST", path: "/api/codex-auth/accounts", module: "codex/auth-api", mutates: true },
|
|
94
|
+
{ method: "POST", path: "/api/codex-auth/accounts/clear-cooldown", module: "codex/auth-api", mutates: true },
|
|
95
|
+
{ method: "POST", path: "/api/codex-auth/login", module: "codex/auth-api", mutates: true },
|
|
96
|
+
{ method: "POST", path: "/api/codex-auth/login/cancel", module: "codex/auth-api", mutates: true },
|
|
97
|
+
{ method: "POST", path: "/api/codex-auth/login/code", module: "codex/auth-api", mutates: true },
|
|
98
|
+
{ method: "POST", path: "/api/codex-auth/reset-credits/consume", module: "codex/auth-api", mutates: true },
|
|
99
|
+
{ method: "PUT", path: "/api/codex-auth/accounts/alias", module: "codex/auth-api", mutates: true },
|
|
100
|
+
{ method: "PUT", path: "/api/codex-auth/accounts/pause", module: "codex/auth-api", mutates: true },
|
|
101
|
+
{ method: "PUT", path: "/api/codex-auth/accounts/pause-exhausted", module: "codex/auth-api", mutates: true },
|
|
102
|
+
{ method: "PUT", path: "/api/codex-auth/accounts/priority", module: "codex/auth-api", mutates: true },
|
|
103
|
+
{ method: "PUT", path: "/api/codex-auth/active", module: "codex/auth-api", mutates: true },
|
|
104
|
+
{ method: "PUT", path: "/api/codex-auth/auto-switch", module: "codex/auth-api", mutates: true },
|
|
105
|
+
{ method: "PUT", path: "/api/codex-auth/failover", module: "codex/auth-api", mutates: true },
|
|
106
|
+
{ method: "PUT", path: "/api/codex-auth/pool-strategy", module: "codex/auth-api", mutates: true },
|
|
107
|
+
// codex/native-profile-api
|
|
108
|
+
{ method: "GET", path: "/api/native-main-profiles", module: "codex/native-profile-api", mutates: false },
|
|
109
|
+
{ method: "GET", path: "/api/native-main-profiles/doctor", module: "codex/native-profile-api", mutates: false },
|
|
110
|
+
{ method: "POST", path: "/api/native-main-profiles/recover", module: "codex/native-profile-api", mutates: true },
|
|
111
|
+
{ method: "POST", path: "/api/native-main-profiles/register", module: "codex/native-profile-api", mutates: true },
|
|
112
|
+
{ method: "POST", path: "/api/native-main-profiles/stage", module: "codex/native-profile-api", mutates: true },
|
|
113
|
+
{ method: "POST", path: "/api/native-main-profiles/stage/cancel", module: "codex/native-profile-api", mutates: true },
|
|
114
|
+
{ method: "POST", path: "/api/native-main-profiles/stage/finish", module: "codex/native-profile-api", mutates: true },
|
|
115
|
+
{ method: "POST", path: "/api/native-main-profiles/stage/heartbeat", module: "codex/native-profile-api", mutates: true },
|
|
116
|
+
{ method: "POST", path: "/api/native-main-profiles/switch", module: "codex/native-profile-api", mutates: true },
|
|
117
|
+
// server/management/agent-settings-routes
|
|
118
|
+
{ method: "GET", path: "/api/claude-code", module: "server/management/agent-settings-routes", mutates: false },
|
|
119
|
+
{ method: "GET", path: "/api/claude-desktop", module: "server/management/agent-settings-routes", mutates: false },
|
|
120
|
+
{ method: "GET", path: "/api/claude-desktop/status", module: "server/management/agent-settings-routes", mutates: false },
|
|
121
|
+
{ method: "GET", path: "/api/codex-auth/features/default-mode-request-user-input", module: "server/management/agent-settings-routes", mutates: false },
|
|
122
|
+
{ method: "GET", path: "/api/effort-caps", module: "server/management/agent-settings-routes", mutates: false },
|
|
123
|
+
{ method: "GET", path: "/api/grok", module: "server/management/agent-settings-routes", mutates: false },
|
|
124
|
+
{ method: "GET", path: "/api/injection-model", module: "server/management/agent-settings-routes", mutates: false },
|
|
125
|
+
{ method: "GET", path: "/api/subagent-model-fallback", module: "server/management/agent-settings-routes", mutates: false },
|
|
126
|
+
{ method: "GET", path: "/api/subagent-models", module: "server/management/agent-settings-routes", mutates: false },
|
|
127
|
+
{ method: "GET", path: "/api/subagent-roles", module: "server/management/agent-settings-routes", mutates: false },
|
|
128
|
+
{ method: "GET", path: "/api/v2", module: "server/management/agent-settings-routes", mutates: false },
|
|
129
|
+
{ method: "POST", path: "/api/claude-desktop/apply", module: "server/management/agent-settings-routes", mutates: true },
|
|
130
|
+
{ method: "POST", path: "/api/grok/apply", module: "server/management/agent-settings-routes", mutates: true },
|
|
131
|
+
{ method: "POST", path: "/api/subagent-model-authority", module: "server/management/agent-settings-routes", mutates: false },
|
|
132
|
+
{ method: "PUT", path: "/api/claude-code", module: "server/management/agent-settings-routes", mutates: true },
|
|
133
|
+
{ method: "PUT", path: "/api/claude-desktop", module: "server/management/agent-settings-routes", mutates: true },
|
|
134
|
+
{ method: "PUT", path: "/api/codex-auth/features/default-mode-request-user-input", module: "server/management/agent-settings-routes", mutates: true },
|
|
135
|
+
{ method: "PUT", path: "/api/effort-caps", module: "server/management/agent-settings-routes", mutates: true },
|
|
136
|
+
{ method: "PUT", path: "/api/grok/selection", module: "server/management/agent-settings-routes", mutates: true },
|
|
137
|
+
{ method: "PUT", path: "/api/injection-model", module: "server/management/agent-settings-routes", mutates: true },
|
|
138
|
+
{ method: "PUT", path: "/api/subagent-model-fallback", module: "server/management/agent-settings-routes", mutates: true },
|
|
139
|
+
{ method: "PUT", path: "/api/subagent-models", module: "server/management/agent-settings-routes", mutates: true },
|
|
140
|
+
{ method: "PUT", path: "/api/subagent-roles", module: "server/management/agent-settings-routes", mutates: true },
|
|
141
|
+
{ method: "PUT", path: "/api/v2", module: "server/management/agent-settings-routes", mutates: true },
|
|
142
|
+
// server/management/codex-prompt-routes
|
|
143
|
+
{ method: "GET", path: "/api/codex-prompt", module: "server/management/codex-prompt-routes", mutates: false },
|
|
144
|
+
{ method: "GET", path: "/api/codex-prompt/text", module: "server/management/codex-prompt-routes", mutates: false },
|
|
145
|
+
{ 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)." } },
|
|
146
|
+
{ 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)." } },
|
|
147
|
+
{ 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)." } },
|
|
148
|
+
{ 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)." } },
|
|
149
|
+
{ 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)." } },
|
|
150
|
+
{ 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)." } },
|
|
151
|
+
// server/management/combo-routes
|
|
152
|
+
{ method: "DELETE", path: "/api/combos", module: "server/management/combo-routes", mutates: true },
|
|
153
|
+
{ method: "GET", path: "/api/combos", module: "server/management/combo-routes", mutates: false },
|
|
154
|
+
{ method: "PUT", path: "/api/combos", module: "server/management/combo-routes", mutates: true },
|
|
155
|
+
// server/management/config-routes
|
|
156
|
+
{ method: "GET", path: "/api/config", module: "server/management/config-routes", mutates: false },
|
|
157
|
+
{ method: "GET", path: "/api/diagnostics/project-config", module: "server/management/config-routes", mutates: false },
|
|
158
|
+
{ method: "GET", path: "/api/settings", module: "server/management/config-routes", mutates: false },
|
|
159
|
+
{ method: "GET", path: "/api/shadow-call-settings", module: "server/management/config-routes", mutates: false },
|
|
160
|
+
{ method: "GET", path: "/api/sidecar-settings", module: "server/management/config-routes", mutates: false },
|
|
161
|
+
{ method: "GET", path: "/api/startup-health", module: "server/management/config-routes", mutates: false },
|
|
162
|
+
{ method: "GET", path: "/api/update/check", module: "server/management/config-routes", mutates: false },
|
|
163
|
+
{ method: "GET", path: "/api/update/status", module: "server/management/config-routes", mutates: false },
|
|
164
|
+
{ method: "GET", path: "/api/windows-tray", module: "server/management/config-routes", mutates: false },
|
|
165
|
+
{ method: "POST", path: "/api/startup-action", module: "server/management/config-routes", mutates: true },
|
|
166
|
+
{ method: "POST", path: "/api/sync", module: "server/management/config-routes", mutates: true },
|
|
167
|
+
{ method: "POST", path: "/api/update/run", module: "server/management/config-routes", mutates: true },
|
|
168
|
+
{ method: "POST", path: "/api/windows-tray", module: "server/management/config-routes", mutates: true },
|
|
169
|
+
{ 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." } },
|
|
170
|
+
{ method: "PUT", path: "/api/settings", module: "server/management/config-routes", mutates: true },
|
|
171
|
+
{ method: "PUT", path: "/api/shadow-call-settings", module: "server/management/config-routes", mutates: true },
|
|
172
|
+
{ method: "PUT", path: "/api/sidecar-settings", module: "server/management/config-routes", mutates: true },
|
|
173
|
+
// server/management/integration-routes
|
|
174
|
+
{ method: "GET", path: "/api/client-integrations", module: "server/management/integration-routes", mutates: false },
|
|
175
|
+
{ method: "GET", path: "/api/client-integrations/journal", module: "server/management/integration-routes", mutates: false },
|
|
176
|
+
{ method: "POST", path: "/api/client-integrations/restore", module: "server/management/integration-routes", mutates: true },
|
|
177
|
+
// server/management/lab-automation-routes
|
|
178
|
+
{ 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." } },
|
|
179
|
+
{ 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." } },
|
|
180
|
+
{ 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" } },
|
|
181
|
+
{ 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" } },
|
|
182
|
+
// server/management/lab-routes
|
|
183
|
+
{ 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." } },
|
|
184
|
+
{ 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." } },
|
|
185
|
+
{ 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." } },
|
|
186
|
+
{ 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." } },
|
|
187
|
+
{ 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." } },
|
|
188
|
+
{ 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." } },
|
|
189
|
+
{ 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." } },
|
|
190
|
+
{ 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." } },
|
|
191
|
+
{ 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." } },
|
|
192
|
+
{ 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" } },
|
|
193
|
+
{ 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" } },
|
|
194
|
+
{ 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" } },
|
|
195
|
+
{ 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" } },
|
|
196
|
+
// server/management/logs-usage-routes
|
|
197
|
+
{ method: "GET", path: "/api/claude/inbound-debug", module: "server/management/logs-usage-routes", mutates: false },
|
|
198
|
+
{ method: "GET", path: "/api/debug", module: "server/management/logs-usage-routes", mutates: false },
|
|
199
|
+
{ method: "GET", path: "/api/debug/injection-logs", module: "server/management/logs-usage-routes", mutates: false },
|
|
200
|
+
{ method: "GET", path: "/api/debug/logs", module: "server/management/logs-usage-routes", mutates: false },
|
|
201
|
+
{ method: "GET", path: "/api/debug/usage-logs", module: "server/management/logs-usage-routes", mutates: false },
|
|
202
|
+
{ method: "GET", path: "/api/logs", module: "server/management/logs-usage-routes", mutates: false },
|
|
203
|
+
{ method: "GET", path: "/api/storage/cleanup-policy", module: "server/management/logs-usage-routes", mutates: false },
|
|
204
|
+
{ 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." } },
|
|
205
|
+
{ method: "GET", path: "/api/storage/trash", module: "server/management/logs-usage-routes", mutates: false },
|
|
206
|
+
{ 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." } },
|
|
207
|
+
{ method: "GET", path: "/api/usage", module: "server/management/logs-usage-routes", mutates: false },
|
|
208
|
+
{ method: "POST", path: "/api/storage/cleanup", module: "server/management/logs-usage-routes", mutates: true },
|
|
209
|
+
{ method: "POST", path: "/api/storage/cleanup-policy/run", module: "server/management/logs-usage-routes", mutates: true },
|
|
210
|
+
{ method: "POST", path: "/api/storage/cleanup/preview", module: "server/management/logs-usage-routes", mutates: true },
|
|
211
|
+
{ method: "POST", path: "/api/storage/trash/restore", module: "server/management/logs-usage-routes", mutates: true },
|
|
212
|
+
{ method: "PUT", path: "/api/debug", module: "server/management/logs-usage-routes", mutates: true },
|
|
213
|
+
{ method: "PUT", path: "/api/storage/cleanup-policy", module: "server/management/logs-usage-routes", mutates: true },
|
|
214
|
+
// server/management/model-routes
|
|
215
|
+
{ method: "GET", path: "/api/aliases", module: "server/management/model-routes", mutates: false },
|
|
216
|
+
{ method: "GET", path: "/api/catalog", module: "server/management/model-routes", mutates: false },
|
|
217
|
+
{ method: "GET", path: "/api/client-config", module: "server/management/model-routes", mutates: false },
|
|
218
|
+
{ method: "GET", path: "/api/custom-models", module: "server/management/model-routes", mutates: false },
|
|
219
|
+
{ method: "GET", path: "/api/model-discovery", module: "server/management/model-routes", mutates: false },
|
|
220
|
+
{ method: "GET", path: "/api/model-presets", module: "server/management/model-routes", mutates: false },
|
|
221
|
+
{ method: "GET", path: "/api/models", module: "server/management/model-routes", mutates: false },
|
|
222
|
+
{ method: "GET", path: "/api/selected-models", module: "server/management/model-routes", mutates: false },
|
|
223
|
+
{ method: "POST", path: "/api/custom-models", module: "server/management/model-routes", mutates: true },
|
|
224
|
+
{ method: "POST", path: "/api/model-discovery/acknowledge", module: "server/management/model-routes", mutates: true },
|
|
225
|
+
{ method: "PUT", path: "/api/default-aliases", module: "server/management/model-routes", mutates: true },
|
|
226
|
+
{ method: "PUT", path: "/api/disabled-models", module: "server/management/model-routes", mutates: true },
|
|
227
|
+
{ method: "PUT", path: "/api/model-discovery", module: "server/management/model-routes", mutates: true },
|
|
228
|
+
{ method: "PUT", path: "/api/model-presets", module: "server/management/model-routes", mutates: true },
|
|
229
|
+
{ method: "PUT", path: "/api/model-visibility", module: "server/management/model-routes", mutates: true },
|
|
230
|
+
{ method: "PUT", path: "/api/selected-models", module: "server/management/model-routes", mutates: true },
|
|
231
|
+
// server/management/native-integration-routes
|
|
232
|
+
{ method: "GET", path: "/api/native-integrations", module: "server/management/native-integration-routes", mutates: false },
|
|
233
|
+
{ method: "PUT", path: "/api/native-integrations/claude", module: "server/management/native-integration-routes", mutates: true },
|
|
234
|
+
{ method: "PUT", path: "/api/native-integrations/claude-desktop", module: "server/management/native-integration-routes", mutates: true },
|
|
235
|
+
{ method: "PUT", path: "/api/native-integrations/codex", module: "server/management/native-integration-routes", mutates: true },
|
|
236
|
+
{ method: "PUT", path: "/api/native-integrations/grok", module: "server/management/native-integration-routes", mutates: true },
|
|
237
|
+
// server/management/oauth-account-routes
|
|
238
|
+
{ method: "DELETE", path: "/api/keys", module: "server/management/oauth-account-routes", mutates: true },
|
|
239
|
+
{ method: "DELETE", path: "/api/oauth/accounts", module: "server/management/oauth-account-routes", mutates: true },
|
|
240
|
+
{ method: "DELETE", path: "/api/providers/keys", module: "server/management/oauth-account-routes", mutates: true },
|
|
241
|
+
{ method: "GET", path: "/api/key-providers", module: "server/management/oauth-account-routes", mutates: false },
|
|
242
|
+
{ method: "GET", path: "/api/keys", module: "server/management/oauth-account-routes", mutates: false },
|
|
243
|
+
{ method: "GET", path: "/api/oauth/accounts", module: "server/management/oauth-account-routes", mutates: false },
|
|
244
|
+
{ method: "GET", path: "/api/oauth/accounts/pool", module: "server/management/oauth-account-routes", mutates: false },
|
|
245
|
+
{ method: "GET", path: "/api/oauth/providers", module: "server/management/oauth-account-routes", mutates: false },
|
|
246
|
+
{ method: "GET", path: "/api/oauth/status", module: "server/management/oauth-account-routes", mutates: false },
|
|
247
|
+
{ method: "GET", path: "/api/providers/keys", module: "server/management/oauth-account-routes", mutates: false },
|
|
248
|
+
{ method: "PATCH", path: "/api/keys", module: "server/management/oauth-account-routes", mutates: true },
|
|
249
|
+
{ method: "PATCH", path: "/api/oauth/accounts/pool", module: "server/management/oauth-account-routes", mutates: true },
|
|
250
|
+
{ method: "POST", path: "/api/keys", module: "server/management/oauth-account-routes", mutates: true },
|
|
251
|
+
{ method: "POST", path: "/api/oauth/accounts/clear-cooldown", module: "server/management/oauth-account-routes", mutates: true },
|
|
252
|
+
{ method: "POST", path: "/api/oauth/accounts/import", module: "server/management/oauth-account-routes", mutates: true },
|
|
253
|
+
{ method: "POST", path: "/api/oauth/login", module: "server/management/oauth-account-routes", mutates: true },
|
|
254
|
+
{ method: "POST", path: "/api/oauth/login/cancel", module: "server/management/oauth-account-routes", mutates: true },
|
|
255
|
+
{ method: "POST", path: "/api/oauth/login/code", module: "server/management/oauth-account-routes", mutates: true },
|
|
256
|
+
{ method: "POST", path: "/api/oauth/logout", module: "server/management/oauth-account-routes", mutates: true },
|
|
257
|
+
{ method: "POST", path: "/api/providers/keys", module: "server/management/oauth-account-routes", mutates: true },
|
|
258
|
+
{ method: "PUT", path: "/api/oauth/accounts/active", module: "server/management/oauth-account-routes", mutates: true },
|
|
259
|
+
{ method: "PUT", path: "/api/oauth/accounts/alias", module: "server/management/oauth-account-routes", mutates: true },
|
|
260
|
+
{ method: "PUT", path: "/api/oauth/accounts/pool", module: "server/management/oauth-account-routes", mutates: true },
|
|
261
|
+
{ method: "PUT", path: "/api/providers/keys/active", module: "server/management/oauth-account-routes", mutates: true },
|
|
262
|
+
{ method: "PUT", path: "/api/providers/keys/alias", module: "server/management/oauth-account-routes", mutates: true },
|
|
263
|
+
// server/management/provider-routes
|
|
264
|
+
{ method: "DELETE", path: "/api/providers", module: "server/management/provider-routes", mutates: true },
|
|
265
|
+
{ method: "GET", path: "/api/provider-context-caps", module: "server/management/provider-routes", mutates: false },
|
|
266
|
+
{ method: "GET", path: "/api/provider-presets", module: "server/management/provider-routes", mutates: false },
|
|
267
|
+
{ method: "GET", path: "/api/provider-quotas", module: "server/management/provider-routes", mutates: false },
|
|
268
|
+
{ method: "GET", path: "/api/provider-request-pacing", module: "server/management/provider-routes", mutates: false },
|
|
269
|
+
{ method: "GET", path: "/api/providers", module: "server/management/provider-routes", mutates: false },
|
|
270
|
+
{ method: "PATCH", path: "/api/providers", module: "server/management/provider-routes", mutates: true },
|
|
271
|
+
{ method: "POST", path: "/api/providers", module: "server/management/provider-routes", mutates: true },
|
|
272
|
+
{ method: "POST", path: "/api/providers/test", module: "server/management/provider-routes", mutates: true },
|
|
273
|
+
{ method: "PUT", path: "/api/provider-context-caps", module: "server/management/provider-routes", mutates: true },
|
|
274
|
+
// server/management/replit-provider-routes
|
|
275
|
+
{ method: "POST", path: "/api/providers/replit-pair", module: "server/management/replit-provider-routes", mutates: true },
|
|
276
|
+
// server/management/request-history-routes
|
|
277
|
+
{ method: "GET", path: "/api/request-history", module: "server/management/request-history-routes", mutates: false },
|
|
278
|
+
// server/management/routing-analytics-routes
|
|
279
|
+
// server/management/routing-profile-routes
|
|
280
|
+
{ method: "DELETE", path: "/api/routing-profiles", module: "server/management/routing-profile-routes", mutates: true },
|
|
281
|
+
{ method: "GET", path: "/api/routing-profiles", module: "server/management/routing-profile-routes", mutates: false },
|
|
282
|
+
{ method: "POST", path: "/api/routing-profiles/dry-run", module: "server/management/routing-profile-routes", mutates: true },
|
|
283
|
+
{ method: "PUT", path: "/api/routing-profiles", module: "server/management/routing-profile-routes", mutates: true },
|
|
284
|
+
// server/management/sidebar-routes
|
|
285
|
+
{ method: "GET", path: "/api/github/star", module: "server/management/sidebar-routes", mutates: false },
|
|
286
|
+
{ method: "GET", path: "/api/update/badge", module: "server/management/sidebar-routes", mutates: false },
|
|
287
|
+
{ 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." } },
|
|
288
|
+
// server/management/storage-log-guard-routes
|
|
289
|
+
{ method: "GET", path: "/api/storage/codex-logs", module: "server/management/storage-log-guard-routes", mutates: false },
|
|
290
|
+
{ method: "POST", path: "/api/storage/codex-logs/compact", module: "server/management/storage-log-guard-routes", mutates: true },
|
|
291
|
+
{ method: "POST", path: "/api/storage/codex-logs/protect", module: "server/management/storage-log-guard-routes", mutates: true },
|
|
292
|
+
{ method: "POST", path: "/api/storage/codex-logs/repair", module: "server/management/storage-log-guard-routes", mutates: true },
|
|
293
|
+
{ method: "POST", path: "/api/storage/codex-logs/unprotect", module: "server/management/storage-log-guard-routes", mutates: true },
|
|
294
|
+
// server/management/system-routes
|
|
295
|
+
{ method: "GET", path: "/api/system/memory", module: "server/management/system-routes", mutates: false },
|
|
296
|
+
{ method: "GET", path: "/api/system/windows-replace-retries", module: "server/management/system-routes", mutates: false },
|
|
297
|
+
{ method: "POST", path: "/api/system/restart", module: "server/management/system-routes", mutates: true },
|
|
298
|
+
// --- Routes an equality scan of their own file cannot see (18). ---
|
|
299
|
+
// Each carries `mechanism`; the reconciliation test counts these separately.
|
|
300
|
+
{ method: "GET", path: "/api/storage", module: "server/management/storage-log-guard-routes", mutates: false, mechanism: "negated-guard" },
|
|
301
|
+
{ method: "GET", path: "/api/routing-analytics", module: "server/management/routing-analytics-routes", mutates: false, mechanism: "negated-guard" },
|
|
302
|
+
{ method: "GET", path: "/api/system/codex-app-server", module: "server/management/system-routes", mutates: false, mechanism: "path-constant" },
|
|
303
|
+
{ method: "POST", path: "/api/system/codex-restart", module: "server/management/system-routes", mutates: true, mechanism: "path-constant" },
|
|
304
|
+
{ 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." } },
|
|
305
|
+
{ method: "GET", path: "/api/client-integrations/{clientId}", module: "server/management/integration-routes", mutates: false, mechanism: "prefix-decode" },
|
|
306
|
+
{ method: "PUT", path: "/api/client-integrations/{clientId}", module: "server/management/integration-routes", mutates: true, mechanism: "prefix-decode" },
|
|
307
|
+
{ method: "GET", path: "/api/request-history/{id}", module: "server/management/request-history-routes", mutates: false, mechanism: "slice" },
|
|
308
|
+
{ method: "GET", path: "/api/request-history/{id}/route-decision", module: "server/management/request-history-routes", mutates: false, mechanism: "ends-with" },
|
|
309
|
+
{ method: "PUT", path: "/api/providers/{provider}/alias", module: "server/management/model-routes", mutates: true, mechanism: "regex" },
|
|
310
|
+
{ method: "PUT", path: "/api/providers/{provider}/model-aliases", module: "server/management/model-routes", mutates: true, mechanism: "regex" },
|
|
311
|
+
{ method: "PUT", path: "/api/custom-models/{id}", module: "server/management/model-routes", mutates: true, mechanism: "regex" },
|
|
312
|
+
{ method: "DELETE", path: "/api/custom-models/{id}", module: "server/management/model-routes", mutates: true, mechanism: "regex" },
|
|
313
|
+
{ 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." } },
|
|
314
|
+
{ 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." } },
|
|
315
|
+
{ 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." } },
|
|
316
|
+
{ 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" } },
|
|
317
|
+
];
|
|
@@ -68,6 +68,14 @@ export interface LiveProxy {
|
|
|
68
68
|
hostname?: string;
|
|
69
69
|
/** Whether the successful probe used runtime-port metadata or the configured listen port. */
|
|
70
70
|
source: "runtime" | "config";
|
|
71
|
+
/**
|
|
72
|
+
* Version the live proxy reported on `/healthz`, when it reported one.
|
|
73
|
+
*
|
|
74
|
+
* Carried so a stale `ocx` on PATH can be detected without a second request: the
|
|
75
|
+
* identity probe already parsed and validated this body. Absent for a legacy proxy whose
|
|
76
|
+
* healthz body predates the field.
|
|
77
|
+
*/
|
|
78
|
+
version?: string;
|
|
71
79
|
}
|
|
72
80
|
|
|
73
81
|
/**
|
|
@@ -99,7 +107,7 @@ export async function proxyIdentityAt(
|
|
|
99
107
|
port: number,
|
|
100
108
|
opts: { hostname?: string; expectedPid?: number } = {},
|
|
101
109
|
io: LivenessIo = {},
|
|
102
|
-
): Promise<{ pid: number | null } | null> {
|
|
110
|
+
): Promise<{ pid: number | null; version?: string } | null> {
|
|
103
111
|
const fetchFn = io.fetchFn ?? directLocalHttpFetch;
|
|
104
112
|
const sleepFn = io.sleepFn ?? ((ms: number) => new Promise<void>(r => setTimeout(r, ms)));
|
|
105
113
|
const nowFn = io.nowFn ?? Date.now;
|
|
@@ -122,7 +130,9 @@ export async function proxyIdentityAt(
|
|
|
122
130
|
if (!isOpencodexHealthz(body)) return null;
|
|
123
131
|
const pid = typeof body?.pid === "number" ? body.pid : null;
|
|
124
132
|
if (opts.expectedPid !== undefined && pid !== null && pid !== opts.expectedPid) return null;
|
|
125
|
-
|
|
133
|
+
// Guarded the same way `pid` is: a non-string version is absent, not coerced.
|
|
134
|
+
const version = typeof body?.version === "string" ? body.version : undefined;
|
|
135
|
+
return version === undefined ? { pid } : { pid, version };
|
|
126
136
|
} catch {
|
|
127
137
|
// Transport failure (timeout / refused) — retry while budget remains; a proxy that
|
|
128
138
|
// has only just begun listening can miss a single short probe (#764).
|
|
@@ -180,7 +190,13 @@ export async function findLiveProxy(io: LivenessIo = {}): Promise<LiveProxy | nu
|
|
|
180
190
|
// healthz confirmed the pid itself → trusted; a pidless legacy body did not,
|
|
181
191
|
// so the cheap pid must pass full identity verification before it is returned.
|
|
182
192
|
const trusted = identity.pid === pid ? pid : killablePid(pid);
|
|
183
|
-
return {
|
|
193
|
+
return {
|
|
194
|
+
pid: trusted,
|
|
195
|
+
port: runtime.port,
|
|
196
|
+
hostname: runtime.hostname,
|
|
197
|
+
source: "runtime",
|
|
198
|
+
...(identity.version === undefined ? {} : { version: identity.version }),
|
|
199
|
+
};
|
|
184
200
|
}
|
|
185
201
|
}
|
|
186
202
|
}
|
|
@@ -197,7 +213,13 @@ export async function findLiveProxy(io: LivenessIo = {}): Promise<LiveProxy | nu
|
|
|
197
213
|
// (its process dead, the port reused by a pidless legacy proxy) — synthesizing it
|
|
198
214
|
// would hand destructive callers (stopProxy → kill fallback) a reusable pid.
|
|
199
215
|
if (identity) {
|
|
200
|
-
return {
|
|
216
|
+
return {
|
|
217
|
+
pid: verifiedReportedPid(identity.pid),
|
|
218
|
+
port: record.port,
|
|
219
|
+
hostname: record.hostname,
|
|
220
|
+
source: "runtime",
|
|
221
|
+
...(identity.version === undefined ? {} : { version: identity.version }),
|
|
222
|
+
};
|
|
201
223
|
}
|
|
202
224
|
}
|
|
203
225
|
|
|
@@ -211,6 +233,7 @@ export async function findLiveProxy(io: LivenessIo = {}): Promise<LiveProxy | nu
|
|
|
211
233
|
port,
|
|
212
234
|
hostname: config.hostname,
|
|
213
235
|
source: "config",
|
|
236
|
+
...(identity.version === undefined ? {} : { version: identity.version }),
|
|
214
237
|
};
|
|
215
238
|
}
|
|
216
239
|
return null;
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
isKnownAdmissionKind,
|
|
22
22
|
isKnownInboundProtocol,
|
|
23
23
|
isKnownUsageSurface,
|
|
24
|
+
isCodexUsageAccountLogLabel,
|
|
24
25
|
isPersistableAccountLogLabel,
|
|
25
26
|
isValidReasoningWireValue,
|
|
26
27
|
readRecentUsageEntries,
|
|
@@ -65,6 +66,13 @@ export interface RequestLogContext {
|
|
|
65
66
|
* product: widening that enum would merge Responses and Chat Completions,
|
|
66
67
|
* since both leave it undefined. */
|
|
67
68
|
inboundProtocol?: "responses" | "chat" | "messages";
|
|
69
|
+
/**
|
|
70
|
+
* Set when an adapter answered the turn locally and no upstream request was made
|
|
71
|
+
* (`ProviderAdapter.localTerminal`). A fixed identifier naming the code path, never
|
|
72
|
+
* conversation-derived: it exists so a request log showing zero sends is explainable
|
|
73
|
+
* rather than looking like a lost request.
|
|
74
|
+
*/
|
|
75
|
+
localTerminalReason?: string;
|
|
68
76
|
agentKind?: AgentKind;
|
|
69
77
|
/** Stable non-PII Codex Pool account identity for durable usage attribution. */
|
|
70
78
|
accountLogLabel?: string;
|
|
@@ -136,6 +144,12 @@ export interface RequestLogEntry {
|
|
|
136
144
|
/** TTFT: ms from request start to the first non-empty model output delta; unset for non-streaming/tool-only. */
|
|
137
145
|
firstOutputMs?: number;
|
|
138
146
|
surface?: "claude" | "claude-desktop" | "grok";
|
|
147
|
+
/**
|
|
148
|
+
* Set when the proxy answered this turn locally and sent nothing upstream. Without it a zero-send
|
|
149
|
+
* row is indistinguishable from a request that vanished. A fixed adapter-supplied identifier,
|
|
150
|
+
* never conversation-derived.
|
|
151
|
+
*/
|
|
152
|
+
localTerminalReason?: string;
|
|
139
153
|
/** The matched configured key's id. Set ONLY for admissionKind "configured" —
|
|
140
154
|
* never a sentinel, so a hand-edited entry whose id happens to be "loopback"
|
|
141
155
|
* cannot absorb unrelated traffic. */
|
|
@@ -264,7 +278,7 @@ export function requestLogEntryFromPersistedUsage(entry: PersistedUsageEntry): R
|
|
|
264
278
|
...(entry.firstOutputMs !== undefined ? { firstOutputMs: entry.firstOutputMs } : {}),
|
|
265
279
|
...(isKnownUsageSurface(entry.surface) ? { surface: entry.surface } : {}),
|
|
266
280
|
...(entry.conversationId ? { conversationId: entry.conversationId } : {}),
|
|
267
|
-
...(
|
|
281
|
+
...(isCodexUsageAccountLogLabel(entry.accountLogLabel)
|
|
268
282
|
? { accountLogLabel: entry.accountLogLabel }
|
|
269
283
|
: {}),
|
|
270
284
|
...(entry.requestedModel ? { requestedModel: entry.requestedModel } : {}),
|
|
@@ -949,6 +963,7 @@ export function addFinalRequestLog(
|
|
|
949
963
|
logCtx.usage,
|
|
950
964
|
logCtx.usageLogInputTokens,
|
|
951
965
|
contextWindowForModel(logCtx.providerAdapter ?? logCtx.provider, logCtx.model),
|
|
966
|
+
logCtx.localTerminalReason !== undefined,
|
|
952
967
|
);
|
|
953
968
|
const attempts = logCtx.attempts?.map(attempt => ({
|
|
954
969
|
...attempt,
|
|
@@ -976,6 +991,9 @@ export function addFinalRequestLog(
|
|
|
976
991
|
...(logCtx.apiKeyId ? { apiKeyId: logCtx.apiKeyId } : {}),
|
|
977
992
|
...(logCtx.admissionKind ? { admissionKind: logCtx.admissionKind } : {}),
|
|
978
993
|
...(logCtx.inboundProtocol ? { inboundProtocol: logCtx.inboundProtocol } : {}),
|
|
994
|
+
...(logCtx.localTerminalReason
|
|
995
|
+
? { localTerminalReason: sanitizeLogMetadataString(logCtx.localTerminalReason) }
|
|
996
|
+
: {}),
|
|
979
997
|
...(logCtx.agentKind ? { agentKind: logCtx.agentKind } : {}),
|
|
980
998
|
...(isPersistableAccountLogLabel(logCtx.accountLogLabel)
|
|
981
999
|
? { accountLogLabel: logCtx.accountLogLabel }
|
|
@@ -1037,29 +1055,29 @@ export function filterRequestLogs(logs: RequestLogEntry[], params: URLSearchPara
|
|
|
1037
1055
|
filtered = filtered.filter(entry => entry.provider === provider
|
|
1038
1056
|
|| entry.attempts?.some(attempt => attempt.provider === provider));
|
|
1039
1057
|
}
|
|
1040
|
-
const
|
|
1058
|
+
const conversationId = params.get("conversationId")?.trim() || params.get("conversation")?.trim();
|
|
1059
|
+
if (conversationId) {
|
|
1060
|
+
filtered = filtered.filter(entry => matchesLogConversationId(entry.conversationId, conversationId));
|
|
1061
|
+
}
|
|
1062
|
+
// #2704: there was no `model` clause at all, so `?model=x` was ACCEPTED and silently
|
|
1063
|
+
// ignored -- worse than an error, because it yields wrong conclusions from output that
|
|
1064
|
+
// looks correct. Attempts are matched for the same reason `provider` matches them: a
|
|
1065
|
+
// request that failed over should be findable by the model that actually served it.
|
|
1066
|
+
const model = params.get("model")?.trim();
|
|
1041
1067
|
if (model) {
|
|
1042
|
-
filtered = filtered.filter(entry => entry.model
|
|
1043
|
-
|| entry.resolvedModel
|
|
1044
|
-
|| entry.attempts?.some(attempt => attempt.model
|
|
1068
|
+
filtered = filtered.filter(entry => entry.model === model
|
|
1069
|
+
|| entry.resolvedModel === model
|
|
1070
|
+
|| entry.attempts?.some(attempt => attempt.model === model));
|
|
1045
1071
|
}
|
|
1046
1072
|
const sinceRaw = params.get("since")?.trim();
|
|
1047
1073
|
if (sinceRaw) {
|
|
1048
1074
|
const since = Number(sinceRaw);
|
|
1049
|
-
if (Number.isFinite(since))
|
|
1050
|
-
filtered = filtered.filter(entry => entry.timestamp >= since);
|
|
1051
|
-
}
|
|
1075
|
+
if (Number.isFinite(since)) filtered = filtered.filter(entry => entry.timestamp >= since);
|
|
1052
1076
|
}
|
|
1053
1077
|
const untilRaw = params.get("until")?.trim();
|
|
1054
1078
|
if (untilRaw) {
|
|
1055
1079
|
const until = Number(untilRaw);
|
|
1056
|
-
if (Number.isFinite(until))
|
|
1057
|
-
filtered = filtered.filter(entry => entry.timestamp <= until);
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
const conversationId = params.get("conversationId")?.trim() || params.get("conversation")?.trim();
|
|
1061
|
-
if (conversationId) {
|
|
1062
|
-
filtered = filtered.filter(entry => matchesLogConversationId(entry.conversationId, conversationId));
|
|
1080
|
+
if (Number.isFinite(until)) filtered = filtered.filter(entry => entry.timestamp <= until);
|
|
1063
1081
|
}
|
|
1064
1082
|
const status = params.get("status")?.trim().toLowerCase();
|
|
1065
1083
|
if (status) {
|
|
@@ -1130,6 +1148,7 @@ function finalizedUsage(
|
|
|
1130
1148
|
usage: OcxUsage | undefined,
|
|
1131
1149
|
inputTokenEstimate: number | undefined,
|
|
1132
1150
|
contextWindow: number | undefined,
|
|
1151
|
+
locallyAnswered = false,
|
|
1133
1152
|
): FinalizedUsageResult {
|
|
1134
1153
|
// The ESTIMATE itself is capped at the model's context window (codex-router PR #140). The
|
|
1135
1154
|
// combined value below keeps its max(inputTokens, estimate) behavior — a provider-reported
|
|
@@ -1139,7 +1158,7 @@ function finalizedUsage(
|
|
|
1139
1158
|
&& inputTokenEstimate >= 0
|
|
1140
1159
|
? capEstimateAtContextWindow(inputTokenEstimate, contextWindow)
|
|
1141
1160
|
: undefined;
|
|
1142
|
-
const finalUsage = usageForFinalLog(adapter, usage);
|
|
1161
|
+
const finalUsage = usageForFinalLog(adapter, usage, locallyAnswered);
|
|
1143
1162
|
const usageFallback = !finalUsage && estimate !== undefined
|
|
1144
1163
|
? { inputTokens: estimate, outputTokens: 0, estimated: true }
|
|
1145
1164
|
: undefined;
|
|
@@ -1203,7 +1222,7 @@ export function sealRequestAttemptIdentity(
|
|
|
1203
1222
|
if (!attempt) return;
|
|
1204
1223
|
attempt.provider = provider;
|
|
1205
1224
|
attempt.adapter = adapter;
|
|
1206
|
-
if (
|
|
1225
|
+
if (isCodexUsageAccountLogLabel(accountLogLabel)) attempt.accountLogLabel = accountLogLabel;
|
|
1207
1226
|
}
|
|
1208
1227
|
|
|
1209
1228
|
export function noteAttemptSend(
|
|
@@ -1240,6 +1259,7 @@ export function finishRequestAttempt(
|
|
|
1240
1259
|
usage ?? attempt.usage,
|
|
1241
1260
|
attempt.inputTokenEstimate,
|
|
1242
1261
|
contextWindowForModel(attempt.adapter, attempt.model),
|
|
1262
|
+
attempt.locallyAnswered === true,
|
|
1243
1263
|
);
|
|
1244
1264
|
attempt.status = status;
|
|
1245
1265
|
attempt.durationMs = Math.max(0, durationMs);
|