@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.mjs CHANGED
@@ -22,7 +22,7 @@ import { createCipheriv, createDecipheriv, createHash, createHmac, createPublicK
22
22
  import * as FS$1 from "node:fs";
23
23
  import fs, { accessSync, chmodSync, constants, createReadStream, existsSync, mkdirSync, mkdtempSync, promises, readFile, readFileSync, readdir, readdirSync, realpathSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
24
24
  import * as NodeOS from "node:os";
25
- import $U, { homedir, networkInterfaces, tmpdir } from "node:os";
25
+ import os, { homedir, networkInterfaces, tmpdir } from "node:os";
26
26
  import * as Path$1 from "node:path";
27
27
  import path, { basename, delimiter, dirname, extname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
28
28
  import { pathToFileURL } from "node:url";
@@ -26804,6 +26804,23 @@ function encodeCmmdRuntimeThreadLifecycleMetadata(lifecycle) {
26804
26804
  } };
26805
26805
  }
26806
26806
  //#endregion
26807
+ //#region ../../packages/contracts/src/cmmdRuntimeThreadGoal.ts
26808
+ function encodeCmmdRuntimeThreadGoalMetadata(goal) {
26809
+ return { forgeGoal: {
26810
+ schemaVersion: 1,
26811
+ goal: goal.goal
26812
+ } };
26813
+ }
26814
+ function decodeCmmdRuntimeThreadGoalMetadata(metadata) {
26815
+ const value = metadata?.forgeGoal;
26816
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
26817
+ const record = value;
26818
+ const goal = record.goal;
26819
+ if (record.schemaVersion !== 1 || goal !== null && typeof goal !== "string") return null;
26820
+ if (typeof goal === "string" && goal.trim().length === 0) return null;
26821
+ return { goal };
26822
+ }
26823
+ //#endregion
26807
26824
  //#region ../../packages/contracts/src/cmmdRuntimeThreadWorkspace.ts
26808
26825
  function encodeCmmdRuntimeThreadWorkspaceMetadata(workspace) {
26809
26826
  return { forgeWorkspace: {
@@ -50597,7 +50614,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
50597
50614
  const min = forceColor || 0;
50598
50615
  if (env.TERM === "dumb") return min;
50599
50616
  if (process$1.platform === "win32") {
50600
- const osRelease = $U.release().split(".");
50617
+ const osRelease = os.release().split(".");
50601
50618
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
50602
50619
  return 1;
50603
50620
  }
@@ -53040,7 +53057,7 @@ var require_ProcessDetector = /* @__PURE__ */ __commonJSMin(((exports) => {
53040
53057
  exports.processDetector = void 0;
53041
53058
  const api_1 = (init_esm$1(), __toCommonJS(esm_exports$1));
53042
53059
  const semconv_1 = require_semconv$1();
53043
- const os$3 = __require("os");
53060
+ const os$4 = __require("os");
53044
53061
  /**
53045
53062
  * ProcessDetector will be used to detect the resources related current process running
53046
53063
  * and being instrumented from the NodeJS Process module.
@@ -53062,7 +53079,7 @@ var require_ProcessDetector = /* @__PURE__ */ __commonJSMin(((exports) => {
53062
53079
  };
53063
53080
  if (process.argv.length > 1) attributes[semconv_1.ATTR_PROCESS_COMMAND] = process.argv[1];
53064
53081
  try {
53065
- const userInfo = os$3.userInfo();
53082
+ const userInfo = os$4.userInfo();
53066
53083
  attributes[semconv_1.ATTR_PROCESS_OWNER] = userInfo.username;
53067
53084
  } catch (e) {
53068
53085
  api_1.diag.debug(`error obtaining process owner: ${e}`);
@@ -65985,7 +66002,7 @@ function normalizeNumberish(value) {
65985
66002
  }
65986
66003
  //#endregion
65987
66004
  //#region package.json
65988
- var version$1 = "0.13.7";
66005
+ var version$1 = "0.13.9";
65989
66006
  //#endregion
65990
66007
  //#region src/sentry.ts
65991
66008
  const SERVER_APP_NAME = "forge-server";
@@ -75198,7 +75215,7 @@ var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) =>
75198
75215
  var fs$6 = __require("fs");
75199
75216
  var path$5 = __require("path");
75200
75217
  var url$1 = __require("url");
75201
- var os$2 = __require("os");
75218
+ var os$3 = __require("os");
75202
75219
  var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
75203
75220
  var vars = process.config && process.config.variables || {};
75204
75221
  var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
@@ -75206,8 +75223,8 @@ var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) =>
75206
75223
  var abi = versions.modules;
75207
75224
  if (versions.deno || process.isBun) abi = "unsupported";
75208
75225
  var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node";
75209
- var arch = process.env.npm_config_arch || os$2.arch();
75210
- var platform = process.env.npm_config_platform || os$2.platform();
75226
+ var arch = process.env.npm_config_arch || os$3.arch();
75227
+ var platform = process.env.npm_config_platform || os$3.platform();
75211
75228
  var libc = process.env.LIBC || (isMusl(platform) ? "musl" : "glibc");
75212
75229
  var armv = process.env.ARM_VERSION || (arch === "arm64" ? "8" : vars.arm_version) || "";
75213
75230
  var uv = (versions.uv || "").split(".")[0];
@@ -87701,14 +87718,18 @@ function resolveRuntimeGitHubGrantAuthFromEnv(headers) {
87701
87718
  }
87702
87719
  function buildCmmdRuntimeGrantFetchRequest(auth, repoFullName) {
87703
87720
  return {
87704
- url: new URL(`/api/forge/runtimes/${encodeURIComponent(auth.runtimeId)}/github/installation-token`, resolveCommandAppUrl()).toString(),
87721
+ url: new URL(`/api/forge/runtimes/${encodeURIComponent(auth.runtimeId)}/scm/credential`, resolveCommandAppUrl()).toString(),
87705
87722
  init: {
87706
87723
  method: "POST",
87707
87724
  headers: {
87708
87725
  Authorization: `Bearer ${auth.token}`,
87709
87726
  "Content-Type": "application/json"
87710
87727
  },
87711
- body: JSON.stringify({ repo_full_name: repoFullName })
87728
+ body: JSON.stringify({
87729
+ provider: "github",
87730
+ host: "github.com",
87731
+ repository_path: repoFullName
87732
+ })
87712
87733
  }
87713
87734
  };
87714
87735
  }
@@ -88170,10 +88191,19 @@ function fetchInstallationTokenForAuth(auth, repoFullName) {
88170
88191
  ok: false,
88171
88192
  ...lastError
88172
88193
  };
88173
- if (tokenResp.ok) return {
88174
- ok: true,
88175
- token: (yield* promise(() => tokenResp.json())).token
88176
- };
88194
+ if (tokenResp.ok) {
88195
+ const tokenData = yield* promise(() => tokenResp.json());
88196
+ const token = auth.kind === "cmmd-runtime-ticket" ? tokenData.credential : tokenData.token;
88197
+ if (typeof token === "string" && token.trim().length > 0) return {
88198
+ ok: true,
88199
+ token: token.trim()
88200
+ };
88201
+ return {
88202
+ ok: false,
88203
+ status: 502,
88204
+ error: "CMMD returned an invalid source-control credential response."
88205
+ };
88206
+ }
88177
88207
  const err = yield* promise(() => tokenResp.json().catch(() => ({})));
88178
88208
  lastError = {
88179
88209
  status: tokenResp.status,
@@ -89095,23 +89125,38 @@ var GitHubBroker = class {
89095
89125
  async cloneRepository(auth, input) {
89096
89126
  const cloneInput = validateCloneInput(input);
89097
89127
  if ("ok" in cloneInput) return cloneInput;
89098
- const { branch } = cloneInput;
89128
+ let { branch } = cloneInput;
89099
89129
  const gitToken = await this.resolveInstallationToken(auth, input.repoFullName);
89100
89130
  if (typeof gitToken !== "string") return gitToken;
89101
- const initFailure = await this.runCloneGitStep([
89131
+ try {
89132
+ await mkdir(input.destination);
89133
+ } catch (error) {
89134
+ if (isNodeErrorWithCode(error, "EEXIST")) return cloneDestinationExistsResult();
89135
+ return {
89136
+ ok: false,
89137
+ code: "GITHUB_CLONE_DESTINATION_CREATE_FAILED",
89138
+ error: "Could not create the clone destination."
89139
+ };
89140
+ }
89141
+ const initFailure = await this.runCloneGitStep(branch === null ? ["init", input.destination] : [
89102
89142
  "init",
89103
89143
  "-b",
89104
89144
  branch,
89105
89145
  input.destination
89106
89146
  ], "GITHUB_CLONE_INIT_FAILED", "Could not initialize the clone destination.");
89107
- if (initFailure) return initFailure;
89147
+ if (initFailure) return removeFailedCloneDestination(input.destination, initFailure);
89108
89148
  const configured = await this.configureProjectGitCredential({
89109
89149
  cwd: input.destination,
89110
89150
  repoFullName: input.repoFullName,
89111
89151
  token: gitToken,
89112
89152
  remoteMode: "add"
89113
89153
  });
89114
- if (!configured.ok) return configured;
89154
+ if (!configured.ok) return removeFailedCloneDestination(input.destination, configured);
89155
+ if (branch === null) {
89156
+ const defaultBranch = await this.resolveRemoteDefaultBranch(input.destination);
89157
+ if (typeof defaultBranch !== "string") return removeFailedCloneDestination(input.destination, defaultBranch);
89158
+ branch = defaultBranch;
89159
+ }
89115
89160
  const fetchFailure = await this.runCloneGitStep([
89116
89161
  "-C",
89117
89162
  input.destination,
@@ -89121,7 +89166,7 @@ var GitHubBroker = class {
89121
89166
  "origin",
89122
89167
  branch
89123
89168
  ], "GITHUB_CLONE_FETCH_FAILED", "Could not fetch the requested repository branch.", { timeoutMs: 12e4 });
89124
- if (fetchFailure) return fetchFailure;
89169
+ if (fetchFailure) return removeFailedCloneDestination(input.destination, fetchFailure);
89125
89170
  const checkoutFailure = await this.runCloneGitStep([
89126
89171
  "-C",
89127
89172
  input.destination,
@@ -89130,7 +89175,7 @@ var GitHubBroker = class {
89130
89175
  branch,
89131
89176
  "FETCH_HEAD"
89132
89177
  ], "GITHUB_CLONE_CHECKOUT_FAILED", "Could not check out the requested repository branch.");
89133
- if (checkoutFailure) return checkoutFailure;
89178
+ if (checkoutFailure) return removeFailedCloneDestination(input.destination, checkoutFailure);
89134
89179
  return {
89135
89180
  ok: true,
89136
89181
  data: {
@@ -89740,9 +89785,9 @@ var GitHubBroker = class {
89740
89785
  };
89741
89786
  }
89742
89787
  async resolveInstallationToken(auth, repoFullName) {
89743
- const runtimeGrant = this.resolveRuntimeGrant();
89788
+ const runtimeGrant = this.resolveRuntimeGrant("scm");
89744
89789
  if (runtimeGrant) {
89745
- const token = await this.fetchRuntimeInstallationToken(runtimeGrant, repoFullName);
89790
+ const token = await this.fetchRuntimeScmCredential(runtimeGrant, repoFullName);
89746
89791
  if (!token.ok) return token;
89747
89792
  return token.token ?? invalidInstallationTokenResult();
89748
89793
  }
@@ -90125,7 +90170,7 @@ var GitHubBroker = class {
90125
90170
  repoFullName
90126
90171
  };
90127
90172
  }
90128
- resolveRuntimeGrant() {
90173
+ resolveRuntimeGrant(requiredScope = "github") {
90129
90174
  if (this.runtimeRole !== "user-vm") return null;
90130
90175
  const runtimeId = process.env.FORGE_CMMD_RUNTIME_ID?.trim();
90131
90176
  if (!runtimeId) return null;
@@ -90135,7 +90180,7 @@ var GitHubBroker = class {
90135
90180
  runtimeId,
90136
90181
  machineId: identity.machineId,
90137
90182
  credentialEpoch: identity.credentialEpoch,
90138
- requiredScope: "github"
90183
+ requiredScope
90139
90184
  });
90140
90185
  return authority ? {
90141
90186
  runtimeId,
@@ -90149,8 +90194,8 @@ var GitHubBroker = class {
90149
90194
  token: legacyToken
90150
90195
  } : null;
90151
90196
  }
90152
- runtimeGrantAuthContext() {
90153
- const grant = this.resolveRuntimeGrant();
90197
+ runtimeGrantAuthContext(requiredScope = "github") {
90198
+ const grant = this.resolveRuntimeGrant(requiredScope);
90154
90199
  if (grant === null) return null;
90155
90200
  return {
90156
90201
  sessionId: grant.sessionId ?? AuthSessionId.make(`cmmd-runtime:${grant.runtimeId}`),
@@ -90202,13 +90247,33 @@ var GitHubBroker = class {
90202
90247
  };
90203
90248
  }
90204
90249
  async fetchRuntimeInstallationToken(grant, repoFullName) {
90205
- const response = await this.fetchImpl(makeUrl(this.commandAppUrl, `/api/forge/runtimes/${encodeURIComponent(grant.runtimeId)}/github/installation-token`), {
90250
+ return this.fetchRuntimeCredential(grant, {
90251
+ url: makeUrl(this.commandAppUrl, `/api/forge/runtimes/${encodeURIComponent(grant.runtimeId)}/github/installation-token`),
90252
+ requestBody: { repo_full_name: repoFullName },
90253
+ responseField: "token",
90254
+ label: "GitHub installation token"
90255
+ });
90256
+ }
90257
+ async fetchRuntimeScmCredential(grant, repoFullName) {
90258
+ return this.fetchRuntimeCredential(grant, {
90259
+ url: makeUrl(this.commandAppUrl, `/api/forge/runtimes/${encodeURIComponent(grant.runtimeId)}/scm/credential`),
90260
+ requestBody: {
90261
+ provider: "github",
90262
+ host: "github.com",
90263
+ repository_path: repoFullName
90264
+ },
90265
+ responseField: "credential",
90266
+ label: "GitHub source-control credential"
90267
+ });
90268
+ }
90269
+ async fetchRuntimeCredential(grant, input) {
90270
+ const response = await this.fetchImpl(input.url, {
90206
90271
  method: "POST",
90207
90272
  headers: {
90208
90273
  Authorization: `Bearer ${grant.token}`,
90209
90274
  "Content-Type": "application/json"
90210
90275
  },
90211
- body: JSON.stringify({ repo_full_name: repoFullName }),
90276
+ body: JSON.stringify(input.requestBody),
90212
90277
  signal: AbortSignal.timeout(GITHUB_BROKER_REQUEST_TIMEOUT_MS)
90213
90278
  });
90214
90279
  const body = await parseResponseBody(response);
@@ -90217,10 +90282,10 @@ var GitHubBroker = class {
90217
90282
  status: response.status,
90218
90283
  code: response.status === 401 ? "GITHUB_AUTH_REQUIRED" : "GITHUB_BROKER_REQUEST_FAILED",
90219
90284
  ...response.status === 401 ? { userActionRequired: "connect_github" } : {},
90220
- error: errorFromBody(body, `GitHub installation token request failed with status ${response.status}.`),
90285
+ error: errorFromBody(body, `${input.label} request failed with status ${response.status}.`),
90221
90286
  data: body
90222
90287
  };
90223
- const token = typeof body === "object" && body !== null ? body.token : null;
90288
+ const token = typeof body === "object" && body !== null ? body[input.responseField] : null;
90224
90289
  if (typeof token !== "string" || token.trim().length === 0) return invalidInstallationTokenResult();
90225
90290
  return {
90226
90291
  ok: true,
@@ -90239,6 +90304,25 @@ var GitHubBroker = class {
90239
90304
  const branch = result.result.stdout.trim();
90240
90305
  return branch.length > 0 ? branch : null;
90241
90306
  }
90307
+ async resolveRemoteDefaultBranch(cwd) {
90308
+ const result = await this.runGit([
90309
+ "-C",
90310
+ cwd,
90311
+ "ls-remote",
90312
+ "--symref",
90313
+ "origin",
90314
+ "HEAD"
90315
+ ], { allowNonZeroExit: true });
90316
+ if (!isGitRunResult(result)) return result;
90317
+ if (result.result.code !== 0) return gitCommandFailure("GITHUB_DEFAULT_BRANCH_LOOKUP_FAILED", result.result.stderr, "Could not determine the repository default branch.");
90318
+ const branch = /^ref:\s+refs\/heads\/([^\s]+)\s+HEAD$/m.exec(result.result.stdout)?.[1];
90319
+ if (branch === void 0) return {
90320
+ ok: false,
90321
+ code: "GITHUB_DEFAULT_BRANCH_RESPONSE_INVALID",
90322
+ error: "GitHub did not return a valid default branch for the repository."
90323
+ };
90324
+ return validateGitBranchName(branch) ?? branch;
90325
+ }
90242
90326
  };
90243
90327
  function isCmmdCloudRuntimeModeEnv() {
90244
90328
  return process.env.FORGE_CMMD_RUNTIME_MODE === "true" || process.env.FORGE_CMMD_RUNTIME_MODE === "1";
@@ -90323,20 +90407,40 @@ function validateCloneDestination(destination) {
90323
90407
  code: "GITHUB_CLONE_DESTINATION_INVALID",
90324
90408
  error: "An absolute clone destination is required."
90325
90409
  };
90326
- if (existsSync(destination)) return {
90410
+ if (existsSync(destination)) return cloneDestinationExistsResult();
90411
+ return null;
90412
+ }
90413
+ function cloneDestinationExistsResult() {
90414
+ return {
90327
90415
  ok: false,
90328
90416
  code: "GITHUB_CLONE_DESTINATION_EXISTS",
90329
90417
  error: "Clone destination already exists; choose a new empty path."
90330
90418
  };
90331
- return null;
90419
+ }
90420
+ function isNodeErrorWithCode(error, code) {
90421
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
90422
+ }
90423
+ async function removeFailedCloneDestination(destination, failure) {
90424
+ try {
90425
+ await rm(destination, {
90426
+ recursive: true,
90427
+ force: true
90428
+ });
90429
+ return failure;
90430
+ } catch {
90431
+ return {
90432
+ ...failure,
90433
+ error: `${failure.error ?? "Clone failed."} The incomplete clone destination could not be removed.`
90434
+ };
90435
+ }
90332
90436
  }
90333
90437
  function validateCloneInput(input) {
90334
90438
  const repoFullNameValidation = validateRepoFullName(input.repoFullName);
90335
90439
  if (repoFullNameValidation) return repoFullNameValidation;
90336
90440
  const destinationValidation = validateCloneDestination(input.destination);
90337
90441
  if (destinationValidation) return destinationValidation;
90338
- const branch = input.branch?.trim() || "main";
90339
- return validateGitBranchName(branch) ?? { branch };
90442
+ const branch = input.branch?.trim() || null;
90443
+ return branch === null ? { branch } : validateGitBranchName(branch) ?? { branch };
90340
90444
  }
90341
90445
  function validateGitBranchName(branch) {
90342
90446
  if (branch.length === 0 || branch.startsWith("-") || Array.from(branch).some((character) => {
@@ -93314,7 +93418,7 @@ const launchDetached = (launch) => gen(function* () {
93314
93418
  });
93315
93419
  const OpenLive = effect(Open, gen(function* () {
93316
93420
  const open = yield* tryPromise({
93317
- try: () => import("./open-D8mGyWmt.mjs"),
93421
+ try: () => import("./open-FIgTDosf.mjs"),
93318
93422
  catch: (cause) => new OpenError$1({
93319
93423
  message: "failed to load browser opener",
93320
93424
  cause
@@ -93501,6 +93605,17 @@ const admitNormalizedDispatchCommand = (command, admit) => uninterruptibleMask$1
93501
93605
  //#region src/orchestration/bootstrapCommandCoordinator.ts
93502
93606
  const MAX_COMPLETED_COMMANDS_PER_ENGINE = 256;
93503
93607
  const commandsByEngine = /* @__PURE__ */ new WeakMap();
93608
+ const sealBootstrapCommand = (engine, commandId) => {
93609
+ const entry = commandsByEngine.get(engine)?.get(commandId);
93610
+ if (entry) entry.cancellable = false;
93611
+ };
93612
+ const cancelBootstrapCommand = (engine, threadId) => promise(async () => {
93613
+ const entry = [...commandsByEngine.get(engine)?.values() ?? []].find((candidate) => candidate.threadId === threadId && !candidate.completed && candidate.cancellable);
93614
+ if (!entry) return false;
93615
+ entry.controller.abort();
93616
+ await entry.promise.catch(() => void 0);
93617
+ return true;
93618
+ });
93504
93619
  const toBootstrapError = (error) => is$1(OrchestrationDispatchCommandError)(error) ? error : new OrchestrationDispatchCommandError({
93505
93620
  message: error instanceof Error ? error.message : "Bootstrap command failed.",
93506
93621
  cause: error
@@ -93520,7 +93635,7 @@ const pruneCompletedCommands = (commands) => {
93520
93635
  * the registry to one server runtime, so reconnects share work while separate
93521
93636
  * runtimes remain isolated.
93522
93637
  */
93523
- const runBootstrapCommand = (engine, commandId, bootstrapEffect) => {
93638
+ const runBootstrapCommand = (engine, commandId, bootstrapEffect, threadId) => {
93524
93639
  let commands = commandsByEngine.get(engine);
93525
93640
  if (commands === void 0) {
93526
93641
  commands = /* @__PURE__ */ new Map();
@@ -93533,16 +93648,21 @@ const runBootstrapCommand = (engine, commandId, bootstrapEffect) => {
93533
93648
  });
93534
93649
  pruneCompletedCommands(commands);
93535
93650
  let entry;
93536
- const promise = runPromise(bootstrapEffect).then((result) => {
93651
+ const controller = new AbortController();
93652
+ const promise = Promise.resolve().then(() => runPromise(bootstrapEffect, { signal: controller.signal })).then((result) => {
93537
93653
  entry.completed = true;
93538
93654
  return result;
93539
93655
  }, (error) => {
93540
- commands.delete(commandId);
93656
+ entry.completed = true;
93657
+ if (!controller.signal.aborted) commands.delete(commandId);
93541
93658
  throw error;
93542
93659
  });
93543
93660
  entry = {
93544
93661
  promise,
93545
- completed: false
93662
+ completed: false,
93663
+ threadId,
93664
+ controller,
93665
+ cancellable: true
93546
93666
  };
93547
93667
  commands.set(commandId, entry);
93548
93668
  return tryPromise({
@@ -93552,6 +93672,10 @@ const runBootstrapCommand = (engine, commandId, bootstrapEffect) => {
93552
93672
  };
93553
93673
  //#endregion
93554
93674
  //#region src/orchestration/bootstrapDispatch.ts
93675
+ const interruptBootstrapTurnStart = (engine, command) => gen(function* () {
93676
+ if (yield* cancelBootstrapCommand(engine, command.threadId)) return { sequence: (yield* engine.getReadModel()).snapshotSequence };
93677
+ return yield* engine.dispatch(command);
93678
+ });
93555
93679
  const MAX_BOOTSTRAP_OUTPUT_LINE_LENGTH = 1e3;
93556
93680
  const toBootstrapDispatchCommandCauseError = (cause) => {
93557
93681
  const error = squash(cause);
@@ -93638,6 +93762,7 @@ const prepareBootstrapWorktree = (input) => gen(function* () {
93638
93762
  const requestedAt = (/* @__PURE__ */ new Date()).toISOString();
93639
93763
  const baseBranchLabel = bootstrapWorktree.baseBranch ?? "<default>";
93640
93764
  const requestedPayload = {
93765
+ turnRequestedAt: input.command.createdAt,
93641
93766
  projectCwd: bootstrapWorktree.projectCwd,
93642
93767
  baseBranch: bootstrapWorktree.baseBranch,
93643
93768
  branch: bootstrapWorktree.branch,
@@ -93658,6 +93783,16 @@ const prepareBootstrapWorktree = (input) => gen(function* () {
93658
93783
  branch: bootstrapWorktree.baseBranch,
93659
93784
  newBranch: bootstrapWorktree.branch,
93660
93785
  path: null,
93786
+ onStage: (update) => appendWorktreeActivity({
93787
+ orchestrationEngine: input.orchestrationEngine,
93788
+ threadId: input.command.threadId,
93789
+ commandId: CommandId.make(`server:worktree-stage:${input.command.commandId}:${crypto.randomUUID()}`),
93790
+ kind: "worktree.stage",
93791
+ summary: "Preparing worktree",
93792
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
93793
+ payload: update,
93794
+ tone: "info"
93795
+ }).pipe(asVoid, ignore),
93661
93796
  progress: {
93662
93797
  onStdoutLine: (line) => {
93663
93798
  const detail = truncateBootstrapOutputLine(line);
@@ -93697,6 +93832,7 @@ const prepareBootstrapWorktree = (input) => gen(function* () {
93697
93832
  }
93698
93833
  }
93699
93834
  }).pipe(catchCause((cause) => {
93835
+ if (hasInterruptsOnly(cause)) return failCause$1(cause);
93700
93836
  const error = squash(cause);
93701
93837
  const detail = error instanceof Error ? error.message : "Unknown worktree failure.";
93702
93838
  return appendWorktreeActivity({
@@ -93823,7 +93959,16 @@ const dispatchBootstrapTurnStart = (input, command) => gen(function* () {
93823
93959
  worktreePath
93824
93960
  }),
93825
93961
  onSuccess: (setupResult) => {
93826
- if (setupResult.status !== "started") return void_$1;
93962
+ if (setupResult.status !== "started") return appendSetupScriptActivity({
93963
+ orchestrationEngine,
93964
+ threadId: command.threadId,
93965
+ commandId: bootstrapCommandId(command, "setup-script-skipped"),
93966
+ kind: "setup-script.skipped",
93967
+ summary: "No setup script configured",
93968
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
93969
+ payload: {},
93970
+ tone: "info"
93971
+ }).pipe(asVoid, ignore);
93827
93972
  return recordSetupScriptStarted({
93828
93973
  requestedAt,
93829
93974
  worktreePath,
@@ -93853,13 +93998,33 @@ const dispatchBootstrapTurnStart = (input, command) => gen(function* () {
93853
93998
  targetProjectCwd = preparedWorktree.projectCwd;
93854
93999
  }
93855
94000
  yield* runSetupProgram();
94001
+ if (bootstrap?.prepareWorktree) yield* appendWorktreeActivity({
94002
+ orchestrationEngine,
94003
+ threadId: command.threadId,
94004
+ commandId: bootstrapCommandId(command, "launch-agent-starting"),
94005
+ kind: "launch.agent-starting",
94006
+ summary: "Starting agent",
94007
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
94008
+ payload: { setupRequested: bootstrap.runSetupScript === true },
94009
+ tone: "info"
94010
+ }).pipe(ignore);
94011
+ sealBootstrapCommand(orchestrationEngine, command.commandId);
93856
94012
  return yield* orchestrationEngine.dispatch(finalTurnStartCommand);
93857
94013
  });
93858
- return yield* runBootstrapCommand(orchestrationEngine, command.commandId, bootstrapProgram.pipe(catchCause((cause) => {
94014
+ return yield* runBootstrapCommand(orchestrationEngine, command.commandId, bootstrapProgram.pipe(onInterrupt(() => appendWorktreeActivity({
94015
+ orchestrationEngine,
94016
+ threadId: command.threadId,
94017
+ commandId: bootstrapCommandId(command, "launch-cancelled"),
94018
+ kind: "launch.cancelled",
94019
+ summary: "Launch cancelled",
94020
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
94021
+ payload: {},
94022
+ tone: "info"
94023
+ }).pipe(ignore)), catchCause((cause) => {
93859
94024
  const dispatchError = toBootstrapDispatchCommandCauseError(cause);
93860
94025
  if (hasInterruptsOnly(cause)) return fail(dispatchError);
93861
94026
  return cleanupCreatedThread().pipe(flatMap(() => fail(dispatchError)));
93862
- })));
94027
+ })), command.threadId);
93863
94028
  });
93864
94029
  //#endregion
93865
94030
  //#region src/orchestration/Services/OrchestrationEngine.ts
@@ -94710,7 +94875,7 @@ function hasValidRuntimeIdentity(value) {
94710
94875
  }
94711
94876
  function decodeRuntime$1(value) {
94712
94877
  if (!isRecord$19(value) || !hasValidRuntimeIdentity(value)) return null;
94713
- 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;
94878
+ 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;
94714
94879
  return value;
94715
94880
  }
94716
94881
  function decodeProject(value) {
@@ -94723,7 +94888,7 @@ function decodeProject(value) {
94723
94888
  };
94724
94889
  }
94725
94890
  function decodeThread$1(value) {
94726
- 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;
94891
+ 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;
94727
94892
  return value;
94728
94893
  }
94729
94894
  function decodeSummary(value) {
@@ -95078,18 +95243,27 @@ function runtimeThreadFinalGenerationId(runtimeId, streamKey, events) {
95078
95243
  function canonicalKindFields(event) {
95079
95244
  switch (event.kind) {
95080
95245
  case "user_message":
95081
- case "assistant_message": return { text: event.text };
95246
+ case "assistant_message": return canonicalMessageFields(event);
95082
95247
  case "activity_summary":
95083
95248
  case "error_summary": return { summary: event.summary };
95084
95249
  case "turn_status": return { status: event.status };
95085
- case "tool_call": return {
95086
- summary: event.summary,
95087
- status: event.status,
95088
- ...event.payload !== void 0 ? { payload: event.payload } : {}
95089
- };
95250
+ case "tool_call": return canonicalToolCallFields(event);
95090
95251
  case "turn_usage": return canonicalTurnUsageFields(event);
95091
95252
  }
95092
95253
  }
95254
+ function canonicalMessageFields(event) {
95255
+ return {
95256
+ text: event.text,
95257
+ ...event.payload === void 0 ? {} : { payload: event.payload }
95258
+ };
95259
+ }
95260
+ function canonicalToolCallFields(event) {
95261
+ return {
95262
+ summary: event.summary,
95263
+ status: event.status,
95264
+ ...event.payload === void 0 ? {} : { payload: event.payload }
95265
+ };
95266
+ }
95093
95267
  /**
95094
95268
  * The usage row's attribution as canonical fields, matching CMMD's
95095
95269
  * `forgeUsageRowAttributionFields`: present only when the publisher named them,
@@ -95231,8 +95405,21 @@ function eventsMatchAcknowledgement(events, acknowledgedSequence) {
95231
95405
  return acknowledgedSequence === expectedSequence - 1;
95232
95406
  }
95233
95407
  //#endregion
95408
+ //#region src/runtimeReplication/replicaMessagePayload.ts
95409
+ function decodeReplicaMessageAttachments(payload) {
95410
+ if (payload === null || typeof payload !== "object" || !("attachments" in payload)) return;
95411
+ const attachments = payload.attachments;
95412
+ if (!Array.isArray(attachments)) return void 0;
95413
+ const decoded = attachments.filter(is$1(ChatAttachment));
95414
+ return decoded.length > 0 ? decoded : void 0;
95415
+ }
95416
+ function messageAttachmentPayload(message) {
95417
+ return message.attachments && message.attachments.length > 0 ? { payload: { attachments: message.attachments } } : {};
95418
+ }
95419
+ //#endregion
95234
95420
  //#region src/runtimeReplication/replicaHydrationMapping.ts
95235
95421
  function replicaMessage(runtimeId, generationId, event) {
95422
+ const attachments = decodeReplicaMessageAttachments(event.payload);
95236
95423
  return {
95237
95424
  id: MessageId.make(encodeReplicaSourceMessageId({
95238
95425
  sequence: event.sequence,
@@ -95245,7 +95432,8 @@ function replicaMessage(runtimeId, generationId, event) {
95245
95432
  turnId: null,
95246
95433
  streaming: false,
95247
95434
  createdAt: event.occurredAt,
95248
- updatedAt: event.occurredAt
95435
+ updatedAt: event.occurredAt,
95436
+ ...attachments ? { attachments: [...attachments] } : {}
95249
95437
  };
95250
95438
  }
95251
95439
  function replicaTurnUsage(event) {
@@ -95278,11 +95466,15 @@ function replicaEventBase(event) {
95278
95466
  function replicaTextEvent(event, base) {
95279
95467
  switch (event.kind) {
95280
95468
  case "user_message":
95281
- case "assistant_message": return {
95282
- ...base,
95283
- kind: event.kind,
95284
- text: event.text
95285
- };
95469
+ case "assistant_message": {
95470
+ const attachments = decodeReplicaMessageAttachments(event.payload);
95471
+ return {
95472
+ ...base,
95473
+ kind: event.kind,
95474
+ text: event.text,
95475
+ ...attachments ? { payload: { attachments } } : {}
95476
+ };
95477
+ }
95286
95478
  case "activity_summary":
95287
95479
  case "error_summary": return {
95288
95480
  ...base,
@@ -95392,7 +95584,7 @@ function replicaToOrchestrationThread(input) {
95392
95584
  status: archived ? "archived" : "idle",
95393
95585
  workerRole: null,
95394
95586
  pendingAutoCreatePrompt: null,
95395
- goal: null,
95587
+ goal: decodeCmmdRuntimeThreadGoalMetadata(detail.thread.metadata)?.goal ?? null,
95396
95588
  titleRegeneration: null
95397
95589
  }
95398
95590
  };
@@ -96928,7 +97120,8 @@ function serializeReplicaMessage(message) {
96928
97120
  occurredAt: message.createdAt,
96929
97121
  ...source.turnId === void 0 ? {} : { turnId: source.turnId },
96930
97122
  kind: message.role === "user" ? "user_message" : "assistant_message",
96931
- text: message.text
97123
+ text: message.text,
97124
+ ...messageAttachmentPayload(message)
96932
97125
  }
96933
97126
  };
96934
97127
  }
@@ -96988,7 +97181,8 @@ function serializeRuntimeInventory(snapshot, providerInventory) {
96988
97181
  settledAt: thread.settledAt ?? null,
96989
97182
  settledOverride: thread.settledOverride ?? null
96990
97183
  }),
96991
- ...encodeCmmdRuntimeThreadWorkspaceMetadata({ worktreePath: thread.worktreePath })
97184
+ ...encodeCmmdRuntimeThreadWorkspaceMetadata({ worktreePath: thread.worktreePath }),
97185
+ ...encodeCmmdRuntimeThreadGoalMetadata({ goal: thread.goal })
96992
97186
  }
96993
97187
  })),
96994
97188
  metadata: {
@@ -97023,7 +97217,8 @@ function orderedLocalMessageEvent(message, content) {
97023
97217
  occurredAt: canonicalRuntimeEventTimestamp(message.createdAt),
97024
97218
  ...eventTurn(message.turnId),
97025
97219
  kind: message.role === "user" ? "user_message" : "assistant_message",
97026
- text: content
97220
+ text: content,
97221
+ ...messageAttachmentPayload(message)
97027
97222
  }
97028
97223
  };
97029
97224
  }
@@ -100508,6 +100703,7 @@ function emptyConfig(source, path) {
100508
100703
  terminals: [],
100509
100704
  systemPackages: [],
100510
100705
  secrets: [],
100706
+ repositoryDependencies: [],
100511
100707
  issues: []
100512
100708
  };
100513
100709
  }
@@ -100593,6 +100789,7 @@ function readConfigFile(source, path) {
100593
100789
  terminals: terminalsFromValue(parsed.terminals),
100594
100790
  systemPackages: stringArray(parsed.systemPackages ?? parsed.aptPackages ?? parsed.packages),
100595
100791
  secrets: stringArray(parsed.secrets ?? parsed.envSecrets),
100792
+ repositoryDependencies: stringArray(parsed.repositoryDependencies),
100596
100793
  issues: []
100597
100794
  };
100598
100795
  }
@@ -101005,6 +101202,7 @@ const EMPTY_WORKSPACE_ENVIRONMENT_CONFIG = {
101005
101202
  terminals: [],
101006
101203
  systemPackages: [],
101007
101204
  secrets: [],
101205
+ repositoryDependencies: [],
101008
101206
  issues: []
101009
101207
  };
101010
101208
  function buildCwdCheck(cwdExists) {
@@ -105807,7 +106005,7 @@ const makeWsRpcLayer = (currentSessionId, currentUserId) => WsRpcGroup.toLayer(g
105807
106005
  git,
105808
106006
  gitStatusBroadcaster,
105809
106007
  projectSetupScriptRunner
105810
- }, normalizedCommand) : orchestrationEngine.dispatch(normalizedCommand).pipe(mapError((cause) => toDispatchCommandError(cause, "Failed to dispatch orchestration command")));
106008
+ }, normalizedCommand) : (normalizedCommand.type === "thread.turn.interrupt" ? interruptBootstrapTurnStart(orchestrationEngine, normalizedCommand) : orchestrationEngine.dispatch(normalizedCommand)).pipe(mapError((cause) => toDispatchCommandError(cause, "Failed to dispatch orchestration command")));
105811
106009
  return startup.enqueueCommand(dispatchEffect).pipe(mapError((cause) => toDispatchCommandError(cause, "Failed to dispatch orchestration command")));
105812
106010
  };
105813
106011
  const loadServerConfig = gen(function* () {
@@ -151156,6 +151354,86 @@ async function attestCodexLocalAccountIdentity(input) {
151156
151354
  return identity;
151157
151355
  }
151158
151356
  //#endregion
151357
+ //#region src/workspace/workspaceRepositoryDependencies.ts
151358
+ function repositoryFullName(value) {
151359
+ return value.trim().match(/^(?:https?:\/\/)?github\.com\/([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+?)(?:\.git)?\/?$/i)?.[1] ?? null;
151360
+ }
151361
+ function dependencyDestination(cloudProjectsRoot, repoFullName) {
151362
+ const root = resolve(cloudProjectsRoot);
151363
+ const destination = resolve(join(root, basename(repoFullName)));
151364
+ const pathFromRoot = relative(root, destination);
151365
+ if (pathFromRoot.startsWith("..") || pathFromRoot === "") throw new Error(`Repository dependency ${repoFullName} has an unsafe destination.`);
151366
+ return destination;
151367
+ }
151368
+ async function readOriginFromGit(destination) {
151369
+ const result = await runProcess("git", [
151370
+ "-C",
151371
+ destination,
151372
+ "remote",
151373
+ "get-url",
151374
+ "origin"
151375
+ ], {
151376
+ allowNonZeroExit: true,
151377
+ timeoutMs: 1e4
151378
+ });
151379
+ return result.code === 0 ? result.stdout.trim() : null;
151380
+ }
151381
+ function resolveRepositoryDependencies(declarations, cloudProjectsRoot) {
151382
+ const destinations = /* @__PURE__ */ new Set();
151383
+ return declarations.map((declaration) => {
151384
+ const repoFullName = repositoryFullName(declaration);
151385
+ if (repoFullName === null) throw new Error(`Unsupported repository dependency: ${declaration}`);
151386
+ const destination = dependencyDestination(cloudProjectsRoot, repoFullName);
151387
+ if (destinations.has(destination)) throw new Error(`Repository dependencies collide at ${destination}.`);
151388
+ destinations.add(destination);
151389
+ return {
151390
+ repoFullName,
151391
+ destination
151392
+ };
151393
+ });
151394
+ }
151395
+ async function prepareRepositoryDependency(input) {
151396
+ const { repoFullName, destination } = input.dependency;
151397
+ if (existsSync(destination)) {
151398
+ const origin = await input.readOrigin(destination);
151399
+ const existingRepo = origin === null ? null : parseRepoFullNameFromRemoteUrl(origin);
151400
+ if (existingRepo?.toLowerCase() !== repoFullName.toLowerCase()) throw new Error(`Repository dependency destination ${destination} contains ${existingRepo ?? "no GitHub repository"} instead of ${repoFullName}.`);
151401
+ return {
151402
+ repoFullName,
151403
+ destination,
151404
+ outcome: "existing"
151405
+ };
151406
+ }
151407
+ const result = await input.broker.cloneRepository(input.auth, {
151408
+ repoFullName,
151409
+ destination
151410
+ });
151411
+ if (!result.ok) throw new Error(`Could not prepare repository dependency ${repoFullName}: ${result.error ?? result.code ?? "clone failed"}`);
151412
+ return {
151413
+ repoFullName,
151414
+ destination,
151415
+ outcome: "cloned"
151416
+ };
151417
+ }
151418
+ async function prepareWorkspaceRepositoryDependencies(input) {
151419
+ if (!input.runtimeMode) return [];
151420
+ const dependencies = resolveWorkspaceEnvironmentConfig(input.cwd).repositoryDependencies;
151421
+ if (dependencies.length === 0) return [];
151422
+ const broker = input.broker ?? new GitHubBroker();
151423
+ const auth = broker.runtimeGrantAuthContext("scm");
151424
+ if (auth === null) throw new Error("Repository dependencies require an exact scoped runtime SCM grant.");
151425
+ const readOrigin = input.readOrigin ?? readOriginFromGit;
151426
+ const resolved = resolveRepositoryDependencies(dependencies, input.cloudProjectsRoot);
151427
+ const prepared = [];
151428
+ for (const dependency of resolved) prepared.push(await prepareRepositoryDependency({
151429
+ dependency,
151430
+ broker,
151431
+ auth,
151432
+ readOrigin
151433
+ }));
151434
+ return prepared;
151435
+ }
151436
+ //#endregion
151159
151437
  //#region src/codexAppServerManager.ts
151160
151438
  const CODEX_LOGIN_STATUS_TIMEOUT_MS = 5e3;
151161
151439
  const CODEX_SKILLS_LIST_TIMEOUT_MS = 4e3;
@@ -151490,6 +151768,11 @@ var CodexAppServerManager = class extends EventEmitter$1 {
151490
151768
  let context;
151491
151769
  try {
151492
151770
  const resolvedCwd = input.cwd ?? process.cwd();
151771
+ await prepareWorkspaceRepositoryDependencies({
151772
+ cwd: resolvedCwd,
151773
+ cloudProjectsRoot: process.env.FORGE_CLOUD_PROJECTS_ROOT?.trim() || "/projects",
151774
+ runtimeMode: process.env.FORGE_CMMD_RUNTIME_MODE === "true"
151775
+ });
151493
151776
  let workspacePreflightReport = runWorkspaceEnvironmentPreflight({
151494
151777
  cwd: resolvedCwd,
151495
151778
  env: process.env
@@ -190264,7 +190547,7 @@ var Vce = {
190264
190547
  function Ve() {
190265
190548
  return Vce;
190266
190549
  }
190267
- var Us = $U.homedir(), lk = $U.tmpdir(), { env: Vc } = process$1, Yce = (e) => {
190550
+ var Us = os.homedir(), lk = os.tmpdir(), { env: Vc } = process$1, Yce = (e) => {
190268
190551
  let t = path.join(Us, "Library");
190269
190552
  return {
190270
190553
  data: path.join(t, "Application Support", e),
@@ -200464,12 +200747,12 @@ function qZ(e, t) {
200464
200747
  }
200465
200748
  return n;
200466
200749
  }
200467
- var os$1 = "https://code.claude.com/docs/en", kKe = [
200750
+ var os$2 = "https://code.claude.com/docs/en", kKe = [
200468
200751
  {
200469
200752
  matches: (e) => e.path === "permissions.defaultMode" && e.code === "invalid_value",
200470
200753
  tip: {
200471
200754
  suggestion: "Valid modes: \"acceptEdits\" (ask before file changes), \"plan\" (analysis only), \"bypassPermissions\" (auto-accept all), or \"default\" (standard behavior)",
200472
- docLink: `${os$1}/iam#permission-modes`
200755
+ docLink: `${os$2}/iam#permission-modes`
200473
200756
  }
200474
200757
  },
200475
200758
  {
@@ -200484,7 +200767,7 @@ var os$1 = "https://code.claude.com/docs/en", kKe = [
200484
200767
  matches: (e) => e.path.startsWith("env.") && e.code === "invalid_type",
200485
200768
  tip: {
200486
200769
  suggestion: "Environment variables must be strings. Wrap numbers and booleans in quotes. Example: \"DEBUG\": \"true\", \"PORT\": \"3000\"",
200487
- docLink: `${os$1}/settings#environment-variables`
200770
+ docLink: `${os$2}/settings#environment-variables`
200488
200771
  }
200489
200772
  },
200490
200773
  {
@@ -200495,14 +200778,14 @@ var os$1 = "https://code.claude.com/docs/en", kKe = [
200495
200778
  matches: (e) => e.path.startsWith("hooks.") && e.code === "invalid_key",
200496
200779
  tip: {
200497
200780
  suggestion: "Not a recognized hook event. Common events: PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, SessionEnd, Stop. Check spelling and capitalization.",
200498
- docLink: `${os$1}/hooks`
200781
+ docLink: `${os$2}/hooks`
200499
200782
  }
200500
200783
  },
200501
200784
  {
200502
200785
  matches: (e) => /\.hooks\.\d+\.command$/.test(e.path) && e.code === "invalid_type" && e.received === "undefined",
200503
200786
  tip: {
200504
200787
  suggestion: "Command hooks require `command`. For exec form (no shell), set `command` to the executable and `args` to its arguments: {\"type\": \"command\", \"command\": \"echo\", \"args\": [\"hi\"]}. For shell form, set `command` to the full shell string: {\"type\": \"command\", \"command\": \"echo hi\"}.",
200505
- docLink: `${os$1}/hooks#exec-form-and-shell-form`
200788
+ docLink: `${os$2}/hooks#exec-form-and-shell-form`
200506
200789
  }
200507
200790
  },
200508
200791
  {
@@ -200517,7 +200800,7 @@ var os$1 = "https://code.claude.com/docs/en", kKe = [
200517
200800
  matches: (e) => e.code === "unrecognized_keys",
200518
200801
  tip: {
200519
200802
  suggestion: "Check for typos or refer to the documentation for valid fields",
200520
- docLink: `${os$1}/settings`
200803
+ docLink: `${os$2}/settings`
200521
200804
  }
200522
200805
  },
200523
200806
  {
@@ -200532,13 +200815,13 @@ var os$1 = "https://code.claude.com/docs/en", kKe = [
200532
200815
  matches: (e) => e.path === "permissions.additionalDirectories" && e.code === "invalid_type",
200533
200816
  tip: {
200534
200817
  suggestion: "Must be an array of directory paths. Example: [\"~/projects\", \"/tmp/workspace\"]. You can also use --add-dir flag or /add-dir command",
200535
- docLink: `${os$1}/iam#working-directories`
200818
+ docLink: `${os$2}/iam#working-directories`
200536
200819
  }
200537
200820
  }
200538
200821
  ], AKe = {
200539
- permissions: `${os$1}/iam#configuring-permissions`,
200540
- env: `${os$1}/settings#environment-variables`,
200541
- hooks: `${os$1}/hooks`
200822
+ permissions: `${os$2}/iam#configuring-permissions`,
200823
+ env: `${os$2}/settings#environment-variables`,
200824
+ hooks: `${os$2}/hooks`
200542
200825
  };
200543
200826
  function GZ(e) {
200544
200827
  let t = kKe.find((r) => r.matches(e));
@@ -216570,6 +216853,19 @@ const makeClaudeAdapter = fn$1("makeClaudeAdapter")(function* (options) {
216570
216853
  const resumeState = readClaudeResumeState(input.resumeCursor);
216571
216854
  const threadId = input.threadId;
216572
216855
  const { existingResumeSessionId, newSessionId, sessionId } = yield* resolveClaudeStartSessionIds(resumeState);
216856
+ const workspaceCwd = input.cwd;
216857
+ if (workspaceCwd) yield* tryPromise({
216858
+ try: () => prepareWorkspaceRepositoryDependencies({
216859
+ cwd: workspaceCwd,
216860
+ cloudProjectsRoot: serverConfig.cloudProjectsRoot ?? "/projects",
216861
+ runtimeMode: serverConfig.forgeCmmdRuntimeMode === true
216862
+ }),
216863
+ catch: (cause) => new ProviderAdapterValidationError({
216864
+ provider: PROVIDER$11,
216865
+ operation: "startSession",
216866
+ issue: cause instanceof Error ? cause.message : "Could not prepare declared repository dependencies."
216867
+ })
216868
+ });
216573
216869
  const runtimeContext = yield* context();
216574
216870
  const runFork = runForkWith(runtimeContext);
216575
216871
  const runPromise = runPromiseWith(runtimeContext);
@@ -232876,12 +233172,12 @@ const collectOutput = fn$1("collectOutput")(function* (input, stream, maxOutputB
232876
233172
  let lineBuffer = "";
232877
233173
  let truncated = false;
232878
233174
  const emitCompleteLines = fn$1("emitCompleteLines")(function* (flush) {
232879
- let newlineIndex = lineBuffer.indexOf("\n");
233175
+ let newlineIndex = lineBuffer.search(/[\r\n]/);
232880
233176
  while (newlineIndex >= 0) {
232881
233177
  const line = lineBuffer.slice(0, newlineIndex).replace(/\r$/, "");
232882
233178
  lineBuffer = lineBuffer.slice(newlineIndex + 1);
232883
233179
  if (line.length > 0 && onLine) yield* onLine(line);
232884
- newlineIndex = lineBuffer.indexOf("\n");
233180
+ newlineIndex = lineBuffer.search(/[\r\n]/);
232885
233181
  }
232886
233182
  if (flush) {
232887
233183
  const trailing = lineBuffer.replace(/\r$/, "");
@@ -233029,6 +233325,7 @@ const GitCoreLive = effect(GitCore, fn$1("makeGitCore")(function* (options) {
233029
233325
  operation,
233030
233326
  cwd,
233031
233327
  args,
233328
+ ...options.env ? { env: options.env } : {},
233032
233329
  ...options.stdin !== void 0 ? { stdin: options.stdin } : {},
233033
233330
  allowNonZeroExit: true,
233034
233331
  ...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {},
@@ -233750,12 +234047,19 @@ const GitCoreLive = effect(GitCore, fn$1("makeGitCore")(function* (options) {
233750
234047
  };
233751
234048
  });
233752
234049
  const createWorktree = fn$1("createWorktree")(function* (input) {
234050
+ const report = (stage, status, detail) => input.onStage?.({
234051
+ stage,
234052
+ status,
234053
+ ...detail ? { detail } : {}
234054
+ }) ?? void_$1;
234055
+ yield* report("resolve", "running");
233753
234056
  const base = input.branch ?? (yield* resolveDefaultBaseBranch(input.cwd));
233754
234057
  const startPoint = yield* resolveWorktreeStartPoint({
233755
234058
  cwd: input.cwd,
233756
234059
  base,
233757
234060
  creatingNewBranch: input.newBranch !== void 0
233758
234061
  });
234062
+ yield* report("resolve", "done", startPoint);
233759
234063
  const targetBranch = input.newBranch ?? base;
233760
234064
  const sanitizedBranch = targetBranch.replace(/\//g, "-");
233761
234065
  const repoName = path$10.basename(input.cwd);
@@ -233767,7 +234071,10 @@ const GitCoreLive = effect(GitCore, fn$1("makeGitCore")(function* (options) {
233767
234071
  limit: 200
233768
234072
  })).branches.find((branch) => branch.isRemote !== true && branch.name === targetBranch && branch.worktreePath !== null && path.resolve(branch.worktreePath) === canonicalWorktreePath);
233769
234073
  if (existingBranch?.worktreePath) {
234074
+ yield* report("checkout", "skipped", "Existing worktree");
234075
+ yield* report("dependencies", "running");
233770
234076
  yield* setupSharedWorktreeDependencies(input.cwd, existingBranch.worktreePath);
234077
+ yield* report("dependencies", "done");
233771
234078
  return { worktree: {
233772
234079
  path: worktreePath,
233773
234080
  branch: targetBranch
@@ -233786,11 +234093,19 @@ const GitCoreLive = effect(GitCore, fn$1("makeGitCore")(function* (options) {
233786
234093
  worktreePath,
233787
234094
  startPoint
233788
234095
  ];
234096
+ yield* report("checkout", "running");
233789
234097
  yield* executeGit("GitCore.createWorktree", input.cwd, args, {
233790
234098
  fallbackErrorMessage: "git worktree add failed",
234099
+ env: {
234100
+ GIT_PROGRESS_DELAY: "0",
234101
+ LC_ALL: "C"
234102
+ },
233791
234103
  ...input.progress ? { progress: input.progress } : {}
233792
234104
  });
234105
+ yield* report("checkout", "done");
234106
+ yield* report("dependencies", "running");
233793
234107
  yield* setupSharedWorktreeDependencies(input.cwd, worktreePath);
234108
+ yield* report("dependencies", "done");
233794
234109
  return { worktree: {
233795
234110
  path: worktreePath,
233796
234111
  branch: targetBranch
@@ -267395,7 +267710,7 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
267395
267710
  var dgram = __require("dgram");
267396
267711
  var thunky = require_thunky();
267397
267712
  var events = __require("events");
267398
- var os = __require("os");
267713
+ var os$1 = __require("os");
267399
267714
  var noop = function() {};
267400
267715
  module.exports = function(opts) {
267401
267716
  if (!opts) opts = {};
@@ -267526,14 +267841,14 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
267526
267841
  return that;
267527
267842
  };
267528
267843
  function defaultInterface() {
267529
- var networks = os.networkInterfaces();
267844
+ var networks = os$1.networkInterfaces();
267530
267845
  var names = Object.keys(networks);
267531
267846
  for (var i = 0; i < names.length; i++) {
267532
267847
  var net = networks[names[i]];
267533
267848
  for (var j = 0; j < net.length; j++) {
267534
267849
  var iface = net[j];
267535
267850
  if (isIPv4(iface.family) && !iface.internal) {
267536
- if (os.platform() === "darwin" && names[i] === "en0") return iface.address;
267851
+ if (os$1.platform() === "darwin" && names[i] === "en0") return iface.address;
267537
267852
  return "0.0.0.0";
267538
267853
  }
267539
267854
  }
@@ -267541,7 +267856,7 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
267541
267856
  return "127.0.0.1";
267542
267857
  }
267543
267858
  function allInterfaces() {
267544
- var networks = os.networkInterfaces();
267859
+ var networks = os$1.networkInterfaces();
267545
267860
  var names = Object.keys(networks);
267546
267861
  var res = [];
267547
267862
  for (var i = 0; i < names.length; i++) {
@@ -296502,7 +296817,7 @@ function resolveBuildCommitFromEnv(env) {
296502
296817
  * environment descriptor down instead of reporting an honest "unknown".
296503
296818
  */
296504
296819
  function readBakedBuildCommit() {
296505
- return "c903d76ff920beb25458b85f671ffe18682f98a0";
296820
+ return "339f0da718657526651ad84cacb841446f1bb38b";
296506
296821
  }
296507
296822
  async function resolveServerBuildCommit(input) {
296508
296823
  if (isFullCommitSha(input.baked)) return input.baked;
@@ -298314,6 +298629,10 @@ const AuthSessionRepositoryLive = effect(AuthSessionRepository, gen(function* ()
298314
298629
  const SIGNING_SECRET_NAME = "server-signing-key";
298315
298630
  const DEFAULT_SESSION_TTL = days(30);
298316
298631
  const DEFAULT_WEBSOCKET_TOKEN_TTL = minutes(5);
298632
+ const toSessionCredentialError = (message) => (cause) => new SessionCredentialError({
298633
+ message,
298634
+ cause
298635
+ });
298317
298636
  const SessionClaims = Struct({
298318
298637
  v: Literal(1),
298319
298638
  kind: Literal("session"),
@@ -298370,10 +298689,6 @@ const SessionCredentialServiceLive = effect(SessionCredentialService, gen(functi
298370
298689
  port: serverConfig.port,
298371
298690
  host: serverConfig.host
298372
298691
  });
298373
- const toSessionCredentialError = (message) => (cause) => new SessionCredentialError({
298374
- message,
298375
- cause
298376
- });
298377
298692
  const emitUpsert = (clientSession) => publish(changesPubSub, {
298378
298693
  type: "clientUpserted",
298379
298694
  clientSession
@@ -298534,15 +298849,28 @@ const SessionCredentialServiceLive = effect(SessionCredentialService, gen(functi
298534
298849
  if (isSome(row)) {
298535
298850
  if (row.value.revokedAt !== null) return yield* new SessionCredentialError({ message: "Websocket session revoked." });
298536
298851
  if (row.value.expiresAt.epochMilliseconds <= now) return yield* new SessionCredentialError({ message: "Websocket session expired." });
298537
- } else if (!(statelessCookieSessions && claims.method === "browser-session-cookie")) return yield* new SessionCredentialError({ message: "Unknown websocket session." });
298852
+ } else {
298853
+ const cloudOwnerSession = serverConfig.forgeCloudShellMode === true && claims.method === "proxy-asserted" && forgeCloudOwnerSessionExpiresAt(claims.sid) !== null;
298854
+ if (cloudOwnerSession && isExpiredForgeCloudOwnerSession(claims.sid, now)) return yield* new SessionCredentialError({ message: "Websocket session expired." });
298855
+ if (statelessCookieSessions && (claims.method === "browser-session-cookie" || cloudOwnerSession)) return {
298856
+ sessionId: claims.sid,
298857
+ token,
298858
+ method: claims.method,
298859
+ client: createDefaultClientMetadata(),
298860
+ expiresAt: makeUnsafe$5(claims.exp),
298861
+ subject: claims.sub,
298862
+ role: claims.role
298863
+ };
298864
+ return yield* new SessionCredentialError({ message: "Unknown websocket session." });
298865
+ }
298538
298866
  return {
298539
298867
  sessionId: claims.sid,
298540
298868
  token,
298541
- method: isSome(row) ? row.value.method : claims.method,
298542
- client: isSome(row) ? toClientMetadata(row.value.client) : createDefaultClientMetadata(),
298543
- expiresAt: isSome(row) ? row.value.expiresAt : makeUnsafe$5(claims.exp),
298544
- subject: isSome(row) ? row.value.subject : claims.sub,
298545
- role: isSome(row) ? row.value.role : claims.role
298869
+ method: row.value.method,
298870
+ client: toClientMetadata(row.value.client),
298871
+ expiresAt: row.value.expiresAt,
298872
+ subject: row.value.subject,
298873
+ role: row.value.role
298546
298874
  };
298547
298875
  }).pipe(mapError((cause) => cause instanceof SessionCredentialError ? cause : new SessionCredentialError({
298548
298876
  message: "Failed to verify websocket token.",
@@ -298819,6 +299147,18 @@ function verifyForgeCloudOwnerCallbackAssertion(assertion, config) {
298819
299147
  //#endregion
298820
299148
  //#region src/auth/Layers/ServerAuth.ts
298821
299149
  const AUTHORIZATION_PREFIX = "Bearer ";
299150
+ function classifyWebSocketTokenFailure(cause) {
299151
+ switch (cause.message) {
299152
+ case "Malformed websocket token.": return "malformed";
299153
+ case "Invalid websocket token signature.": return "invalid_signature";
299154
+ case "Invalid websocket token payload.": return "invalid_payload";
299155
+ case "Websocket token expired.": return "expired_token";
299156
+ case "Websocket session revoked.": return "revoked_parent_session";
299157
+ case "Websocket session expired.": return "expired_parent_session";
299158
+ case "Unknown websocket session.": return "unknown_parent_session";
299159
+ default: return "verification_failed";
299160
+ }
299161
+ }
298822
299162
  function toBootstrapExchangeAuthError(cause) {
298823
299163
  if (cause.status === 500) return new AuthError({
298824
299164
  message: "Failed to validate bootstrap credential.",
@@ -299121,7 +299461,6 @@ const ServerAuthLive = effect(ServerAuth, gen(function* () {
299121
299461
  expiresAt: toUtc(issued.expiresAt)
299122
299462
  })));
299123
299463
  const authenticateWebSocketUpgrade = (request) => gen(function* () {
299124
- if (serverConfig.forgeCloudShellMode === true) return yield* authenticateRequest(request);
299125
299464
  if (serverConfig.forgeCmmdRuntimeMode) {
299126
299465
  if (serverConfig.forgeCmmdAuthRuntime) {
299127
299466
  const authConfig = readCmmdAuthRuntimeConfig(serverConfig);
@@ -299178,7 +299517,7 @@ const ServerAuthLive = effect(ServerAuth, gen(function* () {
299178
299517
  const requestUrl = toURL(request);
299179
299518
  if (isSome(requestUrl)) {
299180
299519
  const websocketToken = readWebSocketUpgradeToken(requestUrl.value.searchParams);
299181
- if (websocketToken) return yield* sessions.verifyWebSocketToken(websocketToken).pipe(map$3((session) => ({
299520
+ if (websocketToken) return yield* sessions.verifyWebSocketToken(websocketToken).pipe(tapError((cause) => logWarning$1("Rejected websocket token.").pipe(annotateLogs({ category: classifyWebSocketTokenFailure(cause) }))), map$3((session) => ({
299182
299521
  sessionId: session.sessionId,
299183
299522
  subject: session.subject,
299184
299523
  method: session.method,
@@ -305217,7 +305556,7 @@ const orchestrationDispatchRouteLayer = add$1("POST", "/api/orchestration/dispat
305217
305556
  }).pipe(mapError((cause) => new OrchestrationDispatchCommandError({
305218
305557
  message: "Failed to dispatch orchestration command.",
305219
305558
  cause
305220
- }))) : orchestrationEngine.dispatch(normalizedCommand).pipe(mapError((cause) => new OrchestrationDispatchCommandError({
305559
+ }))) : (normalizedCommand.type === "thread.turn.interrupt" ? interruptBootstrapTurnStart(orchestrationEngine, normalizedCommand) : orchestrationEngine.dispatch(normalizedCommand)).pipe(mapError((cause) => new OrchestrationDispatchCommandError({
305221
305560
  message: "Failed to dispatch orchestration command.",
305222
305561
  cause
305223
305562
  })));
@@ -320654,7 +320993,7 @@ const connectLoginCommand = make$34("login", {
320654
320993
  })).json();
320655
320994
  },
320656
320995
  openBrowser: async (url) => {
320657
- const open = (await import("./open-D8mGyWmt.mjs")).default;
320996
+ const open = (await import("./open-FIgTDosf.mjs")).default;
320658
320997
  await open(url);
320659
320998
  return true;
320660
320999
  },