@maind-dev/cli 0.9.0 → 0.11.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.
package/build/index.js CHANGED
@@ -145,8 +145,8 @@ var McpClient = class {
145
145
  headers: this.headers(),
146
146
  body: JSON.stringify(frame)
147
147
  });
148
- } catch (err2) {
149
- throw new McpError(`network error contacting ${this.mcpUrl}: ${stringifyErr(err2)}`);
148
+ } catch (err4) {
149
+ throw new McpError(`network error contacting ${this.mcpUrl}: ${stringifyErr(err4)}`);
150
150
  }
151
151
  const sid = response.headers.get("mcp-session-id");
152
152
  if (response.status === 401) {
@@ -207,8 +207,8 @@ async function readSseMessage(response) {
207
207
  flush();
208
208
  return lastPayload;
209
209
  }
210
- function stringifyErr(err2) {
211
- return err2 instanceof Error ? err2.message : String(err2);
210
+ function stringifyErr(err4) {
211
+ return err4 instanceof Error ? err4.message : String(err4);
212
212
  }
213
213
  function parseJsonLoose(text) {
214
214
  const trimmed = text.trim();
@@ -251,56 +251,56 @@ function buildManifest(lessons, conventions, meta) {
251
251
  };
252
252
  }
253
253
  function renderContextMarkdown(lessons, conventions, meta) {
254
- const lines = [];
255
- lines.push("<!-- Generated by `maind context` \u2014 do not edit by hand. -->");
256
- lines.push(`<!-- generated_at: ${meta.generatedAt} | key: ${meta.keyPrefix}${meta.runRef ? ` | run: ${meta.runRef}` : ""} -->`);
257
- lines.push("");
258
- lines.push("# maind context");
259
- lines.push("");
260
- lines.push(
261
- "Vetted lessons and conventions for this stack, pulled from maind for the agent running in this CI job. Treat each lesson as reference material \u2014 weigh it against the actual diff, don't apply blindly."
254
+ const lines2 = [];
255
+ lines2.push("<!-- Generated by `maind context` \u2014 do not edit by hand. -->");
256
+ lines2.push(`<!-- generated_at: ${meta.generatedAt} | key: ${meta.keyPrefix}${meta.runRef ? ` | run: ${meta.runRef}` : ""} -->`);
257
+ lines2.push("");
258
+ lines2.push("# maind context");
259
+ lines2.push("");
260
+ lines2.push(
261
+ "Vetted lessons and conventions for this stack, pulled from MAIND for the agent running in this CI job. Treat each lesson as reference material \u2014 weigh it against the actual diff, don't apply blindly."
262
262
  );
263
- lines.push("");
263
+ lines2.push("");
264
264
  const stackLabel = meta.stack.length > 0 ? meta.stack.join(", ") : "(none)";
265
- lines.push(`**Stack:** ${stackLabel} \xB7 **Lessons:** ${lessons.length} \xB7 **Conventions:** ${conventions.length}`);
266
- lines.push("");
265
+ lines2.push(`**Stack:** ${stackLabel} \xB7 **Lessons:** ${lessons.length} \xB7 **Conventions:** ${conventions.length}`);
266
+ lines2.push("");
267
267
  if (conventions.length > 0) {
268
- lines.push("## Always-on conventions");
269
- lines.push("");
268
+ lines2.push("## Always-on conventions");
269
+ lines2.push("");
270
270
  for (const c of conventions) {
271
- lines.push(`- **${c.title}** \`${c.id}\``);
271
+ lines2.push(`- **${c.title}** \`${c.id}\``);
272
272
  }
273
- lines.push("");
273
+ lines2.push("");
274
274
  }
275
275
  if (lessons.length === 0) {
276
- lines.push("## Lessons");
277
- lines.push("");
278
- lines.push("_No stack-relevant lessons were returned for this query._");
279
- lines.push("");
280
- return lines.join("\n");
281
- }
282
- lines.push("## Lessons");
283
- lines.push("");
276
+ lines2.push("## Lessons");
277
+ lines2.push("");
278
+ lines2.push("_No stack-relevant lessons were returned for this query._");
279
+ lines2.push("");
280
+ return lines2.join("\n");
281
+ }
282
+ lines2.push("## Lessons");
283
+ lines2.push("");
284
284
  for (const l of lessons) {
285
- lines.push(`### ${l.title}`);
285
+ lines2.push(`### ${l.title}`);
286
286
  const meta2 = [`\`${l.id}\``];
287
287
  if (l.tier) meta2.push(l.tier);
288
288
  if (typeof l.version === "number") meta2.push(`v${l.version}`);
289
289
  if (l.last_validated_at) meta2.push(`validated ${l.last_validated_at}`);
290
- lines.push(meta2.join(" \xB7 "));
291
- lines.push("");
290
+ lines2.push(meta2.join(" \xB7 "));
291
+ lines2.push("");
292
292
  if (l.summary) {
293
- lines.push(`> ${l.summary}`);
294
- lines.push("");
293
+ lines2.push(`> ${l.summary}`);
294
+ lines2.push("");
295
295
  }
296
296
  if (l.body && l.body.trim().length > 0) {
297
- lines.push(l.body.trim());
298
- lines.push("");
297
+ lines2.push(l.body.trim());
298
+ lines2.push("");
299
299
  }
300
- lines.push("---");
301
- lines.push("");
300
+ lines2.push("---");
301
+ lines2.push("");
302
302
  }
303
- return lines.join("\n");
303
+ return lines2.join("\n");
304
304
  }
305
305
 
306
306
  // src/context.ts
@@ -383,8 +383,8 @@ async function runContext(opts) {
383
383
  platforms: opts.platforms
384
384
  });
385
385
  if (Array.isArray(briefing.convention_index)) conventions = briefing.convention_index;
386
- } catch (err2) {
387
- warn(`conventions unavailable (continuing with lessons only): ${msg(err2)}`);
386
+ } catch (err4) {
387
+ warn(`conventions unavailable (continuing with lessons only): ${msg(err4)}`);
388
388
  }
389
389
  writeArtifact(opts.out, renderContextMarkdown(lessons, conventions, meta));
390
390
  writeArtifact(opts.manifest, JSON.stringify(buildManifest(lessons, conventions, meta), null, 2) + "\n");
@@ -393,8 +393,8 @@ async function runContext(opts) {
393
393
  `
394
394
  );
395
395
  return 0;
396
- } catch (err2) {
397
- const reason = err2 instanceof MissingApiKeyError ? err2.message : msg(err2);
396
+ } catch (err4) {
397
+ const reason = err4 instanceof MissingApiKeyError ? err4.message : msg(err4);
398
398
  warn(`context pull failed, continuing without maind context: ${reason}`);
399
399
  const emptyManifest = buildManifest([], [], meta);
400
400
  emptyManifest.error = reason;
@@ -425,8 +425,8 @@ function failOpenMarkdown(meta, reason) {
425
425
  ""
426
426
  ].join("\n");
427
427
  }
428
- function msg(err2) {
429
- return err2 instanceof Error ? err2.message : String(err2);
428
+ function msg(err4) {
429
+ return err4 instanceof Error ? err4.message : String(err4);
430
430
  }
431
431
  function warn(line) {
432
432
  process.stderr.write(`maind context: ${line}
@@ -560,10 +560,10 @@ function gatherGitState() {
560
560
  };
561
561
  }
562
562
  function ciFromChecks(prNumber) {
563
- const out = gh(["pr", "checks", String(prNumber), "--json", "bucket"]);
564
- if (!out) return "unknown";
563
+ const out2 = gh(["pr", "checks", String(prNumber), "--json", "bucket"]);
564
+ if (!out2) return "unknown";
565
565
  try {
566
- const rows = JSON.parse(out);
566
+ const rows = JSON.parse(out2);
567
567
  if (rows.length === 0) return "unknown";
568
568
  if (rows.some((r) => r.bucket === "fail")) return "failure";
569
569
  if (rows.some((r) => r.bucket === "pending")) return "pending";
@@ -574,10 +574,10 @@ function ciFromChecks(prNumber) {
574
574
  }
575
575
  }
576
576
  function gatherOpenPrs(currentBranch, max = 5) {
577
- const out = gh(["pr", "list", "--state", "open", "--limit", String(max), "--json", "number,title,headRefName"]);
578
- if (out === null) return { available: false, prs: [] };
577
+ const out2 = gh(["pr", "list", "--state", "open", "--limit", String(max), "--json", "number,title,headRefName"]);
578
+ if (out2 === null) return { available: false, prs: [] };
579
579
  try {
580
- const rows = JSON.parse(out);
580
+ const rows = JSON.parse(out2);
581
581
  const prs = rows.map((r) => ({
582
582
  number: r.number,
583
583
  title: r.title,
@@ -685,8 +685,8 @@ async function runCiReport(opts) {
685
685
  },
686
686
  body
687
687
  });
688
- } catch (err2) {
689
- warn2(`network error posting to ${opts.reportUrl}: ${msg2(err2)}`);
688
+ } catch (err4) {
689
+ warn2(`network error posting to ${opts.reportUrl}: ${msg2(err4)}`);
690
690
  return 0;
691
691
  }
692
692
  const text = await res.text().catch(() => "");
@@ -704,14 +704,14 @@ async function runCiReport(opts) {
704
704
  `maind ci-report: ${parsed.deduplicated ? "deduplicated" : "filed"} draft ${parsed.draft_id ?? "?"}${scope}` + (parsed.review_url ? ` \u2192 ${parsed.review_url}` : "") + "\n"
705
705
  );
706
706
  return 0;
707
- } catch (err2) {
708
- const reason = err2 instanceof MissingApiKeyError ? err2.message : msg2(err2);
707
+ } catch (err4) {
708
+ const reason = err4 instanceof MissingApiKeyError ? err4.message : msg2(err4);
709
709
  warn2(`report failed, continuing: ${reason}`);
710
710
  return 0;
711
711
  }
712
712
  }
713
- function msg2(err2) {
714
- return err2 instanceof Error ? err2.message : String(err2);
713
+ function msg2(err4) {
714
+ return err4 instanceof Error ? err4.message : String(err4);
715
715
  }
716
716
  function warn2(line) {
717
717
  process.stderr.write(`maind ci-report: ${line}
@@ -807,8 +807,8 @@ async function runCiResult(opts) {
807
807
  },
808
808
  body
809
809
  });
810
- } catch (err2) {
811
- warn3(`network error posting to ${opts.resultUrl}: ${msg3(err2)}`);
810
+ } catch (err4) {
811
+ warn3(`network error posting to ${opts.resultUrl}: ${msg3(err4)}`);
812
812
  return 0;
813
813
  }
814
814
  const text = await res.text().catch(() => "");
@@ -826,14 +826,14 @@ async function runCiResult(opts) {
826
826
  `
827
827
  );
828
828
  return 0;
829
- } catch (err2) {
830
- const reason = err2 instanceof MissingApiKeyError ? err2.message : msg3(err2);
829
+ } catch (err4) {
830
+ const reason = err4 instanceof MissingApiKeyError ? err4.message : msg3(err4);
831
831
  warn3(`result failed, continuing: ${reason}`);
832
832
  return 0;
833
833
  }
834
834
  }
835
- function msg3(err2) {
836
- return err2 instanceof Error ? err2.message : String(err2);
835
+ function msg3(err4) {
836
+ return err4 instanceof Error ? err4.message : String(err4);
837
837
  }
838
838
  function warn3(line) {
839
839
  process.stderr.write(`maind ci-result: ${line}
@@ -902,8 +902,8 @@ async function runGitContext(opts) {
902
902
  recommendation: c.recommendation ?? null,
903
903
  checked: true
904
904
  };
905
- } catch (err2) {
906
- warn4(`peer check unavailable: ${msg4(err2)}`);
905
+ } catch (err4) {
906
+ warn4(`peer check unavailable: ${msg4(err4)}`);
907
907
  }
908
908
  }
909
909
  try {
@@ -914,11 +914,11 @@ async function runGitContext(opts) {
914
914
  });
915
915
  lessons = Array.isArray(res.lessons) ? res.lessons : [];
916
916
  lessonsAvailable = true;
917
- } catch (err2) {
918
- warn4(`git lessons unavailable: ${msg4(err2)}`);
917
+ } catch (err4) {
918
+ warn4(`git lessons unavailable: ${msg4(err4)}`);
919
919
  }
920
- } catch (err2) {
921
- warn4(`maind enrichment skipped (${msg4(err2)}); rendering local git state only.`);
920
+ } catch (err4) {
921
+ warn4(`maind enrichment skipped (${msg4(err4)}); rendering local git state only.`);
922
922
  }
923
923
  }
924
924
  writeArtifact2(opts.out, renderMarkdown(git3, prResult, peer, lessons, lessonsAvailable));
@@ -1007,8 +1007,8 @@ function buildManifest2(git3, prs, peer) {
1007
1007
  path_conflicts: peer?.conflicts.map((c) => c.path) ?? []
1008
1008
  };
1009
1009
  }
1010
- function msg4(err2) {
1011
- return err2 instanceof Error ? err2.message : String(err2);
1010
+ function msg4(err4) {
1011
+ return err4 instanceof Error ? err4.message : String(err4);
1012
1012
  }
1013
1013
  function warn4(line) {
1014
1014
  process.stderr.write(`maind git-context: ${line}
@@ -1016,15 +1016,15 @@ function warn4(line) {
1016
1016
  }
1017
1017
 
1018
1018
  // src/index-cmd.ts
1019
- import { execFileSync as execFileSync5, spawnSync } from "node:child_process";
1020
- import { existsSync as existsSync3, mkdtempSync, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
1019
+ import { execFileSync as execFileSync6, spawnSync } from "node:child_process";
1020
+ import { existsSync as existsSync4, mkdtempSync, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
1021
1021
  import { tmpdir } from "node:os";
1022
- import { dirname as dirname3, join as join4 } from "node:path";
1022
+ import { dirname as dirname3, join as join5 } from "node:path";
1023
1023
  import { fileURLToPath } from "node:url";
1024
1024
 
1025
1025
  // ../../packages/code-index/build/node.js
1026
1026
  import { mkdirSync as mkdirSync3 } from "node:fs";
1027
- import { posix as posix5 } from "node:path";
1027
+ import { posix as posix6 } from "node:path";
1028
1028
 
1029
1029
  // ../../packages/code-index/build/parse/tree-sitter/parser.js
1030
1030
  import { join as join3 } from "node:path";
@@ -1432,7 +1432,7 @@ var TreeSitterParser = class {
1432
1432
 
1433
1433
  // ../../packages/code-index/build/query/engine.js
1434
1434
  import { readFileSync as readFileSync5 } from "node:fs";
1435
- import { posix as posix4 } from "node:path";
1435
+ import { posix as posix5 } from "node:path";
1436
1436
 
1437
1437
  // ../../packages/code-index/build/embed/recipe.js
1438
1438
  var EMBED_RECIPE_VERSION = "1";
@@ -1591,16 +1591,16 @@ function toPosix(p) {
1591
1591
  return sep === "/" ? p : p.split(sep).join("/");
1592
1592
  }
1593
1593
  function classify(paths) {
1594
- const out = [];
1594
+ const out2 = [];
1595
1595
  for (const raw of paths) {
1596
1596
  const path = toPosix(raw).trim();
1597
1597
  if (!path || isSkippablePath(path))
1598
1598
  continue;
1599
1599
  const language = languageForPath(path);
1600
1600
  if (language)
1601
- out.push({ path, language });
1601
+ out2.push({ path, language });
1602
1602
  }
1603
- return out;
1603
+ return out2;
1604
1604
  }
1605
1605
  function classifyPaths(paths) {
1606
1606
  return classify(paths);
@@ -1635,11 +1635,16 @@ function walk(root, rel, acc) {
1635
1635
  acc.push(childRel);
1636
1636
  }
1637
1637
  }
1638
+ function resolveDiffBase(repoRoot2, since) {
1639
+ const base = runGit(repoRoot2, ["merge-base", since, "HEAD"]);
1640
+ const trimmed = base?.trim();
1641
+ return trimmed && trimmed.length > 0 ? trimmed : since;
1642
+ }
1638
1643
  function enumerateChangedPaths(repoRoot2, opts = {}) {
1639
1644
  if (headCommit(repoRoot2) === null)
1640
1645
  return null;
1641
1646
  const includeUncommitted = opts.includeUncommitted !== false;
1642
- const ref = opts.since ?? "HEAD";
1647
+ const ref = opts.since ? resolveDiffBase(repoRoot2, opts.since) : "HEAD";
1643
1648
  const diffArgs = ["diff", "--name-status", "--diff-filter=d", ref];
1644
1649
  if (!includeUncommitted) {
1645
1650
  if (!opts.since) {
@@ -1736,7 +1741,7 @@ function changedHunks(repoRoot2, opts = {}) {
1736
1741
  if (runGit(repoRoot2, ["rev-parse", "HEAD"]) === null)
1737
1742
  return null;
1738
1743
  const includeUncommitted = opts.includeUncommitted !== false;
1739
- const ref = opts.since ?? "HEAD";
1744
+ const ref = opts.since ? resolveDiffBase(repoRoot2, opts.since) : "HEAD";
1740
1745
  const diffArgs = [
1741
1746
  "diff",
1742
1747
  "--unified=0",
@@ -1986,11 +1991,11 @@ function readFileHistory(repoRoot2, paths, opts = {}) {
1986
1991
  const commits = [];
1987
1992
  if (raw !== null) {
1988
1993
  for (const record of splitRecords(raw)) {
1989
- const lines = record.split("\n");
1990
- const head = parseHistoryRecord(lines[0] ?? "");
1994
+ const lines2 = record.split("\n");
1995
+ const head = parseHistoryRecord(lines2[0] ?? "");
1991
1996
  if (!head)
1992
1997
  continue;
1993
- const filesTouched = lines.slice(1).filter((l) => l.trim().length > 0).length;
1998
+ const filesTouched = lines2.slice(1).filter((l) => l.trim().length > 0).length;
1994
1999
  commits.push({
1995
2000
  sha: head.sha,
1996
2001
  dateIso: head.dateIso,
@@ -2016,7 +2021,98 @@ function readFileHistory(repoRoot2, paths, opts = {}) {
2016
2021
  }
2017
2022
 
2018
2023
  // ../../packages/code-index/build/repo-health/divergence.js
2024
+ import { execFileSync as execFileSync5 } from "node:child_process";
2025
+
2026
+ // ../../packages/code-index/build/repo-health/hooks.js
2019
2027
  import { execFileSync as execFileSync4 } from "node:child_process";
2028
+ import { readdirSync as readdirSync2, statSync as statSync2 } from "node:fs";
2029
+ import { isAbsolute, join as join4, relative, resolve } from "node:path";
2030
+ var VERSIONED_HOOK_DIRS = [".githooks", ".husky"];
2031
+ function isRealHook(name) {
2032
+ return !name.endsWith(".sample") && !name.startsWith(".");
2033
+ }
2034
+ function gitConfig(root, key) {
2035
+ try {
2036
+ const out2 = execFileSync4("git", ["-C", root, "config", "--get", key], {
2037
+ encoding: "utf-8",
2038
+ timeout: 5e3,
2039
+ stdio: ["ignore", "pipe", "ignore"]
2040
+ }).trim();
2041
+ return out2.length > 0 ? out2 : null;
2042
+ } catch {
2043
+ return null;
2044
+ }
2045
+ }
2046
+ function hasExecutableHook(dir) {
2047
+ let entries;
2048
+ try {
2049
+ entries = readdirSync2(dir);
2050
+ } catch {
2051
+ return null;
2052
+ }
2053
+ for (const name of entries.filter(isRealHook)) {
2054
+ try {
2055
+ const st = statSync2(join4(dir, name));
2056
+ if (st.isFile() && (st.mode & 73) !== 0)
2057
+ return true;
2058
+ } catch {
2059
+ }
2060
+ }
2061
+ return false;
2062
+ }
2063
+ function isDir(p) {
2064
+ try {
2065
+ return statSync2(p).isDirectory();
2066
+ } catch {
2067
+ return false;
2068
+ }
2069
+ }
2070
+ function displayPath(root, absolute) {
2071
+ const rel = relative(root, absolute);
2072
+ return !rel || rel.startsWith("..") ? absolute : rel;
2073
+ }
2074
+ function resolveHookState(root) {
2075
+ const hookDirs = VERSIONED_HOOK_DIRS.filter((d) => isDir(join4(root, d)));
2076
+ const hooksPath = gitConfig(root, "core.hooksPath");
2077
+ const effectiveAbs = hooksPath ? isAbsolute(hooksPath) ? hooksPath : resolve(root, hooksPath) : join4(root, ".git", "hooks");
2078
+ const effectiveDir = displayPath(root, effectiveAbs);
2079
+ const found = hasExecutableHook(effectiveAbs);
2080
+ if (found === true) {
2081
+ return {
2082
+ verdict: "wired",
2083
+ reason: hooksPath ? "wired" : "default_path",
2084
+ hookDirs,
2085
+ hooksPath,
2086
+ effectiveDir
2087
+ };
2088
+ }
2089
+ const reason = hooksPath ? found === null ? "path_missing" : "path_empty" : hookDirs.length > 0 ? "path_unset" : "no_hooks";
2090
+ return {
2091
+ verdict: hookDirs.length > 0 ? "present_unwired" : "absent",
2092
+ reason,
2093
+ hookDirs,
2094
+ hooksPath,
2095
+ effectiveDir
2096
+ };
2097
+ }
2098
+ function describeHookState(state) {
2099
+ switch (state.reason) {
2100
+ case "wired":
2101
+ return `Git-Gates aktiv (core.hooksPath \u2192 ${state.effectiveDir}).`;
2102
+ case "default_path":
2103
+ return "Git-Gates aktiv (.git/hooks, nicht versioniert).";
2104
+ case "path_unset":
2105
+ return `${state.hookDirs.join(", ")} liegt im Repo, aber core.hooksPath ist ungesetzt \u2014 kein Gate feuert.`;
2106
+ case "path_missing":
2107
+ return `core.hooksPath zeigt auf ${state.effectiveDir}, das es nicht gibt \u2014 git f\xFChrt keinen Hook aus.`;
2108
+ case "path_empty":
2109
+ return `core.hooksPath zeigt auf ${state.effectiveDir}, dort liegt kein ausf\xFChrbarer Hook.`;
2110
+ case "no_hooks":
2111
+ return "Keine Git-Hooks im Repo.";
2112
+ }
2113
+ }
2114
+
2115
+ // ../../packages/code-index/build/repo-health/divergence.js
2020
2116
  import { existsSync as existsSync2, readFileSync as readFileSync4 } from "node:fs";
2021
2117
  import { posix as posix3 } from "node:path";
2022
2118
  var DEFAULT_WORKTREE_PROBE_PATHS = [
@@ -2026,12 +2122,12 @@ var DEFAULT_WORKTREE_PROBE_PATHS = [
2026
2122
  ];
2027
2123
  var WORKTREE_REQUIREMENTS_RELPATH = ".maind/worktree-requirements";
2028
2124
  function computeDivergence(facts) {
2029
- const out = [];
2125
+ const out2 = [];
2030
2126
  if (!facts.isRepo)
2031
- return out;
2127
+ return out2;
2032
2128
  const onFeatureBranch = facts.branch != null && facts.defaultBranch != null && facts.branch !== facts.defaultBranch && !facts.detachedHead;
2033
2129
  if (facts.detachedHead) {
2034
- out.push({
2130
+ out2.push({
2035
2131
  id: "worktree.detached-head",
2036
2132
  status: "warn",
2037
2133
  scope: "worktree",
@@ -2042,7 +2138,7 @@ function computeDivergence(facts) {
2042
2138
  }
2043
2139
  if (onFeatureBranch) {
2044
2140
  if (facts.upstream == null) {
2045
- out.push({
2141
+ out2.push({
2046
2142
  id: "branch.no-upstream",
2047
2143
  status: "open",
2048
2144
  scope: "branch",
@@ -2053,7 +2149,7 @@ function computeDivergence(facts) {
2053
2149
  } else {
2054
2150
  const upstreamBranch = facts.upstream.split("/").slice(1).join("/");
2055
2151
  if (upstreamBranch && upstreamBranch !== facts.branch) {
2056
- out.push({
2152
+ out2.push({
2057
2153
  id: "branch.upstream-mismatch",
2058
2154
  status: "open",
2059
2155
  scope: "branch",
@@ -2063,7 +2159,7 @@ function computeDivergence(facts) {
2063
2159
  });
2064
2160
  }
2065
2161
  if (facts.remoteTrackingExists === false) {
2066
- out.push({
2162
+ out2.push({
2067
2163
  id: "branch.unpushed-missing-remote",
2068
2164
  status: "open",
2069
2165
  scope: "branch",
@@ -2077,7 +2173,7 @@ function computeDivergence(facts) {
2077
2173
  const behind = facts.behind ?? 0;
2078
2174
  const ahead = facts.ahead ?? 0;
2079
2175
  if (behind > 0) {
2080
- out.push({
2176
+ out2.push({
2081
2177
  id: "branch.behind",
2082
2178
  status: "info",
2083
2179
  scope: "branch",
@@ -2087,7 +2183,7 @@ function computeDivergence(facts) {
2087
2183
  });
2088
2184
  }
2089
2185
  if (facts.upstream != null && facts.headMatchesUpstream === false) {
2090
- out.push({
2186
+ out2.push({
2091
2187
  id: "branch.unpushed-commits",
2092
2188
  status: "warn",
2093
2189
  scope: "branch",
@@ -2098,7 +2194,7 @@ function computeDivergence(facts) {
2098
2194
  }
2099
2195
  if (facts.unmergedMigrations.length > 0) {
2100
2196
  const n = facts.unmergedMigrations.length;
2101
- out.push({
2197
+ out2.push({
2102
2198
  id: "branch.unmerged-migrations",
2103
2199
  status: "info",
2104
2200
  scope: "branch",
@@ -2108,7 +2204,7 @@ function computeDivergence(facts) {
2108
2204
  });
2109
2205
  }
2110
2206
  if (facts.isSharedMainTree && facts.otherWorktrees > 0 && facts.uncommitted > 0 && !onFeatureBranch) {
2111
- out.push({
2207
+ out2.push({
2112
2208
  id: "worktree.direct-on-shared-base",
2113
2209
  status: "warn",
2114
2210
  scope: "worktree",
@@ -2118,7 +2214,7 @@ function computeDivergence(facts) {
2118
2214
  });
2119
2215
  }
2120
2216
  if (facts.inProgressOp) {
2121
- out.push({
2217
+ out2.push({
2122
2218
  id: "worktree.in-progress-op",
2123
2219
  status: "warn",
2124
2220
  scope: "worktree",
@@ -2129,7 +2225,7 @@ function computeDivergence(facts) {
2129
2225
  }
2130
2226
  if (facts.worktreeParity && facts.worktreeParity.missing.length > 0) {
2131
2227
  const miss = facts.worktreeParity.missing;
2132
- out.push({
2228
+ out2.push({
2133
2229
  id: "worktree.parity-missing",
2134
2230
  status: "open",
2135
2231
  scope: "worktree",
@@ -2139,7 +2235,7 @@ function computeDivergence(facts) {
2139
2235
  });
2140
2236
  }
2141
2237
  if (facts.release?.allRed) {
2142
- out.push({
2238
+ out2.push({
2143
2239
  id: "release.all-checks-red",
2144
2240
  status: "warn",
2145
2241
  scope: "release",
@@ -2148,7 +2244,22 @@ function computeDivergence(facts) {
2148
2244
  hint: "Check the CI provider's billing/spending status before debugging code."
2149
2245
  });
2150
2246
  }
2151
- return sortFindings(out);
2247
+ const hookFinding = computeHookFinding(facts.hooks);
2248
+ if (hookFinding)
2249
+ out2.push(hookFinding);
2250
+ return sortFindings(out2);
2251
+ }
2252
+ function computeHookFinding(hooks) {
2253
+ if (!hooks || hooks.verdict !== "present_unwired")
2254
+ return null;
2255
+ return {
2256
+ id: "setup.hooks-unwired",
2257
+ status: "warn",
2258
+ scope: "setup",
2259
+ title: "Git-Hooks liegen im Repo, feuern aber nicht",
2260
+ detail: describeHookState(hooks),
2261
+ hint: hooks.reason === "path_missing" ? `core.hooksPath zeigt ins Leere. Korrigieren: git config core.hooksPath ${hooks.hookDirs[0] ?? ".githooks"}` : `git config core.hooksPath ${hooks.hookDirs[0] ?? ".githooks"} \u2014 git klont das Verzeichnis mit, den Pfad nie.`
2262
+ };
2152
2263
  }
2153
2264
  var STATUS_ORDER = { open: 0, warn: 1, info: 2, passed: 3 };
2154
2265
  function sortFindings(f) {
@@ -2189,11 +2300,11 @@ function detectInProgressOp(repoRoot2) {
2189
2300
  return null;
2190
2301
  }
2191
2302
  function parseWorktrees(raw) {
2192
- const out = [];
2303
+ const out2 = [];
2193
2304
  let cur = null;
2194
2305
  const flush = () => {
2195
2306
  if (cur?.path)
2196
- out.push({ path: cur.path, branch: cur.branch, detached: cur.detached ?? false });
2307
+ out2.push({ path: cur.path, branch: cur.branch, detached: cur.detached ?? false });
2197
2308
  };
2198
2309
  for (const line of raw.split("\n")) {
2199
2310
  if (line.startsWith("worktree ")) {
@@ -2208,7 +2319,7 @@ function parseWorktrees(raw) {
2208
2319
  }
2209
2320
  }
2210
2321
  flush();
2211
- return out;
2322
+ return out2;
2212
2323
  }
2213
2324
  function readWorktreeRequirements(repoRoot2) {
2214
2325
  const p = posix3.join(repoRoot2, WORKTREE_REQUIREMENTS_RELPATH);
@@ -2239,7 +2350,8 @@ async function gatherRepoHealthFacts(repoRoot2, opts = {}) {
2239
2350
  otherWorktrees: 0,
2240
2351
  worktreeParity: null,
2241
2352
  release: null,
2242
- unmergedMigrations: []
2353
+ unmergedMigrations: [],
2354
+ hooks: null
2243
2355
  };
2244
2356
  }
2245
2357
  const branchRaw = trimOrNull(runGit(repoRoot2, ["rev-parse", "--abbrev-ref", "HEAD"]));
@@ -2318,7 +2430,8 @@ async function gatherRepoHealthFacts(repoRoot2, opts = {}) {
2318
2430
  otherWorktrees,
2319
2431
  worktreeParity,
2320
2432
  release,
2321
- unmergedMigrations
2433
+ unmergedMigrations,
2434
+ hooks: resolveHookState(repoRoot2)
2322
2435
  };
2323
2436
  }
2324
2437
  function samePath(a, b) {
@@ -2349,7 +2462,7 @@ function gatherReleaseFact(repoRoot2, branch) {
2349
2462
  }
2350
2463
  function runGh(repoRoot2, args) {
2351
2464
  try {
2352
- return execFileSync4("gh", args, {
2465
+ return execFileSync5("gh", args, {
2353
2466
  cwd: repoRoot2,
2354
2467
  encoding: "utf8",
2355
2468
  stdio: ["ignore", "pipe", "ignore"],
@@ -2366,6 +2479,318 @@ async function checkDivergence(repoRoot2, opts = {}) {
2366
2479
  return { ok: isHealthy(findings), findings, facts };
2367
2480
  }
2368
2481
 
2482
+ // ../../packages/code-index/build/repo-health/number-collisions.js
2483
+ import { existsSync as existsSync3, readdirSync as readdirSync3 } from "node:fs";
2484
+ import { posix as posix4 } from "node:path";
2485
+ var NUMBERED_RE = /^(?<prefix>[A-Za-z][A-Za-z_.-]*?[-_])?(?<num>\d{2,})(?=[-_.])/;
2486
+ var DEFAULT_MIN_FILES = 3;
2487
+ var DEFAULT_MIN_DISTINCT_RATIO = 0.8;
2488
+ function isCounterNamespace(numbers, opts = {}) {
2489
+ const minFiles = opts.minFiles ?? DEFAULT_MIN_FILES;
2490
+ if (numbers.length < minFiles)
2491
+ return false;
2492
+ const distinct = new Set(numbers).size;
2493
+ return distinct / numbers.length >= (opts.minDistinctRatio ?? DEFAULT_MIN_DISTINCT_RATIO);
2494
+ }
2495
+ function namespaceKey(ns) {
2496
+ return `${ns.dir}#${ns.prefix}`;
2497
+ }
2498
+ function parseNumbered(fileName) {
2499
+ const m = NUMBERED_RE.exec(fileName);
2500
+ if (!m?.groups)
2501
+ return null;
2502
+ return { prefix: m.groups.prefix ?? "", number: m.groups.num };
2503
+ }
2504
+ function computeNumberCollisions(facts) {
2505
+ const out2 = [];
2506
+ if (!facts.isRepo)
2507
+ return out2;
2508
+ const added = new Set(facts.addedPaths);
2509
+ for (const ns of facts.namespaces) {
2510
+ const key = namespaceKey(ns);
2511
+ const byNumber = facts.sightingsByNamespace.get(key);
2512
+ if (!byNumber)
2513
+ continue;
2514
+ const taken = new Set(byNumber.keys());
2515
+ for (const [number, sightings] of byNumber) {
2516
+ const paths = [...new Set(sightings.map((s) => s.path))];
2517
+ if (paths.length < 2)
2518
+ continue;
2519
+ const ownPath = paths.find((p) => added.has(p));
2520
+ const others = paths.filter((p) => p !== ownPath);
2521
+ const label = `${ns.prefix}${number}`;
2522
+ out2.push(ownPath ? {
2523
+ id: `number.collision:${key}#${number}`,
2524
+ status: "open",
2525
+ namespace: ns,
2526
+ number,
2527
+ title: `${label} is already taken`,
2528
+ detail: `This branch adds ${ownPath}, but ${label} already exists as ${others.join(", ")}. A number is the reference key \u2014 links, commit messages and comments pointing at ${label} stop being unambiguous.`,
2529
+ ownPath,
2530
+ sightings: sightings.filter((s) => s.path !== ownPath),
2531
+ suggestion: `${ns.prefix}${suggestNextNumber(taken, number)}`,
2532
+ hint: `Rename yours (git mv) to the suggested number and update every reference: title/frontmatter, any index file, wiki-style links, and comments naming the old filename. Already-merged references (commit messages, applied migrations) stay as they are \u2014 they are history.`
2533
+ } : {
2534
+ id: `number.collision:${key}#${number}`,
2535
+ status: "info",
2536
+ namespace: ns,
2537
+ number,
2538
+ title: `${label} is used more than once (pre-existing)`,
2539
+ detail: `${label} is carried by ${paths.length} files: ${paths.join(", ")}.`,
2540
+ sightings,
2541
+ hint: "Not introduced by this branch \u2014 inventory, not a blocker."
2542
+ });
2543
+ }
2544
+ }
2545
+ const order = { open: 0, warn: 1, info: 2, passed: 3 };
2546
+ return out2.sort((a, b) => order[a.status] - order[b.status] || a.id.localeCompare(b.id));
2547
+ }
2548
+ function isCollisionFree(findings) {
2549
+ return !findings.some((f) => f.status === "open");
2550
+ }
2551
+ function suggestNextNumber(taken, like) {
2552
+ let max = 0;
2553
+ for (const t of taken) {
2554
+ const n = Number(t);
2555
+ if (Number.isFinite(n))
2556
+ max = Math.max(max, n);
2557
+ }
2558
+ return String(max + 1).padStart(like.length, "0");
2559
+ }
2560
+ function normaliseRepoPath(p) {
2561
+ return p.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "");
2562
+ }
2563
+ function checkProposedNumber(facts, proposedPath) {
2564
+ const path = normaliseRepoPath(proposedPath);
2565
+ const abstain = {
2566
+ path,
2567
+ namespace: null,
2568
+ number: null,
2569
+ taken: false,
2570
+ sightings: [],
2571
+ suggestion: null
2572
+ };
2573
+ const parsed = parseNumbered(posix4.basename(path));
2574
+ if (!parsed)
2575
+ return abstain;
2576
+ const key = `${posix4.dirname(path)}#${parsed.prefix}`;
2577
+ const namespace = facts.namespaces.find((ns) => namespaceKey(ns) === key) ?? null;
2578
+ if (!namespace)
2579
+ return { ...abstain, number: parsed.number };
2580
+ const byNumber = facts.sightingsByNamespace.get(key) ?? /* @__PURE__ */ new Map();
2581
+ const seen = /* @__PURE__ */ new Set();
2582
+ const sightings = [];
2583
+ for (const s of byNumber.get(parsed.number) ?? []) {
2584
+ if (s.path === path || seen.has(s.path))
2585
+ continue;
2586
+ seen.add(s.path);
2587
+ sightings.push(s);
2588
+ }
2589
+ return {
2590
+ path,
2591
+ namespace,
2592
+ number: parsed.number,
2593
+ taken: sightings.length > 0,
2594
+ sightings,
2595
+ suggestion: suggestNextNumber(byNumber.keys(), parsed.number)
2596
+ };
2597
+ }
2598
+ function trimOrNull2(s) {
2599
+ const t = s?.trim();
2600
+ return t ? t : null;
2601
+ }
2602
+ function lines(out2) {
2603
+ return out2 ? out2.split("\n").filter(Boolean) : [];
2604
+ }
2605
+ function resolveDefaultBranch3(repoRoot2) {
2606
+ const sym = trimOrNull2(runGit(repoRoot2, ["symbolic-ref", "--quiet", "refs/remotes/origin/HEAD"]));
2607
+ if (sym) {
2608
+ const m = /refs\/remotes\/origin\/(.+)$/.exec(sym);
2609
+ if (m)
2610
+ return m[1];
2611
+ }
2612
+ for (const cand of ["main", "master"]) {
2613
+ if (runGit(repoRoot2, ["rev-parse", "--verify", "--quiet", `origin/${cand}`]) !== null) {
2614
+ return cand;
2615
+ }
2616
+ }
2617
+ return null;
2618
+ }
2619
+ function detectNamespaces(repoRoot2, opts = {}) {
2620
+ const minFiles = opts.minFiles ?? DEFAULT_MIN_FILES;
2621
+ const args = ["ls-files", "-z", "--"];
2622
+ args.push(...opts.dirs?.length ? opts.dirs : ["."]);
2623
+ const raw = runGit(repoRoot2, args);
2624
+ if (raw === null)
2625
+ return [];
2626
+ const candidates = /* @__PURE__ */ new Map();
2627
+ for (const path of raw.split("\0").filter(Boolean)) {
2628
+ const dir = posix4.dirname(path);
2629
+ const parsed = parseNumbered(posix4.basename(path));
2630
+ if (!parsed)
2631
+ continue;
2632
+ const key = `${dir}#${parsed.prefix}`;
2633
+ const existing = candidates.get(key);
2634
+ if (existing)
2635
+ existing.numbers.push(parsed.number);
2636
+ else
2637
+ candidates.set(key, { dir, prefix: parsed.prefix, numbers: [parsed.number] });
2638
+ }
2639
+ return [...candidates.values()].filter((c) => isCounterNamespace(c.numbers, { ...opts, minFiles })).map((c) => ({
2640
+ dir: c.dir,
2641
+ prefix: c.prefix,
2642
+ fileCount: c.numbers.length,
2643
+ distinctRatio: new Set(c.numbers).size / c.numbers.length
2644
+ })).sort((a, b) => namespaceKey(a).localeCompare(namespaceKey(b)));
2645
+ }
2646
+ async function gatherNumberCollisionFacts(repoRoot2, opts = {}) {
2647
+ const skipped = [];
2648
+ const inside = trimOrNull2(runGit(repoRoot2, ["rev-parse", "--is-inside-work-tree"]));
2649
+ if (inside !== "true") {
2650
+ return {
2651
+ isRepo: false,
2652
+ defaultBranch: null,
2653
+ namespaces: [],
2654
+ sightingsByNamespace: /* @__PURE__ */ new Map(),
2655
+ addedPaths: [],
2656
+ skipped: ["not a git work tree"]
2657
+ };
2658
+ }
2659
+ const namespaces = detectNamespaces(repoRoot2, opts);
2660
+ const nsByKey = new Map(namespaces.map((ns) => [namespaceKey(ns), ns]));
2661
+ const dirs = [...new Set(namespaces.map((ns) => ns.dir))];
2662
+ const sightingsByNamespace = /* @__PURE__ */ new Map();
2663
+ const record = (path, kind, where) => {
2664
+ const dir = posix4.dirname(path);
2665
+ const parsed = parseNumbered(posix4.basename(path));
2666
+ if (!parsed)
2667
+ return;
2668
+ const key = `${dir}#${parsed.prefix}`;
2669
+ if (!nsByKey.has(key))
2670
+ return;
2671
+ const byNumber = sightingsByNamespace.get(key) ?? /* @__PURE__ */ new Map();
2672
+ const list = byNumber.get(parsed.number) ?? [];
2673
+ list.push({ kind, where, path });
2674
+ byNumber.set(parsed.number, list);
2675
+ sightingsByNamespace.set(key, byNumber);
2676
+ };
2677
+ const scanTree = (ref, kind, where) => {
2678
+ if (dirs.length === 0)
2679
+ return;
2680
+ const out2 = runGit(repoRoot2, ["ls-tree", "-r", "--name-only", ref, "--", ...dirs]);
2681
+ if (out2 === null) {
2682
+ skipped.push(`could not read ${where}`);
2683
+ return;
2684
+ }
2685
+ for (const path of lines(out2))
2686
+ record(path, kind, where);
2687
+ };
2688
+ for (const dir of dirs) {
2689
+ const abs = posix4.join(repoRoot2, dir);
2690
+ if (!existsSync3(abs))
2691
+ continue;
2692
+ try {
2693
+ for (const file of readdirSync3(abs))
2694
+ record(`${dir}/${file}`, "self", "this worktree");
2695
+ } catch {
2696
+ skipped.push(`could not read ${dir}`);
2697
+ }
2698
+ }
2699
+ const defaultBranch = resolveDefaultBranch3(repoRoot2);
2700
+ if (defaultBranch) {
2701
+ scanTree(`origin/${defaultBranch}`, "default_branch", `origin/${defaultBranch}`);
2702
+ } else {
2703
+ skipped.push("no default branch resolvable (offline clone?) \u2014 base comparison skipped");
2704
+ }
2705
+ const currentBranch = trimOrNull2(runGit(repoRoot2, ["rev-parse", "--abbrev-ref", "HEAD"]));
2706
+ for (const branch of lines(runGit(repoRoot2, ["for-each-ref", "--format=%(refname:short)", "refs/heads"]))) {
2707
+ if (branch === currentBranch)
2708
+ continue;
2709
+ scanTree(branch, "branch", `Branch ${branch}`);
2710
+ }
2711
+ if (opts.includeWorktrees !== false) {
2712
+ const selfRoot = trimOrNull2(runGit(repoRoot2, ["rev-parse", "--show-toplevel"]));
2713
+ for (const line of lines(runGit(repoRoot2, ["worktree", "list", "--porcelain"]))) {
2714
+ if (!line.startsWith("worktree "))
2715
+ continue;
2716
+ const root = line.slice("worktree ".length).trim();
2717
+ if (!root || root === selfRoot || !existsSync3(root))
2718
+ continue;
2719
+ for (const dir of dirs) {
2720
+ const abs = posix4.join(root, dir);
2721
+ if (!existsSync3(abs))
2722
+ continue;
2723
+ try {
2724
+ for (const file of readdirSync3(abs)) {
2725
+ record(`${dir}/${file}`, "worktree", `Worktree ${root}`);
2726
+ }
2727
+ } catch {
2728
+ skipped.push(`could not read ${dir} in ${root}`);
2729
+ }
2730
+ }
2731
+ }
2732
+ }
2733
+ let addedPaths = [];
2734
+ if (defaultBranch && dirs.length > 0) {
2735
+ const diff = runGit(repoRoot2, [
2736
+ "diff",
2737
+ "--name-only",
2738
+ "--diff-filter=A",
2739
+ `origin/${defaultBranch}...HEAD`,
2740
+ "--",
2741
+ ...dirs
2742
+ ]);
2743
+ if (diff === null) {
2744
+ skipped.push("could not diff against the default branch \u2014 everything reported as info");
2745
+ } else {
2746
+ addedPaths = lines(diff);
2747
+ }
2748
+ const untracked = runGit(repoRoot2, [
2749
+ "ls-files",
2750
+ "--others",
2751
+ "--exclude-standard",
2752
+ "--",
2753
+ ...dirs
2754
+ ]);
2755
+ if (untracked !== null)
2756
+ addedPaths = [...addedPaths, ...lines(untracked)];
2757
+ const stagedAdds = runGit(repoRoot2, [
2758
+ "diff",
2759
+ "--cached",
2760
+ "--name-only",
2761
+ "--diff-filter=A",
2762
+ "--",
2763
+ ...dirs
2764
+ ]);
2765
+ if (stagedAdds !== null)
2766
+ addedPaths = [...addedPaths, ...lines(stagedAdds)];
2767
+ }
2768
+ return {
2769
+ isRepo: true,
2770
+ defaultBranch,
2771
+ namespaces,
2772
+ sightingsByNamespace,
2773
+ addedPaths,
2774
+ skipped
2775
+ };
2776
+ }
2777
+ async function checkNumberCollisions(repoRoot2, opts = {}) {
2778
+ const facts = await gatherNumberCollisionFacts(repoRoot2, opts);
2779
+ const findings = computeNumberCollisions(facts);
2780
+ return { ok: isCollisionFree(findings), findings, facts };
2781
+ }
2782
+ async function checkNumberForPath(repoRoot2, proposedPath, opts = {}) {
2783
+ const path = normaliseRepoPath(proposedPath);
2784
+ if (!parseNumbered(posix4.basename(path))) {
2785
+ return { path, namespace: null, number: null, taken: false, sightings: [], suggestion: null };
2786
+ }
2787
+ const facts = await gatherNumberCollisionFacts(repoRoot2, {
2788
+ ...opts,
2789
+ dirs: opts.dirs ?? [posix4.dirname(path)]
2790
+ });
2791
+ return checkProposedNumber(facts, path);
2792
+ }
2793
+
2369
2794
  // ../../packages/code-index/build/review/risk-rules.js
2370
2795
  var RISK_RULES = [
2371
2796
  {
@@ -2690,13 +3115,13 @@ var CodeIndexEngine = class {
2690
3115
  await this.store.init();
2691
3116
  const limit = clampLimit(opts.limit, 20, 100);
2692
3117
  const hits = await this.store.searchFts(query, opts.kind ?? null, limit);
2693
- const out = [];
3118
+ const out2 = [];
2694
3119
  for (const h of hits) {
2695
3120
  const n = await this.store.getNode(h.nodeKey);
2696
3121
  if (n)
2697
- out.push({ ...toHit(n), score: h.score });
3122
+ out2.push({ ...toHit(n), score: h.score });
2698
3123
  }
2699
- return out;
3124
+ return out2;
2700
3125
  }
2701
3126
  async semanticQuery(query, opts = {}) {
2702
3127
  await this.store.init();
@@ -2706,13 +3131,13 @@ var CodeIndexEngine = class {
2706
3131
  const qvec = await this.embedder.embedQuery(query);
2707
3132
  const all = await this.store.allEmbeddings();
2708
3133
  const scored = all.map((e) => ({ nodeKey: e.nodeKey, score: cosineSimilarity(qvec, e.vec) })).sort((a, b) => b.score - a.score).slice(0, limit);
2709
- const out = [];
3134
+ const out2 = [];
2710
3135
  for (const s of scored) {
2711
3136
  const n = await this.store.getNode(s.nodeKey);
2712
3137
  if (n)
2713
- out.push({ ...toHit(n), score: s.score });
3138
+ out2.push({ ...toHit(n), score: s.score });
2714
3139
  }
2715
- return out;
3140
+ return out2;
2716
3141
  }
2717
3142
  async tracePath(nodeKey, opts = {}) {
2718
3143
  await this.store.init();
@@ -2754,7 +3179,7 @@ var CodeIndexEngine = class {
2754
3179
  return null;
2755
3180
  let source = "";
2756
3181
  try {
2757
- const full = readFileSync5(posix4.join(this.repoRoot, n.filePath), "utf8");
3182
+ const full = readFileSync5(posix5.join(this.repoRoot, n.filePath), "utf8");
2758
3183
  source = full.slice(n.startByte, n.endByte);
2759
3184
  } catch {
2760
3185
  return null;
@@ -2825,6 +3250,12 @@ var CodeIndexEngine = class {
2825
3250
  async checkDivergence(opts = {}) {
2826
3251
  return checkDivergence(this.repoRoot, opts);
2827
3252
  }
3253
+ async checkNumberCollisions(opts = {}) {
3254
+ return checkNumberCollisions(this.repoRoot, opts);
3255
+ }
3256
+ async checkNumberForPath(proposedPath, opts = {}) {
3257
+ return checkNumberForPath(this.repoRoot, proposedPath, opts);
3258
+ }
2828
3259
  async reviewChanges(opts = {}) {
2829
3260
  await this.store.init();
2830
3261
  const rawPaths = enumerateChangedPaths(this.repoRoot, opts);
@@ -2888,7 +3319,7 @@ var CodeIndexEngine = class {
2888
3319
  }
2889
3320
  readRepoFile(relPath) {
2890
3321
  try {
2891
- return readFileSync5(posix4.join(this.repoRoot, relPath), "utf8");
3322
+ return readFileSync5(posix5.join(this.repoRoot, relPath), "utf8");
2892
3323
  } catch {
2893
3324
  return null;
2894
3325
  }
@@ -2947,8 +3378,109 @@ function classifyReviewSymbol(row, fileStatus, fh, stale) {
2947
3378
  return { ...row, change: "co_located", changedLineCount: 0, staleIndex: false };
2948
3379
  }
2949
3380
 
3381
+ // ../../packages/code-index/build/store/sqlite-driver.js
3382
+ import { createRequire as createRequire2 } from "node:module";
3383
+ var requireHost = createRequire2(import.meta.url);
3384
+ function loadBuiltin() {
3385
+ return requireHost("node:sqlite");
3386
+ }
3387
+ var builtinProbeCache = null;
3388
+ function probeBuiltinSqlite() {
3389
+ if (builtinProbeCache)
3390
+ return builtinProbeCache;
3391
+ try {
3392
+ const { DatabaseSync } = loadBuiltin();
3393
+ const db = new DatabaseSync(":memory:");
3394
+ try {
3395
+ db.exec("CREATE VIRTUAL TABLE probe_fts USING fts5(t)");
3396
+ db.exec("INSERT INTO probe_fts (t) VALUES ('probe')");
3397
+ db.prepare("SELECT bm25(probe_fts) AS s FROM probe_fts WHERE probe_fts MATCH 'probe'").get();
3398
+ builtinProbeCache = { ok: true };
3399
+ } finally {
3400
+ db.close();
3401
+ }
3402
+ } catch (err4) {
3403
+ builtinProbeCache = {
3404
+ ok: false,
3405
+ reason: err4 instanceof Error ? err4.message : String(err4)
3406
+ };
3407
+ }
3408
+ return builtinProbeCache;
3409
+ }
3410
+ function openBuiltin(dbPath) {
3411
+ const { DatabaseSync } = loadBuiltin();
3412
+ const raw = new DatabaseSync(dbPath);
3413
+ return {
3414
+ prepare: (sql) => raw.prepare(sql),
3415
+ exec: (sql) => raw.exec(sql),
3416
+ close: () => raw.close(),
3417
+ // node:sqlite hat keinen .transaction()-Helper — manuelle Klammer.
3418
+ transaction: (fn) => () => {
3419
+ raw.exec("BEGIN");
3420
+ try {
3421
+ fn();
3422
+ raw.exec("COMMIT");
3423
+ } catch (err4) {
3424
+ try {
3425
+ raw.exec("ROLLBACK");
3426
+ } catch {
3427
+ }
3428
+ throw err4;
3429
+ }
3430
+ }
3431
+ };
3432
+ }
3433
+ function openBetter(dbPath) {
3434
+ const Database = requireHost("better-sqlite3");
3435
+ const raw = new Database(dbPath);
3436
+ return {
3437
+ prepare: (sql) => raw.prepare(sql),
3438
+ exec: (sql) => {
3439
+ raw.exec(sql);
3440
+ },
3441
+ close: () => {
3442
+ raw.close();
3443
+ },
3444
+ transaction: (fn) => raw.transaction(fn)
3445
+ };
3446
+ }
3447
+ function backendOverride() {
3448
+ const v = (process.env.MAIND_SQLITE_BACKEND ?? "").trim().toLowerCase();
3449
+ if (v === "builtin" || v === "better")
3450
+ return v;
3451
+ return null;
3452
+ }
3453
+ function openSqliteDatabase(dbPath) {
3454
+ const override = backendOverride();
3455
+ const openAs = (backend) => {
3456
+ const db = backend === "node:sqlite" ? openBuiltin(dbPath) : openBetter(dbPath);
3457
+ db.exec("PRAGMA journal_mode = WAL");
3458
+ db.exec("PRAGMA foreign_keys = ON");
3459
+ return { db, backend };
3460
+ };
3461
+ if (override === "builtin") {
3462
+ const probe2 = probeBuiltinSqlite();
3463
+ if (!probe2.ok) {
3464
+ throw new Error(`MAIND_SQLITE_BACKEND=builtin, but node:sqlite is unusable: ${probe2.reason}`);
3465
+ }
3466
+ return openAs("node:sqlite");
3467
+ }
3468
+ if (override === "better") {
3469
+ return openAs("better-sqlite3");
3470
+ }
3471
+ const probe = probeBuiltinSqlite();
3472
+ if (probe.ok) {
3473
+ return openAs("node:sqlite");
3474
+ }
3475
+ try {
3476
+ return openAs("better-sqlite3");
3477
+ } catch (err4) {
3478
+ const betterReason = err4 instanceof Error ? err4.message : String(err4);
3479
+ throw new Error(`no usable SQLite backend: node:sqlite unavailable (${probe.reason}); better-sqlite3 unavailable (${betterReason})`);
3480
+ }
3481
+ }
3482
+
2950
3483
  // ../../packages/code-index/build/store/node-sqlite.js
2951
- import Database from "better-sqlite3";
2952
3484
  function toNodeRow(r) {
2953
3485
  return {
2954
3486
  nodeKey: r.node_key,
@@ -2968,10 +3500,12 @@ function toNodeRow(r) {
2968
3500
  var CHUNK = 400;
2969
3501
  var NodeSqliteStore = class {
2970
3502
  db;
3503
+ /** Welches Backend diesen Store trägt — für Diagnose/Status-Ausgaben. */
3504
+ backend;
2971
3505
  constructor(dbPath) {
2972
- this.db = new Database(dbPath);
2973
- this.db.pragma("journal_mode = WAL");
2974
- this.db.pragma("foreign_keys = ON");
3506
+ const opened = openSqliteDatabase(dbPath);
3507
+ this.db = opened.db;
3508
+ this.backend = opened.backend;
2975
3509
  }
2976
3510
  async init() {
2977
3511
  this.db.exec(SCHEMA_SQL);
@@ -3102,7 +3636,7 @@ var NodeSqliteStore = class {
3102
3636
  }
3103
3637
  async pruneOrphanEmbeddings() {
3104
3638
  const info = this.db.prepare("DELETE FROM embeddings WHERE node_key NOT IN (SELECT node_key FROM nodes)").run();
3105
- return info.changes;
3639
+ return Number(info.changes);
3106
3640
  }
3107
3641
  async countEmbeddings() {
3108
3642
  return this.db.prepare("SELECT COUNT(*) AS c FROM embeddings").get().c;
@@ -3444,10 +3978,10 @@ var CodeIndexSync = class {
3444
3978
  };
3445
3979
  var EMBED_CHUNK = 250;
3446
3980
  function chunkArray(items, size) {
3447
- const out = [];
3981
+ const out2 = [];
3448
3982
  for (let i = 0; i < items.length; i += size)
3449
- out.push(items.slice(i, i + size));
3450
- return out;
3983
+ out2.push(items.slice(i, i + size));
3984
+ return out2;
3451
3985
  }
3452
3986
  function numOrNull(v) {
3453
3987
  if (v === null)
@@ -3462,8 +3996,8 @@ function numOr0(v) {
3462
3996
  // ../../packages/code-index/build/node.js
3463
3997
  var DEFAULT_DB_RELPATH = ".maind/code-index.sqlite";
3464
3998
  function createNodeCodeIndex(opts) {
3465
- const dbPath = opts.dbPath ?? posix5.join(opts.repoRoot, DEFAULT_DB_RELPATH);
3466
- mkdirSync3(posix5.dirname(dbPath), { recursive: true });
3999
+ const dbPath = opts.dbPath ?? posix6.join(opts.repoRoot, DEFAULT_DB_RELPATH);
4000
+ mkdirSync3(posix6.dirname(dbPath), { recursive: true });
3467
4001
  const store = new NodeSqliteStore(dbPath);
3468
4002
  const parser = new TreeSitterParser();
3469
4003
  return new CodeIndexEngine({
@@ -3474,7 +4008,7 @@ function createNodeCodeIndex(opts) {
3474
4008
  });
3475
4009
  }
3476
4010
  function createCodeIndexSync(opts) {
3477
- const dbPath = opts.dbPath ?? posix5.join(opts.repoRoot, DEFAULT_DB_RELPATH);
4011
+ const dbPath = opts.dbPath ?? posix6.join(opts.repoRoot, DEFAULT_DB_RELPATH);
3478
4012
  const projectKey = opts.projectKey ?? computeProjectKey(opts.repoRoot) ?? void 0;
3479
4013
  if (!projectKey) {
3480
4014
  throw new Error("No project_key \u2014 the repo has no git remote. Cloud sync scopes by sha256(remote); commit a remote or pass an explicit key.");
@@ -3517,8 +4051,8 @@ function createEmbedder() {
3517
4051
  if (texts.length === 0)
3518
4052
  return [];
3519
4053
  const extractor = await getExtractor();
3520
- const out = await extractor(texts, { pooling: "cls", normalize: true });
3521
- return out.tolist().map((v) => Float32Array.from(v));
4054
+ const out2 = await extractor(texts, { pooling: "cls", normalize: true });
4055
+ return out2.tolist().map((v) => Float32Array.from(v));
3522
4056
  },
3523
4057
  async embedQuery(text) {
3524
4058
  const [vec] = await embedder.embedDocuments([
@@ -3557,13 +4091,13 @@ function isOrtWorker(argv) {
3557
4091
  return argv.includes(WORKER_FLAG);
3558
4092
  }
3559
4093
  function runOrtIsolated(argv) {
3560
- const dir = mkdtempSync(join4(tmpdir(), "maind-ort-"));
3561
- const okFile = join4(dir, "ok");
4094
+ const dir = mkdtempSync(join5(tmpdir(), "maind-ort-"));
4095
+ const okFile = join5(dir, "ok");
3562
4096
  const res = spawnSync(process.execPath, [CLI_ENTRY, ...argv, WORKER_FLAG], {
3563
4097
  stdio: ["ignore", "inherit", "inherit"],
3564
4098
  env: { ...process.env, [OK_FILE_ENV]: okFile }
3565
4099
  });
3566
- const ok = existsSync3(okFile);
4100
+ const ok = existsSync4(okFile);
3567
4101
  try {
3568
4102
  rmSync(dirname3(okFile), { recursive: true, force: true });
3569
4103
  } catch {
@@ -3591,7 +4125,7 @@ function value(argv, name) {
3591
4125
  function resolveRoot(explicit) {
3592
4126
  if (explicit) return explicit;
3593
4127
  try {
3594
- return execFileSync5("git", ["rev-parse", "--show-toplevel"], {
4128
+ return execFileSync6("git", ["rev-parse", "--show-toplevel"], {
3595
4129
  encoding: "utf8",
3596
4130
  stdio: ["ignore", "pipe", "ignore"]
3597
4131
  }).trim();
@@ -3765,90 +4299,1645 @@ async function runIndexArch(opts) {
3765
4299
  }
3766
4300
  }
3767
4301
 
3768
- // src/review.ts
3769
- import { execFileSync as execFileSync6 } from "node:child_process";
3770
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "node:fs";
3771
- import { dirname as dirname4 } from "node:path";
3772
-
3773
- // ../../packages/code-index/build/index.js
3774
- var CODE_INDEX_VERSION = "0.1.0";
4302
+ // src/launch-cmd.ts
4303
+ import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync7 } from "node:child_process";
4304
+ import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
4305
+ import { homedir as homedir2 } from "node:os";
4306
+ import { dirname as dirname4, join as join6 } from "node:path";
3775
4307
 
3776
- // src/version.ts
3777
- import { createRequire as createRequire2 } from "node:module";
3778
- function resolveVersion() {
3779
- if (true) return "0.9.0";
3780
- try {
3781
- const require2 = createRequire2(import.meta.url);
3782
- return require2("../package.json").version;
3783
- } catch {
3784
- return "0.0.0-unknown";
4308
+ // ../../node_modules/.pnpm/smol-toml@1.6.1/node_modules/smol-toml/dist/error.js
4309
+ function getLineColFromPtr(string, ptr) {
4310
+ let lines2 = string.slice(0, ptr).split(/\r\n|\n|\r/g);
4311
+ return [lines2.length, lines2.pop().length + 1];
4312
+ }
4313
+ function makeCodeBlock(string, line, column) {
4314
+ let lines2 = string.split(/\r\n|\n|\r/g);
4315
+ let codeblock = "";
4316
+ let numberLen = (Math.log10(line + 1) | 0) + 1;
4317
+ for (let i = line - 1; i <= line + 1; i++) {
4318
+ let l = lines2[i - 1];
4319
+ if (!l)
4320
+ continue;
4321
+ codeblock += i.toString().padEnd(numberLen, " ");
4322
+ codeblock += ": ";
4323
+ codeblock += l;
4324
+ codeblock += "\n";
4325
+ if (i === line) {
4326
+ codeblock += " ".repeat(numberLen + column + 2);
4327
+ codeblock += "^\n";
4328
+ }
3785
4329
  }
4330
+ return codeblock;
3786
4331
  }
3787
- var VERSION = resolveVersion();
4332
+ var TomlError = class extends Error {
4333
+ line;
4334
+ column;
4335
+ codeblock;
4336
+ constructor(message, options) {
4337
+ const [line, column] = getLineColFromPtr(options.toml, options.ptr);
4338
+ const codeblock = makeCodeBlock(options.toml, line, column);
4339
+ super(`Invalid TOML document: ${message}
3788
4340
 
3789
- // src/review-render.ts
3790
- var COMMENT_MARKER = "<!-- maind-review -->";
3791
- var COMMENT_FINDINGS_CAP = 30;
3792
- var FOOTER = "maind review \xB7 deterministic, provenance-backed";
3793
- function buildReviewManifest(data, verdict, meta) {
3794
- const review = data.review;
3795
- return {
3796
- schema: "maind.review.manifest/v1",
3797
- generated_at: meta.generatedAt,
3798
- key_prefix: meta.keyPrefix,
3799
- run_ref: meta.runRef,
3800
- base: meta.base,
3801
- diff_stats: meta.diffStats,
3802
- symbol_count: meta.symbolCount,
3803
- risk_flags: review?.risk_flags ?? [],
3804
- findings: (review?.convention_findings ?? []).map((f) => ({
3805
- convention_id: f.convention_id,
3806
- version: f.convention_version,
3807
- severity: f.severity,
3808
- grade: f.grade,
3809
- matched_symbol_count: f.matched_symbols.length,
3810
- matched_changed_symbol_count: f.matched_changed_symbols?.length ?? 0
3811
- })),
3812
- served: (review?.lesson_hints ?? []).map((l) => ({
3813
- id: l.id,
3814
- version: typeof l.version === "number" ? l.version : null,
3815
- tier: l.tier ?? null
3816
- })),
3817
- verdict: verdict?.ok === true && typeof verdict.verdict === "string" ? {
3818
- verdict: verdict.verdict,
3819
- counts: {
3820
- block: verdict.counts?.block ?? 0,
3821
- warn: verdict.counts?.warn ?? 0,
3822
- note: verdict.counts?.note ?? 0
3823
- },
3824
- fail_on: meta.failOn
3825
- } : null,
3826
- run: verdict?.ok === true ? verdict.run ?? null : null,
3827
- ...verdict?.ok === true && verdict.run_note ? { run_note: verdict.run_note } : {},
3828
- coverage_note: review?.coverage_note ?? null,
3829
- regression_context: review?.regression_context ?? null
3830
- };
3831
- }
3832
- function severityBadge(f) {
3833
- return `**[${f.severity}]**`;
3834
- }
3835
- function findingLine(f) {
3836
- const cite = `\`${f.convention_id}@v${f.convention_version}\``;
3837
- const grade = f.grade === "verdict" ? " \xB7 verdict-grade" : "";
3838
- const changed = f.matched_changed_symbols?.length ?? 0;
3839
- const matchInfo = changed > 0 ? `matched on changed symbols: ${formatSymbols(f.matched_changed_symbols ?? [])}` : `matched (co-located): ${formatSymbols(f.matched_symbols)}`;
3840
- const summary = f.summary?.trim() ? ` \u2014 ${f.summary.trim()}` : "";
3841
- return `- ${severityBadge(f)} ${cite}${summary}${grade}
3842
- ${matchInfo}`;
4341
+ ${codeblock}`, options);
4342
+ this.line = line;
4343
+ this.column = column;
4344
+ this.codeblock = codeblock;
4345
+ }
4346
+ };
4347
+
4348
+ // ../../node_modules/.pnpm/smol-toml@1.6.1/node_modules/smol-toml/dist/util.js
4349
+ function isEscaped(str, ptr) {
4350
+ let i = 0;
4351
+ while (str[ptr - ++i] === "\\")
4352
+ ;
4353
+ return --i && i % 2;
4354
+ }
4355
+ function indexOfNewline(str, start = 0, end = str.length) {
4356
+ let idx = str.indexOf("\n", start);
4357
+ if (str[idx - 1] === "\r")
4358
+ idx--;
4359
+ return idx <= end ? idx : -1;
4360
+ }
4361
+ function skipComment(str, ptr) {
4362
+ for (let i = ptr; i < str.length; i++) {
4363
+ let c = str[i];
4364
+ if (c === "\n")
4365
+ return i;
4366
+ if (c === "\r" && str[i + 1] === "\n")
4367
+ return i + 1;
4368
+ if (c < " " && c !== " " || c === "\x7F") {
4369
+ throw new TomlError("control characters are not allowed in comments", {
4370
+ toml: str,
4371
+ ptr
4372
+ });
4373
+ }
4374
+ }
4375
+ return str.length;
4376
+ }
4377
+ function skipVoid(str, ptr, banNewLines, banComments) {
4378
+ let c;
4379
+ while (1) {
4380
+ while ((c = str[ptr]) === " " || c === " " || !banNewLines && (c === "\n" || c === "\r" && str[ptr + 1] === "\n"))
4381
+ ptr++;
4382
+ if (banComments || c !== "#")
4383
+ break;
4384
+ ptr = skipComment(str, ptr);
4385
+ }
4386
+ return ptr;
4387
+ }
4388
+ function skipUntil(str, ptr, sep2, end, banNewLines = false) {
4389
+ if (!end) {
4390
+ ptr = indexOfNewline(str, ptr);
4391
+ return ptr < 0 ? str.length : ptr;
4392
+ }
4393
+ for (let i = ptr; i < str.length; i++) {
4394
+ let c = str[i];
4395
+ if (c === "#") {
4396
+ i = indexOfNewline(str, i);
4397
+ } else if (c === sep2) {
4398
+ return i + 1;
4399
+ } else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
4400
+ return i;
4401
+ }
4402
+ }
4403
+ throw new TomlError("cannot find end of structure", {
4404
+ toml: str,
4405
+ ptr
4406
+ });
3843
4407
  }
3844
- function formatSymbols(symbols, max = 4) {
3845
- const shown = symbols.slice(0, max).map((s) => `\`${s}\``);
3846
- const rest = symbols.length - shown.length;
3847
- return shown.join(", ") + (rest > 0 ? ` (+${rest} more)` : "");
4408
+ function getStringEnd(str, seek) {
4409
+ let first = str[seek];
4410
+ let target = first === str[seek + 1] && str[seek + 1] === str[seek + 2] ? str.slice(seek, seek + 3) : first;
4411
+ seek += target.length - 1;
4412
+ do
4413
+ seek = str.indexOf(target, ++seek);
4414
+ while (seek > -1 && first !== "'" && isEscaped(str, seek));
4415
+ if (seek > -1) {
4416
+ seek += target.length;
4417
+ if (target.length > 1) {
4418
+ if (str[seek] === first)
4419
+ seek++;
4420
+ if (str[seek] === first)
4421
+ seek++;
4422
+ }
4423
+ }
4424
+ return seek;
3848
4425
  }
3849
- function verdictLabel(verdict) {
3850
- const counts = verdict.counts ?? {};
3851
- return `**Verdict: ${(verdict.verdict ?? "?").toUpperCase()}** (block: ${counts.block ?? 0} \xB7 warn: ${counts.warn ?? 0} \xB7 note: ${counts.note ?? 0})`;
4426
+
4427
+ // ../../node_modules/.pnpm/smol-toml@1.6.1/node_modules/smol-toml/dist/date.js
4428
+ var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
4429
+ var TomlDate = class _TomlDate extends Date {
4430
+ #hasDate = false;
4431
+ #hasTime = false;
4432
+ #offset = null;
4433
+ constructor(date) {
4434
+ let hasDate = true;
4435
+ let hasTime = true;
4436
+ let offset = "Z";
4437
+ if (typeof date === "string") {
4438
+ let match = date.match(DATE_TIME_RE);
4439
+ if (match) {
4440
+ if (!match[1]) {
4441
+ hasDate = false;
4442
+ date = `0000-01-01T${date}`;
4443
+ }
4444
+ hasTime = !!match[2];
4445
+ hasTime && date[10] === " " && (date = date.replace(" ", "T"));
4446
+ if (match[2] && +match[2] > 23) {
4447
+ date = "";
4448
+ } else {
4449
+ offset = match[3] || null;
4450
+ date = date.toUpperCase();
4451
+ if (!offset && hasTime)
4452
+ date += "Z";
4453
+ }
4454
+ } else {
4455
+ date = "";
4456
+ }
4457
+ }
4458
+ super(date);
4459
+ if (!isNaN(this.getTime())) {
4460
+ this.#hasDate = hasDate;
4461
+ this.#hasTime = hasTime;
4462
+ this.#offset = offset;
4463
+ }
4464
+ }
4465
+ isDateTime() {
4466
+ return this.#hasDate && this.#hasTime;
4467
+ }
4468
+ isLocal() {
4469
+ return !this.#hasDate || !this.#hasTime || !this.#offset;
4470
+ }
4471
+ isDate() {
4472
+ return this.#hasDate && !this.#hasTime;
4473
+ }
4474
+ isTime() {
4475
+ return this.#hasTime && !this.#hasDate;
4476
+ }
4477
+ isValid() {
4478
+ return this.#hasDate || this.#hasTime;
4479
+ }
4480
+ toISOString() {
4481
+ let iso = super.toISOString();
4482
+ if (this.isDate())
4483
+ return iso.slice(0, 10);
4484
+ if (this.isTime())
4485
+ return iso.slice(11, 23);
4486
+ if (this.#offset === null)
4487
+ return iso.slice(0, -1);
4488
+ if (this.#offset === "Z")
4489
+ return iso;
4490
+ let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
4491
+ offset = this.#offset[0] === "-" ? offset : -offset;
4492
+ let offsetDate = new Date(this.getTime() - offset * 6e4);
4493
+ return offsetDate.toISOString().slice(0, -1) + this.#offset;
4494
+ }
4495
+ static wrapAsOffsetDateTime(jsDate, offset = "Z") {
4496
+ let date = new _TomlDate(jsDate);
4497
+ date.#offset = offset;
4498
+ return date;
4499
+ }
4500
+ static wrapAsLocalDateTime(jsDate) {
4501
+ let date = new _TomlDate(jsDate);
4502
+ date.#offset = null;
4503
+ return date;
4504
+ }
4505
+ static wrapAsLocalDate(jsDate) {
4506
+ let date = new _TomlDate(jsDate);
4507
+ date.#hasTime = false;
4508
+ date.#offset = null;
4509
+ return date;
4510
+ }
4511
+ static wrapAsLocalTime(jsDate) {
4512
+ let date = new _TomlDate(jsDate);
4513
+ date.#hasDate = false;
4514
+ date.#offset = null;
4515
+ return date;
4516
+ }
4517
+ };
4518
+
4519
+ // ../../node_modules/.pnpm/smol-toml@1.6.1/node_modules/smol-toml/dist/primitive.js
4520
+ var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
4521
+ var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
4522
+ var LEADING_ZERO = /^[+-]?0[0-9_]/;
4523
+ var ESCAPE_REGEX = /^[0-9a-f]{2,8}$/i;
4524
+ var ESC_MAP = {
4525
+ b: "\b",
4526
+ t: " ",
4527
+ n: "\n",
4528
+ f: "\f",
4529
+ r: "\r",
4530
+ e: "\x1B",
4531
+ '"': '"',
4532
+ "\\": "\\"
4533
+ };
4534
+ function parseString(str, ptr = 0, endPtr = str.length) {
4535
+ let isLiteral = str[ptr] === "'";
4536
+ let isMultiline = str[ptr++] === str[ptr] && str[ptr] === str[ptr + 1];
4537
+ if (isMultiline) {
4538
+ endPtr -= 2;
4539
+ if (str[ptr += 2] === "\r")
4540
+ ptr++;
4541
+ if (str[ptr] === "\n")
4542
+ ptr++;
4543
+ }
4544
+ let tmp = 0;
4545
+ let isEscape;
4546
+ let parsed = "";
4547
+ let sliceStart = ptr;
4548
+ while (ptr < endPtr - 1) {
4549
+ let c = str[ptr++];
4550
+ if (c === "\n" || c === "\r" && str[ptr] === "\n") {
4551
+ if (!isMultiline) {
4552
+ throw new TomlError("newlines are not allowed in strings", {
4553
+ toml: str,
4554
+ ptr: ptr - 1
4555
+ });
4556
+ }
4557
+ } else if (c < " " && c !== " " || c === "\x7F") {
4558
+ throw new TomlError("control characters are not allowed in strings", {
4559
+ toml: str,
4560
+ ptr: ptr - 1
4561
+ });
4562
+ }
4563
+ if (isEscape) {
4564
+ isEscape = false;
4565
+ if (c === "x" || c === "u" || c === "U") {
4566
+ let code = str.slice(ptr, ptr += c === "x" ? 2 : c === "u" ? 4 : 8);
4567
+ if (!ESCAPE_REGEX.test(code)) {
4568
+ throw new TomlError("invalid unicode escape", {
4569
+ toml: str,
4570
+ ptr: tmp
4571
+ });
4572
+ }
4573
+ try {
4574
+ parsed += String.fromCodePoint(parseInt(code, 16));
4575
+ } catch {
4576
+ throw new TomlError("invalid unicode escape", {
4577
+ toml: str,
4578
+ ptr: tmp
4579
+ });
4580
+ }
4581
+ } else if (isMultiline && (c === "\n" || c === " " || c === " " || c === "\r")) {
4582
+ ptr = skipVoid(str, ptr - 1, true);
4583
+ if (str[ptr] !== "\n" && str[ptr] !== "\r") {
4584
+ throw new TomlError("invalid escape: only line-ending whitespace may be escaped", {
4585
+ toml: str,
4586
+ ptr: tmp
4587
+ });
4588
+ }
4589
+ ptr = skipVoid(str, ptr);
4590
+ } else if (c in ESC_MAP) {
4591
+ parsed += ESC_MAP[c];
4592
+ } else {
4593
+ throw new TomlError("unrecognized escape sequence", {
4594
+ toml: str,
4595
+ ptr: tmp
4596
+ });
4597
+ }
4598
+ sliceStart = ptr;
4599
+ } else if (!isLiteral && c === "\\") {
4600
+ tmp = ptr - 1;
4601
+ isEscape = true;
4602
+ parsed += str.slice(sliceStart, tmp);
4603
+ }
4604
+ }
4605
+ return parsed + str.slice(sliceStart, endPtr - 1);
4606
+ }
4607
+ function parseValue(value2, toml, ptr, integersAsBigInt) {
4608
+ if (value2 === "true")
4609
+ return true;
4610
+ if (value2 === "false")
4611
+ return false;
4612
+ if (value2 === "-inf")
4613
+ return -Infinity;
4614
+ if (value2 === "inf" || value2 === "+inf")
4615
+ return Infinity;
4616
+ if (value2 === "nan" || value2 === "+nan" || value2 === "-nan")
4617
+ return NaN;
4618
+ if (value2 === "-0")
4619
+ return integersAsBigInt ? 0n : 0;
4620
+ let isInt = INT_REGEX.test(value2);
4621
+ if (isInt || FLOAT_REGEX.test(value2)) {
4622
+ if (LEADING_ZERO.test(value2)) {
4623
+ throw new TomlError("leading zeroes are not allowed", {
4624
+ toml,
4625
+ ptr
4626
+ });
4627
+ }
4628
+ value2 = value2.replace(/_/g, "");
4629
+ let numeric = +value2;
4630
+ if (isNaN(numeric)) {
4631
+ throw new TomlError("invalid number", {
4632
+ toml,
4633
+ ptr
4634
+ });
4635
+ }
4636
+ if (isInt) {
4637
+ if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) {
4638
+ throw new TomlError("integer value cannot be represented losslessly", {
4639
+ toml,
4640
+ ptr
4641
+ });
4642
+ }
4643
+ if (isInt || integersAsBigInt === true)
4644
+ numeric = BigInt(value2);
4645
+ }
4646
+ return numeric;
4647
+ }
4648
+ const date = new TomlDate(value2);
4649
+ if (!date.isValid()) {
4650
+ throw new TomlError("invalid value", {
4651
+ toml,
4652
+ ptr
4653
+ });
4654
+ }
4655
+ return date;
4656
+ }
4657
+
4658
+ // ../../node_modules/.pnpm/smol-toml@1.6.1/node_modules/smol-toml/dist/extract.js
4659
+ function sliceAndTrimEndOf(str, startPtr, endPtr) {
4660
+ let value2 = str.slice(startPtr, endPtr);
4661
+ let commentIdx = value2.indexOf("#");
4662
+ if (commentIdx > -1) {
4663
+ skipComment(str, commentIdx);
4664
+ value2 = value2.slice(0, commentIdx);
4665
+ }
4666
+ return [value2.trimEnd(), commentIdx];
4667
+ }
4668
+ function extractValue(str, ptr, end, depth, integersAsBigInt) {
4669
+ if (depth === 0) {
4670
+ throw new TomlError("document contains excessively nested structures. aborting.", {
4671
+ toml: str,
4672
+ ptr
4673
+ });
4674
+ }
4675
+ let c = str[ptr];
4676
+ if (c === "[" || c === "{") {
4677
+ let [value2, endPtr2] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt);
4678
+ if (end) {
4679
+ endPtr2 = skipVoid(str, endPtr2);
4680
+ if (str[endPtr2] === ",")
4681
+ endPtr2++;
4682
+ else if (str[endPtr2] !== end) {
4683
+ throw new TomlError("expected comma or end of structure", {
4684
+ toml: str,
4685
+ ptr: endPtr2
4686
+ });
4687
+ }
4688
+ }
4689
+ return [value2, endPtr2];
4690
+ }
4691
+ let endPtr;
4692
+ if (c === '"' || c === "'") {
4693
+ endPtr = getStringEnd(str, ptr);
4694
+ let parsed = parseString(str, ptr, endPtr);
4695
+ if (end) {
4696
+ endPtr = skipVoid(str, endPtr);
4697
+ if (str[endPtr] && str[endPtr] !== "," && str[endPtr] !== end && str[endPtr] !== "\n" && str[endPtr] !== "\r") {
4698
+ throw new TomlError("unexpected character encountered", {
4699
+ toml: str,
4700
+ ptr: endPtr
4701
+ });
4702
+ }
4703
+ endPtr += +(str[endPtr] === ",");
4704
+ }
4705
+ return [parsed, endPtr];
4706
+ }
4707
+ endPtr = skipUntil(str, ptr, ",", end);
4708
+ let slice = sliceAndTrimEndOf(str, ptr, endPtr - +(str[endPtr - 1] === ","));
4709
+ if (!slice[0]) {
4710
+ throw new TomlError("incomplete key-value declaration: no value specified", {
4711
+ toml: str,
4712
+ ptr
4713
+ });
4714
+ }
4715
+ if (end && slice[1] > -1) {
4716
+ endPtr = skipVoid(str, ptr + slice[1]);
4717
+ endPtr += +(str[endPtr] === ",");
4718
+ }
4719
+ return [
4720
+ parseValue(slice[0], str, ptr, integersAsBigInt),
4721
+ endPtr
4722
+ ];
4723
+ }
4724
+
4725
+ // ../../node_modules/.pnpm/smol-toml@1.6.1/node_modules/smol-toml/dist/struct.js
4726
+ var KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
4727
+ function parseKey(str, ptr, end = "=") {
4728
+ let dot = ptr - 1;
4729
+ let parsed = [];
4730
+ let endPtr = str.indexOf(end, ptr);
4731
+ if (endPtr < 0) {
4732
+ throw new TomlError("incomplete key-value: cannot find end of key", {
4733
+ toml: str,
4734
+ ptr
4735
+ });
4736
+ }
4737
+ do {
4738
+ let c = str[ptr = ++dot];
4739
+ if (c !== " " && c !== " ") {
4740
+ if (c === '"' || c === "'") {
4741
+ if (c === str[ptr + 1] && c === str[ptr + 2]) {
4742
+ throw new TomlError("multiline strings are not allowed in keys", {
4743
+ toml: str,
4744
+ ptr
4745
+ });
4746
+ }
4747
+ let eos = getStringEnd(str, ptr);
4748
+ if (eos < 0) {
4749
+ throw new TomlError("unfinished string encountered", {
4750
+ toml: str,
4751
+ ptr
4752
+ });
4753
+ }
4754
+ dot = str.indexOf(".", eos);
4755
+ let strEnd = str.slice(eos, dot < 0 || dot > endPtr ? endPtr : dot);
4756
+ let newLine = indexOfNewline(strEnd);
4757
+ if (newLine > -1) {
4758
+ throw new TomlError("newlines are not allowed in keys", {
4759
+ toml: str,
4760
+ ptr: ptr + dot + newLine
4761
+ });
4762
+ }
4763
+ if (strEnd.trimStart()) {
4764
+ throw new TomlError("found extra tokens after the string part", {
4765
+ toml: str,
4766
+ ptr: eos
4767
+ });
4768
+ }
4769
+ if (endPtr < eos) {
4770
+ endPtr = str.indexOf(end, eos);
4771
+ if (endPtr < 0) {
4772
+ throw new TomlError("incomplete key-value: cannot find end of key", {
4773
+ toml: str,
4774
+ ptr
4775
+ });
4776
+ }
4777
+ }
4778
+ parsed.push(parseString(str, ptr, eos));
4779
+ } else {
4780
+ dot = str.indexOf(".", ptr);
4781
+ let part = str.slice(ptr, dot < 0 || dot > endPtr ? endPtr : dot);
4782
+ if (!KEY_PART_RE.test(part)) {
4783
+ throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", {
4784
+ toml: str,
4785
+ ptr
4786
+ });
4787
+ }
4788
+ parsed.push(part.trimEnd());
4789
+ }
4790
+ }
4791
+ } while (dot + 1 && dot < endPtr);
4792
+ return [parsed, skipVoid(str, endPtr + 1, true, true)];
4793
+ }
4794
+ function parseInlineTable(str, ptr, depth, integersAsBigInt) {
4795
+ let res = {};
4796
+ let seen = /* @__PURE__ */ new Set();
4797
+ let c;
4798
+ ptr++;
4799
+ while ((c = str[ptr++]) !== "}" && c) {
4800
+ if (c === ",") {
4801
+ throw new TomlError("expected value, found comma", {
4802
+ toml: str,
4803
+ ptr: ptr - 1
4804
+ });
4805
+ } else if (c === "#")
4806
+ ptr = skipComment(str, ptr);
4807
+ else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
4808
+ let k;
4809
+ let t = res;
4810
+ let hasOwn = false;
4811
+ let [key, keyEndPtr] = parseKey(str, ptr - 1);
4812
+ for (let i = 0; i < key.length; i++) {
4813
+ if (i)
4814
+ t = hasOwn ? t[k] : t[k] = {};
4815
+ k = key[i];
4816
+ if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) {
4817
+ throw new TomlError("trying to redefine an already defined value", {
4818
+ toml: str,
4819
+ ptr
4820
+ });
4821
+ }
4822
+ if (!hasOwn && k === "__proto__") {
4823
+ Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
4824
+ }
4825
+ }
4826
+ if (hasOwn) {
4827
+ throw new TomlError("trying to redefine an already defined value", {
4828
+ toml: str,
4829
+ ptr
4830
+ });
4831
+ }
4832
+ let [value2, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1, integersAsBigInt);
4833
+ seen.add(value2);
4834
+ t[k] = value2;
4835
+ ptr = valueEndPtr;
4836
+ }
4837
+ }
4838
+ if (!c) {
4839
+ throw new TomlError("unfinished table encountered", {
4840
+ toml: str,
4841
+ ptr
4842
+ });
4843
+ }
4844
+ return [res, ptr];
4845
+ }
4846
+ function parseArray(str, ptr, depth, integersAsBigInt) {
4847
+ let res = [];
4848
+ let c;
4849
+ ptr++;
4850
+ while ((c = str[ptr++]) !== "]" && c) {
4851
+ if (c === ",") {
4852
+ throw new TomlError("expected value, found comma", {
4853
+ toml: str,
4854
+ ptr: ptr - 1
4855
+ });
4856
+ } else if (c === "#")
4857
+ ptr = skipComment(str, ptr);
4858
+ else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
4859
+ let e = extractValue(str, ptr - 1, "]", depth - 1, integersAsBigInt);
4860
+ res.push(e[0]);
4861
+ ptr = e[1];
4862
+ }
4863
+ }
4864
+ if (!c) {
4865
+ throw new TomlError("unfinished array encountered", {
4866
+ toml: str,
4867
+ ptr
4868
+ });
4869
+ }
4870
+ return [res, ptr];
4871
+ }
4872
+
4873
+ // ../../node_modules/.pnpm/smol-toml@1.6.1/node_modules/smol-toml/dist/parse.js
4874
+ function peekTable(key, table, meta, type) {
4875
+ let t = table;
4876
+ let m = meta;
4877
+ let k;
4878
+ let hasOwn = false;
4879
+ let state;
4880
+ for (let i = 0; i < key.length; i++) {
4881
+ if (i) {
4882
+ t = hasOwn ? t[k] : t[k] = {};
4883
+ m = (state = m[k]).c;
4884
+ if (type === 0 && (state.t === 1 || state.t === 2)) {
4885
+ return null;
4886
+ }
4887
+ if (state.t === 2) {
4888
+ let l = t.length - 1;
4889
+ t = t[l];
4890
+ m = m[l].c;
4891
+ }
4892
+ }
4893
+ k = key[i];
4894
+ if ((hasOwn = Object.hasOwn(t, k)) && m[k]?.t === 0 && m[k]?.d) {
4895
+ return null;
4896
+ }
4897
+ if (!hasOwn) {
4898
+ if (k === "__proto__") {
4899
+ Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
4900
+ Object.defineProperty(m, k, { enumerable: true, configurable: true, writable: true });
4901
+ }
4902
+ m[k] = {
4903
+ t: i < key.length - 1 && type === 2 ? 3 : type,
4904
+ d: false,
4905
+ i: 0,
4906
+ c: {}
4907
+ };
4908
+ }
4909
+ }
4910
+ state = m[k];
4911
+ if (state.t !== type && !(type === 1 && state.t === 3)) {
4912
+ return null;
4913
+ }
4914
+ if (type === 2) {
4915
+ if (!state.d) {
4916
+ state.d = true;
4917
+ t[k] = [];
4918
+ }
4919
+ t[k].push(t = {});
4920
+ state.c[state.i++] = state = { t: 1, d: false, i: 0, c: {} };
4921
+ }
4922
+ if (state.d) {
4923
+ return null;
4924
+ }
4925
+ state.d = true;
4926
+ if (type === 1) {
4927
+ t = hasOwn ? t[k] : t[k] = {};
4928
+ } else if (type === 0 && hasOwn) {
4929
+ return null;
4930
+ }
4931
+ return [k, t, state.c];
4932
+ }
4933
+ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
4934
+ let res = {};
4935
+ let meta = {};
4936
+ let tbl = res;
4937
+ let m = meta;
4938
+ for (let ptr = skipVoid(toml, 0); ptr < toml.length; ) {
4939
+ if (toml[ptr] === "[") {
4940
+ let isTableArray = toml[++ptr] === "[";
4941
+ let k = parseKey(toml, ptr += +isTableArray, "]");
4942
+ if (isTableArray) {
4943
+ if (toml[k[1] - 1] !== "]") {
4944
+ throw new TomlError("expected end of table declaration", {
4945
+ toml,
4946
+ ptr: k[1] - 1
4947
+ });
4948
+ }
4949
+ k[1]++;
4950
+ }
4951
+ let p = peekTable(
4952
+ k[0],
4953
+ res,
4954
+ meta,
4955
+ isTableArray ? 2 : 1
4956
+ /* Type.EXPLICIT */
4957
+ );
4958
+ if (!p) {
4959
+ throw new TomlError("trying to redefine an already defined table or value", {
4960
+ toml,
4961
+ ptr
4962
+ });
4963
+ }
4964
+ m = p[2];
4965
+ tbl = p[1];
4966
+ ptr = k[1];
4967
+ } else {
4968
+ let k = parseKey(toml, ptr);
4969
+ let p = peekTable(
4970
+ k[0],
4971
+ tbl,
4972
+ m,
4973
+ 0
4974
+ /* Type.DOTTED */
4975
+ );
4976
+ if (!p) {
4977
+ throw new TomlError("trying to redefine an already defined table or value", {
4978
+ toml,
4979
+ ptr
4980
+ });
4981
+ }
4982
+ let v = extractValue(toml, k[1], void 0, maxDepth, integersAsBigInt);
4983
+ p[1][p[0]] = v[0];
4984
+ ptr = v[1];
4985
+ }
4986
+ ptr = skipVoid(toml, ptr, true);
4987
+ if (toml[ptr] && toml[ptr] !== "\n" && toml[ptr] !== "\r") {
4988
+ throw new TomlError("each key-value declaration must be followed by an end-of-line", {
4989
+ toml,
4990
+ ptr
4991
+ });
4992
+ }
4993
+ ptr = skipVoid(toml, ptr);
4994
+ }
4995
+ return res;
4996
+ }
4997
+
4998
+ // ../../node_modules/.pnpm/smol-toml@1.6.1/node_modules/smol-toml/dist/stringify.js
4999
+ var BARE_KEY = /^[a-z0-9-_]+$/i;
5000
+ function extendedTypeOf(obj) {
5001
+ let type = typeof obj;
5002
+ if (type === "object") {
5003
+ if (Array.isArray(obj))
5004
+ return "array";
5005
+ if (obj instanceof Date)
5006
+ return "date";
5007
+ }
5008
+ return type;
5009
+ }
5010
+ function isArrayOfTables(obj) {
5011
+ for (let i = 0; i < obj.length; i++) {
5012
+ if (extendedTypeOf(obj[i]) !== "object")
5013
+ return false;
5014
+ }
5015
+ return obj.length != 0;
5016
+ }
5017
+ function formatString(s) {
5018
+ return JSON.stringify(s).replace(/\x7f/g, "\\u007f");
5019
+ }
5020
+ function stringifyValue(val, type, depth, numberAsFloat) {
5021
+ if (depth === 0) {
5022
+ throw new Error("Could not stringify the object: maximum object depth exceeded");
5023
+ }
5024
+ if (type === "number") {
5025
+ if (isNaN(val))
5026
+ return "nan";
5027
+ if (val === Infinity)
5028
+ return "inf";
5029
+ if (val === -Infinity)
5030
+ return "-inf";
5031
+ if (numberAsFloat && Number.isInteger(val))
5032
+ return val.toFixed(1);
5033
+ return val.toString();
5034
+ }
5035
+ if (type === "bigint" || type === "boolean") {
5036
+ return val.toString();
5037
+ }
5038
+ if (type === "string") {
5039
+ return formatString(val);
5040
+ }
5041
+ if (type === "date") {
5042
+ if (isNaN(val.getTime())) {
5043
+ throw new TypeError("cannot serialize invalid date");
5044
+ }
5045
+ return val.toISOString();
5046
+ }
5047
+ if (type === "object") {
5048
+ return stringifyInlineTable(val, depth, numberAsFloat);
5049
+ }
5050
+ if (type === "array") {
5051
+ return stringifyArray(val, depth, numberAsFloat);
5052
+ }
5053
+ }
5054
+ function stringifyInlineTable(obj, depth, numberAsFloat) {
5055
+ let keys = Object.keys(obj);
5056
+ if (keys.length === 0)
5057
+ return "{}";
5058
+ let res = "{ ";
5059
+ for (let i = 0; i < keys.length; i++) {
5060
+ let k = keys[i];
5061
+ if (i)
5062
+ res += ", ";
5063
+ res += BARE_KEY.test(k) ? k : formatString(k);
5064
+ res += " = ";
5065
+ res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat);
5066
+ }
5067
+ return res + " }";
5068
+ }
5069
+ function stringifyArray(array, depth, numberAsFloat) {
5070
+ if (array.length === 0)
5071
+ return "[]";
5072
+ let res = "[ ";
5073
+ for (let i = 0; i < array.length; i++) {
5074
+ if (i)
5075
+ res += ", ";
5076
+ if (array[i] === null || array[i] === void 0) {
5077
+ throw new TypeError("arrays cannot contain null or undefined values");
5078
+ }
5079
+ res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1, numberAsFloat);
5080
+ }
5081
+ return res + " ]";
5082
+ }
5083
+ function stringifyArrayTable(array, key, depth, numberAsFloat) {
5084
+ if (depth === 0) {
5085
+ throw new Error("Could not stringify the object: maximum object depth exceeded");
5086
+ }
5087
+ let res = "";
5088
+ for (let i = 0; i < array.length; i++) {
5089
+ res += `${res && "\n"}[[${key}]]
5090
+ `;
5091
+ res += stringifyTable(0, array[i], key, depth, numberAsFloat);
5092
+ }
5093
+ return res;
5094
+ }
5095
+ function stringifyTable(tableKey, obj, prefix, depth, numberAsFloat) {
5096
+ if (depth === 0) {
5097
+ throw new Error("Could not stringify the object: maximum object depth exceeded");
5098
+ }
5099
+ let preamble = "";
5100
+ let tables = "";
5101
+ let keys = Object.keys(obj);
5102
+ for (let i = 0; i < keys.length; i++) {
5103
+ let k = keys[i];
5104
+ if (obj[k] !== null && obj[k] !== void 0) {
5105
+ let type = extendedTypeOf(obj[k]);
5106
+ if (type === "symbol" || type === "function") {
5107
+ throw new TypeError(`cannot serialize values of type '${type}'`);
5108
+ }
5109
+ let key = BARE_KEY.test(k) ? k : formatString(k);
5110
+ if (type === "array" && isArrayOfTables(obj[k])) {
5111
+ tables += (tables && "\n") + stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat);
5112
+ } else if (type === "object") {
5113
+ let tblKey = prefix ? `${prefix}.${key}` : key;
5114
+ tables += (tables && "\n") + stringifyTable(tblKey, obj[k], tblKey, depth - 1, numberAsFloat);
5115
+ } else {
5116
+ preamble += key;
5117
+ preamble += " = ";
5118
+ preamble += stringifyValue(obj[k], type, depth, numberAsFloat);
5119
+ preamble += "\n";
5120
+ }
5121
+ }
5122
+ }
5123
+ if (tableKey && (preamble || !tables))
5124
+ preamble = preamble ? `[${tableKey}]
5125
+ ${preamble}` : `[${tableKey}]`;
5126
+ return preamble && tables ? `${preamble}
5127
+ ${tables}` : preamble || tables;
5128
+ }
5129
+ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
5130
+ if (extendedTypeOf(obj) !== "object") {
5131
+ throw new TypeError("stringify can only be called with an object");
5132
+ }
5133
+ let str = stringifyTable(0, obj, "", maxDepth, numbersAsFloat);
5134
+ if (str[str.length - 1] !== "\n")
5135
+ return str + "\n";
5136
+ return str;
5137
+ }
5138
+
5139
+ // src/switchyard.ts
5140
+ var SWITCHYARD_BIN = "switchyard";
5141
+ var SWITCHYARD_INSTALL_ARGV = [
5142
+ "tool",
5143
+ "install",
5144
+ "--python",
5145
+ "3.12",
5146
+ "nemo-switchyard[cli]"
5147
+ ];
5148
+ var SWITCHYARD_INSTALL_ONELINER = 'uv tool install --python 3.12 "nemo-switchyard[cli]"';
5149
+ var UV_INSTALL_DOCS = "https://docs.astral.sh/uv/getting-started/installation/";
5150
+ var DEFAULT_ROUTE = "switchyard";
5151
+ var ROUTES_FILENAME = "switchyard-routes.toml";
5152
+ var STARTUP_GRACE_MS = 5e3;
5153
+ var LAUNCH_TEMPLATE_ID = "tmpl_switchyard_routes_default";
5154
+ var ANTHROPIC_CAPABLE_ID = "anthropic/claude-opus-5";
5155
+ var ANTHROPIC_EFFICIENT_ID = "anthropic/claude-haiku-4-5-20251001";
5156
+ var OPENROUTER_CAPABLE_ID = "openrouter/anthropic/claude-opus-5";
5157
+ var OPENROUTER_EFFICIENT_ID = "openrouter/anthropic/claude-haiku-4-5";
5158
+ var SUPPORTED_AGENTS = ["claude"];
5159
+ var PLANNED_AGENTS = ["codex", "openclaw"];
5160
+ function classifyAgent(agent) {
5161
+ if (agent === "claude") return { kind: "supported", agent };
5162
+ if (agent !== null && PLANNED_AGENTS.includes(agent)) return { kind: "planned", agent };
5163
+ return { kind: "unknown", agent };
5164
+ }
5165
+ function chooseBackend(env) {
5166
+ const hasAnthropic = (env.ANTHROPIC_API_KEY ?? "").trim().length > 0;
5167
+ const hasOpenRouter = (env.OPENROUTER_API_KEY ?? "").trim().length > 0;
5168
+ if (hasAnthropic) {
5169
+ return {
5170
+ kind: "anthropic",
5171
+ capableId: ANTHROPIC_CAPABLE_ID,
5172
+ efficientId: ANTHROPIC_EFFICIENT_ID,
5173
+ warning: null
5174
+ };
5175
+ }
5176
+ if (hasOpenRouter) {
5177
+ return {
5178
+ kind: "openrouter",
5179
+ capableId: OPENROUTER_CAPABLE_ID,
5180
+ efficientId: OPENROUTER_EFFICIENT_ID,
5181
+ warning: null
5182
+ };
5183
+ }
5184
+ return {
5185
+ kind: "none",
5186
+ capableId: OPENROUTER_CAPABLE_ID,
5187
+ efficientId: OPENROUTER_EFFICIENT_ID,
5188
+ warning: "no backend API key found (ANTHROPIC_API_KEY or OPENROUTER_API_KEY) \u2014 the proxy will start but upstream requests will fail until one is exported."
5189
+ };
5190
+ }
5191
+ var CAPABLE_TARGET = "capable";
5192
+ var EFFICIENT_TARGET = "efficient";
5193
+ function policyHeader(backend, policySource) {
5194
+ return [
5195
+ "# Generated by `maind launch` (Agent Switchyard Phase 1, maind.dev \u2014 ADR-272).",
5196
+ "# Regenerated on every launch; do not hand-edit. For a custom policy use",
5197
+ "# `maind launch <agent> --config <path>`.",
5198
+ "#",
5199
+ `# Routing policy: ${policySource === "curated" ? "curated (MAIND content plane)" : "builtin default"}`,
5200
+ "# \u2014 deterministic stage routing (NVIDIA NeMo Switchyard `stage_router`).",
5201
+ "# effort low/medium -> efficient_target (fast tier)",
5202
+ "# effort high/xhigh/max -> capable_target (strong tier)",
5203
+ "# picker `efficient_first` + confidence_threshold 0.5: steady write progress",
5204
+ "# keeps the efficient tier; corroborating error/exploration signals escalate",
5205
+ "# to the capable tier.",
5206
+ "#",
5207
+ `# Backend: ${backend.kind === "none" ? "openrouter (EXAMPLE \u2014 no API key detected)" : backend.kind}`,
5208
+ "# \u2014 detected locally from the environment, never from the policy source.",
5209
+ "# API keys are read from the environment by the proxy at runtime \u2014 never",
5210
+ "# stored in this file.",
5211
+ ""
5212
+ ].join("\n");
5213
+ }
5214
+ function defaultRouteTable(routeName) {
5215
+ return {
5216
+ [routeName]: {
5217
+ type: "stage_router",
5218
+ capable_target: CAPABLE_TARGET,
5219
+ efficient_target: EFFICIENT_TARGET,
5220
+ picker: "efficient_first",
5221
+ confidence_threshold: 0.5
5222
+ }
5223
+ };
5224
+ }
5225
+ function buildRoutesToml(routeName, backend, curatedRoutes = null) {
5226
+ const doc = {
5227
+ targets: {
5228
+ [CAPABLE_TARGET]: { id: backend.capableId },
5229
+ [EFFICIENT_TARGET]: { id: backend.efficientId }
5230
+ },
5231
+ routes: curatedRoutes ?? defaultRouteTable(routeName)
5232
+ };
5233
+ return policyHeader(backend, curatedRoutes ? "curated" : "builtin") + stringify(doc) + "\n";
5234
+ }
5235
+ function acceptPolicyTemplate(body, routeName) {
5236
+ let parsed;
5237
+ try {
5238
+ parsed = parse(body);
5239
+ } catch {
5240
+ return null;
5241
+ }
5242
+ if (typeof parsed !== "object" || parsed === null) return null;
5243
+ const doc = parsed;
5244
+ if ("targets" in doc) return null;
5245
+ const routes = doc.routes;
5246
+ if (typeof routes !== "object" || routes === null) return null;
5247
+ const table = routes;
5248
+ const route = table[routeName];
5249
+ if (typeof route !== "object" || route === null) return null;
5250
+ for (const key of ["capable_target", "efficient_target"]) {
5251
+ const ref = route[key];
5252
+ if (ref !== void 0 && ref !== CAPABLE_TARGET && ref !== EFFICIENT_TARGET) return null;
5253
+ }
5254
+ return table;
5255
+ }
5256
+ function acceptRoutesToml(body, routeName) {
5257
+ let parsed;
5258
+ try {
5259
+ parsed = parse(body);
5260
+ } catch {
5261
+ return null;
5262
+ }
5263
+ if (typeof parsed !== "object" || parsed === null) return null;
5264
+ const routes = parsed.routes;
5265
+ if (typeof routes !== "object" || routes === null) return null;
5266
+ if (!(routeName in routes)) return null;
5267
+ return body;
5268
+ }
5269
+ function buildSwitchyardArgv(bin, agent, routeName, configPath) {
5270
+ return [bin, "launch", agent, "--model", routeName, "--config", configPath];
5271
+ }
5272
+ function buildDirectArgv(agent) {
5273
+ return [agent];
5274
+ }
5275
+ var SIGNAL_NUMBERS = {
5276
+ SIGHUP: 1,
5277
+ SIGINT: 2,
5278
+ SIGQUIT: 3,
5279
+ SIGKILL: 9,
5280
+ SIGTERM: 15
5281
+ };
5282
+ function exitCodeFromChild(code, signal) {
5283
+ if (code !== null) return code;
5284
+ if (signal !== null) {
5285
+ const num2 = SIGNAL_NUMBERS[signal];
5286
+ return num2 !== void 0 ? 128 + num2 : 1;
5287
+ }
5288
+ return 1;
5289
+ }
5290
+ function classifyChildExit(code, signal, elapsedMs) {
5291
+ if (signal !== null) return "propagate";
5292
+ if (code === 0) return "propagate";
5293
+ return elapsedMs < STARTUP_GRACE_MS ? "fallback-eligible" : "propagate";
5294
+ }
5295
+ function buildInstallAnnouncement() {
5296
+ return `switchyard not found \u2014 installing via uv: ${SWITCHYARD_INSTALL_ONELINER}`;
5297
+ }
5298
+ function buildUvMissingMessage() {
5299
+ return `switchyard is not installed and \`uv\` is missing, so MAIND will not install it for you.
5300
+ maind: install uv (${UV_INSTALL_DOCS}), then run:
5301
+ maind: ${SWITCHYARD_INSTALL_ONELINER}
5302
+ maind: and re-run \`maind launch claude\`. (Or launch without routing: \`maind launch claude --direct\`.)`;
5303
+ }
5304
+ function buildInstallStillMissingMessage() {
5305
+ return "switchyard still not reachable after install \u2014 uv's bin dir may be missing from PATH (try `uv tool update-shell`, then open a new terminal).";
5306
+ }
5307
+ function buildFallbackBanner(reason) {
5308
+ return [
5309
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
5310
+ ` switchyard proxy unavailable: ${reason}`,
5311
+ " launching claude DIRECTLY \u2014 no model routing for this session.",
5312
+ " (disable this fallback with --no-fallback)",
5313
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
5314
+ ].join("\n");
5315
+ }
5316
+ function buildDirectBanner() {
5317
+ return "launching claude directly (--direct) \u2014 no switchyard proxy, no model routing.";
5318
+ }
5319
+ function renderDryRun(plan, json) {
5320
+ if (json) {
5321
+ const payload = {
5322
+ agent: plan.agent,
5323
+ config_path: plan.configPath,
5324
+ config_source: plan.configSource,
5325
+ toml: plan.toml,
5326
+ argv: plan.argv,
5327
+ backend: plan.backendKind,
5328
+ switchyard_detected: plan.switchyardDetected
5329
+ };
5330
+ return { stdout: JSON.stringify(payload, null, 2) + "\n", stderr: "" };
5331
+ }
5332
+ const stderr = [
5333
+ `maind: dry-run \u2014 nothing installed, written, or spawned.`,
5334
+ `maind: config ${plan.configPath} (${plan.configSource})`,
5335
+ `maind: switchyard detected: ${plan.switchyardDetected ? "yes" : "no"}`,
5336
+ `maind: would run: ${plan.argv.join(" ")}`
5337
+ ].join("\n");
5338
+ return {
5339
+ stdout: plan.toml ?? `(using existing config: ${plan.configPath})
5340
+ `,
5341
+ stderr: stderr + "\n"
5342
+ };
5343
+ }
5344
+
5345
+ // src/version.ts
5346
+ import { createRequire as createRequire3 } from "node:module";
5347
+ function resolveVersion() {
5348
+ if (true) return "0.11.0";
5349
+ try {
5350
+ const require2 = createRequire3(import.meta.url);
5351
+ return require2("../package.json").version;
5352
+ } catch {
5353
+ return "0.0.0-unknown";
5354
+ }
5355
+ }
5356
+ var VERSION = resolveVersion();
5357
+
5358
+ // src/launch-cmd.ts
5359
+ var TEMPLATE_FETCH_TIMEOUT_MS = 5e3;
5360
+ function err(line) {
5361
+ process.stderr.write(`maind: ${line}
5362
+ `);
5363
+ }
5364
+ function msg5(e) {
5365
+ return e instanceof Error ? e.message : String(e);
5366
+ }
5367
+ var VALUE_FLAGS = /* @__PURE__ */ new Set(["--config", "--route", "--mcp-url"]);
5368
+ function parseLaunchArgs(argv) {
5369
+ const get = (name) => {
5370
+ const i = argv.indexOf(name);
5371
+ if (i === -1 || i + 1 >= argv.length) return void 0;
5372
+ return argv[i + 1];
5373
+ };
5374
+ const has = (name) => argv.includes(name);
5375
+ let agent = null;
5376
+ for (let i = 0; i < argv.length; i++) {
5377
+ const tok = argv[i];
5378
+ if (tok.startsWith("-")) {
5379
+ if (VALUE_FLAGS.has(tok)) i++;
5380
+ continue;
5381
+ }
5382
+ agent = tok;
5383
+ break;
5384
+ }
5385
+ return {
5386
+ agent,
5387
+ dryRun: has("--dry-run"),
5388
+ config: get("--config") ?? null,
5389
+ route: get("--route") ?? DEFAULT_ROUTE,
5390
+ direct: has("--direct"),
5391
+ noFallback: has("--no-fallback"),
5392
+ noInstall: has("--no-install"),
5393
+ json: has("--json"),
5394
+ mcpUrl: get("--mcp-url") ?? null
5395
+ };
5396
+ }
5397
+ var realLaunchDeps = {
5398
+ probe(bin, args) {
5399
+ const res = spawnSync2(bin, args, {
5400
+ stdio: ["ignore", "pipe", "pipe"],
5401
+ encoding: "utf8",
5402
+ timeout: 1e4
5403
+ });
5404
+ const ok = res.status === 0 && !res.error;
5405
+ const out2 = typeof res.stdout === "string" ? res.stdout.trim() : "";
5406
+ return { ok, stdout: out2.length > 0 ? out2 : null };
5407
+ },
5408
+ install(argv) {
5409
+ const res = spawnSync2("uv", [...argv], { stdio: ["ignore", "inherit", "inherit"] });
5410
+ return res.status;
5411
+ },
5412
+ spawnInteractive(argv) {
5413
+ const start = Date.now();
5414
+ return new Promise((resolve2) => {
5415
+ let settled = false;
5416
+ const child = spawn(argv[0], argv.slice(1), { stdio: "inherit", env: process.env });
5417
+ const onSigint = () => {
5418
+ };
5419
+ const makeForward = (sig) => () => {
5420
+ try {
5421
+ child.kill(sig);
5422
+ } catch {
5423
+ }
5424
+ };
5425
+ const onSigterm = makeForward("SIGTERM");
5426
+ const onSighup = makeForward("SIGHUP");
5427
+ process.on("SIGINT", onSigint);
5428
+ process.on("SIGTERM", onSigterm);
5429
+ process.on("SIGHUP", onSighup);
5430
+ const cleanup = () => {
5431
+ process.removeListener("SIGINT", onSigint);
5432
+ process.removeListener("SIGTERM", onSigterm);
5433
+ process.removeListener("SIGHUP", onSighup);
5434
+ };
5435
+ child.on("error", (e) => {
5436
+ if (settled) return;
5437
+ settled = true;
5438
+ cleanup();
5439
+ resolve2({ code: null, signal: null, elapsedMs: Date.now() - start, spawnError: e.message });
5440
+ });
5441
+ child.on("exit", (code, signal) => {
5442
+ if (settled) return;
5443
+ settled = true;
5444
+ cleanup();
5445
+ resolve2({ code, signal, elapsedMs: Date.now() - start, spawnError: null });
5446
+ });
5447
+ });
5448
+ },
5449
+ async fetchTemplate(mcpUrl, projectKey) {
5450
+ let auth;
5451
+ try {
5452
+ auth = resolveAuth();
5453
+ } catch (e) {
5454
+ if (e instanceof MissingApiKeyError) return null;
5455
+ throw e;
5456
+ }
5457
+ try {
5458
+ const client = new McpClient({
5459
+ apiKey: auth.apiKey,
5460
+ deviceId: auth.deviceId,
5461
+ clientVersion: VERSION,
5462
+ mcpUrl: mcpUrl ?? void 0,
5463
+ projectKey
5464
+ });
5465
+ const timeout = new Promise((resolve2) => {
5466
+ const t = setTimeout(() => resolve2(null), TEMPLATE_FETCH_TIMEOUT_MS);
5467
+ t.unref();
5468
+ });
5469
+ const call = client.callTool("get_template", { template_id: LAUNCH_TEMPLATE_ID }).then(
5470
+ (r) => typeof r.template_body === "string" && r.template_body.trim().length > 0 ? r.template_body : null
5471
+ ).catch(() => null);
5472
+ return await Promise.race([call, timeout]);
5473
+ } catch {
5474
+ return null;
5475
+ }
5476
+ },
5477
+ writeConfig(path, content) {
5478
+ const dir = dirname4(path);
5479
+ if (dir && dir !== ".") mkdirSync4(dir, { recursive: true });
5480
+ writeFileSync4(path, content, "utf8");
5481
+ },
5482
+ readFile(path) {
5483
+ try {
5484
+ return readFileSync6(path, "utf8");
5485
+ } catch {
5486
+ return null;
5487
+ }
5488
+ },
5489
+ fileExists(path) {
5490
+ return existsSync5(path);
5491
+ },
5492
+ repoRoot() {
5493
+ try {
5494
+ const out2 = execFileSync7("git", ["rev-parse", "--show-toplevel"], {
5495
+ encoding: "utf8",
5496
+ stdio: ["ignore", "pipe", "ignore"],
5497
+ timeout: 5e3
5498
+ }).trim();
5499
+ return out2.length > 0 ? out2 : null;
5500
+ } catch {
5501
+ return null;
5502
+ }
5503
+ },
5504
+ projectKey() {
5505
+ return gatherGitState().projectKey;
5506
+ },
5507
+ userConfigDir() {
5508
+ return configDir();
5509
+ },
5510
+ homeDir() {
5511
+ return homedir2();
5512
+ },
5513
+ env: process.env,
5514
+ platform: process.platform
5515
+ };
5516
+ function resolveRoutesPath(repoRoot2, userConfigDir) {
5517
+ return repoRoot2 !== null ? join6(repoRoot2, ".maind", ROUTES_FILENAME) : join6(userConfigDir, ROUTES_FILENAME);
5518
+ }
5519
+ async function runLaunch(opts, deps = realLaunchDeps) {
5520
+ const verdict = classifyAgent(opts.agent);
5521
+ if (verdict.kind === "unknown") {
5522
+ err(
5523
+ `usage: maind launch <agent> [--dry-run] [--config <path>] [--route <name>] [--direct] [--no-fallback] [--no-install] \u2014 supported: ${SUPPORTED_AGENTS.join(", ")}`
5524
+ );
5525
+ return 2;
5526
+ }
5527
+ if (verdict.kind === "planned") {
5528
+ err(
5529
+ `agent '${verdict.agent}' is planned but not yet supported \u2014 v1 supports: ${SUPPORTED_AGENTS.join(", ")}.`
5530
+ );
5531
+ return 2;
5532
+ }
5533
+ if (opts.json && !opts.dryRun) {
5534
+ err("--json is only valid together with --dry-run (stdout belongs to the agent session).");
5535
+ return 2;
5536
+ }
5537
+ const agent = verdict.agent;
5538
+ if (opts.direct) {
5539
+ err(buildDirectBanner());
5540
+ return spawnAndPropagate(deps, buildDirectArgv(agent));
5541
+ }
5542
+ const backend = chooseBackend(deps.env);
5543
+ if (backend.warning !== null) err(backend.warning);
5544
+ let configPath;
5545
+ let toml;
5546
+ let source;
5547
+ if (opts.config !== null) {
5548
+ if (!deps.fileExists(opts.config)) {
5549
+ err(`config not found: ${opts.config}`);
5550
+ return 2;
5551
+ }
5552
+ const body = deps.readFile(opts.config);
5553
+ if (body === null || acceptRoutesToml(body, opts.route) === null) {
5554
+ err(`config ${opts.config} is not valid routes TOML with a [routes.${opts.route}] entry.`);
5555
+ return 2;
5556
+ }
5557
+ configPath = opts.config;
5558
+ toml = null;
5559
+ source = "flag";
5560
+ } else {
5561
+ const template = await deps.fetchTemplate(opts.mcpUrl, deps.projectKey());
5562
+ const curatedRoutes = template === null ? null : acceptPolicyTemplate(template, opts.route);
5563
+ toml = buildRoutesToml(opts.route, backend, curatedRoutes);
5564
+ if (curatedRoutes !== null) {
5565
+ source = "template";
5566
+ } else {
5567
+ source = "builtin";
5568
+ const reason = template === null ? "no curated template (offline, unauthenticated, or not published)" : `curated template unusable (missing route '${opts.route}', or it pins its own targets)`;
5569
+ err(`using builtin routing policy (${reason}).`);
5570
+ }
5571
+ configPath = resolveRoutesPath(deps.repoRoot(), deps.userConfigDir());
5572
+ }
5573
+ let bin = SWITCHYARD_BIN;
5574
+ let detected = deps.probe(SWITCHYARD_BIN, ["--version"]).ok;
5575
+ if (opts.dryRun) {
5576
+ const plan = {
5577
+ agent,
5578
+ configPath,
5579
+ configSource: source,
5580
+ toml,
5581
+ argv: buildSwitchyardArgv(bin, agent, opts.route, configPath),
5582
+ backendKind: backend.kind,
5583
+ switchyardDetected: detected
5584
+ };
5585
+ const out2 = renderDryRun(plan, opts.json);
5586
+ if (out2.stderr.length > 0) process.stderr.write(out2.stderr);
5587
+ process.stdout.write(out2.stdout);
5588
+ return 0;
5589
+ }
5590
+ if (!detected) {
5591
+ if (opts.noInstall) {
5592
+ err(`switchyard not found (--no-install). Install it with:
5593
+ maind: ${SWITCHYARD_INSTALL_ONELINER}`);
5594
+ return 1;
5595
+ }
5596
+ if (!deps.probe("uv", ["--version"]).ok) {
5597
+ err(buildUvMissingMessage());
5598
+ return 1;
5599
+ }
5600
+ err(buildInstallAnnouncement());
5601
+ deps.install(SWITCHYARD_INSTALL_ARGV);
5602
+ if (deps.probe(SWITCHYARD_BIN, ["--version"]).ok) {
5603
+ detected = true;
5604
+ } else {
5605
+ const shim = join6(
5606
+ deps.homeDir(),
5607
+ ".local",
5608
+ "bin",
5609
+ deps.platform === "win32" ? "switchyard.exe" : "switchyard"
5610
+ );
5611
+ if (deps.probe(shim, ["--version"]).ok) {
5612
+ bin = shim;
5613
+ detected = true;
5614
+ }
5615
+ }
5616
+ if (!detected) {
5617
+ return degradeOrFail(deps, opts, agent, buildInstallStillMissingMessage());
5618
+ }
5619
+ }
5620
+ if (source !== "flag" && toml !== null) {
5621
+ try {
5622
+ deps.writeConfig(configPath, toml);
5623
+ } catch (e) {
5624
+ err(`could not write ${configPath}: ${msg5(e)}`);
5625
+ return 1;
5626
+ }
5627
+ }
5628
+ const result = await deps.spawnInteractive(buildSwitchyardArgv(bin, agent, opts.route, configPath));
5629
+ if (result.spawnError !== null) {
5630
+ return degradeOrFail(deps, opts, agent, `could not start switchyard (${result.spawnError})`);
5631
+ }
5632
+ if (classifyChildExit(result.code, result.signal, result.elapsedMs) === "fallback-eligible") {
5633
+ return degradeOrFail(
5634
+ deps,
5635
+ opts,
5636
+ agent,
5637
+ `switchyard exited with code ${result.code} after ${(result.elapsedMs / 1e3).toFixed(1)}s`
5638
+ );
5639
+ }
5640
+ return exitCodeFromChild(result.code, result.signal);
5641
+ }
5642
+ async function degradeOrFail(deps, opts, agent, reason) {
5643
+ if (opts.noFallback) {
5644
+ err(`${reason} (--no-fallback set \u2014 not degrading to a direct spawn).`);
5645
+ return 1;
5646
+ }
5647
+ process.stderr.write(buildFallbackBanner(reason) + "\n");
5648
+ return spawnAndPropagate(deps, buildDirectArgv(agent));
5649
+ }
5650
+ async function spawnAndPropagate(deps, argv) {
5651
+ const result = await deps.spawnInteractive(argv);
5652
+ if (result.spawnError !== null) {
5653
+ err(`'${argv[0]}' not found on PATH \u2014 install the agent CLI first (${result.spawnError}).`);
5654
+ return 1;
5655
+ }
5656
+ return exitCodeFromChild(result.code, result.signal);
5657
+ }
5658
+
5659
+ // src/object-cmd.ts
5660
+ import { randomUUID } from "node:crypto";
5661
+ import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync7, realpathSync } from "node:fs";
5662
+ import { homedir as homedir3 } from "node:os";
5663
+ import { join as join7 } from "node:path";
5664
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
5665
+ var SNAPSHOT_MAX_AGE_MS = 120 * 6e4;
5666
+ var PHANTOM_TTL_MINUTES = 10;
5667
+ var USAGE = `maind: usage:
5668
+ maind object create --title "<text>" [--parent <uuid>] [--anchor <repo-rel-path>]... [--session <uuid>]
5669
+ maind object link --object <uuid> --ref <ns:id> [--url <url>] [--session <uuid>]
5670
+ maind object report --event pr_opened|merge --ref <ns:id> [--occurred-on YYYY-MM-DD] [--session <uuid>]
5671
+ `;
5672
+ function parseObjectArgs(argv) {
5673
+ const sub = argv[0];
5674
+ if (sub !== "create" && sub !== "link" && sub !== "report") return null;
5675
+ const args = { sub, anchors: [] };
5676
+ for (let i = 1; i < argv.length; i++) {
5677
+ const a = argv[i];
5678
+ switch (a) {
5679
+ case "--title":
5680
+ args.title = argv[++i];
5681
+ break;
5682
+ case "--parent":
5683
+ args.parent = argv[++i];
5684
+ break;
5685
+ case "--anchor":
5686
+ args.anchors.push(argv[++i] ?? "");
5687
+ break;
5688
+ case "--object":
5689
+ args.object = argv[++i];
5690
+ break;
5691
+ case "--ref":
5692
+ args.ref = argv[++i];
5693
+ break;
5694
+ case "--url":
5695
+ args.url = argv[++i];
5696
+ break;
5697
+ case "--event": {
5698
+ const v = argv[++i];
5699
+ if (v !== "pr_opened" && v !== "merge") return null;
5700
+ args.event = v;
5701
+ break;
5702
+ }
5703
+ case "--occurred-on":
5704
+ args.occurredOn = argv[++i];
5705
+ break;
5706
+ case "--session":
5707
+ args.session = argv[++i];
5708
+ break;
5709
+ default:
5710
+ return null;
5711
+ }
5712
+ }
5713
+ if (sub === "create" && !args.title) return null;
5714
+ if (sub === "link" && (!args.object || !args.ref)) return null;
5715
+ if (sub === "report" && (!args.event || !args.ref)) return null;
5716
+ return args;
5717
+ }
5718
+ function snapshotSessionId(projectKey) {
5719
+ try {
5720
+ const dir = join7(homedir3(), ".maind", "presence", projectKey);
5721
+ if (!existsSync6(dir)) return null;
5722
+ const here = safeRealpath(process.cwd());
5723
+ let best = null;
5724
+ for (const name of readdirSync4(dir)) {
5725
+ if (!name.endsWith(".json")) continue;
5726
+ try {
5727
+ const raw = JSON.parse(readFileSync7(join7(dir, name), "utf8"));
5728
+ const at = Date.parse(raw.written_at ?? "");
5729
+ if (typeof raw.own_session_id !== "string" || !UUID_RE.test(raw.own_session_id) || Number.isNaN(at) || Date.now() - at > SNAPSHOT_MAX_AGE_MS) {
5730
+ continue;
5731
+ }
5732
+ if (typeof raw.cwd !== "string" || safeRealpath(raw.cwd) !== here) continue;
5733
+ if (best === null || at > best.at) best = { id: raw.own_session_id, at };
5734
+ } catch {
5735
+ }
5736
+ }
5737
+ return best?.id ?? null;
5738
+ } catch {
5739
+ return null;
5740
+ }
5741
+ }
5742
+ function safeRealpath(p) {
5743
+ try {
5744
+ return realpathSync(p);
5745
+ } catch {
5746
+ return p;
5747
+ }
5748
+ }
5749
+ async function resolveSession(client, projectKey, flag2) {
5750
+ if (flag2 && UUID_RE.test(flag2)) return { sessionId: flag2, source: "flag" };
5751
+ const env = process.env.MAIND_SESSION_ID?.trim().toLowerCase();
5752
+ if (env && UUID_RE.test(env)) return { sessionId: env, source: "env" };
5753
+ const snap = snapshotSessionId(projectKey);
5754
+ if (snap) return { sessionId: snap, source: "snapshot" };
5755
+ const id = randomUUID();
5756
+ const res = await client.callTool("announce_session", {
5757
+ project_key: projectKey,
5758
+ session_id: id,
5759
+ focus: "cli:object",
5760
+ ttl_minutes: PHANTOM_TTL_MINUTES
5761
+ });
5762
+ if (res.ok !== true) {
5763
+ process.stderr.write(
5764
+ `maind: could not announce a session (${res.error ?? "unknown"}) \u2014 no live bridge session found for this cwd either.
5765
+ Fallback: run the MCP calls from an agent session (work_object_${"create"}/link_ref/report_event).
5766
+ `
5767
+ );
5768
+ return null;
5769
+ }
5770
+ return { sessionId: id, source: "announced" };
5771
+ }
5772
+ async function endSession(client, projectKey, sessionId) {
5773
+ try {
5774
+ await client.callTool("announce_session", {
5775
+ project_key: projectKey,
5776
+ session_id: sessionId,
5777
+ status: "ended"
5778
+ });
5779
+ } catch {
5780
+ }
5781
+ }
5782
+ async function runObject(args) {
5783
+ if (args === null) {
5784
+ process.stderr.write(USAGE);
5785
+ return 2;
5786
+ }
5787
+ const failOpen = args.sub !== "create";
5788
+ const fail = (msg8) => {
5789
+ process.stderr.write(`maind: object ${args.sub}: ${msg8}
5790
+ `);
5791
+ return failOpen ? 0 : 1;
5792
+ };
5793
+ let auth;
5794
+ try {
5795
+ auth = resolveAuth();
5796
+ } catch (err4) {
5797
+ return fail(err4 instanceof MissingApiKeyError ? err4.message : String(err4));
5798
+ }
5799
+ const projectKey = gatherGitState().projectKey;
5800
+ if (!projectKey) return fail("not a git repo with a remote \u2014 no project_key.");
5801
+ const client = new McpClient({
5802
+ apiKey: auth.apiKey,
5803
+ deviceId: auth.deviceId,
5804
+ clientVersion: VERSION,
5805
+ projectKey
5806
+ });
5807
+ let session = null;
5808
+ try {
5809
+ session = await resolveSession(client, projectKey, args.session);
5810
+ if (session === null) return failOpen ? 0 : 1;
5811
+ if (args.sub === "create") {
5812
+ const res2 = await client.callTool("work_object_create", {
5813
+ project_key: projectKey,
5814
+ session_id: session.sessionId,
5815
+ kind: "issue",
5816
+ title: args.title,
5817
+ ...args.parent ? { parent_id: args.parent } : {},
5818
+ ...args.anchors.length > 0 ? { anchors: args.anchors.map((p) => ({ path_prefix: p })) } : {}
5819
+ });
5820
+ const id = res2.object?.id;
5821
+ if (res2.ok !== true || typeof id !== "string") {
5822
+ return fail(`server refused (${res2.error ?? "no object id"})${res2.hint ? ` \u2014 ${res2.hint}` : ""}`);
5823
+ }
5824
+ process.stderr.write(
5825
+ `maind: object ${res2["created"] === false ? "already existed" : "created"} (via ${session.source} session).
5826
+ `
5827
+ );
5828
+ process.stdout.write(id + "\n");
5829
+ return 0;
5830
+ }
5831
+ if (args.sub === "link") {
5832
+ const res2 = await client.callTool("work_object_link_ref", {
5833
+ project_key: projectKey,
5834
+ session_id: session.sessionId,
5835
+ object_id: args.object,
5836
+ ref: args.ref,
5837
+ ...args.url ? { url: args.url } : {}
5838
+ });
5839
+ if (res2.ok === true || res2.error === "ref_already_linked") {
5840
+ process.stderr.write(
5841
+ `maind: ref ${args.ref} ${res2.error === "ref_already_linked" ? "already linked" : "linked"}.
5842
+ `
5843
+ );
5844
+ return 0;
5845
+ }
5846
+ return fail(`link failed (${res2.error ?? "unknown"})${res2.hint ? ` \u2014 ${res2.hint}` : ""}`);
5847
+ }
5848
+ const res = await client.callTool("work_object_report_event", {
5849
+ project_key: projectKey,
5850
+ session_id: session.sessionId,
5851
+ event: args.event,
5852
+ ref: args.ref,
5853
+ ...args.occurredOn ? { occurred_on: args.occurredOn } : {}
5854
+ });
5855
+ if (res.ok !== true) {
5856
+ return fail(`report failed (${res.error ?? "unknown"})${res.hint ? ` \u2014 ${res.hint}` : ""}`);
5857
+ }
5858
+ process.stderr.write(`maind: ${args.event} reported for ${args.ref}.
5859
+ `);
5860
+ return 0;
5861
+ } catch (err4) {
5862
+ return fail(err4 instanceof Error ? err4.message : String(err4));
5863
+ } finally {
5864
+ if (session?.source === "announced") {
5865
+ await endSession(client, projectKey, session.sessionId);
5866
+ }
5867
+ }
5868
+ }
5869
+
5870
+ // src/review.ts
5871
+ import { execFileSync as execFileSync8 } from "node:child_process";
5872
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
5873
+ import { dirname as dirname5 } from "node:path";
5874
+
5875
+ // ../../packages/code-index/build/index.js
5876
+ var CODE_INDEX_VERSION = "0.1.0";
5877
+
5878
+ // src/review-render.ts
5879
+ var COMMENT_MARKER = "<!-- maind-review -->";
5880
+ var COMMENT_FINDINGS_CAP = 30;
5881
+ var FOOTER = "maind review \xB7 deterministic, provenance-backed";
5882
+ function buildReviewManifest(data, verdict, meta) {
5883
+ const review = data.review;
5884
+ return {
5885
+ schema: "maind.review.manifest/v1",
5886
+ generated_at: meta.generatedAt,
5887
+ key_prefix: meta.keyPrefix,
5888
+ run_ref: meta.runRef,
5889
+ base: meta.base,
5890
+ diff_stats: meta.diffStats,
5891
+ symbol_count: meta.symbolCount,
5892
+ risk_flags: review?.risk_flags ?? [],
5893
+ findings: (review?.convention_findings ?? []).map((f) => ({
5894
+ convention_id: f.convention_id,
5895
+ version: f.convention_version,
5896
+ severity: f.severity,
5897
+ grade: f.grade,
5898
+ matched_symbol_count: f.matched_symbols.length,
5899
+ matched_changed_symbol_count: f.matched_changed_symbols?.length ?? 0
5900
+ })),
5901
+ served: (review?.lesson_hints ?? []).map((l) => ({
5902
+ id: l.id,
5903
+ version: typeof l.version === "number" ? l.version : null,
5904
+ tier: l.tier ?? null
5905
+ })),
5906
+ verdict: verdict?.ok === true && typeof verdict.verdict === "string" ? {
5907
+ verdict: verdict.verdict,
5908
+ counts: {
5909
+ block: verdict.counts?.block ?? 0,
5910
+ warn: verdict.counts?.warn ?? 0,
5911
+ note: verdict.counts?.note ?? 0
5912
+ },
5913
+ fail_on: meta.failOn
5914
+ } : null,
5915
+ run: verdict?.ok === true ? verdict.run ?? null : null,
5916
+ ...verdict?.ok === true && verdict.run_note ? { run_note: verdict.run_note } : {},
5917
+ coverage_note: review?.coverage_note ?? null,
5918
+ regression_context: review?.regression_context ?? null
5919
+ };
5920
+ }
5921
+ function severityBadge(f) {
5922
+ return `**[${f.severity}]**`;
5923
+ }
5924
+ function findingLine(f) {
5925
+ const cite = `\`${f.convention_id}@v${f.convention_version}\``;
5926
+ const grade = f.grade === "verdict" ? " \xB7 verdict-grade" : "";
5927
+ const changed = f.matched_changed_symbols?.length ?? 0;
5928
+ const matchInfo = changed > 0 ? `matched on changed symbols: ${formatSymbols(f.matched_changed_symbols ?? [])}` : `matched (co-located): ${formatSymbols(f.matched_symbols)}`;
5929
+ const summary = f.summary?.trim() ? ` \u2014 ${f.summary.trim()}` : "";
5930
+ return `- ${severityBadge(f)} ${cite}${summary}${grade}
5931
+ ${matchInfo}`;
5932
+ }
5933
+ function formatSymbols(symbols, max = 4) {
5934
+ const shown = symbols.slice(0, max).map((s) => `\`${s}\``);
5935
+ const rest = symbols.length - shown.length;
5936
+ return shown.join(", ") + (rest > 0 ? ` (+${rest} more)` : "");
5937
+ }
5938
+ function verdictLabel(verdict) {
5939
+ const counts = verdict.counts ?? {};
5940
+ return `**Verdict: ${(verdict.verdict ?? "?").toUpperCase()}** (block: ${counts.block ?? 0} \xB7 warn: ${counts.warn ?? 0} \xB7 note: ${counts.note ?? 0})`;
3852
5941
  }
3853
5942
  function attestationLine(verdict) {
3854
5943
  const r = verdict.run;
@@ -3867,132 +5956,132 @@ function renderReviewMarkdown(data, verdict, meta) {
3867
5956
  const findings = review?.convention_findings ?? [];
3868
5957
  const hints = review?.lesson_hints ?? [];
3869
5958
  const riskFlags = review?.risk_flags ?? [];
3870
- const lines = [];
3871
- lines.push("<!-- Generated by `maind review` \u2014 do not edit by hand. -->");
3872
- lines.push(
5959
+ const lines2 = [];
5960
+ lines2.push("<!-- Generated by `maind review` \u2014 do not edit by hand. -->");
5961
+ lines2.push(
3873
5962
  `<!-- generated_at: ${meta.generatedAt} | key: ${meta.keyPrefix}${meta.runRef ? ` | run: ${meta.runRef}` : ""} -->`
3874
5963
  );
3875
- lines.push("");
3876
- lines.push("# maind review");
3877
- lines.push("");
3878
- lines.push(
5964
+ lines2.push("");
5965
+ lines2.push("# maind review");
5966
+ lines2.push("");
5967
+ lines2.push(
3879
5968
  `Reviewed ${baseLabel(meta)}: ${meta.symbolCount} changed symbol(s) across ${meta.diffStats?.changed_file_count ?? 0} file(s) \xB7 findings: ${findings.length} \xB7 risk flags: ${riskFlags.length} \xB7 lesson hints: ${hints.length}`
3880
5969
  );
3881
- lines.push("");
5970
+ lines2.push("");
3882
5971
  if (verdict?.ok === true && verdict.verdict) {
3883
- lines.push(verdictLabel(verdict));
5972
+ lines2.push(verdictLabel(verdict));
3884
5973
  const attest = attestationLine(verdict);
3885
5974
  if (attest) {
3886
- lines.push("");
3887
- lines.push(attest);
5975
+ lines2.push("");
5976
+ lines2.push(attest);
3888
5977
  }
3889
5978
  if (verdict.trust_note) {
3890
- lines.push("");
3891
- lines.push(`_${verdict.trust_note}_`);
5979
+ lines2.push("");
5980
+ lines2.push(`_${verdict.trust_note}_`);
3892
5981
  }
3893
- lines.push("");
5982
+ lines2.push("");
3894
5983
  }
3895
5984
  if (findings.length > 0) {
3896
- lines.push("## Convention findings");
3897
- lines.push("");
3898
- for (const f of findings) lines.push(findingLine(f));
3899
- lines.push("");
5985
+ lines2.push("## Convention findings");
5986
+ lines2.push("");
5987
+ for (const f of findings) lines2.push(findingLine(f));
5988
+ lines2.push("");
3900
5989
  } else {
3901
- lines.push("## Convention findings");
3902
- lines.push("");
3903
- lines.push("_No convention findings for this change set._");
3904
- lines.push("");
5990
+ lines2.push("## Convention findings");
5991
+ lines2.push("");
5992
+ lines2.push("_No convention findings for this change set._");
5993
+ lines2.push("");
3905
5994
  }
3906
5995
  if (riskFlags.length > 0) {
3907
- lines.push("## Risk flags");
3908
- lines.push("");
3909
- lines.push(
5996
+ lines2.push("## Risk flags");
5997
+ lines2.push("");
5998
+ lines2.push(
3910
5999
  "_Path heuristics from the local diff \u2014 informational, they never block._"
3911
6000
  );
3912
- lines.push("");
3913
- for (const flag2 of riskFlags) lines.push(`- \`${flag2}\``);
3914
- lines.push("");
6001
+ lines2.push("");
6002
+ for (const flag2 of riskFlags) lines2.push(`- \`${flag2}\``);
6003
+ lines2.push("");
3915
6004
  }
3916
6005
  if (hints.length > 0) {
3917
- lines.push("## Lesson hints");
3918
- lines.push("");
3919
- lines.push("_Semantic suggestions \u2014 advisory, never part of a verdict._");
3920
- lines.push("");
6006
+ lines2.push("## Lesson hints");
6007
+ lines2.push("");
6008
+ lines2.push("_Semantic suggestions \u2014 advisory, never part of a verdict._");
6009
+ lines2.push("");
3921
6010
  for (const h of hints) {
3922
6011
  const parts = [`\`${h.id}\``];
3923
6012
  if (h.tier) parts.push(h.tier);
3924
6013
  if (h.match_reason) parts.push(h.match_reason);
3925
- lines.push(`- **${h.title}** (${parts.join(" \xB7 ")})`);
6014
+ lines2.push(`- **${h.title}** (${parts.join(" \xB7 ")})`);
3926
6015
  }
3927
- lines.push("");
6016
+ lines2.push("");
3928
6017
  }
3929
6018
  const rc = review?.regression_context;
3930
6019
  if (rc && (rc.hot_files ?? 0) > 0) {
3931
- lines.push("");
3932
- lines.push(
6020
+ lines2.push("");
6021
+ lines2.push(
3933
6022
  `_History: ${rc.hot_files}/${rc.files_scanned ?? "?"} changed file(s) high-churn (max ${rc.max_recent_commits ?? "?"} commits in the last ${rc.window_commits ?? "?"}-commit window, ${rc.distinct_authors ?? "?"} author(s))._`
3934
6023
  );
3935
6024
  }
3936
6025
  if (review?.coverage_note) {
3937
- lines.push("## Coverage");
3938
- lines.push("");
3939
- lines.push(`> ${review.coverage_note}`);
3940
- lines.push("");
6026
+ lines2.push("## Coverage");
6027
+ lines2.push("");
6028
+ lines2.push(`> ${review.coverage_note}`);
6029
+ lines2.push("");
3941
6030
  }
3942
- lines.push("---");
3943
- lines.push(FOOTER);
3944
- lines.push("");
3945
- return lines.join("\n");
6031
+ lines2.push("---");
6032
+ lines2.push(FOOTER);
6033
+ lines2.push("");
6034
+ return lines2.join("\n");
3946
6035
  }
3947
6036
  function renderReviewComment(data, verdict, meta, reportPath) {
3948
6037
  const review = data.review;
3949
6038
  const findings = review?.convention_findings ?? [];
3950
6039
  const riskFlags = review?.risk_flags ?? [];
3951
6040
  const hints = review?.lesson_hints ?? [];
3952
- const lines = [];
3953
- lines.push(COMMENT_MARKER);
3954
- lines.push("## maind review");
3955
- lines.push("");
6041
+ const lines2 = [];
6042
+ lines2.push(COMMENT_MARKER);
6043
+ lines2.push("## maind review");
6044
+ lines2.push("");
3956
6045
  if (verdict?.ok === true && verdict.verdict) {
3957
- lines.push(verdictLabel(verdict));
6046
+ lines2.push(verdictLabel(verdict));
3958
6047
  const attest = attestationLine(verdict);
3959
- if (attest) lines.push(attest);
3960
- lines.push("");
6048
+ if (attest) lines2.push(attest);
6049
+ lines2.push("");
3961
6050
  }
3962
6051
  if (findings.length === 0) {
3963
- lines.push(
6052
+ lines2.push(
3964
6053
  `No convention findings for this change set (${meta.symbolCount} changed symbol(s) reviewed ${baseLabel(meta)}).`
3965
6054
  );
3966
- lines.push("");
6055
+ lines2.push("");
3967
6056
  } else {
3968
6057
  const shown = findings.slice(0, COMMENT_FINDINGS_CAP);
3969
- for (const f of shown) lines.push(findingLine(f));
6058
+ for (const f of shown) lines2.push(findingLine(f));
3970
6059
  if (findings.length > shown.length) {
3971
- lines.push("");
3972
- lines.push(
6060
+ lines2.push("");
6061
+ lines2.push(
3973
6062
  `\u2026and ${findings.length - shown.length} more finding(s) \u2014 see the \`${reportPath}\` build artifact.`
3974
6063
  );
3975
6064
  }
3976
- lines.push("");
6065
+ lines2.push("");
3977
6066
  }
3978
6067
  if (riskFlags.length > 0) {
3979
- lines.push(
6068
+ lines2.push(
3980
6069
  `**Risk flags:** ${riskFlags.map((f) => `\`${f}\``).join(" \xB7 ")} _(heuristics, never blocking)_`
3981
6070
  );
3982
- lines.push("");
6071
+ lines2.push("");
3983
6072
  }
3984
6073
  if (hints.length > 0) {
3985
- lines.push("**Related lessons:** " + hints.map((h) => `\`${h.id}\``).join(" \xB7 "));
3986
- lines.push("");
6074
+ lines2.push("**Related lessons:** " + hints.map((h) => `\`${h.id}\``).join(" \xB7 "));
6075
+ lines2.push("");
3987
6076
  }
3988
6077
  if (review?.coverage_note) {
3989
- lines.push(`> ${review.coverage_note}`);
3990
- lines.push("");
6078
+ lines2.push(`> ${review.coverage_note}`);
6079
+ lines2.push("");
3991
6080
  }
3992
- lines.push("---");
3993
- lines.push(`_${FOOTER}_`);
3994
- lines.push("");
3995
- return lines.join("\n");
6081
+ lines2.push("---");
6082
+ lines2.push(`_${FOOTER}_`);
6083
+ lines2.push("");
6084
+ return lines2.join("\n");
3996
6085
  }
3997
6086
  function renderFailOpenReview(meta, reason) {
3998
6087
  return [
@@ -4061,12 +6150,12 @@ function nowIso3() {
4061
6150
  return (/* @__PURE__ */ new Date()).toISOString();
4062
6151
  }
4063
6152
  function writeArtifact3(path, content) {
4064
- const dir = dirname4(path);
4065
- if (dir && dir !== ".") mkdirSync4(dir, { recursive: true });
4066
- writeFileSync4(path, content, "utf8");
6153
+ const dir = dirname5(path);
6154
+ if (dir && dir !== ".") mkdirSync5(dir, { recursive: true });
6155
+ writeFileSync5(path, content, "utf8");
4067
6156
  }
4068
- function manifestPathFor(out) {
4069
- return out.endsWith(".md") ? out.slice(0, -3) + ".json" : out + ".json";
6157
+ function manifestPathFor(out2) {
6158
+ return out2.endsWith(".md") ? out2.slice(0, -3) + ".json" : out2 + ".json";
4070
6159
  }
4071
6160
  function verdictCrossesFailOn(verdict, failOn) {
4072
6161
  return failOn === "block" ? verdict === "block" : verdict === "block" || verdict === "warn";
@@ -4088,7 +6177,7 @@ function buildDiffStats(result) {
4088
6177
  }
4089
6178
  function resolveRepoRoot() {
4090
6179
  try {
4091
- return execFileSync6("git", ["rev-parse", "--show-toplevel"], {
6180
+ return execFileSync8("git", ["rev-parse", "--show-toplevel"], {
4092
6181
  encoding: "utf8",
4093
6182
  stdio: ["ignore", "pipe", "ignore"]
4094
6183
  }).trim();
@@ -4123,7 +6212,7 @@ async function runReview(opts) {
4123
6212
  if (opts.comment) writeArtifact3(opts.comment, renderFailOpenComment(meta, reason));
4124
6213
  if (opts.json) process.stdout.write(JSON.stringify(manifest, null, 2) + "\n");
4125
6214
  } catch (writeErr) {
4126
- warn5(`could not write fail-open artifacts: ${msg5(writeErr)}`);
6215
+ warn5(`could not write fail-open artifacts: ${msg6(writeErr)}`);
4127
6216
  return opts.strict ? 2 : 1;
4128
6217
  }
4129
6218
  return hard ? 2 : 0;
@@ -4258,9 +6347,9 @@ async function runReview(opts) {
4258
6347
  verdict = null;
4259
6348
  }
4260
6349
  }
4261
- } catch (err2) {
4262
- if (opts.strict) return failOpen(`review_verdict failed: ${msg5(err2)}`, "infra");
4263
- warn5(`gate unavailable (continuing advisory): ${msg5(err2)}`);
6350
+ } catch (err4) {
6351
+ if (opts.strict) return failOpen(`review_verdict failed: ${msg6(err4)}`, "infra");
6352
+ warn5(`gate unavailable (continuing advisory): ${msg6(err4)}`);
4264
6353
  verdict = null;
4265
6354
  }
4266
6355
  }
@@ -4281,9 +6370,9 @@ async function runReview(opts) {
4281
6370
  }
4282
6371
  }
4283
6372
  return 0;
4284
- } catch (err2) {
4285
- if (err2 instanceof MissingApiKeyError) return failOpen(err2.message, "expected");
4286
- return failOpen(msg5(err2), "infra");
6373
+ } catch (err4) {
6374
+ if (err4 instanceof MissingApiKeyError) return failOpen(err4.message, "expected");
6375
+ return failOpen(msg6(err4), "infra");
4287
6376
  }
4288
6377
  }
4289
6378
  var EXPECTED_SERVER_ERRORS = /* @__PURE__ */ new Set([
@@ -4306,25 +6395,541 @@ function writeAll(review, verdict, meta, opts) {
4306
6395
  }
4307
6396
  if (opts.json) process.stdout.write(JSON.stringify(manifest, null, 2) + "\n");
4308
6397
  }
4309
- function msg5(err2) {
4310
- return err2 instanceof Error ? err2.message : String(err2);
6398
+ function msg6(err4) {
6399
+ return err4 instanceof Error ? err4.message : String(err4);
4311
6400
  }
4312
6401
  function warn5(line) {
4313
6402
  process.stderr.write(`maind review: ${line}
4314
6403
  `);
4315
6404
  }
4316
6405
 
6406
+ // ../../packages/claude-code-telemetry/dist/session-analysis.js
6407
+ import { createReadStream, existsSync as existsSync7 } from "node:fs";
6408
+ import { createInterface } from "node:readline";
6409
+
6410
+ // ../../packages/claude-code-telemetry/dist/effort.js
6411
+ var LEVELS = /* @__PURE__ */ new Set([
6412
+ "low",
6413
+ "medium",
6414
+ "high",
6415
+ "xhigh",
6416
+ "max"
6417
+ ]);
6418
+ var DIRECTIVE_RE = /(?:^|\s)\/(low|medium|high|xhigh|max)(?=\s|$|[!?.,;:])/gi;
6419
+ function detectEffortLevel(messageText) {
6420
+ if (!messageText)
6421
+ return null;
6422
+ let last = null;
6423
+ for (const match of messageText.matchAll(DIRECTIVE_RE)) {
6424
+ const lvl = match[1].toLowerCase();
6425
+ if (LEVELS.has(lvl))
6426
+ last = lvl;
6427
+ }
6428
+ return last;
6429
+ }
6430
+
6431
+ // ../../packages/claude-code-telemetry/dist/session-analysis.js
6432
+ var MAIND_TOOL_PREFIX = "mcp__maind__";
6433
+ var ANALYZER_VERSION = "2026-08-16";
6434
+ var REWORK_RE = /(\brückgängig\b|zurücknehmen|\bnochmal(s)?\b|noch mal|\brevert\b|\bundo\b|\bredo\b|stattdessen|\binstead\b|mach(e)? das (nochmal|neu)|try again)/i;
6435
+ var CORRECTION_RE = /(\bnein\b|\bfalsch\b|stimmt nicht|das ist nicht|so nicht|\bnicht so\b|warum hast du|wieso hast du|\bno\b|\bnope\b|\bwrong\b|\bincorrect\b|that'?s not|that is not|\bdon'?t\b|\bdoesn'?t\b|shouldn'?t)/i;
6436
+ var ACCEPTANCE_RE = /(\bdanke\b|\bperfekt\b|\bsuper\b|\bpasst\b|\bgenau\b|sieht gut|\bcommit\b|\bship\b|\bmerge\b|\bpush\b|looks good|\blgtm\b|\bthanks\b|thank you|\bperfect\b|\bgreat\b|\bexactly\b|\bnice\b|well done|👍|✅|🎉)/i;
6437
+ var INTERRUPT_MARKER = "[Request interrupted by user";
6438
+ var DENIAL_MARKER = "The user doesn't want to proceed with this tool use";
6439
+ var SYNTHETIC_MODEL = "<synthetic>";
6440
+ var MOMENTUM_DECAY = 0.7;
6441
+ var MAG = {
6442
+ denial: 1.5,
6443
+ interrupt: 1.25,
6444
+ rework: 1.5,
6445
+ correction: 1,
6446
+ acceptance: 1,
6447
+ repeat: 0.75
6448
+ };
6449
+ function num(v) {
6450
+ return typeof v === "number" && Number.isFinite(v) ? v : 0;
6451
+ }
6452
+ function bumpModel(acc, model, sidechain, outputTokens, ts) {
6453
+ const key = `${sidechain ? "s" : "m"}:${model}`;
6454
+ const cur = acc.get(key);
6455
+ if (!cur) {
6456
+ acc.set(key, {
6457
+ model,
6458
+ turns: 1,
6459
+ output_tokens: outputTokens,
6460
+ first_ts: ts,
6461
+ last_ts: ts,
6462
+ sidechain
6463
+ });
6464
+ return;
6465
+ }
6466
+ cur.turns++;
6467
+ cur.output_tokens += outputTokens;
6468
+ if (ts > 0) {
6469
+ if (cur.first_ts === 0 || ts < cur.first_ts)
6470
+ cur.first_ts = ts;
6471
+ if (ts > cur.last_ts)
6472
+ cur.last_ts = ts;
6473
+ }
6474
+ }
6475
+ function asBlocks(content) {
6476
+ if (typeof content === "string")
6477
+ return [{ type: "text", text: content }];
6478
+ if (!Array.isArray(content))
6479
+ return [];
6480
+ return content.filter((b) => b !== null && typeof b === "object");
6481
+ }
6482
+ function textOf(blocks) {
6483
+ const parts = [];
6484
+ for (const b of blocks) {
6485
+ if (b.type === "text" && typeof b.text === "string")
6486
+ parts.push(b.text);
6487
+ }
6488
+ return parts.join("\n");
6489
+ }
6490
+ function isRepeat(prev, cur) {
6491
+ const toks = (s) => new Set(s.toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").split(/\s+/).filter((w) => w.length > 2));
6492
+ const a = toks(prev);
6493
+ const b = toks(cur);
6494
+ if (a.size < 3 || b.size < 3)
6495
+ return false;
6496
+ const [small, big] = a.size <= b.size ? [a, b] : [b, a];
6497
+ let shared = 0;
6498
+ for (const w of small)
6499
+ if (big.has(w))
6500
+ shared++;
6501
+ return shared / small.size >= 0.8;
6502
+ }
6503
+ function classifyGenuine(text, prevText, priorWork) {
6504
+ if (REWORK_RE.test(text))
6505
+ return { polarity: -1, magnitude: MAG.rework, kind: "rework" };
6506
+ if (priorWork && CORRECTION_RE.test(text))
6507
+ return { polarity: -1, magnitude: MAG.correction, kind: "correction" };
6508
+ if (ACCEPTANCE_RE.test(text))
6509
+ return { polarity: 1, magnitude: MAG.acceptance, kind: "acceptance" };
6510
+ if (prevText !== null && isRepeat(prevText, text))
6511
+ return { polarity: -1, magnitude: MAG.repeat, kind: "repeat" };
6512
+ return { polarity: 0, magnitude: 0, kind: "neutral" };
6513
+ }
6514
+ function emptyAnalysis(sessionId) {
6515
+ return {
6516
+ session_id: sessionId,
6517
+ user_turns: 0,
6518
+ assistant_turns: 0,
6519
+ tool_calls: 0,
6520
+ agent_questions: 0,
6521
+ input_tokens: 0,
6522
+ output_tokens: 0,
6523
+ cache_read_tokens: 0,
6524
+ cache_creation_tokens: 0,
6525
+ user_chars: 0,
6526
+ user_token_estimate: 0,
6527
+ human_share: 0,
6528
+ reactions_pos: 0,
6529
+ reactions_neg: 0,
6530
+ net_sentiment: 0,
6531
+ corrections: 0,
6532
+ reworks: 0,
6533
+ interrupts: 0,
6534
+ tool_denials: 0,
6535
+ repeated_instructions: 0,
6536
+ acceptances: 0,
6537
+ momentum_series: [],
6538
+ momentum_final: 0,
6539
+ momentum_auc: 0,
6540
+ ended_positive: false,
6541
+ recovery_events: 0,
6542
+ effort_at_end: null,
6543
+ model_mix: [],
6544
+ ai_title: null,
6545
+ session_slug: null,
6546
+ maind_tool_calls: {},
6547
+ maind_connected: "unknown",
6548
+ lines_seen: 0,
6549
+ analyzer_version: ANALYZER_VERSION
6550
+ };
6551
+ }
6552
+ async function analyzeSession(path) {
6553
+ const a = emptyAnalysis("");
6554
+ if (!path || !existsSync7(path))
6555
+ return a;
6556
+ const reactions = [];
6557
+ const modelMix = /* @__PURE__ */ new Map();
6558
+ let effort = null;
6559
+ let priorAssistantWorked = false;
6560
+ let prevUserText = null;
6561
+ await new Promise((resolve2) => {
6562
+ const stream = createReadStream(path, { encoding: "utf-8" });
6563
+ const rl = createInterface({ input: stream });
6564
+ const processLine = (line) => {
6565
+ const trimmed = line.trim();
6566
+ if (!trimmed)
6567
+ return;
6568
+ let parsed;
6569
+ try {
6570
+ parsed = JSON.parse(trimmed);
6571
+ } catch {
6572
+ return;
6573
+ }
6574
+ a.lines_seen++;
6575
+ if (!a.session_id) {
6576
+ const sid = parsed.sessionId ?? parsed.session_id;
6577
+ if (typeof sid === "string" && sid)
6578
+ a.session_id = sid;
6579
+ }
6580
+ if (parsed.type === "ai-title" && typeof parsed.aiTitle === "string" && parsed.aiTitle) {
6581
+ a.ai_title = parsed.aiTitle;
6582
+ }
6583
+ if (typeof parsed.slug === "string" && parsed.slug)
6584
+ a.session_slug = parsed.slug;
6585
+ const role = parsed.message?.role;
6586
+ const isSide = parsed.isSidechain === true;
6587
+ const usage = parsed.message?.usage;
6588
+ if (role === "assistant" && usage) {
6589
+ a.input_tokens += num(usage.input_tokens);
6590
+ a.output_tokens += num(usage.output_tokens);
6591
+ a.cache_read_tokens += num(usage.cache_read_input_tokens);
6592
+ a.cache_creation_tokens += num(usage.cache_creation_input_tokens);
6593
+ }
6594
+ if (role === "assistant" && typeof parsed.message?.model === "string" && parsed.message.model && parsed.message.model !== SYNTHETIC_MODEL) {
6595
+ const rawTs = parsed.timestamp ? Date.parse(parsed.timestamp) : Number.NaN;
6596
+ bumpModel(modelMix, parsed.message.model, isSide, num(usage?.output_tokens), Number.isFinite(rawTs) ? rawTs : 0);
6597
+ }
6598
+ if (role === "assistant") {
6599
+ for (const b of asBlocks(parsed.message?.content)) {
6600
+ if (b.type !== "tool_use" || typeof b.name !== "string")
6601
+ continue;
6602
+ if (!b.name.startsWith(MAIND_TOOL_PREFIX))
6603
+ continue;
6604
+ const tool = b.name.slice(MAIND_TOOL_PREFIX.length);
6605
+ if (!tool)
6606
+ continue;
6607
+ a.maind_tool_calls[tool] = (a.maind_tool_calls[tool] ?? 0) + 1;
6608
+ }
6609
+ }
6610
+ if (isSide)
6611
+ return;
6612
+ if (role === "assistant") {
6613
+ a.assistant_turns++;
6614
+ const blocks2 = asBlocks(parsed.message?.content);
6615
+ let worked = false;
6616
+ for (const b of blocks2) {
6617
+ if (b.type === "tool_use") {
6618
+ a.tool_calls++;
6619
+ worked = true;
6620
+ if (b.name === "AskUserQuestion")
6621
+ a.agent_questions++;
6622
+ }
6623
+ }
6624
+ priorAssistantWorked = worked;
6625
+ return;
6626
+ }
6627
+ if (role !== "user")
6628
+ return;
6629
+ const blocks = asBlocks(parsed.message?.content);
6630
+ const text = textOf(blocks);
6631
+ if (text.includes(INTERRUPT_MARKER)) {
6632
+ a.interrupts++;
6633
+ reactions.push({ polarity: -1, magnitude: MAG.interrupt, kind: "interrupt" });
6634
+ return;
6635
+ }
6636
+ const denied = blocks.some((b) => b.type === "tool_result" && b.is_error === true && typeof b.content === "string" && b.content.includes(DENIAL_MARKER));
6637
+ if (denied) {
6638
+ a.tool_denials++;
6639
+ reactions.push({ polarity: -1, magnitude: MAG.denial, kind: "denial" });
6640
+ return;
6641
+ }
6642
+ if (blocks.some((b) => b.type === "tool_result"))
6643
+ return;
6644
+ if (!text.trim())
6645
+ return;
6646
+ a.user_turns++;
6647
+ a.user_chars += text.length;
6648
+ const directive = detectEffortLevel(text);
6649
+ if (directive)
6650
+ effort = directive;
6651
+ const r = classifyGenuine(text, prevUserText, priorAssistantWorked);
6652
+ prevUserText = text;
6653
+ if (r.kind === "correction")
6654
+ a.corrections++;
6655
+ else if (r.kind === "rework")
6656
+ a.reworks++;
6657
+ else if (r.kind === "repeat")
6658
+ a.repeated_instructions++;
6659
+ else if (r.kind === "acceptance")
6660
+ a.acceptances++;
6661
+ if (r.polarity !== 0)
6662
+ reactions.push(r);
6663
+ priorAssistantWorked = false;
6664
+ };
6665
+ rl.on("line", (line) => {
6666
+ try {
6667
+ processLine(line);
6668
+ } catch {
6669
+ }
6670
+ });
6671
+ rl.on("close", () => resolve2());
6672
+ rl.on("error", () => resolve2());
6673
+ stream.on("error", () => resolve2());
6674
+ });
6675
+ a.effort_at_end = effort;
6676
+ a.model_mix = [...modelMix.values()].sort((x, y) => x.first_ts - y.first_ts || x.model.localeCompare(y.model));
6677
+ a.user_token_estimate = Math.round(a.user_chars / 4);
6678
+ const denom = a.user_token_estimate + a.output_tokens;
6679
+ a.human_share = denom > 0 ? Number((a.user_token_estimate / denom).toFixed(4)) : 0;
6680
+ let momentum = 0;
6681
+ let auc = 0;
6682
+ const series = [];
6683
+ reactions.forEach((r, i) => {
6684
+ if (r.polarity > 0)
6685
+ a.reactions_pos++;
6686
+ else if (r.polarity < 0)
6687
+ a.reactions_neg++;
6688
+ momentum = momentum * MOMENTUM_DECAY + r.polarity * r.magnitude;
6689
+ const value2 = Number(momentum.toFixed(3));
6690
+ series.push({
6691
+ t: i,
6692
+ value: value2,
6693
+ ...r.kind !== "neutral" ? { kind: r.kind } : {}
6694
+ });
6695
+ auc += value2;
6696
+ if (i > 0 && reactions[i - 1].polarity < 0 && r.polarity > 0)
6697
+ a.recovery_events++;
6698
+ });
6699
+ a.net_sentiment = a.reactions_pos - a.reactions_neg;
6700
+ a.momentum_series = series;
6701
+ a.momentum_final = series.length ? series[series.length - 1].value : 0;
6702
+ a.momentum_auc = Number(auc.toFixed(3));
6703
+ a.ended_positive = a.momentum_final > 0;
6704
+ if (Object.keys(a.maind_tool_calls).length > 0)
6705
+ a.maind_connected = "connected";
6706
+ return a;
6707
+ }
6708
+
6709
+ // ../../packages/claude-code-telemetry/dist/ingest.js
6710
+ function ingestBody(analytics, span, ctx) {
6711
+ const body = { session_analytics: analytics };
6712
+ if (span && span.started_at) {
6713
+ body.session_span = ctx ? { ...span, ...ctx } : span;
6714
+ }
6715
+ return body;
6716
+ }
6717
+ function ingestHeaders(auth) {
6718
+ const headers = {
6719
+ "content-type": "application/json",
6720
+ authorization: `Bearer ${auth.apiKey}`
6721
+ };
6722
+ if (auth.deviceId)
6723
+ headers["x-maind-device-id"] = auth.deviceId;
6724
+ return headers;
6725
+ }
6726
+ async function postSessionAnalytics(target, analytics, span, ctx) {
6727
+ try {
6728
+ const res = await fetch(target.endpoint, {
6729
+ method: "POST",
6730
+ headers: ingestHeaders(target),
6731
+ body: JSON.stringify(ingestBody(analytics, span, ctx))
6732
+ });
6733
+ if (!res.ok) {
6734
+ const text = await res.text().catch(() => "");
6735
+ return { ok: false, inserted: 0, status: res.status, error: text.slice(0, 500) };
6736
+ }
6737
+ const json = await res.json().catch(() => null);
6738
+ return {
6739
+ ok: true,
6740
+ inserted: json?.analytics_stored ? 1 : 0,
6741
+ spanStored: json?.span_stored === true,
6742
+ status: res.status
6743
+ };
6744
+ } catch (err4) {
6745
+ return {
6746
+ ok: false,
6747
+ inserted: 0,
6748
+ error: err4 instanceof Error ? err4.message : String(err4)
6749
+ };
6750
+ }
6751
+ }
6752
+
6753
+ // ../../packages/claude-code-telemetry/dist/windows.js
6754
+ var FIVE_HOURS_MS = 5 * 60 * 60 * 1e3;
6755
+ var WEEK_MS = 7 * 24 * 60 * 60 * 1e3;
6756
+
6757
+ // ../../packages/claude-code-telemetry/dist/projects.js
6758
+ import { readdir, stat } from "node:fs/promises";
6759
+ import { homedir as homedir4 } from "node:os";
6760
+ import { join as join8 } from "node:path";
6761
+ var HOME = homedir4();
6762
+ var DEFAULT_PROJECTS_DIR = join8(HOME, ".claude", "projects");
6763
+ function cwdFromProjectDir(encoded) {
6764
+ if (!encoded.startsWith("-"))
6765
+ return encoded;
6766
+ return encoded.replace(/-/g, "/");
6767
+ }
6768
+ async function listProjects(projectsDir = DEFAULT_PROJECTS_DIR) {
6769
+ let entries;
6770
+ try {
6771
+ entries = await readdir(projectsDir);
6772
+ } catch {
6773
+ return [];
6774
+ }
6775
+ const out2 = [];
6776
+ for (const entry of entries) {
6777
+ if (!entry.startsWith("-"))
6778
+ continue;
6779
+ const dir = join8(projectsDir, entry);
6780
+ let files;
6781
+ try {
6782
+ files = await readdir(dir);
6783
+ } catch {
6784
+ continue;
6785
+ }
6786
+ const transcripts = files.filter((f) => f.endsWith(".jsonl"));
6787
+ if (transcripts.length === 0)
6788
+ continue;
6789
+ let mtimeMs = 0;
6790
+ for (const f of transcripts) {
6791
+ try {
6792
+ const st = await stat(join8(dir, f));
6793
+ if (st.mtimeMs > mtimeMs)
6794
+ mtimeMs = st.mtimeMs;
6795
+ } catch {
6796
+ }
6797
+ }
6798
+ out2.push({
6799
+ encodedDir: entry,
6800
+ cwd: cwdFromProjectDir(entry),
6801
+ transcripts: transcripts.map((f) => join8(dir, f)),
6802
+ mtimeMs
6803
+ });
6804
+ }
6805
+ out2.sort((a, b) => b.mtimeMs - a.mtimeMs);
6806
+ return out2.map(({ mtimeMs: _mtime, ...rest }) => rest);
6807
+ }
6808
+
6809
+ // src/sessions-cmd.ts
6810
+ var DEFAULT_ENDPOINT = "https://vsddmiosisvfrairepxv.supabase.co/functions/v1/mcp-client-metrics-ingest";
6811
+ var THROTTLE_MS = 120;
6812
+ function err2(line) {
6813
+ process.stderr.write(`maind: ${line}
6814
+ `);
6815
+ }
6816
+ function out(line) {
6817
+ process.stdout.write(line + "\n");
6818
+ }
6819
+ function parseSessionsArgs(argv) {
6820
+ const args = { dryRun: false, since: null, json: false };
6821
+ for (let i = 0; i < argv.length; i++) {
6822
+ const a = argv[i];
6823
+ if (a === "--dry-run") args.dryRun = true;
6824
+ else if (a === "--json") args.json = true;
6825
+ else if (a === "--since") {
6826
+ const raw = argv[++i];
6827
+ const ts = raw ? Date.parse(raw) : Number.NaN;
6828
+ if (Number.isFinite(ts)) args.since = ts;
6829
+ else err2(`ignoring unparseable --since '${raw ?? ""}' (expected YYYY-MM-DD)`);
6830
+ }
6831
+ }
6832
+ return args;
6833
+ }
6834
+ function endpoint() {
6835
+ const raw = process.env.MAIND_INGEST_URL?.trim();
6836
+ return raw && raw.length > 0 ? raw : DEFAULT_ENDPOINT;
6837
+ }
6838
+ var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
6839
+ async function runSessionsBackfill(args) {
6840
+ let auth;
6841
+ try {
6842
+ auth = resolveAuth();
6843
+ } catch (e) {
6844
+ if (e instanceof MissingApiKeyError) {
6845
+ err2(e.message);
6846
+ return 1;
6847
+ }
6848
+ throw e;
6849
+ }
6850
+ const projects = await listProjects();
6851
+ const transcripts = projects.flatMap((p) => p.transcripts);
6852
+ if (transcripts.length === 0) {
6853
+ err2("no Claude Code transcripts found under ~/.claude/projects.");
6854
+ return 0;
6855
+ }
6856
+ const target = endpoint();
6857
+ const rows = [];
6858
+ let skipped = 0;
6859
+ let failed = 0;
6860
+ for (const path of transcripts) {
6861
+ const analysis = await analyzeSession(path);
6862
+ if (!analysis.session_id) {
6863
+ skipped++;
6864
+ continue;
6865
+ }
6866
+ if (args.since !== null) {
6867
+ const last = analysis.model_mix.reduce((m, s) => Math.max(m, s.last_ts), 0);
6868
+ if (last > 0 && last < args.since) {
6869
+ skipped++;
6870
+ continue;
6871
+ }
6872
+ }
6873
+ const main2 = analysis.model_mix.filter((m) => !m.sidechain);
6874
+ const row = {
6875
+ session_id: analysis.session_id,
6876
+ title: analysis.ai_title,
6877
+ models: main2.map((m) => `${m.model}\xD7${m.turns}`).join(", ") || "\u2014",
6878
+ turns: analysis.assistant_turns,
6879
+ lines: analysis.lines_seen,
6880
+ posted: false
6881
+ };
6882
+ if (!args.dryRun) {
6883
+ const res = await postSessionAnalytics(
6884
+ { endpoint: target, apiKey: auth.apiKey, deviceId: auth.deviceId },
6885
+ analysis
6886
+ );
6887
+ row.posted = res.ok;
6888
+ if (!res.ok) {
6889
+ failed++;
6890
+ row.error = res.error ?? `status ${res.status ?? "?"}`;
6891
+ }
6892
+ await sleep(THROTTLE_MS);
6893
+ }
6894
+ rows.push(row);
6895
+ }
6896
+ if (args.json) {
6897
+ out(JSON.stringify({ ok: failed === 0, dry_run: args.dryRun, skipped, failed, sessions: rows }, null, 2));
6898
+ return failed === 0 ? 0 : 1;
6899
+ }
6900
+ out(
6901
+ args.dryRun ? `Would upload ${rows.length} session(s) to ${target}:` : `Uploaded ${rows.length - failed}/${rows.length} session(s) to ${target}:`
6902
+ );
6903
+ out("");
6904
+ for (const r of rows) {
6905
+ const mark = args.dryRun ? " " : r.posted ? "\u2713" : "\u2717";
6906
+ out(`${mark} ${r.session_id.slice(0, 8)} ${String(r.turns).padStart(4)} turns ${r.models}`);
6907
+ out(` title: ${r.title ?? "\u2014"}`);
6908
+ if (r.error) out(` error: ${r.error}`);
6909
+ }
6910
+ out("");
6911
+ if (skipped > 0) out(`${skipped} transcript(s) skipped (no session id, or older than --since).`);
6912
+ if (args.dryRun) {
6913
+ out("Dry run \u2014 nothing was uploaded.");
6914
+ out(
6915
+ "Note: a real run uploads the session TITLES listed above (content-derived) for every project on this machine. They are only stored if you enabled 'Session titles' in the consent center; without it the numbers land and the titles are dropped."
6916
+ );
6917
+ }
6918
+ if (failed > 0) err2(`${failed} session(s) failed \u2014 re-running is safe, the server upserts.`);
6919
+ return failed === 0 ? 0 : 1;
6920
+ }
6921
+
4317
6922
  // src/sync-cmd.ts
4318
- import { execFileSync as execFileSync7 } from "node:child_process";
6923
+ import { execFileSync as execFileSync9 } from "node:child_process";
4319
6924
  var CONSENT_POLICY_VERSION = "2026-07-05";
4320
6925
  var DEFAULT_DASHBOARD_URL = "https://app.maind.dev";
4321
- function err(line) {
6926
+ function err3(line) {
4322
6927
  process.stderr.write(`maind: ${line}
4323
6928
  `);
4324
6929
  }
4325
6930
  function repoRoot() {
4326
6931
  try {
4327
- return execFileSync7("git", ["rev-parse", "--show-toplevel"], { encoding: "utf8" }).trim();
6932
+ return execFileSync9("git", ["rev-parse", "--show-toplevel"], { encoding: "utf8" }).trim();
4328
6933
  } catch {
4329
6934
  return process.cwd();
4330
6935
  }
@@ -4339,7 +6944,7 @@ function makeSync(json) {
4339
6944
  auth = resolveAuth();
4340
6945
  } catch (e) {
4341
6946
  if (e instanceof MissingApiKeyError) {
4342
- err(e.message);
6947
+ err3(e.message);
4343
6948
  return null;
4344
6949
  }
4345
6950
  throw e;
@@ -4353,11 +6958,11 @@ function makeSync(json) {
4353
6958
  onProgress: json ? void 0 : (p) => process.stderr.write(` ${p.phase}: ${p.done}/${p.total}\r`)
4354
6959
  });
4355
6960
  } catch (e) {
4356
- err(e instanceof Error ? e.message : String(e));
6961
+ err3(e instanceof Error ? e.message : String(e));
4357
6962
  return null;
4358
6963
  }
4359
6964
  }
4360
- function msg6(e) {
6965
+ function msg7(e) {
4361
6966
  return e instanceof Error ? e.message : String(e);
4362
6967
  }
4363
6968
  function parseSyncArgs(argv) {
@@ -4381,10 +6986,10 @@ async function runSync(opts) {
4381
6986
  }
4382
6987
  } catch (e) {
4383
6988
  if (e instanceof SyncError && e.code === "consent_required") {
4384
- err("codebase cloud-sync is not enabled \u2014 run `maind sync enable` first.");
6989
+ err3("codebase cloud-sync is not enabled \u2014 run `maind sync enable` first.");
4385
6990
  return 1;
4386
6991
  }
4387
- err(`sync failed: ${msg6(e)}`);
6992
+ err3(`sync failed: ${msg7(e)}`);
4388
6993
  return 1;
4389
6994
  } finally {
4390
6995
  await sync.close().catch(() => {
@@ -4420,7 +7025,7 @@ cloud: ${remote.indexed ? `${remote.node_count ?? "?"} symbols \xB7 ${remote.ed
4420
7025
  async function push(sync, json) {
4421
7026
  const local = await sync.localStatus();
4422
7027
  if (!local.indexed || local.nodeCount === 0) {
4423
- err("no local index found \u2014 run `maind index` first.");
7028
+ err3("no local index found \u2014 run `maind index` first.");
4424
7029
  return 1;
4425
7030
  }
4426
7031
  const res = await sync.push();
@@ -4437,7 +7042,7 @@ async function push(sync, json) {
4437
7042
  }
4438
7043
 
4439
7044
  // src/index.ts
4440
- var HELP = `maind ${VERSION} \u2014 headless maind CLI for CI + git context
7045
+ var HELP = `maind ${VERSION} \u2014 headless MAIND CLI for CI + git context
4441
7046
 
4442
7047
  Usage:
4443
7048
  maind context [options] Pull stack-relevant lessons + conventions into the runner
@@ -4451,7 +7056,12 @@ Usage:
4451
7056
  maind sync Push the local index to the cloud (opt-in; hashed rows only)
4452
7057
  maind sync status [--json] Show local vs cloud sync state
4453
7058
  maind sync enable|disable Opt in/out of codebase cloud-sync (consent)
7059
+ maind sessions backfill [.] Recompute session analytics for transcripts already on disk
7060
+ maind launch <agent> [..] Plug&play: local Switchyard model-routing proxy + agent behind it (v1: claude)
4454
7061
  maind review [options] Provenance-backed review findings for a change set (advisory by default)
7062
+ maind object create|link|report [options]
7063
+ Planning integration (ADR-286): create a work object (prints its id),
7064
+ link a PR ref, report pr_opened/merge \u2014 used by feature.sh
4455
7065
  maind ci-report [options] Report a CI failure as a draft-lesson candidate (on failure)
4456
7066
  maind ci-result [options] Report a build outcome + served manifest (end of job)
4457
7067
  maind --help Show this help
@@ -4478,6 +7088,24 @@ review options (advisory by default \u2014 exits 0 unless --gate + --fail-on):
4478
7088
  --project-key <hex> Repo project_key override (default: auto-detect from git)
4479
7089
  --mcp-url <url> Override MCP endpoint (default $MAIND_MCP_URL or production)
4480
7090
 
7091
+ launch options (v1 agent: claude; codex/openclaw planned \u2014 ADR-272):
7092
+ --dry-run Print the generated routes TOML (stdout) + config path, detection
7093
+ state and the exact spawn command (stderr); installs, writes and
7094
+ spawns nothing
7095
+ --json With --dry-run: machine-readable plan JSON on stdout
7096
+ --config <path> Use an existing routes.toml \u2014 skips generation + template fetch
7097
+ --route <name> Route name for --model and the generated [routes.<name>] (default: switchyard)
7098
+ --direct Skip the proxy \u2014 spawn the agent directly (no routing, visible banner)
7099
+ --no-fallback On switchyard startup failure exit 1 instead of degrading to a
7100
+ direct agent spawn
7101
+ --no-install Never auto-install; print the install one-liner and exit 1 when missing
7102
+ --mcp-url <url> Override MCP endpoint for the curated-template fetch
7103
+ Prereqs: installs nemo-switchyard[cli] via uv automatically when uv exists \u2014 never
7104
+ installs uv itself (prints the official instruction instead). The generated config
7105
+ lands in <repoRoot>/.maind/switchyard-routes.toml (or the maind user config dir
7106
+ outside a repo). Backend keys (ANTHROPIC_API_KEY / OPENROUTER_API_KEY) are read
7107
+ from the environment by the proxy at runtime \u2014 never written into the TOML.
7108
+
4481
7109
  git-context options (run at session-start; reads local git + gh, all fail-open):
4482
7110
  --out <path> Briefing markdown output (default .maind/git-context.md)
4483
7111
  --manifest <path> Optional structured JSON output (git_context manifest)
@@ -4503,6 +7131,16 @@ ci-result options (run at the end of a job, success OR failure):
4503
7131
  --run-url <url> Link to the CI run (default derived from GitHub env)
4504
7132
  --result-url <url> Override ingest endpoint (default $MAIND_RESULT_URL or prod)
4505
7133
 
7134
+ sessions backfill options:
7135
+ --dry-run List what WOULD be uploaded (incl. the session titles) and stop.
7136
+ Recommended before the first real run \u2014 a backfill covers every
7137
+ project on this machine, and titles are content-derived.
7138
+ --since <YYYY-MM-DD> Only sessions whose last turn is on/after this date
7139
+ --json Machine-readable result
7140
+ Idempotent: the server upserts on (user_id, session_id), so re-running is safe.
7141
+ Titles are only stored if 'Session titles' is enabled in the consent center;
7142
+ otherwise the numbers land and the title is dropped server-side.
7143
+
4506
7144
  context options:
4507
7145
  --stack <a,b> Stack hint (seeds the platforms filter), e.g. nextjs,supabase
4508
7146
  --platforms <a,b> Explicit platforms filter (overrides --stack)
@@ -4546,6 +7184,9 @@ async function main() {
4546
7184
  process.stdout.write(key + "\n");
4547
7185
  return 0;
4548
7186
  }
7187
+ if (cmd === "launch") {
7188
+ return runLaunch(parseLaunchArgs(argv.slice(1)));
7189
+ }
4549
7190
  const usesOrt = cmd === "index" && argv.includes("--embed") || cmd === "index-semantic";
4550
7191
  if (usesOrt && !isOrtWorker(argv)) {
4551
7192
  return runOrtIsolated(argv);
@@ -4568,9 +7209,19 @@ async function main() {
4568
7209
  if (cmd === "sync") {
4569
7210
  return runSync(parseSyncArgs(argv.slice(1)));
4570
7211
  }
7212
+ if (cmd === "sessions") {
7213
+ if (argv[1] !== "backfill") {
7214
+ process.stderr.write("maind: usage: maind sessions backfill [--dry-run] [--since YYYY-MM-DD] [--json]\n");
7215
+ return 2;
7216
+ }
7217
+ return runSessionsBackfill(parseSessionsArgs(argv.slice(2)));
7218
+ }
4571
7219
  if (cmd === "review") {
4572
7220
  return runReview(parseReviewArgs(argv.slice(1)));
4573
7221
  }
7222
+ if (cmd === "object") {
7223
+ return runObject(parseObjectArgs(argv.slice(1)));
7224
+ }
4574
7225
  if (cmd === "ci-report") {
4575
7226
  return runCiReport(parseCiReportArgs(argv.slice(1)));
4576
7227
  }
@@ -4581,8 +7232,271 @@ async function main() {
4581
7232
  `);
4582
7233
  return 2;
4583
7234
  }
4584
- main().then((code) => process.exit(code)).catch((err2) => {
4585
- process.stderr.write(`maind: fatal: ${err2 instanceof Error ? err2.stack ?? err2.message : String(err2)}
7235
+ main().then((code) => process.exit(code)).catch((err4) => {
7236
+ process.stderr.write(`maind: fatal: ${err4 instanceof Error ? err4.stack ?? err4.message : String(err4)}
4586
7237
  `);
4587
7238
  process.exit(1);
4588
7239
  });
7240
+ /*! Bundled license information:
7241
+
7242
+ smol-toml/dist/error.js:
7243
+ (*!
7244
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
7245
+ * SPDX-License-Identifier: BSD-3-Clause
7246
+ *
7247
+ * Redistribution and use in source and binary forms, with or without
7248
+ * modification, are permitted provided that the following conditions are met:
7249
+ *
7250
+ * 1. Redistributions of source code must retain the above copyright notice, this
7251
+ * list of conditions and the following disclaimer.
7252
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
7253
+ * this list of conditions and the following disclaimer in the
7254
+ * documentation and/or other materials provided with the distribution.
7255
+ * 3. Neither the name of the copyright holder nor the names of its contributors
7256
+ * may be used to endorse or promote products derived from this software without
7257
+ * specific prior written permission.
7258
+ *
7259
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7260
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
7261
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
7262
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7263
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7264
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
7265
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
7266
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
7267
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
7268
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7269
+ *)
7270
+
7271
+ smol-toml/dist/util.js:
7272
+ (*!
7273
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
7274
+ * SPDX-License-Identifier: BSD-3-Clause
7275
+ *
7276
+ * Redistribution and use in source and binary forms, with or without
7277
+ * modification, are permitted provided that the following conditions are met:
7278
+ *
7279
+ * 1. Redistributions of source code must retain the above copyright notice, this
7280
+ * list of conditions and the following disclaimer.
7281
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
7282
+ * this list of conditions and the following disclaimer in the
7283
+ * documentation and/or other materials provided with the distribution.
7284
+ * 3. Neither the name of the copyright holder nor the names of its contributors
7285
+ * may be used to endorse or promote products derived from this software without
7286
+ * specific prior written permission.
7287
+ *
7288
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7289
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
7290
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
7291
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7292
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7293
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
7294
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
7295
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
7296
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
7297
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7298
+ *)
7299
+
7300
+ smol-toml/dist/date.js:
7301
+ (*!
7302
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
7303
+ * SPDX-License-Identifier: BSD-3-Clause
7304
+ *
7305
+ * Redistribution and use in source and binary forms, with or without
7306
+ * modification, are permitted provided that the following conditions are met:
7307
+ *
7308
+ * 1. Redistributions of source code must retain the above copyright notice, this
7309
+ * list of conditions and the following disclaimer.
7310
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
7311
+ * this list of conditions and the following disclaimer in the
7312
+ * documentation and/or other materials provided with the distribution.
7313
+ * 3. Neither the name of the copyright holder nor the names of its contributors
7314
+ * may be used to endorse or promote products derived from this software without
7315
+ * specific prior written permission.
7316
+ *
7317
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7318
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
7319
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
7320
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7321
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7322
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
7323
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
7324
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
7325
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
7326
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7327
+ *)
7328
+
7329
+ smol-toml/dist/primitive.js:
7330
+ (*!
7331
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
7332
+ * SPDX-License-Identifier: BSD-3-Clause
7333
+ *
7334
+ * Redistribution and use in source and binary forms, with or without
7335
+ * modification, are permitted provided that the following conditions are met:
7336
+ *
7337
+ * 1. Redistributions of source code must retain the above copyright notice, this
7338
+ * list of conditions and the following disclaimer.
7339
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
7340
+ * this list of conditions and the following disclaimer in the
7341
+ * documentation and/or other materials provided with the distribution.
7342
+ * 3. Neither the name of the copyright holder nor the names of its contributors
7343
+ * may be used to endorse or promote products derived from this software without
7344
+ * specific prior written permission.
7345
+ *
7346
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7347
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
7348
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
7349
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7350
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7351
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
7352
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
7353
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
7354
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
7355
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7356
+ *)
7357
+
7358
+ smol-toml/dist/extract.js:
7359
+ (*!
7360
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
7361
+ * SPDX-License-Identifier: BSD-3-Clause
7362
+ *
7363
+ * Redistribution and use in source and binary forms, with or without
7364
+ * modification, are permitted provided that the following conditions are met:
7365
+ *
7366
+ * 1. Redistributions of source code must retain the above copyright notice, this
7367
+ * list of conditions and the following disclaimer.
7368
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
7369
+ * this list of conditions and the following disclaimer in the
7370
+ * documentation and/or other materials provided with the distribution.
7371
+ * 3. Neither the name of the copyright holder nor the names of its contributors
7372
+ * may be used to endorse or promote products derived from this software without
7373
+ * specific prior written permission.
7374
+ *
7375
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7376
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
7377
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
7378
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7379
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7380
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
7381
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
7382
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
7383
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
7384
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7385
+ *)
7386
+
7387
+ smol-toml/dist/struct.js:
7388
+ (*!
7389
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
7390
+ * SPDX-License-Identifier: BSD-3-Clause
7391
+ *
7392
+ * Redistribution and use in source and binary forms, with or without
7393
+ * modification, are permitted provided that the following conditions are met:
7394
+ *
7395
+ * 1. Redistributions of source code must retain the above copyright notice, this
7396
+ * list of conditions and the following disclaimer.
7397
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
7398
+ * this list of conditions and the following disclaimer in the
7399
+ * documentation and/or other materials provided with the distribution.
7400
+ * 3. Neither the name of the copyright holder nor the names of its contributors
7401
+ * may be used to endorse or promote products derived from this software without
7402
+ * specific prior written permission.
7403
+ *
7404
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7405
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
7406
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
7407
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7408
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7409
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
7410
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
7411
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
7412
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
7413
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7414
+ *)
7415
+
7416
+ smol-toml/dist/parse.js:
7417
+ (*!
7418
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
7419
+ * SPDX-License-Identifier: BSD-3-Clause
7420
+ *
7421
+ * Redistribution and use in source and binary forms, with or without
7422
+ * modification, are permitted provided that the following conditions are met:
7423
+ *
7424
+ * 1. Redistributions of source code must retain the above copyright notice, this
7425
+ * list of conditions and the following disclaimer.
7426
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
7427
+ * this list of conditions and the following disclaimer in the
7428
+ * documentation and/or other materials provided with the distribution.
7429
+ * 3. Neither the name of the copyright holder nor the names of its contributors
7430
+ * may be used to endorse or promote products derived from this software without
7431
+ * specific prior written permission.
7432
+ *
7433
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7434
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
7435
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
7436
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7437
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7438
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
7439
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
7440
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
7441
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
7442
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7443
+ *)
7444
+
7445
+ smol-toml/dist/stringify.js:
7446
+ (*!
7447
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
7448
+ * SPDX-License-Identifier: BSD-3-Clause
7449
+ *
7450
+ * Redistribution and use in source and binary forms, with or without
7451
+ * modification, are permitted provided that the following conditions are met:
7452
+ *
7453
+ * 1. Redistributions of source code must retain the above copyright notice, this
7454
+ * list of conditions and the following disclaimer.
7455
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
7456
+ * this list of conditions and the following disclaimer in the
7457
+ * documentation and/or other materials provided with the distribution.
7458
+ * 3. Neither the name of the copyright holder nor the names of its contributors
7459
+ * may be used to endorse or promote products derived from this software without
7460
+ * specific prior written permission.
7461
+ *
7462
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7463
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
7464
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
7465
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7466
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7467
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
7468
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
7469
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
7470
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
7471
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7472
+ *)
7473
+
7474
+ smol-toml/dist/index.js:
7475
+ (*!
7476
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
7477
+ * SPDX-License-Identifier: BSD-3-Clause
7478
+ *
7479
+ * Redistribution and use in source and binary forms, with or without
7480
+ * modification, are permitted provided that the following conditions are met:
7481
+ *
7482
+ * 1. Redistributions of source code must retain the above copyright notice, this
7483
+ * list of conditions and the following disclaimer.
7484
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
7485
+ * this list of conditions and the following disclaimer in the
7486
+ * documentation and/or other materials provided with the distribution.
7487
+ * 3. Neither the name of the copyright holder nor the names of its contributors
7488
+ * may be used to endorse or promote products derived from this software without
7489
+ * specific prior written permission.
7490
+ *
7491
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7492
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
7493
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
7494
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7495
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7496
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
7497
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
7498
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
7499
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
7500
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7501
+ *)
7502
+ */