@cmmd-center/forge 0.10.5 → 0.10.7
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/dist/bin.cjs +1294 -795
- package/dist/bin.mjs +1293 -792
- package/dist/client/assets/{CanvasPanel-Dr4I7MnM.js → CanvasPanel-ECmvVI7T.js} +2 -2
- package/dist/client/assets/{CompositeItem-Cj6_oAlz.js → CompositeItem-8hzrVacr.js} +2 -2
- package/dist/client/assets/{DiffPanel-CsMWXFsK.js → DiffPanel-BqOO3dsl.js} +3 -3
- package/dist/client/assets/{DiffPanel.logic-Cyp3p58B.js → DiffPanel.logic-Bzm8oiCr.js} +2 -2
- package/dist/client/assets/DiffPanelShell-DVVw1mR3.js +2531 -0
- package/dist/client/assets/{DiffWorkerPoolProvider-DOF7ypo1.js → DiffWorkerPoolProvider-BsMgSHbg.js} +8 -8
- package/dist/client/assets/{PullRequestCodePanel-BuK0wrXE.js → PullRequestCodePanel-DNrNrubs.js} +3 -3
- package/dist/client/assets/{Virtualizer-CQJMsfKa.js → Virtualizer-RRV_x18w.js} +2 -2
- package/dist/client/assets/{canvasStateStore-DncdOQ4J.js → canvasStateStore-3EN8RaUf.js} +2 -2
- package/dist/client/assets/{cmmdAuthRedirect-DWiMDVzN.js → cmmdAuthRedirect-DwPtzhq9.js} +2 -2
- package/dist/client/assets/index-D22UpSjv.css +1 -0
- package/dist/client/assets/{index-C6vF1RSl.js → index-DCVtRkq1.js} +56 -56
- package/dist/client/assets/{src-CtyKlVph.js → src-DZBONdiY.js} +2 -2
- package/dist/client/assets/{toggle-pTm2fPLg.js → toggle-mQ7UG7Dd.js} +2 -2
- package/dist/client/assets/{useTriggerFocusGuards-B4Ejoaox.js → useTriggerFocusGuards-BUEnX8xa.js} +2 -2
- package/dist/client/index.html +11 -11
- package/dist/forge-build.json +1 -1
- package/package.json +1 -1
- package/dist/client/assets/DiffPanelShell-h78vZ6dX.js +0 -2531
- package/dist/client/assets/index-T36rURmx.css +0 -1
package/dist/bin.mjs
CHANGED
|
@@ -24231,6 +24231,7 @@ const UsageBucket = Struct({
|
|
|
24231
24231
|
costSource: UsageCostSource,
|
|
24232
24232
|
records: NonNegativeInt,
|
|
24233
24233
|
unpricedRecords: NonNegativeInt,
|
|
24234
|
+
unreportedRecords: optional$4(NonNegativeInt),
|
|
24234
24235
|
sessions: NonNegativeInt,
|
|
24235
24236
|
runtimeId: optional$4(TrimmedNonEmptyString),
|
|
24236
24237
|
origin: optional$4(UsageBucketOrigin),
|
|
@@ -65120,7 +65121,7 @@ function normalizeNumberish(value) {
|
|
|
65120
65121
|
}
|
|
65121
65122
|
//#endregion
|
|
65122
65123
|
//#region package.json
|
|
65123
|
-
var version$1 = "0.10.
|
|
65124
|
+
var version$1 = "0.10.7";
|
|
65124
65125
|
//#endregion
|
|
65125
65126
|
//#region src/sentry.ts
|
|
65126
65127
|
const SERVER_APP_NAME = "forge-server";
|
|
@@ -67888,6 +67889,15 @@ function parsePersistedServerObservabilitySettings(raw) {
|
|
|
67888
67889
|
* @module ServerConfig
|
|
67889
67890
|
*/
|
|
67890
67891
|
const DEFAULT_PORT = 13773;
|
|
67892
|
+
/**
|
|
67893
|
+
* Where a managed cloud runtime keeps the user's checkouts when
|
|
67894
|
+
* FORGE_CLOUD_PROJECTS_ROOT is not set. CMMD seeds every sprite checkout under
|
|
67895
|
+
* /projects (forge-guest-layout.ts on the CMMD side) and passes that value in
|
|
67896
|
+
* the Service env, so this default only matters for a server started without
|
|
67897
|
+
* it. It used to be a path under the Fly-era mounted volume; on a sprite the
|
|
67898
|
+
* two repos disagreed and every local-checkout turn was refused (FOR-36484).
|
|
67899
|
+
*/
|
|
67900
|
+
const DEFAULT_CLOUD_PROJECTS_ROOT = "/projects";
|
|
67891
67901
|
const RuntimeMode = Literals(["web", "desktop"]);
|
|
67892
67902
|
Literals(["browser", "headless"]);
|
|
67893
67903
|
const deriveServerPaths = fn$1(function* (baseDir, _devUrl, _mode) {
|
|
@@ -68013,7 +68023,7 @@ var ServerConfig = class ServerConfig extends Service$1()("forge/config/ServerCo
|
|
|
68013
68023
|
forgeCodexHomePath: void 0,
|
|
68014
68024
|
forgeClaudeConfigPath: void 0,
|
|
68015
68025
|
forgeApexBaseUrl: void 0,
|
|
68016
|
-
cloudProjectsRoot:
|
|
68026
|
+
cloudProjectsRoot: DEFAULT_CLOUD_PROJECTS_ROOT,
|
|
68017
68027
|
...overrides
|
|
68018
68028
|
};
|
|
68019
68029
|
}));
|
|
@@ -70017,6 +70027,14 @@ function invalidateCachedCmmdWorkIntakeForIdentity(identityKey) {
|
|
|
70017
70027
|
*
|
|
70018
70028
|
* Bespoke routes (MCP/PAT transport, hybrid fallback, multipart) stay in
|
|
70019
70029
|
* http.ts and are NOT migrated here.
|
|
70030
|
+
*
|
|
70031
|
+
* A second, narrower entry point — `registerProxyHandler` / `ProxyHandlerRoute`
|
|
70032
|
+
* — covers routes whose middle (request parsing, the actual gateway call,
|
|
70033
|
+
* success shaping) cannot be expressed by the five `ProxyRoute` fields above,
|
|
70034
|
+
* while still sharing the same prologue: session auth, the CMMD-connection
|
|
70035
|
+
* gate, and the same `buildProxyErrorResponse` error mapping plus
|
|
70036
|
+
* `clearUnrecoverableCmmdAuthForSession` on an auth failure. See the type doc
|
|
70037
|
+
* below for the exact contract.
|
|
70020
70038
|
*/
|
|
70021
70039
|
/** Substitutes ":paramName" tokens in a path template from a params record. */
|
|
70022
70040
|
function substitutePath(template, params) {
|
|
@@ -70066,6 +70084,29 @@ function buildProxyErrorResponse(error) {
|
|
|
70066
70084
|
}
|
|
70067
70085
|
return jsonUnsafe({ error: "CMMD REST request failed." }, { status: 502 });
|
|
70068
70086
|
}
|
|
70087
|
+
/**
|
|
70088
|
+
* Clears every unrecoverable CMMD credential tied to this session, logging a
|
|
70089
|
+
* warning rather than failing the request if the clear itself errors — a
|
|
70090
|
+
* session that already has no usable credential must still get its 401,
|
|
70091
|
+
* not a 500 from a failed best-effort cleanup.
|
|
70092
|
+
*/
|
|
70093
|
+
function clearCmmdAuthAfterFailure(sessionId) {
|
|
70094
|
+
return clearUnrecoverableCmmdAuthForSession(sessionId).pipe(catch_((error) => logWarning$1("Failed to clear unrecoverable CMMD auth after CMMD auth failure.", {
|
|
70095
|
+
cause: error,
|
|
70096
|
+
sessionId
|
|
70097
|
+
})));
|
|
70098
|
+
}
|
|
70099
|
+
/**
|
|
70100
|
+
* The single "no usable CMMD credential" response: clears whatever
|
|
70101
|
+
* unrecoverable auth state this session is holding, then returns the
|
|
70102
|
+
* canonical `CMMD_AUTH_REQUIRED` body. Every prologue path that decides the
|
|
70103
|
+
* session has no way to reach CMMD — a missing PAT, a JWT that fails to
|
|
70104
|
+
* resolve, a bespoke gate elsewhere in http.ts — emits this same response so
|
|
70105
|
+
* the Shell only ever has one `CMMD_AUTH_REQUIRED` body to branch on.
|
|
70106
|
+
*/
|
|
70107
|
+
function respondCmmdConnectionRequired(sessionId) {
|
|
70108
|
+
return clearCmmdAuthAfterFailure(sessionId).pipe(as$3(buildProxyErrorResponse(new CmmdProxyAuthenticationRequiredError("CMMD connection required. Reconnect CMMD to continue."))));
|
|
70109
|
+
}
|
|
70069
70110
|
async function dispatchToProxy(method, jwt, cmmdPath, rawBody, orgId, searchParams) {
|
|
70070
70111
|
return cmmdGateway.request({
|
|
70071
70112
|
method,
|
|
@@ -70096,12 +70137,27 @@ function buildProxySearchParams(input) {
|
|
|
70096
70137
|
return Object.keys(result).length > 0 ? result : void 0;
|
|
70097
70138
|
}
|
|
70098
70139
|
const _registeredRoutes = [];
|
|
70099
|
-
|
|
70100
|
-
|
|
70101
|
-
*
|
|
70102
|
-
|
|
70103
|
-
|
|
70104
|
-
|
|
70140
|
+
const _registeredLayers = [];
|
|
70141
|
+
/**
|
|
70142
|
+
* Layers produced by every registerProxyRoute call so far, in registration
|
|
70143
|
+
* order. Callers that want only the routes registered by their own module
|
|
70144
|
+
* should snapshot `.length` before their own registerProxyRoute calls run and
|
|
70145
|
+
* slice from that index — see command/http.ts's `cmmdProxyRouteLayers`.
|
|
70146
|
+
*
|
|
70147
|
+
* Typed via `ReturnType<typeof buildProxyRouteLayer>` (not `HttpRouter.add`
|
|
70148
|
+
* directly, and not `registerProxyRoute` itself — that would be circular
|
|
70149
|
+
* since registerProxyRoute pushes onto this same array): `buildProxyRouteLayer`
|
|
70150
|
+
* takes a concrete, non-generic `ProxyRoute` argument and never references
|
|
70151
|
+
* this array, so its return type is fully resolved independently. Referencing
|
|
70152
|
+
* the generic `HttpRouter.add` on its own instead collapses its unresolved E/R
|
|
70153
|
+
* type parameters to `unknown`, which then leaks into makeRoutesLayer's
|
|
70154
|
+
* requirements channel everywhere this array is spread.
|
|
70155
|
+
*/
|
|
70156
|
+
function registeredProxyRouteLayers() {
|
|
70157
|
+
return Object.freeze([..._registeredLayers]);
|
|
70158
|
+
}
|
|
70159
|
+
/** Builds the Effect HttpRouter layer for one route, with no registry side effects. */
|
|
70160
|
+
function buildProxyRouteLayer(route) {
|
|
70105
70161
|
const handler = gen(function* () {
|
|
70106
70162
|
const req = yield* HttpServerRequest;
|
|
70107
70163
|
const session = yield* (yield* ServerAuth).authenticateHttpRequest(req);
|
|
@@ -70124,23 +70180,14 @@ function registerProxyRoute(route) {
|
|
|
70124
70180
|
forceRefresh
|
|
70125
70181
|
});
|
|
70126
70182
|
const jwt = yield* resolveJwt();
|
|
70127
|
-
if (!jwt)
|
|
70128
|
-
yield* clearUnrecoverableCmmdAuthForSession(session.sessionId).pipe(catch_((error) => logWarning$1("Failed to clear unrecoverable CMMD auth after missing JWT.", {
|
|
70129
|
-
cause: error,
|
|
70130
|
-
sessionId: session.sessionId
|
|
70131
|
-
})));
|
|
70132
|
-
return buildProxyErrorResponse(new CmmdProxyAuthenticationRequiredError("CMMD connection required. Reconnect CMMD to continue."));
|
|
70133
|
-
}
|
|
70183
|
+
if (!jwt) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
70134
70184
|
let outcome = yield* promise(() => runProxy(() => dispatchToProxy(route.method, jwt, cmmdPath, rawBody, orgId, searchParams)));
|
|
70135
70185
|
if (!outcome.ok && outcome.error instanceof CmmdProxyAuthError) {
|
|
70136
70186
|
const refreshedJwt = yield* resolveJwt(true);
|
|
70137
70187
|
if (refreshedJwt && refreshedJwt !== jwt) outcome = yield* promise(() => runProxy(() => dispatchToProxy(route.method, refreshedJwt, cmmdPath, rawBody, orgId, searchParams)));
|
|
70138
70188
|
}
|
|
70139
70189
|
if (!outcome.ok) {
|
|
70140
|
-
if (outcome.error instanceof CmmdProxyAuthError || outcome.error instanceof CmmdProxyAuthenticationRequiredError) yield*
|
|
70141
|
-
cause: error,
|
|
70142
|
-
sessionId: session.sessionId
|
|
70143
|
-
})));
|
|
70190
|
+
if (outcome.error instanceof CmmdProxyAuthError || outcome.error instanceof CmmdProxyAuthenticationRequiredError) yield* clearCmmdAuthAfterFailure(session.sessionId);
|
|
70144
70191
|
return buildProxyErrorResponse(outcome.error);
|
|
70145
70192
|
}
|
|
70146
70193
|
const payload = route.responseShape === "passthrough" ? outcome.value : unwrapEnvelope$1(outcome.value);
|
|
@@ -70150,6 +70197,59 @@ function registerProxyRoute(route) {
|
|
|
70150
70197
|
}).pipe(catchTag("AuthError", (error) => respondToAuthError(error)));
|
|
70151
70198
|
return add$1(route.method, route.forgePath, handler);
|
|
70152
70199
|
}
|
|
70200
|
+
/**
|
|
70201
|
+
* Generates an Effect HttpRouter layer for the given route and records it in
|
|
70202
|
+
* the registry (for auditing / tests, and so command/http.ts's
|
|
70203
|
+
* `cmmdProxyRouteLayers` can pick it up). The returned layer registers one
|
|
70204
|
+
* handler at forgePath.
|
|
70205
|
+
*/
|
|
70206
|
+
function registerProxyRoute(route) {
|
|
70207
|
+
_registeredRoutes.push(route);
|
|
70208
|
+
const layer = buildProxyRouteLayer(route);
|
|
70209
|
+
_registeredLayers.push(layer);
|
|
70210
|
+
return layer;
|
|
70211
|
+
}
|
|
70212
|
+
/**
|
|
70213
|
+
* Builds the bare handler Effect for one handler route (no `HttpRouter.add`
|
|
70214
|
+
* wrapping, no registry side effects) — exposed on its own so tests can
|
|
70215
|
+
* exercise it the same way they exercise every other bespoke handler in
|
|
70216
|
+
* http.ts: providing `HttpServerRequest` / `ServerAuth` directly and running
|
|
70217
|
+
* the Effect, without standing up a router.
|
|
70218
|
+
*/
|
|
70219
|
+
function buildProxyHandlerEffect(route) {
|
|
70220
|
+
return gen(function* () {
|
|
70221
|
+
const req = yield* HttpServerRequest;
|
|
70222
|
+
const session = yield* (yield* ServerAuth).authenticateHttpRequest(req);
|
|
70223
|
+
if (!readCommandAccessTokenForSession(session.sessionId)) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
70224
|
+
const parsed = yield* route.parse(req);
|
|
70225
|
+
if (!parsed.ok) return jsonUnsafe(parsed.body, { status: parsed.status });
|
|
70226
|
+
const result$4 = yield* route.run(parsed.value, { session }).pipe(result);
|
|
70227
|
+
if (isFailure$1(result$4)) {
|
|
70228
|
+
const error = result$4.failure;
|
|
70229
|
+
if (error instanceof CmmdProxyAuthError || error instanceof CmmdProxyAuthenticationRequiredError) yield* clearCmmdAuthAfterFailure(session.sessionId);
|
|
70230
|
+
return buildProxyErrorResponse(error);
|
|
70231
|
+
}
|
|
70232
|
+
return jsonUnsafe(result$4.success.body, { status: result$4.success.status });
|
|
70233
|
+
}).pipe(catchTag("AuthError", (error) => respondToAuthError(error)));
|
|
70234
|
+
}
|
|
70235
|
+
const _registeredHandlerRoutes = [];
|
|
70236
|
+
/**
|
|
70237
|
+
* Builds the handler Effect for one route, mounts it via `HttpRouter.add` and
|
|
70238
|
+
* records that layer in the same registry `registerProxyRoute` uses (so
|
|
70239
|
+
* command/http.ts's `cmmdProxyRouteLayers` picks it up without a separate
|
|
70240
|
+
* mount list) — then returns the bare handler Effect rather than the layer,
|
|
70241
|
+
* so the caller can keep a single `__xHandlerForTests`-style export that
|
|
70242
|
+
* doubles as both the thing under test and the thing that gets mounted.
|
|
70243
|
+
*/
|
|
70244
|
+
function registerProxyHandler(route) {
|
|
70245
|
+
_registeredHandlerRoutes.push({
|
|
70246
|
+
method: route.method,
|
|
70247
|
+
forgePath: route.forgePath
|
|
70248
|
+
});
|
|
70249
|
+
const handler = buildProxyHandlerEffect(route);
|
|
70250
|
+
_registeredLayers.push(add$1(route.method, route.forgePath, handler));
|
|
70251
|
+
return handler;
|
|
70252
|
+
}
|
|
70153
70253
|
//#endregion
|
|
70154
70254
|
//#region src/connect/credentialRefresh.ts
|
|
70155
70255
|
async function refreshConnectCredential(deps) {
|
|
@@ -92262,6 +92362,172 @@ function classifyRuntimeReplicationHttpFailure(failure) {
|
|
|
92262
92362
|
};
|
|
92263
92363
|
}
|
|
92264
92364
|
//#endregion
|
|
92365
|
+
//#region src/runtimeReplication/runtimeLane.ts
|
|
92366
|
+
/**
|
|
92367
|
+
* Read a grant-lane response the way the gateway reads an owner-lane one: a
|
|
92368
|
+
* non-2xx becomes a `CmmdProxyRequestError` carrying the status and CMMD's
|
|
92369
|
+
* error code, so a caller can classify either lane's failure with one rule.
|
|
92370
|
+
*/
|
|
92371
|
+
async function parseRuntimeLaneResponse(response) {
|
|
92372
|
+
const text = await response.text();
|
|
92373
|
+
let body = null;
|
|
92374
|
+
if (text) try {
|
|
92375
|
+
body = JSON.parse(text);
|
|
92376
|
+
} catch {
|
|
92377
|
+
body = null;
|
|
92378
|
+
}
|
|
92379
|
+
if (!response.ok) {
|
|
92380
|
+
const code = readRuntimeReplicationErrorCode(body);
|
|
92381
|
+
throw new CmmdProxyRequestError(`CMMD runtime replication failed (${response.status})`, response.status, null, code ? { code } : null);
|
|
92382
|
+
}
|
|
92383
|
+
if (body === null) throw new Error("CMMD runtime replication returned an empty or invalid JSON response.");
|
|
92384
|
+
return body;
|
|
92385
|
+
}
|
|
92386
|
+
/**
|
|
92387
|
+
* One request on whichever lane the runtime holds. The caller has already
|
|
92388
|
+
* built the path for `lane.kind`; this only decides the transport and the
|
|
92389
|
+
* credential header, and normalises failures to the gateway's error classes.
|
|
92390
|
+
*/
|
|
92391
|
+
async function requestOnRuntimeLane(lane, request, transport = {}) {
|
|
92392
|
+
if (lane.kind === "owner-session") return (transport.gateway ?? cmmdGateway).request({
|
|
92393
|
+
method: request.method,
|
|
92394
|
+
jwt: lane.jwt,
|
|
92395
|
+
path: request.path,
|
|
92396
|
+
...request.body === void 0 ? {} : { body: request.body }
|
|
92397
|
+
});
|
|
92398
|
+
return parseRuntimeLaneResponse(await (transport.fetchImpl ?? fetch)(new URL(request.path, `${lane.controlPlaneUrl}/`), {
|
|
92399
|
+
method: request.method,
|
|
92400
|
+
headers: {
|
|
92401
|
+
authorization: `Bearer ${lane.grantToken}`,
|
|
92402
|
+
accept: "application/json",
|
|
92403
|
+
...request.body === void 0 ? {} : { "content-type": "application/json" }
|
|
92404
|
+
},
|
|
92405
|
+
...request.body === void 0 ? {} : { body: JSON.stringify(request.body) },
|
|
92406
|
+
...request.signal === void 0 ? {} : { signal: request.signal }
|
|
92407
|
+
}));
|
|
92408
|
+
}
|
|
92409
|
+
function mapRuntimeReplicationClientError(error, operation) {
|
|
92410
|
+
if (error instanceof CmmdProxyAuthError) return new RuntimeReplicationClientError({
|
|
92411
|
+
kind: "auth",
|
|
92412
|
+
code: "CMMD_AUTH_REQUIRED",
|
|
92413
|
+
detail: error.message
|
|
92414
|
+
});
|
|
92415
|
+
if (error instanceof CmmdProxyAuthenticationRequiredError) return new RuntimeReplicationClientError({
|
|
92416
|
+
kind: "auth",
|
|
92417
|
+
code: "CMMD_AUTH_REQUIRED",
|
|
92418
|
+
detail: error.message
|
|
92419
|
+
});
|
|
92420
|
+
if (error instanceof CmmdProxyPermissionError) return new RuntimeReplicationClientError({
|
|
92421
|
+
kind: "permanent",
|
|
92422
|
+
code: "CMMD_PERMISSION_DENIED",
|
|
92423
|
+
detail: error.message
|
|
92424
|
+
});
|
|
92425
|
+
if (error instanceof CmmdProxyRequestError) return new RuntimeReplicationClientError(classifyRuntimeReplicationHttpFailure({
|
|
92426
|
+
status: error.status,
|
|
92427
|
+
body: error.body,
|
|
92428
|
+
detail: error.detail ?? error.message,
|
|
92429
|
+
...operation ? { operation } : {}
|
|
92430
|
+
}));
|
|
92431
|
+
return new RuntimeReplicationClientError({
|
|
92432
|
+
kind: "retryable",
|
|
92433
|
+
code: "CMMD_UNAVAILABLE",
|
|
92434
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
92435
|
+
});
|
|
92436
|
+
}
|
|
92437
|
+
//#endregion
|
|
92438
|
+
//#region src/runtimeReplication/lifecycleIntentClient.ts
|
|
92439
|
+
/**
|
|
92440
|
+
* The runtime half of a lifecycle intent: a settle or un-settle a person asked
|
|
92441
|
+
* for while this runtime was offline, held by CMMD until the runtime lists it,
|
|
92442
|
+
* applies it through its own orchestration, and acknowledges it.
|
|
92443
|
+
*
|
|
92444
|
+
* Both lanes carry the same envelope (pinned equal in the contracts package),
|
|
92445
|
+
* so one client serves the desktop's owner-session lane and the cloud
|
|
92446
|
+
* runtime's grant lane; only the path family differs.
|
|
92447
|
+
*/
|
|
92448
|
+
const LIFECYCLE_INTENT_TIMEOUT = "10 seconds";
|
|
92449
|
+
const LifecycleIntentListEnvelope = Struct({ data: Struct({ intents: ArraySchema(Struct({
|
|
92450
|
+
runtimeId: String$1,
|
|
92451
|
+
threadId: String$1,
|
|
92452
|
+
action: Literals(["settle", "unsettle"]),
|
|
92453
|
+
requestedAt: String$1
|
|
92454
|
+
})) }) });
|
|
92455
|
+
const LifecycleIntentAcknowledgementEnvelope = Struct({ data: Struct({ acknowledged: Number$1 }) });
|
|
92456
|
+
const decodeListEnvelope = decodeUnknownSync(LifecycleIntentListEnvelope);
|
|
92457
|
+
const decodeAcknowledgementEnvelope = decodeUnknownSync(LifecycleIntentAcknowledgementEnvelope);
|
|
92458
|
+
function decodeLifecycleIntentListResponse(response) {
|
|
92459
|
+
return decodeListEnvelope(response).data;
|
|
92460
|
+
}
|
|
92461
|
+
function decodeLifecycleIntentAcknowledgementResponse(response) {
|
|
92462
|
+
return decodeAcknowledgementEnvelope(response).data;
|
|
92463
|
+
}
|
|
92464
|
+
/**
|
|
92465
|
+
* Ids arrive from runtime rows, not constrained to path-safe characters, so
|
|
92466
|
+
* they are encoded the way every other runtime-lane path builder encodes them.
|
|
92467
|
+
*/
|
|
92468
|
+
function lifecycleIntentPath(lane, operation) {
|
|
92469
|
+
const base = `/api/forge/context/${lane.kind === "grant" ? "runtime-replication" : "devices"}/runtimes/${encodeURIComponent(lane.runtimeId)}/thread-lifecycle-intents`;
|
|
92470
|
+
return operation === "ack" ? `${base}/ack` : base;
|
|
92471
|
+
}
|
|
92472
|
+
function timedOut(operation) {
|
|
92473
|
+
return new RuntimeReplicationClientError({
|
|
92474
|
+
kind: "retryable",
|
|
92475
|
+
code: "CMMD_TIMEOUT",
|
|
92476
|
+
detail: `CMMD lifecycle intent ${operation} timed out.`
|
|
92477
|
+
});
|
|
92478
|
+
}
|
|
92479
|
+
function decodeOrFail(response, decode, label) {
|
|
92480
|
+
return try_({
|
|
92481
|
+
try: () => decode(response),
|
|
92482
|
+
catch: (cause) => new RuntimeReplicationClientError({
|
|
92483
|
+
kind: "permanent",
|
|
92484
|
+
code: "CMMD_PROTOCOL_INVALID_RESPONSE",
|
|
92485
|
+
detail: `CMMD returned an invalid lifecycle intent ${label}: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
92486
|
+
})
|
|
92487
|
+
});
|
|
92488
|
+
}
|
|
92489
|
+
/**
|
|
92490
|
+
* Every pending intent for this runtime, or an empty list.
|
|
92491
|
+
*
|
|
92492
|
+
* 404 is an ordinary answer, not a failure: a CMMD that predates the route
|
|
92493
|
+
* has nothing pending for anyone, and a runtime it has not registered yet has
|
|
92494
|
+
* nothing pending either. Every other non-2xx is a typed error -- a signed-out
|
|
92495
|
+
* owner (auth) is the caller's to skip, an outage is the next tick's to retry.
|
|
92496
|
+
*/
|
|
92497
|
+
function listPendingLifecycleIntents(lane, transport) {
|
|
92498
|
+
return tryPromise({
|
|
92499
|
+
try: (signal) => requestOnRuntimeLane(lane, {
|
|
92500
|
+
method: "GET",
|
|
92501
|
+
path: lifecycleIntentPath(lane, "list"),
|
|
92502
|
+
signal
|
|
92503
|
+
}, transport),
|
|
92504
|
+
catch: (cause) => cause instanceof CmmdProxyRequestError && cause.status === 404 ? null : mapRuntimeReplicationClientError(cause)
|
|
92505
|
+
}).pipe(catch_((cause) => cause === null ? succeed(null) : fail(cause)), flatMap((response) => response === null ? succeed([]) : decodeOrFail(response, decodeLifecycleIntentListResponse, "list").pipe(map$3((list) => list.intents))), timeoutOrElse({
|
|
92506
|
+
duration: LIFECYCLE_INTENT_TIMEOUT,
|
|
92507
|
+
orElse: () => fail(timedOut("list"))
|
|
92508
|
+
}));
|
|
92509
|
+
}
|
|
92510
|
+
/**
|
|
92511
|
+
* Tell CMMD which intents were applied (or deliberately skipped), by thread
|
|
92512
|
+
* and requested time. CMMD drops only an intent whose requested time matches,
|
|
92513
|
+
* so a newer request recorded while this one was being applied survives.
|
|
92514
|
+
*/
|
|
92515
|
+
function acknowledgeLifecycleIntents(lane, intents, transport) {
|
|
92516
|
+
const body = { intents };
|
|
92517
|
+
return tryPromise({
|
|
92518
|
+
try: (signal) => requestOnRuntimeLane(lane, {
|
|
92519
|
+
method: "POST",
|
|
92520
|
+
path: lifecycleIntentPath(lane, "ack"),
|
|
92521
|
+
body,
|
|
92522
|
+
signal
|
|
92523
|
+
}, transport),
|
|
92524
|
+
catch: mapRuntimeReplicationClientError
|
|
92525
|
+
}).pipe(flatMap((response) => decodeOrFail(response, decodeLifecycleIntentAcknowledgementResponse, "acknowledgement")), timeoutOrElse({
|
|
92526
|
+
duration: LIFECYCLE_INTENT_TIMEOUT,
|
|
92527
|
+
orElse: () => fail(timedOut("ack"))
|
|
92528
|
+
}));
|
|
92529
|
+
}
|
|
92530
|
+
//#endregion
|
|
92265
92531
|
//#region src/runtimeReplication/runtimeReplicationGrantPolicy.ts
|
|
92266
92532
|
/**
|
|
92267
92533
|
* Chooses which CMMD grant a replication send should use: the in-memory
|
|
@@ -92357,26 +92623,11 @@ function runtimeReplicationDevicePath(input) {
|
|
|
92357
92623
|
const threadId = input.streamKey.slice(7);
|
|
92358
92624
|
return `${devicePath}/threads/${encodeURIComponent(threadId)}/events`;
|
|
92359
92625
|
}
|
|
92360
|
-
async function parseRuntimeReplicationResponse(response) {
|
|
92361
|
-
const text = await response.text();
|
|
92362
|
-
let body = null;
|
|
92363
|
-
if (text) try {
|
|
92364
|
-
body = JSON.parse(text);
|
|
92365
|
-
} catch {
|
|
92366
|
-
body = null;
|
|
92367
|
-
}
|
|
92368
|
-
if (!response.ok) {
|
|
92369
|
-
const code = readRuntimeReplicationErrorCode(body);
|
|
92370
|
-
throw new CmmdProxyRequestError(`CMMD runtime replication failed (${response.status})`, response.status, null, code ? { code } : null);
|
|
92371
|
-
}
|
|
92372
|
-
if (body === null) throw new Error("CMMD runtime replication returned an empty or invalid JSON response.");
|
|
92373
|
-
return body;
|
|
92374
|
-
}
|
|
92375
92626
|
async function requestRuntimeReplicationWithGrant(input, fetchImpl = fetch) {
|
|
92376
92627
|
const abortController = new AbortController();
|
|
92377
92628
|
const timeout = setTimeout(() => abortController.abort(), RUNTIME_REPLICATION_TIMEOUT_MS);
|
|
92378
92629
|
try {
|
|
92379
|
-
return await
|
|
92630
|
+
return await parseRuntimeLaneResponse(await fetchImpl(new URL(runtimeReplicationGrantPath(input), `${input.controlPlaneUrl}/`), {
|
|
92380
92631
|
method: input.operation === "inventory" ? "PUT" : "POST",
|
|
92381
92632
|
headers: {
|
|
92382
92633
|
authorization: `Bearer ${input.grantToken}`,
|
|
@@ -92389,34 +92640,6 @@ async function requestRuntimeReplicationWithGrant(input, fetchImpl = fetch) {
|
|
|
92389
92640
|
clearTimeout(timeout);
|
|
92390
92641
|
}
|
|
92391
92642
|
}
|
|
92392
|
-
function mapRuntimeReplicationClientError(error, operation) {
|
|
92393
|
-
if (error instanceof CmmdProxyAuthError) return new RuntimeReplicationClientError({
|
|
92394
|
-
kind: "auth",
|
|
92395
|
-
code: "CMMD_AUTH_REQUIRED",
|
|
92396
|
-
detail: error.message
|
|
92397
|
-
});
|
|
92398
|
-
if (error instanceof CmmdProxyAuthenticationRequiredError) return new RuntimeReplicationClientError({
|
|
92399
|
-
kind: "auth",
|
|
92400
|
-
code: "CMMD_AUTH_REQUIRED",
|
|
92401
|
-
detail: error.message
|
|
92402
|
-
});
|
|
92403
|
-
if (error instanceof CmmdProxyPermissionError) return new RuntimeReplicationClientError({
|
|
92404
|
-
kind: "permanent",
|
|
92405
|
-
code: "CMMD_PERMISSION_DENIED",
|
|
92406
|
-
detail: error.message
|
|
92407
|
-
});
|
|
92408
|
-
if (error instanceof CmmdProxyRequestError) return new RuntimeReplicationClientError(classifyRuntimeReplicationHttpFailure({
|
|
92409
|
-
status: error.status,
|
|
92410
|
-
body: error.body,
|
|
92411
|
-
detail: error.detail ?? error.message,
|
|
92412
|
-
...operation ? { operation } : {}
|
|
92413
|
-
}));
|
|
92414
|
-
return new RuntimeReplicationClientError({
|
|
92415
|
-
kind: "retryable",
|
|
92416
|
-
code: "CMMD_UNAVAILABLE",
|
|
92417
|
-
detail: error instanceof Error ? error.message : String(error)
|
|
92418
|
-
});
|
|
92419
|
-
}
|
|
92420
92643
|
function decodeRuntimeThreadAcknowledgementResponse(response) {
|
|
92421
92644
|
return decodeThreadAcknowledgement(response).data.acknowledgement;
|
|
92422
92645
|
}
|
|
@@ -92492,9 +92715,12 @@ function replicateWithOwnerSession(sql, input) {
|
|
|
92492
92715
|
const jwt = owner.jwt;
|
|
92493
92716
|
const path = runtimeReplicationDevicePath(input);
|
|
92494
92717
|
const response = yield* tryPromise({
|
|
92495
|
-
try: () =>
|
|
92718
|
+
try: () => requestOnRuntimeLane({
|
|
92719
|
+
kind: "owner-session",
|
|
92720
|
+
runtimeId: input.runtimeId,
|
|
92721
|
+
jwt
|
|
92722
|
+
}, {
|
|
92496
92723
|
method: input.operation === "inventory" ? "PUT" : "POST",
|
|
92497
|
-
jwt,
|
|
92498
92724
|
path,
|
|
92499
92725
|
body: input.payload
|
|
92500
92726
|
}),
|
|
@@ -92505,11 +92731,63 @@ function replicateWithOwnerSession(sql, input) {
|
|
|
92505
92731
|
return yield* decodeAcknowledgementOrFail(response, decodeRuntimeThreadAcknowledgementResponse, "transcript");
|
|
92506
92732
|
});
|
|
92507
92733
|
}
|
|
92734
|
+
/**
|
|
92735
|
+
* The lane this runtime holds right now, resolved per call because both
|
|
92736
|
+
* credentials rotate: the cloud grant is re-read from the control authority,
|
|
92737
|
+
* and the owner session is whichever sign-in is newest on this desktop.
|
|
92738
|
+
*/
|
|
92739
|
+
function resolveRuntimeLane(config, sql, input) {
|
|
92740
|
+
return gen(function* () {
|
|
92741
|
+
if (config.forgeCmmdRuntimeMode === true) {
|
|
92742
|
+
const cloudGrant = resolveCloudRuntimeReplicationGrant(config);
|
|
92743
|
+
if (!cloudGrant) return yield* new RuntimeReplicationClientError({
|
|
92744
|
+
kind: "auth",
|
|
92745
|
+
code: "CMMD_RUNTIME_GRANT_REQUIRED",
|
|
92746
|
+
detail: "Cloud runtime replication requires a canonical runtime ID, CMMD URL, and scoped runtime grant."
|
|
92747
|
+
});
|
|
92748
|
+
if (input.runtimeId !== cloudGrant.runtimeId) return yield* new RuntimeReplicationClientError({
|
|
92749
|
+
kind: "permanent",
|
|
92750
|
+
code: "CMMD_RUNTIME_ID_MISMATCH",
|
|
92751
|
+
detail: "The requested runtime does not match this cloud runtime identity."
|
|
92752
|
+
});
|
|
92753
|
+
return {
|
|
92754
|
+
kind: "grant",
|
|
92755
|
+
controlPlaneUrl: cloudGrant.controlPlaneUrl,
|
|
92756
|
+
runtimeId: cloudGrant.runtimeId,
|
|
92757
|
+
grantToken: cloudGrant.grantToken
|
|
92758
|
+
};
|
|
92759
|
+
}
|
|
92760
|
+
const owner = yield* resolveCmmdOwnerSessionCredential(sql, { logPrefix: input.logPrefix });
|
|
92761
|
+
if (owner.kind === "no-session") return yield* new RuntimeReplicationClientError({
|
|
92762
|
+
kind: "auth",
|
|
92763
|
+
code: "CMMD_AUTH_REQUIRED",
|
|
92764
|
+
detail: "CMMD sign-in is required for runtime replication."
|
|
92765
|
+
});
|
|
92766
|
+
if (owner.kind === "no-credential") return yield* new RuntimeReplicationClientError({
|
|
92767
|
+
kind: "auth",
|
|
92768
|
+
code: "CMMD_AUTH_REQUIRED",
|
|
92769
|
+
detail: "CMMD REST credentials are unavailable for runtime replication."
|
|
92770
|
+
});
|
|
92771
|
+
return {
|
|
92772
|
+
kind: "owner-session",
|
|
92773
|
+
runtimeId: input.runtimeId,
|
|
92774
|
+
jwt: owner.jwt
|
|
92775
|
+
};
|
|
92776
|
+
});
|
|
92777
|
+
}
|
|
92508
92778
|
const RuntimeReplicationClientLive = effect(RuntimeReplicationClient, gen(function* () {
|
|
92509
92779
|
const sql = yield* SqlClient;
|
|
92510
92780
|
const config = yield* ServerConfig;
|
|
92511
92781
|
const send = (input) => config.forgeCmmdRuntimeMode === true ? replicateWithRuntimeGrant(config, input) : replicateWithOwnerSession(sql, input);
|
|
92512
|
-
|
|
92782
|
+
const lane = (runtimeId) => resolveRuntimeLane(config, sql, {
|
|
92783
|
+
runtimeId,
|
|
92784
|
+
logPrefix: "lifecycle-intents"
|
|
92785
|
+
});
|
|
92786
|
+
return RuntimeReplicationClient.of({
|
|
92787
|
+
send,
|
|
92788
|
+
listPendingLifecycleIntents: ({ runtimeId }) => lane(runtimeId).pipe(flatMap((l) => listPendingLifecycleIntents(l))),
|
|
92789
|
+
acknowledgeLifecycleIntents: ({ runtimeId, intents }) => lane(runtimeId).pipe(flatMap((l) => acknowledgeLifecycleIntents(l, intents)))
|
|
92790
|
+
});
|
|
92513
92791
|
}));
|
|
92514
92792
|
//#endregion
|
|
92515
92793
|
//#region src/runtimeReplication/Services/RuntimeReplicationOutbox.ts
|
|
@@ -92827,6 +93105,14 @@ function stableReplicaDigest(...values) {
|
|
|
92827
93105
|
function replicaHydrationCommandId(runtimeId, generationId, threadId) {
|
|
92828
93106
|
return CommandId.make("runtime-replica-hydration:" + stableReplicaDigest(runtimeId, generationId, threadId));
|
|
92829
93107
|
}
|
|
93108
|
+
/**
|
|
93109
|
+
* One id per (runtime, thread, requested time): a restart between dispatch and
|
|
93110
|
+
* acknowledgement re-lists the same intent, and the engine's command receipts
|
|
93111
|
+
* turn the second dispatch into a no-op instead of a second settle.
|
|
93112
|
+
*/
|
|
93113
|
+
function lifecycleIntentCommandId(runtimeId, threadId, requestedAt) {
|
|
93114
|
+
return CommandId.make("lifecycle-intent:" + stableReplicaDigest(runtimeId, threadId, requestedAt));
|
|
93115
|
+
}
|
|
92830
93116
|
//#endregion
|
|
92831
93117
|
//#region src/runtimeReplication/protocol.ts
|
|
92832
93118
|
const EMPTY_RUNTIME_THREAD_HEAD_HASH = "sha256:47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU";
|
|
@@ -93776,6 +94062,21 @@ function totalTokens(totals) {
|
|
|
93776
94062
|
return totals.uncachedInputTokens + totals.cachedInputTokens + totals.cacheCreationTokens + totals.outputTokens;
|
|
93777
94063
|
}
|
|
93778
94064
|
/**
|
|
94065
|
+
* What a transcript record's own on-disk facts say it is a row of.
|
|
94066
|
+
*
|
|
94067
|
+
* Reuses exactly the facts `usageDrivers.ts`'s `isForgeAgent` reads to route a
|
|
94068
|
+
* record to the Forge agents lane, minus the "is this one of this
|
|
94069
|
+
* environment's own threads" gate: a Claude sidechain or a Codex subagent
|
|
94070
|
+
* rollout is a Subagent row regardless of which thread (if any) it hangs
|
|
94071
|
+
* under, so a subagent driven from outside Forge is still `subagent`, not a
|
|
94072
|
+
* plain Recorded-turn-shaped `turn`. Exported so the scan cache can recompute
|
|
94073
|
+
* the same value on decode instead of storing it as a redundant column.
|
|
94074
|
+
*/
|
|
94075
|
+
function transcriptRecordKind(provider, sidechain, rootSessionId) {
|
|
94076
|
+
if (provider === "claude") return sidechain === true ? "subagent" : "turn";
|
|
94077
|
+
return rootSessionId !== void 0 ? "subagent" : "turn";
|
|
94078
|
+
}
|
|
94079
|
+
/**
|
|
93779
94080
|
* Cheap substring gate applied before `JSON.parse`.
|
|
93780
94081
|
*
|
|
93781
94082
|
* Transcripts are mostly tool output; only a minority of lines carry usage. On
|
|
@@ -93844,6 +94145,7 @@ function parseClaudeLine(line, diagnostics) {
|
|
|
93844
94145
|
const dedupeKey = claudeDedupeKey(stringAt(messageRecord, "id"), stringAt(record, "requestId"));
|
|
93845
94146
|
const cost = record["costUSD"];
|
|
93846
94147
|
const launcher = stringAt(record, "entrypoint");
|
|
94148
|
+
const sidechain = record["isSidechain"] === true;
|
|
93847
94149
|
return {
|
|
93848
94150
|
provider: "claude",
|
|
93849
94151
|
timestampMs,
|
|
@@ -93852,8 +94154,9 @@ function parseClaudeLine(line, diagnostics) {
|
|
|
93852
94154
|
totals: claudeTokenBuckets(usageRecord) ?? EMPTY_TOTALS,
|
|
93853
94155
|
reportedCostUsd: typeof cost === "number" && Number.isFinite(cost) ? cost : null,
|
|
93854
94156
|
dedupeKey,
|
|
94157
|
+
kind: transcriptRecordKind("claude", sidechain, void 0),
|
|
93855
94158
|
...launcher === null ? {} : { launcher },
|
|
93856
|
-
...
|
|
94159
|
+
...sidechain ? { sidechain: true } : {}
|
|
93857
94160
|
};
|
|
93858
94161
|
}
|
|
93859
94162
|
function initialCodexScanState() {
|
|
@@ -93970,6 +94273,7 @@ function parseCodexTokenCount(record, payloadRecord, state) {
|
|
|
93970
94273
|
totals,
|
|
93971
94274
|
reportedCostUsd: null,
|
|
93972
94275
|
dedupeKey: null,
|
|
94276
|
+
kind: transcriptRecordKind("codex", void 0, state.rootSessionId),
|
|
93973
94277
|
...codexSessionFields(state)
|
|
93974
94278
|
};
|
|
93975
94279
|
}
|
|
@@ -94238,7 +94542,8 @@ var UsageAggregator = class {
|
|
|
94238
94542
|
origin,
|
|
94239
94543
|
sync,
|
|
94240
94544
|
runtimeId,
|
|
94241
|
-
driver
|
|
94545
|
+
driver,
|
|
94546
|
+
record.kind
|
|
94242
94547
|
].join("\0");
|
|
94243
94548
|
const existing = this.#buckets.get(key);
|
|
94244
94549
|
if (existing !== void 0) return existing;
|
|
@@ -94276,7 +94581,7 @@ var UsageAggregator = class {
|
|
|
94276
94581
|
finish() {
|
|
94277
94582
|
const buckets = [];
|
|
94278
94583
|
for (const [key, bucket] of this.#buckets) {
|
|
94279
|
-
const [day = "", hourStart = "", provider = "", model = "", origin = "", sync = "", runtimeId = "", driver = ""] = key.split("\0");
|
|
94584
|
+
const [day = "", hourStart = "", provider = "", model = "", origin = "", sync = "", runtimeId = "", driver = "", kind = ""] = key.split("\0");
|
|
94280
94585
|
buckets.push({
|
|
94281
94586
|
day,
|
|
94282
94587
|
...hourStart === "" ? {} : { hourStart },
|
|
@@ -94292,10 +94597,15 @@ var UsageAggregator = class {
|
|
|
94292
94597
|
origin,
|
|
94293
94598
|
...sync === "" ? {} : { sync },
|
|
94294
94599
|
...runtimeId === "" ? {} : { runtimeId },
|
|
94295
|
-
...driver === "" ? {} : { driver }
|
|
94600
|
+
...driver === "" ? {} : { driver },
|
|
94601
|
+
kind
|
|
94296
94602
|
});
|
|
94297
94603
|
}
|
|
94298
|
-
buckets.sort((a, b) =>
|
|
94604
|
+
buckets.sort((a, b) => {
|
|
94605
|
+
const left = bucketSortKey(a);
|
|
94606
|
+
const right = bucketSortKey(b);
|
|
94607
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
94608
|
+
});
|
|
94299
94609
|
return {
|
|
94300
94610
|
buckets,
|
|
94301
94611
|
duplicatesDropped: this.#duplicatesDropped,
|
|
@@ -94313,7 +94623,8 @@ function bucketSortKey(bucket) {
|
|
|
94313
94623
|
bucket.origin ?? "",
|
|
94314
94624
|
bucket.sync ?? "",
|
|
94315
94625
|
bucket.runtimeId ?? "",
|
|
94316
|
-
bucket.driver ?? ""
|
|
94626
|
+
bucket.driver ?? "",
|
|
94627
|
+
bucket.kind ?? ""
|
|
94317
94628
|
].join("\0");
|
|
94318
94629
|
}
|
|
94319
94630
|
/**
|
|
@@ -95302,6 +95613,7 @@ function syncOf(sequence, options, threadId, events) {
|
|
|
95302
95613
|
return sequence <= cursor.acknowledgedSequence ? "acknowledged" : "pending";
|
|
95303
95614
|
}
|
|
95304
95615
|
function recordOf(event, provider, sync, threadId, runtimeId) {
|
|
95616
|
+
const kind = event.usageKind ?? "turn";
|
|
95305
95617
|
return {
|
|
95306
95618
|
provider,
|
|
95307
95619
|
timestampMs: Date.parse(event.occurredAt),
|
|
@@ -95310,6 +95622,7 @@ function recordOf(event, provider, sync, threadId, runtimeId) {
|
|
|
95310
95622
|
totals: event.usage ?? EMPTY_TOTALS,
|
|
95311
95623
|
reportedCostUsd: null,
|
|
95312
95624
|
dedupeKey: `recorded:${threadId}:${event.turnId}:${event.usageKind ?? "turn"}:${event.subagentId ?? ""}:${event.model}`,
|
|
95625
|
+
kind,
|
|
95313
95626
|
origin: "recorded",
|
|
95314
95627
|
...sync === void 0 ? {} : { sync },
|
|
95315
95628
|
...runtimeId === void 0 ? {} : { runtimeId },
|
|
@@ -96030,6 +96343,22 @@ async function readTranscriptRecords(filePath, provider) {
|
|
|
96030
96343
|
//#endregion
|
|
96031
96344
|
//#region src/usage/usageScanCache.ts
|
|
96032
96345
|
/**
|
|
96346
|
+
* Durable per-file scan cache.
|
|
96347
|
+
*
|
|
96348
|
+
* Transcripts are append-only and a file that has not changed can never yield
|
|
96349
|
+
* different usage, so parsed records are keyed by `(size, mtime)` and reused.
|
|
96350
|
+
* Without this every server restart re-parses the whole window: seconds for a
|
|
96351
|
+
* 30-day scan, against milliseconds to reload this cache.
|
|
96352
|
+
*
|
|
96353
|
+
* Caching *per file* rather than per day is deliberate. It is timezone
|
|
96354
|
+
* independent, so changing the reporting zone does not invalidate anything, and
|
|
96355
|
+
* it keeps cross-file de-duplication exact: cached entries are de-duplicated
|
|
96356
|
+
* within their own file only, and the aggregator still applies the global
|
|
96357
|
+
* dedupe pass over the small surviving key set.
|
|
96358
|
+
*
|
|
96359
|
+
* @module usageScanCache
|
|
96360
|
+
*/
|
|
96361
|
+
/**
|
|
96033
96362
|
* Bumped whenever cached records could differ from what a fresh parse produces.
|
|
96034
96363
|
*
|
|
96035
96364
|
* Version 1 was written before `parseCodexLine` suppressed the parent history a
|
|
@@ -96175,6 +96504,7 @@ function decodeRecord(row, provider, tables) {
|
|
|
96175
96504
|
},
|
|
96176
96505
|
reportedCostUsd: finiteNumber(reportedCostUsd),
|
|
96177
96506
|
dedupeKey: typeof dedupeKey === "string" ? dedupeKey : null,
|
|
96507
|
+
kind: transcriptRecordKind(provider, session.sidechain, session.rootSessionId),
|
|
96178
96508
|
...session
|
|
96179
96509
|
};
|
|
96180
96510
|
}
|
|
@@ -97138,7 +97468,7 @@ const resolveAutoBootstrapWelcomeTargets = gen(function* () {
|
|
|
97138
97468
|
/**
|
|
97139
97469
|
* Cloud-mode project recovery — runs only on cloud execution runtimes.
|
|
97140
97470
|
* Scans `cloudProjectsRoot` (default
|
|
97141
|
-
* /
|
|
97471
|
+
* /projects) for git-repo subdirectories and registers any not yet in
|
|
97142
97472
|
* the orchestration engine. This is the cloud-mode replacement for the
|
|
97143
97473
|
* gated `autoBootstrapProjectFromCwd` path: managed runtimes whose volume
|
|
97144
97474
|
* already holds cloned repos surface them in the sidebar after restart.
|
|
@@ -99142,144 +99472,6 @@ function claudeWriteToken(env = process.env) {
|
|
|
99142
99472
|
return accessor.read(env);
|
|
99143
99473
|
}
|
|
99144
99474
|
//#endregion
|
|
99145
|
-
//#region src/usage/providerRateLimits.ts
|
|
99146
|
-
/**
|
|
99147
|
-
* In-process cache of the latest Claude 5h/7d rate-limit telemetry, decoded
|
|
99148
|
-
* from the genuine Claude Agent SDK's own `rate_limit_event` messages
|
|
99149
|
-
* (see ClaudeAdapter.ts). This is intentionally NOT a CMMD call site: CMMD
|
|
99150
|
-
* must never replay a personal Claude OAuth token against api.anthropic.com
|
|
99151
|
-
* from its own backend (see CMMD's personal-claude-delivery.ts) - the only
|
|
99152
|
-
* legitimate source for this data is the real in-VM SDK session reporting it
|
|
99153
|
-
* as a side effect of a real turn.
|
|
99154
|
-
*
|
|
99155
|
-
* Snapshots are fenced by the exact non-secret credential-generation hash.
|
|
99156
|
-
* A Forge process can outlive an account reconnect, so a process-wide singleton
|
|
99157
|
-
* without that fence can leak account A's windows into account B's session.
|
|
99158
|
-
* The request-scoped route that reads this
|
|
99159
|
-
* cache (apps/server/src/command/http.ts) is what actually forwards it to
|
|
99160
|
-
* CMMD, using the request's own authenticated session - a background event
|
|
99161
|
-
* pipeline has no such session to reuse safely.
|
|
99162
|
-
*/
|
|
99163
|
-
/**
|
|
99164
|
-
* The SDK only ever reports ONE window per event. Only `five_hour` and
|
|
99165
|
-
* `seven_day` map to the two windows the Usage page shows; the
|
|
99166
|
-
* per-model/overage variants (seven_day_opus, overage, ...) are ignored here
|
|
99167
|
-
* on purpose rather than silently overwriting the plain 7-day figure.
|
|
99168
|
-
*/
|
|
99169
|
-
function mapClaudeRateLimitInfo(info) {
|
|
99170
|
-
if (typeof info.utilization !== "number" || typeof info.resetsAt !== "number" || !info.status) return null;
|
|
99171
|
-
const kind = info.rateLimitType === "five_hour" ? "fiveHour" : info.rateLimitType === "seven_day" ? "sevenDay" : null;
|
|
99172
|
-
if (!kind) return null;
|
|
99173
|
-
return {
|
|
99174
|
-
kind,
|
|
99175
|
-
window: {
|
|
99176
|
-
usedPercent: Math.round(info.utilization * 100),
|
|
99177
|
-
resetsAt: (/* @__PURE__ */ new Date(info.resetsAt * 1e3)).toISOString(),
|
|
99178
|
-
status: info.status
|
|
99179
|
-
}
|
|
99180
|
-
};
|
|
99181
|
-
}
|
|
99182
|
-
const SEVEN_DAY_MODEL_PREFIX = "seven_day_";
|
|
99183
|
-
const SEVEN_DAY_OVERAGE_SUFFIX = "overage_included";
|
|
99184
|
-
function capitalizeModelSuffix(suffix) {
|
|
99185
|
-
return suffix.length === 0 ? suffix : suffix.charAt(0).toUpperCase() + suffix.slice(1);
|
|
99186
|
-
}
|
|
99187
|
-
/**
|
|
99188
|
-
* Maps a per-model weekly SDKRateLimitInfo (`seven_day_<model>`, e.g.
|
|
99189
|
-
* `seven_day_opus`) into a `ProviderUsageModelWindow`. `seven_day_overage_included`
|
|
99190
|
-
* is not a per-model window (it reports overage-inclusive quota, not a
|
|
99191
|
-
* specific model) and stays ignored here, same as plain `overage`.
|
|
99192
|
-
*/
|
|
99193
|
-
function mapClaudeModelRateLimitInfo(info) {
|
|
99194
|
-
if (typeof info.utilization !== "number" || typeof info.resetsAt !== "number" || !info.status) return null;
|
|
99195
|
-
if (!info.rateLimitType?.startsWith(SEVEN_DAY_MODEL_PREFIX)) return null;
|
|
99196
|
-
const suffix = info.rateLimitType.slice(10);
|
|
99197
|
-
if (suffix.length === 0 || suffix === SEVEN_DAY_OVERAGE_SUFFIX) return null;
|
|
99198
|
-
return {
|
|
99199
|
-
model: capitalizeModelSuffix(suffix),
|
|
99200
|
-
window: {
|
|
99201
|
-
usedPercent: Math.round(info.utilization * 100),
|
|
99202
|
-
resetsAt: (/* @__PURE__ */ new Date(info.resetsAt * 1e3)).toISOString(),
|
|
99203
|
-
status: info.status
|
|
99204
|
-
}
|
|
99205
|
-
};
|
|
99206
|
-
}
|
|
99207
|
-
const cachedSnapshots = /* @__PURE__ */ new Map();
|
|
99208
|
-
let localClaudeGenerationHash = null;
|
|
99209
|
-
function setLocalClaudeUsageGeneration(generationId) {
|
|
99210
|
-
localClaudeGenerationHash = createHash("sha256").update(generationId).digest("hex");
|
|
99211
|
-
}
|
|
99212
|
-
function currentClaudeUsageGenerationHash() {
|
|
99213
|
-
const value = process.env.FORGE_PERSONAL_CLAUDE_GENERATION_HASH?.trim() ?? "";
|
|
99214
|
-
return /^[a-f0-9]{64}$/.test(value) ? value : localClaudeGenerationHash;
|
|
99215
|
-
}
|
|
99216
|
-
function cacheKeyFor(generationHash, providerAccountId) {
|
|
99217
|
-
return providerAccountId ? `${providerAccountId}:${generationHash}` : generationHash;
|
|
99218
|
-
}
|
|
99219
|
-
/**
|
|
99220
|
-
* `observedAt` here is a placeholder, not an observation — it becomes
|
|
99221
|
-
* meaningful only once a standard (five_hour/seven_day) window actually
|
|
99222
|
-
* lands via `withStandardWindow`, which recomputes it from the retained
|
|
99223
|
-
* windows' own observation times. A per-model-only cache (no standard window
|
|
99224
|
-
* yet) still carries this placeholder, so callers should treat `observedAt`
|
|
99225
|
-
* as trustworthy only once `fiveHour` or `sevenDay` is non-null.
|
|
99226
|
-
*/
|
|
99227
|
-
function emptyCachedSnapshot(observedAt) {
|
|
99228
|
-
return {
|
|
99229
|
-
fiveHour: null,
|
|
99230
|
-
sevenDay: null,
|
|
99231
|
-
modelWindowsByModel: {},
|
|
99232
|
-
observedAt,
|
|
99233
|
-
fiveHourObservedAt: null,
|
|
99234
|
-
sevenDayObservedAt: null
|
|
99235
|
-
};
|
|
99236
|
-
}
|
|
99237
|
-
/** Oldest observation among the retained standard windows, so one fresh event cannot mask stale data. */
|
|
99238
|
-
function oldestObservedAt(fiveHourObservedAt, sevenDayObservedAt) {
|
|
99239
|
-
return [fiveHourObservedAt, sevenDayObservedAt].filter((value) => value !== null).toSorted()[0];
|
|
99240
|
-
}
|
|
99241
|
-
function withStandardWindow(previous, mapped, observedAt) {
|
|
99242
|
-
const isFiveHour = mapped.kind === "fiveHour";
|
|
99243
|
-
const fiveHourObservedAt = isFiveHour ? observedAt : previous.fiveHourObservedAt;
|
|
99244
|
-
const sevenDayObservedAt = isFiveHour ? previous.sevenDayObservedAt : observedAt;
|
|
99245
|
-
return {
|
|
99246
|
-
...previous,
|
|
99247
|
-
fiveHour: isFiveHour ? mapped.window : previous.fiveHour,
|
|
99248
|
-
sevenDay: isFiveHour ? previous.sevenDay : mapped.window,
|
|
99249
|
-
fiveHourObservedAt,
|
|
99250
|
-
sevenDayObservedAt,
|
|
99251
|
-
observedAt: oldestObservedAt(fiveHourObservedAt, sevenDayObservedAt)
|
|
99252
|
-
};
|
|
99253
|
-
}
|
|
99254
|
-
function withModelWindow(previous, mapped) {
|
|
99255
|
-
return {
|
|
99256
|
-
...previous,
|
|
99257
|
-
modelWindowsByModel: {
|
|
99258
|
-
...previous.modelWindowsByModel,
|
|
99259
|
-
[mapped.model]: mapped.window
|
|
99260
|
-
}
|
|
99261
|
-
};
|
|
99262
|
-
}
|
|
99263
|
-
/**
|
|
99264
|
-
* Merges a single-window update into the cached snapshot without clobbering
|
|
99265
|
-
* the other windows. A per-model weekly report (`seven_day_<model>`) merges
|
|
99266
|
-
* into `modelWindowsByModel` keyed by model, leaving every other model and
|
|
99267
|
-
* the plain five_hour/seven_day windows untouched.
|
|
99268
|
-
*/
|
|
99269
|
-
function recordClaudeRateLimitTelemetry(info, generationHash = currentClaudeUsageGenerationHash(), providerAccountId) {
|
|
99270
|
-
if (generationHash === null) return;
|
|
99271
|
-
const cacheKey = cacheKeyFor(generationHash, providerAccountId);
|
|
99272
|
-
const observedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
99273
|
-
const previous = cachedSnapshots.get(cacheKey) ?? emptyCachedSnapshot(observedAt);
|
|
99274
|
-
const standard = mapClaudeRateLimitInfo(info);
|
|
99275
|
-
if (standard) {
|
|
99276
|
-
cachedSnapshots.set(cacheKey, withStandardWindow(previous, standard, observedAt));
|
|
99277
|
-
return;
|
|
99278
|
-
}
|
|
99279
|
-
const model = mapClaudeModelRateLimitInfo(info);
|
|
99280
|
-
if (model) cachedSnapshots.set(cacheKey, withModelWindow(previous, model));
|
|
99281
|
-
}
|
|
99282
|
-
//#endregion
|
|
99283
99475
|
//#region src/providerAuth/ClaudeDeviceAuth.ts
|
|
99284
99476
|
const AUTHORIZE_URL_PATTERN = /https:\/\/[^\s]*\/oauth\/authorize\?[^\s]+/u;
|
|
99285
99477
|
const ANSI_ESCAPE_PATTERN$1 = new RegExp(String.raw`\x1B\[[0-?]*[ -/]*[@-~]`, "gu");
|
|
@@ -99794,7 +99986,6 @@ async function finalizeClaudeCredentialSync(input) {
|
|
|
99794
99986
|
const providerAccountId = extractClaudeProviderAccountId(input.response);
|
|
99795
99987
|
const credentialGenerationId = extractClaudeCredentialGenerationId(input.response);
|
|
99796
99988
|
if (providerAccountId === null || credentialGenerationId === null) return null;
|
|
99797
|
-
if (input.auth.path === USER_CLAUDE_CREDENTIAL_PATH) setLocalClaudeUsageGeneration(credentialGenerationId);
|
|
99798
99989
|
return publishClaudeUsageAfterSync({
|
|
99799
99990
|
auth: input.auth,
|
|
99800
99991
|
providerAccountId,
|
|
@@ -146884,137 +147075,6 @@ const LocalAutomationRepositoryLive = effect(LocalAutomationRepository, gen(func
|
|
|
146884
147075
|
*/
|
|
146885
147076
|
var CodexAdapter = class extends Service$1()("forge/provider/Services/CodexAdapter") {};
|
|
146886
147077
|
//#endregion
|
|
146887
|
-
//#region ../../packages/shared/src/model.ts
|
|
146888
|
-
/** Check whether a capabilities object includes a given effort value. */
|
|
146889
|
-
function hasEffortLevel(caps, value) {
|
|
146890
|
-
return caps.reasoningEffortLevels.some((l) => l.value === value);
|
|
146891
|
-
}
|
|
146892
|
-
/** Return the default effort value for a capabilities object, or null if none. */
|
|
146893
|
-
function getDefaultEffort(caps) {
|
|
146894
|
-
return caps.reasoningEffortLevels.find((l) => l.isDefault)?.value ?? null;
|
|
146895
|
-
}
|
|
146896
|
-
/**
|
|
146897
|
-
* Resolve a raw effort option against capabilities.
|
|
146898
|
-
*
|
|
146899
|
-
* Returns the effective effort value — the explicit value if supported and not
|
|
146900
|
-
* prompt-injected, otherwise the model's default. Returns `undefined` only
|
|
146901
|
-
* when the model has no effort levels at all.
|
|
146902
|
-
*
|
|
146903
|
-
* Prompt-injected efforts (e.g. "ultrathink") are excluded because they are
|
|
146904
|
-
* applied via prompt text, not the effort API parameter.
|
|
146905
|
-
*/
|
|
146906
|
-
function resolveEffort(caps, raw) {
|
|
146907
|
-
const defaultValue = getDefaultEffort(caps);
|
|
146908
|
-
const trimmed = typeof raw === "string" ? raw.trim() : null;
|
|
146909
|
-
if (trimmed && !caps.promptInjectedEffortLevels.includes(trimmed) && hasEffortLevel(caps, trimmed)) return trimmed;
|
|
146910
|
-
return defaultValue ?? void 0;
|
|
146911
|
-
}
|
|
146912
|
-
/** Check whether a capabilities object includes a given context window value. */
|
|
146913
|
-
function hasContextWindowOption(caps, value) {
|
|
146914
|
-
return caps.contextWindowOptions.some((o) => o.value === value);
|
|
146915
|
-
}
|
|
146916
|
-
/** Return the default context window value, or `null` if none is defined. */
|
|
146917
|
-
function getDefaultContextWindow(caps) {
|
|
146918
|
-
return caps.contextWindowOptions.find((o) => o.isDefault)?.value ?? null;
|
|
146919
|
-
}
|
|
146920
|
-
/**
|
|
146921
|
-
* Resolve a raw `contextWindow` option against capabilities.
|
|
146922
|
-
*
|
|
146923
|
-
* Returns the effective context window value — the explicit value if supported,
|
|
146924
|
-
* otherwise the model's default. Returns `undefined` only when the model has
|
|
146925
|
-
* no context window options at all.
|
|
146926
|
-
*
|
|
146927
|
-
* Unlike effort levels (where the API has matching defaults), the context
|
|
146928
|
-
* window requires an explicit API suffix (e.g. `[1m]`), so we always preserve
|
|
146929
|
-
* the resolved value to avoid ambiguity between "user chose the default" and
|
|
146930
|
-
* "not specified".
|
|
146931
|
-
*/
|
|
146932
|
-
function resolveContextWindow(caps, raw) {
|
|
146933
|
-
const defaultValue = getDefaultContextWindow(caps);
|
|
146934
|
-
if (!raw) return defaultValue ?? void 0;
|
|
146935
|
-
return hasContextWindowOption(caps, raw) ? raw : defaultValue ?? void 0;
|
|
146936
|
-
}
|
|
146937
|
-
function normalizeCodexModelOptionsWithCapabilities(caps, modelOptions) {
|
|
146938
|
-
const reasoningEffort = resolveEffort(caps, modelOptions?.reasoningEffort);
|
|
146939
|
-
const fastMode = caps.supportsFastMode ? modelOptions?.fastMode : void 0;
|
|
146940
|
-
const nextOptions = {
|
|
146941
|
-
...reasoningEffort ? { reasoningEffort } : {},
|
|
146942
|
-
...fastMode !== void 0 ? { fastMode } : {}
|
|
146943
|
-
};
|
|
146944
|
-
return Object.keys(nextOptions).length > 0 ? nextOptions : void 0;
|
|
146945
|
-
}
|
|
146946
|
-
function normalizeClaudeModelOptionsWithCapabilities(caps, modelOptions) {
|
|
146947
|
-
const effort = resolveEffort(caps, modelOptions?.effort);
|
|
146948
|
-
const thinking = caps.supportsThinkingToggle ? modelOptions?.thinking : void 0;
|
|
146949
|
-
const fastMode = caps.supportsFastMode ? modelOptions?.fastMode : void 0;
|
|
146950
|
-
const contextWindow = resolveContextWindow(caps, modelOptions?.contextWindow);
|
|
146951
|
-
const nextOptions = {
|
|
146952
|
-
...thinking !== void 0 ? { thinking } : {},
|
|
146953
|
-
...effort ? { effort } : {},
|
|
146954
|
-
...fastMode !== void 0 ? { fastMode } : {},
|
|
146955
|
-
...contextWindow !== void 0 ? { contextWindow } : {}
|
|
146956
|
-
};
|
|
146957
|
-
return Object.keys(nextOptions).length > 0 ? nextOptions : void 0;
|
|
146958
|
-
}
|
|
146959
|
-
function normalizeModelSlug(model, provider = "codex") {
|
|
146960
|
-
if (typeof model !== "string") return null;
|
|
146961
|
-
const trimmed = model.trim();
|
|
146962
|
-
if (!trimmed) return null;
|
|
146963
|
-
const aliases = MODEL_SLUG_ALIASES_BY_PROVIDER[provider];
|
|
146964
|
-
const aliased = Object.prototype.hasOwnProperty.call(aliases, trimmed) ? aliases[trimmed] : void 0;
|
|
146965
|
-
return typeof aliased === "string" ? aliased : trimmed;
|
|
146966
|
-
}
|
|
146967
|
-
/** Trim a string, returning null for empty/missing values. */
|
|
146968
|
-
function trimOrNull(value) {
|
|
146969
|
-
if (typeof value !== "string") return null;
|
|
146970
|
-
return value.trim() || null;
|
|
146971
|
-
}
|
|
146972
|
-
/**
|
|
146973
|
-
* Resolve the actual API model identifier from a model selection.
|
|
146974
|
-
*
|
|
146975
|
-
* Provider-aware: each provider can map `contextWindow` (or other options)
|
|
146976
|
-
* to whatever the API requires — a model-id suffix, a separate parameter, etc.
|
|
146977
|
-
* The canonical slug stored in the selection stays unchanged so the
|
|
146978
|
-
* capabilities system keeps working.
|
|
146979
|
-
*
|
|
146980
|
-
* Expects `contextWindow` to already be resolved (via `resolveContextWindow`)
|
|
146981
|
-
* to the effective value, not stripped to `undefined` for defaults.
|
|
146982
|
-
*/
|
|
146983
|
-
function resolveApiModelId(modelSelection) {
|
|
146984
|
-
switch (modelSelection.provider) {
|
|
146985
|
-
case "claudeAgent": switch (modelSelection.options?.contextWindow) {
|
|
146986
|
-
case "1m": return `${modelSelection.model}[1m]`;
|
|
146987
|
-
default: return modelSelection.model;
|
|
146988
|
-
}
|
|
146989
|
-
default: return modelSelection.model;
|
|
146990
|
-
}
|
|
146991
|
-
}
|
|
146992
|
-
function applyClaudePromptEffortPrefix(text, effort) {
|
|
146993
|
-
const trimmed = text.trim();
|
|
146994
|
-
if (!trimmed) return trimmed;
|
|
146995
|
-
if (effort !== "ultrathink") return trimmed;
|
|
146996
|
-
if (trimmed.startsWith("Ultrathink:")) return trimmed;
|
|
146997
|
-
return `Ultrathink:\n${trimmed}`;
|
|
146998
|
-
}
|
|
146999
|
-
function getRawProviderOptionSelectionValue(selections, id) {
|
|
147000
|
-
return selections?.find((candidate) => candidate.id === id)?.value;
|
|
147001
|
-
}
|
|
147002
|
-
function getProviderOptionSelectionValue(selections, id) {
|
|
147003
|
-
return getRawProviderOptionSelectionValue(selections, id);
|
|
147004
|
-
}
|
|
147005
|
-
function getProviderOptionStringSelectionValue(selections, id) {
|
|
147006
|
-
const value = getProviderOptionSelectionValue(selections, id);
|
|
147007
|
-
return typeof value === "string" ? value : void 0;
|
|
147008
|
-
}
|
|
147009
|
-
function flatProviderOptions(selection) {
|
|
147010
|
-
if (!selection) return void 0;
|
|
147011
|
-
if (selection.provider !== "cursor" && selection.provider !== "opencode") return void 0;
|
|
147012
|
-
return selection.options;
|
|
147013
|
-
}
|
|
147014
|
-
function getModelSelectionStringOptionValue(selection, id) {
|
|
147015
|
-
return getProviderOptionStringSelectionValue(flatProviderOptions(selection), id);
|
|
147016
|
-
}
|
|
147017
|
-
//#endregion
|
|
147018
147078
|
//#region src/provider/codexCliVersion.ts
|
|
147019
147079
|
const CODEX_VERSION_PATTERN = /\bv?(\d+\.\d+(?:\.\d+)?(?:-[0-9A-Za-z.-]+)?)\b/;
|
|
147020
147080
|
const MINIMUM_CODEX_CLI_VERSION = "0.37.0";
|
|
@@ -147669,6 +147729,213 @@ async function probeCodexDiscovery(input) {
|
|
|
147669
147729
|
});
|
|
147670
147730
|
}
|
|
147671
147731
|
//#endregion
|
|
147732
|
+
//#region ../../packages/shared/src/model.ts
|
|
147733
|
+
/** Check whether a capabilities object includes a given effort value. */
|
|
147734
|
+
function hasEffortLevel(caps, value) {
|
|
147735
|
+
return caps.reasoningEffortLevels.some((l) => l.value === value);
|
|
147736
|
+
}
|
|
147737
|
+
/** Return the default effort value for a capabilities object, or null if none. */
|
|
147738
|
+
function getDefaultEffort(caps) {
|
|
147739
|
+
return caps.reasoningEffortLevels.find((l) => l.isDefault)?.value ?? null;
|
|
147740
|
+
}
|
|
147741
|
+
/**
|
|
147742
|
+
* Resolve a raw effort option against capabilities.
|
|
147743
|
+
*
|
|
147744
|
+
* Returns the effective effort value — the explicit value if supported and not
|
|
147745
|
+
* prompt-injected, otherwise the model's default. Returns `undefined` only
|
|
147746
|
+
* when the model has no effort levels at all.
|
|
147747
|
+
*
|
|
147748
|
+
* Prompt-injected efforts (e.g. "ultrathink") are excluded because they are
|
|
147749
|
+
* applied via prompt text, not the effort API parameter.
|
|
147750
|
+
*/
|
|
147751
|
+
function resolveEffort(caps, raw) {
|
|
147752
|
+
const defaultValue = getDefaultEffort(caps);
|
|
147753
|
+
const trimmed = typeof raw === "string" ? raw.trim() : null;
|
|
147754
|
+
if (trimmed && !caps.promptInjectedEffortLevels.includes(trimmed) && hasEffortLevel(caps, trimmed)) return trimmed;
|
|
147755
|
+
return defaultValue ?? void 0;
|
|
147756
|
+
}
|
|
147757
|
+
/** Check whether a capabilities object includes a given context window value. */
|
|
147758
|
+
function hasContextWindowOption(caps, value) {
|
|
147759
|
+
return caps.contextWindowOptions.some((o) => o.value === value);
|
|
147760
|
+
}
|
|
147761
|
+
/** Return the default context window value, or `null` if none is defined. */
|
|
147762
|
+
function getDefaultContextWindow(caps) {
|
|
147763
|
+
return caps.contextWindowOptions.find((o) => o.isDefault)?.value ?? null;
|
|
147764
|
+
}
|
|
147765
|
+
/**
|
|
147766
|
+
* Resolve a raw `contextWindow` option against capabilities.
|
|
147767
|
+
*
|
|
147768
|
+
* Returns the effective context window value — the explicit value if supported,
|
|
147769
|
+
* otherwise the model's default. Returns `undefined` only when the model has
|
|
147770
|
+
* no context window options at all.
|
|
147771
|
+
*
|
|
147772
|
+
* Unlike effort levels (where the API has matching defaults), the context
|
|
147773
|
+
* window requires an explicit API suffix (e.g. `[1m]`), so we always preserve
|
|
147774
|
+
* the resolved value to avoid ambiguity between "user chose the default" and
|
|
147775
|
+
* "not specified".
|
|
147776
|
+
*/
|
|
147777
|
+
function resolveContextWindow(caps, raw) {
|
|
147778
|
+
const defaultValue = getDefaultContextWindow(caps);
|
|
147779
|
+
if (!raw) return defaultValue ?? void 0;
|
|
147780
|
+
return hasContextWindowOption(caps, raw) ? raw : defaultValue ?? void 0;
|
|
147781
|
+
}
|
|
147782
|
+
function normalizeCodexModelOptionsWithCapabilities(caps, modelOptions) {
|
|
147783
|
+
const reasoningEffort = resolveEffort(caps, modelOptions?.reasoningEffort);
|
|
147784
|
+
const fastMode = caps.supportsFastMode ? modelOptions?.fastMode : void 0;
|
|
147785
|
+
const nextOptions = {
|
|
147786
|
+
...reasoningEffort ? { reasoningEffort } : {},
|
|
147787
|
+
...fastMode !== void 0 ? { fastMode } : {}
|
|
147788
|
+
};
|
|
147789
|
+
return Object.keys(nextOptions).length > 0 ? nextOptions : void 0;
|
|
147790
|
+
}
|
|
147791
|
+
function normalizeClaudeModelOptionsWithCapabilities(caps, modelOptions) {
|
|
147792
|
+
const effort = resolveEffort(caps, modelOptions?.effort);
|
|
147793
|
+
const thinking = caps.supportsThinkingToggle ? modelOptions?.thinking : void 0;
|
|
147794
|
+
const fastMode = caps.supportsFastMode ? modelOptions?.fastMode : void 0;
|
|
147795
|
+
const contextWindow = resolveContextWindow(caps, modelOptions?.contextWindow);
|
|
147796
|
+
const nextOptions = {
|
|
147797
|
+
...thinking !== void 0 ? { thinking } : {},
|
|
147798
|
+
...effort ? { effort } : {},
|
|
147799
|
+
...fastMode !== void 0 ? { fastMode } : {},
|
|
147800
|
+
...contextWindow !== void 0 ? { contextWindow } : {}
|
|
147801
|
+
};
|
|
147802
|
+
return Object.keys(nextOptions).length > 0 ? nextOptions : void 0;
|
|
147803
|
+
}
|
|
147804
|
+
function normalizeModelSlug(model, provider = "codex") {
|
|
147805
|
+
if (typeof model !== "string") return null;
|
|
147806
|
+
const trimmed = model.trim();
|
|
147807
|
+
if (!trimmed) return null;
|
|
147808
|
+
const aliases = MODEL_SLUG_ALIASES_BY_PROVIDER[provider];
|
|
147809
|
+
const aliased = Object.prototype.hasOwnProperty.call(aliases, trimmed) ? aliases[trimmed] : void 0;
|
|
147810
|
+
return typeof aliased === "string" ? aliased : trimmed;
|
|
147811
|
+
}
|
|
147812
|
+
/** Trim a string, returning null for empty/missing values. */
|
|
147813
|
+
function trimOrNull(value) {
|
|
147814
|
+
if (typeof value !== "string") return null;
|
|
147815
|
+
return value.trim() || null;
|
|
147816
|
+
}
|
|
147817
|
+
/**
|
|
147818
|
+
* Resolve the actual API model identifier from a model selection.
|
|
147819
|
+
*
|
|
147820
|
+
* Provider-aware: each provider can map `contextWindow` (or other options)
|
|
147821
|
+
* to whatever the API requires — a model-id suffix, a separate parameter, etc.
|
|
147822
|
+
* The canonical slug stored in the selection stays unchanged so the
|
|
147823
|
+
* capabilities system keeps working.
|
|
147824
|
+
*
|
|
147825
|
+
* Expects `contextWindow` to already be resolved (via `resolveContextWindow`)
|
|
147826
|
+
* to the effective value, not stripped to `undefined` for defaults.
|
|
147827
|
+
*/
|
|
147828
|
+
function resolveApiModelId(modelSelection) {
|
|
147829
|
+
switch (modelSelection.provider) {
|
|
147830
|
+
case "claudeAgent": switch (modelSelection.options?.contextWindow) {
|
|
147831
|
+
case "1m": return `${modelSelection.model}[1m]`;
|
|
147832
|
+
default: return modelSelection.model;
|
|
147833
|
+
}
|
|
147834
|
+
default: return modelSelection.model;
|
|
147835
|
+
}
|
|
147836
|
+
}
|
|
147837
|
+
function applyClaudePromptEffortPrefix(text, effort) {
|
|
147838
|
+
const trimmed = text.trim();
|
|
147839
|
+
if (!trimmed) return trimmed;
|
|
147840
|
+
if (effort !== "ultrathink") return trimmed;
|
|
147841
|
+
if (trimmed.startsWith("Ultrathink:")) return trimmed;
|
|
147842
|
+
return `Ultrathink:\n${trimmed}`;
|
|
147843
|
+
}
|
|
147844
|
+
function getRawProviderOptionSelectionValue(selections, id) {
|
|
147845
|
+
return selections?.find((candidate) => candidate.id === id)?.value;
|
|
147846
|
+
}
|
|
147847
|
+
function getProviderOptionSelectionValue(selections, id) {
|
|
147848
|
+
return getRawProviderOptionSelectionValue(selections, id);
|
|
147849
|
+
}
|
|
147850
|
+
function getProviderOptionStringSelectionValue(selections, id) {
|
|
147851
|
+
const value = getProviderOptionSelectionValue(selections, id);
|
|
147852
|
+
return typeof value === "string" ? value : void 0;
|
|
147853
|
+
}
|
|
147854
|
+
function flatProviderOptions(selection) {
|
|
147855
|
+
if (!selection) return void 0;
|
|
147856
|
+
if (selection.provider !== "cursor" && selection.provider !== "opencode") return void 0;
|
|
147857
|
+
return selection.options;
|
|
147858
|
+
}
|
|
147859
|
+
function getModelSelectionStringOptionValue(selection, id) {
|
|
147860
|
+
return getProviderOptionStringSelectionValue(flatProviderOptions(selection), id);
|
|
147861
|
+
}
|
|
147862
|
+
function acceptableModelSlug(value) {
|
|
147863
|
+
const trimmed = value?.trim();
|
|
147864
|
+
if (!trimmed || trimmed.length > 120) return;
|
|
147865
|
+
return trimmed;
|
|
147866
|
+
}
|
|
147867
|
+
/**
|
|
147868
|
+
* Order the credential's model scope: selected model first, then the catalog,
|
|
147869
|
+
* deduplicated and capped.
|
|
147870
|
+
*
|
|
147871
|
+
* Returns `undefined` when there is no catalog to widen to, which is the signal
|
|
147872
|
+
* to send the old single-model body. A slug CMMD would refuse is dropped rather
|
|
147873
|
+
* than sent, because one bad entry 400s the whole mint and takes the session
|
|
147874
|
+
* with it.
|
|
147875
|
+
*/
|
|
147876
|
+
function providerEgressModelScope(model, models) {
|
|
147877
|
+
const catalog = (models ?? []).map(acceptableModelSlug).filter((slug) => slug !== void 0);
|
|
147878
|
+
if (catalog.length === 0) return;
|
|
147879
|
+
const selected = acceptableModelSlug(model);
|
|
147880
|
+
const ordered = new Set(selected ? [selected] : []);
|
|
147881
|
+
for (const slug of catalog) {
|
|
147882
|
+
if (ordered.size >= 32) break;
|
|
147883
|
+
ordered.add(slug);
|
|
147884
|
+
}
|
|
147885
|
+
return [...ordered];
|
|
147886
|
+
}
|
|
147887
|
+
//#endregion
|
|
147888
|
+
//#region src/provider/codexCredentialModelScope.ts
|
|
147889
|
+
/**
|
|
147890
|
+
* Which Codex models one workspace egress credential has to cover.
|
|
147891
|
+
*
|
|
147892
|
+
* FOR-36501: the credential was scoped to the model the user picked, and the
|
|
147893
|
+
* Codex app-server holds one credential for the whole process. A turn on
|
|
147894
|
+
* gpt-6-astra that called `spawn_agent` with gpt-5.6-terra therefore lost the
|
|
147895
|
+
* child to a 401 before it spent a token. The subagent model is the model's own
|
|
147896
|
+
* choice in the tool arguments, so Forge cannot predict it and has to scope the
|
|
147897
|
+
* credential to the catalog a spawn can pick from.
|
|
147898
|
+
*
|
|
147899
|
+
* The catalog is the built-in Codex list, which is what the picker offers. It
|
|
147900
|
+
* includes the Spark model even though only a Pro account may call it: the
|
|
147901
|
+
* account snapshot is not resolved at issue time in workspace mode, and CMMD
|
|
147902
|
+
* still decides per call which models the account may use, so a slug in the
|
|
147903
|
+
* scope is permission to ask, never permission to spend.
|
|
147904
|
+
*/
|
|
147905
|
+
/**
|
|
147906
|
+
* Normalize a Codex model slug to the one the app-server and the mint route use.
|
|
147907
|
+
*
|
|
147908
|
+
* Lives here rather than in codexAppServerManager.ts so the catalog builder can
|
|
147909
|
+
* use it without importing the manager back. The manager re-exports it, which is
|
|
147910
|
+
* where every existing caller still reads it from.
|
|
147911
|
+
*/
|
|
147912
|
+
function normalizeCodexModelSlug(model, preferredId) {
|
|
147913
|
+
const normalized = normalizeModelSlug(model);
|
|
147914
|
+
if (!normalized) return;
|
|
147915
|
+
if (preferredId?.endsWith("-codex") && preferredId !== normalized) return preferredId;
|
|
147916
|
+
return normalized;
|
|
147917
|
+
}
|
|
147918
|
+
/** The model a proxy token is minted for when the thread names none. */
|
|
147919
|
+
function resolveCodexProviderProxyTokenModel(model) {
|
|
147920
|
+
const displaySlug = model?.trim().toLowerCase().replace(/\s+/g, "-");
|
|
147921
|
+
return normalizeCodexModelSlug(displaySlug) ?? "gpt-6-astra";
|
|
147922
|
+
}
|
|
147923
|
+
/** Every built-in Codex slug a `spawn_agent` call can name. */
|
|
147924
|
+
function codexCredentialModelCatalog() {
|
|
147925
|
+
return CODEX_BUILT_IN_MODELS.map((model) => normalizeCodexModelSlug(model.slug) ?? model.slug);
|
|
147926
|
+
}
|
|
147927
|
+
/**
|
|
147928
|
+
* The `models` list to mint a Codex session credential with.
|
|
147929
|
+
*
|
|
147930
|
+
* `undefined` means the catalog is unknown, and the caller then sends `model`
|
|
147931
|
+
* alone, exactly as before this card. That is the only safe answer: an empty
|
|
147932
|
+
* list would narrow the credential rather than widen it.
|
|
147933
|
+
*/
|
|
147934
|
+
function buildCodexCredentialModelScope(input) {
|
|
147935
|
+
const catalog = (input.catalogModels ?? codexCredentialModelCatalog()).map((slug) => normalizeCodexModelSlug(slug) ?? slug).filter((slug) => slug.trim().length > 0);
|
|
147936
|
+
return providerEgressModelScope(input.selectedModel, catalog);
|
|
147937
|
+
}
|
|
147938
|
+
//#endregion
|
|
147672
147939
|
//#region src/egress/providerDeliveryReceipt.ts
|
|
147673
147940
|
const PROVIDER_ACCOUNT_IDENTITY$2 = /^pai_v1_[A-Za-z0-9_-]{43}$/;
|
|
147674
147941
|
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
@@ -147920,6 +148187,21 @@ function runtimeProviderEgressBaseUrl(provider, controlPlaneUrl) {
|
|
|
147920
148187
|
anthropic: "/api/provider-egress/anthropic"
|
|
147921
148188
|
}[provider]}`;
|
|
147922
148189
|
}
|
|
148190
|
+
/**
|
|
148191
|
+
* The model fields of a mint body.
|
|
148192
|
+
*
|
|
148193
|
+
* `model` stays the single selected model, which is what CMMD runs its
|
|
148194
|
+
* post-mint constraint check on. `models` appears only when the caller knows a
|
|
148195
|
+
* catalog, so a caller that does not know one sends exactly the body it sent
|
|
148196
|
+
* before FOR-36501.
|
|
148197
|
+
*/
|
|
148198
|
+
function providerEgressModelBodyFields(input) {
|
|
148199
|
+
const scope = providerEgressModelScope(input.model, input.models);
|
|
148200
|
+
return {
|
|
148201
|
+
...input.model ? { model: input.model } : {},
|
|
148202
|
+
...scope ? { models: scope } : {}
|
|
148203
|
+
};
|
|
148204
|
+
}
|
|
147923
148205
|
const issueProviderEgressToken = (input) => issueProviderEgressCredential(input).pipe(map$3((credential) => credential.token));
|
|
147924
148206
|
const issueProviderEgressCredential = (input) => tryPromise({
|
|
147925
148207
|
try: async () => {
|
|
@@ -147943,7 +148225,7 @@ async function issueCmmdRuntimeProviderEgressCredential(input) {
|
|
|
147943
148225
|
token: runtimeGrantToken,
|
|
147944
148226
|
body: JSON.stringify({
|
|
147945
148227
|
provider: input.provider,
|
|
147946
|
-
...input
|
|
148228
|
+
...providerEgressModelBodyFields(input),
|
|
147947
148229
|
...input.provider === "openai" && input.providerAccountId ? { provider_account_id: input.providerAccountId } : {}
|
|
147948
148230
|
})
|
|
147949
148231
|
});
|
|
@@ -148059,7 +148341,7 @@ function issueCmmdLocalUserProviderEgressCredential(input) {
|
|
|
148059
148341
|
},
|
|
148060
148342
|
body: JSON.stringify({
|
|
148061
148343
|
provider: input.provider,
|
|
148062
|
-
...input
|
|
148344
|
+
...providerEgressModelBodyFields(input),
|
|
148063
148345
|
...input.provider === "openai" && input.providerAccountId ? { provider_account_id: input.providerAccountId } : {},
|
|
148064
148346
|
client: "local-desktop",
|
|
148065
148347
|
sessionId,
|
|
@@ -148442,16 +148724,6 @@ function mapCodexRuntimeMode(runtimeMode) {
|
|
|
148442
148724
|
async function killChildTree(child) {
|
|
148443
148725
|
await killCodexChildProcess(child);
|
|
148444
148726
|
}
|
|
148445
|
-
function normalizeCodexModelSlug(model, preferredId) {
|
|
148446
|
-
const normalized = normalizeModelSlug(model);
|
|
148447
|
-
if (!normalized) return;
|
|
148448
|
-
if (preferredId?.endsWith("-codex") && preferredId !== normalized) return preferredId;
|
|
148449
|
-
return normalized;
|
|
148450
|
-
}
|
|
148451
|
-
function resolveCodexProviderProxyTokenModel(model) {
|
|
148452
|
-
const displaySlug = model?.trim().toLowerCase().replace(/\s+/g, "-");
|
|
148453
|
-
return normalizeCodexModelSlug(displaySlug) ?? "gpt-6-astra";
|
|
148454
|
-
}
|
|
148455
148727
|
function buildCodexCollaborationMode(input) {
|
|
148456
148728
|
if (input.interactionMode === void 0) return;
|
|
148457
148729
|
const model = normalizeCodexModelSlug(input.model) ?? "gpt-6-astra";
|
|
@@ -149002,9 +149274,11 @@ var CodexAppServerManager = class extends EventEmitter$1 {
|
|
|
149002
149274
|
const proxyConfig = getOpenAiProviderEgressProxyConfig({ allowLocalUser: true });
|
|
149003
149275
|
if (proxyConfig.mode === "disabled") return null;
|
|
149004
149276
|
if (proxyConfig.mode === "misconfigured") throw new ProviderEgressTokenError({ message: proxyConfig.message });
|
|
149277
|
+
const models = buildCodexCredentialModelScope({ selectedModel: input.model });
|
|
149005
149278
|
return await runPromise(issueProviderEgressCredential({
|
|
149006
149279
|
provider: "openai",
|
|
149007
149280
|
model: input.model,
|
|
149281
|
+
...models ? { models } : {},
|
|
149008
149282
|
threadId: input.threadId,
|
|
149009
149283
|
...input.providerAccountId ? { providerAccountId: input.providerAccountId } : {}
|
|
149010
149284
|
}));
|
|
@@ -149397,13 +149671,40 @@ var CodexAppServerManager = class extends EventEmitter$1 {
|
|
|
149397
149671
|
if (!providerConversationId) return;
|
|
149398
149672
|
return context.collabReceiverTurns.get(providerConversationId);
|
|
149399
149673
|
}
|
|
149674
|
+
/**
|
|
149675
|
+
* The child threads one thread item says the turn spawned.
|
|
149676
|
+
*
|
|
149677
|
+
* Two item shapes name a child, and which one arrives depends on the Codex
|
|
149678
|
+
* build. `CollabAgentToolCallThreadItem` lists `receiverThreadIds`, which
|
|
149679
|
+
* "in case of spawn operation ... corresponds to the newly spawned agent".
|
|
149680
|
+
* `SubAgentActivityThreadItem` names a single `agentThreadId` and is what a
|
|
149681
|
+
* `spawn_agent` call reports on codex-cli 0.152/0.153: measured on the
|
|
149682
|
+
* packaged desktop on 2026-09-06, the spawn arrived as `SubAgentActivity`
|
|
149683
|
+
* (`kind: started`) and the only collab tool call that followed was the
|
|
149684
|
+
* `wait`, whose `receiverThreadIds` was empty. Reading only the collab item
|
|
149685
|
+
* left the child unmapped, so its spend was published as a second turn row
|
|
149686
|
+
* under the child's own turn id instead of a subagent row under the parent's.
|
|
149687
|
+
*
|
|
149688
|
+
* `SubAgentActivityThreadItem` has no `model` field, so a `completed` report
|
|
149689
|
+
* for a child a collab call already named must not blank the model out; the
|
|
149690
|
+
* caller's `model ?? known` merge is what keeps it.
|
|
149691
|
+
*/
|
|
149692
|
+
readSpawnedThreadIds(item, itemType) {
|
|
149693
|
+
if (itemType === "subAgentActivity") {
|
|
149694
|
+
const agentThreadId = this.readString(item, "agentThreadId");
|
|
149695
|
+
return agentThreadId ? [agentThreadId] : [];
|
|
149696
|
+
}
|
|
149697
|
+
if (itemType !== "collabAgentToolCall") return [];
|
|
149698
|
+
return this.readArray(item, "receiverThreadIds")?.map((value) => typeof value === "string" ? value : null).filter((value) => value !== null) ?? [];
|
|
149699
|
+
}
|
|
149400
149700
|
rememberCollabReceiverTurns(context, params, parentTurnId) {
|
|
149401
149701
|
if (!parentTurnId) return;
|
|
149402
149702
|
const payload = this.readObject(params);
|
|
149403
149703
|
const item = this.readObject(payload, "item") ?? payload;
|
|
149404
|
-
|
|
149704
|
+
const itemType = this.readString(item, "type") ?? this.readString(item, "kind");
|
|
149705
|
+
const receiverThreadIds = this.readSpawnedThreadIds(item, itemType);
|
|
149706
|
+
if (receiverThreadIds.length === 0) return;
|
|
149405
149707
|
const model = this.readString(item, "model");
|
|
149406
|
-
const receiverThreadIds = this.readArray(item, "receiverThreadIds")?.map((value) => typeof value === "string" ? value : null).filter((value) => value !== null) ?? [];
|
|
149407
149708
|
for (const receiverThreadId of receiverThreadIds) {
|
|
149408
149709
|
const known = context.collabReceiverTurns.get(receiverThreadId)?.model;
|
|
149409
149710
|
const resolved = model ?? known;
|
|
@@ -149419,8 +149720,8 @@ var CodexAppServerManager = class extends EventEmitter$1 {
|
|
|
149419
149720
|
* Codex reports a child thread's tokens on the parent's own connection:
|
|
149420
149721
|
* `ThreadTokenUsageUpdatedNotification` requires `threadId` and `turnId` and
|
|
149421
149722
|
* names the child thread for a child, and `Thread.parentThreadId` is "only
|
|
149422
|
-
* set if this thread is a subagent" (codex 0.
|
|
149423
|
-
* schema). Every other child notification is suppressed so it cannot replace
|
|
149723
|
+
* set if this thread is a subagent" (still true of the codex-cli 0.153
|
|
149724
|
+
* app-server protocol schema). Every other child notification is suppressed so it cannot replace
|
|
149424
149725
|
* the parent turn; this one is not, because the tokens belong on the ledger.
|
|
149425
149726
|
* The method is Forge's own rather than the protocol's, because the payload
|
|
149426
149727
|
* carries what the Usage row needs rather than what the notification held.
|
|
@@ -207164,36 +207465,23 @@ function mapCodexThreadNameUpdatedEvent(event, canonicalThreadId, payload) {
|
|
|
207164
207465
|
}
|
|
207165
207466
|
}];
|
|
207166
207467
|
}
|
|
207167
|
-
/** One provider call's spend, from Codex's `last_token_usage`. */
|
|
207168
|
-
function codexTurnUsageDelta(value) {
|
|
207169
|
-
const usage = asObject$2(value);
|
|
207170
|
-
return codexUsageBuckets(usage?.last_token_usage ?? usage?.last, "call-delta");
|
|
207171
|
-
}
|
|
207172
207468
|
/**
|
|
207173
|
-
* One
|
|
207174
|
-
*
|
|
207175
|
-
*
|
|
207176
|
-
*
|
|
207469
|
+
* One provider call's spend, from Codex's `last_token_usage`. Reads the
|
|
207470
|
+
* buckets via `codexTokenBuckets`, the shared home of the Claude/Codex
|
|
207471
|
+
* disjointness rule (providerTokenBuckets.ts): Codex reports `input_tokens`
|
|
207472
|
+
* inclusive of the cached and cache-write portions, so the uncached bucket is
|
|
207473
|
+
* the remainder, and reasoning is reported inside output and surfaced
|
|
207474
|
+
* separately without being added again. Mirrors `parseCodexLine` in
|
|
207177
207475
|
* usage/usageTranscripts.ts so a Recorded turn and a scanned transcript agree
|
|
207178
207476
|
* on the same numbers.
|
|
207179
207477
|
*/
|
|
207180
|
-
function
|
|
207181
|
-
const
|
|
207182
|
-
|
|
207183
|
-
|
|
207184
|
-
|
|
207185
|
-
|
|
207186
|
-
|
|
207187
|
-
const outputTokens = int("output_tokens", "outputTokens");
|
|
207188
|
-
if (inputTokens + cachedInputTokens + cacheCreationTokens + outputTokens === 0) return void 0;
|
|
207189
|
-
return {
|
|
207190
|
-
scope,
|
|
207191
|
-
uncachedInputTokens: Math.max(0, inputTokens - cachedInputTokens - cacheCreationTokens),
|
|
207192
|
-
cachedInputTokens,
|
|
207193
|
-
cacheCreationTokens,
|
|
207194
|
-
outputTokens,
|
|
207195
|
-
reasoningTokens: Math.min(outputTokens, int("reasoning_output_tokens", "reasoningOutputTokens"))
|
|
207196
|
-
};
|
|
207478
|
+
function codexTurnUsageDelta(value) {
|
|
207479
|
+
const usage = asObject$2(value);
|
|
207480
|
+
const buckets = codexTokenBuckets(usage?.last_token_usage ?? usage?.last);
|
|
207481
|
+
return buckets ? {
|
|
207482
|
+
scope: "call-delta",
|
|
207483
|
+
...buckets
|
|
207484
|
+
} : void 0;
|
|
207197
207485
|
}
|
|
207198
207486
|
function mapCodexThreadTokenUsageEvent(event, canonicalThreadId, payload) {
|
|
207199
207487
|
const tokenUsage = asObject$2(payload?.tokenUsage);
|
|
@@ -207216,11 +207504,14 @@ function mapCodexThreadTokenUsageEvent(event, canonicalThreadId, payload) {
|
|
|
207216
207504
|
*
|
|
207217
207505
|
* The source is the live app-server protocol, not a rollout read: Codex sends
|
|
207218
207506
|
* `thread/tokenUsage/updated` for a child thread on the parent's own
|
|
207219
|
-
* connection (
|
|
207220
|
-
* `
|
|
207221
|
-
*
|
|
207222
|
-
*
|
|
207223
|
-
*
|
|
207507
|
+
* connection (`ThreadTokenUsageUpdatedNotification` requires `threadId` and
|
|
207508
|
+
* `turnId`, and `Thread.parentThreadId` is set only for a subagent), and
|
|
207509
|
+
* `codexAppServerManager` already tracked those child threads to route their
|
|
207510
|
+
* notifications onto the parent turn. It learns a child from whichever item
|
|
207511
|
+
* the running Codex build uses to announce a spawn: the
|
|
207512
|
+
* `receiverThreadIds` of a `CollabAgentToolCallThreadItem`, which also names
|
|
207513
|
+
* the spawned agent's `model`, or the `agentThreadId` of a
|
|
207514
|
+
* `SubAgentActivityThreadItem`, which names no model.
|
|
207224
207515
|
*
|
|
207225
207516
|
* The row carries no context-meter snapshot and no `turnUsage`: the parent's
|
|
207226
207517
|
* own row is never re-summed with its children. It carries the call's delta
|
|
@@ -207882,6 +208173,7 @@ const DEFAULT_PUBLIC_PROVIDER_ERROR = "CMMD is temporarily unavailable. Check th
|
|
|
207882
208173
|
function categorizePublicProviderError(message) {
|
|
207883
208174
|
if (!message) return null;
|
|
207884
208175
|
const m = message.toLowerCase();
|
|
208176
|
+
if (/\bforge_provider_model_not_allowed\b/.test(m) || /\bnot\s+scoped\s+to\s+the\s+requested\s+model\b/.test(m)) return "The workspace AI credential does not cover the model this turn asked for. Retry, or pick that model for the thread.";
|
|
207885
208177
|
if (/\bmodel\b[\s\S]*\b(not\s+(found|available|supported)|does\s+not\s+exist|unsupported|invalid|unknown)\b/.test(m) || /\b(unsupported|unknown|invalid)\b[\s\S]*\bmodel\b/.test(m) || /\b(model_not_found|invalid_model|model_not_supported)\b/.test(m)) return "The selected model isn't available right now. Pick a different model and retry.";
|
|
207886
208178
|
if (/\b(rate[\s-]?limit|too\s+many\s+requests|quota|insufficient_quota)\b/.test(m) || /\b429\b/.test(m)) return "The AI service is rate-limited or out of quota. Wait a moment and retry.";
|
|
207887
208179
|
if (/\b(unauthorized|forbidden|authentication\s+(failed|error|required)|invalid\s+api\s+key|expired\s+(token|credential))\b/.test(m) || /\b40[13]\b/.test(m)) return "Workspace AI authentication failed. Reconnect the workspace and retry.";
|
|
@@ -208102,7 +208394,8 @@ const CODE_BY_UPSTREAM_REASON$1 = {
|
|
|
208102
208394
|
credential_expired_refreshing: "CREDENTIAL_EXPIRED_REFRESHING",
|
|
208103
208395
|
credential_reconnect_required: "CREDENTIAL_RECONNECT_REQUIRED",
|
|
208104
208396
|
credential_not_connected: "CREDENTIAL_RECONNECT_REQUIRED",
|
|
208105
|
-
credential_generation_not_applied: "CREDENTIAL_GENERATION_NOT_APPLIED"
|
|
208397
|
+
credential_generation_not_applied: "CREDENTIAL_GENERATION_NOT_APPLIED",
|
|
208398
|
+
runtime_unavailable: "RUNTIME_UNAVAILABLE"
|
|
208106
208399
|
};
|
|
208107
208400
|
const CLAUDE_NATIVE_CREDENTIAL_UNUSABLE_COPY = "The delivered Claude credential is unavailable or unusable in this runtime.";
|
|
208108
208401
|
/**
|
|
@@ -208165,10 +208458,17 @@ function claudeNativeCredentialUnusableMessage() {
|
|
|
208165
208458
|
* CMMD writes this marker when it activates a personal Claude subscription
|
|
208166
208459
|
* inside a running sprite. Activation always happens after boot, so a
|
|
208167
208460
|
* boot-time env var alone cannot reflect it (FOR-36249).
|
|
208461
|
+
*
|
|
208462
|
+
* CMMD names the file in the Service env (FORGE_PERSONAL_CLAUDE_MARKER_PATH).
|
|
208463
|
+
* Without that, the marker sits directly under FORGE_HOME, which is the same
|
|
208464
|
+
* guest home CMMD derives every sprite path from. A server with neither has no
|
|
208465
|
+
* sprite home to look in, and a desktop never has a marker, so it reads none.
|
|
208168
208466
|
*/
|
|
208169
|
-
const
|
|
208467
|
+
const PERSONAL_CLAUDE_IN_VM_MARKER_NAME = ".forge-personal-claude-in-vm";
|
|
208170
208468
|
function markerPath(env) {
|
|
208171
|
-
|
|
208469
|
+
if (env.FORGE_PERSONAL_CLAUDE_MARKER_PATH) return env.FORGE_PERSONAL_CLAUDE_MARKER_PATH;
|
|
208470
|
+
if (env.FORGE_HOME) return join(env.FORGE_HOME, PERSONAL_CLAUDE_IN_VM_MARKER_NAME);
|
|
208471
|
+
return null;
|
|
208172
208472
|
}
|
|
208173
208473
|
/**
|
|
208174
208474
|
* True when this runtime should offer the personal Claude subscription lane.
|
|
@@ -208181,8 +208481,10 @@ function markerPath(env) {
|
|
|
208181
208481
|
*/
|
|
208182
208482
|
function personalClaudeInVmEnabled(env = process.env) {
|
|
208183
208483
|
if (env.FORGE_PERSONAL_CLAUDE_IN_VM === "true") return true;
|
|
208484
|
+
const marker = markerPath(env);
|
|
208485
|
+
if (!marker) return false;
|
|
208184
208486
|
try {
|
|
208185
|
-
return existsSync(
|
|
208487
|
+
return existsSync(marker);
|
|
208186
208488
|
} catch {
|
|
208187
208489
|
return false;
|
|
208188
208490
|
}
|
|
@@ -209720,9 +210022,6 @@ function buildClaudeSessionContext(input) {
|
|
|
209720
210022
|
query: input.queryRuntime,
|
|
209721
210023
|
streamFiber: void 0,
|
|
209722
210024
|
startedAt: input.startedAt,
|
|
209723
|
-
recordsPersonalUsageTelemetry: input.recordsPersonalUsageTelemetry,
|
|
209724
|
-
personalUsageGenerationHash: input.personalUsageGenerationHash,
|
|
209725
|
-
personalUsageProviderAccountId: input.personalUsageProviderAccountId,
|
|
209726
210025
|
basePermissionMode: input.permissionMode,
|
|
209727
210026
|
resumeSessionId: input.sessionId,
|
|
209728
210027
|
pendingApprovals: input.pendingApprovals,
|
|
@@ -210080,26 +210379,18 @@ function finiteNumberFieldOrZero(usage, key) {
|
|
|
210080
210379
|
}
|
|
210081
210380
|
/**
|
|
210082
210381
|
* The whole turn's spend from the SDK result message, cache split intact.
|
|
210083
|
-
*
|
|
210084
|
-
*
|
|
210085
|
-
*
|
|
210382
|
+
* Reads the buckets via `claudeTokenBuckets`, the shared home of the
|
|
210383
|
+
* Claude/Codex disjointness rule (providerTokenBuckets.ts): Claude reports
|
|
210384
|
+
* `input_tokens` exclusive of the cached and cache-creation portions, so the
|
|
210385
|
+
* buckets are already disjoint, and Claude does not report reasoning
|
|
210386
|
+
* separately.
|
|
210086
210387
|
*/
|
|
210087
210388
|
function claudeTurnUsageTotal(value) {
|
|
210088
|
-
const
|
|
210089
|
-
|
|
210090
|
-
const uncachedInputTokens = finiteNumberFieldOrZero(usage, "input_tokens");
|
|
210091
|
-
const cachedInputTokens = finiteNumberFieldOrZero(usage, "cache_read_input_tokens");
|
|
210092
|
-
const cacheCreationTokens = finiteNumberFieldOrZero(usage, "cache_creation_input_tokens");
|
|
210093
|
-
const outputTokens = finiteNumberFieldOrZero(usage, "output_tokens");
|
|
210094
|
-
if (uncachedInputTokens + cachedInputTokens + cacheCreationTokens + outputTokens <= 0) return;
|
|
210095
|
-
return {
|
|
210389
|
+
const buckets = claudeTokenBuckets(value);
|
|
210390
|
+
return buckets ? {
|
|
210096
210391
|
scope: "turn-total",
|
|
210097
|
-
|
|
210098
|
-
|
|
210099
|
-
cacheCreationTokens: Math.trunc(cacheCreationTokens),
|
|
210100
|
-
outputTokens: Math.trunc(outputTokens),
|
|
210101
|
-
reasoningTokens: 0
|
|
210102
|
-
};
|
|
210392
|
+
...buckets
|
|
210393
|
+
} : void 0;
|
|
210103
210394
|
}
|
|
210104
210395
|
const EMPTY_MODEL_USAGE_BUCKETS = {
|
|
210105
210396
|
uncachedInputTokens: 0,
|
|
@@ -210112,20 +210403,14 @@ function bucketsTotal(buckets) {
|
|
|
210112
210403
|
return buckets.uncachedInputTokens + buckets.cachedInputTokens + buckets.cacheCreationTokens + buckets.outputTokens;
|
|
210113
210404
|
}
|
|
210114
210405
|
/**
|
|
210115
|
-
* One `ModelUsage` entry as buckets
|
|
210116
|
-
* camelCase, unlike `result.usage`,
|
|
210117
|
-
* Claude reports `inputTokens` exclusive of the
|
|
210118
|
-
* portions, so the buckets are already disjoint, and
|
|
210406
|
+
* One `ModelUsage` entry as buckets, via `claudeTokenBuckets`. `ModelUsage`
|
|
210407
|
+
* names its fields in camelCase, unlike `result.usage`, but `claudeTokenBuckets`
|
|
210408
|
+
* already reads both spellings. Claude reports `inputTokens` exclusive of the
|
|
210409
|
+
* cached and cache-creation portions, so the buckets are already disjoint, and
|
|
210410
|
+
* it reports no reasoning.
|
|
210119
210411
|
*/
|
|
210120
210412
|
function claudeModelUsageBuckets(usage) {
|
|
210121
|
-
|
|
210122
|
-
return {
|
|
210123
|
-
uncachedInputTokens: Math.trunc(finiteNumberFieldOrZero(record, "inputTokens")),
|
|
210124
|
-
cachedInputTokens: Math.trunc(finiteNumberFieldOrZero(record, "cacheReadInputTokens")),
|
|
210125
|
-
cacheCreationTokens: Math.trunc(finiteNumberFieldOrZero(record, "cacheCreationInputTokens")),
|
|
210126
|
-
outputTokens: Math.trunc(finiteNumberFieldOrZero(record, "outputTokens")),
|
|
210127
|
-
reasoningTokens: 0
|
|
210128
|
-
};
|
|
210413
|
+
return claudeTokenBuckets(usage) ?? EMPTY_MODEL_USAGE_BUCKETS;
|
|
210129
210414
|
}
|
|
210130
210415
|
/**
|
|
210131
210416
|
* What each model spent during THIS turn, from the SDK's per-model totals.
|
|
@@ -211468,7 +211753,6 @@ const makeClaudeAdapter = fn$1("makeClaudeAdapter")(function* (options) {
|
|
|
211468
211753
|
return;
|
|
211469
211754
|
}
|
|
211470
211755
|
if (message.type === "rate_limit_event") {
|
|
211471
|
-
if (context.recordsPersonalUsageTelemetry) recordClaudeRateLimitTelemetry(message.rate_limit_info, context.personalUsageGenerationHash, context.personalUsageProviderAccountId);
|
|
211472
211756
|
yield* offerRuntimeEvent({
|
|
211473
211757
|
...base,
|
|
211474
211758
|
type: "account.rate-limits.updated",
|
|
@@ -211966,10 +212250,7 @@ const makeClaudeAdapter = fn$1("makeClaudeAdapter")(function* (options) {
|
|
|
211966
212250
|
inFlightTools,
|
|
211967
212251
|
resumeSessionAt: resumeState?.resumeSessionAt,
|
|
211968
212252
|
effectiveApiModelId: modelConfig.effectiveApiModelId,
|
|
211969
|
-
effectiveEffort: modelConfig.effectiveEffort
|
|
211970
|
-
recordsPersonalUsageTelemetry: sessionProvider === PROVIDER$11 && modelConfig.endpointProfile === void 0 && providerProxyCredential === null && !claudeSettings.anthropicBaseUrl && !claudeSettings.anthropicApiKey,
|
|
211971
|
-
personalUsageGenerationHash: currentClaudeUsageGenerationHash(),
|
|
211972
|
-
personalUsageProviderAccountId: modelConfig.modelSelection?.provider === "claudeAgent" ? modelConfig.modelSelection.providerAccountId : void 0
|
|
212253
|
+
effectiveEffort: modelConfig.effectiveEffort
|
|
211973
212254
|
});
|
|
211974
212255
|
yield* set$2(contextRef, context$4);
|
|
211975
212256
|
sessions.set(threadId, context$4);
|
|
@@ -226762,7 +227043,8 @@ const CLAUDE_READINESS_COPY = {
|
|
|
226762
227043
|
failed: "Claude native runtime setup could not be applied. Reconnect Claude in Settings.",
|
|
226763
227044
|
invalid: "Claude native runtime readiness is no longer valid. Reconnect Claude in Settings.",
|
|
226764
227045
|
unavailable: "Claude native runtime readiness could not be verified.",
|
|
226765
|
-
generationMismatch: "Claude native runtime generation does not match CMMD readiness."
|
|
227046
|
+
generationMismatch: "Claude native runtime generation does not match CMMD readiness.",
|
|
227047
|
+
environmentUnavailable: "This Environment is not running, so Claude cannot run on it. Restart the Environment, then try again."
|
|
226766
227048
|
};
|
|
226767
227049
|
var ClaudeRuntimeReadinessError = class extends Error {
|
|
226768
227050
|
constructor(safeIssue, retryable = false, retryProfile = "default") {
|
|
@@ -226832,6 +227114,7 @@ async function withReadinessRetry(attempt) {
|
|
|
226832
227114
|
*/
|
|
226833
227115
|
function readinessReasonIssue(readiness) {
|
|
226834
227116
|
const code = claudeReadinessReasonCode(readiness.reason);
|
|
227117
|
+
if (code === "RUNTIME_UNAVAILABLE") return CLAUDE_READINESS_COPY.environmentUnavailable;
|
|
226835
227118
|
if (code === "CREDENTIAL_RECONNECT_REQUIRED") return CLAUDE_READINESS_COPY.invalid;
|
|
226836
227119
|
if (code === "CREDENTIAL_GENERATION_NOT_APPLIED") return CLAUDE_READINESS_COPY.applying;
|
|
226837
227120
|
if (code !== "CREDENTIAL_EXPIRED_REFRESHING") return null;
|
|
@@ -226842,6 +227125,10 @@ function readinessReasonIssue(readiness) {
|
|
|
226842
227125
|
function isCredentialRefreshInFlight(readiness) {
|
|
226843
227126
|
return claudeReadinessReasonCode(readiness.reason) === "CREDENTIAL_EXPIRED_REFRESHING";
|
|
226844
227127
|
}
|
|
227128
|
+
/** True when CMMD says the runtime itself cannot take a delivery (CMMD-36473). */
|
|
227129
|
+
function isRuntimeUnavailable(readiness) {
|
|
227130
|
+
return claudeReadinessReasonCode(readiness.reason) === "RUNTIME_UNAVAILABLE";
|
|
227131
|
+
}
|
|
226845
227132
|
function readinessFailureIssue(readiness) {
|
|
226846
227133
|
const reasonIssue = readinessReasonIssue(readiness);
|
|
226847
227134
|
if (reasonIssue !== null) return reasonIssue;
|
|
@@ -226881,11 +227168,12 @@ function verifiedClaudeDeliveryBinding(readiness, authority) {
|
|
|
226881
227168
|
function appliedClaudeGeneration(readiness) {
|
|
226882
227169
|
if (readiness.connected !== true || readiness.deliveryStatus !== "applied" || readiness.nativeExecutable !== true || typeof readiness.generationId !== "string" || readiness.generationId.trim().length === 0) {
|
|
226883
227170
|
const refreshing = isCredentialRefreshInFlight(readiness);
|
|
226884
|
-
|
|
227171
|
+
const retryable = !isRuntimeUnavailable(readiness) && (refreshing || [
|
|
226885
227172
|
"pending",
|
|
226886
227173
|
"claimed",
|
|
226887
227174
|
"activating"
|
|
226888
|
-
].includes(readiness.deliveryStatus)
|
|
227175
|
+
].includes(readiness.deliveryStatus));
|
|
227176
|
+
throw new ClaudeRuntimeReadinessError(readinessFailureIssue(readiness), retryable, refreshing ? "credentialRefresh" : "default");
|
|
226889
227177
|
}
|
|
226890
227178
|
return readiness.generationId;
|
|
226891
227179
|
}
|
|
@@ -228039,15 +228327,15 @@ const collectOutput = fn$1("collectOutput")(function* (input, stream, maxOutputB
|
|
|
228039
228327
|
/**
|
|
228040
228328
|
* Adds a `safe.directory` exception to a git child environment.
|
|
228041
228329
|
*
|
|
228042
|
-
* Forge runs git against workspaces on a mounted volume (
|
|
228043
|
-
* Fly). A volume mount replaces the build-time ownership of its mountpoint, so a
|
|
228330
|
+
* Forge runs git against workspaces on a mounted volume (`<cloudProjectsRoot>/...`
|
|
228331
|
+
* on Fly). A volume mount replaces the build-time ownership of its mountpoint, so a
|
|
228044
228332
|
* repository there can be owned by a uid other than the server's, and git then
|
|
228045
228333
|
* refuses EVERY command against it with "detected dubious ownership" — the
|
|
228046
228334
|
* FORGE-2T failure in `CheckpointStore.captureCheckpoint`.
|
|
228047
228335
|
*
|
|
228048
228336
|
* The exception has to be `*`, verified against git 2.43:
|
|
228049
228337
|
* - git compares `safe.directory` entries literally, so a prefix such as
|
|
228050
|
-
* `/
|
|
228338
|
+
* `/projects/*` does not match the repository at all.
|
|
228051
228339
|
* - the value must name the DISCOVERED REPOSITORY ROOT, which is an ancestor of
|
|
228052
228340
|
* `cwd` whenever a command runs from a subdirectory. Resolving that root means
|
|
228053
228341
|
* asking git, which is the command being refused.
|
|
@@ -284169,6 +284457,27 @@ const makeRuntimeDrainReporter = gen(function* () {
|
|
|
284169
284457
|
var RuntimeDrainReporter = class extends Service$1()("forge/runtimeDrain/RuntimeDrainReporter") {};
|
|
284170
284458
|
const RuntimeDrainReporterLive = effect(RuntimeDrainReporter, makeRuntimeDrainReporter);
|
|
284171
284459
|
//#endregion
|
|
284460
|
+
//#region src/usage/providerRateLimits.ts
|
|
284461
|
+
/**
|
|
284462
|
+
* The SDK only ever reports ONE window per event. Only `five_hour` and
|
|
284463
|
+
* `seven_day` map to the two windows the Usage page shows; the
|
|
284464
|
+
* per-model/overage variants (seven_day_opus, overage, ...) are ignored here
|
|
284465
|
+
* on purpose rather than silently overwriting the plain 7-day figure.
|
|
284466
|
+
*/
|
|
284467
|
+
function mapClaudeRateLimitInfo(info) {
|
|
284468
|
+
if (typeof info.utilization !== "number" || typeof info.resetsAt !== "number" || !info.status) return null;
|
|
284469
|
+
const kind = info.rateLimitType === "five_hour" ? "fiveHour" : info.rateLimitType === "seven_day" ? "sevenDay" : null;
|
|
284470
|
+
if (!kind) return null;
|
|
284471
|
+
return {
|
|
284472
|
+
kind,
|
|
284473
|
+
window: {
|
|
284474
|
+
usedPercent: Math.round(info.utilization * 100),
|
|
284475
|
+
resetsAt: (/* @__PURE__ */ new Date(info.resetsAt * 1e3)).toISOString(),
|
|
284476
|
+
status: info.status
|
|
284477
|
+
}
|
|
284478
|
+
};
|
|
284479
|
+
}
|
|
284480
|
+
//#endregion
|
|
284172
284481
|
//#region src/orchestration/Layers/ProviderRuntimeIngestion.ts
|
|
284173
284482
|
const providerTurnKey = (threadId, turnId) => `${threadId}:${turnId}`;
|
|
284174
284483
|
const providerCommandId = (event, tag) => CommandId.make(`provider:${event.eventId}:${tag}:${crypto.randomUUID()}`);
|
|
@@ -290891,7 +291200,7 @@ const ServerLoggerLive = gen(function* () {
|
|
|
290891
291200
|
* Observed live on a Forge Cloud sprite (2026-07-25): the browser opens
|
|
290892
291201
|
* `wss://<sprite>.sprites.app/ws?routeKey=…&runtimeTicket=<JWT>`, and the HTTP
|
|
290893
291202
|
* instrumentation records `url.full` / `url.query` verbatim. The ticket then
|
|
290894
|
-
* lands in
|
|
291203
|
+
* lands in `<FORGE_HOME>/userdata/logs/server.trace.ndjson` at mode 644 — readable by
|
|
290895
291204
|
* the same user the agent runs as — and the URL also crosses fly.io's edge,
|
|
290896
291205
|
* where infrastructure we do not control may log it.
|
|
290897
291206
|
*
|
|
@@ -291183,7 +291492,7 @@ function resolveBuildCommitFromEnv(env) {
|
|
|
291183
291492
|
* environment descriptor down instead of reporting an honest "unknown".
|
|
291184
291493
|
*/
|
|
291185
291494
|
function readBakedBuildCommit() {
|
|
291186
|
-
return "
|
|
291495
|
+
return "9e352ae66ea610fd1916726270fce8a1ab138a3b";
|
|
291187
291496
|
}
|
|
291188
291497
|
async function resolveServerBuildCommit(input) {
|
|
291189
291498
|
if (isFullCommitSha(input.baked)) return input.baked;
|
|
@@ -299172,16 +299481,6 @@ function describeDispatchCause(cause) {
|
|
|
299172
299481
|
if (deepest === void 0 || deepest.length <= DISPATCH_CAUSE_DETAIL_LIMIT) return deepest;
|
|
299173
299482
|
return `${deepest.slice(0, DISPATCH_CAUSE_DETAIL_LIMIT)}...`;
|
|
299174
299483
|
}
|
|
299175
|
-
/**
|
|
299176
|
-
* Where automation-created projects live when the caller does not say.
|
|
299177
|
-
*
|
|
299178
|
-
* This is the documented default of the `cloudProjectsRoot` setting
|
|
299179
|
-
* (FORGE_CLOUD_PROJECTS_ROOT, see cli.ts) and exists only for direct callers
|
|
299180
|
-
* such as tests. Every HTTP route passes the CONFIGURED value instead: reading
|
|
299181
|
-
* the default here is what made a runtime configured with any other root create
|
|
299182
|
-
* its automation projects in a directory nothing else read.
|
|
299183
|
-
*/
|
|
299184
|
-
const DEFAULT_CLOUD_PROJECTS_ROOT = "/data/Projects";
|
|
299185
299484
|
const respondToOrchestrationHttpError = (error) => gen(function* () {
|
|
299186
299485
|
if (error._tag === "OrchestrationGetSnapshotError") {
|
|
299187
299486
|
yield* logError("orchestration http route failed", {
|
|
@@ -300376,6 +300675,7 @@ function resolveWsUrl(baseUrl) {
|
|
|
300376
300675
|
const callCmmdTool = legacyCmmdToolBridge.callTool;
|
|
300377
300676
|
const extractMcpToolText = legacyCmmdToolBridge.extractText;
|
|
300378
300677
|
const isCmmdMcpAuthError = legacyCmmdToolBridge.isAuthError;
|
|
300678
|
+
const __cmmdProxyRouteLayersStartIndex = registeredProxyRouteLayers().length;
|
|
300379
300679
|
/**
|
|
300380
300680
|
* CMMD-side path for the PROJECT-keyed Forge Cloud catalog. Shared by the list
|
|
300381
300681
|
* proxy, the SSE poll-and-emit proxy, and the register/unregister proxies so the
|
|
@@ -300385,8 +300685,9 @@ const CMMD_CLOUD_PROJECTS_PATH = "/api/forge/context/cloud-projects";
|
|
|
300385
300685
|
const CMMD_RUNTIMES_PATH = "/api/forge/context/runtimes";
|
|
300386
300686
|
/**
|
|
300387
300687
|
* Authenticate the browser session and resolve the CMMD JWT to forward
|
|
300388
|
-
* upstream.
|
|
300389
|
-
* turns into
|
|
300688
|
+
* upstream. `jwt` is null when none could be resolved, which every caller
|
|
300689
|
+
* turns into `respondCmmdConnectionRequired(session.sessionId)` — the same
|
|
300690
|
+
* unified `CMMD_AUTH_REQUIRED` body and auth-clear the registry uses.
|
|
300390
300691
|
*
|
|
300391
300692
|
* Shared so the auth preamble is written once rather than once per proxy route.
|
|
300392
300693
|
*/
|
|
@@ -300394,11 +300695,14 @@ function makeCmmdProxyAccessTokenEffect(logPrefix) {
|
|
|
300394
300695
|
return gen(function* () {
|
|
300395
300696
|
const request = yield* HttpServerRequest;
|
|
300396
300697
|
const session = yield* (yield* ServerAuth).authenticateHttpRequest(request);
|
|
300397
|
-
return
|
|
300398
|
-
|
|
300399
|
-
|
|
300400
|
-
|
|
300401
|
-
|
|
300698
|
+
return {
|
|
300699
|
+
session,
|
|
300700
|
+
jwt: yield* resolveCmmdJwtForSession({
|
|
300701
|
+
sessionId: session.sessionId,
|
|
300702
|
+
subject: session.subject,
|
|
300703
|
+
logPrefix
|
|
300704
|
+
})
|
|
300705
|
+
};
|
|
300402
300706
|
});
|
|
300403
300707
|
}
|
|
300404
300708
|
var WorkIntakeSnapshotReadError = class extends TaggedErrorClass()("WorkIntakeSnapshotReadError", {
|
|
@@ -300478,32 +300782,19 @@ const cmmdProfileRouteLayer = add$1("GET", "/api/cmmd/profile", gen(function* ()
|
|
|
300478
300782
|
* `resolution`/`sinceTime`/`untilTime` when the page is drawing hours, which is
|
|
300479
300783
|
* what lets CMMD cut hour buckets rather than only days.
|
|
300480
300784
|
*/
|
|
300481
|
-
|
|
300785
|
+
registerProxyRoute({
|
|
300482
300786
|
forgePath: "/api/cmmd/usage/summary",
|
|
300483
300787
|
method: "GET",
|
|
300484
300788
|
cmmdPath: "/api/forge/context/usage/summary",
|
|
300485
300789
|
orgIdSource: "none"
|
|
300486
300790
|
});
|
|
300487
|
-
|
|
300488
|
-
* The workspace's CMMD plan: entitlements, the current period, and how much of
|
|
300489
|
-
* each metered allowance is left. This is subscription consumption, which is a
|
|
300490
|
-
* different question from the API-equivalent estimate the usage summary above
|
|
300491
|
-
* computes from transcripts.
|
|
300492
|
-
*
|
|
300493
|
-
* `orgIdSource` is `query` (FOR-36406): a plan belongs to an organization, and
|
|
300494
|
-
* without one CMMD answers for the user's default organization, which is their
|
|
300495
|
-
* personal space rather than the workspace their Environment runs in. The web
|
|
300496
|
-
* passes the Environment's organization as `?orgId=` and the registry turns it
|
|
300497
|
-
* into `X-Organization-ID`; without it CMMD still answers, for the default.
|
|
300498
|
-
*/
|
|
300499
|
-
const cmmdBillingRouteLayer = registerProxyRoute({
|
|
300791
|
+
registerProxyRoute({
|
|
300500
300792
|
forgePath: "/api/cmmd/billing",
|
|
300501
300793
|
method: "GET",
|
|
300502
300794
|
cmmdPath: "/api/forge/context/billing",
|
|
300503
300795
|
orgIdSource: "query"
|
|
300504
300796
|
});
|
|
300505
|
-
|
|
300506
|
-
const cmmdBillingSeriesRouteLayer = registerProxyRoute({
|
|
300797
|
+
registerProxyRoute({
|
|
300507
300798
|
forgePath: "/api/cmmd/billing/series",
|
|
300508
300799
|
method: "GET",
|
|
300509
300800
|
cmmdPath: "/api/forge/context/billing/series",
|
|
@@ -300541,6 +300832,15 @@ function runCmmdRestProxy(session, proxy, dependencies = {}) {
|
|
|
300541
300832
|
});
|
|
300542
300833
|
}
|
|
300543
300834
|
/**
|
|
300835
|
+
* Adapts `runCmmdRestProxy`'s `{ ok, value | error }` outcome into a
|
|
300836
|
+
* `ProxyHandlerRoute.run` result: the shared shape every converted handler's
|
|
300837
|
+
* `run` uses so it stays the three or so lines of the actual gateway call
|
|
300838
|
+
* plus response shaping, with resolve-and-retry left to `runCmmdRestProxy`.
|
|
300839
|
+
*/
|
|
300840
|
+
function runCmmdRestProxyAsHandlerResult(session, proxy, shape) {
|
|
300841
|
+
return runCmmdRestProxy(session, proxy).pipe(flatMap((outcome) => outcome.ok ? succeed(shape(outcome.value)) : fail(outcome.error)));
|
|
300842
|
+
}
|
|
300843
|
+
/**
|
|
300544
300844
|
* Forge-context REST responses wrap their payload in `{ data, meta, pagination? }`
|
|
300545
300845
|
* (see CMMD `sendForgeEnvelope`). Unwrap to the bare payload so handler response
|
|
300546
300846
|
* shapes match what the web client expected from the prior MCP text path.
|
|
@@ -300704,22 +301004,34 @@ function buildCreateBrainDocumentInput(payload) {
|
|
|
300704
301004
|
...payload.tags && payload.tags.length > 0 ? { tags: payload.tags } : {}
|
|
300705
301005
|
};
|
|
300706
301006
|
}
|
|
300707
|
-
|
|
300708
|
-
|
|
300709
|
-
|
|
300710
|
-
|
|
300711
|
-
|
|
300712
|
-
|
|
300713
|
-
|
|
301007
|
+
function parseCreateBrainDocRequest(request) {
|
|
301008
|
+
return request.json.pipe(orElseSucceed(() => null), map$3((rawBody) => {
|
|
301009
|
+
const payload = parseBrainDocPayload(rawBody);
|
|
301010
|
+
return payload ? {
|
|
301011
|
+
ok: true,
|
|
301012
|
+
value: payload
|
|
301013
|
+
} : {
|
|
301014
|
+
ok: false,
|
|
301015
|
+
status: 400,
|
|
301016
|
+
body: { error: "Invalid request: title (1-500 chars) and content (1-100k chars) are required." }
|
|
301017
|
+
};
|
|
301018
|
+
}));
|
|
301019
|
+
}
|
|
301020
|
+
registerProxyHandler({
|
|
301021
|
+
forgePath: "/api/cmmd/brain-docs",
|
|
301022
|
+
method: "POST",
|
|
301023
|
+
parse: parseCreateBrainDocRequest,
|
|
301024
|
+
run: (payload, { session }) => runCmmdRestProxyAsHandlerResult(session, (jwt) => cmmdGateway.createBrainDocument({
|
|
300714
301025
|
jwt,
|
|
300715
301026
|
document: buildCreateBrainDocumentInput(payload)
|
|
300716
|
-
}))
|
|
300717
|
-
|
|
300718
|
-
|
|
300719
|
-
|
|
300720
|
-
|
|
300721
|
-
|
|
300722
|
-
})
|
|
301027
|
+
}), (value) => ({
|
|
301028
|
+
status: 201,
|
|
301029
|
+
body: {
|
|
301030
|
+
success: true,
|
|
301031
|
+
doc: unwrapForgeEnvelope(value)
|
|
301032
|
+
}
|
|
301033
|
+
}))
|
|
301034
|
+
});
|
|
300723
301035
|
function normalizeOptionalNullableString(value, options) {
|
|
300724
301036
|
if (value === void 0) return void 0;
|
|
300725
301037
|
if (value === null) return null;
|
|
@@ -300773,46 +301085,77 @@ function buildUpdateTaskToolInput(payload) {
|
|
|
300773
301085
|
...payload.labels !== void 0 ? { tags: payload.labels } : {}
|
|
300774
301086
|
};
|
|
300775
301087
|
}
|
|
300776
|
-
|
|
300777
|
-
|
|
300778
|
-
|
|
300779
|
-
|
|
300780
|
-
|
|
300781
|
-
|
|
301088
|
+
function parseUpdateCmmdTaskRequest(request) {
|
|
301089
|
+
return request.json.pipe(orElseSucceed(() => null), map$3((rawBody) => {
|
|
301090
|
+
const payload = parseUpdateTaskPayload(rawBody);
|
|
301091
|
+
return payload ? {
|
|
301092
|
+
ok: true,
|
|
301093
|
+
value: payload
|
|
301094
|
+
} : {
|
|
301095
|
+
ok: false,
|
|
301096
|
+
status: 400,
|
|
301097
|
+
body: { error: "Invalid request: taskId is required and at least one update field must be provided." }
|
|
301098
|
+
};
|
|
301099
|
+
}));
|
|
301100
|
+
}
|
|
301101
|
+
function runUpdateCmmdTask(payload, { session }) {
|
|
300782
301102
|
const { taskId, ...patch } = buildUpdateTaskToolInput(payload);
|
|
300783
|
-
|
|
301103
|
+
return runCmmdRestProxyAsHandlerResult(session, (jwt) => cmmdGateway.updateTask({
|
|
300784
301104
|
jwt,
|
|
300785
301105
|
taskId: String(taskId),
|
|
300786
301106
|
patch
|
|
300787
|
-
}))
|
|
300788
|
-
if (restOutcome.ok) {
|
|
301107
|
+
}), (value) => {
|
|
300789
301108
|
invalidateCachedCmmdWorkIntakeForSession(session.sessionId);
|
|
300790
|
-
return
|
|
300791
|
-
|
|
300792
|
-
|
|
300793
|
-
|
|
300794
|
-
|
|
300795
|
-
|
|
300796
|
-
}
|
|
300797
|
-
|
|
300798
|
-
|
|
300799
|
-
|
|
300800
|
-
|
|
300801
|
-
|
|
300802
|
-
|
|
300803
|
-
|
|
300804
|
-
|
|
300805
|
-
|
|
301109
|
+
return {
|
|
301110
|
+
status: 200,
|
|
301111
|
+
body: {
|
|
301112
|
+
success: true,
|
|
301113
|
+
details: unwrapForgeEnvelope(value)
|
|
301114
|
+
}
|
|
301115
|
+
};
|
|
301116
|
+
});
|
|
301117
|
+
}
|
|
301118
|
+
registerProxyHandler({
|
|
301119
|
+
forgePath: "/api/cmmd/tasks/update",
|
|
301120
|
+
method: "POST",
|
|
301121
|
+
parse: parseUpdateCmmdTaskRequest,
|
|
301122
|
+
run: runUpdateCmmdTask
|
|
301123
|
+
});
|
|
301124
|
+
registerProxyHandler({
|
|
301125
|
+
forgePath: "/api/command/tasks/update",
|
|
301126
|
+
method: "POST",
|
|
301127
|
+
parse: parseUpdateCmmdTaskRequest,
|
|
301128
|
+
run: runUpdateCmmdTask
|
|
301129
|
+
});
|
|
301130
|
+
function parseAddCmmdTaskCommentRequest(request) {
|
|
301131
|
+
return request.json.pipe(orElseSucceed(() => null), map$3((rawBody) => {
|
|
301132
|
+
const payload = parseTaskCommentPayload(rawBody);
|
|
301133
|
+
return payload ? {
|
|
301134
|
+
ok: true,
|
|
301135
|
+
value: payload
|
|
301136
|
+
} : {
|
|
301137
|
+
ok: false,
|
|
301138
|
+
status: 400,
|
|
301139
|
+
body: { error: "taskId and content (max 2000 chars) are required." }
|
|
301140
|
+
};
|
|
301141
|
+
}));
|
|
301142
|
+
}
|
|
301143
|
+
registerProxyHandler({
|
|
301144
|
+
forgePath: "/api/cmmd/tasks/comment",
|
|
301145
|
+
method: "POST",
|
|
301146
|
+
parse: parseAddCmmdTaskCommentRequest,
|
|
301147
|
+
run: (payload, { session }) => runCmmdRestProxyAsHandlerResult(session, (jwt) => cmmdGateway.addTaskComment({
|
|
300806
301148
|
jwt,
|
|
300807
301149
|
taskId: payload.taskId,
|
|
300808
301150
|
content: payload.content
|
|
300809
|
-
}))
|
|
300810
|
-
|
|
300811
|
-
|
|
300812
|
-
|
|
300813
|
-
|
|
300814
|
-
|
|
300815
|
-
})
|
|
301151
|
+
}), (value) => ({
|
|
301152
|
+
status: 201,
|
|
301153
|
+
body: {
|
|
301154
|
+
success: true,
|
|
301155
|
+
details: unwrapForgeEnvelope(value)
|
|
301156
|
+
}
|
|
301157
|
+
}))
|
|
301158
|
+
});
|
|
300816
301159
|
function parseTaskCommentPayload(body) {
|
|
300817
301160
|
if (typeof body !== "object" || body === null) return null;
|
|
300818
301161
|
const b = body;
|
|
@@ -300841,23 +301184,38 @@ function normalizeTaskSearchParams(url) {
|
|
|
300841
301184
|
limit: Math.min(Number(url.searchParams.get("limit") ?? "20"), 50)
|
|
300842
301185
|
};
|
|
300843
301186
|
}
|
|
300844
|
-
|
|
300845
|
-
|
|
300846
|
-
|
|
300847
|
-
|
|
300848
|
-
|
|
300849
|
-
|
|
300850
|
-
|
|
300851
|
-
|
|
300852
|
-
|
|
300853
|
-
|
|
301187
|
+
function parseSearchCmmdTasksRequest(request) {
|
|
301188
|
+
return sync$1(() => ({
|
|
301189
|
+
ok: true,
|
|
301190
|
+
value: normalizeTaskSearchParams(new URL(request.url, "http://localhost"))
|
|
301191
|
+
}));
|
|
301192
|
+
}
|
|
301193
|
+
function runSearchCmmdTasks(search, { session }) {
|
|
301194
|
+
if (!search) return succeed({
|
|
301195
|
+
status: 200,
|
|
301196
|
+
body: {
|
|
301197
|
+
tasks: [],
|
|
301198
|
+
total: 0
|
|
301199
|
+
}
|
|
301200
|
+
});
|
|
301201
|
+
const accessToken = readCommandAccessTokenForSession(session.sessionId) ?? "";
|
|
301202
|
+
return promise(() => callCmmdTool(accessToken, "search_tasks", {
|
|
300854
301203
|
query: search.query,
|
|
300855
301204
|
limit: search.limit
|
|
300856
|
-
})))
|
|
300857
|
-
|
|
300858
|
-
|
|
300859
|
-
|
|
300860
|
-
|
|
301205
|
+
})).pipe(map$3((result) => ({
|
|
301206
|
+
status: 200,
|
|
301207
|
+
body: parseJsonObjectText(extractMcpToolText(result)) ?? {
|
|
301208
|
+
tasks: [],
|
|
301209
|
+
total: 0
|
|
301210
|
+
}
|
|
301211
|
+
})));
|
|
301212
|
+
}
|
|
301213
|
+
registerProxyHandler({
|
|
301214
|
+
forgePath: "/api/cmmd/tasks/search",
|
|
301215
|
+
method: "GET",
|
|
301216
|
+
parse: parseSearchCmmdTasksRequest,
|
|
301217
|
+
run: runSearchCmmdTasks
|
|
301218
|
+
});
|
|
300861
301219
|
function parseJsonObjectText(text) {
|
|
300862
301220
|
if (!text) return null;
|
|
300863
301221
|
try {
|
|
@@ -300871,23 +301229,47 @@ function parsePositiveIntegerId(value) {
|
|
|
300871
301229
|
const numericId = Number(value);
|
|
300872
301230
|
return Number.isInteger(numericId) && numericId > 0 ? numericId : null;
|
|
300873
301231
|
}
|
|
300874
|
-
|
|
300875
|
-
|
|
300876
|
-
|
|
300877
|
-
|
|
300878
|
-
|
|
300879
|
-
|
|
300880
|
-
|
|
300881
|
-
|
|
300882
|
-
|
|
301232
|
+
function parseGetCmmdTaskRequest(request) {
|
|
301233
|
+
return sync$1(() => {
|
|
301234
|
+
const taskId = extractIdFromPath(new URL(request.url, "http://localhost").pathname, 1);
|
|
301235
|
+
if (!taskId) return {
|
|
301236
|
+
ok: false,
|
|
301237
|
+
status: 400,
|
|
301238
|
+
body: { error: "Task ID is required." }
|
|
301239
|
+
};
|
|
301240
|
+
const numericId = parsePositiveIntegerId(taskId);
|
|
301241
|
+
if (!numericId) return {
|
|
301242
|
+
ok: false,
|
|
301243
|
+
status: 400,
|
|
301244
|
+
body: { error: "Invalid task ID." }
|
|
301245
|
+
};
|
|
301246
|
+
return {
|
|
301247
|
+
ok: true,
|
|
301248
|
+
value: numericId
|
|
301249
|
+
};
|
|
301250
|
+
});
|
|
301251
|
+
}
|
|
301252
|
+
function runGetCmmdTask(numericId, { session }) {
|
|
301253
|
+
return runCmmdRestProxyAsHandlerResult(session, (jwt) => cmmdGateway.getTask({
|
|
300883
301254
|
jwt,
|
|
300884
301255
|
taskId: String(numericId)
|
|
300885
|
-
}))
|
|
300886
|
-
|
|
300887
|
-
|
|
300888
|
-
|
|
300889
|
-
|
|
300890
|
-
}
|
|
301256
|
+
}), (value) => {
|
|
301257
|
+
const task = unwrapForgeEnvelope(value);
|
|
301258
|
+
return task === null || task === void 0 ? {
|
|
301259
|
+
status: 404,
|
|
301260
|
+
body: { error: "Task not found." }
|
|
301261
|
+
} : {
|
|
301262
|
+
status: 200,
|
|
301263
|
+
body: task
|
|
301264
|
+
};
|
|
301265
|
+
});
|
|
301266
|
+
}
|
|
301267
|
+
registerProxyHandler({
|
|
301268
|
+
forgePath: "/api/cmmd/tasks/:id",
|
|
301269
|
+
method: "GET",
|
|
301270
|
+
parse: parseGetCmmdTaskRequest,
|
|
301271
|
+
run: runGetCmmdTask
|
|
301272
|
+
});
|
|
300891
301273
|
function extractIdFromPath(pathname, fromEnd) {
|
|
300892
301274
|
const parts = pathname.split("/").filter(Boolean);
|
|
300893
301275
|
return parts[parts.length - fromEnd];
|
|
@@ -300899,22 +301281,37 @@ function decodePathSegment(segment) {
|
|
|
300899
301281
|
return null;
|
|
300900
301282
|
}
|
|
300901
301283
|
}
|
|
300902
|
-
|
|
300903
|
-
|
|
300904
|
-
|
|
300905
|
-
|
|
300906
|
-
|
|
300907
|
-
|
|
300908
|
-
|
|
301284
|
+
function parseGetCmmdTaskCommentsRequest(request) {
|
|
301285
|
+
return sync$1(() => {
|
|
301286
|
+
const taskId = extractIdFromPath(new URL(request.url, "http://localhost").pathname, 2);
|
|
301287
|
+
return taskId ? {
|
|
301288
|
+
ok: true,
|
|
301289
|
+
value: taskId
|
|
301290
|
+
} : {
|
|
301291
|
+
ok: false,
|
|
301292
|
+
status: 400,
|
|
301293
|
+
body: { error: "Task ID is required." }
|
|
301294
|
+
};
|
|
301295
|
+
});
|
|
301296
|
+
}
|
|
301297
|
+
function runGetCmmdTaskComments(taskId, { session }) {
|
|
301298
|
+
return runCmmdRestProxyAsHandlerResult(session, (jwt) => cmmdGateway.listTaskComments({
|
|
300909
301299
|
jwt,
|
|
300910
301300
|
taskId
|
|
300911
|
-
}))
|
|
300912
|
-
|
|
300913
|
-
|
|
300914
|
-
|
|
300915
|
-
|
|
300916
|
-
|
|
300917
|
-
})
|
|
301301
|
+
}), (value) => {
|
|
301302
|
+
const data = unwrapForgeEnvelope(value);
|
|
301303
|
+
return {
|
|
301304
|
+
status: 200,
|
|
301305
|
+
body: { comments: Array.isArray(data) ? data : [] }
|
|
301306
|
+
};
|
|
301307
|
+
});
|
|
301308
|
+
}
|
|
301309
|
+
registerProxyHandler({
|
|
301310
|
+
forgePath: "/api/cmmd/tasks/:id/comments",
|
|
301311
|
+
method: "GET",
|
|
301312
|
+
parse: parseGetCmmdTaskCommentsRequest,
|
|
301313
|
+
run: runGetCmmdTaskComments
|
|
301314
|
+
});
|
|
300918
301315
|
function normalizeCommentList(value) {
|
|
300919
301316
|
if (Array.isArray(value)) return value;
|
|
300920
301317
|
if (!value || typeof value !== "object") return [];
|
|
@@ -301020,55 +301417,54 @@ const cmmdUpdateProjectRouteLayer = add$1("PATCH", "/api/cmmd/projects/:id", gen
|
|
|
301020
301417
|
project: outcome.value
|
|
301021
301418
|
}, { status: 200 });
|
|
301022
301419
|
}).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
|
|
301023
|
-
|
|
301420
|
+
registerProxyRoute({
|
|
301024
301421
|
forgePath: "/api/cmmd/projects/:id/repository",
|
|
301025
301422
|
method: "GET",
|
|
301026
301423
|
cmmdPath: "/api/forge/context/projects/:id/repository",
|
|
301027
301424
|
orgIdSource: "none",
|
|
301028
301425
|
responseShape: "unwrapData"
|
|
301029
301426
|
});
|
|
301030
|
-
|
|
301031
|
-
const cmmdListProjectRepositoriesRouteLayer = registerProxyRoute({
|
|
301427
|
+
registerProxyRoute({
|
|
301032
301428
|
forgePath: "/api/cmmd/projects/:projectId/repositories",
|
|
301033
301429
|
method: "GET",
|
|
301034
301430
|
cmmdPath: "/api/forge/context/projects/:projectId/repositories",
|
|
301035
301431
|
orgIdSource: "none",
|
|
301036
301432
|
responseShape: "unwrapData"
|
|
301037
301433
|
});
|
|
301038
|
-
|
|
301434
|
+
registerProxyRoute({
|
|
301039
301435
|
forgePath: "/api/cmmd/organizations/:id/members",
|
|
301040
301436
|
method: "GET",
|
|
301041
301437
|
cmmdPath: "/api/organizations/:id/members",
|
|
301042
301438
|
orgIdSource: "none",
|
|
301043
301439
|
responseShape: "unwrapData"
|
|
301044
301440
|
});
|
|
301045
|
-
|
|
301441
|
+
registerProxyRoute({
|
|
301046
301442
|
forgePath: "/api/cmmd/sim-host/hosts",
|
|
301047
301443
|
method: "GET",
|
|
301048
301444
|
cmmdPath: "/api/forge/context/sim-host/hosts",
|
|
301049
301445
|
responseShape: "unwrapData"
|
|
301050
301446
|
});
|
|
301051
|
-
|
|
301447
|
+
registerProxyRoute({
|
|
301052
301448
|
forgePath: "/api/cmmd/sim-host/leases",
|
|
301053
301449
|
method: "GET",
|
|
301054
301450
|
cmmdPath: "/api/forge/context/sim-host/leases",
|
|
301055
301451
|
responseShape: "unwrapData"
|
|
301056
301452
|
});
|
|
301057
|
-
|
|
301453
|
+
registerProxyRoute({
|
|
301058
301454
|
forgePath: "/api/cmmd/sim-host/leases",
|
|
301059
301455
|
method: "POST",
|
|
301060
301456
|
cmmdPath: "/api/forge/context/sim-host/leases",
|
|
301061
301457
|
responseShape: "unwrapData",
|
|
301062
301458
|
successStatus: 200
|
|
301063
301459
|
});
|
|
301064
|
-
|
|
301460
|
+
registerProxyRoute({
|
|
301065
301461
|
forgePath: "/api/cmmd/sim-host/leases/:leaseId/release",
|
|
301066
301462
|
method: "POST",
|
|
301067
301463
|
cmmdPath: "/api/forge/context/sim-host/leases/:leaseId/release",
|
|
301068
301464
|
responseShape: "unwrapData",
|
|
301069
301465
|
successStatus: 200
|
|
301070
301466
|
});
|
|
301071
|
-
|
|
301467
|
+
registerProxyRoute({
|
|
301072
301468
|
forgePath: "/api/cmmd/sim-host/leases/:leaseId/renew",
|
|
301073
301469
|
method: "POST",
|
|
301074
301470
|
cmmdPath: "/api/forge/context/sim-host/leases/:leaseId/renew",
|
|
@@ -301092,7 +301488,7 @@ function getMultipartContentType(headers) {
|
|
|
301092
301488
|
const contentType = headers["content-type"] ?? "";
|
|
301093
301489
|
return contentType.includes("multipart/form-data") ? contentType : null;
|
|
301094
301490
|
}
|
|
301095
|
-
|
|
301491
|
+
registerProxyRoute({
|
|
301096
301492
|
forgePath: "/api/cmmd/tasks/:id/attachments",
|
|
301097
301493
|
method: "GET",
|
|
301098
301494
|
cmmdPath: "/api/forge/context/tasks/:id/attachments",
|
|
@@ -301127,150 +301523,150 @@ const cmmdUpdateTaskCommentRouteLayer = add$1("PATCH", "/api/cmmd/tasks/:taskId/
|
|
|
301127
301523
|
...outcome.value
|
|
301128
301524
|
}, { status: 200 });
|
|
301129
301525
|
}).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
|
|
301130
|
-
|
|
301526
|
+
registerProxyRoute({
|
|
301131
301527
|
forgePath: "/api/cmmd/tasks/:taskId/comments/:commentId",
|
|
301132
301528
|
method: "DELETE",
|
|
301133
301529
|
cmmdPath: "/api/forge/context/tasks/:taskId/comments/:commentId",
|
|
301134
301530
|
orgIdSource: "none",
|
|
301135
301531
|
requestBody: "json"
|
|
301136
301532
|
});
|
|
301137
|
-
|
|
301533
|
+
registerProxyRoute({
|
|
301138
301534
|
forgePath: "/api/cmmd/projects/:projectId/agent-members",
|
|
301139
301535
|
method: "GET",
|
|
301140
301536
|
cmmdPath: "/api/forge/context/projects/:projectId/agent-members",
|
|
301141
301537
|
orgIdSource: "none",
|
|
301142
301538
|
responseShape: "unwrapData"
|
|
301143
301539
|
});
|
|
301144
|
-
|
|
301540
|
+
registerProxyRoute({
|
|
301145
301541
|
forgePath: "/api/cmmd/projects/:projectId/agent-members",
|
|
301146
301542
|
method: "POST",
|
|
301147
301543
|
cmmdPath: "/api/forge/context/projects/:projectId/agent-members",
|
|
301148
301544
|
orgIdSource: "none",
|
|
301149
301545
|
responseShape: "unwrapData"
|
|
301150
301546
|
});
|
|
301151
|
-
|
|
301547
|
+
registerProxyRoute({
|
|
301152
301548
|
forgePath: "/api/cmmd/projects/:projectId/agent-members/:memberId",
|
|
301153
301549
|
method: "GET",
|
|
301154
301550
|
cmmdPath: "/api/forge/context/projects/:projectId/agent-members/:memberId",
|
|
301155
301551
|
orgIdSource: "none",
|
|
301156
301552
|
responseShape: "unwrapData"
|
|
301157
301553
|
});
|
|
301158
|
-
|
|
301554
|
+
registerProxyRoute({
|
|
301159
301555
|
forgePath: "/api/cmmd/projects/:projectId/agent-members/:memberId",
|
|
301160
301556
|
method: "PATCH",
|
|
301161
301557
|
cmmdPath: "/api/forge/context/projects/:projectId/agent-members/:memberId",
|
|
301162
301558
|
orgIdSource: "none",
|
|
301163
301559
|
responseShape: "unwrapData"
|
|
301164
301560
|
});
|
|
301165
|
-
|
|
301561
|
+
registerProxyRoute({
|
|
301166
301562
|
forgePath: "/api/cmmd/projects/:projectId/agent-members/:memberId/retire",
|
|
301167
301563
|
method: "POST",
|
|
301168
301564
|
cmmdPath: "/api/forge/context/projects/:projectId/agent-members/:memberId/retire",
|
|
301169
301565
|
orgIdSource: "none",
|
|
301170
301566
|
responseShape: "unwrapData"
|
|
301171
301567
|
});
|
|
301172
|
-
|
|
301568
|
+
registerProxyRoute({
|
|
301173
301569
|
forgePath: "/api/cmmd/projects/:projectId/agent-members/:memberId/instances",
|
|
301174
301570
|
method: "GET",
|
|
301175
301571
|
cmmdPath: "/api/forge/context/projects/:projectId/agent-members/:memberId/instances",
|
|
301176
301572
|
orgIdSource: "none",
|
|
301177
301573
|
responseShape: "unwrapData"
|
|
301178
301574
|
});
|
|
301179
|
-
|
|
301575
|
+
registerProxyRoute({
|
|
301180
301576
|
forgePath: "/api/cmmd/projects/:projectId/agent-members/consolidation/preview",
|
|
301181
301577
|
method: "POST",
|
|
301182
301578
|
cmmdPath: "/api/forge/context/projects/:projectId/agent-members/consolidation/preview",
|
|
301183
301579
|
orgIdSource: "none",
|
|
301184
301580
|
responseShape: "unwrapData"
|
|
301185
301581
|
});
|
|
301186
|
-
|
|
301582
|
+
registerProxyRoute({
|
|
301187
301583
|
forgePath: "/api/cmmd/projects/:projectId/agent-members/consolidation/apply",
|
|
301188
301584
|
method: "POST",
|
|
301189
301585
|
cmmdPath: "/api/forge/context/projects/:projectId/agent-members/consolidation/apply",
|
|
301190
301586
|
orgIdSource: "none",
|
|
301191
301587
|
responseShape: "unwrapData"
|
|
301192
301588
|
});
|
|
301193
|
-
|
|
301589
|
+
registerProxyRoute({
|
|
301194
301590
|
forgePath: "/api/cmmd/projects/:projectId/tasks/:taskId/assignment",
|
|
301195
301591
|
method: "PUT",
|
|
301196
301592
|
cmmdPath: "/api/forge/context/projects/:projectId/tasks/:taskId/assignment",
|
|
301197
301593
|
orgIdSource: "none",
|
|
301198
301594
|
responseShape: "unwrapData"
|
|
301199
301595
|
});
|
|
301200
|
-
|
|
301596
|
+
registerProxyRoute({
|
|
301201
301597
|
forgePath: "/api/cmmd/tasks",
|
|
301202
301598
|
method: "GET",
|
|
301203
301599
|
cmmdPath: "/api/forge/context/tasks"
|
|
301204
301600
|
});
|
|
301205
|
-
|
|
301601
|
+
registerProxyRoute({
|
|
301206
301602
|
forgePath: "/api/cmmd/tasks",
|
|
301207
301603
|
method: "POST",
|
|
301208
301604
|
cmmdPath: "/api/forge/context/tasks"
|
|
301209
301605
|
});
|
|
301210
|
-
|
|
301606
|
+
registerProxyRoute({
|
|
301211
301607
|
forgePath: "/api/cmmd/tasks/:id/archive",
|
|
301212
301608
|
method: "POST",
|
|
301213
301609
|
cmmdPath: "/api/forge/context/tasks/:id/archive",
|
|
301214
301610
|
orgIdSource: "none"
|
|
301215
301611
|
});
|
|
301216
|
-
|
|
301612
|
+
registerProxyRoute({
|
|
301217
301613
|
forgePath: "/api/cmmd/tasks/:id/unarchive",
|
|
301218
301614
|
method: "POST",
|
|
301219
301615
|
cmmdPath: "/api/forge/context/tasks/:id/unarchive",
|
|
301220
301616
|
orgIdSource: "none"
|
|
301221
301617
|
});
|
|
301222
|
-
|
|
301618
|
+
registerProxyRoute({
|
|
301223
301619
|
forgePath: "/api/cmmd/saved-views",
|
|
301224
301620
|
method: "GET",
|
|
301225
301621
|
cmmdPath: "/api/forge/context/saved-views",
|
|
301226
301622
|
orgIdSource: "none"
|
|
301227
301623
|
});
|
|
301228
|
-
|
|
301624
|
+
registerProxyRoute({
|
|
301229
301625
|
forgePath: "/api/cmmd/saved-views",
|
|
301230
301626
|
method: "POST",
|
|
301231
301627
|
cmmdPath: "/api/forge/context/saved-views",
|
|
301232
301628
|
orgIdSource: "none",
|
|
301233
301629
|
successStatus: 201
|
|
301234
301630
|
});
|
|
301235
|
-
|
|
301631
|
+
registerProxyRoute({
|
|
301236
301632
|
forgePath: "/api/cmmd/saved-views/import",
|
|
301237
301633
|
method: "POST",
|
|
301238
301634
|
cmmdPath: "/api/forge/context/saved-views/import",
|
|
301239
301635
|
orgIdSource: "none"
|
|
301240
301636
|
});
|
|
301241
|
-
|
|
301637
|
+
registerProxyRoute({
|
|
301242
301638
|
forgePath: "/api/cmmd/saved-views/:viewId",
|
|
301243
301639
|
method: "PATCH",
|
|
301244
301640
|
cmmdPath: "/api/forge/context/saved-views/:viewId",
|
|
301245
301641
|
orgIdSource: "none"
|
|
301246
301642
|
});
|
|
301247
|
-
|
|
301643
|
+
registerProxyRoute({
|
|
301248
301644
|
forgePath: "/api/cmmd/saved-views/:viewId",
|
|
301249
301645
|
method: "DELETE",
|
|
301250
301646
|
cmmdPath: "/api/forge/context/saved-views/:viewId",
|
|
301251
301647
|
orgIdSource: "none",
|
|
301252
301648
|
forwardSearchParams: true
|
|
301253
301649
|
});
|
|
301254
|
-
|
|
301650
|
+
registerProxyRoute({
|
|
301255
301651
|
forgePath: "/api/cmmd/projects",
|
|
301256
301652
|
method: "GET",
|
|
301257
301653
|
cmmdPath: "/api/forge/context/projects",
|
|
301258
301654
|
responseShape: "passthrough"
|
|
301259
301655
|
});
|
|
301260
|
-
|
|
301656
|
+
registerProxyRoute({
|
|
301261
301657
|
forgePath: "/api/cmmd/projects/:id",
|
|
301262
301658
|
method: "GET",
|
|
301263
301659
|
cmmdPath: "/api/forge/context/projects/:id",
|
|
301264
301660
|
orgIdSource: "none",
|
|
301265
301661
|
responseShape: "passthrough"
|
|
301266
301662
|
});
|
|
301267
|
-
|
|
301663
|
+
registerProxyRoute({
|
|
301268
301664
|
forgePath: "/api/cmmd/projects",
|
|
301269
301665
|
method: "POST",
|
|
301270
301666
|
cmmdPath: "/api/projects",
|
|
301271
301667
|
responseShape: "passthrough"
|
|
301272
301668
|
});
|
|
301273
|
-
|
|
301669
|
+
registerProxyRoute({
|
|
301274
301670
|
forgePath: "/api/cmmd/projects/:id",
|
|
301275
301671
|
method: "DELETE",
|
|
301276
301672
|
cmmdPath: "/api/forge/context/projects/:id",
|
|
@@ -301278,78 +301674,78 @@ const cmmdDeleteProjectRouteLayer = registerProxyRoute({
|
|
|
301278
301674
|
fixedSearchParams: { soft: "false" },
|
|
301279
301675
|
workIntakeInvalidation: "always"
|
|
301280
301676
|
});
|
|
301281
|
-
|
|
301677
|
+
registerProxyRoute({
|
|
301282
301678
|
forgePath: "/api/cmmd/projects/:id/move",
|
|
301283
301679
|
method: "POST",
|
|
301284
301680
|
cmmdPath: "/api/forge/context/projects/:id/move",
|
|
301285
301681
|
orgIdSource: "none",
|
|
301286
301682
|
responseShape: "unwrapData"
|
|
301287
301683
|
});
|
|
301288
|
-
|
|
301684
|
+
registerProxyRoute({
|
|
301289
301685
|
forgePath: "/api/cmmd/projects/:id/members",
|
|
301290
301686
|
method: "GET",
|
|
301291
301687
|
cmmdPath: "/api/forge/context/projects/:id/team"
|
|
301292
301688
|
});
|
|
301293
|
-
|
|
301689
|
+
registerProxyRoute({
|
|
301294
301690
|
forgePath: "/api/cmmd/projects/:id/milestones",
|
|
301295
301691
|
method: "GET",
|
|
301296
301692
|
cmmdPath: "/api/forge/context/projects/:id/milestones"
|
|
301297
301693
|
});
|
|
301298
|
-
|
|
301694
|
+
registerProxyRoute({
|
|
301299
301695
|
forgePath: "/api/cmmd/projects/:id/milestones",
|
|
301300
301696
|
method: "POST",
|
|
301301
301697
|
cmmdPath: "/api/forge/context/projects/:id/milestones",
|
|
301302
301698
|
orgIdSource: "none",
|
|
301303
301699
|
responseShape: "unwrapData"
|
|
301304
301700
|
});
|
|
301305
|
-
|
|
301701
|
+
registerProxyRoute({
|
|
301306
301702
|
forgePath: "/api/cmmd/projects/:id/milestones/:milestoneId",
|
|
301307
301703
|
method: "PATCH",
|
|
301308
301704
|
cmmdPath: "/api/forge/context/projects/:id/milestones/:milestoneId",
|
|
301309
301705
|
orgIdSource: "none",
|
|
301310
301706
|
responseShape: "unwrapData"
|
|
301311
301707
|
});
|
|
301312
|
-
|
|
301708
|
+
registerProxyRoute({
|
|
301313
301709
|
forgePath: "/api/cmmd/projects/:id/milestones/:milestoneId",
|
|
301314
301710
|
method: "DELETE",
|
|
301315
301711
|
cmmdPath: "/api/forge/context/projects/:id/milestones/:milestoneId",
|
|
301316
301712
|
orgIdSource: "none"
|
|
301317
301713
|
});
|
|
301318
|
-
|
|
301714
|
+
registerProxyRoute({
|
|
301319
301715
|
forgePath: "/api/cmmd/projects/:id/updates",
|
|
301320
301716
|
method: "GET",
|
|
301321
301717
|
cmmdPath: "/api/forge/context/projects/:id/updates",
|
|
301322
301718
|
orgIdSource: "none",
|
|
301323
301719
|
responseShape: "passthrough"
|
|
301324
301720
|
});
|
|
301325
|
-
|
|
301721
|
+
registerProxyRoute({
|
|
301326
301722
|
forgePath: "/api/cmmd/projects/:id/updates",
|
|
301327
301723
|
method: "POST",
|
|
301328
301724
|
cmmdPath: "/api/forge/context/projects/:id/updates",
|
|
301329
301725
|
orgIdSource: "none",
|
|
301330
301726
|
responseShape: "unwrapData"
|
|
301331
301727
|
});
|
|
301332
|
-
|
|
301728
|
+
registerProxyRoute({
|
|
301333
301729
|
forgePath: "/api/cmmd/projects/:id/updates/:updateId",
|
|
301334
301730
|
method: "PATCH",
|
|
301335
301731
|
cmmdPath: "/api/forge/context/projects/:id/updates/:updateId",
|
|
301336
301732
|
orgIdSource: "none",
|
|
301337
301733
|
responseShape: "unwrapData"
|
|
301338
301734
|
});
|
|
301339
|
-
|
|
301735
|
+
registerProxyRoute({
|
|
301340
301736
|
forgePath: "/api/cmmd/projects/:id/updates/:updateId",
|
|
301341
301737
|
method: "DELETE",
|
|
301342
301738
|
cmmdPath: "/api/forge/context/projects/:id/updates/:updateId",
|
|
301343
301739
|
orgIdSource: "none"
|
|
301344
301740
|
});
|
|
301345
|
-
|
|
301741
|
+
registerProxyRoute({
|
|
301346
301742
|
forgePath: "/api/cmmd/projects/:id/content/readability",
|
|
301347
301743
|
method: "POST",
|
|
301348
301744
|
cmmdPath: "/api/forge/context/projects/:id/content/readability",
|
|
301349
301745
|
orgIdSource: "none",
|
|
301350
301746
|
responseShape: "unwrapData"
|
|
301351
301747
|
});
|
|
301352
|
-
|
|
301748
|
+
registerProxyRoute({
|
|
301353
301749
|
forgePath: "/api/cmmd/projects/:projectId/task-drafts",
|
|
301354
301750
|
method: "POST",
|
|
301355
301751
|
cmmdPath: "/api/forge/context/projects/:projectId/task-drafts",
|
|
@@ -301357,7 +301753,7 @@ const cmmdCreateProjectTaskDraftRouteLayer = registerProxyRoute({
|
|
|
301357
301753
|
responseShape: "unwrapData",
|
|
301358
301754
|
successStatus: 201
|
|
301359
301755
|
});
|
|
301360
|
-
|
|
301756
|
+
registerProxyRoute({
|
|
301361
301757
|
forgePath: "/api/cmmd/projects/:projectId/task-drafts/:draftId",
|
|
301362
301758
|
method: "GET",
|
|
301363
301759
|
cmmdPath: "/api/forge/context/projects/:projectId/task-drafts/:draftId",
|
|
@@ -301365,7 +301761,7 @@ const cmmdGetProjectTaskDraftRouteLayer = registerProxyRoute({
|
|
|
301365
301761
|
responseShape: "unwrapData",
|
|
301366
301762
|
successStatus: 200
|
|
301367
301763
|
});
|
|
301368
|
-
|
|
301764
|
+
registerProxyRoute({
|
|
301369
301765
|
forgePath: "/api/cmmd/projects/:projectId/task-drafts/:draftId",
|
|
301370
301766
|
method: "PATCH",
|
|
301371
301767
|
cmmdPath: "/api/forge/context/projects/:projectId/task-drafts/:draftId",
|
|
@@ -301373,7 +301769,7 @@ const cmmdUpdateProjectTaskDraftRouteLayer = registerProxyRoute({
|
|
|
301373
301769
|
responseShape: "unwrapData",
|
|
301374
301770
|
successStatus: 200
|
|
301375
301771
|
});
|
|
301376
|
-
|
|
301772
|
+
registerProxyRoute({
|
|
301377
301773
|
forgePath: "/api/cmmd/projects/:projectId/task-drafts/:draftId/preview",
|
|
301378
301774
|
method: "POST",
|
|
301379
301775
|
cmmdPath: "/api/forge/context/projects/:projectId/task-drafts/:draftId/preview",
|
|
@@ -301381,7 +301777,7 @@ const cmmdPreviewProjectTaskDraftRouteLayer = registerProxyRoute({
|
|
|
301381
301777
|
responseShape: "unwrapData",
|
|
301382
301778
|
successStatus: 200
|
|
301383
301779
|
});
|
|
301384
|
-
|
|
301780
|
+
registerProxyRoute({
|
|
301385
301781
|
forgePath: "/api/cmmd/projects/:projectId/task-drafts/:draftId/commit",
|
|
301386
301782
|
method: "POST",
|
|
301387
301783
|
cmmdPath: "/api/forge/context/projects/:projectId/task-drafts/:draftId/commit",
|
|
@@ -301389,7 +301785,7 @@ const cmmdCommitProjectTaskDraftRouteLayer = registerProxyRoute({
|
|
|
301389
301785
|
responseShape: "unwrapData",
|
|
301390
301786
|
successStatus: 200
|
|
301391
301787
|
});
|
|
301392
|
-
|
|
301788
|
+
registerProxyRoute({
|
|
301393
301789
|
forgePath: "/api/cmmd/projects/:projectId/task-drafts/:draftId/discard",
|
|
301394
301790
|
method: "POST",
|
|
301395
301791
|
cmmdPath: "/api/forge/context/projects/:projectId/task-drafts/:draftId/discard",
|
|
@@ -301397,352 +301793,352 @@ const cmmdDiscardProjectTaskDraftRouteLayer = registerProxyRoute({
|
|
|
301397
301793
|
responseShape: "unwrapData",
|
|
301398
301794
|
successStatus: 200
|
|
301399
301795
|
});
|
|
301400
|
-
|
|
301796
|
+
registerProxyRoute({
|
|
301401
301797
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/plan",
|
|
301402
301798
|
method: "GET",
|
|
301403
301799
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/plan",
|
|
301404
301800
|
orgIdSource: "none"
|
|
301405
301801
|
});
|
|
301406
|
-
|
|
301802
|
+
registerProxyRoute({
|
|
301407
301803
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/authority/activate",
|
|
301408
301804
|
method: "POST",
|
|
301409
301805
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/authority/activate",
|
|
301410
301806
|
orgIdSource: "none",
|
|
301411
301807
|
responseShape: "unwrapData"
|
|
301412
301808
|
});
|
|
301413
|
-
|
|
301809
|
+
registerProxyRoute({
|
|
301414
301810
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/readiness",
|
|
301415
301811
|
method: "GET",
|
|
301416
301812
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/readiness",
|
|
301417
301813
|
orgIdSource: "none"
|
|
301418
301814
|
});
|
|
301419
|
-
|
|
301815
|
+
registerProxyRoute({
|
|
301420
301816
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/capabilities",
|
|
301421
301817
|
method: "GET",
|
|
301422
301818
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/capabilities",
|
|
301423
301819
|
orgIdSource: "none"
|
|
301424
301820
|
});
|
|
301425
|
-
|
|
301821
|
+
registerProxyRoute({
|
|
301426
301822
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/summary",
|
|
301427
301823
|
method: "GET",
|
|
301428
301824
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/summary",
|
|
301429
301825
|
orgIdSource: "none"
|
|
301430
301826
|
});
|
|
301431
|
-
|
|
301827
|
+
registerProxyRoute({
|
|
301432
301828
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/detail",
|
|
301433
301829
|
method: "GET",
|
|
301434
301830
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/detail",
|
|
301435
301831
|
orgIdSource: "none"
|
|
301436
301832
|
});
|
|
301437
|
-
|
|
301833
|
+
registerProxyRoute({
|
|
301438
301834
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/briefing",
|
|
301439
301835
|
method: "GET",
|
|
301440
301836
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/briefing",
|
|
301441
301837
|
orgIdSource: "none"
|
|
301442
301838
|
});
|
|
301443
|
-
|
|
301839
|
+
registerProxyRoute({
|
|
301444
301840
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/events",
|
|
301445
301841
|
method: "GET",
|
|
301446
301842
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/events",
|
|
301447
301843
|
orgIdSource: "none"
|
|
301448
301844
|
});
|
|
301449
|
-
|
|
301845
|
+
registerProxyRoute({
|
|
301450
301846
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/explain",
|
|
301451
301847
|
method: "GET",
|
|
301452
301848
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/explain",
|
|
301453
301849
|
orgIdSource: "none"
|
|
301454
301850
|
});
|
|
301455
|
-
|
|
301851
|
+
registerProxyRoute({
|
|
301456
301852
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/pause",
|
|
301457
301853
|
method: "POST",
|
|
301458
301854
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/pause",
|
|
301459
301855
|
orgIdSource: "none"
|
|
301460
301856
|
});
|
|
301461
|
-
|
|
301857
|
+
registerProxyRoute({
|
|
301462
301858
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/resume",
|
|
301463
301859
|
method: "POST",
|
|
301464
301860
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/resume",
|
|
301465
301861
|
orgIdSource: "none"
|
|
301466
301862
|
});
|
|
301467
|
-
|
|
301863
|
+
registerProxyRoute({
|
|
301468
301864
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/tasks/:taskId/reservations",
|
|
301469
301865
|
method: "POST",
|
|
301470
301866
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/tasks/:taskId/reservations",
|
|
301471
301867
|
orgIdSource: "none"
|
|
301472
301868
|
});
|
|
301473
|
-
|
|
301869
|
+
registerProxyRoute({
|
|
301474
301870
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/reservations/:reservationId/release",
|
|
301475
301871
|
method: "POST",
|
|
301476
301872
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/reservations/:reservationId/release",
|
|
301477
301873
|
orgIdSource: "none"
|
|
301478
301874
|
});
|
|
301479
|
-
|
|
301875
|
+
registerProxyRoute({
|
|
301480
301876
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/reconcile",
|
|
301481
301877
|
method: "POST",
|
|
301482
301878
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/reconcile",
|
|
301483
301879
|
orgIdSource: "none"
|
|
301484
301880
|
});
|
|
301485
|
-
|
|
301881
|
+
registerProxyRoute({
|
|
301486
301882
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/attention/:attentionId/resolve",
|
|
301487
301883
|
method: "POST",
|
|
301488
301884
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/attention/:attentionId/resolve",
|
|
301489
301885
|
orgIdSource: "none"
|
|
301490
301886
|
});
|
|
301491
|
-
|
|
301887
|
+
registerProxyRoute({
|
|
301492
301888
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/controller/claim",
|
|
301493
301889
|
method: "POST",
|
|
301494
301890
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/controller/claim",
|
|
301495
301891
|
orgIdSource: "none"
|
|
301496
301892
|
});
|
|
301497
|
-
|
|
301893
|
+
registerProxyRoute({
|
|
301498
301894
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/controller/claim/renew",
|
|
301499
301895
|
method: "POST",
|
|
301500
301896
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/controller/claim/renew",
|
|
301501
301897
|
orgIdSource: "none"
|
|
301502
301898
|
});
|
|
301503
|
-
|
|
301899
|
+
registerProxyRoute({
|
|
301504
301900
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/controller/claim/yield",
|
|
301505
301901
|
method: "POST",
|
|
301506
301902
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/controller/claim/yield",
|
|
301507
301903
|
orgIdSource: "none"
|
|
301508
301904
|
});
|
|
301509
|
-
|
|
301905
|
+
registerProxyRoute({
|
|
301510
301906
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/controller/events/:eventId/acknowledge",
|
|
301511
301907
|
method: "POST",
|
|
301512
301908
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/controller/events/:eventId/acknowledge",
|
|
301513
301909
|
orgIdSource: "none"
|
|
301514
301910
|
});
|
|
301515
|
-
|
|
301911
|
+
registerProxyRoute({
|
|
301516
301912
|
forgePath: "/api/cmmd/projects/:projectId/project-lead/controller/decisions",
|
|
301517
301913
|
method: "POST",
|
|
301518
301914
|
cmmdPath: "/api/forge/context/projects/:projectId/project-lead/controller/decisions",
|
|
301519
301915
|
orgIdSource: "none"
|
|
301520
301916
|
});
|
|
301521
|
-
|
|
301917
|
+
registerProxyRoute({
|
|
301522
301918
|
forgePath: "/api/cmmd/automations/presets",
|
|
301523
301919
|
method: "GET",
|
|
301524
301920
|
cmmdPath: "/api/forge/context/automations/presets",
|
|
301525
301921
|
orgIdSource: "none",
|
|
301526
301922
|
responseShape: "unwrapData"
|
|
301527
301923
|
});
|
|
301528
|
-
|
|
301924
|
+
registerProxyRoute({
|
|
301529
301925
|
forgePath: "/api/cmmd/automations/user/rules",
|
|
301530
301926
|
method: "GET",
|
|
301531
301927
|
cmmdPath: "/api/forge/context/automations/user/rules",
|
|
301532
301928
|
orgIdSource: "none",
|
|
301533
301929
|
responseShape: "unwrapData"
|
|
301534
301930
|
});
|
|
301535
|
-
|
|
301931
|
+
registerProxyRoute({
|
|
301536
301932
|
forgePath: "/api/cmmd/automations/user/rules",
|
|
301537
301933
|
method: "POST",
|
|
301538
301934
|
cmmdPath: "/api/forge/context/automations/user/rules",
|
|
301539
301935
|
orgIdSource: "none",
|
|
301540
301936
|
responseShape: "unwrapData"
|
|
301541
301937
|
});
|
|
301542
|
-
|
|
301938
|
+
registerProxyRoute({
|
|
301543
301939
|
forgePath: "/api/cmmd/automations/user/rules/:ruleId",
|
|
301544
301940
|
method: "PATCH",
|
|
301545
301941
|
cmmdPath: "/api/forge/context/automations/user/rules/:ruleId",
|
|
301546
301942
|
orgIdSource: "none",
|
|
301547
301943
|
responseShape: "unwrapData"
|
|
301548
301944
|
});
|
|
301549
|
-
|
|
301945
|
+
registerProxyRoute({
|
|
301550
301946
|
forgePath: "/api/cmmd/automations/user/rules/:ruleId/runs",
|
|
301551
301947
|
method: "GET",
|
|
301552
301948
|
cmmdPath: "/api/forge/context/automations/user/rules/:ruleId/runs",
|
|
301553
301949
|
orgIdSource: "none",
|
|
301554
301950
|
responseShape: "unwrapData"
|
|
301555
301951
|
});
|
|
301556
|
-
|
|
301952
|
+
registerProxyRoute({
|
|
301557
301953
|
forgePath: "/api/cmmd/automations/user/rules/:ruleId/runs",
|
|
301558
301954
|
method: "POST",
|
|
301559
301955
|
cmmdPath: "/api/forge/context/automations/user/rules/:ruleId/runs",
|
|
301560
301956
|
orgIdSource: "none",
|
|
301561
301957
|
responseShape: "unwrapData"
|
|
301562
301958
|
});
|
|
301563
|
-
|
|
301959
|
+
registerProxyRoute({
|
|
301564
301960
|
forgePath: "/api/cmmd/automations/projects/:projectId/rules",
|
|
301565
301961
|
method: "GET",
|
|
301566
301962
|
cmmdPath: "/api/forge/context/automations/projects/:projectId/rules",
|
|
301567
301963
|
orgIdSource: "query",
|
|
301568
301964
|
responseShape: "unwrapData"
|
|
301569
301965
|
});
|
|
301570
|
-
|
|
301966
|
+
registerProxyRoute({
|
|
301571
301967
|
forgePath: "/api/cmmd/automations/projects/:projectId/rules",
|
|
301572
301968
|
method: "POST",
|
|
301573
301969
|
cmmdPath: "/api/forge/context/automations/projects/:projectId/rules",
|
|
301574
301970
|
orgIdSource: "query",
|
|
301575
301971
|
responseShape: "unwrapData"
|
|
301576
301972
|
});
|
|
301577
|
-
|
|
301973
|
+
registerProxyRoute({
|
|
301578
301974
|
forgePath: "/api/cmmd/automations/projects/:projectId/rules/:ruleId",
|
|
301579
301975
|
method: "PATCH",
|
|
301580
301976
|
cmmdPath: "/api/forge/context/automations/projects/:projectId/rules/:ruleId",
|
|
301581
301977
|
orgIdSource: "query",
|
|
301582
301978
|
responseShape: "unwrapData"
|
|
301583
301979
|
});
|
|
301584
|
-
|
|
301980
|
+
registerProxyRoute({
|
|
301585
301981
|
forgePath: "/api/cmmd/automations/projects/:projectId/runs",
|
|
301586
301982
|
method: "GET",
|
|
301587
301983
|
cmmdPath: "/api/forge/context/automations/projects/:projectId/runs",
|
|
301588
301984
|
orgIdSource: "query",
|
|
301589
301985
|
responseShape: "unwrapData"
|
|
301590
301986
|
});
|
|
301591
|
-
|
|
301987
|
+
registerProxyRoute({
|
|
301592
301988
|
forgePath: "/api/cmmd/automations/projects/:projectId/tasks/:taskId/runs",
|
|
301593
301989
|
method: "POST",
|
|
301594
301990
|
cmmdPath: "/api/forge/context/automations/projects/:projectId/tasks/:taskId/runs",
|
|
301595
301991
|
orgIdSource: "query",
|
|
301596
301992
|
responseShape: "unwrapData"
|
|
301597
301993
|
});
|
|
301598
|
-
|
|
301994
|
+
registerProxyRoute({
|
|
301599
301995
|
forgePath: "/api/cmmd/automations/runs/:runId",
|
|
301600
301996
|
method: "GET",
|
|
301601
301997
|
cmmdPath: "/api/forge/context/automations/runs/:runId",
|
|
301602
301998
|
orgIdSource: "query",
|
|
301603
301999
|
responseShape: "unwrapData"
|
|
301604
302000
|
});
|
|
301605
|
-
|
|
302001
|
+
registerProxyRoute({
|
|
301606
302002
|
forgePath: "/api/cmmd/automations/runs/:runId/retry",
|
|
301607
302003
|
method: "POST",
|
|
301608
302004
|
cmmdPath: "/api/forge/context/automations/runs/:runId/retry",
|
|
301609
302005
|
orgIdSource: "query",
|
|
301610
302006
|
responseShape: "unwrapData"
|
|
301611
302007
|
});
|
|
301612
|
-
|
|
302008
|
+
registerProxyRoute({
|
|
301613
302009
|
forgePath: "/api/cmmd/automations/runs/:runId/cancel",
|
|
301614
302010
|
method: "POST",
|
|
301615
302011
|
cmmdPath: "/api/forge/context/automations/runs/:runId/cancel",
|
|
301616
302012
|
orgIdSource: "query",
|
|
301617
302013
|
responseShape: "unwrapData"
|
|
301618
302014
|
});
|
|
301619
|
-
|
|
302015
|
+
registerProxyRoute({
|
|
301620
302016
|
forgePath: "/api/cmmd/automations/runs/:runId/escalations/approve",
|
|
301621
302017
|
method: "POST",
|
|
301622
302018
|
cmmdPath: "/api/forge/context/automations/runs/:runId/escalations/approve",
|
|
301623
302019
|
orgIdSource: "query",
|
|
301624
302020
|
responseShape: "unwrapData"
|
|
301625
302021
|
});
|
|
301626
|
-
|
|
302022
|
+
registerProxyRoute({
|
|
301627
302023
|
forgePath: "/api/cmmd/automations/runs/:runId/escalations/reject",
|
|
301628
302024
|
method: "POST",
|
|
301629
302025
|
cmmdPath: "/api/forge/context/automations/runs/:runId/escalations/reject",
|
|
301630
302026
|
orgIdSource: "query",
|
|
301631
302027
|
responseShape: "unwrapData"
|
|
301632
302028
|
});
|
|
301633
|
-
|
|
302029
|
+
registerProxyRoute({
|
|
301634
302030
|
forgePath: "/api/cmmd/projects/:id/board",
|
|
301635
302031
|
method: "GET",
|
|
301636
302032
|
cmmdPath: "/api/forge/context/projects/:id/board",
|
|
301637
302033
|
orgIdSource: "none",
|
|
301638
302034
|
responseShape: "unwrapData"
|
|
301639
302035
|
});
|
|
301640
|
-
|
|
302036
|
+
registerProxyRoute({
|
|
301641
302037
|
forgePath: "/api/cmmd/projects/:id/task-workflow",
|
|
301642
302038
|
method: "GET",
|
|
301643
302039
|
cmmdPath: "/api/forge/context/projects/:id/task-workflow",
|
|
301644
302040
|
orgIdSource: "none",
|
|
301645
302041
|
responseShape: "unwrapData"
|
|
301646
302042
|
});
|
|
301647
|
-
|
|
302043
|
+
registerProxyRoute({
|
|
301648
302044
|
forgePath: "/api/cmmd/projects/:id/task-workflow",
|
|
301649
302045
|
method: "PUT",
|
|
301650
302046
|
cmmdPath: "/api/forge/context/projects/:id/task-workflow",
|
|
301651
302047
|
orgIdSource: "none",
|
|
301652
302048
|
responseShape: "unwrapData"
|
|
301653
302049
|
});
|
|
301654
|
-
|
|
302050
|
+
registerProxyRoute({
|
|
301655
302051
|
forgePath: "/api/cmmd/projects/:id/board",
|
|
301656
302052
|
method: "POST",
|
|
301657
302053
|
cmmdPath: "/api/forge/context/projects/:id/board",
|
|
301658
302054
|
orgIdSource: "none",
|
|
301659
302055
|
responseShape: "unwrapData"
|
|
301660
302056
|
});
|
|
301661
|
-
|
|
302057
|
+
registerProxyRoute({
|
|
301662
302058
|
forgePath: "/api/cmmd/projects/:id/board/:taskId",
|
|
301663
302059
|
method: "PATCH",
|
|
301664
302060
|
cmmdPath: "/api/forge/context/projects/:id/board/:taskId",
|
|
301665
302061
|
orgIdSource: "none",
|
|
301666
302062
|
responseShape: "unwrapData"
|
|
301667
302063
|
});
|
|
301668
|
-
|
|
302064
|
+
registerProxyRoute({
|
|
301669
302065
|
forgePath: "/api/cmmd/projects/:id/board/:taskId/status",
|
|
301670
302066
|
method: "PATCH",
|
|
301671
302067
|
cmmdPath: "/api/forge/context/projects/:id/board/:taskId/status",
|
|
301672
302068
|
orgIdSource: "none",
|
|
301673
302069
|
responseShape: "unwrapData"
|
|
301674
302070
|
});
|
|
301675
|
-
|
|
302071
|
+
registerProxyRoute({
|
|
301676
302072
|
forgePath: "/api/cmmd/projects/:id/board/:taskId/execution-options",
|
|
301677
302073
|
method: "GET",
|
|
301678
302074
|
cmmdPath: "/api/forge/context/projects/:id/board/:taskId/execution-options",
|
|
301679
302075
|
orgIdSource: "none",
|
|
301680
302076
|
responseShape: "unwrapData"
|
|
301681
302077
|
});
|
|
301682
|
-
|
|
302078
|
+
registerProxyRoute({
|
|
301683
302079
|
forgePath: "/api/cmmd/projects/:id/board/:taskId/work-sessions",
|
|
301684
302080
|
method: "POST",
|
|
301685
302081
|
cmmdPath: "/api/forge/context/projects/:id/board/:taskId/work-sessions",
|
|
301686
302082
|
orgIdSource: "none",
|
|
301687
302083
|
responseShape: "unwrapData"
|
|
301688
302084
|
});
|
|
301689
|
-
|
|
302085
|
+
registerProxyRoute({
|
|
301690
302086
|
forgePath: "/api/cmmd/projects/:id/work-sessions",
|
|
301691
302087
|
method: "GET",
|
|
301692
302088
|
cmmdPath: "/api/forge/context/projects/:id/work-sessions",
|
|
301693
302089
|
orgIdSource: "none",
|
|
301694
302090
|
responseShape: "unwrapData"
|
|
301695
302091
|
});
|
|
301696
|
-
|
|
302092
|
+
registerProxyRoute({
|
|
301697
302093
|
forgePath: "/api/cmmd/work-sessions/:workSessionId",
|
|
301698
302094
|
method: "GET",
|
|
301699
302095
|
cmmdPath: "/api/forge/context/work-sessions/:workSessionId",
|
|
301700
302096
|
orgIdSource: "none",
|
|
301701
302097
|
responseShape: "unwrapData"
|
|
301702
302098
|
});
|
|
301703
|
-
|
|
302099
|
+
registerProxyRoute({
|
|
301704
302100
|
forgePath: "/api/cmmd/work-sessions/:workSessionId",
|
|
301705
302101
|
method: "PATCH",
|
|
301706
302102
|
cmmdPath: "/api/forge/context/work-sessions/:workSessionId",
|
|
301707
302103
|
orgIdSource: "none",
|
|
301708
302104
|
responseShape: "unwrapData"
|
|
301709
302105
|
});
|
|
301710
|
-
|
|
302106
|
+
registerProxyRoute({
|
|
301711
302107
|
forgePath: "/api/cmmd/work-sessions/:workSessionId/threads",
|
|
301712
302108
|
method: "POST",
|
|
301713
302109
|
cmmdPath: "/api/forge/context/work-sessions/:workSessionId/threads",
|
|
301714
302110
|
orgIdSource: "none",
|
|
301715
302111
|
responseShape: "unwrapData"
|
|
301716
302112
|
});
|
|
301717
|
-
|
|
302113
|
+
registerProxyRoute({
|
|
301718
302114
|
forgePath: "/api/cmmd/tasks/:taskId/conversations",
|
|
301719
302115
|
method: "GET",
|
|
301720
302116
|
cmmdPath: "/api/forge/context/tasks/:taskId/conversations",
|
|
301721
302117
|
orgIdSource: "none",
|
|
301722
302118
|
responseShape: "unwrapData"
|
|
301723
302119
|
});
|
|
301724
|
-
|
|
302120
|
+
registerProxyRoute({
|
|
301725
302121
|
forgePath: "/api/cmmd/tasks/:taskId/conversations",
|
|
301726
302122
|
method: "POST",
|
|
301727
302123
|
cmmdPath: "/api/forge/context/tasks/:taskId/conversations",
|
|
301728
302124
|
orgIdSource: "none",
|
|
301729
302125
|
responseShape: "unwrapData"
|
|
301730
302126
|
});
|
|
301731
|
-
|
|
302127
|
+
registerProxyRoute({
|
|
301732
302128
|
forgePath: "/api/cmmd/tasks/:taskId/history",
|
|
301733
302129
|
method: "GET",
|
|
301734
302130
|
cmmdPath: "/api/forge/context/tasks/:taskId/history",
|
|
301735
302131
|
orgIdSource: "none",
|
|
301736
302132
|
responseShape: "unwrapData"
|
|
301737
302133
|
});
|
|
301738
|
-
|
|
302134
|
+
registerProxyRoute({
|
|
301739
302135
|
forgePath: "/api/cmmd/tasks/:taskId/pull-requests",
|
|
301740
302136
|
method: "PUT",
|
|
301741
302137
|
cmmdPath: "/api/forge/context/tasks/:taskId/pull-requests",
|
|
301742
302138
|
orgIdSource: "none",
|
|
301743
302139
|
responseShape: "unwrapData"
|
|
301744
302140
|
});
|
|
301745
|
-
const
|
|
302141
|
+
for (const path of [
|
|
301746
302142
|
"list",
|
|
301747
302143
|
"list-stats",
|
|
301748
302144
|
"detail",
|
|
@@ -301760,70 +302156,70 @@ const cmmdPullRequestRouteLayers = [
|
|
|
301760
302156
|
"thread/resolution",
|
|
301761
302157
|
"reviewers",
|
|
301762
302158
|
"reaction"
|
|
301763
|
-
]
|
|
302159
|
+
]) registerProxyRoute({
|
|
301764
302160
|
forgePath: `/api/cmmd/pull-requests/${path}`,
|
|
301765
302161
|
method: "POST",
|
|
301766
302162
|
cmmdPath: `/api/forge/context/pull-requests/${path}`,
|
|
301767
302163
|
orgIdSource: "none",
|
|
301768
302164
|
responseShape: "unwrapData"
|
|
301769
|
-
})
|
|
301770
|
-
|
|
302165
|
+
});
|
|
302166
|
+
registerProxyRoute({
|
|
301771
302167
|
forgePath: "/api/cmmd/tasks/:taskId/conversations/:conversationId",
|
|
301772
302168
|
method: "GET",
|
|
301773
302169
|
cmmdPath: "/api/forge/context/tasks/:taskId/conversations/:conversationId",
|
|
301774
302170
|
orgIdSource: "none",
|
|
301775
302171
|
responseShape: "unwrapData"
|
|
301776
302172
|
});
|
|
301777
|
-
|
|
302173
|
+
registerProxyRoute({
|
|
301778
302174
|
forgePath: "/api/cmmd/projects/:id/board/:taskId/spawn-forge-thread",
|
|
301779
302175
|
method: "POST",
|
|
301780
302176
|
cmmdPath: "/api/forge/context/projects/:id/board/:taskId/spawn-forge-thread",
|
|
301781
302177
|
orgIdSource: "none",
|
|
301782
302178
|
responseShape: "unwrapData"
|
|
301783
302179
|
});
|
|
301784
|
-
|
|
302180
|
+
registerProxyRoute({
|
|
301785
302181
|
forgePath: "/api/cmmd/work-items/board",
|
|
301786
302182
|
method: "GET",
|
|
301787
302183
|
cmmdPath: "/api/forge/context/work-items/board",
|
|
301788
302184
|
orgIdSource: "none",
|
|
301789
302185
|
responseShape: "unwrapData"
|
|
301790
302186
|
});
|
|
301791
|
-
|
|
302187
|
+
registerProxyRoute({
|
|
301792
302188
|
forgePath: "/api/cmmd/work-items/board",
|
|
301793
302189
|
method: "POST",
|
|
301794
302190
|
cmmdPath: "/api/forge/context/work-items/board",
|
|
301795
302191
|
orgIdSource: "none",
|
|
301796
302192
|
responseShape: "unwrapData"
|
|
301797
302193
|
});
|
|
301798
|
-
|
|
302194
|
+
registerProxyRoute({
|
|
301799
302195
|
forgePath: "/api/cmmd/feedback",
|
|
301800
302196
|
method: "POST",
|
|
301801
302197
|
cmmdPath: "/api/forge/context/feedback",
|
|
301802
302198
|
orgIdSource: "none",
|
|
301803
302199
|
responseShape: "unwrapData"
|
|
301804
302200
|
});
|
|
301805
|
-
|
|
302201
|
+
registerProxyRoute({
|
|
301806
302202
|
forgePath: "/api/cmmd/work-items/board/:taskId",
|
|
301807
302203
|
method: "PATCH",
|
|
301808
302204
|
cmmdPath: "/api/forge/context/work-items/board/:taskId",
|
|
301809
302205
|
orgIdSource: "none",
|
|
301810
302206
|
responseShape: "unwrapData"
|
|
301811
302207
|
});
|
|
301812
|
-
|
|
302208
|
+
registerProxyRoute({
|
|
301813
302209
|
forgePath: "/api/cmmd/work-items/board/:taskId/move",
|
|
301814
302210
|
method: "PATCH",
|
|
301815
302211
|
cmmdPath: "/api/forge/context/work-items/board/:taskId/move",
|
|
301816
302212
|
orgIdSource: "none",
|
|
301817
302213
|
responseShape: "unwrapData"
|
|
301818
302214
|
});
|
|
301819
|
-
|
|
302215
|
+
registerProxyRoute({
|
|
301820
302216
|
forgePath: "/api/cmmd/projects/:projectId/board/:taskId/move",
|
|
301821
302217
|
method: "PATCH",
|
|
301822
302218
|
cmmdPath: "/api/forge/context/projects/:projectId/board/:taskId/move",
|
|
301823
302219
|
orgIdSource: "none",
|
|
301824
302220
|
responseShape: "unwrapData"
|
|
301825
302221
|
});
|
|
301826
|
-
|
|
302222
|
+
registerProxyRoute({
|
|
301827
302223
|
forgePath: "/api/cmmd/projects/:projectId/board/:taskId/archive",
|
|
301828
302224
|
method: "POST",
|
|
301829
302225
|
cmmdPath: "/api/forge/context/projects/:projectId/board/:taskId/archive",
|
|
@@ -301831,7 +302227,7 @@ const cmmdArchiveProjectBoardTaskRouteLayer = registerProxyRoute({
|
|
|
301831
302227
|
responseShape: "unwrapData",
|
|
301832
302228
|
requestBody: "none"
|
|
301833
302229
|
});
|
|
301834
|
-
|
|
302230
|
+
registerProxyRoute({
|
|
301835
302231
|
forgePath: "/api/cmmd/projects/:projectId/board/:taskId/unarchive",
|
|
301836
302232
|
method: "POST",
|
|
301837
302233
|
cmmdPath: "/api/forge/context/projects/:projectId/board/:taskId/unarchive",
|
|
@@ -301839,7 +302235,7 @@ const cmmdUnarchiveProjectBoardTaskRouteLayer = registerProxyRoute({
|
|
|
301839
302235
|
responseShape: "unwrapData",
|
|
301840
302236
|
requestBody: "none"
|
|
301841
302237
|
});
|
|
301842
|
-
|
|
302238
|
+
registerProxyRoute({
|
|
301843
302239
|
forgePath: "/api/cmmd/work-items/board/:taskId/archive",
|
|
301844
302240
|
method: "POST",
|
|
301845
302241
|
cmmdPath: "/api/forge/context/work-items/board/:taskId/archive",
|
|
@@ -301847,7 +302243,7 @@ const cmmdArchiveCenterBoardTaskRouteLayer = registerProxyRoute({
|
|
|
301847
302243
|
responseShape: "unwrapData",
|
|
301848
302244
|
requestBody: "none"
|
|
301849
302245
|
});
|
|
301850
|
-
|
|
302246
|
+
registerProxyRoute({
|
|
301851
302247
|
forgePath: "/api/cmmd/work-items/board/:taskId/unarchive",
|
|
301852
302248
|
method: "POST",
|
|
301853
302249
|
cmmdPath: "/api/forge/context/work-items/board/:taskId/unarchive",
|
|
@@ -301855,109 +302251,109 @@ const cmmdUnarchiveCenterBoardTaskRouteLayer = registerProxyRoute({
|
|
|
301855
302251
|
responseShape: "unwrapData",
|
|
301856
302252
|
requestBody: "none"
|
|
301857
302253
|
});
|
|
301858
|
-
|
|
302254
|
+
registerProxyRoute({
|
|
301859
302255
|
forgePath: "/api/cmmd/campaigns",
|
|
301860
302256
|
method: "GET",
|
|
301861
302257
|
cmmdPath: "/api/forge/context/campaigns",
|
|
301862
302258
|
orgIdSource: "none",
|
|
301863
302259
|
responseShape: "passthrough"
|
|
301864
302260
|
});
|
|
301865
|
-
|
|
302261
|
+
registerProxyRoute({
|
|
301866
302262
|
forgePath: "/api/cmmd/campaigns/:id",
|
|
301867
302263
|
method: "GET",
|
|
301868
302264
|
cmmdPath: "/api/forge/context/campaigns/:id",
|
|
301869
302265
|
orgIdSource: "none",
|
|
301870
302266
|
responseShape: "passthrough"
|
|
301871
302267
|
});
|
|
301872
|
-
|
|
302268
|
+
registerProxyRoute({
|
|
301873
302269
|
forgePath: "/api/cmmd/campaigns",
|
|
301874
302270
|
method: "POST",
|
|
301875
302271
|
cmmdPath: "/api/projects/campaigns",
|
|
301876
302272
|
responseShape: "passthrough"
|
|
301877
302273
|
});
|
|
301878
|
-
|
|
302274
|
+
registerProxyRoute({
|
|
301879
302275
|
forgePath: "/api/cmmd/campaigns/:id",
|
|
301880
302276
|
method: "PUT",
|
|
301881
302277
|
cmmdPath: "/api/projects/campaigns/:id",
|
|
301882
302278
|
responseShape: "passthrough"
|
|
301883
302279
|
});
|
|
301884
|
-
|
|
302280
|
+
registerProxyRoute({
|
|
301885
302281
|
forgePath: "/api/cmmd/campaigns/:id",
|
|
301886
302282
|
method: "DELETE",
|
|
301887
302283
|
cmmdPath: "/api/projects/campaigns/:id",
|
|
301888
302284
|
orgIdSource: "none"
|
|
301889
302285
|
});
|
|
301890
|
-
|
|
302286
|
+
registerProxyRoute({
|
|
301891
302287
|
forgePath: "/api/cmmd/bootstrap",
|
|
301892
302288
|
method: "GET",
|
|
301893
302289
|
cmmdPath: "/api/forge/context/bootstrap",
|
|
301894
302290
|
orgIdSource: "none",
|
|
301895
302291
|
responseShape: "passthrough"
|
|
301896
302292
|
});
|
|
301897
|
-
|
|
302293
|
+
registerProxyRoute({
|
|
301898
302294
|
forgePath: "/api/cmmd/account/preferences",
|
|
301899
302295
|
method: "GET",
|
|
301900
302296
|
cmmdPath: "/api/forge/context/account/preferences",
|
|
301901
302297
|
orgIdSource: "none",
|
|
301902
302298
|
responseShape: "unwrapData"
|
|
301903
302299
|
});
|
|
301904
|
-
|
|
302300
|
+
registerProxyRoute({
|
|
301905
302301
|
forgePath: "/api/cmmd/account/preferences",
|
|
301906
302302
|
method: "PATCH",
|
|
301907
302303
|
cmmdPath: "/api/forge/context/account/preferences",
|
|
301908
302304
|
orgIdSource: "none",
|
|
301909
302305
|
responseShape: "unwrapData"
|
|
301910
302306
|
});
|
|
301911
|
-
|
|
302307
|
+
registerProxyRoute({
|
|
301912
302308
|
forgePath: "/api/cmmd/org/provider-policy",
|
|
301913
302309
|
method: "GET",
|
|
301914
302310
|
cmmdPath: "/api/forge/context/org/provider-policy",
|
|
301915
302311
|
orgIdSource: "none",
|
|
301916
302312
|
responseShape: "unwrapData"
|
|
301917
302313
|
});
|
|
301918
|
-
|
|
302314
|
+
registerProxyRoute({
|
|
301919
302315
|
forgePath: "/api/cmmd/chats",
|
|
301920
302316
|
method: "GET",
|
|
301921
302317
|
cmmdPath: "/api/forge/context/chats",
|
|
301922
302318
|
orgIdSource: "none",
|
|
301923
302319
|
responseShape: "unwrapData"
|
|
301924
302320
|
});
|
|
301925
|
-
|
|
302321
|
+
registerProxyRoute({
|
|
301926
302322
|
forgePath: "/api/cmmd/chats/:threadId",
|
|
301927
302323
|
method: "GET",
|
|
301928
302324
|
cmmdPath: "/api/forge/context/chats/:threadId",
|
|
301929
302325
|
orgIdSource: "none",
|
|
301930
302326
|
responseShape: "unwrapData"
|
|
301931
302327
|
});
|
|
301932
|
-
|
|
302328
|
+
registerProxyRoute({
|
|
301933
302329
|
forgePath: "/api/cmmd/devices",
|
|
301934
302330
|
method: "GET",
|
|
301935
302331
|
cmmdPath: "/api/forge/context/devices",
|
|
301936
302332
|
orgIdSource: "none",
|
|
301937
302333
|
responseShape: "unwrapData"
|
|
301938
302334
|
});
|
|
301939
|
-
|
|
302335
|
+
registerProxyRoute({
|
|
301940
302336
|
forgePath: "/api/cmmd/devices/register",
|
|
301941
302337
|
method: "POST",
|
|
301942
302338
|
cmmdPath: "/api/forge/context/devices/register",
|
|
301943
302339
|
orgIdSource: "none",
|
|
301944
302340
|
responseShape: "unwrapData"
|
|
301945
302341
|
});
|
|
301946
|
-
|
|
302342
|
+
registerProxyRoute({
|
|
301947
302343
|
forgePath: "/api/cmmd/devices/runtimes/:runtimeId/heartbeat",
|
|
301948
302344
|
method: "POST",
|
|
301949
302345
|
cmmdPath: "/api/forge/context/devices/runtimes/:runtimeId/heartbeat",
|
|
301950
302346
|
orgIdSource: "none",
|
|
301951
302347
|
responseShape: "unwrapData"
|
|
301952
302348
|
});
|
|
301953
|
-
|
|
302349
|
+
registerProxyRoute({
|
|
301954
302350
|
forgePath: "/api/cmmd/devices/runtimes/:runtimeId/access-grants",
|
|
301955
302351
|
method: "POST",
|
|
301956
302352
|
cmmdPath: "/api/forge/context/devices/runtimes/:runtimeId/access-grants",
|
|
301957
302353
|
orgIdSource: "none",
|
|
301958
302354
|
responseShape: "unwrapData"
|
|
301959
302355
|
});
|
|
301960
|
-
|
|
302356
|
+
registerProxyRoute({
|
|
301961
302357
|
forgePath: "/api/cmmd/devices/runtimes/:runtimeId/access-grants/:grantId/revoke",
|
|
301962
302358
|
method: "POST",
|
|
301963
302359
|
cmmdPath: "/api/forge/context/devices/runtimes/:runtimeId/access-grants/:grantId/revoke",
|
|
@@ -301965,46 +302361,60 @@ const cmmdRevokeRuntimeAccessRouteLayer = registerProxyRoute({
|
|
|
301965
302361
|
responseShape: "unwrapData",
|
|
301966
302362
|
successStatus: 200
|
|
301967
302363
|
});
|
|
301968
|
-
|
|
302364
|
+
registerProxyRoute({
|
|
301969
302365
|
forgePath: "/api/cmmd/devices/runtimes/:runtimeId/relay-routes",
|
|
301970
302366
|
method: "POST",
|
|
301971
302367
|
cmmdPath: "/api/forge/context/devices/runtimes/:runtimeId/relay-routes",
|
|
301972
302368
|
orgIdSource: "none",
|
|
301973
302369
|
responseShape: "unwrapData"
|
|
301974
302370
|
});
|
|
301975
|
-
|
|
302371
|
+
registerProxyRoute({
|
|
301976
302372
|
forgePath: "/api/cmmd/devices/runtimes/:runtimeId/relay-action-grants",
|
|
301977
302373
|
method: "POST",
|
|
301978
302374
|
cmmdPath: "/api/forge/context/devices/runtimes/:runtimeId/relay-action-grants",
|
|
301979
302375
|
orgIdSource: "none",
|
|
301980
302376
|
responseShape: "unwrapData"
|
|
301981
302377
|
});
|
|
301982
|
-
|
|
302378
|
+
registerProxyRoute({
|
|
301983
302379
|
forgePath: "/api/cmmd/devices/runtimes/:runtimeId/inventory",
|
|
301984
302380
|
method: "PUT",
|
|
301985
302381
|
cmmdPath: "/api/forge/context/devices/runtimes/:runtimeId/inventory",
|
|
301986
302382
|
orgIdSource: "none",
|
|
301987
302383
|
responseShape: "unwrapData"
|
|
301988
302384
|
});
|
|
301989
|
-
|
|
302385
|
+
registerProxyRoute({
|
|
301990
302386
|
forgePath: "/api/cmmd/runtime-inventory",
|
|
301991
302387
|
method: "GET",
|
|
301992
302388
|
cmmdPath: "/api/forge/context/runtime-inventory",
|
|
301993
302389
|
orgIdSource: "none",
|
|
301994
302390
|
responseShape: "unwrapData"
|
|
301995
302391
|
});
|
|
302392
|
+
registerProxyRoute({
|
|
302393
|
+
forgePath: "/api/cmmd/threads/:runtimeId/:threadId/lifecycle-intent",
|
|
302394
|
+
method: "PUT",
|
|
302395
|
+
cmmdPath: "/api/forge/context/threads/:runtimeId/:threadId/lifecycle-intent",
|
|
302396
|
+
orgIdSource: "none",
|
|
302397
|
+
requestBody: "json",
|
|
302398
|
+
responseShape: "unwrapData"
|
|
302399
|
+
});
|
|
302400
|
+
registerProxyRoute({
|
|
302401
|
+
forgePath: "/api/cmmd/threads/:runtimeId/:threadId/lifecycle-intent",
|
|
302402
|
+
method: "DELETE",
|
|
302403
|
+
cmmdPath: "/api/forge/context/threads/:runtimeId/:threadId/lifecycle-intent",
|
|
302404
|
+
orgIdSource: "none"
|
|
302405
|
+
});
|
|
301996
302406
|
/**
|
|
301997
302407
|
* Owner-scoped, bounded control-plane observation. This is intentionally
|
|
301998
302408
|
* separate from the runtime inventory publisher and never wakes a runtime.
|
|
301999
302409
|
*/
|
|
302000
|
-
|
|
302410
|
+
registerProxyRoute({
|
|
302001
302411
|
forgePath: "/api/cmmd/runtime-diagnostics/v2/runtimes/:runtimeId",
|
|
302002
302412
|
method: "GET",
|
|
302003
302413
|
cmmdPath: "/api/forge/context/runtime-diagnostics/v2/runtimes/:runtimeId",
|
|
302004
302414
|
orgIdSource: "none",
|
|
302005
302415
|
responseShape: "unwrapData"
|
|
302006
302416
|
});
|
|
302007
|
-
|
|
302417
|
+
registerProxyRoute({
|
|
302008
302418
|
forgePath: "/api/cmmd/auth-runtime",
|
|
302009
302419
|
method: "POST",
|
|
302010
302420
|
cmmdPath: "/api/forge/context/auth-runtime",
|
|
@@ -302012,21 +302422,21 @@ const cmmdProvisionAuthRuntimeRouteLayer = registerProxyRoute({
|
|
|
302012
302422
|
responseShape: "unwrapData",
|
|
302013
302423
|
requestBody: "none"
|
|
302014
302424
|
});
|
|
302015
|
-
|
|
302425
|
+
registerProxyRoute({
|
|
302016
302426
|
forgePath: "/api/cmmd/auth-runtime",
|
|
302017
302427
|
method: "GET",
|
|
302018
302428
|
cmmdPath: "/api/forge/context/auth-runtime",
|
|
302019
302429
|
orgIdSource: "none",
|
|
302020
302430
|
responseShape: "unwrapData"
|
|
302021
302431
|
});
|
|
302022
|
-
|
|
302432
|
+
registerProxyRoute({
|
|
302023
302433
|
forgePath: "/api/cmmd/auth-runtime",
|
|
302024
302434
|
method: "DELETE",
|
|
302025
302435
|
cmmdPath: "/api/forge/context/auth-runtime",
|
|
302026
302436
|
orgIdSource: "none",
|
|
302027
302437
|
responseShape: "unwrapData"
|
|
302028
302438
|
});
|
|
302029
|
-
|
|
302439
|
+
registerProxyRoute({
|
|
302030
302440
|
forgePath: "/api/cmmd/auth-runtime/connect",
|
|
302031
302441
|
method: "POST",
|
|
302032
302442
|
cmmdPath: "/api/forge/context/auth-runtime/connect",
|
|
@@ -302034,14 +302444,14 @@ const cmmdConnectAuthRuntimeRouteLayer = registerProxyRoute({
|
|
|
302034
302444
|
responseShape: "unwrapData",
|
|
302035
302445
|
requestBody: "none"
|
|
302036
302446
|
});
|
|
302037
|
-
|
|
302447
|
+
registerProxyRoute({
|
|
302038
302448
|
forgePath: "/api/cmmd/providers/accounts",
|
|
302039
302449
|
method: "GET",
|
|
302040
302450
|
cmmdPath: "/api/forge/context/providers/accounts",
|
|
302041
302451
|
orgIdSource: "none",
|
|
302042
302452
|
responseShape: "unwrapData"
|
|
302043
302453
|
});
|
|
302044
|
-
|
|
302454
|
+
registerProxyRoute({
|
|
302045
302455
|
forgePath: "/api/cmmd/providers/accounts/:id",
|
|
302046
302456
|
method: "DELETE",
|
|
302047
302457
|
cmmdPath: "/api/forge/context/providers/accounts/:id",
|
|
@@ -302049,23 +302459,29 @@ const cmmdDeleteProviderAccountRouteLayer = registerProxyRoute({
|
|
|
302049
302459
|
responseShape: "unwrapData",
|
|
302050
302460
|
requestBody: "none"
|
|
302051
302461
|
});
|
|
302052
|
-
|
|
302462
|
+
registerProxyRoute({
|
|
302053
302463
|
forgePath: "/api/cmmd/providers/accounts/default",
|
|
302054
302464
|
method: "PUT",
|
|
302055
302465
|
cmmdPath: "/api/forge/context/providers/accounts/default",
|
|
302056
302466
|
orgIdSource: "none",
|
|
302057
302467
|
responseShape: "unwrapData"
|
|
302058
302468
|
});
|
|
302059
|
-
|
|
302060
|
-
|
|
302061
|
-
|
|
302469
|
+
registerProxyHandler({
|
|
302470
|
+
forgePath: "/api/cmmd/providers/usage",
|
|
302471
|
+
method: "GET",
|
|
302472
|
+
parse: () => succeed({
|
|
302473
|
+
ok: true,
|
|
302474
|
+
value: void 0
|
|
302475
|
+
}),
|
|
302476
|
+
run: (_parsed, { session }) => runCmmdRestProxyAsHandlerResult(session, (jwt) => cmmdGateway.request({
|
|
302062
302477
|
method: "GET",
|
|
302063
302478
|
jwt,
|
|
302064
302479
|
path: "/api/forge/context/providers/usage"
|
|
302065
|
-
}))
|
|
302066
|
-
|
|
302067
|
-
|
|
302068
|
-
})
|
|
302480
|
+
}), (value) => ({
|
|
302481
|
+
status: 200,
|
|
302482
|
+
body: unwrapForgeEnvelope(value)
|
|
302483
|
+
}))
|
|
302484
|
+
});
|
|
302069
302485
|
function parseProviderUsageRefreshInput(rawBody) {
|
|
302070
302486
|
if (rawBody === null || typeof rawBody !== "object") return null;
|
|
302071
302487
|
const body = rawBody;
|
|
@@ -302147,56 +302563,56 @@ function makeRefreshProviderUsageHandler(dependencies = {}) {
|
|
|
302147
302563
|
}).pipe(catchTag("AuthError", (error) => respondToAuthError(error)));
|
|
302148
302564
|
}
|
|
302149
302565
|
const cmmdRefreshProviderUsageRouteLayer = add$1("POST", "/api/cmmd/providers/usage/refresh", makeRefreshProviderUsageHandler());
|
|
302150
|
-
|
|
302566
|
+
registerProxyRoute({
|
|
302151
302567
|
forgePath: "/api/cmmd/providers/codex/credential",
|
|
302152
302568
|
method: "GET",
|
|
302153
302569
|
cmmdPath: "/api/forge/context/providers/codex/credential",
|
|
302154
302570
|
orgIdSource: "none",
|
|
302155
302571
|
responseShape: "unwrapData"
|
|
302156
302572
|
});
|
|
302157
|
-
|
|
302573
|
+
registerProxyRoute({
|
|
302158
302574
|
forgePath: "/api/cmmd/providers/codex/credential",
|
|
302159
302575
|
method: "DELETE",
|
|
302160
302576
|
cmmdPath: "/api/forge/context/providers/codex/credential",
|
|
302161
302577
|
orgIdSource: "none",
|
|
302162
302578
|
responseShape: "unwrapData"
|
|
302163
302579
|
});
|
|
302164
|
-
|
|
302580
|
+
registerProxyRoute({
|
|
302165
302581
|
forgePath: "/api/cmmd/providers/claude/credential",
|
|
302166
302582
|
method: "GET",
|
|
302167
302583
|
cmmdPath: "/api/forge/context/providers/claude/credential",
|
|
302168
302584
|
orgIdSource: "none",
|
|
302169
302585
|
responseShape: "unwrapData"
|
|
302170
302586
|
});
|
|
302171
|
-
|
|
302587
|
+
registerProxyRoute({
|
|
302172
302588
|
forgePath: "/api/cmmd/providers/claude/credential",
|
|
302173
302589
|
method: "DELETE",
|
|
302174
302590
|
cmmdPath: "/api/forge/context/providers/claude/credential",
|
|
302175
302591
|
orgIdSource: "none",
|
|
302176
302592
|
responseShape: "unwrapData"
|
|
302177
302593
|
});
|
|
302178
|
-
|
|
302594
|
+
registerProxyRoute({
|
|
302179
302595
|
forgePath: "/api/cmmd/providers/claude/runtime-readiness/:runtimeId",
|
|
302180
302596
|
method: "GET",
|
|
302181
302597
|
cmmdPath: "/api/forge/context/providers/claude/runtime-readiness/:runtimeId",
|
|
302182
302598
|
orgIdSource: "none",
|
|
302183
302599
|
responseShape: "unwrapData"
|
|
302184
302600
|
});
|
|
302185
|
-
|
|
302601
|
+
registerProxyRoute({
|
|
302186
302602
|
forgePath: "/api/cmmd/devices/runtimes/:runtimeId/threads/:threadId/events",
|
|
302187
302603
|
method: "POST",
|
|
302188
302604
|
cmmdPath: "/api/forge/context/devices/runtimes/:runtimeId/threads/:threadId/events",
|
|
302189
302605
|
orgIdSource: "none",
|
|
302190
302606
|
responseShape: "unwrapData"
|
|
302191
302607
|
});
|
|
302192
|
-
|
|
302608
|
+
registerProxyRoute({
|
|
302193
302609
|
forgePath: "/api/cmmd/threads/:runtimeId/:threadId",
|
|
302194
302610
|
method: "GET",
|
|
302195
302611
|
cmmdPath: "/api/forge/context/threads/:runtimeId/:threadId",
|
|
302196
302612
|
orgIdSource: "none",
|
|
302197
302613
|
responseShape: "unwrapData"
|
|
302198
302614
|
});
|
|
302199
|
-
|
|
302615
|
+
registerProxyRoute({
|
|
302200
302616
|
forgePath: "/api/cmmd/devices/:deviceId/rename",
|
|
302201
302617
|
method: "POST",
|
|
302202
302618
|
cmmdPath: "/api/forge/context/devices/:deviceId/rename",
|
|
@@ -302212,7 +302628,7 @@ const cmmdRenameDeviceRouteLayer = registerProxyRoute({
|
|
|
302212
302628
|
* the status and the code reach the browser unchanged, which is what lets the
|
|
302213
302629
|
* rename field say something specific instead of "something went wrong".
|
|
302214
302630
|
*/
|
|
302215
|
-
|
|
302631
|
+
registerProxyRoute({
|
|
302216
302632
|
forgePath: "/api/cmmd/forge-runtimes/:runtimeId/rename",
|
|
302217
302633
|
method: "POST",
|
|
302218
302634
|
cmmdPath: "/api/forge/context/runtimes/:runtimeId/rename",
|
|
@@ -302220,7 +302636,7 @@ const cmmdRenameForgeRuntimeRouteLayer = registerProxyRoute({
|
|
|
302220
302636
|
responseShape: "unwrapData",
|
|
302221
302637
|
successStatus: 200
|
|
302222
302638
|
});
|
|
302223
|
-
|
|
302639
|
+
registerProxyRoute({
|
|
302224
302640
|
forgePath: "/api/cmmd/devices/:deviceId/revoke",
|
|
302225
302641
|
method: "POST",
|
|
302226
302642
|
cmmdPath: "/api/forge/context/devices/:deviceId/revoke",
|
|
@@ -302229,24 +302645,21 @@ const cmmdRevokeDeviceRouteLayer = registerProxyRoute({
|
|
|
302229
302645
|
requestBody: "none",
|
|
302230
302646
|
successStatus: 200
|
|
302231
302647
|
});
|
|
302232
|
-
|
|
302648
|
+
registerProxyRoute({
|
|
302233
302649
|
forgePath: "/api/cmmd/connectors",
|
|
302234
302650
|
method: "GET",
|
|
302235
302651
|
cmmdPath: "/api/forge/context/connectors",
|
|
302236
302652
|
orgIdSource: "none"
|
|
302237
302653
|
});
|
|
302238
|
-
|
|
302654
|
+
registerProxyRoute({
|
|
302239
302655
|
forgePath: "/api/cmmd/connectors/:connectorId/install",
|
|
302240
302656
|
method: "POST",
|
|
302241
302657
|
cmmdPath: "/api/forge/context/connectors/:connectorId/install",
|
|
302242
302658
|
orgIdSource: "none"
|
|
302243
302659
|
});
|
|
302244
302660
|
const cmmdForgeCloudProjectsListRouteLayer = add$1("GET", "/api/cmmd/forge-cloud-projects", gen(function* () {
|
|
302245
|
-
const accessToken = yield* makeCmmdProxyAccessTokenEffect("forge-cloud-projects");
|
|
302246
|
-
if (!accessToken) return
|
|
302247
|
-
code: "CMMD_AUTH_REQUIRED",
|
|
302248
|
-
message: "CMMD authentication is required. Sign in again to continue."
|
|
302249
|
-
});
|
|
302661
|
+
const { session, jwt: accessToken } = yield* makeCmmdProxyAccessTokenEffect("forge-cloud-projects");
|
|
302662
|
+
if (!accessToken) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
302250
302663
|
const upstreamUrl = `${resolveCommandAppUrl()}${CMMD_CLOUD_PROJECTS_PATH}`;
|
|
302251
302664
|
const upstreamOrError = yield* fetchCmmdUpstreamWithRetry(() => fetch(upstreamUrl, { headers: {
|
|
302252
302665
|
Authorization: `Bearer ${accessToken}`,
|
|
@@ -302257,10 +302670,7 @@ const cmmdForgeCloudProjectsListRouteLayer = add$1("GET", "/api/cmmd/forge-cloud
|
|
|
302257
302670
|
code: "CMMD_UNAVAILABLE"
|
|
302258
302671
|
}, { status: 503 });
|
|
302259
302672
|
const upstream = upstreamOrError.res;
|
|
302260
|
-
if (upstream.status === 401 || upstream.status === 403) return
|
|
302261
|
-
code: "CMMD_AUTH_REQUIRED",
|
|
302262
|
-
message: "CMMD authentication expired. Sign in again to continue."
|
|
302263
|
-
});
|
|
302673
|
+
if (upstream.status === 401 || upstream.status === 403) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
302264
302674
|
const bodyOrError = yield* tryPromise(() => upstream.text()).pipe(map$3((text) => ({
|
|
302265
302675
|
ok: true,
|
|
302266
302676
|
text
|
|
@@ -302282,35 +302692,35 @@ const cmmdForgeCloudProjectsListRouteLayer = add$1("GET", "/api/cmmd/forge-cloud
|
|
|
302282
302692
|
headers: { "content-type": "application/json" }
|
|
302283
302693
|
});
|
|
302284
302694
|
}).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
|
|
302285
|
-
|
|
302695
|
+
registerProxyRoute({
|
|
302286
302696
|
forgePath: "/api/cmmd/forge-cloud-projects",
|
|
302287
302697
|
method: "POST",
|
|
302288
302698
|
cmmdPath: CMMD_CLOUD_PROJECTS_PATH,
|
|
302289
302699
|
orgIdSource: "none",
|
|
302290
302700
|
responseShape: "unwrapData"
|
|
302291
302701
|
});
|
|
302292
|
-
|
|
302702
|
+
registerProxyRoute({
|
|
302293
302703
|
forgePath: "/api/cmmd/forge-cloud-projects/:projectId",
|
|
302294
302704
|
method: "DELETE",
|
|
302295
302705
|
cmmdPath: `${CMMD_CLOUD_PROJECTS_PATH}/:projectId`,
|
|
302296
302706
|
orgIdSource: "none",
|
|
302297
302707
|
responseShape: "unwrapData"
|
|
302298
302708
|
});
|
|
302299
|
-
|
|
302709
|
+
registerProxyRoute({
|
|
302300
302710
|
forgePath: "/api/cmmd/forge-cloud-projects/:projectId/lifecycle-preflight",
|
|
302301
302711
|
method: "GET",
|
|
302302
302712
|
cmmdPath: `${CMMD_CLOUD_PROJECTS_PATH}/:projectId/lifecycle-preflight`,
|
|
302303
302713
|
orgIdSource: "none",
|
|
302304
302714
|
responseShape: "unwrapData"
|
|
302305
302715
|
});
|
|
302306
|
-
|
|
302716
|
+
registerProxyRoute({
|
|
302307
302717
|
forgePath: "/api/cmmd/forge-cloud-projects/:projectId/removal-preview",
|
|
302308
302718
|
method: "GET",
|
|
302309
302719
|
cmmdPath: `${CMMD_CLOUD_PROJECTS_PATH}/:projectId/removal-preview`,
|
|
302310
302720
|
orgIdSource: "none",
|
|
302311
302721
|
responseShape: "unwrapData"
|
|
302312
302722
|
});
|
|
302313
|
-
|
|
302723
|
+
registerProxyRoute({
|
|
302314
302724
|
forgePath: "/api/cmmd/forge-cloud-projects/:projectId/removal",
|
|
302315
302725
|
method: "POST",
|
|
302316
302726
|
cmmdPath: `${CMMD_CLOUD_PROJECTS_PATH}/:projectId/removal`,
|
|
@@ -302319,7 +302729,7 @@ const cmmdForgeCloudProjectRemovalRouteLayer = registerProxyRoute({
|
|
|
302319
302729
|
successStatus: 202,
|
|
302320
302730
|
workIntakeInvalidation: "completedPermanentRemoval"
|
|
302321
302731
|
});
|
|
302322
|
-
|
|
302732
|
+
registerProxyRoute({
|
|
302323
302733
|
forgePath: "/api/cmmd/forge-cloud-project-removals/:operationId",
|
|
302324
302734
|
method: "GET",
|
|
302325
302735
|
cmmdPath: `${CMMD_CLOUD_PROJECTS_PATH}/removals/:operationId`,
|
|
@@ -302383,11 +302793,8 @@ function makeFetchCloudProjectsFrameEffect(upstreamUrl, accessToken) {
|
|
|
302383
302793
|
})).pipe(catch_(() => succeed(null)));
|
|
302384
302794
|
}
|
|
302385
302795
|
const cmmdForgeCloudProjectsEventsRouteLayer = add$1("GET", "/api/cmmd/forge-cloud-projects/events", gen(function* () {
|
|
302386
|
-
const accessToken = yield* makeCmmdProxyAccessTokenEffect("forge-cloud-projects/events");
|
|
302387
|
-
if (!accessToken) return
|
|
302388
|
-
code: "CMMD_AUTH_REQUIRED",
|
|
302389
|
-
message: "CMMD authentication is required. Sign in again to continue."
|
|
302390
|
-
});
|
|
302796
|
+
const { session, jwt: accessToken } = yield* makeCmmdProxyAccessTokenEffect("forge-cloud-projects/events");
|
|
302797
|
+
if (!accessToken) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
302391
302798
|
const fetchCloudProjectsFrame = makeFetchCloudProjectsFrameEffect(`${resolveCommandAppUrl()}${CMMD_CLOUD_PROJECTS_PATH}`, accessToken);
|
|
302392
302799
|
const dataStream = concat$2(fromEffect(fetchCloudProjectsFrame), tick(FORGE_RUNTIMES_POLL_INTERVAL).pipe(mapEffect$1(() => fetchCloudProjectsFrame))).pipe(filter$2((frame) => frame !== null));
|
|
302393
302800
|
const keepaliveStream = tick(FORGE_RUNTIMES_KEEPALIVE_INTERVAL).pipe(map$7(() => FORGE_RUNTIMES_KEEPALIVE_FRAME));
|
|
@@ -302459,11 +302866,8 @@ function fetchCmmdUpstreamWithRetry(send, policy = "idempotent") {
|
|
|
302459
302866
|
}
|
|
302460
302867
|
const cmmdForgeRuntimesEnsureRouteLayer = add$1("POST", "/api/cmmd/forge-runtimes/ensure", gen(function* () {
|
|
302461
302868
|
const request = yield* HttpServerRequest;
|
|
302462
|
-
const accessToken = yield* makeCmmdProxyAccessTokenEffect("forge-runtimes/ensure");
|
|
302463
|
-
if (!accessToken) return
|
|
302464
|
-
code: "CMMD_AUTH_REQUIRED",
|
|
302465
|
-
message: "CMMD authentication is required. Sign in again to continue."
|
|
302466
|
-
});
|
|
302869
|
+
const { session, jwt: accessToken } = yield* makeCmmdProxyAccessTokenEffect("forge-runtimes/ensure");
|
|
302870
|
+
if (!accessToken) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
302467
302871
|
const scopedBody = splitCmmdRuntimeOrganizationScope(yield* request.json.pipe(catch_(() => succeed({}))));
|
|
302468
302872
|
if (!scopedBody) return jsonUnsafe({ error: "A valid organizationId is required when organization scope is provided." }, { status: 400 });
|
|
302469
302873
|
const upstreamUrl = `${resolveCommandAppUrl()}/api/forge/context/runtimes/ensure`;
|
|
@@ -302482,10 +302886,7 @@ const cmmdForgeRuntimesEnsureRouteLayer = add$1("POST", "/api/cmmd/forge-runtime
|
|
|
302482
302886
|
code: "CMMD_UNAVAILABLE"
|
|
302483
302887
|
}, { status: 503 });
|
|
302484
302888
|
const upstream = upstreamOrError.res;
|
|
302485
|
-
if (upstream.status === 401 || upstream.status === 403) return
|
|
302486
|
-
code: "CMMD_AUTH_REQUIRED",
|
|
302487
|
-
message: "CMMD authentication expired. Sign in again to continue."
|
|
302488
|
-
});
|
|
302889
|
+
if (upstream.status === 401 || upstream.status === 403) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
302489
302890
|
const bodyOrError = yield* tryPromise(() => upstream.text()).pipe(map$3((text) => ({
|
|
302490
302891
|
ok: true,
|
|
302491
302892
|
text
|
|
@@ -302509,11 +302910,8 @@ const cmmdForgeRuntimesEnsureRouteLayer = add$1("POST", "/api/cmmd/forge-runtime
|
|
|
302509
302910
|
}).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
|
|
302510
302911
|
const cmmdForgeRuntimesConnectRouteLayer = add$1("POST", "/api/cmmd/forge-runtimes/:runtimeId/connect", gen(function* () {
|
|
302511
302912
|
const request = yield* HttpServerRequest;
|
|
302512
|
-
const accessToken = yield* makeCmmdProxyAccessTokenEffect("forge-runtimes/connect");
|
|
302513
|
-
if (!accessToken) return
|
|
302514
|
-
code: "CMMD_AUTH_REQUIRED",
|
|
302515
|
-
message: "CMMD authentication is required. Sign in again to continue."
|
|
302516
|
-
});
|
|
302913
|
+
const { session, jwt: accessToken } = yield* makeCmmdProxyAccessTokenEffect("forge-runtimes/connect");
|
|
302914
|
+
if (!accessToken) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
302517
302915
|
const runtimeId = extractIdFromPath(new URL(request.url, "http://localhost").pathname, 2);
|
|
302518
302916
|
if (!runtimeId) return jsonUnsafe({ error: "Runtime ID is required." }, { status: 400 });
|
|
302519
302917
|
const scopedBody = splitCmmdRuntimeOrganizationScope(yield* request.json.pipe(catch_(() => succeed({}))));
|
|
@@ -302534,10 +302932,7 @@ const cmmdForgeRuntimesConnectRouteLayer = add$1("POST", "/api/cmmd/forge-runtim
|
|
|
302534
302932
|
code: "CMMD_UNAVAILABLE"
|
|
302535
302933
|
}, { status: 503 });
|
|
302536
302934
|
const upstream = upstreamOrError.res;
|
|
302537
|
-
if (upstream.status === 401 || upstream.status === 403) return
|
|
302538
|
-
code: "CMMD_AUTH_REQUIRED",
|
|
302539
|
-
message: "CMMD authentication expired. Sign in again to continue."
|
|
302540
|
-
});
|
|
302935
|
+
if (upstream.status === 401 || upstream.status === 403) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
302541
302936
|
const bodyOrError = yield* tryPromise(() => upstream.text()).pipe(map$3((text) => ({
|
|
302542
302937
|
ok: true,
|
|
302543
302938
|
text
|
|
@@ -302561,11 +302956,8 @@ const cmmdForgeRuntimesConnectRouteLayer = add$1("POST", "/api/cmmd/forge-runtim
|
|
|
302561
302956
|
}).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
|
|
302562
302957
|
const cmmdForgeRuntimesStatusRouteLayer = add$1("GET", "/api/cmmd/forge-runtimes/:runtimeId/status", gen(function* () {
|
|
302563
302958
|
const request = yield* HttpServerRequest;
|
|
302564
|
-
const accessToken = yield* makeCmmdProxyAccessTokenEffect("forge-runtimes/status");
|
|
302565
|
-
if (!accessToken) return
|
|
302566
|
-
code: "CMMD_AUTH_REQUIRED",
|
|
302567
|
-
message: "CMMD authentication is required. Sign in again to continue."
|
|
302568
|
-
});
|
|
302959
|
+
const { session, jwt: accessToken } = yield* makeCmmdProxyAccessTokenEffect("forge-runtimes/status");
|
|
302960
|
+
if (!accessToken) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
302569
302961
|
const runtimeId = extractIdFromPath(new URL(request.url, "http://localhost").pathname, 2);
|
|
302570
302962
|
if (!runtimeId) return jsonUnsafe({ error: "Runtime ID is required." }, { status: 400 });
|
|
302571
302963
|
const upstreamUrl = `${resolveCommandAppUrl()}/api/forge/context/runtimes/${encodeURIComponent(runtimeId)}/status`;
|
|
@@ -302581,10 +302973,7 @@ const cmmdForgeRuntimesStatusRouteLayer = add$1("GET", "/api/cmmd/forge-runtimes
|
|
|
302581
302973
|
code: "CMMD_UNAVAILABLE"
|
|
302582
302974
|
}, { status: 503 });
|
|
302583
302975
|
const upstream = upstreamOrError.res;
|
|
302584
|
-
if (upstream.status === 401 || upstream.status === 403) return
|
|
302585
|
-
code: "CMMD_AUTH_REQUIRED",
|
|
302586
|
-
message: "CMMD authentication expired. Sign in again to continue."
|
|
302587
|
-
});
|
|
302976
|
+
if (upstream.status === 401 || upstream.status === 403) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
302588
302977
|
const bodyOrError = yield* tryPromise(() => upstream.text()).pipe(map$3((text) => ({
|
|
302589
302978
|
ok: true,
|
|
302590
302979
|
text
|
|
@@ -302615,10 +303004,7 @@ function makeCmmdForgeRuntimesLifecycleHandler(action) {
|
|
|
302615
303004
|
subject: session.subject,
|
|
302616
303005
|
logPrefix: `forge-runtimes/${action}`
|
|
302617
303006
|
});
|
|
302618
|
-
if (!accessToken) return
|
|
302619
|
-
code: "CMMD_AUTH_REQUIRED",
|
|
302620
|
-
message: "CMMD authentication is required. Sign in again to continue."
|
|
302621
|
-
});
|
|
303007
|
+
if (!accessToken) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
302622
303008
|
const runtimeId = extractIdFromPath(new URL(request.url, "http://localhost").pathname, 2);
|
|
302623
303009
|
if (!runtimeId) return jsonUnsafe({ error: "Runtime ID is required." }, { status: 400 });
|
|
302624
303010
|
const scopedBody = splitCmmdRuntimeOrganizationScope(yield* request.json.pipe(catch_(() => succeed({}))));
|
|
@@ -302639,10 +303025,7 @@ function makeCmmdForgeRuntimesLifecycleHandler(action) {
|
|
|
302639
303025
|
code: "CMMD_UNAVAILABLE"
|
|
302640
303026
|
}, { status: 503 });
|
|
302641
303027
|
const upstream = upstreamOrError.res;
|
|
302642
|
-
if (upstream.status === 401 || upstream.status === 403) return
|
|
302643
|
-
code: "CMMD_AUTH_REQUIRED",
|
|
302644
|
-
message: "CMMD authentication expired. Sign in again to continue."
|
|
302645
|
-
});
|
|
303028
|
+
if (upstream.status === 401 || upstream.status === 403) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
302646
303029
|
const bodyOrError = yield* tryPromise(() => upstream.text()).pipe(map$3((text) => ({
|
|
302647
303030
|
ok: true,
|
|
302648
303031
|
text
|
|
@@ -302675,11 +303058,8 @@ const cmmdForgeRuntimesRecycleRouteLayer = add$1("POST", "/api/cmmd/forge-runtim
|
|
|
302675
303058
|
const cmmdForgeRuntimesUpdateCommitRouteLayer = add$1("POST", "/api/cmmd/forge-runtimes/:runtimeId/update-commit", __cmmdForgeRuntimesUpdateCommitHandlerForTests);
|
|
302676
303059
|
const cmmdForgeRuntimesDestroyRouteLayer = add$1("POST", "/api/cmmd/forge-runtimes/:runtimeId/destroy", gen(function* () {
|
|
302677
303060
|
const request = yield* HttpServerRequest;
|
|
302678
|
-
const accessToken = yield* makeCmmdProxyAccessTokenEffect("forge-runtimes/destroy");
|
|
302679
|
-
if (!accessToken) return
|
|
302680
|
-
code: "CMMD_AUTH_REQUIRED",
|
|
302681
|
-
message: "CMMD authentication is required. Sign in again to continue."
|
|
302682
|
-
});
|
|
303061
|
+
const { session, jwt: accessToken } = yield* makeCmmdProxyAccessTokenEffect("forge-runtimes/destroy");
|
|
303062
|
+
if (!accessToken) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
302683
303063
|
const runtimeId = extractIdFromPath(new URL(request.url, "http://localhost").pathname, 2);
|
|
302684
303064
|
if (!runtimeId) return jsonUnsafe({ error: "Runtime ID is required." }, { status: 400 });
|
|
302685
303065
|
const scopedBody = splitCmmdRuntimeOrganizationScope(yield* request.json.pipe(catch_(() => succeed({}))));
|
|
@@ -302700,10 +303080,7 @@ const cmmdForgeRuntimesDestroyRouteLayer = add$1("POST", "/api/cmmd/forge-runtim
|
|
|
302700
303080
|
code: "CMMD_UNAVAILABLE"
|
|
302701
303081
|
}, { status: 503 });
|
|
302702
303082
|
const upstream = upstreamOrError.res;
|
|
302703
|
-
if (upstream.status === 401 || upstream.status === 403) return
|
|
302704
|
-
code: "CMMD_AUTH_REQUIRED",
|
|
302705
|
-
message: "CMMD authentication expired. Sign in again to continue."
|
|
302706
|
-
});
|
|
303083
|
+
if (upstream.status === 401 || upstream.status === 403) return yield* respondCmmdConnectionRequired(session.sessionId);
|
|
302707
303084
|
const bodyOrError = yield* tryPromise(() => upstream.text()).pipe(map$3((text) => ({
|
|
302708
303085
|
ok: true,
|
|
302709
303086
|
text
|
|
@@ -302725,6 +303102,7 @@ const cmmdForgeRuntimesDestroyRouteLayer = add$1("POST", "/api/cmmd/forge-runtim
|
|
|
302725
303102
|
headers: { "content-type": "application/json" }
|
|
302726
303103
|
});
|
|
302727
303104
|
}).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
|
|
303105
|
+
const cmmdProxyRouteLayers = registeredProxyRouteLayers().slice(__cmmdProxyRouteLayersStartIndex);
|
|
302728
303106
|
//#endregion
|
|
302729
303107
|
//#region src/cmmdData/projectTeamProxyRoutes.ts
|
|
302730
303108
|
const cmmdListWorkspaceMembersRouteLayer = registerProxyRoute({
|
|
@@ -303967,6 +304345,103 @@ function recordRuntimeReplicationOutboxDiagnostics(diagnostics, now = Date.now()
|
|
|
303967
304345
|
]).pipe(asVoid);
|
|
303968
304346
|
}
|
|
303969
304347
|
//#endregion
|
|
304348
|
+
//#region src/runtimeReplication/pendingLifecycleIntents.ts
|
|
304349
|
+
/**
|
|
304350
|
+
* The newest moment a person or a turn touched this thread, mirroring the
|
|
304351
|
+
* client's `threadLastActivityAt` over the full thread rather than its shell:
|
|
304352
|
+
* the shell's `latestUserMessageAt` is projected from exactly these messages.
|
|
304353
|
+
*/
|
|
304354
|
+
function readModelThreadLastActivityAt(thread) {
|
|
304355
|
+
const candidates = [
|
|
304356
|
+
...thread.messages.filter((message) => message.role === "user").map((m) => m.createdAt),
|
|
304357
|
+
thread.latestTurn?.requestedAt,
|
|
304358
|
+
thread.latestTurn?.startedAt,
|
|
304359
|
+
thread.latestTurn?.completedAt
|
|
304360
|
+
];
|
|
304361
|
+
let latest = null;
|
|
304362
|
+
let latestTimestamp = Number.NEGATIVE_INFINITY;
|
|
304363
|
+
for (const candidate of candidates) {
|
|
304364
|
+
if (candidate === null || candidate === void 0) continue;
|
|
304365
|
+
const timestamp = Date.parse(candidate);
|
|
304366
|
+
if (timestamp > latestTimestamp) {
|
|
304367
|
+
latest = candidate;
|
|
304368
|
+
latestTimestamp = timestamp;
|
|
304369
|
+
}
|
|
304370
|
+
}
|
|
304371
|
+
return latest;
|
|
304372
|
+
}
|
|
304373
|
+
function intentIsSpent(thread, intent) {
|
|
304374
|
+
const lastActivityAt = readModelThreadLastActivityAt(thread);
|
|
304375
|
+
if (lastActivityAt === null) return false;
|
|
304376
|
+
const activity = Date.parse(lastActivityAt);
|
|
304377
|
+
const requested = Date.parse(intent.requestedAt);
|
|
304378
|
+
return Number.isFinite(activity) && Number.isFinite(requested) && activity > requested;
|
|
304379
|
+
}
|
|
304380
|
+
function commandFor(runtimeId, intent) {
|
|
304381
|
+
const commandId = lifecycleIntentCommandId(runtimeId, intent.threadId, intent.requestedAt);
|
|
304382
|
+
const threadId = ThreadId.make(intent.threadId);
|
|
304383
|
+
return intent.action === "settle" ? {
|
|
304384
|
+
type: "thread.settle",
|
|
304385
|
+
commandId,
|
|
304386
|
+
threadId,
|
|
304387
|
+
settledOverride: "settled"
|
|
304388
|
+
} : {
|
|
304389
|
+
type: "thread.unsettle",
|
|
304390
|
+
commandId,
|
|
304391
|
+
threadId
|
|
304392
|
+
};
|
|
304393
|
+
}
|
|
304394
|
+
const applyOne = fn$1("applyLifecycleIntent")(function* (runtimeId, intent, dependencies) {
|
|
304395
|
+
const base = {
|
|
304396
|
+
runtimeId,
|
|
304397
|
+
threadId: intent.threadId,
|
|
304398
|
+
action: intent.action,
|
|
304399
|
+
requestedAt: intent.requestedAt
|
|
304400
|
+
};
|
|
304401
|
+
const report = (outcome, detail) => dependencies.log({
|
|
304402
|
+
...base,
|
|
304403
|
+
outcome,
|
|
304404
|
+
...detail === void 0 ? {} : { detail }
|
|
304405
|
+
}).pipe(as$3(outcome));
|
|
304406
|
+
const thread = (yield* dependencies.getReadModel()).threads.find((candidate) => candidate.id === intent.threadId);
|
|
304407
|
+
if (thread === void 0) return yield* report("missing-thread");
|
|
304408
|
+
if (intentIsSpent(thread, intent)) return yield* report("spent");
|
|
304409
|
+
return yield* dependencies.dispatch(commandFor(runtimeId, intent)).pipe(flatMap(() => report("applied")), catch_((error) => error._tag === "OrchestrationCommandInvariantError" || error._tag === "OrchestrationCommandPreviouslyRejectedError" ? report("refused", error.detail) : report("failed", error.message)));
|
|
304410
|
+
});
|
|
304411
|
+
/**
|
|
304412
|
+
* One tick: list, apply each, acknowledge everything that got an answer.
|
|
304413
|
+
*
|
|
304414
|
+
* A signed-out owner is not an error to retry into the log every five
|
|
304415
|
+
* minutes; it is a state the desktop leaves when someone signs in, so it is
|
|
304416
|
+
* logged once at info and the tick ends. Any other listing or acknowledgement
|
|
304417
|
+
* failure is returned typed, and the intents stay pending on CMMD.
|
|
304418
|
+
*/
|
|
304419
|
+
function applyPendingLifecycleIntents(input, dependencies) {
|
|
304420
|
+
return gen(function* () {
|
|
304421
|
+
const intents = yield* dependencies.listPending();
|
|
304422
|
+
if (intents.length === 0) return;
|
|
304423
|
+
const answered = [];
|
|
304424
|
+
for (const intent of intents) if ((yield* applyOne(input.runtimeId, intent, dependencies)) !== "failed") answered.push({
|
|
304425
|
+
threadId: intent.threadId,
|
|
304426
|
+
requestedAt: intent.requestedAt
|
|
304427
|
+
});
|
|
304428
|
+
if (answered.length === 0) return;
|
|
304429
|
+
yield* dependencies.acknowledge(answered);
|
|
304430
|
+
}).pipe(catch_((error) => error.kind === "auth" ? logInfo("Lifecycle intents skipped: CMMD sign-in is required.", {
|
|
304431
|
+
runtimeId: input.runtimeId,
|
|
304432
|
+
code: error.code
|
|
304433
|
+
}) : fail(error)));
|
|
304434
|
+
}
|
|
304435
|
+
/**
|
|
304436
|
+
* One structured line per intent, so a row that "came back" after a wake can
|
|
304437
|
+
* be explained from the log: applied, refused by the decider, or spent by
|
|
304438
|
+
* newer activity.
|
|
304439
|
+
*/
|
|
304440
|
+
function logLifecycleIntentOutcome(outcome) {
|
|
304441
|
+
const message = `Lifecycle intent ${outcome.outcome}.`;
|
|
304442
|
+
return outcome.outcome === "refused" || outcome.outcome === "failed" ? logWarning$1(message, outcome) : logInfo(message, outcome);
|
|
304443
|
+
}
|
|
304444
|
+
//#endregion
|
|
303970
304445
|
//#region src/runtimeReplication/processOutboxItem.ts
|
|
303971
304446
|
function publicationMetricAttributes(item, outcome, failure) {
|
|
303972
304447
|
return {
|
|
@@ -304163,6 +304638,31 @@ const RuntimeReplicationLive = effect(RuntimeReplication, gen(function* () {
|
|
|
304163
304638
|
}).pipe(asVoid, catchCause((cause) => logError("Runtime replication reconciliation failed.", { cause })));
|
|
304164
304639
|
const heartbeat = enqueueAll.pipe(repeat(spaced("5 minutes")), forkScoped);
|
|
304165
304640
|
/**
|
|
304641
|
+
* Settle and un-settle requests a person recorded in CMMD while this
|
|
304642
|
+
* runtime was offline. The first tick runs at once, which is the
|
|
304643
|
+
* startup case (this phase starts after the orchestration reactors);
|
|
304644
|
+
* every heartbeat after that picks up requests made while awake. The
|
|
304645
|
+
* tick handles its own expected failures; the supervisor restarts the
|
|
304646
|
+
* schedule if it ever dies between ticks.
|
|
304647
|
+
*/
|
|
304648
|
+
const lifecycleIntents = runSupervisedRepeat({
|
|
304649
|
+
label: "Lifecycle intent applier",
|
|
304650
|
+
work: applyPendingLifecycleIntents({ runtimeId }, {
|
|
304651
|
+
listPending: () => client.listPendingLifecycleIntents({ runtimeId }),
|
|
304652
|
+
acknowledge: (intents) => client.acknowledgeLifecycleIntents({
|
|
304653
|
+
runtimeId,
|
|
304654
|
+
intents
|
|
304655
|
+
}),
|
|
304656
|
+
dispatch: engine.dispatch,
|
|
304657
|
+
getReadModel: engine.getReadModel,
|
|
304658
|
+
log: logLifecycleIntentOutcome
|
|
304659
|
+
}).pipe(catchCause((cause) => logError("Lifecycle intent tick failed.", {
|
|
304660
|
+
cause,
|
|
304661
|
+
runtimeId
|
|
304662
|
+
}))),
|
|
304663
|
+
interval: "5 minutes"
|
|
304664
|
+
}).pipe(forkScoped);
|
|
304665
|
+
/**
|
|
304166
304666
|
* Closes and reports whatever Active Hour interval is currently open,
|
|
304167
304667
|
* every 5 minutes -- the same cadence as the inventory heartbeat, not
|
|
304168
304668
|
* because the two are related, but because it is a reasonable default
|
|
@@ -304181,6 +304681,7 @@ const RuntimeReplicationLive = effect(RuntimeReplication, gen(function* () {
|
|
|
304181
304681
|
reactor,
|
|
304182
304682
|
providerRegistry.streamChanges.pipe(debounce$1("250 millis"), mapEffect$1(() => enqueueAll, { concurrency: 1 }), runDrain, forkScoped),
|
|
304183
304683
|
heartbeat,
|
|
304684
|
+
lifecycleIntents,
|
|
304184
304685
|
activeHourFlush,
|
|
304185
304686
|
gen(function* () {
|
|
304186
304687
|
yield* outbox.recover();
|
|
@@ -313581,7 +314082,7 @@ const MiscRuntimeLayerLive = mergeAll(AnalyticsServiceLayerLive, OpenLive, Serve
|
|
|
313581
314082
|
const RuntimeDependenciesWithoutPullRequestsLive = ReactorLayerLive.pipe(provideMerge(CheckpointingLayerLive), provideMerge(GitLayerLive), provideMerge(OrchestrationLayerLive), provideMerge(ProviderLayerLive), provideMerge(TerminalLayerLive), provideMerge(AgentBrowserManagerLive), provideMerge(mergeAll(ThreadDevRuntimeLive, DevTunnelLive.pipe(provide$1(ThreadDevRuntimeLive)))), provideMerge(PersistenceLayerLive), provideMerge(KeybindingsLive), provideMerge(ProviderRegistryLive), provideMerge(mergeAll(ServerSettingsLive, UsageServiceLive.pipe(provide$1(ServerSettingsLive), provide$1(UsageSessionLookupLive), provide$1(UsageRecordedSourceLive.pipe(provide$1(OrchestrationLayerLive), provide$1(RuntimeReplicationOutboxLive), provide$1(ProviderSessionRuntimeRepositoryLive), provide$1(TextGenerationSessionRepositoryLive)))))), provideMerge(WorkspaceLayerLive), provideMerge(WorkspaceReadinessStateLive), provideMerge(ProjectFaviconResolverLive), provideMerge(RepositoryIdentityResolverLive), provideMerge(ServerEnvironmentLive), provideMerge(AuthLayerLive), provideMerge(ServerSecretStoreLayerLive), provideMerge(mergeAll(CloudRedisCoordinationLive, CloudStateSyncLive.pipe(provide$1(PersistenceLayerLive)))), provideMerge(MiscRuntimeLayerLive));
|
|
313582
314083
|
const RuntimeDependenciesLive = pullRequestServiceFactoryLayer.pipe(provideMerge(RuntimeDependenciesWithoutPullRequestsLive), provideMerge(cmmdProjectIdentityResolverLive.pipe(provide$1(RuntimeDependenciesWithoutPullRequestsLive))), provideMerge(pullRequestProviderRuntimeLive));
|
|
313583
314084
|
const RuntimeServicesLive = ServerRuntimeStartupLive.pipe(provideMerge(RuntimeDependenciesLive));
|
|
313584
|
-
const makeRoutesLayer = mergeAll(authBearerBootstrapRouteLayer, authBootstrapRouteLayer, authCommandBearerBootstrapRouteLayer, authCommandBootstrapRouteLayer, authOAuthTokenExchangeRouteLayer, authWebSocketTicketRouteLayer, authCmmdOAuthDeviceRouteLayer, authCmmdOAuthTokenRouteLayer, authCmmdPasswordTokenRouteLayer, authClientsRevokeOthersRouteLayer, authClientsRevokeRouteLayer, authClientsRouteLayer, authLogoutRouteLayer, authPairingLinksRevokeRouteLayer, authPairingLinksRouteLayer, authPairingCredentialRouteLayer, authSessionRouteLayer, authWebSocketTokenRouteLayer, authWebLoginRouteLayer, authWebCallbackRouteLayer, desktopLocalWebBridgePublishRouteLayer, desktopLocalWebBridgeBootstrapRouteLayer, desktopRelayControlPlaneRouteLayer, apiDocsHtmlRouteLayer, apiDocsOpenApiRouteLayer, pulseSignalStateListRouteLayer, pulseSignalStateUpsertRouteLayer, cmmdProfileRouteLayer,
|
|
314085
|
+
const makeRoutesLayer = mergeAll(authBearerBootstrapRouteLayer, authBootstrapRouteLayer, authCommandBearerBootstrapRouteLayer, authCommandBootstrapRouteLayer, authOAuthTokenExchangeRouteLayer, authWebSocketTicketRouteLayer, authCmmdOAuthDeviceRouteLayer, authCmmdOAuthTokenRouteLayer, authCmmdPasswordTokenRouteLayer, authClientsRevokeOthersRouteLayer, authClientsRevokeRouteLayer, authClientsRouteLayer, authLogoutRouteLayer, authPairingLinksRevokeRouteLayer, authPairingLinksRouteLayer, authPairingCredentialRouteLayer, authSessionRouteLayer, authWebSocketTokenRouteLayer, authWebLoginRouteLayer, authWebCallbackRouteLayer, desktopLocalWebBridgePublishRouteLayer, desktopLocalWebBridgeBootstrapRouteLayer, desktopRelayControlPlaneRouteLayer, apiDocsHtmlRouteLayer, apiDocsOpenApiRouteLayer, pulseSignalStateListRouteLayer, pulseSignalStateUpsertRouteLayer, cmmdProfileRouteLayer, ...cmmdProxyRouteLayers, cmmdWorkIntakeRouteLayer, cmmdWsTokenRouteLayer, cmmdGetProjectCommentsRouteLayer, cmmdAddProjectCommentRouteLayer, cmmdUpdateProjectRouteLayer, cmmdUploadTaskAttachmentRouteLayer, cmmdUpdateTaskCommentRouteLayer, cmmdListWorkspaceMembersRouteLayer, cmmdAddProjectMemberRouteLayer, cmmdUpdateProjectAgentMemberAvatarRouteLayer, runtimeReplicationStatusRouteLayer, cmmdRefreshProviderUsageRouteLayer, cmmdForgeCloudProjectsListRouteLayer, cmmdForgeCloudProjectsEventsRouteLayer, cmmdForgeRuntimesEnsureRouteLayer, cmmdForgeRuntimesConnectRouteLayer, ownerRuntimeCodexReadinessRouteLayer, cmmdForgeRuntimesStatusRouteLayer, cmmdForgeRuntimesStartRouteLayer, cmmdForgeRuntimesStopRouteLayer, cmmdForgeRuntimesRecycleRouteLayer, cmmdForgeRuntimesUpdateCommitRouteLayer, cmmdForgeRuntimesDestroyRouteLayer, mobileProviderCatalogRouteLayer, attachmentsRouteLayer, orchestrationDispatchRouteLayer, orchestrationCmmdWorkRunEventRouteLayer, orchestrationAutomationStartThreadRouteLayer, orchestrationAutomationRebindRouteLayer, orchestrationAutomationTerminalReconcileRouteLayer, mobileGitRunStackedActionRouteLayer, pullRequestDiffRouteLayer, orchestrationSnapshotRouteLayer, localAutomationListRouteLayer, localAutomationCreateRouteLayer, localAutomationUpdateRouteLayer, localAutomationDeleteRouteLayer, localAutomationRunRouteLayer, otlpTracesProxyRouteLayer, devTunnelProxyRouteLayer, devTunnelLocalPortProxyRouteLayer, projectFaviconRouteLayer, serverEnvironmentRouteLayer, browserWebRtcReadinessRouteLayer, staticAndDevRouteLayer, githubStatusRouteLayer, githubAuthorizeUrlRouteLayer, githubDisconnectRouteLayer, githubReposRouteLayer, githubCloneRouteLayer, githubCloneJobStartRouteLayer, githubCloneJobStatusRouteLayer, githubRefreshCredentialsRouteLayer, githubToolConfirmationApproveRouteLayer, projectLinkGetRouteLayer, projectLinkListRouteLayer, projectLinkSetRouteLayer, projectLinkDeleteRouteLayer, cmmdWorkspacesRouteLayer, cmmdCampaignsRouteLayer, cmmdProjectLinksRouteLayer, cmmdEnsureGitHubProjectContextRouteLayer, cmmdProjectRepositoryEnsureRouteLayer, cmmdProjectsGetRouteLayer, cmmdProjectsCreateRouteLayer, workspaceReadinessRouteLayer, runtimeLivenessRouteLayer, claudeNativeGenerationProofRouteLayer, claudeUsageRouteLayer, codexRuntimeProviderReadinessRouteLayer, runtimeDiagnosticsRouteLayer, cloudFoldersRouteLayer, cloudProjectCreateRouteLayer, gitUrlCloneRouteLayer, websocketRpcRouteLayer).pipe(provide$1(browserApiCorsLayer));
|
|
313585
314086
|
const runServer = launch$1(unwrap(gen(function* () {
|
|
313586
314087
|
const config = yield* ServerConfig;
|
|
313587
314088
|
fixPath({ preferProcessPath: config.forgeCmmdRuntimeMode === true });
|
|
@@ -314093,7 +314594,7 @@ const resolveServerConfig = (flags, cliLogLevel, options) => gen(function* () {
|
|
|
314093
314594
|
forgeCodexHomePath: env.forgeCodexHomePath,
|
|
314094
314595
|
forgeClaudeConfigPath: env.forgeClaudeConfigPath,
|
|
314095
314596
|
forgeApexBaseUrl: env.forgeApexBaseUrl,
|
|
314096
|
-
cloudProjectsRoot: env.cloudProjectsRoot ?? "/
|
|
314597
|
+
cloudProjectsRoot: env.cloudProjectsRoot ?? "/projects"
|
|
314097
314598
|
};
|
|
314098
314599
|
if (config.forgeCloudShellMode === true && (!config.forgeCloudOwnerAssertionPublicKey?.trim() || !config.forgeCloudOwnerAssertionKeyId?.trim())) return yield* die$1(/* @__PURE__ */ new Error("FORGE_CMMD_CLOUD_OWNER_ASSERTION_PUBLIC_KEY and FORGE_CMMD_CLOUD_OWNER_ASSERTION_KEY_ID are required in cloud-shell mode; runtime ticket keys are not accepted for Cloud owner assertions."));
|
|
314099
314600
|
if (config.forgeCloudShellMode === true && !isEd25519PublicKey(config.forgeCloudOwnerAssertionPublicKey ?? "")) return yield* die$1(/* @__PURE__ */ new Error("FORGE_CMMD_CLOUD_OWNER_ASSERTION_PUBLIC_KEY must be a valid Ed25519 public key in cloud-shell mode."));
|