@ai-development-environment/control-agent 0.0.141 → 0.0.143

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 (2) hide show
  1. package/dist/control-agent.js +1059 -357
  2. package/package.json +1 -1
@@ -7617,22 +7617,31 @@ var AgentGraphQLClient = class {
7617
7617
  health() {
7618
7618
  return this.request(`query Health { health }`);
7619
7619
  }
7620
+ async requestDefaultBranchConfiguration(query) {
7621
+ try {
7622
+ return await this.request(query);
7623
+ } catch (error) {
7624
+ if (!(error instanceof Error) || !/Cannot query field "defaultBranchPatterns"/.test(error.message))
7625
+ throw error;
7626
+ return this.request(query.replace(/\sdefaultBranchPatterns\b/g, ""));
7627
+ }
7628
+ }
7620
7629
  async agentCodebases() {
7621
- const data = await this.request(`query AgentCodebases {
7630
+ const data = await this.requestDefaultBranchConfiguration(`query AgentCodebases {
7622
7631
  agentCodebases {
7623
- id folder canonicalOrigin defaultBranch keepBaseBranchUpToDate lastFetchedAt lastFetchAttemptAt
7632
+ id folder canonicalOrigin defaultBranch keepBaseBranchUpToDate defaultBranchPatterns lastFetchedAt lastFetchAttemptAt
7624
7633
  worktrees { id folder branch gitDirectory baseBranchOverride }
7625
7634
  }
7626
7635
  }`);
7627
7636
  return data.agentCodebases;
7628
7637
  }
7629
7638
  async agentCodebaseConfiguration() {
7630
- const data = await this.request(`query AgentCodebaseConfiguration {
7639
+ const data = await this.requestDefaultBranchConfiguration(`query AgentCodebaseConfiguration {
7631
7640
  agentCodebaseConfiguration {
7632
7641
  refreshIntervalSeconds
7633
7642
  fetchIntervalSeconds
7634
7643
  codebases {
7635
- id folder canonicalOrigin defaultBranch keepBaseBranchUpToDate lastFetchedAt lastFetchAttemptAt
7644
+ id folder canonicalOrigin defaultBranch keepBaseBranchUpToDate defaultBranchPatterns lastFetchedAt lastFetchAttemptAt
7636
7645
  worktrees { id folder branch gitDirectory baseBranchOverride }
7637
7646
  }
7638
7647
  }
@@ -8134,6 +8143,50 @@ var CODEBASE_GIT_INSPECT_JOB_KIND = "codebase.git.inspect";
8134
8143
  var CODEBASE_GIT_OPERATION_JOB_KIND = "codebase.git.operation";
8135
8144
  var CODEBASE_BRANCHES_DELETE_JOB_KIND = "codebase.branches.delete";
8136
8145
  var CODEBASE_RECONCILE_EVENT_CAPABILITY = "codebase.reconcile.requested";
8146
+ var CODEBASE_DEFAULT_BRANCHES_CAPABILITY = "codebase.default-branches.v1";
8147
+ function normalizeDefaultBranchPatterns(value) {
8148
+ if (!Array.isArray(value) || value.length > 100)
8149
+ throw new Error(
8150
+ "Default branch patterns must be a list of at most 100 entries"
8151
+ );
8152
+ const patterns = value.map((entry) => {
8153
+ if (typeof entry !== "string" || entry.trim().length > 255)
8154
+ throw new Error(
8155
+ "Default branch patterns must be strings of at most 255 characters"
8156
+ );
8157
+ const pattern = entry.trim();
8158
+ if (pattern && /[\s\x00-\x1f\x7f]/.test(pattern))
8159
+ throw new Error(
8160
+ "Default branch patterns cannot contain whitespace or control characters"
8161
+ );
8162
+ return pattern;
8163
+ });
8164
+ return [...new Set(patterns.filter(Boolean))];
8165
+ }
8166
+ function isDefaultBranch(branch, remoteDefaultBranch, patterns = []) {
8167
+ if (!branch) return false;
8168
+ if (branch === remoteDefaultBranch) return true;
8169
+ return patterns.some((pattern) => {
8170
+ let position = 0;
8171
+ let patternPosition = 0;
8172
+ let star = -1;
8173
+ let resume = 0;
8174
+ while (position < branch.length) {
8175
+ if (pattern[patternPosition] === "*") {
8176
+ star = patternPosition++;
8177
+ resume = position;
8178
+ } else if (pattern[patternPosition] === branch[position]) {
8179
+ patternPosition++;
8180
+ position++;
8181
+ } else if (star >= 0) {
8182
+ patternPosition = star + 1;
8183
+ position = ++resume;
8184
+ } else return false;
8185
+ }
8186
+ while (pattern[patternPosition] === "*") patternPosition++;
8187
+ return patternPosition === pattern.length;
8188
+ });
8189
+ }
8137
8190
  var MAX_CODEBASE_GIT_BRANCHES = 1e3;
8138
8191
  var MAX_CODEBASE_STASHES = 200;
8139
8192
  var MAX_CODEBASE_STASH_PATCH_BYTES = 256 * 1024;
@@ -8439,7 +8492,8 @@ function codebaseJobPayload(value) {
8439
8492
  "codebaseId",
8440
8493
  "expectedOrigin",
8441
8494
  "baseBranch",
8442
- "keepBaseBranchUpToDate"
8495
+ "keepBaseBranchUpToDate",
8496
+ "defaultBranchPatterns"
8443
8497
  ]);
8444
8498
  const unexpected = Object.keys(payload).find((key) => !allowed.has(key));
8445
8499
  if (unexpected)
@@ -8461,6 +8515,11 @@ function codebaseJobPayload(value) {
8461
8515
  payload.keepBaseBranchUpToDate,
8462
8516
  "payload.keepBaseBranchUpToDate"
8463
8517
  )
8518
+ },
8519
+ ...payload.defaultBranchPatterns === void 0 ? {} : {
8520
+ defaultBranchPatterns: normalizeDefaultBranchPatterns(
8521
+ payload.defaultBranchPatterns
8522
+ )
8464
8523
  }
8465
8524
  };
8466
8525
  }
@@ -11683,7 +11742,7 @@ function tailscaleServeRemovePayload(value) {
11683
11742
  // package.json
11684
11743
  var package_default = {
11685
11744
  name: "@ai-development-environment/control-agent",
11686
- version: "0.0.141",
11745
+ version: "0.0.143",
11687
11746
  description: "Control agent for the AI Development Environment",
11688
11747
  license: "MIT",
11689
11748
  repository: {
@@ -11753,6 +11812,7 @@ var PORTABLE_AGENT_CAPABILITIES = [
11753
11812
  CCUSAGE_REPORT_JOB_KIND,
11754
11813
  ...CODEBASE_JOB_KINDS,
11755
11814
  CODEBASE_RECONCILE_EVENT_CAPABILITY,
11815
+ CODEBASE_DEFAULT_BRANCHES_CAPABILITY,
11756
11816
  ...WORKTREE_JOB_KINDS,
11757
11817
  WORKTREE_REVIEWED_SYNC_CAPABILITY,
11758
11818
  ...SKILL_JOB_KINDS,
@@ -11810,7 +11870,7 @@ import { randomUUID as randomUUID10 } from "node:crypto";
11810
11870
  // src/runs/branch-naming.ts
11811
11871
  import { mkdtemp as mkdtemp2, rm as rm7 } from "node:fs/promises";
11812
11872
  import { tmpdir as tmpdir2 } from "node:os";
11813
- import { join as join9 } from "node:path";
11873
+ import { join as join10 } from "node:path";
11814
11874
 
11815
11875
  // src/runs/codex-adapter.ts
11816
11876
  import {
@@ -13166,7 +13226,9 @@ var CodexAdapter = class {
13166
13226
 
13167
13227
  // src/runs/claude-adapter.ts
13168
13228
  import { randomUUID as randomUUID2 } from "node:crypto";
13229
+ import { stat as stat3 } from "node:fs/promises";
13169
13230
  import { homedir as homedir5 } from "node:os";
13231
+ import { dirname as dirname5, join as join7 } from "node:path";
13170
13232
 
13171
13233
  // src/runs/claude-import.ts
13172
13234
  import { createReadStream as createReadStream3 } from "node:fs";
@@ -13194,6 +13256,83 @@ function timestamp2(value) {
13194
13256
  const date = typeof value === "string" || typeof value === "number" ? new Date(value) : void 0;
13195
13257
  return date && Number.isFinite(date.getTime()) ? date.toISOString() : void 0;
13196
13258
  }
13259
+ function claudeSubagentSnapshot(nativeId, values, metadataValues = [], options = { transcriptStatus: "AVAILABLE" }) {
13260
+ const messages = /* @__PURE__ */ new Map();
13261
+ for (const value of values) {
13262
+ const record = asRecord(value);
13263
+ if ((record.type === "user" || record.type === "assistant") && typeof record.uuid === "string")
13264
+ messages.set(record.uuid, { ...record, agent_id: nativeId });
13265
+ }
13266
+ const records = [...messages.values()];
13267
+ const toolUseId = records.map((record) => record.parent_tool_use_id).find((value) => typeof value === "string" && !!value);
13268
+ const parentNativeId = records.map((record) => record.parent_agent_id).find((value) => typeof value === "string" && !!value);
13269
+ let label;
13270
+ let agentType;
13271
+ let status2;
13272
+ let nativeRunId;
13273
+ for (const value of metadataValues) {
13274
+ const envelope = asRecord(value);
13275
+ const record = envelope.raw ? asRecord(envelope.raw) : envelope;
13276
+ const content = asRecord(record.message).content;
13277
+ for (const candidate of Array.isArray(content) ? content : []) {
13278
+ const block = asRecord(candidate);
13279
+ if (block.type === "tool_use" && block.id === toolUseId && (block.name === "Agent" || block.name === "Task")) {
13280
+ const input = asRecord(block.input);
13281
+ if (typeof input.description === "string") label = input.description;
13282
+ if (typeof input.subagent_type === "string")
13283
+ agentType = input.subagent_type;
13284
+ }
13285
+ }
13286
+ if (record.task_id !== nativeId) continue;
13287
+ if (typeof record.description === "string") label ??= record.description;
13288
+ if (typeof record.subagent_type === "string")
13289
+ agentType = record.subagent_type;
13290
+ const runId = typeof record.run_id === "string" ? record.run_id : void 0;
13291
+ if (nativeRunId && (!runId || runId < nativeRunId)) continue;
13292
+ if (runId && runId !== nativeRunId) {
13293
+ nativeRunId = runId;
13294
+ status2 = void 0;
13295
+ }
13296
+ const state = record.status ?? asRecord(record.patch).status ?? (record.subtype === "task_started" || record.subtype === "task_progress" ? "RUNNING" : void 0);
13297
+ if (typeof state === "string") status2 = state.toUpperCase();
13298
+ }
13299
+ const prompt = records.filter((record) => record.type === "user").map((record) => textBlocks(asRecord(record.message).content)).find(Boolean);
13300
+ const replies = /* @__PURE__ */ new Map();
13301
+ let finalReplyId;
13302
+ for (const record of records) {
13303
+ if (record.type !== "assistant") continue;
13304
+ const message2 = asRecord(record.message);
13305
+ const reply = textBlocks(message2.content);
13306
+ if (reply) {
13307
+ const replyId = String(message2.id ?? record.uuid);
13308
+ const parts = replies.get(replyId) ?? /* @__PURE__ */ new Map();
13309
+ parts.set(String(record.uuid), reply);
13310
+ replies.set(replyId, parts);
13311
+ finalReplyId = replyId;
13312
+ }
13313
+ }
13314
+ const last = records.at(-1);
13315
+ const finished = options.transcriptStatus === "AVAILABLE" && status2 !== "RUNNING" && status2 !== "PAUSED" && last?.type === "assistant" && asRecord(last.message).stop_reason === "end_turn";
13316
+ return {
13317
+ nativeId,
13318
+ ...nativeRunId ? { nativeRunId } : {},
13319
+ ...parentNativeId ? { parentNativeId } : {},
13320
+ ...toolUseId ? { toolUseId } : {},
13321
+ ...label ? { label } : {},
13322
+ ...agentType ? { agentType } : {},
13323
+ ...status2 || finished ? { status: status2 ?? "COMPLETED" } : {},
13324
+ ...prompt ? { prompt } : {},
13325
+ ...finalReplyId && status2 !== "RUNNING" && status2 !== "PAUSED" ? { finalOutput: [...replies.get(finalReplyId).values()].join("\n\n") } : {},
13326
+ startedAt: timestamp2(records[0]?.timestamp),
13327
+ ...finished ? { finishedAt: timestamp2(last?.timestamp) } : {},
13328
+ ...options,
13329
+ messages: records.map((record) => ({
13330
+ nativeId: String(record.uuid),
13331
+ raw: record,
13332
+ createdAt: timestamp2(record.timestamp)
13333
+ }))
13334
+ };
13335
+ }
13197
13336
  function claudeTranscriptMetadata(values) {
13198
13337
  const records = values.map(asRecord);
13199
13338
  const requests = /* @__PURE__ */ new Map();
@@ -13422,6 +13561,8 @@ import { randomBytes as Wwe } from "crypto";
13422
13561
  import { closeSync as nct, constants as Gt, fchmodSync as rct, fstatSync as oct, ftruncateSync as sct, lstatSync as ict, openSync as act, readFileSync as lct, renameSync as cct, unlinkSync as uct, writeFileSync as dct } from "fs";
13423
13562
  import { lstat as cg, open as Rd, rename as rF, stat as Vwe, unlink as Ad, writeFile as qwe } from "fs/promises";
13424
13563
  import { basename as Ywe, join as Zwe } from "path";
13564
+ import { readdir as zxe, readFile as EF } from "fs/promises";
13565
+ import { isAbsolute as bF, join as ug, relative as CF, sep as dg } from "path";
13425
13566
  import { randomUUID as A$e } from "crypto";
13426
13567
  import { join as j1 } from "path";
13427
13568
  import { lstat as s6e } from "fs/promises";
@@ -17312,6 +17453,10 @@ function Ef(e10) {
17312
17453
  }
17313
17454
  var ak = "[\\w-]{1,63}";
17314
17455
  var AJ = new RegExp(`^${ak}$`);
17456
+ var RJ = /^[\w-]{1,128}$/;
17457
+ function eS(e10) {
17458
+ return RJ.test(e10);
17459
+ }
17315
17460
  var DJe = new RegExp(`^a(?:${ak}-)?[0-9a-f]{16}$`);
17316
17461
  function tS(e10, t) {
17317
17462
  let n = Buffer.from(t.replace(/-/g, ""), "hex"), r = ik("sha1").update(n).update(Buffer.from(e10, "utf8")).digest();
@@ -30304,6 +30449,12 @@ function R0(e10, t) {
30304
30449
  function DR(e10, t) {
30305
30450
  return typeof t === "string" && e10.test(t);
30306
30451
  }
30452
+ function VTe(e10) {
30453
+ if (e10.year !== void 0 && e10.projectKey === void 0) return Y("scope.projectKey", "required when year is given");
30454
+ if (e10.month !== void 0 && e10.year === void 0) return Y("scope.year", "required when month is given");
30455
+ if (e10.day !== void 0 && e10.month === void 0) return Y("scope.month", "required when day is given");
30456
+ return R0("scope", e10);
30457
+ }
30307
30458
  var qTe = /^[0-9a-f]{8}$/;
30308
30459
  function YTe(e10) {
30309
30460
  switch (e10.namespace) {
@@ -30376,6 +30527,97 @@ function YTe(e10) {
30376
30527
  }
30377
30528
  return;
30378
30529
  }
30530
+ function LR(e10) {
30531
+ if (typeof e10 !== "object" || e10 === null) return Y("scope", "expected a scope object");
30532
+ let t = QTe(e10);
30533
+ if (t === void 0) return Y("scope", `${String(e10.namespace)} is not a listable namespace`);
30534
+ return JTe(e10) ?? n0("scope", t);
30535
+ }
30536
+ var ZTe = { transcript: [["agentId", "names one agent transcript, a stream key, not a scope: narrow a scope with agentRelPath"], ["journal", "names a run journal, a stream key, not a scope: narrow a scope with agentRelPath"], ["sessionJournal", "names a session's own journal, a stream key, not a scope: the session scope lists it"]], log: [["agentId", "names one log stream, a stream key, not a scope"], ["runId", "names one log stream, a stream key, not a scope"]], sessionLog: [["logName", "names one session's log, a stream key, not a scope: a day scope lists its logs"]], task: [["taskId", "names one task value, a key, not a scope: a list scope narrows with listId only"], ["meta", "names one task value, a key, not a scope: a list scope narrows with listId only"], ["highWaterMark", "names one task value, a key, not a scope: a list scope narrows with listId only"]], mailbox: [["teammate", "names one inbox, a key, not a scope"]], cache: [["id", "names one cached value, a key, not a scope: a cache scope narrows with store only"]], pluginAssetCache: [["digest", "names one cached asset, a key, not a scope"]], fileHistory: [["backupFileName", "names one backup, a key, not a scope: a file-history scope narrows with sessionId only"]], state: [["id", "names one value, a key, not a scope"]], feedbackDraft: [["draftId", "names one draft, a key, not a scope"]], jobsRoot: [["file", "names one value, a key, not a scope"], ["draftKey", "names one value, a key, not a scope"]], plan: [["name", "names one plan, a key, not a scope"]], paste: [["id", "names one paste, a key, not a scope"]], session: [["file", "names one value, a key, not a scope"]], globalConfig: [["stamp", "names one recovery copy, a key, not a scope: the scope narrows with kind only"]], marketplaceCache: [["form", "names one of the marketplace's two engine-written files, a key, not a scope: the tree narrows with relPath only"]], memory: [], pluginCache: [], daemon: [], sidecar: [], agentMemory: [], scratch: [], userConfigDir: [], job: [], bridgeSpawn: [] };
30537
+ function JTe(e10) {
30538
+ let t = e10.namespace === "agentMemory" ? XTe(e10) : void 0;
30539
+ if (t !== void 0) return t;
30540
+ if (e10.namespace === "transcript" || e10.namespace === "sidecar") {
30541
+ let r = ng("scope.sessionId", e10.sessionId);
30542
+ if (r !== void 0) return r;
30543
+ }
30544
+ for (let [r, o] of ZTe[e10.namespace]) if (r in e10 && e10[r] !== void 0) return Y(`scope.${r}`, o);
30545
+ if (e10.namespace === "sidecar" && rg(e10.relPath)) return Y("scope.relPath", _d);
30546
+ if (e10.namespace === "sidecar" && h0(e10.relPath)) return Y("scope.relPath", m0);
30547
+ if (e10.namespace === "log" && e10.channel !== void 0 && !E0(e10.channel)) return Y("scope.channel", S0);
30548
+ if (e10.namespace === "job" && A0(e10.relPath)) return Y("scope.relPath", C0);
30549
+ let n = e10.namespace === "sessionLog" ? VTe(e10) : void 0;
30550
+ if (n !== void 0) return n;
30551
+ if (e10.namespace === "scratch" && e10.sessionId === void 0 && e10.relPath !== void 0) return Y("scope.relPath", "requires scope.sessionId: a scratch relPath narrows one session directory, and no cross-session prefix filter exists");
30552
+ if (e10.namespace === "userConfigDir" && !o0.has(e10.dir)) return Y("scope.dir", s0);
30553
+ if (e10.namespace === "transcript" && e10.agentRelPath !== void 0 && (e10.projectKey === void 0 || e10.sessionId === void 0)) return Y("scope.agentRelPath", "requires scope.projectKey and scope.sessionId: an agentRelPath narrows the subagents/ tree of one session directory");
30554
+ if (e10.namespace === "transcript" && rg(e10.agentRelPath)) return Y("scope.agentRelPath", _d);
30555
+ if (e10.namespace === "pluginCache") {
30556
+ if (e10.marketplace === void 0 && e10.plugin !== void 0) return Y("scope.plugin", "requires scope.marketplace: a plugin narrows one marketplace folder");
30557
+ if (e10.plugin === void 0 && e10.version !== void 0) return Y("scope.version", "requires scope.plugin: a version narrows one plugin folder");
30558
+ if (e10.version === void 0 && e10.relPath !== void 0) return Y("scope.relPath", "requires scope.version: a relPath narrows one version folder");
30559
+ }
30560
+ if (e10.namespace === "job" && e10.jobId === void 0 && e10.relPath !== void 0) return Y("scope.relPath", "requires scope.jobId: a job relPath narrows one job directory, and no cross-job prefix filter exists");
30561
+ if (e10.namespace === "transcript" && e10.projectKey === void 0 && e10.sessionId !== void 0) return Y("scope.sessionId", "requires scope.projectKey: a session narrows one project folder, and no cross-project session filter exists");
30562
+ if (e10.namespace === "globalConfig" && e10.kind !== void 0 && !p0(e10.kind)) return Y("scope.kind", d0);
30563
+ return;
30564
+ }
30565
+ function XTe(e10) {
30566
+ if (!c0(e10.layer)) return Y("scope.layer", "must be user, project or local");
30567
+ if (e10.layer === "user" && "projectKey" in e10) return Y("scope.projectKey", "the user layer is not keyed by project");
30568
+ if (e10.layer !== "user" && typeof e10.projectKey !== "string") return Y("scope.projectKey", "required for the project and local layers");
30569
+ return e10.agentType === void 0 && e10.relPath !== void 0 ? Y("scope.relPath", "requires scope.agentType: an agent-memory relPath narrows one agent directory") : void 0;
30570
+ }
30571
+ function QTe(e10) {
30572
+ switch (e10.namespace) {
30573
+ case "transcript":
30574
+ return [["projectKey", e10.projectKey, "optional"], ["sessionId", e10.sessionId, "optional"], ["agentRelPath", e10.agentRelPath, "optional"]];
30575
+ case "task":
30576
+ return [["listId", e10.listId, "optional"]];
30577
+ case "mailbox":
30578
+ return [["team", e10.team, "optional"]];
30579
+ case "memory":
30580
+ return [["projectKey", e10.projectKey], ["relPath", e10.relPath, "optional"]];
30581
+ case "pluginCache":
30582
+ return [["marketplace", e10.marketplace, "optional"], ["plugin", e10.plugin, "optional"], ["version", e10.version, "optional"], ["relPath", e10.relPath, "optional"]];
30583
+ case "marketplaceCache":
30584
+ return [["marketplace", e10.marketplace], ["relPath", e10.relPath, "optional"]];
30585
+ case "cache":
30586
+ return [["store", e10.store]];
30587
+ case "state":
30588
+ case "plan":
30589
+ case "paste":
30590
+ case "pluginAssetCache":
30591
+ case "feedbackDraft":
30592
+ return [];
30593
+ case "sidecar":
30594
+ return [["projectKey", e10.projectKey], ["sessionId", e10.sessionId], ["relPath", e10.relPath, "optional"]];
30595
+ case "agentMemory":
30596
+ return [["projectKey", e10.layer === "user" ? void 0 : e10.projectKey, "optional"], ["agentType", e10.agentType, "optional"], ["relPath", e10.relPath, "optional"]];
30597
+ case "scratch":
30598
+ return [["sessionId", e10.sessionId, "optional"], ["relPath", e10.relPath, "optional"]];
30599
+ case "userConfigDir":
30600
+ return [["relPath", e10.relPath, "optional"]];
30601
+ case "fileHistory":
30602
+ return [["sessionId", e10.sessionId, "optional"]];
30603
+ case "job":
30604
+ return [["jobId", e10.jobId, "optional"], ["relPath", e10.relPath, "optional"]];
30605
+ case "daemon":
30606
+ return [["relPath", e10.relPath, "optional"]];
30607
+ case "jobsRoot":
30608
+ case "session":
30609
+ return [];
30610
+ case "bridgeSpawn":
30611
+ return [["dir", e10.dir, "optional"]];
30612
+ case "globalConfig":
30613
+ return [["kind", e10.kind, "optional"]];
30614
+ case "log":
30615
+ return [["sessionId", e10.sessionId, "optional"]];
30616
+ case "sessionLog":
30617
+ return [["projectKey", e10.projectKey, "optional"], ["year", e10.year, "optional"], ["month", e10.month, "optional"], ["day", e10.day, "optional"]];
30618
+ }
30619
+ return;
30620
+ }
30379
30621
  function twe(e10) {
30380
30622
  let t = process.cwd();
30381
30623
  return t.endsWith(O0) ? t + e10 : t + O0 + e10;
@@ -31553,6 +31795,158 @@ var xxe = new Exe();
31553
31795
  function gl() {
31554
31796
  return xxe.getStore() ?? new fF();
31555
31797
  }
31798
+ async function AF(e10, t, n, r, o) {
31799
+ let s = await ws(e10, t, Hn(n), r, o);
31800
+ if (!s) return null;
31801
+ let i = s.filePath.replace(/\.jsonl$/, "");
31802
+ return ug(i, "subagents");
31803
+ }
31804
+ function RF(e10) {
31805
+ let t = CF(Et(), e10);
31806
+ if (t === "" || t.startsWith(`..${dg}`) || t === ".." || bF(t)) return null;
31807
+ let n = t.split(dg);
31808
+ return n.length < 4 || n[2] !== "subagents" ? null : n;
31809
+ }
31810
+ function jxe(e10) {
31811
+ let t = RF(e10), n = t?.at(-1);
31812
+ if (!t || !n?.startsWith("agent-") || !n.endsWith(".jsonl")) return null;
31813
+ let r = n.slice(6, -6), o = t.slice(3, -1);
31814
+ if (!$n([t[0], t[1], r]) || o.length > 0 && !$n(o)) return null;
31815
+ let s = Ut.transcript(t[0], t[1], r, o.length > 0 ? o : void 0);
31816
+ return zo(s) === void 0 ? s : null;
31817
+ }
31818
+ function Bxe(e10) {
31819
+ let t = RF(e10);
31820
+ if (!t) return null;
31821
+ let n = t.slice(2);
31822
+ if (!$n([t[0], t[1]]) || !$n(n)) return null;
31823
+ let r = Ut.sidecar(t[0], t[1], n);
31824
+ return zo(r) === void 0 ? r : null;
31825
+ }
31826
+ async function OF(e10, t, { rejectUnlistable: n = false } = {}) {
31827
+ let r = be() && t !== void 0 ? Kxe(e10) : null;
31828
+ if (t !== void 0 && r !== null) return Wxe(t, r, e10, Gxe, n);
31829
+ let o = [];
31830
+ async function s(i) {
31831
+ let a;
31832
+ try {
31833
+ a = await zxe(i, { withFileTypes: true });
31834
+ } catch (l) {
31835
+ if (n && !at(l)) throw l;
31836
+ return;
31837
+ }
31838
+ for (let l of a) if (l.isFile() && l.name.startsWith("agent-") && l.name.endsWith(".jsonl")) {
31839
+ let c = l.name.slice(6, -6);
31840
+ o.push({ agentId: c, filePath: ug(i, l.name) });
31841
+ } else if (l.isDirectory()) await s(ug(i, l.name));
31842
+ }
31843
+ return await s(e10), o;
31844
+ }
31845
+ function Kxe(e10) {
31846
+ let t = CF(Et(), e10);
31847
+ if (t === "" || t.startsWith(`..${dg}`) || bF(t)) return null;
31848
+ let n = t.split(dg);
31849
+ if (n.length !== 3 || n[2] !== "subagents" || !$n([n[0], n[1]])) return null;
31850
+ let r = { namespace: "transcript", projectKey: n[0], sessionId: n[1] };
31851
+ return LR(r) === void 0 ? r : null;
31852
+ }
31853
+ var Gxe = 1e4;
31854
+ async function Wxe(e10, t, n, r, o) {
31855
+ let s = [], i = [t], a = /* @__PURE__ */ new Set([""]), l = 0;
31856
+ try {
31857
+ while (i.length > 0) {
31858
+ if (++l > r) throw Error("sub-agent listing incomplete");
31859
+ let c = i.shift(), d = [];
31860
+ if ((await kr((f) => e10.listEntries(c, { skipKeyStats: true, skipScopeStats: true, ...f !== void 0 && { cursor: f } }), (f) => {
31861
+ for (let m of f) if (m.kind === "key" && m.key.namespace === "transcript" && m.key.agentId !== void 0 && en(m.key.agentId) && (m.key.agentRelPath === void 0 || $n(m.key.agentRelPath))) s.push({ agentId: m.key.agentId, filePath: ug(n, ...m.key.agentRelPath ?? [], `agent-${m.key.agentId}.jsonl`) });
31862
+ else if (m.kind === "scope" && m.scope.namespace === "transcript" && m.scope.agentRelPath !== void 0 && $n(m.scope.agentRelPath) && !a.has(m.scope.agentRelPath.join("/"))) {
31863
+ let g = { ...t, agentRelPath: m.scope.agentRelPath };
31864
+ if (LR(g) === void 0) a.add(m.scope.agentRelPath.join("/")), d.push(g);
31865
+ }
31866
+ })).status !== "done") throw Error("sub-agent listing incomplete");
31867
+ i.unshift(...d);
31868
+ }
31869
+ } catch (c) {
31870
+ if (o) throw c;
31871
+ return [];
31872
+ }
31873
+ return s;
31874
+ }
31875
+ function Vxe(e10) {
31876
+ let t = [], n = 10, r = e10.length, o = 0;
31877
+ while (o < r) {
31878
+ let s = e10.indexOf(10, o);
31879
+ if (s === -1) s = r;
31880
+ let i = o;
31881
+ while (i < s && e10[i] <= 32) i++;
31882
+ if (o = s + 1, i >= s) continue;
31883
+ let a = e10.toString("utf-8", i, s);
31884
+ try {
31885
+ let l = je(a), c = l.type;
31886
+ if ((c === "user" || c === "assistant" || c === "attachment") && typeof l.uuid === "string") t.push(l);
31887
+ } catch {
31888
+ }
31889
+ }
31890
+ return t;
31891
+ }
31892
+ function qxe(e10) {
31893
+ if (e10.length === 0) return [];
31894
+ let t = /* @__PURE__ */ new Map();
31895
+ for (let i of e10) t.set(i.uuid, i);
31896
+ let n = e10.findLast((i) => i.type === "user" || i.type === "assistant");
31897
+ if (!n) return [];
31898
+ let r = [], o = /* @__PURE__ */ new Set(), s = n;
31899
+ while (s) {
31900
+ if (o.has(s.uuid)) break;
31901
+ o.add(s.uuid), r.push(s), s = s.parentUuid ? t.get(s.parentUuid) : void 0;
31902
+ }
31903
+ return r.reverse(), r;
31904
+ }
31905
+ async function TF(e10, t, n, r) {
31906
+ if (!Ve(e10)) return [];
31907
+ let o = be(), s = o ? n : void 0, i = await AF(e10, t?.dir, s, o, r);
31908
+ if (!i) return [];
31909
+ return (await OF(i, s)).map((l) => l.agentId);
31910
+ }
31911
+ async function wF(e10, t, n, r, o) {
31912
+ if (!Ve(e10)) return [];
31913
+ if (!t) return [];
31914
+ let s = be(), i = s ? r : void 0, a = await AF(e10, n?.dir, i, s, o);
31915
+ if (!a) return [];
31916
+ let c = (await OF(a, i)).find((g) => g.agentId === t);
31917
+ if (!c) return [];
31918
+ let d, p = i !== void 0 ? jxe(c.filePath) : null;
31919
+ if (i !== void 0 && p !== null) try {
31920
+ let g = await i.read([p]), _ = g.ok ? g.value.items[0] : void 0;
31921
+ if (!_?.found) return [];
31922
+ d = Buffer.from(_.value);
31923
+ } catch {
31924
+ return [];
31925
+ }
31926
+ else try {
31927
+ d = await EF(c.filePath);
31928
+ } catch {
31929
+ return [];
31930
+ }
31931
+ let f, m;
31932
+ try {
31933
+ let g = c.filePath.replace(/\.jsonl$/, ".meta.json"), _ = i !== void 0 ? Bxe(g) : null, y;
31934
+ if (i !== void 0 && _ !== null) {
31935
+ let E = await i.read([_]);
31936
+ if (!E.ok || !E.value.items[0]?.found) throw Error("sidecar absent");
31937
+ y = Buffer.from(E.value.items[0].value).toString("utf-8");
31938
+ } else y = await EF(g, "utf-8");
31939
+ let S = je(y);
31940
+ f = S.toolUseId, m = S.parentAgentId;
31941
+ } catch {
31942
+ }
31943
+ return YR(d, n, f, m);
31944
+ }
31945
+ function YR(e10, t, n, r) {
31946
+ if (e10.length === 0) return [];
31947
+ let o = Vxe(e10), s = qxe(o), i = Du(n), a = typeof r === "string" && eS(r) ? r : void 0, l = FR(s, { keepMeta: true }).filter((c) => c.type === "user" || c.type === "assistant").map((c) => $R(c, i, a));
31948
+ return HR(l, t);
31949
+ }
31556
31950
  function IF(e10, t) {
31557
31951
  let n = e10.data;
31558
31952
  if (n.isSidechain === true) return null;
@@ -43065,6 +43459,14 @@ async function jWt(e10) {
43065
43459
  if (e10?.sessionStore) return bJe(e10.sessionStore, e10);
43066
43460
  return X0(e10);
43067
43461
  }
43462
+ async function WWt(e10, t) {
43463
+ if (t?.sessionStore) return wJe(t.sessionStore, e10, t.dir);
43464
+ return TF(e10, t);
43465
+ }
43466
+ async function VWt(e10, t, n) {
43467
+ if (n?.sessionStore) return xJe(n.sessionStore, e10, t, n);
43468
+ return wF(e10, t, n);
43469
+ }
43068
43470
  function tJ(e10) {
43069
43471
  return e10.map((t) => ae(t)).join(`
43070
43472
  `) + `
@@ -43129,8 +43531,46 @@ async function RJe(e10, t, n) {
43129
43531
  if (!o || o.length === 0) return [];
43130
43532
  return M0(o, { limit: n.limit, offset: n.offset, includeSystemMessages: n.includeSystemMessages });
43131
43533
  }
43534
+ async function wJe(e10, t, n) {
43535
+ if (!Ve(t)) return [];
43536
+ if (!e10.listSubkeys) throw Error("sessionStore.listSubkeys is not implemented -- cannot list subagents. Provide a store with a listSubkeys() method.");
43537
+ let r = Pn(n), o = await e10.listSubkeys({ projectKey: r, sessionId: t }), s = /* @__PURE__ */ new Set();
43538
+ for (let i of o) {
43539
+ if (!i.startsWith("subagents/")) continue;
43540
+ let a = i.split("/").at(-1);
43541
+ if (a.startsWith("agent-")) s.add(a.slice(6));
43542
+ }
43543
+ return [...s];
43544
+ }
43545
+ async function xJe(e10, t, n, r) {
43546
+ if (!Ve(t)) return [];
43547
+ if (!n) return [];
43548
+ let o = Pn(r.dir), s = `subagents/agent-${n}`;
43549
+ if (e10.listSubkeys) {
43550
+ let p = await e10.listSubkeys({ projectKey: o, sessionId: t }), f = `agent-${n}`, m = p.find((g) => g.startsWith("subagents/") && g.split("/").at(-1) === f);
43551
+ if (!m) return [];
43552
+ s = m;
43553
+ }
43554
+ let i = await e10.load({ projectKey: o, sessionId: t, subpath: s });
43555
+ if (!i || i.length === 0) return [];
43556
+ let a = i.findLast(df), l = typeof a?.toolUseId === "string" ? a.toolUseId : void 0, c = typeof a?.parentAgentId === "string" ? a.parentAgentId : void 0, d = i.filter((p) => !df(p));
43557
+ if (d.length === 0) return [];
43558
+ return YR(Buffer.from(tJ(d)), { limit: r.limit, offset: r.offset }, l, c);
43559
+ }
43132
43560
 
43133
43561
  // src/runs/claude-adapter.ts
43562
+ var SUBAGENT_PAGE_SIZE = 500;
43563
+ var MAX_SUBAGENT_MESSAGES = 1e4;
43564
+ var MAX_SUBAGENT_BYTES = 8 * 1024 * 1024;
43565
+ var MAX_SESSION_SUBAGENT_BYTES = 32 * 1024 * 1024;
43566
+ var MAX_SUBAGENT_CACHE_BYTES = 64 * 1024 * 1024;
43567
+ function claudeMessageSummary(record) {
43568
+ const message2 = asRecord(record.message);
43569
+ const content = Array.isArray(message2.content) ? message2.content : [];
43570
+ return content.map(asRecord).map(
43571
+ (block) => block.type === "tool_use" ? String(block.name ?? "Tool call") : block.type === "tool_result" ? "Tool result" : block.type === "thinking" || block.type === "redacted_thinking" ? "Thinking" : String(block.type ?? "Claude message")
43572
+ ).join(", ") || `Claude ${String(record.type)}`;
43573
+ }
43134
43574
  function findClaudeCodeExecutable(options = {}) {
43135
43575
  return findExecutable("claude", {
43136
43576
  ...options,
@@ -43276,6 +43716,23 @@ var ClaudeAdapter = class {
43276
43716
  };
43277
43717
  catalogPromise;
43278
43718
  hydrationCache = /* @__PURE__ */ new Map();
43719
+ subagentHistoryCache = /* @__PURE__ */ new Map();
43720
+ subagentHistoryCacheBytes = 0;
43721
+ cacheSubagentHistory(key, entry) {
43722
+ const previous = this.subagentHistoryCache.get(key);
43723
+ if (previous) this.subagentHistoryCacheBytes -= previous.bytes;
43724
+ this.subagentHistoryCache.delete(key);
43725
+ if (entry) {
43726
+ this.subagentHistoryCache.set(key, entry);
43727
+ this.subagentHistoryCacheBytes += entry.bytes;
43728
+ }
43729
+ while (this.subagentHistoryCacheBytes > MAX_SUBAGENT_CACHE_BYTES) {
43730
+ const oldest = this.subagentHistoryCache.keys().next().value;
43731
+ if (oldest === void 0) break;
43732
+ this.subagentHistoryCacheBytes -= this.subagentHistoryCache.get(oldest).bytes;
43733
+ this.subagentHistoryCache.delete(oldest);
43734
+ }
43735
+ }
43279
43736
  catalog() {
43280
43737
  this.catalogPromise ??= (async () => {
43281
43738
  const messages = new MessageQueue();
@@ -43337,6 +43794,7 @@ var ClaudeAdapter = class {
43337
43794
  permissionMode: input.run.kind === "PLAN" ? "plan" : "bypassPermissions",
43338
43795
  allowDangerouslySkipPermissions: input.run.kind === "SESSION",
43339
43796
  includePartialMessages: true,
43797
+ forwardSubagentText: true,
43340
43798
  env: { ...claudeEnvironment(), ...executionEnvironment() },
43341
43799
  spawnClaudeCodeProcess: ({ command: command3, args, cwd, env, signal: signal2 }) => spawnExecutionProcess(command3, args, {
43342
43800
  cwd,
@@ -43376,8 +43834,9 @@ var ClaudeAdapter = class {
43376
43834
  try {
43377
43835
  for await (const message2 of activeQuery) {
43378
43836
  const record = asRecord(message2);
43837
+ const childMessage = typeof record.agent_id === "string" || typeof record.parent_tool_use_id === "string";
43379
43838
  const sessionId = typeof record.session_id === "string" ? record.session_id : void 0;
43380
- if (sessionId && sessionId !== nativeId) {
43839
+ if (sessionId && sessionId !== nativeId && !childMessage) {
43381
43840
  nativeId = sessionId;
43382
43841
  const version = record.subtype === "init" && typeof record.claude_code_version === "string" ? record.claude_code_version : void 0;
43383
43842
  const path = await findClaudeSessionFile(
@@ -43394,11 +43853,14 @@ var ClaudeAdapter = class {
43394
43853
  record.message ?? record.result ?? record.summary
43395
43854
  );
43396
43855
  const type = String(record.type ?? "message").toUpperCase();
43397
- if (messageText) {
43856
+ if (messageText || record.type === "assistant" || record.type === "user") {
43398
43857
  await callbacks.onEvent({
43399
43858
  type: type === "ASSISTANT" ? "ASSISTANT" : type,
43400
- summary: messageText.slice(0, 2e3),
43401
- detailMarkdown: messageText,
43859
+ summary: (messageText || claudeMessageSummary(record)).slice(
43860
+ 0,
43861
+ 2e3
43862
+ ),
43863
+ detailMarkdown: messageText || void 0,
43402
43864
  raw: message2
43403
43865
  });
43404
43866
  } else if (record.type === "system" && record.subtype) {
@@ -43408,7 +43870,7 @@ var ClaudeAdapter = class {
43408
43870
  raw: message2
43409
43871
  });
43410
43872
  }
43411
- if (record.type === "result") {
43873
+ if (record.type === "result" && !childMessage) {
43412
43874
  finalOutput = typeof record.result === "string" ? record.result : finalOutput;
43413
43875
  for (const usage2 of claudeModelUsages(record, input.run.model)) {
43414
43876
  await callbacks.onUsage(usage2);
@@ -43459,6 +43921,118 @@ var ClaudeAdapter = class {
43459
43921
  delete(nativeId, cwd) {
43460
43922
  return dJe(nativeId, { dir: cwd });
43461
43923
  }
43924
+ async discoverSubagents(sessionId, folder, history, transcriptPath) {
43925
+ let ids;
43926
+ try {
43927
+ ids = await WWt(sessionId, { dir: folder });
43928
+ } catch {
43929
+ return void 0;
43930
+ }
43931
+ const children = [];
43932
+ let sessionBytes = 0;
43933
+ for (const nativeId of [...new Set(ids)]) {
43934
+ const cacheKey = JSON.stringify([sessionId, folder, nativeId]);
43935
+ let fingerprint;
43936
+ if (transcriptPath && !/[/\\]/.test(nativeId)) {
43937
+ try {
43938
+ const childPath = join7(
43939
+ dirname5(transcriptPath),
43940
+ sessionId,
43941
+ "subagents",
43942
+ `agent-${nativeId}`
43943
+ );
43944
+ const file = await stat3(`${childPath}.jsonl`);
43945
+ const metadata2 = await stat3(`${childPath}.meta.json`).catch(
43946
+ (error) => {
43947
+ if (error.code === "ENOENT")
43948
+ return null;
43949
+ throw error;
43950
+ }
43951
+ );
43952
+ if (file.isFile())
43953
+ fingerprint = `${file.size}:${file.mtimeMs}:${metadata2?.size ?? "missing"}:${metadata2?.mtimeMs ?? "missing"}`;
43954
+ } catch {
43955
+ }
43956
+ }
43957
+ const cached = this.subagentHistoryCache.get(cacheKey);
43958
+ if (cached && cached.fingerprint === fingerprint && sessionBytes + cached.bytes <= MAX_SESSION_SUBAGENT_BYTES) {
43959
+ this.cacheSubagentHistory(cacheKey, cached);
43960
+ children.push({
43961
+ nativeId,
43962
+ messages: cached.messages,
43963
+ transcriptStatus: "AVAILABLE"
43964
+ });
43965
+ sessionBytes += cached.bytes;
43966
+ continue;
43967
+ }
43968
+ this.cacheSubagentHistory(cacheKey);
43969
+ const messages = [];
43970
+ let transcriptStatus = "AVAILABLE";
43971
+ let transcriptError;
43972
+ let offset = 0;
43973
+ let childBytes = 0;
43974
+ try {
43975
+ while (offset < MAX_SUBAGENT_MESSAGES) {
43976
+ if (sessionBytes >= MAX_SESSION_SUBAGENT_BYTES) {
43977
+ transcriptStatus = messages.length ? "PARTIAL" : "UNAVAILABLE";
43978
+ transcriptError = "Session subagent transcript size limit reached.";
43979
+ break;
43980
+ }
43981
+ const limit = Math.min(
43982
+ SUBAGENT_PAGE_SIZE,
43983
+ MAX_SUBAGENT_MESSAGES - offset
43984
+ );
43985
+ const page = await VWt(sessionId, nativeId, {
43986
+ dir: folder,
43987
+ limit,
43988
+ offset
43989
+ });
43990
+ for (const message2 of page) {
43991
+ const bytes = Buffer.byteLength(JSON.stringify(message2));
43992
+ if (childBytes + bytes > MAX_SUBAGENT_BYTES || sessionBytes + bytes > MAX_SESSION_SUBAGENT_BYTES) {
43993
+ transcriptStatus = messages.length ? "PARTIAL" : "UNAVAILABLE";
43994
+ transcriptError = "Subagent transcript size limit reached.";
43995
+ break;
43996
+ }
43997
+ messages.push(message2);
43998
+ childBytes += bytes;
43999
+ sessionBytes += bytes;
44000
+ }
44001
+ if (transcriptError || page.length < limit) break;
44002
+ offset += page.length;
44003
+ if (offset >= MAX_SUBAGENT_MESSAGES) {
44004
+ transcriptStatus = "PARTIAL";
44005
+ transcriptError = "Subagent transcript message limit reached.";
44006
+ }
44007
+ }
44008
+ if (!messages.length && !transcriptError) {
44009
+ transcriptStatus = "UNAVAILABLE";
44010
+ transcriptError = "Subagent transcript was not found.";
44011
+ }
44012
+ } catch (error) {
44013
+ transcriptStatus = messages.length ? "PARTIAL" : "UNAVAILABLE";
44014
+ transcriptError = error instanceof Error ? error.message : "Subagent transcript failed.";
44015
+ }
44016
+ children.push({ nativeId, messages, transcriptStatus, transcriptError });
44017
+ if (transcriptStatus === "AVAILABLE" && fingerprint) {
44018
+ this.cacheSubagentHistory(cacheKey, {
44019
+ fingerprint,
44020
+ messages,
44021
+ bytes: childBytes
44022
+ });
44023
+ }
44024
+ }
44025
+ const metadata = [
44026
+ ...history.events ?? [],
44027
+ ...children.flatMap((child) => child.messages)
44028
+ ];
44029
+ return children.map(
44030
+ (child) => claudeSubagentSnapshot(child.nativeId, child.messages, metadata, {
44031
+ transcriptStatus: child.transcriptStatus,
44032
+ transcriptError: child.transcriptError
44033
+ })
44034
+ );
44035
+ }
43462
44036
  async discover(worktrees) {
43463
44037
  const results = [];
43464
44038
  for (const worktree of worktrees) {
@@ -43505,6 +44079,12 @@ var ClaudeAdapter = class {
43505
44079
  } catch {
43506
44080
  }
43507
44081
  }
44082
+ const subagents = await this.discoverSubagents(
44083
+ session.sessionId,
44084
+ worktree.folder,
44085
+ history,
44086
+ sessionInfo.nativeTranscriptPath
44087
+ );
43508
44088
  results.push({
43509
44089
  nativeId: session.sessionId,
43510
44090
  worktreeId: worktree.id,
@@ -43515,7 +44095,8 @@ var ClaudeAdapter = class {
43515
44095
  createdAt: session.createdAt ? new Date(session.createdAt).toISOString() : void 0,
43516
44096
  updatedAt: new Date(session.lastModified).toISOString(),
43517
44097
  rawMetadata: session,
43518
- sessionInfo
44098
+ sessionInfo,
44099
+ ...subagents === void 0 ? {} : { subagents }
43519
44100
  });
43520
44101
  }
43521
44102
  }
@@ -43528,7 +44109,7 @@ init_promise();
43528
44109
  import { execFile as execFile2 } from "node:child_process";
43529
44110
  import { randomUUID as randomUUID3 } from "node:crypto";
43530
44111
  import { mkdir as mkdir2, rm as rm6 } from "node:fs/promises";
43531
- import { dirname as dirname5, join as join8 } from "node:path";
44112
+ import { dirname as dirname6, join as join9 } from "node:path";
43532
44113
  import { promisify as promisify2 } from "node:util";
43533
44114
 
43534
44115
  // ../../node_modules/@opencode/client/dist/chunks/rpc-runtime-ve4aws36.js
@@ -43661,7 +44242,7 @@ function matchesVersion2(version, options) {
43661
44242
 
43662
44243
  // ../../node_modules/@opencode/client/dist/chunks/rpc-runtime-8ye1ye6f.js
43663
44244
  import { homedir as homedir6 } from "node:os";
43664
- import { join as join7 } from "node:path";
44245
+ import { join as join8 } from "node:path";
43665
44246
  function decide2(service, options) {
43666
44247
  if (!matchesVersion2(service.version, options))
43667
44248
  return { _tag: "replace", pty: service.state === "ready" ? "handoff" : "clear" };
@@ -43677,7 +44258,7 @@ function fail(message2) {
43677
44258
  return { _tag: "fail", error: new Error(message2) };
43678
44259
  }
43679
44260
  function fallback2() {
43680
- return join7(process.env["XDG_STATE_HOME"] ?? join7(homedir6(), ".local", "state"), "opencode", "service.json");
44261
+ return join8(process.env["XDG_STATE_HOME"] ?? join8(homedir6(), ".local", "state"), "opencode", "service.json");
43681
44262
  }
43682
44263
  function same2(left, right) {
43683
44264
  return left.id === right.id && left.version === right.version && left.url === right.url && left.pid === right.pid;
@@ -44013,12 +44594,12 @@ var supportedOpenCodeVersion = (version) => {
44013
44594
  var OpenCodeRuntime = class {
44014
44595
  constructor(isolated = false) {
44015
44596
  this.isolated = isolated;
44016
- this.stateDirectory = join8(
44017
- dirname5(configPath()),
44597
+ this.stateDirectory = join9(
44598
+ dirname6(configPath()),
44018
44599
  "opencode",
44019
44600
  isolated ? `run-${randomUUID3()}` : "agent"
44020
44601
  );
44021
- this.file = join8(this.stateDirectory, "opencode", "service.json");
44602
+ this.file = join9(this.stateDirectory, "opencode", "service.json");
44022
44603
  }
44023
44604
  isolated;
44024
44605
  starting;
@@ -44064,7 +44645,7 @@ var OpenCodeRuntime = class {
44064
44645
  `OpenCode >=2.1.1 <3 is required; found ${stdout.trim()}`
44065
44646
  );
44066
44647
  const version = stdout.trim().replace(/^(?:opencode\s+)?v?/, "");
44067
- await mkdir2(dirname5(this.file), { recursive: true, mode: 448 });
44648
+ await mkdir2(dirname6(this.file), { recursive: true, mode: 448 });
44068
44649
  try {
44069
44650
  const endpoint = await Service.ensure({
44070
44651
  file: this.file,
@@ -44135,7 +44716,7 @@ async function generateBranchName(naming, parentSignal) {
44135
44716
  ),
44136
44717
  12e4
44137
44718
  );
44138
- const directory = await mkdtemp2(join9(tmpdir2(), "aide-branch-"));
44719
+ const directory = await mkdtemp2(join10(tmpdir2(), "aide-branch-"));
44139
44720
  const signal2 = controller.signal;
44140
44721
  const adapter = naming.provider === "CODEX" ? new CodexAdapter() : naming.provider === "CLAUDE" ? new ClaudeAdapter() : null;
44141
44722
  const runtime = naming.provider === "OPENCODE" ? new OpenCodeRuntime(true) : null;
@@ -44256,7 +44837,7 @@ var generateTicketBranch = async (payload, _timeout, signal2) => {
44256
44837
  // src/handlers/commands.ts
44257
44838
  import { chmod as chmod2, mkdtemp as mkdtemp3, realpath, rm as rm8, writeFile as writeFile4 } from "node:fs/promises";
44258
44839
  import { homedir as homedir7, tmpdir as tmpdir3 } from "node:os";
44259
- import { join as join10 } from "node:path";
44840
+ import { join as join11 } from "node:path";
44260
44841
 
44261
44842
  // src/command-processes.ts
44262
44843
  import { createHash as createHash4 } from "node:crypto";
@@ -44403,9 +44984,9 @@ var runCommand = async (rawPayload, _timeoutMs, signal2, _onLog, context) => {
44403
44984
  throw new Error("Command output uploader is unavailable");
44404
44985
  }
44405
44986
  const directory = await mkdtemp3(
44406
- join10(tmpdir3(), commandScriptPrefix(context.agentId))
44987
+ join11(tmpdir3(), commandScriptPrefix(context.agentId))
44407
44988
  );
44408
- const scriptPath = join10(directory, "command.sh");
44989
+ const scriptPath = join11(directory, "command.sh");
44409
44990
  await writeFile4(scriptPath, payload.script, {
44410
44991
  encoding: "utf8",
44411
44992
  mode: 384
@@ -44649,9 +45230,9 @@ async function localBranchReport(folder, timeoutMs, signal2, unavailable) {
44649
45230
  }
44650
45231
 
44651
45232
  // src/handlers/codebases.ts
44652
- import { readdir as readdir2, realpath as realpath3, stat as stat3 } from "node:fs/promises";
45233
+ import { readdir as readdir2, realpath as realpath3, stat as stat4 } from "node:fs/promises";
44653
45234
  import { homedir as homedir8 } from "node:os";
44654
- import { dirname as dirname6, join as join12, resolve as resolve4 } from "node:path";
45235
+ import { dirname as dirname7, join as join13, resolve as resolve4 } from "node:path";
44655
45236
 
44656
45237
  // src/repository-metadata.ts
44657
45238
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
@@ -44721,7 +45302,7 @@ async function withMetadataKey(key, task, signal2) {
44721
45302
  // src/git-sync-snapshot.ts
44722
45303
  import { readFile as readFile5, rename as rename3, rm as rm9, writeFile as writeFile5 } from "node:fs/promises";
44723
45304
  import { randomUUID as randomUUID4 } from "node:crypto";
44724
- import { join as join11 } from "node:path";
45305
+ import { join as join12 } from "node:path";
44725
45306
  async function git(folder, args, timeoutMs, signal2, allowMissing = false) {
44726
45307
  const result = await captureCommand({
44727
45308
  command: "git",
@@ -44851,7 +45432,7 @@ async function fetchPinnedRef(folder, remote, ref, timeoutMs, signal2) {
44851
45432
  signal2
44852
45433
  );
44853
45434
  }
44854
- var leaseFile = (gitDirectory2) => join11(gitDirectory2, "aide-sync-push-lease.json");
45435
+ var leaseFile = (gitDirectory2) => join12(gitDirectory2, "aide-sync-push-lease.json");
44855
45436
  async function saveSyncPushLease(gitDirectory2, lease) {
44856
45437
  const destination = leaseFile(gitDirectory2);
44857
45438
  const temporary = `${destination}.${randomUUID4()}.tmp`;
@@ -44964,7 +45545,7 @@ function baseSnapshot(folder) {
44964
45545
  }
44965
45546
  async function fetchedAt(commonDirectory) {
44966
45547
  try {
44967
- return (await stat3(join12(commonDirectory, "FETCH_HEAD"))).mtime.toISOString();
45548
+ return (await stat4(join13(commonDirectory, "FETCH_HEAD"))).mtime.toISOString();
44968
45549
  } catch {
44969
45550
  return null;
44970
45551
  }
@@ -44975,7 +45556,7 @@ async function inspectCodebaseProcess(selectedFolder, timeoutMs, signal2, expect
44975
45556
  let selected;
44976
45557
  try {
44977
45558
  selected = await realpath3(fallbackFolder);
44978
- if (!(await stat3(selected)).isDirectory())
45559
+ if (!(await stat4(selected)).isDirectory())
44979
45560
  throw new Error("Folder is not a directory");
44980
45561
  } catch (error) {
44981
45562
  return {
@@ -45145,7 +45726,7 @@ var browseCodebaseDirectories = async (payload) => {
45145
45726
  const input = codebaseBrowsePayload(payload);
45146
45727
  const homePath = await realpath3(homedir8());
45147
45728
  const path = await realpath3(input.path ? resolve4(input.path) : homePath);
45148
- if (!(await stat3(path)).isDirectory())
45729
+ if (!(await stat4(path)).isDirectory())
45149
45730
  throw new Error("Path is not a directory");
45150
45731
  const candidates = await readdir2(path, { withFileTypes: true });
45151
45732
  const entries = [];
@@ -45153,13 +45734,13 @@ var browseCodebaseDirectories = async (payload) => {
45153
45734
  if (candidate.isDirectory()) {
45154
45735
  entries.push({
45155
45736
  name: candidate.name,
45156
- path: join12(path, candidate.name),
45737
+ path: join13(path, candidate.name),
45157
45738
  hidden: candidate.name.startsWith(".")
45158
45739
  });
45159
45740
  } else if (candidate.isSymbolicLink()) {
45160
45741
  try {
45161
- const target2 = join12(path, candidate.name);
45162
- if ((await stat3(target2)).isDirectory()) {
45742
+ const target2 = join13(path, candidate.name);
45743
+ if ((await stat4(target2)).isDirectory()) {
45163
45744
  entries.push({
45164
45745
  name: candidate.name,
45165
45746
  path: target2,
@@ -45173,7 +45754,7 @@ var browseCodebaseDirectories = async (payload) => {
45173
45754
  entries.sort((first, second) => first.name.localeCompare(second.name));
45174
45755
  const listing = {
45175
45756
  path,
45176
- parentPath: dirname6(path) === path ? null : dirname6(path),
45757
+ parentPath: dirname7(path) === path ? null : dirname7(path),
45177
45758
  homePath,
45178
45759
  entries: entries.slice(0, 1e3),
45179
45760
  truncated: entries.length > 1e3
@@ -45204,76 +45785,165 @@ var refreshCodebase = async (payload, timeoutMs, signal2) => {
45204
45785
  )
45205
45786
  };
45206
45787
  };
45207
- async function updateBaseBranchAfterFetch(folder, baseBranch, timeoutMs, signal2) {
45208
- const localRef = `refs/heads/${baseBranch}`;
45209
- const remoteRef = `refs/remotes/origin/${baseBranch}`;
45788
+ async function updateBaseBranchAfterFetch(folder, baseBranch, timeoutMs, signal2, expectedOrigin, expectedGitDirectory) {
45210
45789
  try {
45211
- const validRef = await git2(
45212
- folder,
45213
- ["check-ref-format", localRef],
45214
- timeoutMs,
45215
- signal2
45216
- );
45217
- if (validRef.exitCode !== 0) return false;
45218
- const staged = await git2(
45219
- folder,
45220
- ["diff", "--cached", "--quiet"],
45221
- timeoutMs,
45222
- signal2
45223
- );
45224
- if (staged.exitCode !== 0) return false;
45225
- const remoteExists = await git2(
45226
- folder,
45227
- ["show-ref", "--verify", "--quiet", remoteRef],
45228
- timeoutMs,
45229
- signal2
45230
- );
45231
- if (remoteExists.exitCode !== 0) return false;
45232
- const remoteTip = requireSuccess(
45233
- await git2(folder, ["rev-parse", remoteRef], timeoutMs, signal2),
45234
- "Could not pin the fetched base branch"
45235
- ).stdout.trim();
45236
- const currentBranch2 = await git2(
45790
+ return await withRepositoryMetadata(
45237
45791
  folder,
45238
- ["symbolic-ref", "--short", "-q", "HEAD"],
45239
- timeoutMs,
45792
+ async () => {
45793
+ if (expectedGitDirectory) {
45794
+ const directory = await git2(
45795
+ folder,
45796
+ ["rev-parse", "--path-format=absolute", "--git-dir"],
45797
+ timeoutMs,
45798
+ signal2
45799
+ );
45800
+ if (directory.exitCode !== 0 || await realpath3(directory.stdout.trim()) !== expectedGitDirectory)
45801
+ return false;
45802
+ }
45803
+ const current = await git2(
45804
+ folder,
45805
+ ["symbolic-ref", "--short", "-q", "HEAD"],
45806
+ timeoutMs,
45807
+ signal2
45808
+ );
45809
+ if (current.exitCode !== 0 || current.stdout.trim() !== baseBranch)
45810
+ return false;
45811
+ if (expectedOrigin) {
45812
+ const remote = await git2(
45813
+ folder,
45814
+ ["remote", "get-url", "origin"],
45815
+ timeoutMs,
45816
+ signal2
45817
+ );
45818
+ if (remote.exitCode !== 0 || normalizeGitOrigin(remote.stdout.trim()).canonicalOrigin !== expectedOrigin)
45819
+ return false;
45820
+ }
45821
+ const status2 = await git2(
45822
+ folder,
45823
+ [
45824
+ "status",
45825
+ "--porcelain=v1",
45826
+ "-z",
45827
+ "--untracked-files=all",
45828
+ "--ignore-submodules=none"
45829
+ ],
45830
+ timeoutMs,
45831
+ signal2
45832
+ );
45833
+ if (status2.exitCode !== 0 || status2.outputTruncated || status2.stdout)
45834
+ return false;
45835
+ for (const name of [
45836
+ "MERGE_HEAD",
45837
+ "rebase-merge",
45838
+ "rebase-apply",
45839
+ "CHERRY_PICK_HEAD",
45840
+ "REVERT_HEAD"
45841
+ ]) {
45842
+ const path = await git2(
45843
+ folder,
45844
+ ["rev-parse", "--path-format=absolute", "--git-path", name],
45845
+ timeoutMs,
45846
+ signal2
45847
+ );
45848
+ if (path.exitCode !== 0) return false;
45849
+ try {
45850
+ await stat4(path.stdout.trim());
45851
+ return false;
45852
+ } catch (error) {
45853
+ if (error.code !== "ENOENT") throw error;
45854
+ }
45855
+ }
45856
+ const remoteRef = `refs/remotes/origin/${baseBranch}`;
45857
+ const valid = await git2(
45858
+ folder,
45859
+ ["check-ref-format", remoteRef],
45860
+ timeoutMs,
45861
+ signal2
45862
+ );
45863
+ if (valid.exitCode !== 0) return false;
45864
+ const tip = await git2(
45865
+ folder,
45866
+ ["rev-parse", "--verify", remoteRef],
45867
+ timeoutMs,
45868
+ signal2
45869
+ );
45870
+ if (tip.exitCode !== 0) return false;
45871
+ const ancestor = await git2(
45872
+ folder,
45873
+ ["merge-base", "--is-ancestor", "HEAD", tip.stdout.trim()],
45874
+ timeoutMs,
45875
+ signal2
45876
+ );
45877
+ if (ancestor.exitCode !== 0) return false;
45878
+ const branch = await git2(
45879
+ folder,
45880
+ ["symbolic-ref", "--short", "-q", "HEAD"],
45881
+ timeoutMs,
45882
+ signal2
45883
+ );
45884
+ if (branch.exitCode !== 0 || branch.stdout.trim() !== baseBranch)
45885
+ return false;
45886
+ return (await git2(
45887
+ folder,
45888
+ ["merge", "--ff-only", tip.stdout.trim()],
45889
+ timeoutMs,
45890
+ signal2
45891
+ )).exitCode === 0;
45892
+ },
45240
45893
  signal2
45241
45894
  );
45242
- if (currentBranch2.exitCode === 0 && currentBranch2.stdout.trim() === baseBranch) {
45243
- const merged = await git2(
45244
- folder,
45245
- ["merge", "--ff-only", remoteTip],
45246
- timeoutMs,
45247
- signal2
45248
- );
45249
- return merged.exitCode === 0;
45250
- }
45251
- const localExists = await git2(
45895
+ } catch (error) {
45896
+ if (signal2.aborted) throw error;
45897
+ return false;
45898
+ }
45899
+ }
45900
+ async function updateDefaultBranchesAfterFetch(folder, defaultBranch, patterns, timeoutMs, signal2, withCheckout, expectedOrigin) {
45901
+ const listed = requireSuccess(
45902
+ await git2(
45252
45903
  folder,
45253
- ["show-ref", "--verify", "--quiet", localRef],
45904
+ ["worktree", "list", "--porcelain", "-z"],
45254
45905
  timeoutMs,
45255
45906
  signal2
45256
- );
45257
- if (localExists.exitCode === 0) {
45258
- const fastForward = await git2(
45259
- folder,
45260
- ["merge-base", "--is-ancestor", localRef, remoteTip],
45261
- timeoutMs,
45262
- signal2
45907
+ ),
45908
+ "Could not list worktrees"
45909
+ );
45910
+ if (listed.outputTruncated) return;
45911
+ for (const block of listed.stdout.split("\0\0")) {
45912
+ signal2.throwIfAborted();
45913
+ const fields = block.split("\0");
45914
+ if (fields.some((field) => field.startsWith("prunable")) || fields.includes("bare"))
45915
+ continue;
45916
+ const checkout = fields.find((field) => field.startsWith("worktree "))?.slice(9);
45917
+ const branch = fields.find((field) => field.startsWith("branch refs/heads/"))?.slice(18);
45918
+ if (!checkout || !isDefaultBranch(branch, defaultBranch, patterns))
45919
+ continue;
45920
+ try {
45921
+ const path = await realpath3(checkout);
45922
+ const directory = requireSuccess(
45923
+ await git2(
45924
+ path,
45925
+ ["rev-parse", "--path-format=absolute", "--git-dir"],
45926
+ timeoutMs,
45927
+ signal2
45928
+ ),
45929
+ "Could not resolve worktree"
45930
+ ).stdout.trim();
45931
+ const expectedGitDirectory = await realpath3(directory);
45932
+ await withCheckout(
45933
+ path,
45934
+ expectedGitDirectory,
45935
+ () => updateBaseBranchAfterFetch(
45936
+ path,
45937
+ branch,
45938
+ timeoutMs,
45939
+ signal2,
45940
+ expectedOrigin,
45941
+ expectedGitDirectory
45942
+ )
45263
45943
  );
45264
- if (fastForward.exitCode !== 0) return false;
45265
- } else if (localExists.exitCode !== 1) {
45266
- return false;
45944
+ } catch (error) {
45945
+ if (signal2.aborted) throw error;
45267
45946
  }
45268
- const updated = await git2(
45269
- folder,
45270
- ["branch", "--force", baseBranch, remoteTip],
45271
- timeoutMs,
45272
- signal2
45273
- );
45274
- return updated.exitCode === 0;
45275
- } catch {
45276
- return false;
45277
45947
  }
45278
45948
  }
45279
45949
  var fetchCodebase = async (payload, timeoutMs, signal2, onLog, context) => {
@@ -45312,46 +45982,37 @@ var fetchCodebase = async (payload, timeoutMs, signal2, onLog, context) => {
45312
45982
  if (error instanceof InterruptedGitInspection) return error.result;
45313
45983
  throw error;
45314
45984
  }
45315
- if (result.exitCode === 0 && input.keepBaseBranchUpToDate && input.baseBranch) {
45316
- await log2("Updating the base branch where it can be fast-forwarded");
45317
- const update = () => updateBaseBranchAfterFetch(
45985
+ if (result.exitCode === 0 && input.keepBaseBranchUpToDate) {
45986
+ await log2(
45987
+ "Updating clean default branch worktrees from their matching origin branches"
45988
+ );
45989
+ await updateDefaultBranchesAfterFetch(
45318
45990
  input.folder,
45319
- input.baseBranch,
45991
+ input.baseBranch ?? null,
45992
+ input.defaultBranchPatterns ?? [],
45320
45993
  timeoutMs,
45321
- signal2
45322
- );
45323
- const gitDirectory2 = requireSuccess(
45324
- await git2(
45325
- input.folder,
45326
- ["rev-parse", "--path-format=absolute", "--git-dir"],
45327
- timeoutMs,
45328
- signal2
45329
- ),
45330
- "Could not resolve base worktree"
45331
- ).stdout.trim();
45332
- const grant = context?.tryWithOperationResources ? await context.tryWithOperationResources(
45333
- [
45334
- {
45335
- kind: "WORKTREE",
45336
- key: `${context.agentId}:worktree:${await realpath3(gitDirectory2)}`,
45337
- agentId: context.agentId,
45338
- codebaseId: input.codebaseId,
45339
- mode: "WRITE"
45340
- },
45341
- {
45342
- kind: "PATH",
45343
- key: input.folder,
45344
- path: input.folder,
45345
- agentId: context.agentId,
45346
- codebaseId: input.codebaseId,
45347
- mode: "WRITE"
45348
- }
45349
- ],
45350
- update
45351
- ) : { ran: true, result: await update() };
45352
- const updated = grant.ran && grant.result;
45353
- await log2(
45354
- updated ? "Base branch updated" : "Base branch left unchanged because it could not be safely fast-forwarded"
45994
+ signal2,
45995
+ (folder, gitDirectory2, update) => context?.tryWithOperationResources ? context.tryWithOperationResources(
45996
+ [
45997
+ {
45998
+ kind: "WORKTREE",
45999
+ key: `${context.agentId}:worktree:${gitDirectory2}`,
46000
+ agentId: context.agentId,
46001
+ codebaseId: input.codebaseId,
46002
+ mode: "WRITE"
46003
+ },
46004
+ {
46005
+ kind: "PATH",
46006
+ key: folder,
46007
+ path: folder,
46008
+ agentId: context.agentId,
46009
+ codebaseId: input.codebaseId,
46010
+ mode: "WRITE"
46011
+ }
46012
+ ],
46013
+ update
46014
+ ) : update(),
46015
+ input.expectedOrigin
45355
46016
  );
45356
46017
  }
45357
46018
  const afterResult = await inspectCodebaseProcess(
@@ -45986,9 +46647,9 @@ import {
45986
46647
  rmdir
45987
46648
  } from "node:fs/promises";
45988
46649
  import {
45989
- dirname as dirname8,
46650
+ dirname as dirname9,
45990
46651
  isAbsolute as isAbsolute4,
45991
- join as join14,
46652
+ join as join15,
45992
46653
  parse as parse3,
45993
46654
  relative as relative2,
45994
46655
  resolve as resolve6,
@@ -45998,7 +46659,7 @@ import {
45998
46659
  // src/repository-coordinator.ts
45999
46660
  import { AsyncLocalStorage as AsyncLocalStorage3 } from "node:async_hooks";
46000
46661
  import { lstat, readlink, realpath as realpath4 } from "node:fs/promises";
46001
- import { basename as basename2, dirname as dirname7, join as join13, resolve as resolve5 } from "node:path";
46662
+ import { basename as basename2, dirname as dirname8, join as join14, resolve as resolve5 } from "node:path";
46002
46663
  async function canonicalResourcePath(path) {
46003
46664
  const absolute = resolve5(path);
46004
46665
  try {
@@ -46008,15 +46669,15 @@ async function canonicalResourcePath(path) {
46008
46669
  try {
46009
46670
  if ((await lstat(absolute)).isSymbolicLink())
46010
46671
  return canonicalResourcePath(
46011
- resolve5(dirname7(absolute), await readlink(absolute))
46672
+ resolve5(dirname8(absolute), await readlink(absolute))
46012
46673
  );
46013
46674
  } catch (linkError) {
46014
46675
  if (linkError.code !== "ENOENT")
46015
46676
  throw linkError;
46016
46677
  }
46017
- const parent = dirname7(absolute);
46678
+ const parent = dirname8(absolute);
46018
46679
  if (parent === absolute) throw error;
46019
- return join13(await canonicalResourcePath(parent), basename2(absolute));
46680
+ return join14(await canonicalResourcePath(parent), basename2(absolute));
46020
46681
  }
46021
46682
  }
46022
46683
  var RepositoryCoordinator = class {
@@ -46342,7 +47003,7 @@ async function safeDirectory(path, create) {
46342
47003
  const absolute = resolve6(path);
46343
47004
  let current = parse3(absolute).root;
46344
47005
  for (const component of absolute.slice(current.length).split(sep3).filter(Boolean)) {
46345
- current = join14(current, component);
47006
+ current = join15(current, component);
46346
47007
  let info;
46347
47008
  try {
46348
47009
  info = await lstat2(current);
@@ -46377,7 +47038,7 @@ var inspectCloneDestination = async (value, timeoutMs, signal2) => {
46377
47038
  throw new Error("Clone base directory must be absolute on this agent");
46378
47039
  const destination = resolve6(payload.baseDirectory, payload.relativePath);
46379
47040
  try {
46380
- await safeDirectory(dirname8(destination), false);
47041
+ await safeDirectory(dirname9(destination), false);
46381
47042
  const info = await lstat2(destination);
46382
47043
  if (info.isSymbolicLink() || !info.isDirectory())
46383
47044
  throw new Error(
@@ -46431,7 +47092,7 @@ var cloneCodebase = async (value, timeoutMs, signal2) => {
46431
47092
  const deadline = Date.now() + timeoutMs;
46432
47093
  const remaining = () => Math.max(0, deadline - Date.now());
46433
47094
  await safeDirectory(payload.baseDirectory, true);
46434
- const parent = await safeDirectory(dirname8(destination), true);
47095
+ const parent = await safeDirectory(dirname9(destination), true);
46435
47096
  const parentIdentity = await lstat2(parent);
46436
47097
  const existing = await lstat2(destination).catch((error) => {
46437
47098
  if (missing(error)) return null;
@@ -46456,9 +47117,9 @@ var cloneCodebase = async (value, timeoutMs, signal2) => {
46456
47117
  }
46457
47118
  return { ...success, snapshot, reused: true };
46458
47119
  }
46459
- const staging = await mkdtemp4(join14(parent, ".aide-clone-"));
47120
+ const staging = await mkdtemp4(join15(parent, ".aide-clone-"));
46460
47121
  const stagingIdentity = await lstat2(staging);
46461
- const checkout = join14(staging, "checkout");
47122
+ const checkout = join15(staging, "checkout");
46462
47123
  const verifyStaging = async () => {
46463
47124
  if (!await ownsDirectory(parent, parentIdentity, staging, stagingIdentity)) {
46464
47125
  throw new Error(
@@ -46538,8 +47199,8 @@ var cloneCodebase = async (value, timeoutMs, signal2) => {
46538
47199
  };
46539
47200
 
46540
47201
  // src/handlers/coverage.ts
46541
- import { readFile as readFile7, realpath as realpath7, stat as stat5 } from "node:fs/promises";
46542
- import { join as join16, relative as relative5, sep as sep6 } from "node:path";
47202
+ import { readFile as readFile7, realpath as realpath7, stat as stat6 } from "node:fs/promises";
47203
+ import { join as join17, relative as relative5, sep as sep6 } from "node:path";
46543
47204
 
46544
47205
  // src/handlers/builds.ts
46545
47206
  import { createHash as createHash6, randomUUID as randomUUID5 } from "node:crypto";
@@ -46553,7 +47214,7 @@ import {
46553
47214
  realpath as realpath6,
46554
47215
  rename as rename5,
46555
47216
  rm as rm11,
46556
- stat as stat4,
47217
+ stat as stat5,
46557
47218
  writeFile as writeFile6
46558
47219
  } from "node:fs/promises";
46559
47220
  import { createReadStream as createReadStream5, createWriteStream as createWriteStream2 } from "node:fs";
@@ -46562,9 +47223,9 @@ import { pipeline } from "node:stream/promises";
46562
47223
  import { StringDecoder } from "node:string_decoder";
46563
47224
  import {
46564
47225
  basename as basename3,
46565
- dirname as dirname9,
47226
+ dirname as dirname10,
46566
47227
  isAbsolute as isAbsolute6,
46567
- join as join15,
47228
+ join as join16,
46568
47229
  relative as relative4,
46569
47230
  resolve as resolve8,
46570
47231
  sep as sep5
@@ -46965,7 +47626,7 @@ function requireSuccess2(result, fallback) {
46965
47626
  }
46966
47627
  async function validateWorktree(input, timeoutMs, signal2) {
46967
47628
  const folder = await realpath6(input.folder);
46968
- if (!(await stat4(folder)).isDirectory())
47629
+ if (!(await stat5(folder)).isDirectory())
46969
47630
  throw new Error("Worktree is missing");
46970
47631
  const gitDirectory2 = requireSuccess2(
46971
47632
  await command(
@@ -47012,7 +47673,7 @@ async function validateSource(root, source) {
47012
47673
  if (difference === ".." || difference.startsWith(`..${sep5}`) || isAbsolute6(difference)) {
47013
47674
  throw new Error("Build source resolves outside the worktree");
47014
47675
  }
47015
- const information = await stat4(resolved);
47676
+ const information = await stat5(resolved);
47016
47677
  if (source.kind === "PACKAGE" && !information.isFile()) {
47017
47678
  throw new Error("Package.swift is missing");
47018
47679
  }
@@ -47028,7 +47689,7 @@ async function discoverSourcesInFolder(folder) {
47028
47689
  const current = queue.shift();
47029
47690
  for (const entry of await readdir3(current, { withFileTypes: true })) {
47030
47691
  if (entry.isSymbolicLink()) continue;
47031
- const absolute = join15(current, entry.name);
47692
+ const absolute = join16(current, entry.name);
47032
47693
  const path = relative4(folder, absolute).split(sep5).join("/");
47033
47694
  if (entry.isDirectory()) {
47034
47695
  if (entry.name.endsWith(".xcodeproj")) {
@@ -47099,7 +47760,7 @@ function metadataFromList(value) {
47099
47760
  };
47100
47761
  }
47101
47762
  async function workspaceProjectPaths(workspacePath2, folder) {
47102
- const contentsPath = join15(workspacePath2, "contents.xcworkspacedata");
47763
+ const contentsPath = join16(workspacePath2, "contents.xcworkspacedata");
47103
47764
  let contents;
47104
47765
  try {
47105
47766
  contents = await readFile6(contentsPath, "utf8");
@@ -47120,7 +47781,7 @@ async function workspaceProjectPaths(workspacePath2, folder) {
47120
47781
  }).filter((path) => path.endsWith(".xcodeproj"));
47121
47782
  const projects = [];
47122
47783
  for (const location of locations) {
47123
- const candidate = resolve8(dirname9(workspacePath2), location);
47784
+ const candidate = resolve8(dirname10(workspacePath2), location);
47124
47785
  const difference = relative4(folder, candidate);
47125
47786
  if (difference === ".." || difference.startsWith(`..${sep5}`) || isAbsolute6(difference)) {
47126
47787
  continue;
@@ -47128,7 +47789,7 @@ async function workspaceProjectPaths(workspacePath2, folder) {
47128
47789
  try {
47129
47790
  const resolved = await realpath6(candidate);
47130
47791
  const resolvedDifference = relative4(folder, resolved);
47131
- if (resolvedDifference === ".." || resolvedDifference.startsWith(`..${sep5}`) || isAbsolute6(resolvedDifference) || !(await stat4(resolved)).isDirectory()) {
47792
+ if (resolvedDifference === ".." || resolvedDifference.startsWith(`..${sep5}`) || isAbsolute6(resolvedDifference) || !(await stat5(resolved)).isDirectory()) {
47132
47793
  continue;
47133
47794
  }
47134
47795
  projects.push(resolved);
@@ -47319,7 +47980,7 @@ async function dependentSigningRequirements(source, absolutePath, folder, rootTa
47319
47980
  for (const project of projects.slice(0, 50)) {
47320
47981
  const converted = await command(
47321
47982
  "plutil",
47322
- ["-convert", "json", "-o", "-", join15(project, "project.pbxproj")],
47983
+ ["-convert", "json", "-o", "-", join16(project, "project.pbxproj")],
47323
47984
  Math.min(timeoutMs, 15e3),
47324
47985
  signal2,
47325
47986
  folder
@@ -47580,8 +48241,8 @@ function physicalDestinations(value, includeUnavailable = false) {
47580
48241
  });
47581
48242
  }
47582
48243
  async function listPhysicalDevices(timeoutMs, signal2, includeUnavailable = false) {
47583
- const directory = await mkdtemp5(join15(tmpdir4(), "ade-devices-"));
47584
- const output = join15(directory, "devices.json");
48244
+ const directory = await mkdtemp5(join16(tmpdir4(), "ade-devices-"));
48245
+ const output = join16(directory, "devices.json");
47585
48246
  try {
47586
48247
  const result = await command(
47587
48248
  "xcrun",
@@ -48033,7 +48694,7 @@ function actionArgument(action) {
48033
48694
  }[action];
48034
48695
  }
48035
48696
  function xcodeBuildArguments(input) {
48036
- const resultBundle = join15(input.artifactDirectory, "result.xcresult");
48697
+ const resultBundle = join16(input.artifactDirectory, "result.xcresult");
48037
48698
  const sourcePath = containedPath2(input.folder, input.source.relativePath);
48038
48699
  const usesCapturedTestProducts = input.action === "TEST_WITHOUT_BUILDING";
48039
48700
  const args = [
@@ -48056,13 +48717,13 @@ function xcodeBuildArguments(input) {
48056
48717
  if (input.action === "ARCHIVE") {
48057
48718
  args.push(
48058
48719
  "-archivePath",
48059
- join15(input.artifactDirectory, "archive.xcarchive")
48720
+ join16(input.artifactDirectory, "archive.xcarchive")
48060
48721
  );
48061
48722
  }
48062
48723
  if (input.action === "BUILD_FOR_TESTING") {
48063
48724
  args.push(
48064
48725
  "-testProductsPath",
48065
- join15(input.artifactDirectory, "test-products.xctestproducts")
48726
+ join16(input.artifactDirectory, "test-products.xctestproducts")
48066
48727
  );
48067
48728
  }
48068
48729
  if (input.action === "TEST_WITHOUT_BUILDING" && input.advancedSettings.priorTestProductsPath) {
@@ -48126,15 +48787,15 @@ function classifyFailure(output) {
48126
48787
  }
48127
48788
  async function runHook(options) {
48128
48789
  const phaseDirectory = options.phase === "PRE_BUILD" ? "pre" : "post";
48129
- const directory = join15(
48790
+ const directory = join16(
48130
48791
  options.input.artifactDirectory,
48131
48792
  "hooks",
48132
48793
  phaseDirectory
48133
48794
  );
48134
48795
  const prefix = `${String(options.script.position).padStart(3, "0")}-${options.script.id}`;
48135
- const file = join15(directory, `${prefix}.mjs`);
48136
- const runner = join15(directory, `${prefix}.runner.mjs`);
48137
- const log2 = join15(directory, `${prefix}.log`);
48796
+ const file = join16(directory, `${prefix}.mjs`);
48797
+ const runner = join16(directory, `${prefix}.runner.mjs`);
48798
+ const log2 = join16(directory, `${prefix}.log`);
48138
48799
  const started = Date.now();
48139
48800
  try {
48140
48801
  await mkdir4(directory, { recursive: true, mode: 448 });
@@ -48229,26 +48890,26 @@ if (typeof hookModule.default === "function") {
48229
48890
  }
48230
48891
  async function pathExists(path) {
48231
48892
  try {
48232
- await stat4(path);
48893
+ await stat5(path);
48233
48894
  return true;
48234
48895
  } catch {
48235
48896
  return false;
48236
48897
  }
48237
48898
  }
48238
48899
  async function pathSize(path) {
48239
- const information = await stat4(path);
48900
+ const information = await stat5(path);
48240
48901
  if (information.isFile()) return information.size;
48241
48902
  if (!information.isDirectory()) return 0;
48242
48903
  let size = 0;
48243
48904
  for (const entry of await readdir3(path, { withFileTypes: true })) {
48244
48905
  if (entry.isSymbolicLink()) continue;
48245
- size += await pathSize(join15(path, entry.name));
48906
+ size += await pathSize(join16(path, entry.name));
48246
48907
  }
48247
48908
  return size;
48248
48909
  }
48249
48910
  async function fileChecksum(path) {
48250
48911
  try {
48251
- const information = await stat4(path);
48912
+ const information = await stat5(path);
48252
48913
  if (!information.isFile()) return null;
48253
48914
  const hash = createHash6("sha256");
48254
48915
  await pipeline(createReadStream5(path), hash);
@@ -48272,7 +48933,7 @@ async function plistString(plistPath, keyPath, timeoutMs, signal2) {
48272
48933
  }
48273
48934
  }
48274
48935
  async function archiveApplicationProperties(archivePath, timeoutMs, signal2) {
48275
- const plistPath = join15(archivePath, "Info.plist");
48936
+ const plistPath = join16(archivePath, "Info.plist");
48276
48937
  const read3 = (key) => plistString(plistPath, `ApplicationProperties.${key}`, timeoutMs, signal2);
48277
48938
  const [bundleIdentifier2, bundleShortVersion, bundleVersion, applicationPath] = await Promise.all([
48278
48939
  read3("CFBundleIdentifier"),
@@ -48431,9 +49092,9 @@ function normalizeCoverage(value) {
48431
49092
  };
48432
49093
  }
48433
49094
  async function writeJsonReport(input, kind, timeoutMs, signal2) {
48434
- const resultBundle = join15(input.artifactDirectory, "result.xcresult");
49095
+ const resultBundle = join16(input.artifactDirectory, "result.xcresult");
48435
49096
  const filename = kind === "TEST_RESULTS" ? "test-results.json" : "code-coverage.json";
48436
- const destination = join15(input.artifactDirectory, filename);
49097
+ const destination = join16(input.artifactDirectory, filename);
48437
49098
  const temporary = `${destination}.tmp-${randomUUID5()}`;
48438
49099
  try {
48439
49100
  if (!await pathExists(resultBundle)) {
@@ -48575,7 +49236,7 @@ async function snapshotCoverageChangesLocked(baseBranch, folder, timeoutMs, sign
48575
49236
  const types = changeTypesFromStatus(status2.stdout);
48576
49237
  for (const path of untracked.stdout.split("\0").filter(Boolean)) {
48577
49238
  try {
48578
- const contents = await readFile6(join15(folder, path));
49239
+ const contents = await readFile6(join16(folder, path));
48579
49240
  if (contents.includes(0)) continue;
48580
49241
  const lineCount = contents.length ? contents.toString("utf8").split("\n").length - (contents.toString("utf8").endsWith("\n") ? 1 : 0) : 0;
48581
49242
  lines.set(
@@ -48638,7 +49299,7 @@ async function addChangedCoverage(report, changes, input, folder, timeoutMs, sig
48638
49299
  );
48639
49300
  let lines = EMPTY_COVERAGE_LINES;
48640
49301
  if (coveragePath && change.lines.length) {
48641
- const temporary2 = join15(
49302
+ const temporary2 = join16(
48642
49303
  input.artifactDirectory,
48643
49304
  `.changed-coverage-${randomUUID5()}.json`
48644
49305
  );
@@ -48689,7 +49350,7 @@ async function addChangedCoverage(report, changes, input, folder, timeoutMs, sig
48689
49350
  changedLineCoverage: changedExecutableLines ? changedCoveredLines / changedExecutableLines : null
48690
49351
  };
48691
49352
  const data = { ...report.data, changedFiles };
48692
- const destination = join15(input.artifactDirectory, "worktree-coverage.json");
49353
+ const destination = join16(input.artifactDirectory, "worktree-coverage.json");
48693
49354
  const temporary = `${destination}.tmp-${randomUUID5()}`;
48694
49355
  await writeFile6(temporary, JSON.stringify({ summary, data }, null, 2), {
48695
49356
  mode: 384
@@ -48743,7 +49404,7 @@ async function findFiles(root, predicate, limit = 20) {
48743
49404
  }
48744
49405
  for (const entry of entries) {
48745
49406
  if (entry.isSymbolicLink()) continue;
48746
- const path = join15(current, entry.name);
49407
+ const path = join16(current, entry.name);
48747
49408
  if (entry.isDirectory()) queue.push(path);
48748
49409
  else if (entry.isFile() && predicate(entry.name)) results.push(path);
48749
49410
  if (results.length >= limit) break;
@@ -48781,18 +49442,18 @@ async function dwarfdumpUuids(paths, signal2) {
48781
49442
  }
48782
49443
  async function captureDsyms(input, entries, signal2) {
48783
49444
  const sources = [];
48784
- const archiveDsyms = join15(
49445
+ const archiveDsyms = join16(
48785
49446
  input.artifactDirectory,
48786
49447
  "archive.xcarchive",
48787
49448
  "dSYMs"
48788
49449
  );
48789
49450
  if (input.action === "ARCHIVE" && await pathExists(archiveDsyms)) {
48790
49451
  for (const name of await readdir3(archiveDsyms)) {
48791
- if (name.endsWith(".dSYM")) sources.push(join15(archiveDsyms, name));
49452
+ if (name.endsWith(".dSYM")) sources.push(join16(archiveDsyms, name));
48792
49453
  }
48793
49454
  } else {
48794
49455
  const binaries = entries.map(
48795
- ({ buildSettings: settings }) => settings.TARGET_BUILD_DIR && settings.EXECUTABLE_PATH ? join15(settings.TARGET_BUILD_DIR, settings.EXECUTABLE_PATH) : null
49456
+ ({ buildSettings: settings }) => settings.TARGET_BUILD_DIR && settings.EXECUTABLE_PATH ? join16(settings.TARGET_BUILD_DIR, settings.EXECUTABLE_PATH) : null
48796
49457
  ).filter((path) => Boolean(path));
48797
49458
  const existing = [];
48798
49459
  for (const binary of new Set(binaries)) {
@@ -48808,21 +49469,21 @@ async function captureDsyms(input, entries, signal2) {
48808
49469
  if (!await pathExists(folder)) continue;
48809
49470
  for (const name of await readdir3(folder)) {
48810
49471
  if (!name.endsWith(".dSYM")) continue;
48811
- const bundle = join15(folder, name);
49472
+ const bundle = join16(folder, name);
48812
49473
  const uuids = await dwarfdumpUuids([bundle], signal2);
48813
49474
  if (uuids.some((entry) => built.has(entry.uuid))) sources.push(bundle);
48814
49475
  }
48815
49476
  }
48816
49477
  }
48817
49478
  if (!sources.length) return null;
48818
- const staging = join15(input.artifactDirectory, "dSYMs");
48819
- const zipPath = join15(input.artifactDirectory, DSYMS_ARTIFACT_FILENAME);
49479
+ const staging = join16(input.artifactDirectory, "dSYMs");
49480
+ const zipPath = join16(input.artifactDirectory, DSYMS_ARTIFACT_FILENAME);
48820
49481
  await rm11(staging, { recursive: true, force: true });
48821
49482
  await rm11(zipPath, { force: true });
48822
49483
  await mkdir4(staging, { recursive: true, mode: 448 });
48823
49484
  try {
48824
49485
  for (const source of sources) {
48825
- await cp(source, join15(staging, basename3(source)), {
49486
+ await cp(source, join16(staging, basename3(source)), {
48826
49487
  recursive: true,
48827
49488
  preserveTimestamps: true
48828
49489
  });
@@ -48839,7 +49500,7 @@ async function captureDsyms(input, entries, signal2) {
48839
49500
  );
48840
49501
  }
48841
49502
  const uuids = await dwarfdumpUuids(
48842
- sources.map((source) => join15(staging, basename3(source))),
49503
+ sources.map((source) => join16(staging, basename3(source))),
48843
49504
  signal2
48844
49505
  );
48845
49506
  return await artifact(
@@ -48857,7 +49518,7 @@ async function captureDsyms(input, entries, signal2) {
48857
49518
  }
48858
49519
  async function captureArtifacts(input, folder, signal2, includeProducts = true) {
48859
49520
  const artifacts = [];
48860
- const resultBundle = join15(input.artifactDirectory, "result.xcresult");
49521
+ const resultBundle = join16(input.artifactDirectory, "result.xcresult");
48861
49522
  if (await pathExists(resultBundle)) {
48862
49523
  const coverageProbe = await command(
48863
49524
  "xcrun",
@@ -48884,7 +49545,7 @@ async function captureArtifacts(input, folder, signal2, includeProducts = true)
48884
49545
  );
48885
49546
  }
48886
49547
  if (!includeProducts) return artifacts;
48887
- const archivePath = join15(input.artifactDirectory, "archive.xcarchive");
49548
+ const archivePath = join16(input.artifactDirectory, "archive.xcarchive");
48888
49549
  if (await pathExists(archivePath)) {
48889
49550
  artifacts.push(
48890
49551
  await artifact(input.artifactDirectory, "ARCHIVE", archivePath)
@@ -48921,10 +49582,10 @@ async function captureArtifacts(input, folder, signal2, includeProducts = true)
48921
49582
  if (apps.length === 1) {
48922
49583
  const settings = apps[0].buildSettings;
48923
49584
  const productName = settings.FULL_PRODUCT_NAME ?? settings.WRAPPER_NAME;
48924
- const source = settings.TARGET_BUILD_DIR && productName ? join15(settings.TARGET_BUILD_DIR, productName) : null;
49585
+ const source = settings.TARGET_BUILD_DIR && productName ? join16(settings.TARGET_BUILD_DIR, productName) : null;
48925
49586
  if (source && await pathExists(source)) {
48926
- const productDirectory = join15(input.artifactDirectory, "products");
48927
- const destination = join15(productDirectory, basename3(source));
49587
+ const productDirectory = join16(input.artifactDirectory, "products");
49588
+ const destination = join16(productDirectory, basename3(source));
48928
49589
  await mkdir4(productDirectory, { recursive: true, mode: 448 });
48929
49590
  await rm11(destination, { recursive: true, force: true });
48930
49591
  await cp(source, destination, {
@@ -48944,7 +49605,7 @@ async function captureArtifacts(input, folder, signal2, includeProducts = true)
48944
49605
  }
48945
49606
  }
48946
49607
  if (input.action === "BUILD_FOR_TESTING") {
48947
- const testDirectory = join15(
49608
+ const testDirectory = join16(
48948
49609
  input.artifactDirectory,
48949
49610
  "test-products.xctestproducts"
48950
49611
  );
@@ -48971,8 +49632,8 @@ var runIosBuild = async (payload, timeoutMs, signal2, onLog, context) => {
48971
49632
  const input = parseBuildJobPayload(payload);
48972
49633
  if (!input.worktreeId || /[\\/\0]/.test(input.worktreeId) || input.worktreeId === "." || input.worktreeId === "..")
48973
49634
  throw new Error("Invalid build worktree identifier");
48974
- const derivedDataPath = input.derivedDataPath ?? join15(
48975
- dirname9(input.artifactDirectory),
49635
+ const derivedDataPath = input.derivedDataPath ?? join16(
49636
+ dirname10(input.artifactDirectory),
48976
49637
  ".worktree-derived-data",
48977
49638
  input.worktreeId
48978
49639
  );
@@ -49068,7 +49729,7 @@ var runIosBuildWithPaths = async (payload, timeoutMs, signal2, onLog, context) =
49068
49729
  if (input.derivedDataPath) {
49069
49730
  await mkdir4(input.derivedDataPath, { recursive: true, mode: 448 });
49070
49731
  await writeFile6(
49071
- join15(input.derivedDataPath, ".aide-worktree.json"),
49732
+ join16(input.derivedDataPath, ".aide-worktree.json"),
49072
49733
  `${JSON.stringify({ version: 1, worktreeId: input.worktreeId, folder })}
49073
49734
  `,
49074
49735
  { mode: 384 }
@@ -49078,10 +49739,10 @@ var runIosBuildWithPaths = async (payload, timeoutMs, signal2, onLog, context) =
49078
49739
  const testProductsPath = input.advancedSettings.priorTestProductsPath;
49079
49740
  const xctestrunPath = input.advancedSettings.priorXctestrunPath;
49080
49741
  if (testProductsPath) {
49081
- if (!testProductsPath.endsWith(".xctestproducts") || !await pathExists(testProductsPath) || !(await stat4(testProductsPath)).isDirectory()) {
49742
+ if (!testProductsPath.endsWith(".xctestproducts") || !await pathExists(testProductsPath) || !(await stat5(testProductsPath)).isDirectory()) {
49082
49743
  throw new Error("The captured test-products artifact is unavailable");
49083
49744
  }
49084
- } else if (!xctestrunPath?.endsWith(".xctestrun") || !await pathExists(xctestrunPath) || !(await stat4(xctestrunPath)).isFile()) {
49745
+ } else if (!xctestrunPath?.endsWith(".xctestrun") || !await pathExists(xctestrunPath) || !(await stat5(xctestrunPath)).isFile()) {
49085
49746
  throw new Error("The captured .xctestrun artifact is unavailable");
49086
49747
  }
49087
49748
  }
@@ -49094,11 +49755,11 @@ var runIosBuildWithPaths = async (payload, timeoutMs, signal2, onLog, context) =
49094
49755
  signal2
49095
49756
  );
49096
49757
  await mkdir4(input.artifactDirectory, { recursive: true, mode: 448 });
49097
- const rawLog = join15(input.artifactDirectory, "build.log");
49758
+ const rawLog = join16(input.artifactDirectory, "build.log");
49098
49759
  const logger = new BuildLogger(input.buildId, context, rawLog, process.env);
49099
49760
  try {
49100
49761
  const scriptExecutions = [];
49101
- const contextPath = join15(input.artifactDirectory, "context.json");
49762
+ const contextPath = join16(input.artifactDirectory, "context.json");
49102
49763
  const baseHookContext = {
49103
49764
  buildId: input.buildId,
49104
49765
  branch: input.branch ?? null,
@@ -49123,15 +49784,40 @@ var runIosBuildWithPaths = async (payload, timeoutMs, signal2, onLog, context) =
49123
49784
  let errorCode = null;
49124
49785
  let error = null;
49125
49786
  let failBuild = false;
49126
- try {
49127
- await context?.reportBuildProgress?.({
49128
- buildId: input.buildId,
49129
- status: "PREPARING",
49130
- startedAt: (/* @__PURE__ */ new Date()).toISOString()
49787
+ let progressStatus = "PREPARING";
49788
+ const reportProgress = async (progress) => {
49789
+ try {
49790
+ await context?.reportBuildProgress?.({
49791
+ ...progress,
49792
+ buildId: input.buildId
49793
+ });
49794
+ } catch (progressError) {
49795
+ logger.emit(progress.status, "SYSTEM", cleanError2(progressError));
49796
+ }
49797
+ };
49798
+ const runReportedHook = async (options) => {
49799
+ await reportProgress({
49800
+ status: progressStatus,
49801
+ scriptExecutions: [
49802
+ {
49803
+ phase: options.phase,
49804
+ position: options.script.position,
49805
+ status: "RUNNING"
49806
+ }
49807
+ ]
49131
49808
  });
49132
- } catch (progressError) {
49133
- logger.emit("PREPARING", "SYSTEM", cleanError2(progressError));
49134
- }
49809
+ const execution = await runHook(options);
49810
+ scriptExecutions.push(execution);
49811
+ await reportProgress({
49812
+ status: progressStatus,
49813
+ scriptExecutions: [execution]
49814
+ });
49815
+ return execution;
49816
+ };
49817
+ await reportProgress({
49818
+ status: "PREPARING",
49819
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
49820
+ });
49135
49821
  logger.emit("PREPARING", "SYSTEM", `Preparing build in ${folder}`);
49136
49822
  try {
49137
49823
  await onLog({
@@ -49167,7 +49853,7 @@ var runIosBuildWithPaths = async (payload, timeoutMs, signal2, onLog, context) =
49167
49853
  (a, b) => a.position - b.position
49168
49854
  )) {
49169
49855
  if (!script.preBuildScript) continue;
49170
- const execution = await runHook({
49856
+ const execution = await runReportedHook({
49171
49857
  input,
49172
49858
  folder,
49173
49859
  script,
@@ -49178,7 +49864,6 @@ var runIosBuildWithPaths = async (payload, timeoutMs, signal2, onLog, context) =
49178
49864
  logger,
49179
49865
  signal: signal2
49180
49866
  });
49181
- scriptExecutions.push(execution);
49182
49867
  if (execution.causedBuildFailure) {
49183
49868
  failBuild = true;
49184
49869
  errorCode = "SCRIPT_FAILED";
@@ -49210,14 +49895,11 @@ var runIosBuildWithPaths = async (payload, timeoutMs, signal2, onLog, context) =
49210
49895
  const finishBuild = async () => {
49211
49896
  try {
49212
49897
  if (!failBuild && !signal2.aborted) {
49213
- try {
49214
- await context?.reportBuildProgress?.({
49215
- buildId: input.buildId,
49216
- status: "RUNNING"
49217
- });
49218
- } catch (progressError) {
49219
- logger.emit("RUNNING", "SYSTEM", cleanError2(progressError));
49220
- }
49898
+ progressStatus = "RUNNING";
49899
+ await reportProgress({
49900
+ status: progressStatus,
49901
+ scriptExecutions: [...scriptExecutions]
49902
+ });
49221
49903
  if (input.worktreeCoverage) {
49222
49904
  try {
49223
49905
  coverageChanges = await snapshotCoverageChanges(
@@ -49254,7 +49936,7 @@ var runIosBuildWithPaths = async (payload, timeoutMs, signal2, onLog, context) =
49254
49936
  )) {
49255
49937
  if (!script.postBuildScript) continue;
49256
49938
  try {
49257
- const execution = await runHook({
49939
+ const execution = await runReportedHook({
49258
49940
  input,
49259
49941
  folder,
49260
49942
  script,
@@ -49272,7 +49954,6 @@ var runIosBuildWithPaths = async (payload, timeoutMs, signal2, onLog, context) =
49272
49954
  logger,
49273
49955
  signal: postSignal
49274
49956
  });
49275
- scriptExecutions.push(execution);
49276
49957
  if (execution.causedBuildFailure && !signal2.aborted) {
49277
49958
  failBuild = true;
49278
49959
  errorCode ??= "SCRIPT_FAILED";
@@ -49461,21 +50142,21 @@ var downloadIosBuildArtifact = async (payload, timeoutMs, signal2, onLog, contex
49461
50142
  if (!difference || difference === ".." || difference.startsWith(`..${sep5}`) || isAbsolute6(difference)) {
49462
50143
  throw new Error("Build artifact resolves outside the build folder");
49463
50144
  }
49464
- const information = await stat4(target2);
50145
+ const information = await stat5(target2);
49465
50146
  let uploadPath = target2;
49466
50147
  let filename = basename3(target2);
49467
50148
  let contentType = "application/octet-stream";
49468
50149
  let temporaryArchive = null;
49469
50150
  try {
49470
50151
  if (information.isDirectory()) {
49471
- temporaryArchive = join15(
50152
+ temporaryArchive = join16(
49472
50153
  tmpdir4(),
49473
50154
  `ade-build-artifact-${randomUUID5()}.tar.gz`
49474
50155
  );
49475
50156
  requireSuccess2(
49476
50157
  await command(
49477
50158
  "tar",
49478
- ["-czf", temporaryArchive, "-C", dirname9(target2), basename3(target2)],
50159
+ ["-czf", temporaryArchive, "-C", dirname10(target2), basename3(target2)],
49479
50160
  timeoutMs,
49480
50161
  signal2
49481
50162
  ),
@@ -49521,21 +50202,21 @@ var uploadTransferredIosBuildArtifact = async (payload, timeoutMs, signal2, onLo
49521
50202
  if (!difference || difference === ".." || difference.startsWith(`..${sep5}`) || isAbsolute6(difference)) {
49522
50203
  throw new Error("Build artifact resolves outside the build folder");
49523
50204
  }
49524
- const information = await stat4(target2);
50205
+ const information = await stat5(target2);
49525
50206
  let uploadPath = target2;
49526
50207
  let filename = basename3(target2);
49527
50208
  let contentType = "application/octet-stream";
49528
50209
  let temporaryArchive = null;
49529
50210
  try {
49530
50211
  if (information.isDirectory()) {
49531
- temporaryArchive = join15(
50212
+ temporaryArchive = join16(
49532
50213
  tmpdir4(),
49533
50214
  `ade-build-transfer-${input.transferId}-${randomUUID5()}.tar.gz`
49534
50215
  );
49535
50216
  requireSuccess2(
49536
50217
  await command(
49537
50218
  "tar",
49538
- ["-czf", temporaryArchive, "-C", dirname9(target2), basename3(target2)],
50219
+ ["-czf", temporaryArchive, "-C", dirname10(target2), basename3(target2)],
49539
50220
  timeoutMs,
49540
50221
  signal2
49541
50222
  ),
@@ -49591,24 +50272,24 @@ async function deployPreparedIosBuild(input, folder, appPath, timeoutMs, signal2
49591
50272
  if (!await pathExists(appPath) || !appPath.endsWith(".app")) {
49592
50273
  throw new Error("Runnable app artifact is missing");
49593
50274
  }
49594
- const deploymentsDirectory = join15(input.artifactDirectory, "deployments");
50275
+ const deploymentsDirectory = join16(input.artifactDirectory, "deployments");
49595
50276
  await mkdir4(deploymentsDirectory, { recursive: true, mode: 448 });
49596
50277
  const logger = new BuildLogger(
49597
50278
  input.buildId,
49598
50279
  context,
49599
- join15(deploymentsDirectory, "deployments.log"),
50280
+ join16(deploymentsDirectory, "deployments.log"),
49600
50281
  process.env
49601
50282
  );
49602
50283
  try {
49603
50284
  const outcomes = [];
49604
50285
  for (const deployment of input.deployments) {
49605
- const directory = join15(
50286
+ const directory = join16(
49606
50287
  input.artifactDirectory,
49607
50288
  "deployments",
49608
50289
  deployment.id
49609
50290
  );
49610
50291
  await mkdir4(directory, { recursive: true, mode: 448 });
49611
- const logPath = join15(directory, "deployment.log");
50292
+ const logPath = join16(directory, "deployment.log");
49612
50293
  const started = Date.now();
49613
50294
  let failure = null;
49614
50295
  let launchedAt = null;
@@ -49830,7 +50511,7 @@ var deployIosBuild = async (payload, timeoutMs, signal2, _onLog, context) => {
49830
50511
  };
49831
50512
  async function createRemoteBuildStagingDirectory(buildId) {
49832
50513
  return realpath6(
49833
- await mkdtemp5(join15(tmpdir4(), `ade-remote-build-${buildId}-`))
50514
+ await mkdtemp5(join16(tmpdir4(), `ade-remote-build-${buildId}-`))
49834
50515
  );
49835
50516
  }
49836
50517
  var deployTransferredIosBuild = async (payload, timeoutMs, signal2, onLog, context) => {
@@ -49839,7 +50520,7 @@ var deployTransferredIosBuild = async (payload, timeoutMs, signal2, onLog, conte
49839
50520
  throw new Error("This agent cannot download transferred build artifacts");
49840
50521
  }
49841
50522
  const staging = await createRemoteBuildStagingDirectory(input.buildId);
49842
- const archive = join15(staging, "artifact.tar.gz");
50523
+ const archive = join16(staging, "artifact.tar.gz");
49843
50524
  try {
49844
50525
  await onLog({
49845
50526
  sequence: 0,
@@ -49881,7 +50562,7 @@ var deployTransferredIosBuild = async (payload, timeoutMs, signal2, onLog, conte
49881
50562
  ),
49882
50563
  "Could not extract the transferred app"
49883
50564
  );
49884
- const appPath = await realpath6(join15(staging, root));
50565
+ const appPath = await realpath6(join16(staging, root));
49885
50566
  const pathDifference = relative4(staging, appPath);
49886
50567
  if (pathDifference === ".." || pathDifference.startsWith(`..${sep5}`) || isAbsolute6(pathDifference)) {
49887
50568
  throw new Error("Transferred app resolves outside its staging directory");
@@ -49946,14 +50627,14 @@ var exportIosArchive = async (payload, timeoutMs, signal2, _onLog, context) => {
49946
50627
  if (!await pathExists(archivePath) || !archivePath.endsWith(".xcarchive")) {
49947
50628
  throw new Error("Archive artifact is missing");
49948
50629
  }
49949
- const exportDirectory = join15(
50630
+ const exportDirectory = join16(
49950
50631
  input.artifactDirectory,
49951
50632
  "exports",
49952
50633
  input.exportId
49953
50634
  );
49954
50635
  await mkdir4(exportDirectory, { recursive: true, mode: 448 });
49955
- const plistPath = join15(exportDirectory, "ExportOptions.plist");
49956
- const logPath = join15(exportDirectory, "export.log");
50636
+ const plistPath = join16(exportDirectory, "ExportOptions.plist");
50637
+ const logPath = join16(exportDirectory, "export.log");
49957
50638
  await writeFile6(plistPath, exportPlist(input.settings), { mode: 384 });
49958
50639
  const logger = new BuildLogger(input.buildId, context, logPath, process.env);
49959
50640
  try {
@@ -50022,7 +50703,7 @@ var importCoverageReport = async (payloadValue, timeoutMs, signal2, onLog) => {
50022
50703
  const payload = parseCoverageImportPayload(payloadValue);
50023
50704
  if (signal2.aborted) return { ...successfulProcess4, cancelled: true };
50024
50705
  const folder = await realpath7(payload.folder);
50025
- const reportPath = await realpath7(join16(folder, payload.reportPath)).catch(
50706
+ const reportPath = await realpath7(join17(folder, payload.reportPath)).catch(
50026
50707
  () => {
50027
50708
  throw new Error(`Coverage file ${payload.reportPath} does not exist`);
50028
50709
  }
@@ -50031,7 +50712,7 @@ var importCoverageReport = async (payloadValue, timeoutMs, signal2, onLog) => {
50031
50712
  if (!difference || difference === ".." || difference.startsWith("../")) {
50032
50713
  throw new Error("Coverage file resolves outside the worktree");
50033
50714
  }
50034
- const information = await stat5(reportPath);
50715
+ const information = await stat6(reportPath);
50035
50716
  if (!information.isFile()) throw new Error("Coverage file is not a file");
50036
50717
  if (information.size > MAX_REPORT_BYTES) {
50037
50718
  throw new Error("Coverage file exceeds the 64 MiB limit");
@@ -50095,12 +50776,12 @@ import {
50095
50776
  readdir as readdir4,
50096
50777
  rename as rename6,
50097
50778
  rm as rm12,
50098
- stat as stat6,
50779
+ stat as stat7,
50099
50780
  utimes,
50100
50781
  writeFile as writeFile7
50101
50782
  } from "node:fs/promises";
50102
50783
  import { homedir as homedir9, tmpdir as tmpdir5 } from "node:os";
50103
- import { join as join17 } from "node:path";
50784
+ import { join as join18 } from "node:path";
50104
50785
  var CACHE_LIMIT_BYTES = 10 * 1024 ** 3;
50105
50786
  var ATOS_OUTPUT_LIMIT_BYTES = 16 * 1024 * 1024;
50106
50787
  var successfulProcess5 = {
@@ -50113,7 +50794,7 @@ function dsymCacheDirectory() {
50113
50794
  if (process.env.CONTROL_AGENT_DSYM_CACHE) {
50114
50795
  return process.env.CONTROL_AGENT_DSYM_CACHE;
50115
50796
  }
50116
- return process.platform === "darwin" ? join17(homedir9(), "Library", "Caches", "control-agent", "dsym-cache") : join17(homedir9(), ".cache", "control-agent", "dsym-cache");
50797
+ return process.platform === "darwin" ? join18(homedir9(), "Library", "Caches", "control-agent", "dsym-cache") : join18(homedir9(), ".cache", "control-agent", "dsym-cache");
50117
50798
  }
50118
50799
  async function log(onLog, sequence, message2, stream = "SYSTEM") {
50119
50800
  await onLog({
@@ -50124,10 +50805,10 @@ async function log(onLog, sequence, message2, stream = "SYSTEM") {
50124
50805
  });
50125
50806
  }
50126
50807
  async function cachedDwarf(dsym, cache, download, signal2) {
50127
- const folder = join17(cache, dsym.sha256);
50128
- const path = join17(folder, dsym.binaryName);
50808
+ const folder = join18(cache, dsym.sha256);
50809
+ const path = join18(folder, dsym.binaryName);
50129
50810
  try {
50130
- const existing = await stat6(path);
50811
+ const existing = await stat7(path);
50131
50812
  if (existing.size === dsym.sizeBytes) {
50132
50813
  const now = /* @__PURE__ */ new Date();
50133
50814
  await utimes(folder, now, now).catch(() => void 0);
@@ -50136,7 +50817,7 @@ async function cachedDwarf(dsym, cache, download, signal2) {
50136
50817
  } catch {
50137
50818
  }
50138
50819
  await mkdir5(folder, { recursive: true, mode: 448 });
50139
- const partial = join17(folder, `.${dsym.binaryName}.${randomUUID6()}.partial`);
50820
+ const partial = join18(folder, `.${dsym.binaryName}.${randomUUID6()}.partial`);
50140
50821
  try {
50141
50822
  await download({
50142
50823
  downloadPath: dsym.downloadPath,
@@ -50160,13 +50841,13 @@ async function trimDsymCache(cache, keep, limit = CACHE_LIMIT_BYTES) {
50160
50841
  }
50161
50842
  const folders = [];
50162
50843
  for (const name of entries) {
50163
- const folder = join17(cache, name);
50844
+ const folder = join18(cache, name);
50164
50845
  try {
50165
- const information = await stat6(folder);
50846
+ const information = await stat7(folder);
50166
50847
  if (!information.isDirectory()) continue;
50167
50848
  let size = 0;
50168
50849
  for (const file of await readdir4(folder)) {
50169
- size += (await stat6(join17(folder, file))).size;
50850
+ size += (await stat7(join18(folder, file))).size;
50170
50851
  }
50171
50852
  folders.push({ name, size, used: information.mtimeMs });
50172
50853
  } catch {
@@ -50176,7 +50857,7 @@ async function trimDsymCache(cache, keep, limit = CACHE_LIMIT_BYTES) {
50176
50857
  for (const folder of folders.sort((left, right) => left.used - right.used)) {
50177
50858
  if (total <= limit) break;
50178
50859
  if (keep.has(folder.name)) continue;
50179
- await rm12(join17(cache, folder.name), { recursive: true, force: true });
50860
+ await rm12(join18(cache, folder.name), { recursive: true, force: true });
50180
50861
  total -= folder.size;
50181
50862
  }
50182
50863
  }
@@ -50228,7 +50909,7 @@ var symbolicateCrash = async (payloadValue, timeoutMs, signal2, onLog, context)
50228
50909
  );
50229
50910
  }
50230
50911
  }
50231
- const workFolder = join17(tmpdir5(), `control-agent-atos-${randomUUID6()}`);
50912
+ const workFolder = join18(tmpdir5(), `control-agent-atos-${randomUUID6()}`);
50232
50913
  await mkdir5(workFolder, { recursive: true, mode: 448 });
50233
50914
  const lookups = [];
50234
50915
  try {
@@ -50244,7 +50925,7 @@ var symbolicateCrash = async (payloadValue, timeoutMs, signal2, onLog, context)
50244
50925
  if (!dwarfPath) continue;
50245
50926
  for (let start = 0; start < lookup.offsets.length; start += ATOS_BATCH_SIZE) {
50246
50927
  const batch = lookup.offsets.slice(start, start + ATOS_BATCH_SIZE);
50247
- const offsetsFile = join17(workFolder, `${lookup.uuid}-${start}.txt`);
50928
+ const offsetsFile = join18(workFolder, `${lookup.uuid}-${start}.txt`);
50248
50929
  await writeFile7(offsetsFile, `${batch.join("\n")}
50249
50930
  `, { mode: 384 });
50250
50931
  const run = await captureCommand({
@@ -50465,13 +51146,13 @@ import {
50465
51146
  readFile as readFile8,
50466
51147
  readdir as readdir5,
50467
51148
  rm as rm13,
50468
- stat as stat7,
51149
+ stat as stat8,
50469
51150
  writeFile as writeFile8
50470
51151
  } from "node:fs/promises";
50471
51152
  import { homedir as homedir11, tmpdir as tmpdir6 } from "node:os";
50472
- import { basename as basename4, join as join18, relative as relative6, sep as sep7 } from "node:path";
51153
+ import { basename as basename4, join as join19, relative as relative6, sep as sep7 } from "node:path";
50473
51154
  var PROFILE_DIRECTORIES = [
50474
- join18(
51155
+ join19(
50475
51156
  homedir11(),
50476
51157
  "Library",
50477
51158
  "Developer",
@@ -50479,7 +51160,7 @@ var PROFILE_DIRECTORIES = [
50479
51160
  "UserData",
50480
51161
  "Provisioning Profiles"
50481
51162
  ),
50482
- join18(homedir11(), "Library", "MobileDevice", "Provisioning Profiles")
51163
+ join19(homedir11(), "Library", "MobileDevice", "Provisioning Profiles")
50483
51164
  ];
50484
51165
  var PROFILE_EXTENSIONS = [".mobileprovision", ".provisionprofile"];
50485
51166
  function text(value) {
@@ -50572,7 +51253,7 @@ async function readProfiles(timeoutMs, signal2) {
50572
51253
  continue;
50573
51254
  signal2.throwIfAborted();
50574
51255
  const raw = await decodeProfile(
50575
- join18(directory, entry),
51256
+ join19(directory, entry),
50576
51257
  timeoutMs,
50577
51258
  signal2
50578
51259
  );
@@ -50606,7 +51287,7 @@ async function decodedProfiles(timeoutMs, signal2, strict = false) {
50606
51287
  continue;
50607
51288
  }
50608
51289
  signal2.throwIfAborted();
50609
- const path = join18(directory, entry);
51290
+ const path = join19(directory, entry);
50610
51291
  const raw = await decodeProfile(path, timeoutMs, signal2, strict);
50611
51292
  if (!raw) continue;
50612
51293
  let content;
@@ -50762,7 +51443,7 @@ async function readCertificates(timeoutMs, signal2, strict = false) {
50762
51443
  );
50763
51444
  }
50764
51445
  async function readArchiveBundles(archivePath, timeoutMs, signal2) {
50765
- const products = join18(archivePath, "Products");
51446
+ const products = join19(archivePath, "Products");
50766
51447
  const bundles = [];
50767
51448
  const queue = [products];
50768
51449
  while (queue.length) {
@@ -50776,7 +51457,7 @@ async function readArchiveBundles(archivePath, timeoutMs, signal2) {
50776
51457
  }
50777
51458
  for (const entry of entries) {
50778
51459
  if (entry.isSymbolicLink() || !entry.isDirectory()) continue;
50779
- const path = join18(current, entry.name);
51460
+ const path = join19(current, entry.name);
50780
51461
  const signable = /\.(app|appex)$/.test(entry.name);
50781
51462
  if (!signable) {
50782
51463
  if (!/\.[A-Za-z0-9]+$/.test(entry.name)) queue.push(path);
@@ -50808,7 +51489,7 @@ async function bundleIdentifier(bundlePath, timeoutMs, signal2) {
50808
51489
  "raw",
50809
51490
  "-o",
50810
51491
  "-",
50811
- join18(bundlePath, "Info.plist")
51492
+ join19(bundlePath, "Info.plist")
50812
51493
  ],
50813
51494
  timeoutMs: Math.min(timeoutMs, 5e3),
50814
51495
  signal: signal2
@@ -50824,9 +51505,9 @@ async function embeddedProfile(bundlePath, timeoutMs, signal2) {
50824
51505
  "embedded.mobileprovision",
50825
51506
  "embedded.provisionprofile"
50826
51507
  ]) {
50827
- const path = join18(bundlePath, name);
51508
+ const path = join19(bundlePath, name);
50828
51509
  try {
50829
- await stat7(path);
51510
+ await stat8(path);
50830
51511
  } catch {
50831
51512
  continue;
50832
51513
  }
@@ -50871,7 +51552,7 @@ async function inspectSigningAssets(archivePath, timeoutMs, signal2) {
50871
51552
  }
50872
51553
  var inspectIosSigning = async (payload, timeoutMs, signal2) => {
50873
51554
  const input = parseBuildSigningInspectPayload(payload);
50874
- const archivePath = join18(input.artifactDirectory, input.archiveRelativePath);
51555
+ const archivePath = join19(input.artifactDirectory, input.archiveRelativePath);
50875
51556
  const inspection = await inspectSigningAssets(archivePath, timeoutMs, signal2);
50876
51557
  return {
50877
51558
  exitCode: 0,
@@ -50933,8 +51614,8 @@ var installSigningProfile = async (payload, timeoutMs, signal2) => {
50933
51614
  const { contentBase64 } = signingProfileInstallPayload(payload);
50934
51615
  const content = Buffer.from(contentBase64, "base64");
50935
51616
  if (!content.length) throw new Error("Provisioning profile is empty");
50936
- const temporaryRoot = await mkdtemp6(join18(tmpdir6(), "ade-profile-"));
50937
- const temporaryPath = join18(temporaryRoot, `${randomUUID7()}.mobileprovision`);
51617
+ const temporaryRoot = await mkdtemp6(join19(tmpdir6(), "ade-profile-"));
51618
+ const temporaryPath = join19(temporaryRoot, `${randomUUID7()}.mobileprovision`);
50938
51619
  try {
50939
51620
  await writeFile8(temporaryPath, content, { mode: 384 });
50940
51621
  const raw = await decodeProfile(temporaryPath, timeoutMs, signal2);
@@ -50943,7 +51624,7 @@ var installSigningProfile = async (payload, timeoutMs, signal2) => {
50943
51624
  if (!uuid) throw new Error("Provisioning profile UUID is missing");
50944
51625
  const directory = PROFILE_DIRECTORIES[0];
50945
51626
  await mkdir6(directory, { recursive: true, mode: 448 });
50946
- const destination = join18(directory, `${uuid}.mobileprovision`);
51627
+ const destination = join19(directory, `${uuid}.mobileprovision`);
50947
51628
  await writeFile8(destination, content, { mode: 384 });
50948
51629
  return { ...successfulProcess6, uuid };
50949
51630
  } finally {
@@ -50971,8 +51652,8 @@ var importSigningIdentity = async (payload, timeoutMs, signal2, _onLog, context)
50971
51652
  const hash = createHash7("sha256").update(p12).digest("hex").toUpperCase();
50972
51653
  if (hash !== input.sha256)
50973
51654
  throw new Error("Signing identity transfer changed");
50974
- const temporaryRoot = await mkdtemp6(join18(tmpdir6(), "ade-identity-"));
50975
- const path = join18(temporaryRoot, "identity.p12");
51655
+ const temporaryRoot = await mkdtemp6(join19(tmpdir6(), "ade-identity-"));
51656
+ const path = join19(temporaryRoot, "identity.p12");
50976
51657
  try {
50977
51658
  await writeFile8(path, p12, { mode: 384 });
50978
51659
  const result = await captureCommand({
@@ -51191,15 +51872,15 @@ import {
51191
51872
  realpath as realpath8,
51192
51873
  readFile as readFile9,
51193
51874
  rm as rm14,
51194
- stat as stat8,
51875
+ stat as stat9,
51195
51876
  statfs
51196
51877
  } from "node:fs/promises";
51197
51878
  import { homedir as homedir12 } from "node:os";
51198
51879
  import {
51199
51880
  basename as basename5,
51200
- dirname as dirname10,
51881
+ dirname as dirname11,
51201
51882
  isAbsolute as isAbsolute7,
51202
- join as join19,
51883
+ join as join20,
51203
51884
  relative as relative7,
51204
51885
  resolve as resolve9
51205
51886
  } from "node:path";
@@ -51228,7 +51909,7 @@ async function configuredRoots(payload) {
51228
51909
  }
51229
51910
  async function legacyConfiguredRoots(payload) {
51230
51911
  if (payload.mode === "DEFAULT") {
51231
- return [join19(homedir12(), "Library", "Developer", "Xcode", "DerivedData")];
51912
+ return [join20(homedir12(), "Library", "Developer", "Xcode", "DerivedData")];
51232
51913
  }
51233
51914
  if (payload.mode === "ABSOLUTE") {
51234
51915
  if (!payload.path || !isAbsolute7(payload.path)) {
@@ -51285,21 +51966,21 @@ async function scanRoot(configuredRoot, timeoutMs, signal2) {
51285
51966
  };
51286
51967
  }
51287
51968
  const entries = [];
51288
- const rootStats = await stat8(rootPath2);
51969
+ const rootStats = await stat9(rootPath2);
51289
51970
  const volumeId = String(rootStats.dev);
51290
51971
  for (const child of children) {
51291
51972
  signal2.throwIfAborted();
51292
51973
  if (!child.isDirectory()) continue;
51293
- const path = join19(rootPath2, child.name);
51974
+ const path = join20(rootPath2, child.name);
51294
51975
  const information = await lstat4(path);
51295
51976
  let projectPath = await workspacePath(
51296
- join19(path, "info.plist"),
51977
+ join20(path, "info.plist"),
51297
51978
  timeoutMs,
51298
51979
  signal2
51299
51980
  );
51300
51981
  try {
51301
51982
  const ownership = JSON.parse(
51302
- await readFile9(join19(path, ".aide-worktree.json"), "utf8")
51983
+ await readFile9(join20(path, ".aide-worktree.json"), "utf8")
51303
51984
  );
51304
51985
  if (ownership.version === 1 && ownership.worktreeId === child.name && typeof ownership.folder === "string" && isAbsolute7(ownership.folder))
51305
51986
  projectPath = ownership.folder;
@@ -51319,7 +52000,7 @@ async function scanRoot(configuredRoot, timeoutMs, signal2) {
51319
52000
  return { entries, warning: null };
51320
52001
  }
51321
52002
  async function scanDeviceSupport(signal2) {
51322
- const configuredRoot = join19(
52003
+ const configuredRoot = join20(
51323
52004
  process.env.ADE_IOS_DEVICE_SUPPORT_DIRECTORY ?? homedir12(),
51324
52005
  ...process.env.ADE_IOS_DEVICE_SUPPORT_DIRECTORY ? [] : ["Library", "Developer", "Xcode", "iOS DeviceSupport"]
51325
52006
  );
@@ -51340,7 +52021,7 @@ async function scanDeviceSupport(signal2) {
51340
52021
  const children = await readdir6(rootPath2, { withFileTypes: true });
51341
52022
  return {
51342
52023
  entries: children.filter((child) => child.isDirectory() && !child.isSymbolicLink()).map((child) => ({
51343
- path: join19(rootPath2, child.name),
52024
+ path: join20(rootPath2, child.name),
51344
52025
  rootPath: rootPath2,
51345
52026
  name: child.name,
51346
52027
  kind: "DEVICE_SUPPORT",
@@ -51408,7 +52089,7 @@ async function ownedWorktreeBuildData(folder, configuration, timeoutMs, signal2)
51408
52089
  warnings.push(`${entry.path}: ${errorMessage(error)}`);
51409
52090
  continue;
51410
52091
  }
51411
- let ancestor = dirname10(entry.workspacePath);
52092
+ let ancestor = dirname11(entry.workspacePath);
51412
52093
  while (within(folder, ancestor) && ancestor !== folder) {
51413
52094
  try {
51414
52095
  if (!within(folder, await realpath8(ancestor))) ancestor = "";
@@ -51418,7 +52099,7 @@ async function ownedWorktreeBuildData(folder, configuration, timeoutMs, signal2)
51418
52099
  ancestor = "";
51419
52100
  break;
51420
52101
  }
51421
- ancestor = dirname10(ancestor);
52102
+ ancestor = dirname11(ancestor);
51422
52103
  }
51423
52104
  }
51424
52105
  if (!ancestor) continue;
@@ -51434,7 +52115,7 @@ function assertDirectChild(rootPath2, path) {
51434
52115
  }
51435
52116
  const root = resolve9(rootPath2);
51436
52117
  const target2 = resolve9(path);
51437
- if (target2 === root || dirname10(target2) !== root || basename5(target2) !== basename5(path)) {
52118
+ if (target2 === root || dirname11(target2) !== root || basename5(target2) !== basename5(path)) {
51438
52119
  throw new Error("Build Data target must be a direct child of its root");
51439
52120
  }
51440
52121
  }
@@ -51448,7 +52129,7 @@ async function allocatedBytes(path, signal2) {
51448
52129
  try {
51449
52130
  for await (const entry of directory) {
51450
52131
  signal2.throwIfAborted();
51451
- total += await allocatedBytes(join19(path, entry.name), signal2);
52132
+ total += await allocatedBytes(join20(path, entry.name), signal2);
51452
52133
  }
51453
52134
  } finally {
51454
52135
  await directory.close().catch(() => void 0);
@@ -51463,7 +52144,7 @@ var sizeBuildData = async (rawPayload, _timeoutMs, signal2) => {
51463
52144
  try {
51464
52145
  assertDirectChild(target2.rootPath, target2.path);
51465
52146
  const rootPath2 = await realpath8(target2.rootPath);
51466
- if (rootPath2 !== resolve9(target2.rootPath) || dirname10(resolve9(target2.path)) !== rootPath2) {
52147
+ if (rootPath2 !== resolve9(target2.rootPath) || dirname11(resolve9(target2.path)) !== rootPath2) {
51467
52148
  throw new Error("Build Data root changed since the scan");
51468
52149
  }
51469
52150
  const stats = await lstat4(target2.path);
@@ -51495,7 +52176,7 @@ var deleteBuildData = async (rawPayload, _timeoutMs, signal2, _onLog, context) =
51495
52176
  const removeTarget2 = async () => {
51496
52177
  assertDirectChild(target2.rootPath, target2.path);
51497
52178
  const rootPath2 = await realpath8(target2.rootPath);
51498
- if (rootPath2 !== resolve9(target2.rootPath) || dirname10(resolve9(target2.path)) !== rootPath2) {
52179
+ if (rootPath2 !== resolve9(target2.rootPath) || dirname11(resolve9(target2.path)) !== rootPath2) {
51499
52180
  throw new Error("Build Data root changed since the scan");
51500
52181
  }
51501
52182
  const stats = await lstat4(target2.path);
@@ -51564,13 +52245,13 @@ async function inspectVolume(configuredPath, role, signal2, allowMissing) {
51564
52245
  let candidate = resolve9(configuredPath);
51565
52246
  for (; ; ) {
51566
52247
  signal2.throwIfAborted();
51567
- const parent = dirname10(candidate);
52248
+ const parent = dirname11(candidate);
51568
52249
  if (parent === candidate) throw error;
51569
52250
  missingSegments.unshift(basename5(candidate));
51570
52251
  candidate = parent;
51571
52252
  try {
51572
52253
  inspectionPath = await realpath8(candidate);
51573
- canonicalPath = join19(inspectionPath, ...missingSegments);
52254
+ canonicalPath = join20(inspectionPath, ...missingSegments);
51574
52255
  break;
51575
52256
  } catch (parentError) {
51576
52257
  if (parentError.code !== "ENOENT") {
@@ -51580,7 +52261,7 @@ async function inspectVolume(configuredPath, role, signal2, allowMissing) {
51580
52261
  }
51581
52262
  }
51582
52263
  const [information, filesystem] = await Promise.all([
51583
- stat8(inspectionPath),
52264
+ stat9(inspectionPath),
51584
52265
  statfs(inspectionPath, { bigint: true })
51585
52266
  ]);
51586
52267
  const id2 = String(information.dev);
@@ -51689,11 +52370,11 @@ import {
51689
52370
  readdir as readdir7,
51690
52371
  rename as rename7,
51691
52372
  rm as rm15,
51692
- stat as stat9,
52373
+ stat as stat10,
51693
52374
  writeFile as writeFile9
51694
52375
  } from "node:fs/promises";
51695
52376
  import { homedir as homedir13 } from "node:os";
51696
- import { dirname as dirname11, isAbsolute as isAbsolute8, join as join20, relative as relative8, resolve as resolve10, sep as sep8 } from "node:path";
52377
+ import { dirname as dirname12, isAbsolute as isAbsolute8, join as join21, relative as relative8, resolve as resolve10, sep as sep8 } from "node:path";
51697
52378
  import { promisify as promisify3 } from "node:util";
51698
52379
  var executeFile = promisify3(execFile3);
51699
52380
  var successfulProcess8 = {
@@ -51748,7 +52429,7 @@ var PROJECT_ROOTS = {
51748
52429
  };
51749
52430
  async function directoryExists(path) {
51750
52431
  try {
51751
- return (await stat9(path)).isDirectory();
52432
+ return (await stat10(path)).isDirectory();
51752
52433
  } catch {
51753
52434
  return false;
51754
52435
  }
@@ -51758,7 +52439,7 @@ async function configuredTools(tools) {
51758
52439
  return Promise.all(
51759
52440
  AI_TOOLS.filter((tool) => tools.includes(tool)).map(async (tool) => ({
51760
52441
  tool,
51761
- configured: await directoryExists(join20(homePath, ...CONFIG_PATHS[tool])),
52442
+ configured: await directoryExists(join21(homePath, ...CONFIG_PATHS[tool])),
51762
52443
  homePath
51763
52444
  }))
51764
52445
  );
@@ -51795,7 +52476,7 @@ async function listPackageFiles(skillDirectory) {
51795
52476
  let totalBytes = 0;
51796
52477
  const visit = async (directory) => {
51797
52478
  for (const entry of await readdir7(directory, { withFileTypes: true })) {
51798
- const path = join20(directory, entry.name);
52479
+ const path = join21(directory, entry.name);
51799
52480
  const metadata = await lstat5(path);
51800
52481
  if (metadata.isSymbolicLink()) {
51801
52482
  throw new Error(
@@ -51894,7 +52575,7 @@ async function scanRoot2(location, configured, targets, warnings) {
51894
52575
  const installations = [];
51895
52576
  for (const entry of await readdir7(root, { withFileTypes: true })) {
51896
52577
  if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
51897
- const directory = join20(root, entry.name);
52578
+ const directory = join21(root, entry.name);
51898
52579
  try {
51899
52580
  const skillPackage = await readPackage(directory, resolvedRoot);
51900
52581
  const relativeDirectory = location.folder ? relative8(location.folder, directory).split(sep8).join("/") : "";
@@ -51974,7 +52655,7 @@ var readSkills = async (payload) => {
51974
52655
  const { resolvedRoot } = await resolvedSkillRoot(request);
51975
52656
  packages.push({
51976
52657
  ...request,
51977
- package: await readPackage(join20(root, request.skillName), resolvedRoot)
52658
+ package: await readPackage(join21(root, request.skillName), resolvedRoot)
51978
52659
  });
51979
52660
  }
51980
52661
  return { ...successfulProcess8, packages };
@@ -51992,7 +52673,7 @@ async function gitExcludePath(folder) {
51992
52673
  }
51993
52674
  async function updateManagedExclude(folder, relativeSkillPath, present) {
51994
52675
  const excludePath = await gitExcludePath(folder);
51995
- await mkdir7(dirname11(excludePath), { recursive: true });
52676
+ await mkdir7(dirname12(excludePath), { recursive: true });
51996
52677
  let existing = "";
51997
52678
  try {
51998
52679
  existing = await readFile10(excludePath, "utf8");
@@ -52036,18 +52717,18 @@ async function writePackage(location, skillPackage) {
52036
52717
  throw new Error("New skill copies may only be written to shared roots");
52037
52718
  }
52038
52719
  const root = rootPath(location);
52039
- const destination = join20(root, skillPackage.name);
52720
+ const destination = join21(root, skillPackage.name);
52040
52721
  await assertUntracked(location, destination);
52041
52722
  await mkdir7(root, { recursive: true });
52042
- const temporary = join20(root, `.${skillPackage.name}.${randomUUID8()}.tmp`);
52043
- const backup = join20(root, `.${skillPackage.name}.${randomUUID8()}.bak`);
52723
+ const temporary = join21(root, `.${skillPackage.name}.${randomUUID8()}.tmp`);
52724
+ const backup = join21(root, `.${skillPackage.name}.${randomUUID8()}.bak`);
52044
52725
  await mkdir7(temporary, { recursive: true });
52045
52726
  try {
52046
52727
  for (const file of skillPackage.files) {
52047
52728
  const path = resolve10(temporary, ...file.path.split("/"));
52048
52729
  if (!path.startsWith(`${temporary}${sep8}`))
52049
52730
  throw new Error("Skill file escaped temporary directory");
52050
- await mkdir7(dirname11(path), { recursive: true });
52731
+ await mkdir7(dirname12(path), { recursive: true });
52051
52732
  await writeFile9(path, Buffer.from(file.contentsBase64, "base64"));
52052
52733
  await chmod3(path, file.executable ? 493 : 420);
52053
52734
  }
@@ -52078,7 +52759,7 @@ var applySkills = async (payload) => {
52078
52759
  for (const operation of operations) {
52079
52760
  const root = rootPath(operation);
52080
52761
  const skillName = operation.kind === "WRITE" ? operation.package.name : operation.skillName;
52081
- const destination = join20(root, skillName);
52762
+ const destination = join21(root, skillName);
52082
52763
  await assertUntracked(operation, destination);
52083
52764
  if (operation.kind === "WRITE") {
52084
52765
  await writePackage(operation, operation.package);
@@ -52112,16 +52793,16 @@ import {
52112
52793
  readFile as readFile11,
52113
52794
  realpath as realpath10,
52114
52795
  rm as rm17,
52115
- stat as stat10,
52796
+ stat as stat11,
52116
52797
  writeFile as writeFile10
52117
52798
  } from "node:fs/promises";
52118
52799
  import { tmpdir as tmpdir8 } from "node:os";
52119
- import { join as join22 } from "node:path";
52800
+ import { join as join23 } from "node:path";
52120
52801
 
52121
52802
  // src/runs/git-checkpoint.ts
52122
52803
  import { copyFile, mkdtemp as mkdtemp7, rm as rm16 } from "node:fs/promises";
52123
52804
  import { tmpdir as tmpdir7 } from "node:os";
52124
- import { join as join21 } from "node:path";
52805
+ import { join as join22 } from "node:path";
52125
52806
  var PATCH_LIMIT = 2e6;
52126
52807
  var SUMMARY_LIMIT = 24e4;
52127
52808
  var MANIFEST_LIMIT = 2e6;
@@ -52355,12 +53036,12 @@ async function captureGitCheckpoint(cwd, runId, kind) {
52355
53036
  ["diff", "--stat", "HEAD"],
52356
53037
  SUMMARY_LIMIT
52357
53038
  );
52358
- const directory = await mkdtemp7(join21(tmpdir7(), "aide-run-index-"));
53039
+ const directory = await mkdtemp7(join22(tmpdir7(), "aide-run-index-"));
52359
53040
  let worktreeTree = null;
52360
53041
  let refName = null;
52361
53042
  try {
52362
53043
  const actualIndex = await git3(cwd, ["rev-parse", "--git-path", "index"]);
52363
- const temporaryIndex = join21(directory, "index");
53044
+ const temporaryIndex = join22(directory, "index");
52364
53045
  try {
52365
53046
  await copyFile(actualIndex, temporaryIndex);
52366
53047
  } catch {
@@ -52425,13 +53106,13 @@ var success2 = {
52425
53106
  var runWorkflowTerminal = async (payloadValue, timeoutMs, signal2, onLog, context) => {
52426
53107
  const payload = parseWorkflowTerminalPayload(payloadValue);
52427
53108
  const cwd = await realpath10(payload.cwd);
52428
- const information = await stat10(cwd);
53109
+ const information = await stat11(cwd);
52429
53110
  if (!information.isDirectory())
52430
53111
  throw new Error("Workflow working directory is not a directory");
52431
- const directory = await mkdtemp8(join22(tmpdir8(), "aide-workflow-"));
53112
+ const directory = await mkdtemp8(join23(tmpdir8(), "aide-workflow-"));
52432
53113
  const extension2 = payload.interpreter === "NODE" ? "mjs" : "sh";
52433
- const scriptPath = join22(directory, `step.${extension2}`);
52434
- const sessionPath = join22(directory, "session.json");
53114
+ const scriptPath = join23(directory, `step.${extension2}`);
53115
+ const sessionPath = join23(directory, "session.json");
52435
53116
  try {
52436
53117
  await writeFile10(scriptPath, `${payload.script}
52437
53118
  `, { mode: 384 });
@@ -52522,9 +53203,9 @@ var runWorkflowGitCheckpoint = async (payloadValue, _timeoutMs, signal2) => {
52522
53203
 
52523
53204
  // src/handlers/worktrees.ts
52524
53205
  import { createWriteStream as createWriteStream3, watch } from "node:fs";
52525
- import { mkdtemp as mkdtemp9, open as open3, readFile as readFile13, realpath as realpath12, rm as rm19, stat as stat11 } from "node:fs/promises";
53206
+ import { mkdtemp as mkdtemp9, open as open3, readFile as readFile13, realpath as realpath12, rm as rm19, stat as stat12 } from "node:fs/promises";
52526
53207
  import { tmpdir as tmpdir9 } from "node:os";
52527
- import { basename as basename6, dirname as dirname13, isAbsolute as isAbsolute10, join as join24, relative as relative10 } from "node:path";
53208
+ import { basename as basename6, dirname as dirname14, isAbsolute as isAbsolute10, join as join25, relative as relative10 } from "node:path";
52528
53209
 
52529
53210
  // src/handlers/worktree-preparations.ts
52530
53211
  import { createHash as createHash8 } from "node:crypto";
@@ -52538,7 +53219,7 @@ import {
52538
53219
  rm as rm18,
52539
53220
  writeFile as writeFile11
52540
53221
  } from "node:fs/promises";
52541
- import { dirname as dirname12, isAbsolute as isAbsolute9, join as join23, relative as relative9, resolve as resolve11 } from "node:path";
53222
+ import { dirname as dirname13, isAbsolute as isAbsolute9, join as join24, relative as relative9, resolve as resolve11 } from "node:path";
52542
53223
  import { randomUUID as randomUUID9 } from "node:crypto";
52543
53224
  var EXCLUDE_BEGIN = "# BEGIN AIDE PREPARATIONS";
52544
53225
  var EXCLUDE_END = "# END AIDE PREPARATIONS";
@@ -52590,7 +53271,7 @@ async function safeTarget(folder, path) {
52590
53271
  let current = root;
52591
53272
  const segments = fromRoot.split(/[\\/]/);
52592
53273
  for (const segment of segments.slice(0, -1)) {
52593
- current = join23(current, segment);
53274
+ current = join24(current, segment);
52594
53275
  try {
52595
53276
  const info = await lstat6(current);
52596
53277
  if (info.isSymbolicLink()) {
@@ -52713,7 +53394,7 @@ async function writeExcludeFile(folder, definitions, timeoutMs, signal2) {
52713
53394
  const entries = definitions.filter((definition) => definition.kind === "WRITE").map((definition) => excludeEntry(definition.path)).sort((left, right) => left.localeCompare(right));
52714
53395
  const block = entries.length ? [EXCLUDE_BEGIN, ...entries, EXCLUDE_END].join("\n") : "";
52715
53396
  const next = [base, block].filter(Boolean).join("\n\n");
52716
- await mkdir8(dirname12(path), { recursive: true });
53397
+ await mkdir8(dirname13(path), { recursive: true });
52717
53398
  const temporary = `${path}.${randomUUID9()}.tmp`;
52718
53399
  try {
52719
53400
  await writeFile11(temporary, next ? `${next}
@@ -52803,7 +53484,7 @@ async function applyOne(folder, definition, timeoutMs, signal2) {
52803
53484
  throw error;
52804
53485
  }
52805
53486
  }
52806
- await mkdir8(dirname12(target2), { recursive: true, mode: 493 });
53487
+ await mkdir8(dirname13(target2), { recursive: true, mode: 493 });
52807
53488
  await safeTarget(folder, definition.path);
52808
53489
  await writeFile11(target2, contents, { mode: executable ? 493 : 420 });
52809
53490
  if (executable) await chmod4(target2, 493);
@@ -53077,7 +53758,7 @@ async function rebaseInProgress(folder, timeoutMs, signal2) {
53077
53758
  const candidate = pathResult.stdout.trim();
53078
53759
  if (!candidate) continue;
53079
53760
  try {
53080
- await stat11(isAbsolute10(candidate) ? candidate : join24(folder, candidate));
53761
+ await stat12(isAbsolute10(candidate) ? candidate : join25(folder, candidate));
53081
53762
  return true;
53082
53763
  } catch {
53083
53764
  }
@@ -53099,7 +53780,7 @@ async function gitStatePathExists(folder, name, timeoutMs, signal2) {
53099
53780
  throw new Error(`Could not resolve Git state path ${name}`);
53100
53781
  }
53101
53782
  try {
53102
- await stat11(candidate);
53783
+ await stat12(candidate);
53103
53784
  return true;
53104
53785
  } catch (error) {
53105
53786
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -53153,7 +53834,7 @@ async function rebaseBranch(folder, timeoutMs, signal2) {
53153
53834
  if (!candidate) continue;
53154
53835
  try {
53155
53836
  const headName = (await readFile13(
53156
- isAbsolute10(candidate) ? candidate : join24(folder, candidate),
53837
+ isAbsolute10(candidate) ? candidate : join25(folder, candidate),
53157
53838
  "utf8"
53158
53839
  )).trim();
53159
53840
  if (headName.startsWith("refs/heads/")) {
@@ -53348,7 +54029,7 @@ async function origin(folder, timeoutMs, signal2) {
53348
54029
  }
53349
54030
  async function validateWorktree2(input, timeoutMs, signal2) {
53350
54031
  const folder = await realpath12(input.folder);
53351
- if (!(await stat11(folder)).isDirectory())
54032
+ if (!(await stat12(folder)).isDirectory())
53352
54033
  throw new Error("Worktree is missing");
53353
54034
  const observedGitDirectory = await gitDirectory(folder, timeoutMs, signal2);
53354
54035
  if (observedGitDirectory !== input.gitDirectory) {
@@ -53590,7 +54271,7 @@ function parseNumstat(value) {
53590
54271
  }
53591
54272
  async function untrackedLines(folder, path) {
53592
54273
  try {
53593
- const file = await stat11(`${folder}/${path}`);
54274
+ const file = await stat12(`${folder}/${path}`);
53594
54275
  if (!file.isFile() || file.size > 1024 * 1024) return null;
53595
54276
  const contents = await readFile13(`${folder}/${path}`);
53596
54277
  if (contents.includes(0)) return null;
@@ -53823,7 +54504,7 @@ async function comparisonSides(input, folder, timeoutMs, signal2) {
53823
54504
  if (!input.path) return { before: null, after: null };
53824
54505
  const path = input.path;
53825
54506
  const previousPath = input.previousPath ?? path;
53826
- const currentPath = join24(folder, path);
54507
+ const currentPath = join25(folder, path);
53827
54508
  if (input.scope === "UNTRACKED") {
53828
54509
  return { before: null, after: { kind: "FILE", path: currentPath } };
53829
54510
  }
@@ -53927,7 +54608,7 @@ async function availableSide(side, folder, timeoutMs, signal2) {
53927
54608
  try {
53928
54609
  const resolved = await realpath12(side.path);
53929
54610
  const difference = relative10(folder, resolved);
53930
- return difference !== ".." && !difference.startsWith("../") && (await stat11(resolved)).isFile();
54611
+ return difference !== ".." && !difference.startsWith("../") && (await stat12(resolved)).isFile();
53931
54612
  } catch {
53932
54613
  return false;
53933
54614
  }
@@ -53998,7 +54679,7 @@ async function inspectRequestedDiff(input, folder, timeoutMs, signal2) {
53998
54679
  let patch;
53999
54680
  if (input.scope === "UNTRACKED") {
54000
54681
  const bounded = await readBoundedFile(
54001
- join24(folder, input.path),
54682
+ join25(folder, input.path),
54002
54683
  MAX_DIFF_BYTES
54003
54684
  );
54004
54685
  const contents = bounded.contents;
@@ -54180,8 +54861,8 @@ var downloadWorktreeDiffAsset = async (payload, timeoutMs, signal2, _onLog, cont
54180
54861
  if (!/^\d+$/.test(size) || Number(size) > 20 * 1024 * 1024) {
54181
54862
  throw new Error("Diff image exceeds the 20 MiB limit");
54182
54863
  }
54183
- temporaryDirectory = await mkdtemp9(join24(tmpdir9(), "ade-diff-image-"));
54184
- uploadPath = join24(temporaryDirectory, basename6(input.path));
54864
+ temporaryDirectory = await mkdtemp9(join25(tmpdir9(), "ade-diff-image-"));
54865
+ uploadPath = join25(temporaryDirectory, basename6(input.path));
54185
54866
  await writeGitObject(
54186
54867
  folder,
54187
54868
  selected.specification,
@@ -54190,7 +54871,7 @@ var downloadWorktreeDiffAsset = async (payload, timeoutMs, signal2, _onLog, cont
54190
54871
  signal2
54191
54872
  );
54192
54873
  }
54193
- const information = await stat11(uploadPath);
54874
+ const information = await stat12(uploadPath);
54194
54875
  if (!information.isFile() || information.size > 20 * 1024 * 1024) {
54195
54876
  throw new Error("Diff image exceeds the 20 MiB limit");
54196
54877
  }
@@ -54474,7 +55155,7 @@ async function chooseNewBranch(folder, candidates, allowedCurrentBranch, timeout
54474
55155
  }
54475
55156
  async function validateBranchRoot(input, timeoutMs, signal2) {
54476
55157
  const rootFolder = await realpath12(input.rootFolder);
54477
- if (!(await stat11(rootFolder)).isDirectory()) {
55158
+ if (!(await stat12(rootFolder)).isDirectory()) {
54478
55159
  throw new Error("Base repository is missing");
54479
55160
  }
54480
55161
  if (await origin(rootFolder, timeoutMs, signal2) !== input.expectedOrigin) {
@@ -54545,8 +55226,8 @@ var branchWorktree = async (payload, timeoutMs, signal2, _onLog, context) => {
54545
55226
  timeoutMs,
54546
55227
  signal2
54547
55228
  ) : input.candidates[0];
54548
- const targetFolder = input.action === "CREATE" ? join24(
54549
- dirname13(rootFolder),
55229
+ const targetFolder = input.action === "CREATE" ? join25(
55230
+ dirname14(rootFolder),
54550
55231
  `${basename6(rootFolder)}-${branch.replaceAll("/", "-")}`
54551
55232
  ) : changeFolder;
54552
55233
  const execute2 = () => finishBranchWorktree(
@@ -54575,7 +55256,7 @@ var branchWorktree = async (payload, timeoutMs, signal2, _onLog, context) => {
54575
55256
  async function finishBranchWorktree(input, rootFolder, targetFolder, branch, beforeBranch, timeoutMs, signal2) {
54576
55257
  if (input.action === "CREATE") {
54577
55258
  try {
54578
- await stat11(targetFolder);
55259
+ await stat12(targetFolder);
54579
55260
  throw new Error(`Worktree folder already exists: ${targetFolder}`);
54580
55261
  } catch (error) {
54581
55262
  if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
@@ -54820,8 +55501,8 @@ async function checkedOutBranchFolder(rootFolder, branch, timeoutMs, signal2) {
54820
55501
  var checkoutMovedWorktree = async (payload, timeoutMs, signal2, _onLog, context) => {
54821
55502
  const input = worktreeMoveCheckoutJobPayload(payload);
54822
55503
  const rootFolder = await validateBranchRoot(input, timeoutMs, signal2);
54823
- const targetFolder = input.mode === "NEW" ? join24(
54824
- dirname13(rootFolder),
55504
+ const targetFolder = input.mode === "NEW" ? join25(
55505
+ dirname14(rootFolder),
54825
55506
  `${basename6(rootFolder)}-${input.branch.replaceAll("/", "-")}`
54826
55507
  ) : input.folder;
54827
55508
  const execute2 = () => finishMovedWorktree(input, rootFolder, timeoutMs, signal2);
@@ -54881,12 +55562,12 @@ async function finishMovedWorktree(input, rootFolder, timeoutMs, signal2) {
54881
55562
  `Branch ${input.branch} is already checked out in ${occupiedFolder}`
54882
55563
  );
54883
55564
  }
54884
- targetFolder = join24(
54885
- dirname13(rootFolder),
55565
+ targetFolder = join25(
55566
+ dirname14(rootFolder),
54886
55567
  `${basename6(rootFolder)}-${input.branch.replaceAll("/", "-")}`
54887
55568
  );
54888
55569
  try {
54889
- await stat11(targetFolder);
55570
+ await stat12(targetFolder);
54890
55571
  throw new Error(`Worktree folder already exists: ${targetFolder}`);
54891
55572
  } catch (error) {
54892
55573
  if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
@@ -55132,7 +55813,7 @@ var prepareWorktree = async (payload, timeoutMs, signal2) => {
55132
55813
  var deleteWorktree = async (payload, timeoutMs, signal2, _onLog, context) => {
55133
55814
  const input = worktreeDeleteJobPayload(payload);
55134
55815
  const rootFolder = await realpath12(input.rootFolder);
55135
- if (!(await stat11(rootFolder)).isDirectory()) {
55816
+ if (!(await stat12(rootFolder)).isDirectory()) {
55136
55817
  throw new Error("Base repository is missing");
55137
55818
  }
55138
55819
  if (await origin(rootFolder, timeoutMs, signal2) !== input.expectedOrigin) {
@@ -55605,7 +56286,7 @@ var operateWorktree = async (payload, timeoutMs, signal2) => {
55605
56286
  break;
55606
56287
  }
55607
56288
  case "CLEAR_LOCK":
55608
- await rm19(join24(input.gitDirectory, "index.lock"), { force: true });
56289
+ await rm19(join25(input.gitDirectory, "index.lock"), { force: true });
55609
56290
  break;
55610
56291
  case "STASH_ALL":
55611
56292
  await runGit(["stash", "push", "--include-untracked"], "Stash failed");
@@ -56924,22 +57605,43 @@ var CodebaseMonitor = class {
56924
57605
  signal2
56925
57606
  );
56926
57607
  if (fetchResult.exitCode === 0) {
56927
- if (codebase.keepBaseBranchUpToDate && codebase.defaultBranch) {
56928
- const baseBranch = codebase.defaultBranch;
56929
- await runExclusive(
56930
- () => updateBaseBranchAfterFetch(
56931
- codebase.folder,
56932
- baseBranch,
56933
- INSPECTION_TIMEOUT_MS,
56934
- signal2
56935
- )
56936
- );
56937
- }
56938
57608
  snapshot = await this.inspectRoot(codebase, signal2);
56939
57609
  } else {
56940
57610
  fetchError = (fetchResult.stderr || "Git fetch failed").replace(/([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+@/gi, "$1").slice(0, 2e3);
56941
57611
  }
56942
57612
  }
57613
+ if (snapshot.availability === "AVAILABLE" && codebase.keepBaseBranchUpToDate && !signal2.aborted) {
57614
+ await updateDefaultBranchesAfterFetch(
57615
+ codebase.folder,
57616
+ codebase.defaultBranch,
57617
+ codebase.defaultBranchPatterns ?? [],
57618
+ INSPECTION_TIMEOUT_MS,
57619
+ signal2,
57620
+ (folder, gitDirectory2, update) => this.agentId ? this.repositoryCoordinator.tryWithResources(
57621
+ [
57622
+ {
57623
+ kind: "WORKTREE",
57624
+ key: `${this.agentId}:worktree:${gitDirectory2}`,
57625
+ agentId: this.agentId,
57626
+ codebaseId: codebase.id,
57627
+ mode: "WRITE"
57628
+ },
57629
+ {
57630
+ kind: "PATH",
57631
+ key: folder,
57632
+ path: folder,
57633
+ agentId: this.agentId,
57634
+ codebaseId: codebase.id,
57635
+ mode: "WRITE"
57636
+ }
57637
+ ],
57638
+ update,
57639
+ signal2
57640
+ ) : runExclusive(update),
57641
+ codebase.canonicalOrigin
57642
+ );
57643
+ snapshot = await this.inspectRoot(codebase, signal2);
57644
+ }
56943
57645
  let inventory;
56944
57646
  try {
56945
57647
  inventory = await discoverWorktrees(
@@ -57042,7 +57744,7 @@ var CodebaseMonitor = class {
57042
57744
  import { execFile as execFile4 } from "node:child_process";
57043
57745
  import { createHash as createHash9, randomUUID as randomUUID12 } from "node:crypto";
57044
57746
  import { mkdir as mkdir10, rm as rm21, realpath as realpath13 } from "node:fs/promises";
57045
- import { dirname as dirname15, join as join26 } from "node:path";
57747
+ import { dirname as dirname16, join as join27 } from "node:path";
57046
57748
  import { promisify as promisify4 } from "node:util";
57047
57749
 
57048
57750
  // src/runs/journal.ts
@@ -57054,11 +57756,11 @@ import {
57054
57756
  readFile as readFile14,
57055
57757
  rename as rename9,
57056
57758
  rm as rm20,
57057
- stat as stat12,
57759
+ stat as stat13,
57058
57760
  truncate,
57059
57761
  writeFile as writeFile12
57060
57762
  } from "node:fs/promises";
57061
- import { dirname as dirname14, join as join25 } from "node:path";
57763
+ import { dirname as dirname15, join as join26 } from "node:path";
57062
57764
  var RunJournal = class {
57063
57765
  constructor(runId, attemptId) {
57064
57766
  this.runId = runId;
@@ -57078,13 +57780,13 @@ var RunJournal = class {
57078
57780
  this.attemptId = attemptId;
57079
57781
  }
57080
57782
  get directory() {
57081
- return join25(dirname14(configPath()), "runs", this.runId);
57783
+ return join26(dirname15(configPath()), "runs", this.runId);
57082
57784
  }
57083
57785
  get eventsPath() {
57084
- return join25(this.directory, "events.jsonl");
57786
+ return join26(this.directory, "events.jsonl");
57085
57787
  }
57086
57788
  get statePath() {
57087
- return join25(this.directory, "state.json");
57789
+ return join26(this.directory, "state.json");
57088
57790
  }
57089
57791
  async load() {
57090
57792
  if (this.loaded) return;
@@ -57106,7 +57808,7 @@ var RunJournal = class {
57106
57808
  if (!(error instanceof SyntaxError) && error.code !== "ENOENT")
57107
57809
  throw error;
57108
57810
  }
57109
- const size = await stat12(this.eventsPath).then(
57811
+ const size = await stat13(this.eventsPath).then(
57110
57812
  ({ size: size2 }) => size2,
57111
57813
  (error) => {
57112
57814
  if (error.code === "ENOENT") return 0;
@@ -58781,7 +59483,7 @@ var RunManager = class {
58781
59483
  5
58782
59484
  );
58783
59485
  await this.completeCommand(command3.id, "SUCCEEDED");
58784
- await rm21(join26(dirname15(configPath()), "runs", run.id, "attachments"), {
59486
+ await rm21(join27(dirname16(configPath()), "runs", run.id, "attachments"), {
58785
59487
  recursive: true,
58786
59488
  force: true
58787
59489
  }).catch(() => void 0);
@@ -58994,7 +59696,7 @@ var RunManager = class {
58994
59696
  this.active.delete(run.id);
58995
59697
  this.interruptionRequests.delete(run.id);
58996
59698
  this.executingCommands.delete(command3.id);
58997
- await rm21(join26(dirname15(configPath()), "runs", run.id, "attachments"), {
59699
+ await rm21(join27(dirname16(configPath()), "runs", run.id, "attachments"), {
58998
59700
  recursive: true,
58999
59701
  force: true
59000
59702
  }).catch(() => void 0);
@@ -59232,11 +59934,11 @@ var RunManager = class {
59232
59934
  }
59233
59935
  async stageAttachments(runId, attachments) {
59234
59936
  if (!attachments.length) return [];
59235
- const directory = join26(dirname15(configPath()), "runs", runId, "attachments");
59937
+ const directory = join27(dirname16(configPath()), "runs", runId, "attachments");
59236
59938
  await mkdir10(directory, { recursive: true, mode: 448 });
59237
59939
  return Promise.all(
59238
59940
  attachments.map(async (attachment) => {
59239
- const path = join26(
59941
+ const path = join27(
59240
59942
  directory,
59241
59943
  `${attachment.id}-${safeFilename(attachment.filename)}`
59242
59944
  );