repo-dive 0.16.3 → 0.16.4

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/cli.js CHANGED
@@ -11,7 +11,7 @@ import path, * as Path from "node:path";
11
11
  import { DatabaseSync } from "node:sqlite";
12
12
  import * as NodeUrl from "node:url";
13
13
  import { fileURLToPath, pathToFileURL } from "node:url";
14
- import { access, mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises";
14
+ import { access, mkdir, mkdtemp, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
15
15
  import * as readline from "node:readline";
16
16
  import { registerHooks } from "node:module";
17
17
  //#region node_modules/.pnpm/effect@4.0.0/node_modules/effect/dist/Pipeable.js
@@ -8720,6 +8720,8 @@ var AsyncFiberError = class extends (/*#__PURE__*/ TaggedError$2("AsyncFiberErro
8720
8720
  /** @internal */
8721
8721
  var UnknownErrorTypeId = "~effect/Cause/UnknownError";
8722
8722
  /** @internal */
8723
+ var isUnknownError$1 = (u) => hasProperty(u, UnknownErrorTypeId);
8724
+ /** @internal */
8723
8725
  var UnknownError$2 = class extends (/*#__PURE__*/ TaggedError$2("UnknownError")) {
8724
8726
  [UnknownErrorTypeId] = UnknownErrorTypeId;
8725
8727
  constructor(cause, message) {
@@ -11188,6 +11190,22 @@ var IllegalArgumentError = IllegalArgumentError$1;
11188
11190
  */
11189
11191
  var ExceededCapacityError = ExceededCapacityError$1;
11190
11192
  /**
11193
+ * Checks whether an arbitrary value is an `UnknownError`.
11194
+ *
11195
+ * **Example** (Checking the runtime type)
11196
+ *
11197
+ * ```ts import.meta.vitest
11198
+ * import { Cause } from "effect"
11199
+ *
11200
+ * Cause.isUnknownError(new Cause.UnknownError("x")) // => true
11201
+ * Cause.isUnknownError("nope") // => false
11202
+ * ```
11203
+ *
11204
+ * @category guards
11205
+ * @since 4.0.0
11206
+ */
11207
+ var isUnknownError = isUnknownError$1;
11208
+ /**
11191
11209
  * Constructs an `UnknownError`. The first argument is the original
11192
11210
  * cause (stored in `Error.cause`); the second is an optional human-readable
11193
11211
  * message.
@@ -26041,7 +26059,7 @@ var concatTokens = (prevTokens, nextTokens, isSeparated) => isSeparated || prevT
26041
26059
  ...nextTokens.slice(1)
26042
26060
  ];
26043
26061
  //#endregion
26044
- //#region node_modules/.pnpm/@effect+platform-node-shared@4.0.2_effect@4.0.0/node_modules/@effect/platform-node-shared/dist/internal/nodeChildProcessSpawner.js
26062
+ //#region node_modules/.pnpm/@effect+platform-node-shared@4.0.3_effect@4.0.0/node_modules/@effect/platform-node-shared/dist/internal/nodeChildProcessSpawner.js
26045
26063
  var buildSpawnOptions = (options, base, platform) => {
26046
26064
  const detached = options.detached ?? platform !== "win32";
26047
26065
  return {
@@ -26052,7 +26070,7 @@ var buildSpawnOptions = (options, base, platform) => {
26052
26070
  };
26053
26071
  };
26054
26072
  //#endregion
26055
- //#region node_modules/.pnpm/@effect+platform-node-shared@4.0.2_effect@4.0.0/node_modules/@effect/platform-node-shared/dist/internal/utils.js
26073
+ //#region node_modules/.pnpm/@effect+platform-node-shared@4.0.3_effect@4.0.0/node_modules/@effect/platform-node-shared/dist/internal/utils.js
26056
26074
  /** @internal */
26057
26075
  var handleErrnoException = (module, method) => (err, [path]) => {
26058
26076
  let reason = "Unknown";
@@ -26087,7 +26105,7 @@ var handleErrnoException = (module, method) => (err, [path]) => {
26087
26105
  });
26088
26106
  };
26089
26107
  //#endregion
26090
- //#region node_modules/.pnpm/@effect+platform-node-shared@4.0.2_effect@4.0.0/node_modules/@effect/platform-node-shared/dist/NodeSink.js
26108
+ //#region node_modules/.pnpm/@effect+platform-node-shared@4.0.3_effect@4.0.0/node_modules/@effect/platform-node-shared/dist/NodeSink.js
26091
26109
  /**
26092
26110
  * Creates a `Sink` that writes chunks to a Node writable stream, respecting
26093
26111
  * backpressure, mapping writable errors with `onError`, and ending the stream
@@ -26170,7 +26188,7 @@ var pullIntoWritable = (options) => options.pull.pipe(flatMap$1((chunk) => {
26170
26188
  });
26171
26189
  })));
26172
26190
  //#endregion
26173
- //#region node_modules/.pnpm/@effect+platform-node-shared@4.0.2_effect@4.0.0/node_modules/@effect/platform-node-shared/dist/NodeStream.js
26191
+ //#region node_modules/.pnpm/@effect+platform-node-shared@4.0.3_effect@4.0.0/node_modules/@effect/platform-node-shared/dist/NodeStream.js
26174
26192
  /**
26175
26193
  * Adapters between Node streams and Effect streams, channels, and readables.
26176
26194
  *
@@ -26253,7 +26271,7 @@ var readableToPullUnsafe = (options) => {
26253
26271
  };
26254
26272
  var defaultOnError = (error) => new UnknownError$1(error);
26255
26273
  //#endregion
26256
- //#region node_modules/.pnpm/@effect+platform-node-shared@4.0.2_effect@4.0.0/node_modules/@effect/platform-node-shared/dist/NodeChildProcessSpawner.js
26274
+ //#region node_modules/.pnpm/@effect+platform-node-shared@4.0.3_effect@4.0.0/node_modules/@effect/platform-node-shared/dist/NodeChildProcessSpawner.js
26257
26275
  var toError = (error) => error instanceof globalThis.Error ? error : new globalThis.Error(String(error));
26258
26276
  var toPlatformError = (method, error, command) => {
26259
26277
  const { commands } = flattenCommand(command);
@@ -34500,7 +34518,7 @@ var validateSize = (method, size) => Number.isSafeInteger(size) && size >= 0 ? s
34500
34518
  description: "size must be a non-negative safe integer"
34501
34519
  }));
34502
34520
  //#endregion
34503
- //#region node_modules/.pnpm/@effect+platform-node-shared@4.0.2_effect@4.0.0/node_modules/@effect/platform-node-shared/dist/NodeCrypto.js
34521
+ //#region node_modules/.pnpm/@effect+platform-node-shared@4.0.3_effect@4.0.0/node_modules/@effect/platform-node-shared/dist/NodeCrypto.js
34504
34522
  /**
34505
34523
  * Node-compatible implementation of Effect's `Crypto` service.
34506
34524
  *
@@ -34556,7 +34574,7 @@ var layer$10 = /* @__PURE__ */ succeed$5(Crypto, /* @__PURE__ */ make$12({
34556
34574
  digest
34557
34575
  }));
34558
34576
  //#endregion
34559
- //#region node_modules/.pnpm/@effect+platform-node-shared@4.0.2_effect@4.0.0/node_modules/@effect/platform-node-shared/dist/NodeFileSystem.js
34577
+ //#region node_modules/.pnpm/@effect+platform-node-shared@4.0.3_effect@4.0.0/node_modules/@effect/platform-node-shared/dist/NodeFileSystem.js
34560
34578
  /**
34561
34579
  * Shared Node-compatible implementation of Effect's `FileSystem` service.
34562
34580
  *
@@ -34653,12 +34671,41 @@ var makeTempDirectoryScoped = /*#__PURE__*/ (() => {
34653
34671
  const removeDirectory = /*#__PURE__*/ removeFactory("makeTempDirectoryScoped");
34654
34672
  return (options) => acquireRelease(makeDirectory(options), (directory) => orDie(removeDirectory(directory, { recursive: true })));
34655
34673
  })();
34674
+ var openFlagBits = (flag) => {
34675
+ const { O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY } = NFS.constants;
34676
+ switch (flag) {
34677
+ case "r": return O_RDONLY;
34678
+ case "r+": return O_RDWR;
34679
+ case "w": return O_TRUNC | O_CREAT | O_WRONLY;
34680
+ case "wx": return O_TRUNC | O_CREAT | O_WRONLY | O_EXCL;
34681
+ case "w+": return O_TRUNC | O_CREAT | O_RDWR;
34682
+ case "wx+": return O_TRUNC | O_CREAT | O_RDWR | O_EXCL;
34683
+ case "a": return O_APPEND | O_CREAT | O_WRONLY;
34684
+ case "ax": return O_APPEND | O_CREAT | O_WRONLY | O_EXCL;
34685
+ case "a+": return O_APPEND | O_CREAT | O_RDWR;
34686
+ case "ax+": return O_APPEND | O_CREAT | O_RDWR | O_EXCL;
34687
+ }
34688
+ };
34689
+ var noFollowFlags = (method, flag) => suspend$2(() => {
34690
+ const { O_NOFOLLOW } = NFS.constants;
34691
+ if (process.platform === "win32" || typeof O_NOFOLLOW !== "number" || O_NOFOLLOW === 0) return fail$3(badArgument({
34692
+ module: "FileSystem",
34693
+ method,
34694
+ description: "noFollow is not supported on this platform"
34695
+ }));
34696
+ return succeed$4(openFlagBits(flag) | O_NOFOLLOW);
34697
+ });
34656
34698
  var openFactory = (method) => {
34657
34699
  const nodeOpen = effectify(NFS.open, handleErrnoException("FileSystem", method), handleBadArgument(method));
34658
34700
  const nodeClose = effectify(NFS.close, handleErrnoException("FileSystem", method), handleBadArgument(method));
34659
- return (path, options) => pipe(acquireRelease(nodeOpen(path, options?.flag ?? "r", options?.mode), (fd) => orDie(nodeClose(fd))), map$6((fd) => makeFile(fd, options?.flag?.startsWith("a") ?? false)));
34701
+ return (path, options) => pipe(acquireRelease(options?.noFollow === true ? flatMap$1(noFollowFlags(method, options.flag ?? "r"), (flags) => nodeOpen(path, flags, options.mode)) : nodeOpen(path, options?.flag ?? "r", options?.mode), (fd) => orDie(nodeClose(fd))), map$6((fd) => makeFile(fd, options?.flag?.startsWith("a") ?? false)));
34660
34702
  };
34661
34703
  var open = /*#__PURE__*/ openFactory("open");
34704
+ var negativePosition = (method) => badArgument({
34705
+ module: "FileSystem",
34706
+ method,
34707
+ description: "Cannot read before the start of the file"
34708
+ });
34662
34709
  var makeFile = /*#__PURE__*/ (() => {
34663
34710
  const nodeReadFactory = (method) => effectify(NFS.read, handleErrnoException("FileSystem", method), handleBadArgument(method));
34664
34711
  const nodeRead = /*#__PURE__*/ nodeReadFactory("read");
@@ -34697,8 +34744,13 @@ var makeFile = /*#__PURE__*/ (() => {
34697
34744
  return succeed$4(position);
34698
34745
  });
34699
34746
  }
34700
- read(buffer) {
34747
+ read(buffer, options) {
34701
34748
  return suspend$2(() => {
34749
+ const explicit = options?.position;
34750
+ if (explicit !== void 0) return explicit < BigInt(0) ? fail$3(negativePosition("read")) : nodeRead(this.fd, {
34751
+ buffer,
34752
+ position: explicit
34753
+ });
34702
34754
  const position = this.position;
34703
34755
  return map$6(nodeRead(this.fd, {
34704
34756
  buffer,
@@ -34709,18 +34761,20 @@ var makeFile = /*#__PURE__*/ (() => {
34709
34761
  });
34710
34762
  });
34711
34763
  }
34712
- readAlloc(size) {
34764
+ readAlloc(size, options) {
34713
34765
  return suspend$2(() => {
34714
34766
  try {
34715
34767
  if (!Number.isInteger(size) || size < 0) throw new RangeError("size must be a non-negative integer");
34768
+ const explicit = options?.position;
34769
+ if (explicit !== void 0 && explicit < BigInt(0)) return fail$3(negativePosition("readAlloc"));
34716
34770
  const buffer = Buffer.allocUnsafeSlow(size);
34717
- const position = this.position;
34771
+ const position = explicit ?? this.position;
34718
34772
  return map$6(nodeReadAlloc(this.fd, {
34719
34773
  buffer,
34720
34774
  position
34721
34775
  }), (bytesRead) => {
34722
34776
  if (bytesRead === 0) return none();
34723
- this.position = position + BigInt(bytesRead);
34777
+ if (explicit === void 0) this.position = position + BigInt(bytesRead);
34724
34778
  if (bytesRead === size) return some(buffer);
34725
34779
  const dst = Buffer.allocUnsafeSlow(bytesRead);
34726
34780
  buffer.copy(dst, 0, 0, bytesRead);
@@ -34808,7 +34862,7 @@ var realPath = /*#__PURE__*/ (() => {
34808
34862
  const nodeRealPath = /*#__PURE__*/ effectify(NFS.realpath, /*#__PURE__*/ handleErrnoException("FileSystem", "realPath"), /*#__PURE__*/ handleBadArgument("realPath"));
34809
34863
  return (path) => nodeRealPath(path);
34810
34864
  })();
34811
- var rename = /*#__PURE__*/ (() => {
34865
+ var rename$1 = /*#__PURE__*/ (() => {
34812
34866
  const nodeRename = /*#__PURE__*/ effectify(NFS.rename, /*#__PURE__*/ handleErrnoException("FileSystem", "rename"), /*#__PURE__*/ handleBadArgument("rename"));
34813
34867
  return (oldPath, newPath) => nodeRename(oldPath, newPath);
34814
34868
  })();
@@ -34920,7 +34974,7 @@ var makeFileSystem = /*#__PURE__*/ map$6(/*#__PURE__*/ serviceOption(WatchBacken
34920
34974
  readLink,
34921
34975
  realPath,
34922
34976
  remove,
34923
- rename,
34977
+ rename: rename$1,
34924
34978
  stat,
34925
34979
  symlink,
34926
34980
  truncate,
@@ -34950,7 +35004,7 @@ var makeFileSystem = /*#__PURE__*/ map$6(/*#__PURE__*/ serviceOption(WatchBacken
34950
35004
  */
34951
35005
  var layer$8 = /* @__PURE__ */ effect(FileSystem)(makeFileSystem);
34952
35006
  //#endregion
34953
- //#region node_modules/.pnpm/@effect+platform-node-shared@4.0.2_effect@4.0.0/node_modules/@effect/platform-node-shared/dist/NodePath.js
35007
+ //#region node_modules/.pnpm/@effect+platform-node-shared@4.0.3_effect@4.0.0/node_modules/@effect/platform-node-shared/dist/NodePath.js
34954
35008
  /**
34955
35009
  * Node-backed provider for Effect's `Path` service.
34956
35010
  *
@@ -35035,6 +35089,7 @@ var layer$4 = /* @__PURE__ */ succeed$5(Stdio, /*#__PURE__*/ make$15({
35035
35089
  args: /*#__PURE__*/ sync(() => process.argv.slice(2)),
35036
35090
  stdinIsTerminal: /*#__PURE__*/ sync(() => process.stdin.isTTY === true),
35037
35091
  stdoutIsTerminal: /*#__PURE__*/ sync(() => process.stdout.isTTY === true),
35092
+ stderrIsTerminal: /*#__PURE__*/ sync(() => process.stderr.isTTY === true),
35038
35093
  stdout: (options) => fromWritable({
35039
35094
  evaluate: () => process.stdout,
35040
35095
  onError: (cause) => systemError({
@@ -35147,7 +35202,7 @@ var make$10 = (impl) => Terminal.of({
35147
35202
  });
35148
35203
  /**
35149
35204
  * Provides the default process-backed `Terminal` service, ending key input on
35150
- * Ctrl+C or Ctrl+D.
35205
+ * bare Esc, Ctrl+C, or Ctrl+D.
35151
35206
  *
35152
35207
  * @stability unstable
35153
35208
  * @category layers
@@ -35252,7 +35307,8 @@ var layer$3 = /*#__PURE__*/ effect(Terminal, /*#__PURE__*/ (/* @__PURE__ */ fnUn
35252
35307
  });
35253
35308
  }))(defaultShouldQuit));
35254
35309
  function defaultShouldQuit(input) {
35255
- return input.key.ctrl && (input.key.name === "c" || input.key.name === "d");
35310
+ const key = input.key;
35311
+ return key.name === "escape" || key.ctrl && (key.name === "c" || key.name === "d");
35256
35312
  }
35257
35313
  //#endregion
35258
35314
  //#region node_modules/.pnpm/@effect+platform-node@4.0.0_effect@4.0.0_redis@6.3.0/node_modules/@effect/platform-node/dist/NodeServices.js
@@ -42749,7 +42805,7 @@ var runWith = (command, config) => {
42749
42805
  };
42750
42806
  var package_default = {
42751
42807
  name: "repo-dive",
42752
- version: "0.16.3",
42808
+ version: "0.16.4",
42753
42809
  description: "Dive into a git repo's history: per-commit snapshots, an indexed metrics catalog and an interactive dashboard",
42754
42810
  keywords: [
42755
42811
  "git",
@@ -42819,7 +42875,7 @@ var package_default = {
42819
42875
  prettier: "@kachkaev/prettier-config",
42820
42876
  devDependencies: {
42821
42877
  "@babel/core": "8.0.7",
42822
- "@base-ui/react": "1.8.0",
42878
+ "@base-ui/react": "1.9.0",
42823
42879
  "@changesets/changelog-github": "1.0.1",
42824
42880
  "@changesets/cli": "3.0.3",
42825
42881
  "@changesets/config": "4.0.1",
@@ -42851,7 +42907,7 @@ var package_default = {
42851
42907
  "eslint": "10.12.0",
42852
42908
  "eslint-plugin-react-hooks": "7.1.1",
42853
42909
  "husky": "9.1.7",
42854
- "knip": "6.39.0",
42910
+ "knip": "6.41.0",
42855
42911
  "lint-staged": "17.6.0",
42856
42912
  "lucide-react": "1.52.0",
42857
42913
  "markdownlint-cli": "0.49.1",
@@ -50656,14 +50712,42 @@ var CatalogFormatError = class extends TaggedError$1("CatalogFormatError") {
50656
50712
  return `Catalog at ${this.rootPath} has format version ${String(this.formatVersion)}, but this version of repo-dive expects ${catalogFormatVersion}. Delete the folder to re-collect from scratch.`;
50657
50713
  }
50658
50714
  };
50659
- var writeJson = (filePath, value) => tryPromise(() => writeFile(filePath, `${JSON.stringify(value, void 0, 2)}\n`, "utf8"));
50660
- var readJsonIfExists = (filePath) => tryPromise(async () => {
50715
+ /**
50716
+ * Writes beside the target, then renames over it. A scan cut short (Ctrl+C, a
50717
+ * CI step timeout) or a copy of the catalog taken mid-scan (a CI cache save)
50718
+ * then sees either the previous file or the complete new one, never a
50719
+ * truncated one. A temporary file a cut-short write leaves behind is reused by
50720
+ * the next write of the same file.
50721
+ */
50722
+ var writeJson = (filePath, value) => tryPromise(async () => {
50723
+ const temporaryPath = `${filePath}.tmp`;
50724
+ await writeFile(temporaryPath, `${JSON.stringify(value, void 0, 2)}\n`, "utf8");
50725
+ await rename(temporaryPath, filePath);
50726
+ });
50727
+ var readTextIfExists = async (filePath) => {
50661
50728
  try {
50662
- return JSON.parse(await readFile(filePath, "utf8"));
50729
+ return await readFile(filePath, "utf8");
50663
50730
  } catch (error) {
50664
50731
  if (error instanceof Error && "code" in error && error.code === "ENOENT") return;
50665
50732
  throw error;
50666
50733
  }
50734
+ };
50735
+ var readJsonIfExists = (filePath) => tryPromise(async () => {
50736
+ const raw = await readTextIfExists(filePath);
50737
+ return raw === void 0 ? void 0 : JSON.parse(raw);
50738
+ });
50739
+ /**
50740
+ * Like {@link readJsonIfExists}, but a file that does not parse reads as
50741
+ * missing too. Catalogs written before writes became atomic can hold
50742
+ * truncated files, and failing on one would fail every scan from then on.
50743
+ */
50744
+ var readJsonIfIntact = (filePath) => tryPromise(async () => {
50745
+ const raw = await readTextIfExists(filePath);
50746
+ try {
50747
+ return raw === void 0 ? void 0 : JSON.parse(raw);
50748
+ } catch {
50749
+ return;
50750
+ }
50667
50751
  });
50668
50752
  var cacheKeyOf = (sidecar) => typeof sidecar === "object" && sidecar !== null && "cacheKey" in sidecar ? sidecar.cacheKey : void 0;
50669
50753
  var formatVersionOf = (manifest) => typeof manifest === "object" && manifest !== null && "formatVersion" in manifest ? manifest.formatVersion : void 0;
@@ -50720,8 +50804,11 @@ var openCatalog = fn("openCatalog")(function* ({ repoRoot, catalogPath }) {
50720
50804
  };
50721
50805
  });
50722
50806
  var collectorDir = (catalog, sha, collectorName) => path.join(catalog.rootPath, "commits", sha, collectorName);
50723
- /** Reads the cache fingerprint recorded in a collector's sidecar, if any. */
50724
- var readCollectorCacheKey = (catalog, sha, collectorName) => readJsonIfExists(path.join(collectorDir(catalog, sha, collectorName), "collector.json")).pipe(map$6(cacheKeyOf));
50807
+ /**
50808
+ * Reads the cache fingerprint recorded in a collector's sidecar, if any. A
50809
+ * truncated sidecar has none, so the commit is collected afresh.
50810
+ */
50811
+ var readCollectorCacheKey = (catalog, sha, collectorName) => readJsonIfIntact(path.join(collectorDir(catalog, sha, collectorName), "collector.json")).pipe(map$6(cacheKeyOf));
50725
50812
  /**
50726
50813
  * A (commit, collector) pair is done when a sidecar recording the current cache
50727
50814
  * fingerprint exists. `cacheKey` folds in the collector version and any config
@@ -51322,6 +51409,11 @@ var summarizeCommits = (commits) => {
51322
51409
  lastCommitDate: dates.at(-1)
51323
51410
  };
51324
51411
  };
51412
+ /**
51413
+ * A scan's remaining time at the precision an estimate deserves: seconds only
51414
+ * while under a minute, whole minutes from then on (`~1m`, not `~1m 52s`).
51415
+ */
51416
+ var formatTimeLeft = (seconds) => seconds < 60 ? `${seconds}s` : `${Math.floor(seconds / 60)}m`;
51325
51417
  var runCollector = ({ catalog, sha, collector, cacheKey, worktreePath }) => collector.collect({
51326
51418
  repoRoot: catalog.repoRoot,
51327
51419
  catalogPath: catalog.rootPath,
@@ -51442,9 +51534,7 @@ var runScan = fn("runScan")(function* ({ repoPath, collectorNames, maxCommits, s
51442
51534
  const elapsedSeconds = (now - startedAt) / 1e3;
51443
51535
  const rate = processed / Math.max(1, elapsedSeconds);
51444
51536
  const remainingSeconds = Math.round((selected.length - processed) / Math.max(.01, rate));
51445
- const minutes = Math.floor(remainingSeconds / 60);
51446
- const seconds = remainingSeconds % 60;
51447
- return `${Math.round(rate)}/s, ~${minutes > 0 ? `${minutes}m ` : ""}${seconds}s left`;
51537
+ return `${Math.round(rate)}/s, ~${formatTimeLeft(remainingSeconds)} left`;
51448
51538
  };
51449
51539
  const processedRef = yield* make$31(0);
51450
51540
  const outcomes = yield* forEach$1(selected, (commit) => collectCommit({
@@ -52321,6 +52411,7 @@ var runIndex = fn("runIndex")(function* ({ repoPath }) {
52321
52411
  const factsByCollector = /* @__PURE__ */ new Map();
52322
52412
  let unknownCollectorDirs = 0;
52323
52413
  let offMainlineSnapshots = 0;
52414
+ let incompleteOutputs = 0;
52324
52415
  for (const collectorName of await readdir(commitDir)) {
52325
52416
  const collector = registry.get(collectorName);
52326
52417
  if (!collector) {
@@ -52331,7 +52422,16 @@ var runIndex = fn("runIndex")(function* ({ repoPath }) {
52331
52422
  offMainlineSnapshots += 1;
52332
52423
  continue;
52333
52424
  }
52334
- const raw = JSON.parse(await readFile(path.join(commitDir, collectorName, "output.json"), "utf8"));
52425
+ let raw;
52426
+ try {
52427
+ raw = JSON.parse(await readFile(path.join(commitDir, collectorName, "output.json"), "utf8"));
52428
+ } catch (error) {
52429
+ if (error instanceof SyntaxError || error instanceof Error && "code" in error && error.code === "ENOENT") {
52430
+ incompleteOutputs += 1;
52431
+ continue;
52432
+ }
52433
+ throw error;
52434
+ }
52335
52435
  factsByCollector.set(collectorName, collector.normalize(raw));
52336
52436
  }
52337
52437
  return {
@@ -52344,12 +52444,14 @@ var runIndex = fn("runIndex")(function* ({ repoPath }) {
52344
52444
  factsByCollector
52345
52445
  },
52346
52446
  unknownCollectorDirs,
52347
- offMainlineSnapshots
52447
+ offMainlineSnapshots,
52448
+ incompleteOutputs
52348
52449
  };
52349
52450
  }), { concurrency: 16 });
52350
52451
  const commitFacts = readOutcomes.map((outcome) => outcome.facts);
52351
52452
  const unknownCollectorDirs = readOutcomes.reduce((total, outcome) => total + outcome.unknownCollectorDirs, 0);
52352
52453
  const offMainlineSnapshots = readOutcomes.reduce((total, outcome) => total + outcome.offMainlineSnapshots, 0);
52454
+ const incompleteOutputs = readOutcomes.reduce((total, outcome) => total + outcome.incompleteOutputs, 0);
52353
52455
  const indexDir = path.join(catalogPath, "index");
52354
52456
  yield* tryPromise(() => mkdir(indexDir, { recursive: true }));
52355
52457
  const dbPath = path.join(indexDir, "metrics.sqlite");
@@ -52363,7 +52465,8 @@ var runIndex = fn("runIndex")(function* ({ repoPath }) {
52363
52465
  `Cube: ${dbPath}`,
52364
52466
  `Dashboard data: ${dashboardPath}`,
52365
52467
  ...unknownCollectorDirs > 0 ? [`Skipped ${unknownCollectorDirs} outputs from unknown collectors (see \`gc --stale\`).`] : [],
52366
- ...offMainlineSnapshots > 0 ? [`Skipped ${offMainlineSnapshots} tree snapshots taken off the lineages.`] : []
52468
+ ...offMainlineSnapshots > 0 ? [`Skipped ${offMainlineSnapshots} tree snapshots taken off the lineages.`] : [],
52469
+ ...incompleteOutputs > 0 ? [`Skipped ${incompleteOutputs} incomplete outputs left by an interrupted scan.`] : []
52367
52470
  ].join("\n"));
52368
52471
  yield* warnAboutIgnoreFiles({
52369
52472
  repoRoot,
@@ -59635,5 +59738,14 @@ var cli = make$8("repo-dive", {
59635
59738
  var ReportedCliFailure = class extends TaggedError$1("ReportedCliFailure") {
59636
59739
  [errorReported] = false;
59637
59740
  };
59638
- run(cli, { version: package_default.version }).pipe(catchIf((error) => !isCliError(error), (error$1) => error(error$1 instanceof Error ? error$1.message : String(error$1)).pipe(andThen(fail$3(new ReportedCliFailure())))), provide(layer$1), runMain);
59741
+ /**
59742
+ * The one line a domain failure prints as. `Effect.try` / `Effect.tryPromise`
59743
+ * failures only say "An error occurred in Effect.tryPromise", so the error
59744
+ * they wrap is what tells the user what went wrong.
59745
+ */
59746
+ var describeFailure = (error) => {
59747
+ if (!(error instanceof Error)) return String(error);
59748
+ return isUnknownError(error) && error.cause instanceof Error ? `${error.message}: ${error.cause.message}` : error.message;
59749
+ };
59750
+ run(cli, { version: package_default.version }).pipe(catchIf((error) => !isCliError(error), (error$1) => error(describeFailure(error$1)).pipe(andThen(fail$3(new ReportedCliFailure())))), provide(layer$1), runMain);
59639
59751
  //#endregion