@cmmd-center/forge 0.13.7 → 0.13.9

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.
Files changed (22) hide show
  1. package/dist/bin.cjs +408 -69
  2. package/dist/bin.mjs +432 -93
  3. package/dist/client/assets/{CanvasPanel-C21OO2qi.js → CanvasPanel-z0F-jdf1.js} +2 -2
  4. package/dist/client/assets/{CompositeItem-naFGUtSL.js → CompositeItem-P9UVXCKv.js} +2 -2
  5. package/dist/client/assets/{DiffPanel-D_YC838v.js → DiffPanel-DTiRv6A3.js} +3 -3
  6. package/dist/client/assets/{DiffPanel.logic-Bqk_6nE1.js → DiffPanel.logic-BrHjYrbX.js} +2 -2
  7. package/dist/client/assets/{DiffPanelShell-D1KMJc9z.js → DiffPanelShell-CivZRVc4.js} +114 -114
  8. package/dist/client/assets/{DiffWorkerPoolProvider-B5tF5UEc.js → DiffWorkerPoolProvider-Vm64F-i1.js} +10 -10
  9. package/dist/client/assets/{PullRequestCodePanel-ClD3ZXbi.js → PullRequestCodePanel-DJPvOmkY.js} +3 -3
  10. package/dist/client/assets/{Virtualizer-cvcMb_IQ.js → Virtualizer-CJivXWYL.js} +2 -2
  11. package/dist/client/assets/{canvasStateStore-CpNOSHBt.js → canvasStateStore-CdQxd2aO.js} +2 -2
  12. package/dist/client/assets/{cmmdAuthRedirect-DdH7K490.js → cmmdAuthRedirect-Bp1uQaQ9.js} +2 -2
  13. package/dist/client/assets/{index-BE83u7Db.css → index-DTtOLoW6.css} +1 -1
  14. package/dist/client/assets/index-TdSTLuh4.js +154 -0
  15. package/dist/client/assets/{popover-BajtiGgk.js → popover-CUSlb3eK.js} +2 -2
  16. package/dist/client/assets/{src-D6fBWY6U.js → src-BL-mOkT1.js} +2 -2
  17. package/dist/client/assets/{toggle-BRNCUuRT.js → toggle-BREV66nT.js} +2 -2
  18. package/dist/client/index.html +11 -11
  19. package/dist/forge-build.json +1 -1
  20. package/dist/{open-D8mGyWmt.mjs → open-FIgTDosf.mjs} +3 -3
  21. package/package.json +1 -1
  22. package/dist/client/assets/index-yLc4LtMp.js +0 -153
package/dist/bin.cjs CHANGED
@@ -27083,6 +27083,23 @@ function encodeCmmdRuntimeThreadLifecycleMetadata(lifecycle) {
27083
27083
  } };
27084
27084
  }
27085
27085
  //#endregion
27086
+ //#region ../../packages/contracts/src/cmmdRuntimeThreadGoal.ts
27087
+ function encodeCmmdRuntimeThreadGoalMetadata(goal) {
27088
+ return { forgeGoal: {
27089
+ schemaVersion: 1,
27090
+ goal: goal.goal
27091
+ } };
27092
+ }
27093
+ function decodeCmmdRuntimeThreadGoalMetadata(metadata) {
27094
+ const value = metadata?.forgeGoal;
27095
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
27096
+ const record = value;
27097
+ const goal = record.goal;
27098
+ if (record.schemaVersion !== 1 || goal !== null && typeof goal !== "string") return null;
27099
+ if (typeof goal === "string" && goal.trim().length === 0) return null;
27100
+ return { goal };
27101
+ }
27102
+ //#endregion
27086
27103
  //#region ../../packages/contracts/src/cmmdRuntimeThreadWorkspace.ts
27087
27104
  function encodeCmmdRuntimeThreadWorkspaceMetadata(workspace) {
27088
27105
  return { forgeWorkspace: {
@@ -66272,7 +66289,7 @@ function normalizeNumberish(value) {
66272
66289
  }
66273
66290
  //#endregion
66274
66291
  //#region package.json
66275
- var version$1 = "0.13.7";
66292
+ var version$1 = "0.13.9";
66276
66293
  //#endregion
66277
66294
  //#region src/sentry.ts
66278
66295
  const SERVER_APP_NAME = "forge-server";
@@ -88047,14 +88064,18 @@ function resolveRuntimeGitHubGrantAuthFromEnv(headers) {
88047
88064
  }
88048
88065
  function buildCmmdRuntimeGrantFetchRequest(auth, repoFullName) {
88049
88066
  return {
88050
- url: new URL(`/api/forge/runtimes/${encodeURIComponent(auth.runtimeId)}/github/installation-token`, resolveCommandAppUrl()).toString(),
88067
+ url: new URL(`/api/forge/runtimes/${encodeURIComponent(auth.runtimeId)}/scm/credential`, resolveCommandAppUrl()).toString(),
88051
88068
  init: {
88052
88069
  method: "POST",
88053
88070
  headers: {
88054
88071
  Authorization: `Bearer ${auth.token}`,
88055
88072
  "Content-Type": "application/json"
88056
88073
  },
88057
- body: JSON.stringify({ repo_full_name: repoFullName })
88074
+ body: JSON.stringify({
88075
+ provider: "github",
88076
+ host: "github.com",
88077
+ repository_path: repoFullName
88078
+ })
88058
88079
  }
88059
88080
  };
88060
88081
  }
@@ -88516,10 +88537,19 @@ function fetchInstallationTokenForAuth(auth, repoFullName) {
88516
88537
  ok: false,
88517
88538
  ...lastError
88518
88539
  };
88519
- if (tokenResp.ok) return {
88520
- ok: true,
88521
- token: (yield* require_Schema$1.promise(() => tokenResp.json())).token
88522
- };
88540
+ if (tokenResp.ok) {
88541
+ const tokenData = yield* require_Schema$1.promise(() => tokenResp.json());
88542
+ const token = auth.kind === "cmmd-runtime-ticket" ? tokenData.credential : tokenData.token;
88543
+ if (typeof token === "string" && token.trim().length > 0) return {
88544
+ ok: true,
88545
+ token: token.trim()
88546
+ };
88547
+ return {
88548
+ ok: false,
88549
+ status: 502,
88550
+ error: "CMMD returned an invalid source-control credential response."
88551
+ };
88552
+ }
88523
88553
  const err = yield* require_Schema$1.promise(() => tokenResp.json().catch(() => ({})));
88524
88554
  lastError = {
88525
88555
  status: tokenResp.status,
@@ -89441,23 +89471,38 @@ var GitHubBroker = class {
89441
89471
  async cloneRepository(auth, input) {
89442
89472
  const cloneInput = validateCloneInput(input);
89443
89473
  if ("ok" in cloneInput) return cloneInput;
89444
- const { branch } = cloneInput;
89474
+ let { branch } = cloneInput;
89445
89475
  const gitToken = await this.resolveInstallationToken(auth, input.repoFullName);
89446
89476
  if (typeof gitToken !== "string") return gitToken;
89447
- const initFailure = await this.runCloneGitStep([
89477
+ try {
89478
+ await (0, node_fs_promises.mkdir)(input.destination);
89479
+ } catch (error) {
89480
+ if (isNodeErrorWithCode(error, "EEXIST")) return cloneDestinationExistsResult();
89481
+ return {
89482
+ ok: false,
89483
+ code: "GITHUB_CLONE_DESTINATION_CREATE_FAILED",
89484
+ error: "Could not create the clone destination."
89485
+ };
89486
+ }
89487
+ const initFailure = await this.runCloneGitStep(branch === null ? ["init", input.destination] : [
89448
89488
  "init",
89449
89489
  "-b",
89450
89490
  branch,
89451
89491
  input.destination
89452
89492
  ], "GITHUB_CLONE_INIT_FAILED", "Could not initialize the clone destination.");
89453
- if (initFailure) return initFailure;
89493
+ if (initFailure) return removeFailedCloneDestination(input.destination, initFailure);
89454
89494
  const configured = await this.configureProjectGitCredential({
89455
89495
  cwd: input.destination,
89456
89496
  repoFullName: input.repoFullName,
89457
89497
  token: gitToken,
89458
89498
  remoteMode: "add"
89459
89499
  });
89460
- if (!configured.ok) return configured;
89500
+ if (!configured.ok) return removeFailedCloneDestination(input.destination, configured);
89501
+ if (branch === null) {
89502
+ const defaultBranch = await this.resolveRemoteDefaultBranch(input.destination);
89503
+ if (typeof defaultBranch !== "string") return removeFailedCloneDestination(input.destination, defaultBranch);
89504
+ branch = defaultBranch;
89505
+ }
89461
89506
  const fetchFailure = await this.runCloneGitStep([
89462
89507
  "-C",
89463
89508
  input.destination,
@@ -89467,7 +89512,7 @@ var GitHubBroker = class {
89467
89512
  "origin",
89468
89513
  branch
89469
89514
  ], "GITHUB_CLONE_FETCH_FAILED", "Could not fetch the requested repository branch.", { timeoutMs: 12e4 });
89470
- if (fetchFailure) return fetchFailure;
89515
+ if (fetchFailure) return removeFailedCloneDestination(input.destination, fetchFailure);
89471
89516
  const checkoutFailure = await this.runCloneGitStep([
89472
89517
  "-C",
89473
89518
  input.destination,
@@ -89476,7 +89521,7 @@ var GitHubBroker = class {
89476
89521
  branch,
89477
89522
  "FETCH_HEAD"
89478
89523
  ], "GITHUB_CLONE_CHECKOUT_FAILED", "Could not check out the requested repository branch.");
89479
- if (checkoutFailure) return checkoutFailure;
89524
+ if (checkoutFailure) return removeFailedCloneDestination(input.destination, checkoutFailure);
89480
89525
  return {
89481
89526
  ok: true,
89482
89527
  data: {
@@ -90086,9 +90131,9 @@ var GitHubBroker = class {
90086
90131
  };
90087
90132
  }
90088
90133
  async resolveInstallationToken(auth, repoFullName) {
90089
- const runtimeGrant = this.resolveRuntimeGrant();
90134
+ const runtimeGrant = this.resolveRuntimeGrant("scm");
90090
90135
  if (runtimeGrant) {
90091
- const token = await this.fetchRuntimeInstallationToken(runtimeGrant, repoFullName);
90136
+ const token = await this.fetchRuntimeScmCredential(runtimeGrant, repoFullName);
90092
90137
  if (!token.ok) return token;
90093
90138
  return token.token ?? invalidInstallationTokenResult();
90094
90139
  }
@@ -90471,7 +90516,7 @@ var GitHubBroker = class {
90471
90516
  repoFullName
90472
90517
  };
90473
90518
  }
90474
- resolveRuntimeGrant() {
90519
+ resolveRuntimeGrant(requiredScope = "github") {
90475
90520
  if (this.runtimeRole !== "user-vm") return null;
90476
90521
  const runtimeId = process.env.FORGE_CMMD_RUNTIME_ID?.trim();
90477
90522
  if (!runtimeId) return null;
@@ -90481,7 +90526,7 @@ var GitHubBroker = class {
90481
90526
  runtimeId,
90482
90527
  machineId: identity.machineId,
90483
90528
  credentialEpoch: identity.credentialEpoch,
90484
- requiredScope: "github"
90529
+ requiredScope
90485
90530
  });
90486
90531
  return authority ? {
90487
90532
  runtimeId,
@@ -90495,8 +90540,8 @@ var GitHubBroker = class {
90495
90540
  token: legacyToken
90496
90541
  } : null;
90497
90542
  }
90498
- runtimeGrantAuthContext() {
90499
- const grant = this.resolveRuntimeGrant();
90543
+ runtimeGrantAuthContext(requiredScope = "github") {
90544
+ const grant = this.resolveRuntimeGrant(requiredScope);
90500
90545
  if (grant === null) return null;
90501
90546
  return {
90502
90547
  sessionId: grant.sessionId ?? AuthSessionId.make(`cmmd-runtime:${grant.runtimeId}`),
@@ -90548,13 +90593,33 @@ var GitHubBroker = class {
90548
90593
  };
90549
90594
  }
90550
90595
  async fetchRuntimeInstallationToken(grant, repoFullName) {
90551
- const response = await this.fetchImpl(makeUrl(this.commandAppUrl, `/api/forge/runtimes/${encodeURIComponent(grant.runtimeId)}/github/installation-token`), {
90596
+ return this.fetchRuntimeCredential(grant, {
90597
+ url: makeUrl(this.commandAppUrl, `/api/forge/runtimes/${encodeURIComponent(grant.runtimeId)}/github/installation-token`),
90598
+ requestBody: { repo_full_name: repoFullName },
90599
+ responseField: "token",
90600
+ label: "GitHub installation token"
90601
+ });
90602
+ }
90603
+ async fetchRuntimeScmCredential(grant, repoFullName) {
90604
+ return this.fetchRuntimeCredential(grant, {
90605
+ url: makeUrl(this.commandAppUrl, `/api/forge/runtimes/${encodeURIComponent(grant.runtimeId)}/scm/credential`),
90606
+ requestBody: {
90607
+ provider: "github",
90608
+ host: "github.com",
90609
+ repository_path: repoFullName
90610
+ },
90611
+ responseField: "credential",
90612
+ label: "GitHub source-control credential"
90613
+ });
90614
+ }
90615
+ async fetchRuntimeCredential(grant, input) {
90616
+ const response = await this.fetchImpl(input.url, {
90552
90617
  method: "POST",
90553
90618
  headers: {
90554
90619
  Authorization: `Bearer ${grant.token}`,
90555
90620
  "Content-Type": "application/json"
90556
90621
  },
90557
- body: JSON.stringify({ repo_full_name: repoFullName }),
90622
+ body: JSON.stringify(input.requestBody),
90558
90623
  signal: AbortSignal.timeout(GITHUB_BROKER_REQUEST_TIMEOUT_MS)
90559
90624
  });
90560
90625
  const body = await parseResponseBody(response);
@@ -90563,10 +90628,10 @@ var GitHubBroker = class {
90563
90628
  status: response.status,
90564
90629
  code: response.status === 401 ? "GITHUB_AUTH_REQUIRED" : "GITHUB_BROKER_REQUEST_FAILED",
90565
90630
  ...response.status === 401 ? { userActionRequired: "connect_github" } : {},
90566
- error: errorFromBody(body, `GitHub installation token request failed with status ${response.status}.`),
90631
+ error: errorFromBody(body, `${input.label} request failed with status ${response.status}.`),
90567
90632
  data: body
90568
90633
  };
90569
- const token = typeof body === "object" && body !== null ? body.token : null;
90634
+ const token = typeof body === "object" && body !== null ? body[input.responseField] : null;
90570
90635
  if (typeof token !== "string" || token.trim().length === 0) return invalidInstallationTokenResult();
90571
90636
  return {
90572
90637
  ok: true,
@@ -90585,6 +90650,25 @@ var GitHubBroker = class {
90585
90650
  const branch = result.result.stdout.trim();
90586
90651
  return branch.length > 0 ? branch : null;
90587
90652
  }
90653
+ async resolveRemoteDefaultBranch(cwd) {
90654
+ const result = await this.runGit([
90655
+ "-C",
90656
+ cwd,
90657
+ "ls-remote",
90658
+ "--symref",
90659
+ "origin",
90660
+ "HEAD"
90661
+ ], { allowNonZeroExit: true });
90662
+ if (!isGitRunResult(result)) return result;
90663
+ if (result.result.code !== 0) return gitCommandFailure("GITHUB_DEFAULT_BRANCH_LOOKUP_FAILED", result.result.stderr, "Could not determine the repository default branch.");
90664
+ const branch = /^ref:\s+refs\/heads\/([^\s]+)\s+HEAD$/m.exec(result.result.stdout)?.[1];
90665
+ if (branch === void 0) return {
90666
+ ok: false,
90667
+ code: "GITHUB_DEFAULT_BRANCH_RESPONSE_INVALID",
90668
+ error: "GitHub did not return a valid default branch for the repository."
90669
+ };
90670
+ return validateGitBranchName(branch) ?? branch;
90671
+ }
90588
90672
  };
90589
90673
  function isCmmdCloudRuntimeModeEnv() {
90590
90674
  return process.env.FORGE_CMMD_RUNTIME_MODE === "true" || process.env.FORGE_CMMD_RUNTIME_MODE === "1";
@@ -90669,20 +90753,40 @@ function validateCloneDestination(destination) {
90669
90753
  code: "GITHUB_CLONE_DESTINATION_INVALID",
90670
90754
  error: "An absolute clone destination is required."
90671
90755
  };
90672
- if ((0, node_fs.existsSync)(destination)) return {
90756
+ if ((0, node_fs.existsSync)(destination)) return cloneDestinationExistsResult();
90757
+ return null;
90758
+ }
90759
+ function cloneDestinationExistsResult() {
90760
+ return {
90673
90761
  ok: false,
90674
90762
  code: "GITHUB_CLONE_DESTINATION_EXISTS",
90675
90763
  error: "Clone destination already exists; choose a new empty path."
90676
90764
  };
90677
- return null;
90765
+ }
90766
+ function isNodeErrorWithCode(error, code) {
90767
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
90768
+ }
90769
+ async function removeFailedCloneDestination(destination, failure) {
90770
+ try {
90771
+ await (0, node_fs_promises.rm)(destination, {
90772
+ recursive: true,
90773
+ force: true
90774
+ });
90775
+ return failure;
90776
+ } catch {
90777
+ return {
90778
+ ...failure,
90779
+ error: `${failure.error ?? "Clone failed."} The incomplete clone destination could not be removed.`
90780
+ };
90781
+ }
90678
90782
  }
90679
90783
  function validateCloneInput(input) {
90680
90784
  const repoFullNameValidation = validateRepoFullName(input.repoFullName);
90681
90785
  if (repoFullNameValidation) return repoFullNameValidation;
90682
90786
  const destinationValidation = validateCloneDestination(input.destination);
90683
90787
  if (destinationValidation) return destinationValidation;
90684
- const branch = input.branch?.trim() || "main";
90685
- return validateGitBranchName(branch) ?? { branch };
90788
+ const branch = input.branch?.trim() || null;
90789
+ return branch === null ? { branch } : validateGitBranchName(branch) ?? { branch };
90686
90790
  }
90687
90791
  function validateGitBranchName(branch) {
90688
90792
  if (branch.length === 0 || branch.startsWith("-") || Array.from(branch).some((character) => {
@@ -93855,6 +93959,17 @@ const admitNormalizedDispatchCommand = (command, admit) => require_Schema$1.unin
93855
93959
  //#region src/orchestration/bootstrapCommandCoordinator.ts
93856
93960
  const MAX_COMPLETED_COMMANDS_PER_ENGINE = 256;
93857
93961
  const commandsByEngine = /* @__PURE__ */ new WeakMap();
93962
+ const sealBootstrapCommand = (engine, commandId) => {
93963
+ const entry = commandsByEngine.get(engine)?.get(commandId);
93964
+ if (entry) entry.cancellable = false;
93965
+ };
93966
+ const cancelBootstrapCommand = (engine, threadId) => require_Schema$1.promise(async () => {
93967
+ const entry = [...commandsByEngine.get(engine)?.values() ?? []].find((candidate) => candidate.threadId === threadId && !candidate.completed && candidate.cancellable);
93968
+ if (!entry) return false;
93969
+ entry.controller.abort();
93970
+ await entry.promise.catch(() => void 0);
93971
+ return true;
93972
+ });
93858
93973
  const toBootstrapError = (error) => require_Schema$1.is(OrchestrationDispatchCommandError)(error) ? error : new OrchestrationDispatchCommandError({
93859
93974
  message: error instanceof Error ? error.message : "Bootstrap command failed.",
93860
93975
  cause: error
@@ -93874,7 +93989,7 @@ const pruneCompletedCommands = (commands) => {
93874
93989
  * the registry to one server runtime, so reconnects share work while separate
93875
93990
  * runtimes remain isolated.
93876
93991
  */
93877
- const runBootstrapCommand = (engine, commandId, bootstrapEffect) => {
93992
+ const runBootstrapCommand = (engine, commandId, bootstrapEffect, threadId) => {
93878
93993
  let commands = commandsByEngine.get(engine);
93879
93994
  if (commands === void 0) {
93880
93995
  commands = /* @__PURE__ */ new Map();
@@ -93887,16 +94002,21 @@ const runBootstrapCommand = (engine, commandId, bootstrapEffect) => {
93887
94002
  });
93888
94003
  pruneCompletedCommands(commands);
93889
94004
  let entry;
93890
- const promise = require_Schema$1.runPromise(bootstrapEffect).then((result) => {
94005
+ const controller = new AbortController();
94006
+ const promise = Promise.resolve().then(() => require_Schema$1.runPromise(bootstrapEffect, { signal: controller.signal })).then((result) => {
93891
94007
  entry.completed = true;
93892
94008
  return result;
93893
94009
  }, (error) => {
93894
- commands.delete(commandId);
94010
+ entry.completed = true;
94011
+ if (!controller.signal.aborted) commands.delete(commandId);
93895
94012
  throw error;
93896
94013
  });
93897
94014
  entry = {
93898
94015
  promise,
93899
- completed: false
94016
+ completed: false,
94017
+ threadId,
94018
+ controller,
94019
+ cancellable: true
93900
94020
  };
93901
94021
  commands.set(commandId, entry);
93902
94022
  return require_Schema$1.tryPromise({
@@ -93906,6 +94026,10 @@ const runBootstrapCommand = (engine, commandId, bootstrapEffect) => {
93906
94026
  };
93907
94027
  //#endregion
93908
94028
  //#region src/orchestration/bootstrapDispatch.ts
94029
+ const interruptBootstrapTurnStart = (engine, command) => require_Schema$1.gen(function* () {
94030
+ if (yield* cancelBootstrapCommand(engine, command.threadId)) return { sequence: (yield* engine.getReadModel()).snapshotSequence };
94031
+ return yield* engine.dispatch(command);
94032
+ });
93909
94033
  const MAX_BOOTSTRAP_OUTPUT_LINE_LENGTH = 1e3;
93910
94034
  const toBootstrapDispatchCommandCauseError = (cause) => {
93911
94035
  const error = require_Schema$1.squash(cause);
@@ -93992,6 +94116,7 @@ const prepareBootstrapWorktree = (input) => require_Schema$1.gen(function* () {
93992
94116
  const requestedAt = (/* @__PURE__ */ new Date()).toISOString();
93993
94117
  const baseBranchLabel = bootstrapWorktree.baseBranch ?? "<default>";
93994
94118
  const requestedPayload = {
94119
+ turnRequestedAt: input.command.createdAt,
93995
94120
  projectCwd: bootstrapWorktree.projectCwd,
93996
94121
  baseBranch: bootstrapWorktree.baseBranch,
93997
94122
  branch: bootstrapWorktree.branch,
@@ -94012,6 +94137,16 @@ const prepareBootstrapWorktree = (input) => require_Schema$1.gen(function* () {
94012
94137
  branch: bootstrapWorktree.baseBranch,
94013
94138
  newBranch: bootstrapWorktree.branch,
94014
94139
  path: null,
94140
+ onStage: (update) => appendWorktreeActivity({
94141
+ orchestrationEngine: input.orchestrationEngine,
94142
+ threadId: input.command.threadId,
94143
+ commandId: CommandId.make(`server:worktree-stage:${input.command.commandId}:${crypto.randomUUID()}`),
94144
+ kind: "worktree.stage",
94145
+ summary: "Preparing worktree",
94146
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
94147
+ payload: update,
94148
+ tone: "info"
94149
+ }).pipe(require_Schema$1.asVoid, require_Schema$1.ignore),
94015
94150
  progress: {
94016
94151
  onStdoutLine: (line) => {
94017
94152
  const detail = truncateBootstrapOutputLine(line);
@@ -94051,6 +94186,7 @@ const prepareBootstrapWorktree = (input) => require_Schema$1.gen(function* () {
94051
94186
  }
94052
94187
  }
94053
94188
  }).pipe(require_Schema$1.catchCause((cause) => {
94189
+ if (require_Schema$1.hasInterruptsOnly(cause)) return require_Schema$1.failCause(cause);
94054
94190
  const error = require_Schema$1.squash(cause);
94055
94191
  const detail = error instanceof Error ? error.message : "Unknown worktree failure.";
94056
94192
  return appendWorktreeActivity({
@@ -94177,7 +94313,16 @@ const dispatchBootstrapTurnStart = (input, command) => require_Schema$1.gen(func
94177
94313
  worktreePath
94178
94314
  }),
94179
94315
  onSuccess: (setupResult) => {
94180
- if (setupResult.status !== "started") return require_Schema$1.void_;
94316
+ if (setupResult.status !== "started") return appendSetupScriptActivity({
94317
+ orchestrationEngine,
94318
+ threadId: command.threadId,
94319
+ commandId: bootstrapCommandId(command, "setup-script-skipped"),
94320
+ kind: "setup-script.skipped",
94321
+ summary: "No setup script configured",
94322
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
94323
+ payload: {},
94324
+ tone: "info"
94325
+ }).pipe(require_Schema$1.asVoid, require_Schema$1.ignore);
94181
94326
  return recordSetupScriptStarted({
94182
94327
  requestedAt,
94183
94328
  worktreePath,
@@ -94207,13 +94352,33 @@ const dispatchBootstrapTurnStart = (input, command) => require_Schema$1.gen(func
94207
94352
  targetProjectCwd = preparedWorktree.projectCwd;
94208
94353
  }
94209
94354
  yield* runSetupProgram();
94355
+ if (bootstrap?.prepareWorktree) yield* appendWorktreeActivity({
94356
+ orchestrationEngine,
94357
+ threadId: command.threadId,
94358
+ commandId: bootstrapCommandId(command, "launch-agent-starting"),
94359
+ kind: "launch.agent-starting",
94360
+ summary: "Starting agent",
94361
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
94362
+ payload: { setupRequested: bootstrap.runSetupScript === true },
94363
+ tone: "info"
94364
+ }).pipe(require_Schema$1.ignore);
94365
+ sealBootstrapCommand(orchestrationEngine, command.commandId);
94210
94366
  return yield* orchestrationEngine.dispatch(finalTurnStartCommand);
94211
94367
  });
94212
- return yield* runBootstrapCommand(orchestrationEngine, command.commandId, bootstrapProgram.pipe(require_Schema$1.catchCause((cause) => {
94368
+ return yield* runBootstrapCommand(orchestrationEngine, command.commandId, bootstrapProgram.pipe(require_Schema$1.onInterrupt(() => appendWorktreeActivity({
94369
+ orchestrationEngine,
94370
+ threadId: command.threadId,
94371
+ commandId: bootstrapCommandId(command, "launch-cancelled"),
94372
+ kind: "launch.cancelled",
94373
+ summary: "Launch cancelled",
94374
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
94375
+ payload: {},
94376
+ tone: "info"
94377
+ }).pipe(require_Schema$1.ignore)), require_Schema$1.catchCause((cause) => {
94213
94378
  const dispatchError = toBootstrapDispatchCommandCauseError(cause);
94214
94379
  if (require_Schema$1.hasInterruptsOnly(cause)) return require_Schema$1.fail(dispatchError);
94215
94380
  return cleanupCreatedThread().pipe(require_Schema$1.flatMap(() => require_Schema$1.fail(dispatchError)));
94216
- })));
94381
+ })), command.threadId);
94217
94382
  });
94218
94383
  //#endregion
94219
94384
  //#region src/orchestration/Services/OrchestrationEngine.ts
@@ -95094,7 +95259,7 @@ function hasValidRuntimeIdentity(value) {
95094
95259
  }
95095
95260
  function decodeRuntime$1(value) {
95096
95261
  if (!isRecord$19(value) || !hasValidRuntimeIdentity(value)) return null;
95097
- if (!nullableString(value.endpointUrl) || value.endpointUrl !== null && !URL.canParse(value.endpointUrl) || !nullableInteger(value.deviceId) || !nullableString(value.workspaceRoot) || !nullableString(value.githubRepoFullName) || !(value.lastSeenAt === null || isIsoDateTime(value.lastSeenAt)) || !(value.metadata === null || isRecord$19(value.metadata))) return null;
95262
+ if (!nullableString(value.endpointUrl) || value.endpointUrl !== null && !URL.canParse(value.endpointUrl) || !nullableInteger(value.deviceId) || !nullableString(value.workspaceRoot) || !nullableString(value.githubRepoFullName) || !(value.lastSeenAt === null || isIsoDateTime(value.lastSeenAt)) || !(value.metadata === void 0 || value.metadata === null || isRecord$19(value.metadata))) return null;
95098
95263
  return value;
95099
95264
  }
95100
95265
  function decodeProject(value) {
@@ -95107,7 +95272,7 @@ function decodeProject(value) {
95107
95272
  };
95108
95273
  }
95109
95274
  function decodeThread$1(value) {
95110
- if (!isRecord$19(value) || !isNonBlankString(value.threadId) || typeof value.title !== "string" || !isReplicaThreadStatus(value.status) || !nullableString(value.model) || !nullableString(value.branch) || !(value.lastActivityAt === null || isIsoDateTime(value.lastActivityAt))) return null;
95275
+ if (!isRecord$19(value) || !isNonBlankString(value.threadId) || typeof value.title !== "string" || !isReplicaThreadStatus(value.status) || !nullableString(value.model) || !nullableString(value.branch) || !(value.lastActivityAt === null || isIsoDateTime(value.lastActivityAt)) || !(value.metadata === void 0 || value.metadata === null || isRecord$19(value.metadata))) return null;
95111
95276
  return value;
95112
95277
  }
95113
95278
  function decodeSummary(value) {
@@ -95462,18 +95627,27 @@ function runtimeThreadFinalGenerationId(runtimeId, streamKey, events) {
95462
95627
  function canonicalKindFields(event) {
95463
95628
  switch (event.kind) {
95464
95629
  case "user_message":
95465
- case "assistant_message": return { text: event.text };
95630
+ case "assistant_message": return canonicalMessageFields(event);
95466
95631
  case "activity_summary":
95467
95632
  case "error_summary": return { summary: event.summary };
95468
95633
  case "turn_status": return { status: event.status };
95469
- case "tool_call": return {
95470
- summary: event.summary,
95471
- status: event.status,
95472
- ...event.payload !== void 0 ? { payload: event.payload } : {}
95473
- };
95634
+ case "tool_call": return canonicalToolCallFields(event);
95474
95635
  case "turn_usage": return canonicalTurnUsageFields(event);
95475
95636
  }
95476
95637
  }
95638
+ function canonicalMessageFields(event) {
95639
+ return {
95640
+ text: event.text,
95641
+ ...event.payload === void 0 ? {} : { payload: event.payload }
95642
+ };
95643
+ }
95644
+ function canonicalToolCallFields(event) {
95645
+ return {
95646
+ summary: event.summary,
95647
+ status: event.status,
95648
+ ...event.payload === void 0 ? {} : { payload: event.payload }
95649
+ };
95650
+ }
95477
95651
  /**
95478
95652
  * The usage row's attribution as canonical fields, matching CMMD's
95479
95653
  * `forgeUsageRowAttributionFields`: present only when the publisher named them,
@@ -95615,8 +95789,21 @@ function eventsMatchAcknowledgement(events, acknowledgedSequence) {
95615
95789
  return acknowledgedSequence === expectedSequence - 1;
95616
95790
  }
95617
95791
  //#endregion
95792
+ //#region src/runtimeReplication/replicaMessagePayload.ts
95793
+ function decodeReplicaMessageAttachments(payload) {
95794
+ if (payload === null || typeof payload !== "object" || !("attachments" in payload)) return;
95795
+ const attachments = payload.attachments;
95796
+ if (!Array.isArray(attachments)) return void 0;
95797
+ const decoded = attachments.filter(require_Schema$1.is(ChatAttachment));
95798
+ return decoded.length > 0 ? decoded : void 0;
95799
+ }
95800
+ function messageAttachmentPayload(message) {
95801
+ return message.attachments && message.attachments.length > 0 ? { payload: { attachments: message.attachments } } : {};
95802
+ }
95803
+ //#endregion
95618
95804
  //#region src/runtimeReplication/replicaHydrationMapping.ts
95619
95805
  function replicaMessage(runtimeId, generationId, event) {
95806
+ const attachments = decodeReplicaMessageAttachments(event.payload);
95620
95807
  return {
95621
95808
  id: MessageId.make(encodeReplicaSourceMessageId({
95622
95809
  sequence: event.sequence,
@@ -95629,7 +95816,8 @@ function replicaMessage(runtimeId, generationId, event) {
95629
95816
  turnId: null,
95630
95817
  streaming: false,
95631
95818
  createdAt: event.occurredAt,
95632
- updatedAt: event.occurredAt
95819
+ updatedAt: event.occurredAt,
95820
+ ...attachments ? { attachments: [...attachments] } : {}
95633
95821
  };
95634
95822
  }
95635
95823
  function replicaTurnUsage(event) {
@@ -95662,11 +95850,15 @@ function replicaEventBase(event) {
95662
95850
  function replicaTextEvent(event, base) {
95663
95851
  switch (event.kind) {
95664
95852
  case "user_message":
95665
- case "assistant_message": return {
95666
- ...base,
95667
- kind: event.kind,
95668
- text: event.text
95669
- };
95853
+ case "assistant_message": {
95854
+ const attachments = decodeReplicaMessageAttachments(event.payload);
95855
+ return {
95856
+ ...base,
95857
+ kind: event.kind,
95858
+ text: event.text,
95859
+ ...attachments ? { payload: { attachments } } : {}
95860
+ };
95861
+ }
95670
95862
  case "activity_summary":
95671
95863
  case "error_summary": return {
95672
95864
  ...base,
@@ -95776,7 +95968,7 @@ function replicaToOrchestrationThread(input) {
95776
95968
  status: archived ? "archived" : "idle",
95777
95969
  workerRole: null,
95778
95970
  pendingAutoCreatePrompt: null,
95779
- goal: null,
95971
+ goal: decodeCmmdRuntimeThreadGoalMetadata(detail.thread.metadata)?.goal ?? null,
95780
95972
  titleRegeneration: null
95781
95973
  }
95782
95974
  };
@@ -97313,7 +97505,8 @@ function serializeReplicaMessage(message) {
97313
97505
  occurredAt: message.createdAt,
97314
97506
  ...source.turnId === void 0 ? {} : { turnId: source.turnId },
97315
97507
  kind: message.role === "user" ? "user_message" : "assistant_message",
97316
- text: message.text
97508
+ text: message.text,
97509
+ ...messageAttachmentPayload(message)
97317
97510
  }
97318
97511
  };
97319
97512
  }
@@ -97373,7 +97566,8 @@ function serializeRuntimeInventory(snapshot, providerInventory) {
97373
97566
  settledAt: thread.settledAt ?? null,
97374
97567
  settledOverride: thread.settledOverride ?? null
97375
97568
  }),
97376
- ...encodeCmmdRuntimeThreadWorkspaceMetadata({ worktreePath: thread.worktreePath })
97569
+ ...encodeCmmdRuntimeThreadWorkspaceMetadata({ worktreePath: thread.worktreePath }),
97570
+ ...encodeCmmdRuntimeThreadGoalMetadata({ goal: thread.goal })
97377
97571
  }
97378
97572
  })),
97379
97573
  metadata: {
@@ -97408,7 +97602,8 @@ function orderedLocalMessageEvent(message, content) {
97408
97602
  occurredAt: canonicalRuntimeEventTimestamp(message.createdAt),
97409
97603
  ...eventTurn(message.turnId),
97410
97604
  kind: message.role === "user" ? "user_message" : "assistant_message",
97411
- text: content
97605
+ text: content,
97606
+ ...messageAttachmentPayload(message)
97412
97607
  }
97413
97608
  };
97414
97609
  }
@@ -100899,6 +101094,7 @@ function emptyConfig(source, path) {
100899
101094
  terminals: [],
100900
101095
  systemPackages: [],
100901
101096
  secrets: [],
101097
+ repositoryDependencies: [],
100902
101098
  issues: []
100903
101099
  };
100904
101100
  }
@@ -100984,6 +101180,7 @@ function readConfigFile(source, path) {
100984
101180
  terminals: terminalsFromValue(parsed.terminals),
100985
101181
  systemPackages: stringArray(parsed.systemPackages ?? parsed.aptPackages ?? parsed.packages),
100986
101182
  secrets: stringArray(parsed.secrets ?? parsed.envSecrets),
101183
+ repositoryDependencies: stringArray(parsed.repositoryDependencies),
100987
101184
  issues: []
100988
101185
  };
100989
101186
  }
@@ -101396,6 +101593,7 @@ const EMPTY_WORKSPACE_ENVIRONMENT_CONFIG = {
101396
101593
  terminals: [],
101397
101594
  systemPackages: [],
101398
101595
  secrets: [],
101596
+ repositoryDependencies: [],
101399
101597
  issues: []
101400
101598
  };
101401
101599
  function buildCwdCheck(cwdExists) {
@@ -106203,7 +106401,7 @@ const makeWsRpcLayer = (currentSessionId, currentUserId) => WsRpcGroup.toLayer(r
106203
106401
  git,
106204
106402
  gitStatusBroadcaster,
106205
106403
  projectSetupScriptRunner
106206
- }, normalizedCommand) : orchestrationEngine.dispatch(normalizedCommand).pipe(require_Schema$1.mapError((cause) => toDispatchCommandError(cause, "Failed to dispatch orchestration command")));
106404
+ }, normalizedCommand) : (normalizedCommand.type === "thread.turn.interrupt" ? interruptBootstrapTurnStart(orchestrationEngine, normalizedCommand) : orchestrationEngine.dispatch(normalizedCommand)).pipe(require_Schema$1.mapError((cause) => toDispatchCommandError(cause, "Failed to dispatch orchestration command")));
106207
106405
  return startup.enqueueCommand(dispatchEffect).pipe(require_Schema$1.mapError((cause) => toDispatchCommandError(cause, "Failed to dispatch orchestration command")));
106208
106406
  };
106209
106407
  const loadServerConfig = require_Schema$1.gen(function* () {
@@ -151573,6 +151771,86 @@ async function attestCodexLocalAccountIdentity(input) {
151573
151771
  return identity;
151574
151772
  }
151575
151773
  //#endregion
151774
+ //#region src/workspace/workspaceRepositoryDependencies.ts
151775
+ function repositoryFullName(value) {
151776
+ return value.trim().match(/^(?:https?:\/\/)?github\.com\/([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+?)(?:\.git)?\/?$/i)?.[1] ?? null;
151777
+ }
151778
+ function dependencyDestination(cloudProjectsRoot, repoFullName) {
151779
+ const root = (0, node_path.resolve)(cloudProjectsRoot);
151780
+ const destination = (0, node_path.resolve)((0, node_path.join)(root, (0, node_path.basename)(repoFullName)));
151781
+ const pathFromRoot = (0, node_path.relative)(root, destination);
151782
+ if (pathFromRoot.startsWith("..") || pathFromRoot === "") throw new Error(`Repository dependency ${repoFullName} has an unsafe destination.`);
151783
+ return destination;
151784
+ }
151785
+ async function readOriginFromGit(destination) {
151786
+ const result = await runProcess("git", [
151787
+ "-C",
151788
+ destination,
151789
+ "remote",
151790
+ "get-url",
151791
+ "origin"
151792
+ ], {
151793
+ allowNonZeroExit: true,
151794
+ timeoutMs: 1e4
151795
+ });
151796
+ return result.code === 0 ? result.stdout.trim() : null;
151797
+ }
151798
+ function resolveRepositoryDependencies(declarations, cloudProjectsRoot) {
151799
+ const destinations = /* @__PURE__ */ new Set();
151800
+ return declarations.map((declaration) => {
151801
+ const repoFullName = repositoryFullName(declaration);
151802
+ if (repoFullName === null) throw new Error(`Unsupported repository dependency: ${declaration}`);
151803
+ const destination = dependencyDestination(cloudProjectsRoot, repoFullName);
151804
+ if (destinations.has(destination)) throw new Error(`Repository dependencies collide at ${destination}.`);
151805
+ destinations.add(destination);
151806
+ return {
151807
+ repoFullName,
151808
+ destination
151809
+ };
151810
+ });
151811
+ }
151812
+ async function prepareRepositoryDependency(input) {
151813
+ const { repoFullName, destination } = input.dependency;
151814
+ if ((0, node_fs.existsSync)(destination)) {
151815
+ const origin = await input.readOrigin(destination);
151816
+ const existingRepo = origin === null ? null : parseRepoFullNameFromRemoteUrl(origin);
151817
+ if (existingRepo?.toLowerCase() !== repoFullName.toLowerCase()) throw new Error(`Repository dependency destination ${destination} contains ${existingRepo ?? "no GitHub repository"} instead of ${repoFullName}.`);
151818
+ return {
151819
+ repoFullName,
151820
+ destination,
151821
+ outcome: "existing"
151822
+ };
151823
+ }
151824
+ const result = await input.broker.cloneRepository(input.auth, {
151825
+ repoFullName,
151826
+ destination
151827
+ });
151828
+ if (!result.ok) throw new Error(`Could not prepare repository dependency ${repoFullName}: ${result.error ?? result.code ?? "clone failed"}`);
151829
+ return {
151830
+ repoFullName,
151831
+ destination,
151832
+ outcome: "cloned"
151833
+ };
151834
+ }
151835
+ async function prepareWorkspaceRepositoryDependencies(input) {
151836
+ if (!input.runtimeMode) return [];
151837
+ const dependencies = resolveWorkspaceEnvironmentConfig(input.cwd).repositoryDependencies;
151838
+ if (dependencies.length === 0) return [];
151839
+ const broker = input.broker ?? new GitHubBroker();
151840
+ const auth = broker.runtimeGrantAuthContext("scm");
151841
+ if (auth === null) throw new Error("Repository dependencies require an exact scoped runtime SCM grant.");
151842
+ const readOrigin = input.readOrigin ?? readOriginFromGit;
151843
+ const resolved = resolveRepositoryDependencies(dependencies, input.cloudProjectsRoot);
151844
+ const prepared = [];
151845
+ for (const dependency of resolved) prepared.push(await prepareRepositoryDependency({
151846
+ dependency,
151847
+ broker,
151848
+ auth,
151849
+ readOrigin
151850
+ }));
151851
+ return prepared;
151852
+ }
151853
+ //#endregion
151576
151854
  //#region src/codexAppServerManager.ts
151577
151855
  const CODEX_LOGIN_STATUS_TIMEOUT_MS = 5e3;
151578
151856
  const CODEX_SKILLS_LIST_TIMEOUT_MS = 4e3;
@@ -151907,6 +152185,11 @@ var CodexAppServerManager = class extends node_events.EventEmitter {
151907
152185
  let context;
151908
152186
  try {
151909
152187
  const resolvedCwd = input.cwd ?? process.cwd();
152188
+ await prepareWorkspaceRepositoryDependencies({
152189
+ cwd: resolvedCwd,
152190
+ cloudProjectsRoot: process.env.FORGE_CLOUD_PROJECTS_ROOT?.trim() || "/projects",
152191
+ runtimeMode: process.env.FORGE_CMMD_RUNTIME_MODE === "true"
152192
+ });
151910
152193
  let workspacePreflightReport = runWorkspaceEnvironmentPreflight({
151911
152194
  cwd: resolvedCwd,
151912
152195
  env: process.env
@@ -216993,6 +217276,19 @@ const makeClaudeAdapter = require_Schema$1.fn("makeClaudeAdapter")(function* (op
216993
217276
  const resumeState = readClaudeResumeState(input.resumeCursor);
216994
217277
  const threadId = input.threadId;
216995
217278
  const { existingResumeSessionId, newSessionId, sessionId } = yield* resolveClaudeStartSessionIds(resumeState);
217279
+ const workspaceCwd = input.cwd;
217280
+ if (workspaceCwd) yield* require_Schema$1.tryPromise({
217281
+ try: () => prepareWorkspaceRepositoryDependencies({
217282
+ cwd: workspaceCwd,
217283
+ cloudProjectsRoot: serverConfig.cloudProjectsRoot ?? "/projects",
217284
+ runtimeMode: serverConfig.forgeCmmdRuntimeMode === true
217285
+ }),
217286
+ catch: (cause) => new ProviderAdapterValidationError({
217287
+ provider: PROVIDER$11,
217288
+ operation: "startSession",
217289
+ issue: cause instanceof Error ? cause.message : "Could not prepare declared repository dependencies."
217290
+ })
217291
+ });
216996
217292
  const runtimeContext = yield* require_Schema$1.context();
216997
217293
  const runFork = require_Schema$1.runForkWith(runtimeContext);
216998
217294
  const runPromise = require_Schema$1.runPromiseWith(runtimeContext);
@@ -233332,12 +233628,12 @@ const collectOutput = require_Schema$1.fn("collectOutput")(function* (input, str
233332
233628
  let lineBuffer = "";
233333
233629
  let truncated = false;
233334
233630
  const emitCompleteLines = require_Schema$1.fn("emitCompleteLines")(function* (flush) {
233335
- let newlineIndex = lineBuffer.indexOf("\n");
233631
+ let newlineIndex = lineBuffer.search(/[\r\n]/);
233336
233632
  while (newlineIndex >= 0) {
233337
233633
  const line = lineBuffer.slice(0, newlineIndex).replace(/\r$/, "");
233338
233634
  lineBuffer = lineBuffer.slice(newlineIndex + 1);
233339
233635
  if (line.length > 0 && onLine) yield* onLine(line);
233340
- newlineIndex = lineBuffer.indexOf("\n");
233636
+ newlineIndex = lineBuffer.search(/[\r\n]/);
233341
233637
  }
233342
233638
  if (flush) {
233343
233639
  const trailing = lineBuffer.replace(/\r$/, "");
@@ -233486,6 +233782,7 @@ const makeGitCore = require_Schema$1.fn("makeGitCore")(function* (options) {
233486
233782
  operation,
233487
233783
  cwd,
233488
233784
  args,
233785
+ ...options.env ? { env: options.env } : {},
233489
233786
  ...options.stdin !== void 0 ? { stdin: options.stdin } : {},
233490
233787
  allowNonZeroExit: true,
233491
233788
  ...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {},
@@ -234209,12 +234506,19 @@ const makeGitCore = require_Schema$1.fn("makeGitCore")(function* (options) {
234209
234506
  };
234210
234507
  });
234211
234508
  const createWorktree = require_Schema$1.fn("createWorktree")(function* (input) {
234509
+ const report = (stage, status, detail) => input.onStage?.({
234510
+ stage,
234511
+ status,
234512
+ ...detail ? { detail } : {}
234513
+ }) ?? require_Schema$1.void_;
234514
+ yield* report("resolve", "running");
234212
234515
  const base = input.branch ?? (yield* resolveDefaultBaseBranch(input.cwd));
234213
234516
  const startPoint = yield* resolveWorktreeStartPoint({
234214
234517
  cwd: input.cwd,
234215
234518
  base,
234216
234519
  creatingNewBranch: input.newBranch !== void 0
234217
234520
  });
234521
+ yield* report("resolve", "done", startPoint);
234218
234522
  const targetBranch = input.newBranch ?? base;
234219
234523
  const sanitizedBranch = targetBranch.replace(/\//g, "-");
234220
234524
  const repoName = path.basename(input.cwd);
@@ -234226,7 +234530,10 @@ const makeGitCore = require_Schema$1.fn("makeGitCore")(function* (options) {
234226
234530
  limit: 200
234227
234531
  })).branches.find((branch) => branch.isRemote !== true && branch.name === targetBranch && branch.worktreePath !== null && node_path.default.resolve(branch.worktreePath) === canonicalWorktreePath);
234228
234532
  if (existingBranch?.worktreePath) {
234533
+ yield* report("checkout", "skipped", "Existing worktree");
234534
+ yield* report("dependencies", "running");
234229
234535
  yield* setupSharedWorktreeDependencies(input.cwd, existingBranch.worktreePath);
234536
+ yield* report("dependencies", "done");
234230
234537
  return { worktree: {
234231
234538
  path: worktreePath,
234232
234539
  branch: targetBranch
@@ -234245,11 +234552,19 @@ const makeGitCore = require_Schema$1.fn("makeGitCore")(function* (options) {
234245
234552
  worktreePath,
234246
234553
  startPoint
234247
234554
  ];
234555
+ yield* report("checkout", "running");
234248
234556
  yield* executeGit("GitCore.createWorktree", input.cwd, args, {
234249
234557
  fallbackErrorMessage: "git worktree add failed",
234558
+ env: {
234559
+ GIT_PROGRESS_DELAY: "0",
234560
+ LC_ALL: "C"
234561
+ },
234250
234562
  ...input.progress ? { progress: input.progress } : {}
234251
234563
  });
234564
+ yield* report("checkout", "done");
234565
+ yield* report("dependencies", "running");
234252
234566
  yield* setupSharedWorktreeDependencies(input.cwd, worktreePath);
234567
+ yield* report("dependencies", "done");
234253
234568
  return { worktree: {
234254
234569
  path: worktreePath,
234255
234570
  branch: targetBranch
@@ -297062,7 +297377,7 @@ function resolveBuildCommitFromEnv(env) {
297062
297377
  * environment descriptor down instead of reporting an honest "unknown".
297063
297378
  */
297064
297379
  function readBakedBuildCommit() {
297065
- return "c903d76ff920beb25458b85f671ffe18682f98a0";
297380
+ return "339f0da718657526651ad84cacb841446f1bb38b";
297066
297381
  }
297067
297382
  async function resolveServerBuildCommit(input) {
297068
297383
  if (isFullCommitSha(input.baked)) return input.baked;
@@ -298888,6 +299203,10 @@ const AuthSessionRepositoryLive = require_Schema$1.effect(AuthSessionRepository,
298888
299203
  const SIGNING_SECRET_NAME = "server-signing-key";
298889
299204
  const DEFAULT_SESSION_TTL = require_Schema$1.days(30);
298890
299205
  const DEFAULT_WEBSOCKET_TOKEN_TTL = require_Schema$1.minutes(5);
299206
+ const toSessionCredentialError = (message) => (cause) => new SessionCredentialError({
299207
+ message,
299208
+ cause
299209
+ });
298891
299210
  const SessionClaims = require_Schema$1.Struct({
298892
299211
  v: require_Schema$1.Literal(1),
298893
299212
  kind: require_Schema$1.Literal("session"),
@@ -298944,10 +299263,6 @@ const makeSessionCredentialService = require_Schema$1.gen(function* () {
298944
299263
  port: serverConfig.port,
298945
299264
  host: serverConfig.host
298946
299265
  });
298947
- const toSessionCredentialError = (message) => (cause) => new SessionCredentialError({
298948
- message,
298949
- cause
298950
- });
298951
299266
  const emitUpsert = (clientSession) => require_Path.publish(changesPubSub, {
298952
299267
  type: "clientUpserted",
298953
299268
  clientSession
@@ -299108,15 +299423,28 @@ const makeSessionCredentialService = require_Schema$1.gen(function* () {
299108
299423
  if (require_Schema$1.isSome(row)) {
299109
299424
  if (row.value.revokedAt !== null) return yield* new SessionCredentialError({ message: "Websocket session revoked." });
299110
299425
  if (row.value.expiresAt.epochMilliseconds <= now) return yield* new SessionCredentialError({ message: "Websocket session expired." });
299111
- } else if (!(statelessCookieSessions && claims.method === "browser-session-cookie")) return yield* new SessionCredentialError({ message: "Unknown websocket session." });
299426
+ } else {
299427
+ const cloudOwnerSession = serverConfig.forgeCloudShellMode === true && claims.method === "proxy-asserted" && forgeCloudOwnerSessionExpiresAt(claims.sid) !== null;
299428
+ if (cloudOwnerSession && isExpiredForgeCloudOwnerSession(claims.sid, now)) return yield* new SessionCredentialError({ message: "Websocket session expired." });
299429
+ if (statelessCookieSessions && (claims.method === "browser-session-cookie" || cloudOwnerSession)) return {
299430
+ sessionId: claims.sid,
299431
+ token,
299432
+ method: claims.method,
299433
+ client: createDefaultClientMetadata(),
299434
+ expiresAt: require_Schema$1.makeUnsafe(claims.exp),
299435
+ subject: claims.sub,
299436
+ role: claims.role
299437
+ };
299438
+ return yield* new SessionCredentialError({ message: "Unknown websocket session." });
299439
+ }
299112
299440
  return {
299113
299441
  sessionId: claims.sid,
299114
299442
  token,
299115
- method: require_Schema$1.isSome(row) ? row.value.method : claims.method,
299116
- client: require_Schema$1.isSome(row) ? toClientMetadata(row.value.client) : createDefaultClientMetadata(),
299117
- expiresAt: require_Schema$1.isSome(row) ? row.value.expiresAt : require_Schema$1.makeUnsafe(claims.exp),
299118
- subject: require_Schema$1.isSome(row) ? row.value.subject : claims.sub,
299119
- role: require_Schema$1.isSome(row) ? row.value.role : claims.role
299443
+ method: row.value.method,
299444
+ client: toClientMetadata(row.value.client),
299445
+ expiresAt: row.value.expiresAt,
299446
+ subject: row.value.subject,
299447
+ role: row.value.role
299120
299448
  };
299121
299449
  }).pipe(require_Schema$1.mapError((cause) => cause instanceof SessionCredentialError ? cause : new SessionCredentialError({
299122
299450
  message: "Failed to verify websocket token.",
@@ -299394,6 +299722,18 @@ function verifyForgeCloudOwnerCallbackAssertion(assertion, config) {
299394
299722
  //#endregion
299395
299723
  //#region src/auth/Layers/ServerAuth.ts
299396
299724
  const AUTHORIZATION_PREFIX = "Bearer ";
299725
+ function classifyWebSocketTokenFailure(cause) {
299726
+ switch (cause.message) {
299727
+ case "Malformed websocket token.": return "malformed";
299728
+ case "Invalid websocket token signature.": return "invalid_signature";
299729
+ case "Invalid websocket token payload.": return "invalid_payload";
299730
+ case "Websocket token expired.": return "expired_token";
299731
+ case "Websocket session revoked.": return "revoked_parent_session";
299732
+ case "Websocket session expired.": return "expired_parent_session";
299733
+ case "Unknown websocket session.": return "unknown_parent_session";
299734
+ default: return "verification_failed";
299735
+ }
299736
+ }
299397
299737
  function toBootstrapExchangeAuthError(cause) {
299398
299738
  if (cause.status === 500) return new AuthError({
299399
299739
  message: "Failed to validate bootstrap credential.",
@@ -299696,7 +300036,6 @@ const makeServerAuth = require_Schema$1.gen(function* () {
299696
300036
  expiresAt: require_Schema$1.toUtc(issued.expiresAt)
299697
300037
  })));
299698
300038
  const authenticateWebSocketUpgrade = (request) => require_Schema$1.gen(function* () {
299699
- if (serverConfig.forgeCloudShellMode === true) return yield* authenticateRequest(request);
299700
300039
  if (serverConfig.forgeCmmdRuntimeMode) {
299701
300040
  if (serverConfig.forgeCmmdAuthRuntime) {
299702
300041
  const authConfig = readCmmdAuthRuntimeConfig(serverConfig);
@@ -299753,7 +300092,7 @@ const makeServerAuth = require_Schema$1.gen(function* () {
299753
300092
  const requestUrl = require_HttpServer.toURL(request);
299754
300093
  if (require_Schema$1.isSome(requestUrl)) {
299755
300094
  const websocketToken = readWebSocketUpgradeToken(requestUrl.value.searchParams);
299756
- if (websocketToken) return yield* sessions.verifyWebSocketToken(websocketToken).pipe(require_Schema$1.map((session) => ({
300095
+ if (websocketToken) return yield* sessions.verifyWebSocketToken(websocketToken).pipe(require_Schema$1.tapError((cause) => require_Schema$1.logWarning("Rejected websocket token.").pipe(require_Schema$1.annotateLogs({ category: classifyWebSocketTokenFailure(cause) }))), require_Schema$1.map((session) => ({
299757
300096
  sessionId: session.sessionId,
299758
300097
  subject: session.subject,
299759
300098
  method: session.method,
@@ -305842,7 +306181,7 @@ const orchestrationDispatchRouteLayer = add$1("POST", "/api/orchestration/dispat
305842
306181
  }).pipe(require_Schema$1.mapError((cause) => new OrchestrationDispatchCommandError({
305843
306182
  message: "Failed to dispatch orchestration command.",
305844
306183
  cause
305845
- }))) : orchestrationEngine.dispatch(normalizedCommand).pipe(require_Schema$1.mapError((cause) => new OrchestrationDispatchCommandError({
306184
+ }))) : (normalizedCommand.type === "thread.turn.interrupt" ? interruptBootstrapTurnStart(orchestrationEngine, normalizedCommand) : orchestrationEngine.dispatch(normalizedCommand)).pipe(require_Schema$1.mapError((cause) => new OrchestrationDispatchCommandError({
305846
306185
  message: "Failed to dispatch orchestration command.",
305847
306186
  cause
305848
306187
  })));