@schoolai/shipyard 3.24.0 → 3.25.0

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 (29) hide show
  1. package/dist/capability-detector-worker.js +3 -3
  2. package/dist/{chunk-NG355H2L.js → chunk-BBKZIEKF.js} +68 -1
  3. package/dist/chunk-BBKZIEKF.js.map +1 -0
  4. package/dist/{chunk-BGJ6QJNS.js → chunk-FC3HWVYQ.js} +46 -1
  5. package/dist/{chunk-BGJ6QJNS.js.map → chunk-FC3HWVYQ.js.map} +1 -1
  6. package/dist/{chunk-JZTUQVHQ.js → chunk-IRS6HYMU.js} +2 -2
  7. package/dist/{chunk-UK3IMOSP.js → chunk-VQCBF7X5.js} +71 -7
  8. package/dist/chunk-VQCBF7X5.js.map +1 -0
  9. package/dist/{chunk-TU3MSY2I.js → chunk-X4IWMBWY.js} +2 -2
  10. package/dist/{chunk-DDC5OQOC.js → chunk-XNH6FVIX.js} +3 -3
  11. package/dist/{chunk-BN54GQR3.js → chunk-YTYPMVS4.js} +3 -53
  12. package/dist/chunk-YTYPMVS4.js.map +1 -0
  13. package/dist/cursor-runner.js +8 -4
  14. package/dist/cursor-runner.js.map +1 -1
  15. package/dist/electron-utility.js +2 -2
  16. package/dist/index.js +3 -3
  17. package/dist/{plan-backfill-XYOUK2DY.js → plan-backfill-SDYNTKUX.js} +3 -3
  18. package/dist/{serve-RWFBSQIE.js → serve-HTQMCHRP.js} +334 -188
  19. package/dist/{serve-RWFBSQIE.js.map → serve-HTQMCHRP.js.map} +1 -1
  20. package/dist/{start-ZV22UPMC.js → start-HOICUTYV.js} +4 -4
  21. package/package.json +1 -1
  22. package/dist/chunk-BN54GQR3.js.map +0 -1
  23. package/dist/chunk-NG355H2L.js.map +0 -1
  24. package/dist/chunk-UK3IMOSP.js.map +0 -1
  25. /package/dist/{chunk-JZTUQVHQ.js.map → chunk-IRS6HYMU.js.map} +0 -0
  26. /package/dist/{chunk-TU3MSY2I.js.map → chunk-X4IWMBWY.js.map} +0 -0
  27. /package/dist/{chunk-DDC5OQOC.js.map → chunk-XNH6FVIX.js.map} +0 -0
  28. /package/dist/{plan-backfill-XYOUK2DY.js.map → plan-backfill-SDYNTKUX.js.map} +0 -0
  29. /package/dist/{start-ZV22UPMC.js.map → start-HOICUTYV.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getDaemonVersion
4
- } from "./chunk-DDC5OQOC.js";
4
+ } from "./chunk-XNH6FVIX.js";
5
5
  import {
6
6
  WorkerCommandCodec,
7
7
  WorkerReplyCodec
@@ -1116,4 +1116,4 @@ export {
1116
1116
  shutdownFileWatcherGuard,
1117
1117
  guardedSubscribe
1118
1118
  };
1119
- //# sourceMappingURL=chunk-JZTUQVHQ.js.map
1119
+ //# sourceMappingURL=chunk-IRS6HYMU.js.map
@@ -31,7 +31,7 @@ import {
31
31
  parseShipyardDeliverableUrl,
32
32
  planEditorSerializer,
33
33
  toTaskIndexEntry
34
- } from "./chunk-BGJ6QJNS.js";
34
+ } from "./chunk-FC3HWVYQ.js";
35
35
  import {
36
36
  assertNever
37
37
  } from "./chunk-X3MULCV5.js";
@@ -7360,6 +7360,13 @@ var StorageAdapter = class extends Adapter {
7360
7360
  // src/shared/file-storage-adapter.ts
7361
7361
  import { access, mkdir, open, readdir, readFile, rename, unlink } from "fs/promises";
7362
7362
  import { dirname, join, sep } from "path";
7363
+ function errnoOf(err) {
7364
+ if (err !== null && typeof err === "object" && "code" in err) {
7365
+ const code = Reflect.get(err, "code");
7366
+ if (typeof code === "string") return code;
7367
+ }
7368
+ return "UNKNOWN";
7369
+ }
7363
7370
  var FileStorageAdapter = class _FileStorageAdapter extends StorageAdapter {
7364
7371
  #dataDir;
7365
7372
  /**
@@ -7490,6 +7497,12 @@ var FileStorageAdapter = class _FileStorageAdapter extends StorageAdapter {
7490
7497
  * Returns true if the directory for the given docId exists on disk.
7491
7498
  * Uses a single fs.access call — avoids loading any Loro data.
7492
7499
  * docId is the first key segment (e.g. "canvas:<taskId>:<epoch>").
7500
+ *
7501
+ * A truthy result means ONLY that the directory exists. `#saveAtomic` mkdir's
7502
+ * the chunk directory before the first `rename` lands, compaction can remove
7503
+ * every chunk under a directory it leaves in place, and a directory the
7504
+ * filesystem refuses to list still passes `access`. Callers asking "does real
7505
+ * data exist here?" must use {@link probeDocChunks} instead — see #5266.
7493
7506
  */
7494
7507
  async hasDoc(docId) {
7495
7508
  const dirPath = join(this.#dataDir, encodeURIComponent(docId));
@@ -7500,6 +7513,54 @@ var FileStorageAdapter = class _FileStorageAdapter extends StorageAdapter {
7500
7513
  return false;
7501
7514
  }
7502
7515
  }
7516
+ /**
7517
+ * What is ACTUALLY on disk for a docId: how many non-`.tmp` chunk files the
7518
+ * directory holds, or the errno if the filesystem refused to list it. Still
7519
+ * cheap — `readdir` only, no chunk bytes are read and no Loro import runs.
7520
+ *
7521
+ * Exists because `hasDoc`'s boolean cannot distinguish an empty directory from
7522
+ * one holding real chunks, nor either from an EACCES/EIO refusal, and a caller
7523
+ * that infers "dir exists therefore chunks exist therefore an empty read must be
7524
+ * a transient load failure" misdiagnoses a genuinely-empty doc (#5266).
7525
+ */
7526
+ async probeDocChunks(docId) {
7527
+ const dirPath = join(this.#dataDir, encodeURIComponent(docId));
7528
+ try {
7529
+ const chunkCount = await this.#countChunkFiles(dirPath);
7530
+ return chunkCount === 0 ? { kind: "absent" } : { kind: "chunks", chunkCount, path: dirPath };
7531
+ } catch (err) {
7532
+ const code = errnoOf(err);
7533
+ if (code === "ENOENT") return { kind: "absent" };
7534
+ return {
7535
+ kind: "unreadable",
7536
+ path: dirPath,
7537
+ code,
7538
+ message: err instanceof Error ? err.message : String(err)
7539
+ };
7540
+ }
7541
+ }
7542
+ /**
7543
+ * Chunk files under `dir`, recursively. A directory that does not exist — the
7544
+ * doc has never been written, or compaction removed a subtree mid-walk — counts
7545
+ * as zero, so the caller reports `absent`. Any OTHER errno propagates, so a
7546
+ * directory we were refused (EACCES/EIO/EMFILE) is reported as `unreadable`
7547
+ * rather than silently under-counted as an empty doc.
7548
+ */
7549
+ async #countChunkFiles(dir) {
7550
+ let entries;
7551
+ try {
7552
+ entries = await readdir(dir, { withFileTypes: true });
7553
+ } catch (err) {
7554
+ if (errnoOf(err) === "ENOENT") return 0;
7555
+ throw err;
7556
+ }
7557
+ let count = 0;
7558
+ for (const entry of entries) {
7559
+ if (entry.isDirectory()) count += await this.#countChunkFiles(join(dir, entry.name));
7560
+ else if (entry.isFile() && !entry.name.endsWith(".tmp")) count += 1;
7561
+ }
7562
+ return count;
7563
+ }
7503
7564
  async removeRange(keyPrefix) {
7504
7565
  if (isWholeDocumentKey(keyPrefix)) return;
7505
7566
  const chunks = await this.#collectChunks(keyPrefix);
@@ -33518,9 +33579,12 @@ function replay(planRepo, taskId, versions) {
33518
33579
  });
33519
33580
  }
33520
33581
  }
33521
- function resolveFileFallback(taskId, sources) {
33522
- if (sources.planVersions.length > 0 || !sources.planFilePath) return Promise.resolve(null);
33523
- return readPlanFileFallback(sources.planFilePath, taskId);
33582
+ async function resolveFileFallback(taskId, sources, bookmarks) {
33583
+ if (sources.planVersions.length > 0 || !sources.planFilePath) return null;
33584
+ const version = await readPlanFileFallback(sources.planFilePath, taskId);
33585
+ if (!version) return null;
33586
+ if (bookmarks?.hasVersionBookmark(taskId, version.timestamp, version.toolUseId)) return null;
33587
+ return version;
33524
33588
  }
33525
33589
 
33526
33590
  // src/services/plan-backfill/plan-backfill-executor.ts
@@ -33660,7 +33724,7 @@ async function processDryRunTask(ctx, docId, isResident) {
33660
33724
  ctx.deps.shipyardHome
33661
33725
  );
33662
33726
  const hasOnDiskPlanDoc = await ctx.adapter.hasDoc(docId);
33663
- const fileFallback = await resolveFileFallback(ctx.taskId, sources);
33727
+ const fileFallback = await resolveFileFallback(ctx.taskId, sources, null);
33664
33728
  return planBackfill({
33665
33729
  taskId: ctx.taskId,
33666
33730
  docHasContent: hasOnDiskPlanDoc,
@@ -33683,7 +33747,7 @@ async function processWriteTask(ctx, iso, docId, isResident) {
33683
33747
  );
33684
33748
  const hasOnDiskPlanDoc = await ctx.adapter.hasDoc(docId);
33685
33749
  const docHasContent = await checkContent(iso, ctx.taskId, hasOnDiskPlanDoc, isResident);
33686
- const fileFallback = await resolveFileFallback(ctx.taskId, sources);
33750
+ const fileFallback = await resolveFileFallback(ctx.taskId, sources, iso.planRepo);
33687
33751
  const action = planBackfill({
33688
33752
  taskId: ctx.taskId,
33689
33753
  docHasContent,
@@ -34783,4 +34847,4 @@ export {
34783
34847
  runPlanBackfill,
34784
34848
  buildTaskStateStore
34785
34849
  };
34786
- //# sourceMappingURL=chunk-UK3IMOSP.js.map
34850
+ //# sourceMappingURL=chunk-VQCBF7X5.js.map