@schoolai/shipyard 3.2.3-rc.20260422.2 → 3.2.3-rc.20260422.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -106,7 +106,7 @@ async function handleSubcommand() {
106
106
  return true;
107
107
  }
108
108
  if (subcommand === "start") {
109
- const { startCommand } = await import("./start-4KHICMP2.js");
109
+ const { startCommand } = await import("./start-NH5IIB6O.js");
110
110
  await startCommand();
111
111
  return true;
112
112
  }
@@ -123,7 +123,7 @@ async function main() {
123
123
  const args = parseCliArgs();
124
124
  if (args.serve) {
125
125
  await loadAuthFromConfig(env);
126
- const { serve } = await import("./serve-3FTGY4YL.js");
126
+ const { serve } = await import("./serve-ZAI7K2HR.js");
127
127
  return serve({ isDev: env.SHIPYARD_DEV });
128
128
  }
129
129
  logger.error("Use `shipyard start` to run the daemon. Use --help for usage.");
@@ -87774,6 +87774,7 @@ function skipForMainChannel(content) {
87774
87774
 
87775
87775
  // src/services/plan/plan-handler.ts
87776
87776
  import { existsSync as existsSync7, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
87777
+ import { readFile as readFile30 } from "fs/promises";
87777
87778
  import { homedir as homedir4 } from "os";
87778
87779
  import { join as join39 } from "path";
87779
87780
 
@@ -87851,6 +87852,80 @@ var PlanFileBridge = class _PlanFileBridge {
87851
87852
  });
87852
87853
  }, PERIODIC_REREAD_MS);
87853
87854
  }
87855
+ /**
87856
+ * Re-initialize the bridge for a plan file known from a prior daemon session.
87857
+ *
87858
+ * Differs from `attach()` in that the caller explicitly decides whether to
87859
+ * preserve CRDT content. This lets PlanHandler do a three-way compare
87860
+ * (file vs CRDT vs last stored PlanVersion) and tell the bridge which side
87861
+ * is authoritative:
87862
+ *
87863
+ * - `preserveCrdt: false` — file is truth (fresh daemon start, or Claude
87864
+ * rewrote the plan while the daemon was down). Overwrite CRDT with file
87865
+ * content, same as `attach()`.
87866
+ * - `preserveCrdt: true` — CRDT has edits not yet written to disk (browser
87867
+ * edited before the daemon's debounced write-back fired). Keep CRDT
87868
+ * content; the subscription below will flush it on the next loro change.
87869
+ *
87870
+ * Returns `{ fileContent }` so callers can emit catch-up versions, or
87871
+ * `null` if the file is unreadable.
87872
+ */
87873
+ async reattach(filePath, options) {
87874
+ if (this.#disposed) return null;
87875
+ this.#dirWatcher?.close();
87876
+ this.#dirWatcher = null;
87877
+ this.#crdtUnsub?.();
87878
+ this.#crdtUnsub = null;
87879
+ if (this.#periodicRereadTimer) {
87880
+ clearInterval(this.#periodicRereadTimer);
87881
+ this.#periodicRereadTimer = null;
87882
+ }
87883
+ let fileContent;
87884
+ try {
87885
+ fileContent = await this.#readFileWithRetry(filePath);
87886
+ } catch (err) {
87887
+ this.#config.log({
87888
+ event: "plan_bridge_reattach_read_failed",
87889
+ taskId: this.#config.taskId,
87890
+ filePath,
87891
+ error: err instanceof Error ? err.message : String(err)
87892
+ });
87893
+ return null;
87894
+ }
87895
+ this.#filePath = filePath;
87896
+ this.#config.planRepo.setMetadata(this.#config.taskId, filePath);
87897
+ this.#lastWrittenHash = contentHash(fileContent);
87898
+ if (!options.preserveCrdt) {
87899
+ this.#config.planRepo.updateContent(this.#config.taskId, fileContent);
87900
+ }
87901
+ this.#hasAttachedContent = true;
87902
+ this.#config.log({
87903
+ event: "plan_bridge_reattached",
87904
+ taskId: this.#config.taskId,
87905
+ filePath,
87906
+ crdtPreserved: options.preserveCrdt,
87907
+ fileLength: fileContent.length
87908
+ });
87909
+ this.#startDirectoryWatcher(filePath);
87910
+ this.#startCrdtSubscription();
87911
+ this.#periodicRereadTimer = setInterval(() => {
87912
+ this.#handleFileChanged().catch(() => {
87913
+ });
87914
+ }, PERIODIC_REREAD_MS);
87915
+ if (options.preserveCrdt) {
87916
+ try {
87917
+ await this.flushWriteBack();
87918
+ } catch (err) {
87919
+ this.#config.log({
87920
+ event: "plan_bridge_reattach_flush_failed",
87921
+ taskId: this.#config.taskId,
87922
+ filePath,
87923
+ error: err instanceof Error ? err.message : String(err)
87924
+ });
87925
+ }
87926
+ }
87927
+ return { fileContent };
87928
+ }
87854
87929
  /**
87855
87930
  * Watch the plans DIRECTORY (not the file) for changes.
87856
87931
  * This survives inode changes from atomic writes (tmp + rename).
@@ -88273,8 +88348,177 @@ var PlanHandler = class {
88273
88348
  this.#lastPersistedPlanDetection = deps.initialPlanDetection;
88274
88349
  this.#planPublished = true;
88275
88350
  this.#processedPlanToolUseIds.add(deps.initialPlanDetection.toolUseId);
88351
+ const seedFilePath = deps.initialPlanDetection.filePath;
88352
+ const seedToolUseId = deps.initialPlanDetection.toolUseId;
88353
+ deps.enqueueAsync(() => this.#rehydratePlanFileBridge(seedFilePath, seedToolUseId));
88354
+ }
88355
+ }
88356
+ async #rehydratePlanFileBridge(filePath, toolUseId) {
88357
+ if (this.#deps.isDisposed()) return;
88358
+ if (!existsSync7(filePath)) {
88359
+ this.#deps.log({
88360
+ event: "plan_bridge_rehydrate_file_missing",
88361
+ taskId: this.#deps.taskId,
88362
+ filePath
88363
+ });
88364
+ return;
88365
+ }
88366
+ const fileContent = await this.#readFileForRehydrate(filePath);
88367
+ if (fileContent === null || this.#deps.isDisposed()) return;
88368
+ const versions = await this.#deps.annotationStore.getPlanVersions(this.#deps.taskId);
88369
+ if (this.#deps.isDisposed()) return;
88370
+ const lastVersionMarkdown = versions.at(-1)?.markdown ?? "";
88371
+ const preserveCrdt = this.#shouldPreserveCrdt(fileContent, lastVersionMarkdown);
88372
+ const result = await this.#ensureBridgeAttached(filePath, toolUseId, {
88373
+ mode: "rehydrate",
88374
+ preserveCrdt
88375
+ });
88376
+ if (!result || this.#deps.isDisposed()) return;
88377
+ await this.#maybeEmitRehydrateCatchup(lastVersionMarkdown, preserveCrdt, toolUseId);
88378
+ }
88379
+ /**
88380
+ * Three-way compare of {file on disk, CRDT content, last stored PlanVersion}:
88381
+ *
88382
+ * Case 1 (all equal) → preserveCrdt=false (no-op attach)
88383
+ * Case 2 (file drifted) → preserveCrdt=false (file wins)
88384
+ * Case 3 (browser-edited CRDT) → preserveCrdt=true (keep in-flight edits)
88385
+ * Case 4 (both drifted) → preserveCrdt=false (file wins)
88386
+ *
88387
+ * Case 3 also requires a non-empty lastVersionMarkdown — otherwise a
88388
+ * brand-new task with no prior stored versions would preserve whatever
88389
+ * happens to be in CRDT (e.g. a stale browser session's edits on a fresh
88390
+ * epoch) over an authoritative empty file.
88391
+ */
88392
+ #shouldPreserveCrdt(fileContent, lastVersionMarkdown) {
88393
+ if (lastVersionMarkdown === "") return false;
88394
+ const crdtContent = this.#deps.planRepo.getContent(this.#deps.taskId);
88395
+ const fileMatchesLast = fileContent === lastVersionMarkdown;
88396
+ const crdtHasUnsavedEdits = crdtContent.length > 0 && crdtContent !== lastVersionMarkdown;
88397
+ return fileMatchesLast && crdtHasUnsavedEdits;
88398
+ }
88399
+ /**
88400
+ * Post-attach catch-up: read whatever CRDT now holds (file content or
88401
+ * preserved CRDT content) and emit a single version if it drifted from
88402
+ * `lastVersionMarkdown`. Covers file-drifted and browser-edited cases.
88403
+ *
88404
+ * Source labeling follows authoritative side: preserved CRDT = 'human',
88405
+ * file-overwritten CRDT = 'agent'. Mislabeling would corrupt
88406
+ * `findLastAgentVersion`'s baseline for plan-review diffs.
88407
+ */
88408
+ async #maybeEmitRehydrateCatchup(lastVersionMarkdown, preserveCrdt, toolUseId) {
88409
+ const postAttachMarkdown = this.#deps.planRepo.getContent(this.#deps.taskId);
88410
+ if (postAttachMarkdown.length === 0 || postAttachMarkdown === lastVersionMarkdown) return;
88411
+ const source = preserveCrdt ? "human" : "agent";
88412
+ await this.#emitCatchupVersion(postAttachMarkdown, toolUseId, source);
88413
+ }
88414
+ async #readFileForRehydrate(filePath) {
88415
+ try {
88416
+ return await readFile30(filePath, "utf-8");
88417
+ } catch (err) {
88418
+ this.#deps.log({
88419
+ event: "plan_bridge_rehydrate_read_failed",
88420
+ taskId: this.#deps.taskId,
88421
+ filePath,
88422
+ error: err instanceof Error ? err.message : String(err)
88423
+ });
88424
+ return null;
88425
+ }
88426
+ }
88427
+ async #emitCatchupVersion(markdown, toolUseId, source) {
88428
+ const version = {
88429
+ markdown,
88430
+ timestamp: Date.now(),
88431
+ source,
88432
+ toolUseId
88433
+ };
88434
+ try {
88435
+ await this.#deps.annotationStore.addPlanVersion(this.#deps.taskId, version);
88436
+ const msg = {
88437
+ type: "annotation_version_added",
88438
+ taskId: this.#deps.taskId,
88439
+ version
88440
+ };
88441
+ const send = this.#deps.getSendControlMessage();
88442
+ if (send) {
88443
+ send(msg);
88444
+ } else {
88445
+ this.#deps.enqueueControlMessage(msg);
88446
+ }
88447
+ } catch (err) {
88448
+ this.#deps.log({
88449
+ event: "plan_version_add_failed",
88450
+ taskId: this.#deps.taskId,
88451
+ error: err instanceof Error ? err.message : String(err)
88452
+ });
88276
88453
  }
88277
88454
  }
88455
+ /**
88456
+ * Ensure a PlanFileBridge is attached for this task at the given file path.
88457
+ * Creates the bridge lazily and routes attach vs reattach based on options:
88458
+ *
88459
+ * - `mode: 'fresh'` — new ExitPlanMode cycle, no prior context. Uses
88460
+ * `attach()` which overwrites CRDT with file content.
88461
+ * - `mode: 'rehydrate'` — daemon restart. Uses `reattach()` with an
88462
+ * explicit `preserveCrdt` flag so the caller's three-way compare picks
88463
+ * the authoritative side.
88464
+ *
88465
+ * Noop if the bridge is already attached to the same filePath. Re-attaches
88466
+ * if the bridge points at a different filePath (Scenario A: a 2nd
88467
+ * ExitPlanMode cycle writes to a new UUID).
88468
+ */
88469
+ async #ensureBridgeAttached(filePath, toolUseId, options) {
88470
+ if (this.#deps.isDisposed()) return null;
88471
+ const isFirstAttach = !this.#planFileBridge;
88472
+ if (!this.#planFileBridge) {
88473
+ this.#planFileBridge = this.#createPlanFileBridge(toolUseId);
88474
+ } else if (this.#planFileBridge.filePath === filePath) {
88475
+ return { isFirstAttach: false };
88476
+ }
88477
+ if (options.mode === "rehydrate") {
88478
+ const result = await this.#planFileBridge.reattach(filePath, {
88479
+ preserveCrdt: options.preserveCrdt
88480
+ });
88481
+ if (!result) return null;
88482
+ } else {
88483
+ await this.#planFileBridge.attach(filePath);
88484
+ }
88485
+ if (this.#deps.isDisposed()) return null;
88486
+ return { isFirstAttach };
88487
+ }
88488
+ #createPlanFileBridge(fallbackToolUseId) {
88489
+ return new PlanFileBridge({
88490
+ taskId: this.#deps.taskId,
88491
+ planRepo: this.#deps.planRepo,
88492
+ log: this.#deps.log,
88493
+ onBeforeContentUpdate: (currentMarkdown) => {
88494
+ const version = {
88495
+ markdown: currentMarkdown,
88496
+ timestamp: Date.now(),
88497
+ source: "agent",
88498
+ toolUseId: this.#lastPlanDetection?.toolUseId ?? fallbackToolUseId
88499
+ };
88500
+ this.#deps.annotationStore.addPlanVersion(this.#deps.taskId, version).then(() => {
88501
+ const msg = {
88502
+ type: "annotation_version_added",
88503
+ taskId: this.#deps.taskId,
88504
+ version
88505
+ };
88506
+ const send = this.#deps.getSendControlMessage();
88507
+ if (send) {
88508
+ send(msg);
88509
+ } else {
88510
+ this.#deps.enqueueControlMessage(msg);
88511
+ }
88512
+ }).catch((err) => {
88513
+ this.#deps.log({
88514
+ event: "plan_version_add_failed",
88515
+ taskId: this.#deps.taskId,
88516
+ error: err instanceof Error ? err.message : String(err)
88517
+ });
88518
+ });
88519
+ }
88520
+ });
88521
+ }
88278
88522
  /**
88279
88523
  * Persist a detection (or null clear) with shadow-pending semantics:
88280
88524
  * optimistically update #lastPlanDetection so concurrent reads see the new
@@ -88410,9 +88654,10 @@ var PlanHandler = class {
88410
88654
  });
88411
88655
  }
88412
88656
  detectPlanEvents(content) {
88413
- if (this.#approvalReceived || this.#planPublished) return;
88657
+ if (this.#approvalReceived) return;
88414
88658
  for (const block2 of content) {
88415
88659
  if (block2.type !== "tool_use" || block2.toolName !== "ExitPlanMode") continue;
88660
+ if (this.#processedPlanToolUseIds.has(block2.toolUseId)) continue;
88416
88661
  this.#deps.log({
88417
88662
  event: "exit_plan_mode_detected",
88418
88663
  taskId: this.#deps.taskId,
@@ -88577,51 +88822,32 @@ var PlanHandler = class {
88577
88822
  this.#pendingPlanAllowedPrompts.delete(toolUseId);
88578
88823
  this.#deps.enqueueAsync(async () => {
88579
88824
  if (this.#deps.isDisposed()) return;
88580
- const isFirstAttach = !this.#planFileBridge;
88581
- if (!this.#planFileBridge) {
88582
- this.#planFileBridge = new PlanFileBridge({
88583
- taskId: this.#deps.taskId,
88584
- planRepo: this.#deps.planRepo,
88585
- log: this.#deps.log,
88586
- onBeforeContentUpdate: (currentMarkdown) => {
88587
- const version = {
88588
- markdown: currentMarkdown,
88589
- timestamp: Date.now(),
88590
- source: "agent",
88591
- toolUseId: this.#lastPlanDetection?.toolUseId ?? toolUseId
88592
- };
88593
- this.#deps.annotationStore.addPlanVersion(this.#deps.taskId, version).then(() => {
88594
- this.#deps.getSendControlMessage()?.({
88595
- type: "annotation_version_added",
88596
- taskId: this.#deps.taskId,
88597
- version
88598
- });
88599
- }).catch((err) => {
88600
- this.#deps.log({
88601
- event: "plan_version_add_failed",
88602
- taskId: this.#deps.taskId,
88603
- error: err instanceof Error ? err.message : String(err)
88604
- });
88605
- });
88606
- }
88607
- });
88608
- }
88609
- await this.#planFileBridge.attach(filePath);
88825
+ const attachResult = await this.#ensureBridgeAttached(filePath, toolUseId, {
88826
+ mode: "fresh"
88827
+ });
88828
+ if (!attachResult) return;
88610
88829
  const markdown = this.#deps.planRepo.getContent(this.#deps.taskId);
88611
- if (isFirstAttach && markdown.length > 0) {
88612
- const initialVersion = {
88613
- markdown,
88614
- timestamp: Date.now(),
88615
- source: "agent",
88616
- toolUseId
88617
- };
88618
- await this.#deps.annotationStore.addPlanVersion(this.#deps.taskId, initialVersion);
88619
- this.#deps.getSendControlMessage()?.({
88620
- type: "annotation_version_added",
88621
- taskId: this.#deps.taskId,
88622
- version: initialVersion
88623
- });
88830
+ if (markdown.length > 0) {
88831
+ const existingVersions = await this.#deps.annotationStore.getPlanVersions(
88832
+ this.#deps.taskId
88833
+ );
88834
+ const lastVersion = existingVersions.at(-1);
88835
+ if (lastVersion?.markdown !== markdown) {
88836
+ const initialVersion = {
88837
+ markdown,
88838
+ timestamp: Date.now(),
88839
+ source: "agent",
88840
+ toolUseId
88841
+ };
88842
+ await this.#deps.annotationStore.addPlanVersion(this.#deps.taskId, initialVersion);
88843
+ this.#deps.getSendControlMessage()?.({
88844
+ type: "annotation_version_added",
88845
+ taskId: this.#deps.taskId,
88846
+ version: initialVersion
88847
+ });
88848
+ }
88624
88849
  }
88850
+ const isFirstAttach = attachResult.isFirstAttach;
88625
88851
  const pendingDetection = {
88626
88852
  toolUseId,
88627
88853
  filePath,
@@ -90109,7 +90335,7 @@ var RewindCheckpointHandler = class {
90109
90335
  };
90110
90336
 
90111
90337
  // src/services/task/side-thread-registry.ts
90112
- import { mkdir as mkdir17, readFile as readFile30, rename as rename17, writeFile as writeFile23 } from "fs/promises";
90338
+ import { mkdir as mkdir17, readFile as readFile31, rename as rename17, writeFile as writeFile23 } from "fs/promises";
90113
90339
  import { dirname as dirname15, join as join40 } from "path";
90114
90340
  var ThreadFileSchema = external_exports.object({
90115
90341
  threads: external_exports.record(external_exports.string(), ThreadMetadataSchema)
@@ -90443,7 +90669,7 @@ var SideThreadRegistry = class {
90443
90669
  const filePath = this.#filePath();
90444
90670
  let raw;
90445
90671
  try {
90446
- raw = await readFile30(filePath, "utf-8");
90672
+ raw = await readFile31(filePath, "utf-8");
90447
90673
  } catch (err) {
90448
90674
  if (isEnoent(err)) return;
90449
90675
  throw err;
@@ -90882,7 +91108,7 @@ async function resolveResources(ctx, content, history2, excludeUris) {
90882
91108
 
90883
91109
  // src/services/task/cc-task-file-store.ts
90884
91110
  import { watch as watch4 } from "fs";
90885
- import { readdir as readdir9, readFile as readFile31 } from "fs/promises";
91111
+ import { readdir as readdir9, readFile as readFile32 } from "fs/promises";
90886
91112
  import { homedir as homedir6 } from "os";
90887
91113
  import { basename as basename4, dirname as dirname16, join as join41 } from "path";
90888
91114
  var VALID_STATUSES2 = /* @__PURE__ */ new Set(["pending", "in_progress", "completed"]);
@@ -90918,7 +91144,7 @@ function createCCTaskFileWatcher(listId, log) {
90918
91144
  async function readTask(taskId) {
90919
91145
  const filePath = join41(dir, `${taskId}.json`);
90920
91146
  try {
90921
- const raw = await readFile31(filePath, "utf-8");
91147
+ const raw = await readFile32(filePath, "utf-8");
90922
91148
  const parsed = JSON.parse(raw);
90923
91149
  if (isCCTaskFile(parsed)) return parsed;
90924
91150
  log?.({
@@ -97178,7 +97404,7 @@ function isPlainObject2(v2) {
97178
97404
  }
97179
97405
 
97180
97406
  // src/services/themes/theme-store.ts
97181
- import { mkdir as mkdir19, readdir as readdir11, readFile as readFile32, rename as rename19, stat as stat8, unlink as unlink9, writeFile as writeFile26 } from "fs/promises";
97407
+ import { mkdir as mkdir19, readdir as readdir11, readFile as readFile33, rename as rename19, stat as stat8, unlink as unlink9, writeFile as writeFile26 } from "fs/promises";
97182
97408
  import { join as join47 } from "path";
97183
97409
  function planSeed(input) {
97184
97410
  if (input.configExists) {
@@ -97258,7 +97484,7 @@ function buildThemeStore(dataDir) {
97258
97484
  }
97259
97485
  async function readConfigFile() {
97260
97486
  try {
97261
- const raw = await readFile32(configPath, "utf-8");
97487
+ const raw = await readFile33(configPath, "utf-8");
97262
97488
  const parsed = ThemeConfigSchema.safeParse(JSON.parse(raw));
97263
97489
  if (!parsed.success) return null;
97264
97490
  return parsed.data;
@@ -97277,7 +97503,7 @@ function buildThemeStore(dataDir) {
97277
97503
  await atomicWrite3(themePath(id), serialized);
97278
97504
  }
97279
97505
  async function readThemeFile(id) {
97280
- const raw = await readFile32(themePath(id), "utf-8");
97506
+ const raw = await readFile33(themePath(id), "utf-8");
97281
97507
  const parsed = VSCodeThemeSchema.safeParse(JSON.parse(raw));
97282
97508
  if (!parsed.success) {
97283
97509
  throw new Error(
@@ -97429,7 +97655,7 @@ function buildThemeStore(dataDir) {
97429
97655
  }
97430
97656
 
97431
97657
  // src/services/themes/vscode-scanner.ts
97432
- import { readdir as readdir12, readFile as readFile33, stat as stat9 } from "fs/promises";
97658
+ import { readdir as readdir12, readFile as readFile34, stat as stat9 } from "fs/promises";
97433
97659
  import { homedir as homedir8 } from "os";
97434
97660
  import { dirname as dirname17, join as join48, normalize as normalize5, resolve } from "path";
97435
97661
  var VSCodeThemeEntrySchema2 = external_exports.object({
@@ -97488,7 +97714,7 @@ var PackageJsonContribSchema = external_exports.object({
97488
97714
  async function tryReadPackageJson(extDir) {
97489
97715
  let pkgRaw;
97490
97716
  try {
97491
- pkgRaw = await readFile33(join48(extDir, "package.json"), "utf-8");
97717
+ pkgRaw = await readFile34(join48(extDir, "package.json"), "utf-8");
97492
97718
  } catch {
97493
97719
  return null;
97494
97720
  }
@@ -97558,7 +97784,7 @@ async function readVSCodeThemeWithIncludes(absolutePath) {
97558
97784
  if (!validateScanPath(filePath)) {
97559
97785
  throw new Error(`Include path outside allowed directories: ${filePath}`);
97560
97786
  }
97561
- const raw = await readFile33(filePath, "utf-8");
97787
+ const raw = await readFile34(filePath, "utf-8");
97562
97788
  const errors2 = [];
97563
97789
  const parsed = parse3(raw, errors2, {
97564
97790
  allowTrailingComma: true,
@@ -102221,7 +102447,7 @@ function createCollabRoomManager(deps) {
102221
102447
 
102222
102448
  // src/services/file-io-handler.ts
102223
102449
  import { execFile as execFile10, spawn as spawn6 } from "child_process";
102224
- import { readdir as readdir14, readFile as readFile34, realpath as realpath2, stat as stat10, unlink as unlink10, writeFile as writeFile28 } from "fs/promises";
102450
+ import { readdir as readdir14, readFile as readFile35, realpath as realpath2, stat as stat10, unlink as unlink10, writeFile as writeFile28 } from "fs/promises";
102225
102451
  import { normalize as normalize7, relative as relative3, resolve as resolve2 } from "path";
102226
102452
  import { promisify as promisify7 } from "util";
102227
102453
 
@@ -102689,7 +102915,7 @@ function handleFileIOChannel(initialCwd, send, log, deps) {
102689
102915
  respondError(requestId, "File too large (>10MB)");
102690
102916
  return;
102691
102917
  }
102692
- const content = await readFile34(absPath, "utf-8");
102918
+ const content = await readFile35(absPath, "utf-8");
102693
102919
  respond({ type: "file_content", requestId, content });
102694
102920
  } catch (err) {
102695
102921
  respondError(requestId, formatError(err));
@@ -102883,7 +103109,7 @@ function handleFileIOChannel(initialCwd, send, log, deps) {
102883
103109
  const originalContent = await readGitObject(`${mergeBase}:${filePath}`) ?? "";
102884
103110
  let modifiedContent;
102885
103111
  try {
102886
- modifiedContent = await readFile34(resolve2(cwd, filePath), "utf-8");
103112
+ modifiedContent = await readFile35(resolve2(cwd, filePath), "utf-8");
102887
103113
  } catch {
102888
103114
  modifiedContent = "";
102889
103115
  }
@@ -102940,7 +103166,7 @@ function handleFileIOChannel(initialCwd, send, log, deps) {
102940
103166
  const indexContent = await readGitObject(`:${safeRelPath}`);
102941
103167
  originalContent = indexContent ?? await readGitObject(`HEAD:${safeRelPath}`) ?? "";
102942
103168
  try {
102943
- modifiedContent = await readFile34(absPath, "utf-8");
103169
+ modifiedContent = await readFile35(absPath, "utf-8");
102944
103170
  } catch {
102945
103171
  modifiedContent = "";
102946
103172
  }
@@ -104312,7 +104538,7 @@ import { dirname as dirname21, join as join54 } from "path";
104312
104538
  // src/services/bootstrap/self-update.ts
104313
104539
  import { execFile as execFile11, spawn as spawn8 } from "child_process";
104314
104540
  import { createHash as createHash6 } from "crypto";
104315
- import { chmod as chmod3, mkdir as mkdir22, readFile as readFile35, rename as rename20, unlink as unlink11, writeFile as writeFile29 } from "fs/promises";
104541
+ import { chmod as chmod3, mkdir as mkdir22, readFile as readFile36, rename as rename20, unlink as unlink11, writeFile as writeFile29 } from "fs/promises";
104316
104542
  import { join as join53 } from "path";
104317
104543
 
104318
104544
  // src/services/bootstrap/self-update-installer-scripts.ts
@@ -104734,7 +104960,7 @@ async function downloadTarball(url, destPath, fetchFn) {
104734
104960
  }
104735
104961
  async function verifyChecksum(path2, expectedHash) {
104736
104962
  const algo = expectedHash.length === 40 ? "sha1" : "sha256";
104737
- const raw = await readFile35(path2);
104963
+ const raw = await readFile36(path2);
104738
104964
  const actual = createHash6(algo).update(raw).digest("hex");
104739
104965
  if (actual !== expectedHash) {
104740
104966
  try {
@@ -105485,7 +105711,7 @@ function buildLocalDirectChannelCallbacks(deps) {
105485
105711
 
105486
105712
  // src/services/storage/daemon-settings-store.ts
105487
105713
  import { createHash as createHash7 } from "crypto";
105488
- import { mkdir as mkdir23, readFile as readFile36, rename as rename21, writeFile as writeFile30 } from "fs/promises";
105714
+ import { mkdir as mkdir23, readFile as readFile37, rename as rename21, writeFile as writeFile30 } from "fs/promises";
105489
105715
  import { join as join55 } from "path";
105490
105716
  var ProjectSettingsSchema = external_exports.object({
105491
105717
  disabledMcpServers: external_exports.array(external_exports.string()).optional()
@@ -105504,7 +105730,7 @@ function buildDaemonSettingsStore(dataDir) {
105504
105730
  return {
105505
105731
  async load(projectPath) {
105506
105732
  try {
105507
- const raw = await readFile36(settingsPath(projectPath), "utf-8");
105733
+ const raw = await readFile37(settingsPath(projectPath), "utf-8");
105508
105734
  return ProjectSettingsSchema.parse(JSON.parse(raw));
105509
105735
  } catch (err) {
105510
105736
  if (isEnoent(err)) return {};
@@ -105522,7 +105748,7 @@ function buildDaemonSettingsStore(dataDir) {
105522
105748
  }
105523
105749
 
105524
105750
  // src/services/storage/plugin-config-store.ts
105525
- import { mkdir as mkdir24, readFile as readFile37, rename as rename22, writeFile as writeFile31 } from "fs/promises";
105751
+ import { mkdir as mkdir24, readFile as readFile38, rename as rename22, writeFile as writeFile31 } from "fs/promises";
105526
105752
  import { join as join56 } from "path";
105527
105753
  function buildPluginConfigStore(pluginsDir) {
105528
105754
  const cache2 = /* @__PURE__ */ new Map();
@@ -105534,7 +105760,7 @@ function buildPluginConfigStore(pluginsDir) {
105534
105760
  const cached2 = cache2.get(pluginId);
105535
105761
  if (cached2) return cached2;
105536
105762
  try {
105537
- const raw = await readFile37(configPath(pluginId), "utf-8");
105763
+ const raw = await readFile38(configPath(pluginId), "utf-8");
105538
105764
  const parsed = JSON.parse(raw);
105539
105765
  if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
105540
105766
  const record = Object.fromEntries(Object.entries(parsed));
@@ -105949,4 +106175,4 @@ export {
105949
106175
  _testing,
105950
106176
  serve
105951
106177
  };
105952
- //# sourceMappingURL=serve-3FTGY4YL.js.map
106178
+ //# sourceMappingURL=serve-ZAI7K2HR.js.map