@cmmd-center/forge 0.13.19 → 0.13.21

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 CHANGED
@@ -17245,7 +17245,8 @@ const ExecutionEnvironmentAuthCapabilities = require_Schema$1.Struct({
17245
17245
  ownerBootstrapPromotion: require_Schema$1.Boolean,
17246
17246
  bearerBootstrap: require_Schema$1.Boolean,
17247
17247
  desktopBootstrap: require_Schema$1.Boolean,
17248
- providerCredentialBroker: require_Schema$1.Boolean
17248
+ providerCredentialBroker: require_Schema$1.Boolean,
17249
+ cloudOwnerAssertion: require_Schema$1.optionalKey(require_Schema$1.Boolean)
17249
17250
  });
17250
17251
  const ExecutionEnvironmentToolCapabilities = require_Schema$1.Struct({
17251
17252
  agents: require_Schema$1.Boolean,
@@ -66231,7 +66232,7 @@ function normalizeNumberish(value) {
66231
66232
  }
66232
66233
  //#endregion
66233
66234
  //#region package.json
66234
- var version$1 = "0.13.19";
66235
+ var version$1 = "0.13.21";
66235
66236
  //#endregion
66236
66237
  //#region src/sentry.ts
66237
66238
  const SERVER_APP_NAME = "forge-server";
@@ -68356,6 +68357,7 @@ function extractCookieValue(setCookieHeaders, name) {
68356
68357
  }
68357
68358
  return null;
68358
68359
  }
68360
+ /** @internal exported for the other owner lanes and their tests. */
68359
68361
  function readCmmdJsonResponse(response, fallbackMessage) {
68360
68362
  return require_Schema$1.gen(function* () {
68361
68363
  const payload = yield* require_Schema$1.tryPromise({
@@ -68617,11 +68619,14 @@ function cmmdUserCredential(payload) {
68617
68619
  /**
68618
68620
  * Read one CMMD token-exchange response into the credential set Forge stores.
68619
68621
  *
68620
- * Both owner lanes redeem the same `cmmd-forge-web` authorization code — the
68621
- * browser OAuth callback and Cloud's password login — so they see the same
68622
- * bundle shape. Reading it in one place is what keeps them from drifting on
68623
- * which field carries the PAT; callers still own their own error reporting,
68624
- * which is the only part that legitimately differs between the two.
68622
+ * Every owner lane that redeems a CMMD grant — the browser OAuth callback,
68623
+ * Cloud's password login, the cookie-shaped session renew, and the bearer
68624
+ * device-session redeem in cloudOwnerDeviceSession.ts — sees the same bundle
68625
+ * shape. Reading it in one place is what keeps them from drifting on which
68626
+ * field carries the PAT; callers still own their own error reporting, which
68627
+ * is the only part that legitimately differs between them.
68628
+ *
68629
+ * @internal exported for the other owner lanes and their tests.
68625
68630
  */
68626
68631
  function resolveCmmdTokenBundleCredentials(tokenResult) {
68627
68632
  return require_Schema$1.gen(function* () {
@@ -298212,7 +298217,7 @@ function resolveBuildCommitFromEnv(env) {
298212
298217
  * environment descriptor down instead of reporting an honest "unknown".
298213
298218
  */
298214
298219
  function readBakedBuildCommit() {
298215
- return "413f6c70dd1ffeab5513665939035535510042d8";
298220
+ return "69e84f7ffb374290143d188cb9b7312e17ee2f90";
298216
298221
  }
298217
298222
  async function resolveServerBuildCommit(input) {
298218
298223
  if (isFullCommitSha(input.baked)) return input.baked;
@@ -298340,9 +298345,10 @@ function executionEnvironmentCapabilities(serverConfig) {
298340
298345
  auth: {
298341
298346
  cmmd: true,
298342
298347
  ownerBootstrapPromotion: !isRuntime && !isCloudShell,
298343
- bearerBootstrap: true,
298348
+ bearerBootstrap: !isCloudShell,
298344
298349
  desktopBootstrap: serverConfig.mode === "desktop" || serverConfig.desktopBootstrapToken !== void 0,
298345
- providerCredentialBroker: false
298350
+ providerCredentialBroker: false,
298351
+ cloudOwnerAssertion: isCloudShell
298346
298352
  },
298347
298353
  tools: {
298348
298354
  agents: isExecutionPlane,
@@ -298434,6 +298440,145 @@ const makeServerEnvironment = require_Schema$1.fn("makeServerEnvironment")(funct
298434
298440
  });
298435
298441
  const ServerEnvironmentLive = require_Schema$1.effect(ServerEnvironment, makeServerEnvironment());
298436
298442
  //#endregion
298443
+ //#region src/auth/http/cloudOwnerDeviceSession.ts
298444
+ /**
298445
+ * Native OAuth clients allowed to redeem a Forge Cloud session grant through
298446
+ * this bearer lane. Starts with only the mobile client from FOR-36841's
298447
+ * companion CMMD change; widen deliberately, not by accident.
298448
+ */
298449
+ const CLOUD_NATIVE_OAUTH_CLIENT_IDS = new Set(["cmmd-forge-mobile"]);
298450
+ const CloudOwnerSessionRedeemInput = require_Schema$1.Struct({
298451
+ sessionGrant: require_Schema$1.String,
298452
+ clientId: require_Schema$1.String
298453
+ });
298454
+ function outsideCloudShell() {
298455
+ return require_Schema$1.fail(new AuthError({
298456
+ message: "Forge Cloud session redemption is unavailable.",
298457
+ status: 403
298458
+ }));
298459
+ }
298460
+ function redeemSessionGrantWithCmmd(input) {
298461
+ return require_Schema$1.tryPromise({
298462
+ try: () => fetch(resolveCommandAppEndpoint("/api/mcp-server/oauth/token"), {
298463
+ method: "POST",
298464
+ headers: { "content-type": "application/json" },
298465
+ body: JSON.stringify({
298466
+ grant_type: "forge_session_grant",
298467
+ grant_token: input.sessionGrant,
298468
+ client_id: input.clientId
298469
+ })
298470
+ }),
298471
+ catch: (cause) => new AuthError({
298472
+ message: "Failed to redeem the Forge Cloud session grant with CMMD.",
298473
+ status: 500,
298474
+ cause
298475
+ })
298476
+ }).pipe(require_Schema$1.flatMap((response) => readCmmdJsonResponse(response, "Failed to redeem the Forge Cloud session grant with CMMD.")));
298477
+ }
298478
+ const cloudOwnerSessionRedeemRouteLayer = add$1("POST", "/api/auth/cloud/session", require_Schema$1.gen(function* () {
298479
+ const serverAuth = yield* ServerAuth;
298480
+ if (serverAuth.isForgeCloudShell?.() !== true) return yield* outsideCloudShell();
298481
+ const request = yield* require_HttpServer.HttpServerRequest;
298482
+ const limited = rateLimitOrRespond({
298483
+ routeClass: "auth-bootstrap",
298484
+ clientKey: clientKeyFromRequest(request)
298485
+ });
298486
+ if (limited) return limited;
298487
+ yield* serverAuth.authenticateHttpRequest(request);
298488
+ const payload = yield* require_HttpServer.schemaBodyJson(CloudOwnerSessionRedeemInput).pipe(require_Schema$1.mapError((cause) => new AuthError({
298489
+ message: "Invalid Forge Cloud session redeem payload.",
298490
+ status: 400,
298491
+ cause
298492
+ })));
298493
+ if (!CLOUD_NATIVE_OAUTH_CLIENT_IDS.has(payload.clientId)) return yield* new AuthError({
298494
+ message: "Unknown Forge Cloud native client.",
298495
+ status: 403
298496
+ });
298497
+ const tokenResult = yield* redeemSessionGrantWithCmmd(payload);
298498
+ const { tokenObj, cmmdIdentity, userId, accessToken, mcpToken, refreshToken, forgeOwnerAssertion, sessionGrantExpiresAt, isJwt, patToStore, jwtToStore } = yield* resolveCmmdTokenBundleCredentials(tokenResult);
298499
+ if (!cmmdIdentity || !userId || !patToStore) {
298500
+ yield* require_Schema$1.logError("Forge Cloud session redeem: CMMD token response incomplete.", {
298501
+ clientId: payload.clientId,
298502
+ tokenResponse: describeCmmdTokenResponseForLog({
298503
+ tokenObj,
298504
+ tokenResult,
298505
+ accessToken,
298506
+ mcpToken,
298507
+ refreshToken,
298508
+ isJwt,
298509
+ userId,
298510
+ patToStore,
298511
+ jwtToStore
298512
+ })
298513
+ });
298514
+ return yield* new AuthError({
298515
+ message: "CMMD did not return a complete redeemed Forge Cloud session.",
298516
+ status: 500
298517
+ });
298518
+ }
298519
+ const assertion = yield* validateCloudOwnerCallbackAssertion({
298520
+ serverAuth,
298521
+ assertionToken: forgeOwnerAssertion,
298522
+ authenticatedUserId: userId
298523
+ });
298524
+ if (!assertion) return yield* require_Schema$1.die(/* @__PURE__ */ new Error("Expected a redeemed Forge Cloud owner assertion for a native client."));
298525
+ yield* persistCloudOwnerArtifacts({
298526
+ assertion,
298527
+ accessToken: patToStore,
298528
+ identity: cmmdIdentity,
298529
+ jwtToken: jwtToStore,
298530
+ refreshToken,
298531
+ sessionGrant: payload.sessionGrant,
298532
+ sessionGrantExpiresAt
298533
+ });
298534
+ yield* require_Schema$1.logInfo("Forge Cloud owner session redeemed.", {
298535
+ sessionId: assertion.sessionId,
298536
+ clientId: payload.clientId,
298537
+ userId
298538
+ });
298539
+ return require_HttpServer.jsonUnsafe({
298540
+ assertion: assertion.token,
298541
+ assertionExpiresAt: require_Schema$1.toUtc(assertion.expiresAt),
298542
+ sessionGrantExpiresAt,
298543
+ user: {
298544
+ id: assertion.userId,
298545
+ email: cmmdIdentity.email
298546
+ }
298547
+ }, { status: 200 });
298548
+ }).pipe(require_Schema$1.catchTag("AuthError", (error) => respondToAuthError(error))));
298549
+ /**
298550
+ * Seam for CMMD-side session-grant revocation.
298551
+ *
298552
+ * As of FOR-36841, CMMD does not expose an endpoint to revoke a
298553
+ * `forge_session_grant` token server-side (confirm with the CMMD change
298554
+ * before wiring this in). When it does, call it here, best-effort: a failure
298555
+ * revoking at CMMD must never block the local row deletion below, which is
298556
+ * this endpoint's actual guarantee. Left as a documented no-op rather than a
298557
+ * guess at CMMD's eventual route shape.
298558
+ */
298559
+ function revokeCmmdSessionGrantBestEffort(_sessionId) {
298560
+ return require_Schema$1.void_;
298561
+ }
298562
+ const cloudOwnerSessionRevokeRouteLayer = add$1("POST", "/api/auth/cloud/session/revoke", require_Schema$1.gen(function* () {
298563
+ const serverAuth = yield* ServerAuth;
298564
+ if (serverAuth.isForgeCloudShell?.() !== true) return yield* outsideCloudShell();
298565
+ const request = yield* require_HttpServer.HttpServerRequest;
298566
+ const limited = rateLimitOrRespond({
298567
+ routeClass: "auth-bootstrap",
298568
+ clientKey: clientKeyFromRequest(request)
298569
+ });
298570
+ if (limited) return limited;
298571
+ const session = yield* serverAuth.authenticateHttpRequest(request);
298572
+ yield* clearCommandAccessTokenForSession(session.sessionId).pipe(require_Schema$1.mapError((cause) => new AuthError({
298573
+ message: "Failed to revoke the Forge Cloud owner session.",
298574
+ status: 500,
298575
+ cause
298576
+ })));
298577
+ yield* revokeCmmdSessionGrantBestEffort(session.sessionId);
298578
+ yield* require_Schema$1.logInfo("Forge Cloud owner session revoked.", { sessionId: session.sessionId });
298579
+ return require_HttpServer.empty({ status: 204 });
298580
+ }).pipe(require_Schema$1.catchTag("AuthError", (error) => respondToAuthError(error))));
298581
+ //#endregion
298437
298582
  //#region src/docs/http.ts
298438
298583
  const SCALAR_API_REFERENCE_URL = "https://cdn.jsdelivr.net/npm/@scalar/api-reference@1.64.1";
298439
298584
  const SCALAR_API_REFERENCE_INTEGRITY = "sha384-SmFRDuBBmEoCbbBCTcn8/+cIQONyH0xgOKpsp6OttBlI8uG9uc6iAO8SonYQ3e1W";
@@ -300567,6 +300712,24 @@ function readWebSocketUpgradeToken(params) {
300567
300712
  }
300568
300713
  //#endregion
300569
300714
  //#region src/auth/Layers/ForgeCloudOwnerAuthentication.ts
300715
+ const BEARER_PREFIX = "Bearer ";
300716
+ /**
300717
+ * Reads a Forge Cloud owner assertion presented as `Authorization: Bearer
300718
+ * <assertion>`, alongside the cookie read below.
300719
+ *
300720
+ * Deliberately its own parser rather than a shared one: `ServerAuth.ts`
300721
+ * carries a bearer reader for the local bootstrap/pairing/desktop lanes, and
300722
+ * those must stay untouched by this change. This function is only ever
300723
+ * called from `authenticateForgeCloudOwnerRequest`, which itself only runs
300724
+ * when `serverConfig.forgeCloudShellMode === true` — so a non-cloud server's
300725
+ * bearer lanes never pass through here.
300726
+ */
300727
+ function readForgeCloudOwnerBearerToken(request) {
300728
+ const header = request.headers["authorization"];
300729
+ if (typeof header !== "string" || !header.startsWith(BEARER_PREFIX)) return null;
300730
+ const token = header.slice(7).trim();
300731
+ return token.length > 0 ? token : null;
300732
+ }
300570
300733
  function assertionVerifierConfig(config) {
300571
300734
  const publicKey = config.forgeCloudOwnerAssertionPublicKey;
300572
300735
  const keyId = config.forgeCloudOwnerAssertionKeyId;
@@ -300594,7 +300757,7 @@ function authenticateForgeCloudOwnerRequest(request, config) {
300594
300757
  message: "Forge Cloud owner assertion verification is misconfigured.",
300595
300758
  status: 500
300596
300759
  });
300597
- const token = request.cookies[FORGE_CLOUD_OWNER_ASSERTION_COOKIE];
300760
+ const token = request.cookies["forge_cloud_owner_assertion"] ?? readForgeCloudOwnerBearerToken(request);
300598
300761
  if (!token) return yield* new AuthError({
300599
300762
  message: "Authentication required.",
300600
300763
  status: 401
@@ -321763,7 +321926,7 @@ const MiscRuntimeLayerLive = require_Schema$1.mergeAll(AnalyticsServiceLayerLive
321763
321926
  const RuntimeDependenciesWithoutPullRequestsLive = ReactorLayerLive.pipe(require_Schema$1.provideMerge(CheckpointingLayerLive), require_Schema$1.provideMerge(GitLayerLive), require_Schema$1.provideMerge(OrchestrationLayerLive), require_Schema$1.provideMerge(ProviderLayerLive), require_Schema$1.provideMerge(TerminalLayerLive), require_Schema$1.provideMerge(AgentBrowserManagerLive), require_Schema$1.provideMerge(require_Schema$1.mergeAll(ThreadDevRuntimeLive, DevTunnelLive.pipe(require_Schema$1.provide$1(ThreadDevRuntimeLive)))), require_Schema$1.provideMerge(PersistenceLayerLive), require_Schema$1.provideMerge(KeybindingsLive), require_Schema$1.provideMerge(ProviderRegistryLive), require_Schema$1.provideMerge(require_Schema$1.mergeAll(ServerSettingsLive, UsageServiceLive.pipe(require_Schema$1.provide$1(ServerSettingsLive), require_Schema$1.provide$1(UsageSessionLookupLive), require_Schema$1.provide$1(UsageRecordedSourceLive.pipe(require_Schema$1.provide$1(OrchestrationLayerLive), require_Schema$1.provide$1(RuntimeReplicationOutboxLive), require_Schema$1.provide$1(ProviderSessionRuntimeRepositoryLive), require_Schema$1.provide$1(TextGenerationSessionRepositoryLive)))))), require_Schema$1.provideMerge(WorkspaceLayerLive), require_Schema$1.provideMerge(WorkspaceReadinessStateLive), require_Schema$1.provideMerge(ProjectFaviconResolverLive), require_Schema$1.provideMerge(RepositoryIdentityResolverLive), require_Schema$1.provideMerge(ServerEnvironmentLive), require_Schema$1.provideMerge(AuthLayerLive), require_Schema$1.provideMerge(ServerSecretStoreLayerLive), require_Schema$1.provideMerge(require_Schema$1.mergeAll(CloudRedisCoordinationLive, CloudStateSyncLive.pipe(require_Schema$1.provide$1(PersistenceLayerLive)))), require_Schema$1.provideMerge(MiscRuntimeLayerLive));
321764
321927
  const RuntimeDependenciesLive = pullRequestServiceFactoryLayer.pipe(require_Schema$1.provideMerge(RuntimeDependenciesWithoutPullRequestsLive), require_Schema$1.provideMerge(cmmdProjectIdentityResolverLive.pipe(require_Schema$1.provide$1(RuntimeDependenciesWithoutPullRequestsLive))), require_Schema$1.provideMerge(pullRequestProviderRuntimeLive));
321765
321928
  const RuntimeServicesLive = ServerRuntimeStartupLive.pipe(require_Schema$1.provideMerge(RuntimeDependenciesLive));
321766
- const makeRoutesLayer = require_Schema$1.mergeAll(attachmentUploadRouteLayer, authBearerBootstrapRouteLayer, authBootstrapRouteLayer, authCommandBearerBootstrapRouteLayer, authCommandBootstrapRouteLayer, authOAuthTokenExchangeRouteLayer, authWebSocketTicketRouteLayer, authCmmdOAuthDeviceRouteLayer, authCmmdOAuthTokenRouteLayer, authCmmdPasswordTokenRouteLayer, authClientsRevokeOthersRouteLayer, authClientsRevokeRouteLayer, authClientsRouteLayer, authLogoutRouteLayer, authPairingLinksRevokeRouteLayer, authPairingLinksRouteLayer, authPairingCredentialRouteLayer, authSessionRenewRouteLayer, 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, orchestrationThreadSnapshotRouteLayer, 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, runtimeFilesystemHealthRouteLayer, claudeNativeGenerationProofRouteLayer, claudeUsageRouteLayer, codexRuntimeProviderReadinessRouteLayer, runtimeDiagnosticsRouteLayer, cloudFoldersRouteLayer, cloudProjectCreateRouteLayer, gitUrlCloneRouteLayer, websocketRpcRouteLayer).pipe(require_Schema$1.provide$1(browserApiCorsLayer));
321929
+ const makeRoutesLayer = require_Schema$1.mergeAll(attachmentUploadRouteLayer, authBearerBootstrapRouteLayer, authBootstrapRouteLayer, authCommandBearerBootstrapRouteLayer, authCommandBootstrapRouteLayer, authOAuthTokenExchangeRouteLayer, authWebSocketTicketRouteLayer, authCmmdOAuthDeviceRouteLayer, authCmmdOAuthTokenRouteLayer, authCmmdPasswordTokenRouteLayer, authClientsRevokeOthersRouteLayer, authClientsRevokeRouteLayer, authClientsRouteLayer, authLogoutRouteLayer, authPairingLinksRevokeRouteLayer, authPairingLinksRouteLayer, authPairingCredentialRouteLayer, authSessionRenewRouteLayer, authSessionRouteLayer, authWebSocketTokenRouteLayer, authWebLoginRouteLayer, authWebCallbackRouteLayer, cloudOwnerSessionRedeemRouteLayer, cloudOwnerSessionRevokeRouteLayer, 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, orchestrationThreadSnapshotRouteLayer, 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, runtimeFilesystemHealthRouteLayer, claudeNativeGenerationProofRouteLayer, claudeUsageRouteLayer, codexRuntimeProviderReadinessRouteLayer, runtimeDiagnosticsRouteLayer, cloudFoldersRouteLayer, cloudProjectCreateRouteLayer, gitUrlCloneRouteLayer, websocketRpcRouteLayer).pipe(require_Schema$1.provide$1(browserApiCorsLayer));
321767
321930
  const makeServerLayer = require_Schema$1.unwrap(require_Schema$1.gen(function* () {
321768
321931
  const config = yield* ServerConfig;
321769
321932
  fixPath({ preferProcessPath: config.forgeCmmdRuntimeMode === true });
package/dist/bin.mjs CHANGED
@@ -17203,7 +17203,8 @@ const ExecutionEnvironmentAuthCapabilities = Struct({
17203
17203
  ownerBootstrapPromotion: Boolean$1,
17204
17204
  bearerBootstrap: Boolean$1,
17205
17205
  desktopBootstrap: Boolean$1,
17206
- providerCredentialBroker: Boolean$1
17206
+ providerCredentialBroker: Boolean$1,
17207
+ cloudOwnerAssertion: optionalKey(Boolean$1)
17207
17208
  });
17208
17209
  const ExecutionEnvironmentToolCapabilities = Struct({
17209
17210
  agents: Boolean$1,
@@ -65936,7 +65937,7 @@ function normalizeNumberish(value) {
65936
65937
  }
65937
65938
  //#endregion
65938
65939
  //#region package.json
65939
- var version$1 = "0.13.19";
65940
+ var version$1 = "0.13.21";
65940
65941
  //#endregion
65941
65942
  //#region src/sentry.ts
65942
65943
  const SERVER_APP_NAME = "forge-server";
@@ -68060,6 +68061,7 @@ function extractCookieValue(setCookieHeaders, name) {
68060
68061
  }
68061
68062
  return null;
68062
68063
  }
68064
+ /** @internal exported for the other owner lanes and their tests. */
68063
68065
  function readCmmdJsonResponse(response, fallbackMessage) {
68064
68066
  return gen(function* () {
68065
68067
  const payload = yield* tryPromise({
@@ -68321,11 +68323,14 @@ function cmmdUserCredential(payload) {
68321
68323
  /**
68322
68324
  * Read one CMMD token-exchange response into the credential set Forge stores.
68323
68325
  *
68324
- * Both owner lanes redeem the same `cmmd-forge-web` authorization code — the
68325
- * browser OAuth callback and Cloud's password login — so they see the same
68326
- * bundle shape. Reading it in one place is what keeps them from drifting on
68327
- * which field carries the PAT; callers still own their own error reporting,
68328
- * which is the only part that legitimately differs between the two.
68326
+ * Every owner lane that redeems a CMMD grant — the browser OAuth callback,
68327
+ * Cloud's password login, the cookie-shaped session renew, and the bearer
68328
+ * device-session redeem in cloudOwnerDeviceSession.ts — sees the same bundle
68329
+ * shape. Reading it in one place is what keeps them from drifting on which
68330
+ * field carries the PAT; callers still own their own error reporting, which
68331
+ * is the only part that legitimately differs between them.
68332
+ *
68333
+ * @internal exported for the other owner lanes and their tests.
68329
68334
  */
68330
68335
  function resolveCmmdTokenBundleCredentials(tokenResult) {
68331
68336
  return gen(function* () {
@@ -297643,7 +297648,7 @@ function resolveBuildCommitFromEnv(env) {
297643
297648
  * environment descriptor down instead of reporting an honest "unknown".
297644
297649
  */
297645
297650
  function readBakedBuildCommit() {
297646
- return "413f6c70dd1ffeab5513665939035535510042d8";
297651
+ return "69e84f7ffb374290143d188cb9b7312e17ee2f90";
297647
297652
  }
297648
297653
  async function resolveServerBuildCommit(input) {
297649
297654
  if (isFullCommitSha(input.baked)) return input.baked;
@@ -297771,9 +297776,10 @@ function executionEnvironmentCapabilities(serverConfig) {
297771
297776
  auth: {
297772
297777
  cmmd: true,
297773
297778
  ownerBootstrapPromotion: !isRuntime && !isCloudShell,
297774
- bearerBootstrap: true,
297779
+ bearerBootstrap: !isCloudShell,
297775
297780
  desktopBootstrap: serverConfig.mode === "desktop" || serverConfig.desktopBootstrapToken !== void 0,
297776
- providerCredentialBroker: false
297781
+ providerCredentialBroker: false,
297782
+ cloudOwnerAssertion: isCloudShell
297777
297783
  },
297778
297784
  tools: {
297779
297785
  agents: isExecutionPlane,
@@ -297863,6 +297869,145 @@ const ServerEnvironmentLive = effect(ServerEnvironment, fn$1("makeServerEnvironm
297863
297869
  };
297864
297870
  })());
297865
297871
  //#endregion
297872
+ //#region src/auth/http/cloudOwnerDeviceSession.ts
297873
+ /**
297874
+ * Native OAuth clients allowed to redeem a Forge Cloud session grant through
297875
+ * this bearer lane. Starts with only the mobile client from FOR-36841's
297876
+ * companion CMMD change; widen deliberately, not by accident.
297877
+ */
297878
+ const CLOUD_NATIVE_OAUTH_CLIENT_IDS = new Set(["cmmd-forge-mobile"]);
297879
+ const CloudOwnerSessionRedeemInput = Struct({
297880
+ sessionGrant: String$1,
297881
+ clientId: String$1
297882
+ });
297883
+ function outsideCloudShell() {
297884
+ return fail(new AuthError({
297885
+ message: "Forge Cloud session redemption is unavailable.",
297886
+ status: 403
297887
+ }));
297888
+ }
297889
+ function redeemSessionGrantWithCmmd(input) {
297890
+ return tryPromise({
297891
+ try: () => fetch(resolveCommandAppEndpoint("/api/mcp-server/oauth/token"), {
297892
+ method: "POST",
297893
+ headers: { "content-type": "application/json" },
297894
+ body: JSON.stringify({
297895
+ grant_type: "forge_session_grant",
297896
+ grant_token: input.sessionGrant,
297897
+ client_id: input.clientId
297898
+ })
297899
+ }),
297900
+ catch: (cause) => new AuthError({
297901
+ message: "Failed to redeem the Forge Cloud session grant with CMMD.",
297902
+ status: 500,
297903
+ cause
297904
+ })
297905
+ }).pipe(flatMap((response) => readCmmdJsonResponse(response, "Failed to redeem the Forge Cloud session grant with CMMD.")));
297906
+ }
297907
+ const cloudOwnerSessionRedeemRouteLayer = add$1("POST", "/api/auth/cloud/session", gen(function* () {
297908
+ const serverAuth = yield* ServerAuth;
297909
+ if (serverAuth.isForgeCloudShell?.() !== true) return yield* outsideCloudShell();
297910
+ const request = yield* HttpServerRequest;
297911
+ const limited = rateLimitOrRespond({
297912
+ routeClass: "auth-bootstrap",
297913
+ clientKey: clientKeyFromRequest(request)
297914
+ });
297915
+ if (limited) return limited;
297916
+ yield* serverAuth.authenticateHttpRequest(request);
297917
+ const payload = yield* schemaBodyJson(CloudOwnerSessionRedeemInput).pipe(mapError((cause) => new AuthError({
297918
+ message: "Invalid Forge Cloud session redeem payload.",
297919
+ status: 400,
297920
+ cause
297921
+ })));
297922
+ if (!CLOUD_NATIVE_OAUTH_CLIENT_IDS.has(payload.clientId)) return yield* new AuthError({
297923
+ message: "Unknown Forge Cloud native client.",
297924
+ status: 403
297925
+ });
297926
+ const tokenResult = yield* redeemSessionGrantWithCmmd(payload);
297927
+ const { tokenObj, cmmdIdentity, userId, accessToken, mcpToken, refreshToken, forgeOwnerAssertion, sessionGrantExpiresAt, isJwt, patToStore, jwtToStore } = yield* resolveCmmdTokenBundleCredentials(tokenResult);
297928
+ if (!cmmdIdentity || !userId || !patToStore) {
297929
+ yield* logError("Forge Cloud session redeem: CMMD token response incomplete.", {
297930
+ clientId: payload.clientId,
297931
+ tokenResponse: describeCmmdTokenResponseForLog({
297932
+ tokenObj,
297933
+ tokenResult,
297934
+ accessToken,
297935
+ mcpToken,
297936
+ refreshToken,
297937
+ isJwt,
297938
+ userId,
297939
+ patToStore,
297940
+ jwtToStore
297941
+ })
297942
+ });
297943
+ return yield* new AuthError({
297944
+ message: "CMMD did not return a complete redeemed Forge Cloud session.",
297945
+ status: 500
297946
+ });
297947
+ }
297948
+ const assertion = yield* validateCloudOwnerCallbackAssertion({
297949
+ serverAuth,
297950
+ assertionToken: forgeOwnerAssertion,
297951
+ authenticatedUserId: userId
297952
+ });
297953
+ if (!assertion) return yield* die$1(/* @__PURE__ */ new Error("Expected a redeemed Forge Cloud owner assertion for a native client."));
297954
+ yield* persistCloudOwnerArtifacts({
297955
+ assertion,
297956
+ accessToken: patToStore,
297957
+ identity: cmmdIdentity,
297958
+ jwtToken: jwtToStore,
297959
+ refreshToken,
297960
+ sessionGrant: payload.sessionGrant,
297961
+ sessionGrantExpiresAt
297962
+ });
297963
+ yield* logInfo("Forge Cloud owner session redeemed.", {
297964
+ sessionId: assertion.sessionId,
297965
+ clientId: payload.clientId,
297966
+ userId
297967
+ });
297968
+ return jsonUnsafe({
297969
+ assertion: assertion.token,
297970
+ assertionExpiresAt: toUtc(assertion.expiresAt),
297971
+ sessionGrantExpiresAt,
297972
+ user: {
297973
+ id: assertion.userId,
297974
+ email: cmmdIdentity.email
297975
+ }
297976
+ }, { status: 200 });
297977
+ }).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
297978
+ /**
297979
+ * Seam for CMMD-side session-grant revocation.
297980
+ *
297981
+ * As of FOR-36841, CMMD does not expose an endpoint to revoke a
297982
+ * `forge_session_grant` token server-side (confirm with the CMMD change
297983
+ * before wiring this in). When it does, call it here, best-effort: a failure
297984
+ * revoking at CMMD must never block the local row deletion below, which is
297985
+ * this endpoint's actual guarantee. Left as a documented no-op rather than a
297986
+ * guess at CMMD's eventual route shape.
297987
+ */
297988
+ function revokeCmmdSessionGrantBestEffort(_sessionId) {
297989
+ return void_$1;
297990
+ }
297991
+ const cloudOwnerSessionRevokeRouteLayer = add$1("POST", "/api/auth/cloud/session/revoke", gen(function* () {
297992
+ const serverAuth = yield* ServerAuth;
297993
+ if (serverAuth.isForgeCloudShell?.() !== true) return yield* outsideCloudShell();
297994
+ const request = yield* HttpServerRequest;
297995
+ const limited = rateLimitOrRespond({
297996
+ routeClass: "auth-bootstrap",
297997
+ clientKey: clientKeyFromRequest(request)
297998
+ });
297999
+ if (limited) return limited;
298000
+ const session = yield* serverAuth.authenticateHttpRequest(request);
298001
+ yield* clearCommandAccessTokenForSession(session.sessionId).pipe(mapError((cause) => new AuthError({
298002
+ message: "Failed to revoke the Forge Cloud owner session.",
298003
+ status: 500,
298004
+ cause
298005
+ })));
298006
+ yield* revokeCmmdSessionGrantBestEffort(session.sessionId);
298007
+ yield* logInfo("Forge Cloud owner session revoked.", { sessionId: session.sessionId });
298008
+ return empty$6({ status: 204 });
298009
+ }).pipe(catchTag("AuthError", (error) => respondToAuthError(error))));
298010
+ //#endregion
297866
298011
  //#region src/docs/http.ts
297867
298012
  const SCALAR_API_REFERENCE_URL = "https://cdn.jsdelivr.net/npm/@scalar/api-reference@1.64.1";
297868
298013
  const SCALAR_API_REFERENCE_INTEGRITY = "sha384-SmFRDuBBmEoCbbBCTcn8/+cIQONyH0xgOKpsp6OttBlI8uG9uc6iAO8SonYQ3e1W";
@@ -299983,6 +300128,24 @@ function readWebSocketUpgradeToken(params) {
299983
300128
  }
299984
300129
  //#endregion
299985
300130
  //#region src/auth/Layers/ForgeCloudOwnerAuthentication.ts
300131
+ const BEARER_PREFIX = "Bearer ";
300132
+ /**
300133
+ * Reads a Forge Cloud owner assertion presented as `Authorization: Bearer
300134
+ * <assertion>`, alongside the cookie read below.
300135
+ *
300136
+ * Deliberately its own parser rather than a shared one: `ServerAuth.ts`
300137
+ * carries a bearer reader for the local bootstrap/pairing/desktop lanes, and
300138
+ * those must stay untouched by this change. This function is only ever
300139
+ * called from `authenticateForgeCloudOwnerRequest`, which itself only runs
300140
+ * when `serverConfig.forgeCloudShellMode === true` — so a non-cloud server's
300141
+ * bearer lanes never pass through here.
300142
+ */
300143
+ function readForgeCloudOwnerBearerToken(request) {
300144
+ const header = request.headers["authorization"];
300145
+ if (typeof header !== "string" || !header.startsWith(BEARER_PREFIX)) return null;
300146
+ const token = header.slice(7).trim();
300147
+ return token.length > 0 ? token : null;
300148
+ }
299986
300149
  function assertionVerifierConfig(config) {
299987
300150
  const publicKey = config.forgeCloudOwnerAssertionPublicKey;
299988
300151
  const keyId = config.forgeCloudOwnerAssertionKeyId;
@@ -300010,7 +300173,7 @@ function authenticateForgeCloudOwnerRequest(request, config) {
300010
300173
  message: "Forge Cloud owner assertion verification is misconfigured.",
300011
300174
  status: 500
300012
300175
  });
300013
- const token = request.cookies[FORGE_CLOUD_OWNER_ASSERTION_COOKIE];
300176
+ const token = request.cookies["forge_cloud_owner_assertion"] ?? readForgeCloudOwnerBearerToken(request);
300014
300177
  if (!token) return yield* new AuthError({
300015
300178
  message: "Authentication required.",
300016
300179
  status: 401
@@ -321069,7 +321232,7 @@ const MiscRuntimeLayerLive = mergeAll(AnalyticsServiceLayerLive, OpenLive, Serve
321069
321232
  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));
321070
321233
  const RuntimeDependenciesLive = pullRequestServiceFactoryLayer.pipe(provideMerge(RuntimeDependenciesWithoutPullRequestsLive), provideMerge(cmmdProjectIdentityResolverLive.pipe(provide$1(RuntimeDependenciesWithoutPullRequestsLive))), provideMerge(pullRequestProviderRuntimeLive));
321071
321234
  const RuntimeServicesLive = ServerRuntimeStartupLive.pipe(provideMerge(RuntimeDependenciesLive));
321072
- const makeRoutesLayer = mergeAll(attachmentUploadRouteLayer, authBearerBootstrapRouteLayer, authBootstrapRouteLayer, authCommandBearerBootstrapRouteLayer, authCommandBootstrapRouteLayer, authOAuthTokenExchangeRouteLayer, authWebSocketTicketRouteLayer, authCmmdOAuthDeviceRouteLayer, authCmmdOAuthTokenRouteLayer, authCmmdPasswordTokenRouteLayer, authClientsRevokeOthersRouteLayer, authClientsRevokeRouteLayer, authClientsRouteLayer, authLogoutRouteLayer, authPairingLinksRevokeRouteLayer, authPairingLinksRouteLayer, authPairingCredentialRouteLayer, authSessionRenewRouteLayer, 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, orchestrationThreadSnapshotRouteLayer, 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, runtimeFilesystemHealthRouteLayer, claudeNativeGenerationProofRouteLayer, claudeUsageRouteLayer, codexRuntimeProviderReadinessRouteLayer, runtimeDiagnosticsRouteLayer, cloudFoldersRouteLayer, cloudProjectCreateRouteLayer, gitUrlCloneRouteLayer, websocketRpcRouteLayer).pipe(provide$1(browserApiCorsLayer));
321235
+ const makeRoutesLayer = mergeAll(attachmentUploadRouteLayer, authBearerBootstrapRouteLayer, authBootstrapRouteLayer, authCommandBearerBootstrapRouteLayer, authCommandBootstrapRouteLayer, authOAuthTokenExchangeRouteLayer, authWebSocketTicketRouteLayer, authCmmdOAuthDeviceRouteLayer, authCmmdOAuthTokenRouteLayer, authCmmdPasswordTokenRouteLayer, authClientsRevokeOthersRouteLayer, authClientsRevokeRouteLayer, authClientsRouteLayer, authLogoutRouteLayer, authPairingLinksRevokeRouteLayer, authPairingLinksRouteLayer, authPairingCredentialRouteLayer, authSessionRenewRouteLayer, authSessionRouteLayer, authWebSocketTokenRouteLayer, authWebLoginRouteLayer, authWebCallbackRouteLayer, cloudOwnerSessionRedeemRouteLayer, cloudOwnerSessionRevokeRouteLayer, 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, orchestrationThreadSnapshotRouteLayer, 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, runtimeFilesystemHealthRouteLayer, claudeNativeGenerationProofRouteLayer, claudeUsageRouteLayer, codexRuntimeProviderReadinessRouteLayer, runtimeDiagnosticsRouteLayer, cloudFoldersRouteLayer, cloudProjectCreateRouteLayer, gitUrlCloneRouteLayer, websocketRpcRouteLayer).pipe(provide$1(browserApiCorsLayer));
321073
321236
  const runServer = launch$1(unwrap(gen(function* () {
321074
321237
  const config = yield* ServerConfig;
321075
321238
  fixPath({ preferProcessPath: config.forgeCmmdRuntimeMode === true });