@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 +3213 -299
- package/build/meta.json +1 -1
- package/package.json +4 -2
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 (
|
|
149
|
-
throw new McpError(`network error contacting ${this.mcpUrl}: ${stringifyErr(
|
|
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(
|
|
211
|
-
return
|
|
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
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
"Vetted lessons and conventions for this stack, pulled from
|
|
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
|
-
|
|
263
|
+
lines2.push("");
|
|
264
264
|
const stackLabel = meta.stack.length > 0 ? meta.stack.join(", ") : "(none)";
|
|
265
|
-
|
|
266
|
-
|
|
265
|
+
lines2.push(`**Stack:** ${stackLabel} \xB7 **Lessons:** ${lessons.length} \xB7 **Conventions:** ${conventions.length}`);
|
|
266
|
+
lines2.push("");
|
|
267
267
|
if (conventions.length > 0) {
|
|
268
|
-
|
|
269
|
-
|
|
268
|
+
lines2.push("## Always-on conventions");
|
|
269
|
+
lines2.push("");
|
|
270
270
|
for (const c of conventions) {
|
|
271
|
-
|
|
271
|
+
lines2.push(`- **${c.title}** \`${c.id}\``);
|
|
272
272
|
}
|
|
273
|
-
|
|
273
|
+
lines2.push("");
|
|
274
274
|
}
|
|
275
275
|
if (lessons.length === 0) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
return
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
|
|
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
|
-
|
|
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
|
-
|
|
291
|
-
|
|
290
|
+
lines2.push(meta2.join(" \xB7 "));
|
|
291
|
+
lines2.push("");
|
|
292
292
|
if (l.summary) {
|
|
293
|
-
|
|
294
|
-
|
|
293
|
+
lines2.push(`> ${l.summary}`);
|
|
294
|
+
lines2.push("");
|
|
295
295
|
}
|
|
296
296
|
if (l.body && l.body.trim().length > 0) {
|
|
297
|
-
|
|
298
|
-
|
|
297
|
+
lines2.push(l.body.trim());
|
|
298
|
+
lines2.push("");
|
|
299
299
|
}
|
|
300
|
-
|
|
301
|
-
|
|
300
|
+
lines2.push("---");
|
|
301
|
+
lines2.push("");
|
|
302
302
|
}
|
|
303
|
-
return
|
|
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 (
|
|
387
|
-
warn(`conventions unavailable (continuing with lessons only): ${msg(
|
|
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 (
|
|
397
|
-
const reason =
|
|
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(
|
|
429
|
-
return
|
|
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
|
|
564
|
-
if (!
|
|
563
|
+
const out2 = gh(["pr", "checks", String(prNumber), "--json", "bucket"]);
|
|
564
|
+
if (!out2) return "unknown";
|
|
565
565
|
try {
|
|
566
|
-
const rows = JSON.parse(
|
|
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
|
|
578
|
-
if (
|
|
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(
|
|
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 (
|
|
689
|
-
warn2(`network error posting to ${opts.reportUrl}: ${msg2(
|
|
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 (
|
|
708
|
-
const reason =
|
|
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(
|
|
714
|
-
return
|
|
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 (
|
|
811
|
-
warn3(`network error posting to ${opts.resultUrl}: ${msg3(
|
|
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 (
|
|
830
|
-
const reason =
|
|
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(
|
|
836
|
-
return
|
|
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 (
|
|
906
|
-
warn4(`peer check unavailable: ${msg4(
|
|
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 (
|
|
918
|
-
warn4(`git lessons unavailable: ${msg4(
|
|
917
|
+
} catch (err4) {
|
|
918
|
+
warn4(`git lessons unavailable: ${msg4(err4)}`);
|
|
919
919
|
}
|
|
920
|
-
} catch (
|
|
921
|
-
warn4(`maind enrichment skipped (${msg4(
|
|
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(
|
|
1011
|
-
return
|
|
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
|
|
1020
|
-
import { existsSync as
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
1601
|
+
out2.push({ path, language });
|
|
1602
1602
|
}
|
|
1603
|
-
return
|
|
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
|
|
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
|
|
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
|
|
1990
|
-
const head = parseHistoryRecord(
|
|
1994
|
+
const lines2 = record.split("\n");
|
|
1995
|
+
const head = parseHistoryRecord(lines2[0] ?? "");
|
|
1991
1996
|
if (!head)
|
|
1992
1997
|
continue;
|
|
1993
|
-
const filesTouched =
|
|
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
|
|
2125
|
+
const out2 = [];
|
|
2030
2126
|
if (!facts.isRepo)
|
|
2031
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
2303
|
+
const out2 = [];
|
|
2193
2304
|
let cur = null;
|
|
2194
2305
|
const flush = () => {
|
|
2195
2306
|
if (cur?.path)
|
|
2196
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
3122
|
+
out2.push({ ...toHit(n), score: h.score });
|
|
2698
3123
|
}
|
|
2699
|
-
return
|
|
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
|
|
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
|
-
|
|
3138
|
+
out2.push({ ...toHit(n), score: s.score });
|
|
2714
3139
|
}
|
|
2715
|
-
return
|
|
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(
|
|
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(
|
|
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
|
-
|
|
2973
|
-
this.db
|
|
2974
|
-
this.
|
|
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
|
|
3981
|
+
const out2 = [];
|
|
3448
3982
|
for (let i = 0; i < items.length; i += size)
|
|
3449
|
-
|
|
3450
|
-
return
|
|
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 ??
|
|
3466
|
-
mkdirSync3(
|
|
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 ??
|
|
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
|
|
3521
|
-
return
|
|
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(
|
|
3561
|
-
const okFile =
|
|
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 =
|
|
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
|
|
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/
|
|
3769
|
-
import { execFileSync as
|
|
3770
|
-
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
3771
|
-
import {
|
|
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
|
-
//
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
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
|
|
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
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
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
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
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
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
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
|
|
3871
|
-
|
|
3872
|
-
|
|
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
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
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
|
-
|
|
5970
|
+
lines2.push("");
|
|
3882
5971
|
if (verdict?.ok === true && verdict.verdict) {
|
|
3883
|
-
|
|
5972
|
+
lines2.push(verdictLabel(verdict));
|
|
3884
5973
|
const attest = attestationLine(verdict);
|
|
3885
5974
|
if (attest) {
|
|
3886
|
-
|
|
3887
|
-
|
|
5975
|
+
lines2.push("");
|
|
5976
|
+
lines2.push(attest);
|
|
3888
5977
|
}
|
|
3889
5978
|
if (verdict.trust_note) {
|
|
3890
|
-
|
|
3891
|
-
|
|
5979
|
+
lines2.push("");
|
|
5980
|
+
lines2.push(`_${verdict.trust_note}_`);
|
|
3892
5981
|
}
|
|
3893
|
-
|
|
5982
|
+
lines2.push("");
|
|
3894
5983
|
}
|
|
3895
5984
|
if (findings.length > 0) {
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
for (const f of findings)
|
|
3899
|
-
|
|
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
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
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
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
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
|
-
|
|
3913
|
-
for (const flag2 of riskFlags)
|
|
3914
|
-
|
|
6001
|
+
lines2.push("");
|
|
6002
|
+
for (const flag2 of riskFlags) lines2.push(`- \`${flag2}\``);
|
|
6003
|
+
lines2.push("");
|
|
3915
6004
|
}
|
|
3916
6005
|
if (hints.length > 0) {
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
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
|
-
|
|
6014
|
+
lines2.push(`- **${h.title}** (${parts.join(" \xB7 ")})`);
|
|
3926
6015
|
}
|
|
3927
|
-
|
|
6016
|
+
lines2.push("");
|
|
3928
6017
|
}
|
|
3929
6018
|
const rc = review?.regression_context;
|
|
3930
6019
|
if (rc && (rc.hot_files ?? 0) > 0) {
|
|
3931
|
-
|
|
3932
|
-
|
|
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
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
6026
|
+
lines2.push("## Coverage");
|
|
6027
|
+
lines2.push("");
|
|
6028
|
+
lines2.push(`> ${review.coverage_note}`);
|
|
6029
|
+
lines2.push("");
|
|
3941
6030
|
}
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
return
|
|
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
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
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
|
-
|
|
6046
|
+
lines2.push(verdictLabel(verdict));
|
|
3958
6047
|
const attest = attestationLine(verdict);
|
|
3959
|
-
if (attest)
|
|
3960
|
-
|
|
6048
|
+
if (attest) lines2.push(attest);
|
|
6049
|
+
lines2.push("");
|
|
3961
6050
|
}
|
|
3962
6051
|
if (findings.length === 0) {
|
|
3963
|
-
|
|
6052
|
+
lines2.push(
|
|
3964
6053
|
`No convention findings for this change set (${meta.symbolCount} changed symbol(s) reviewed ${baseLabel(meta)}).`
|
|
3965
6054
|
);
|
|
3966
|
-
|
|
6055
|
+
lines2.push("");
|
|
3967
6056
|
} else {
|
|
3968
6057
|
const shown = findings.slice(0, COMMENT_FINDINGS_CAP);
|
|
3969
|
-
for (const f of shown)
|
|
6058
|
+
for (const f of shown) lines2.push(findingLine(f));
|
|
3970
6059
|
if (findings.length > shown.length) {
|
|
3971
|
-
|
|
3972
|
-
|
|
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
|
-
|
|
6065
|
+
lines2.push("");
|
|
3977
6066
|
}
|
|
3978
6067
|
if (riskFlags.length > 0) {
|
|
3979
|
-
|
|
6068
|
+
lines2.push(
|
|
3980
6069
|
`**Risk flags:** ${riskFlags.map((f) => `\`${f}\``).join(" \xB7 ")} _(heuristics, never blocking)_`
|
|
3981
6070
|
);
|
|
3982
|
-
|
|
6071
|
+
lines2.push("");
|
|
3983
6072
|
}
|
|
3984
6073
|
if (hints.length > 0) {
|
|
3985
|
-
|
|
3986
|
-
|
|
6074
|
+
lines2.push("**Related lessons:** " + hints.map((h) => `\`${h.id}\``).join(" \xB7 "));
|
|
6075
|
+
lines2.push("");
|
|
3987
6076
|
}
|
|
3988
6077
|
if (review?.coverage_note) {
|
|
3989
|
-
|
|
3990
|
-
|
|
6078
|
+
lines2.push(`> ${review.coverage_note}`);
|
|
6079
|
+
lines2.push("");
|
|
3991
6080
|
}
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
return
|
|
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 =
|
|
4065
|
-
if (dir && dir !== ".")
|
|
4066
|
-
|
|
6153
|
+
const dir = dirname5(path);
|
|
6154
|
+
if (dir && dir !== ".") mkdirSync5(dir, { recursive: true });
|
|
6155
|
+
writeFileSync5(path, content, "utf8");
|
|
4067
6156
|
}
|
|
4068
|
-
function manifestPathFor(
|
|
4069
|
-
return
|
|
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
|
|
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: ${
|
|
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 (
|
|
4262
|
-
if (opts.strict) return failOpen(`review_verdict failed: ${
|
|
4263
|
-
warn5(`gate unavailable (continuing advisory): ${
|
|
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 (
|
|
4285
|
-
if (
|
|
4286
|
-
return failOpen(
|
|
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
|
|
4310
|
-
return
|
|
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
|
|
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
|
|
6926
|
+
function err3(line) {
|
|
4322
6927
|
process.stderr.write(`maind: ${line}
|
|
4323
6928
|
`);
|
|
4324
6929
|
}
|
|
4325
6930
|
function repoRoot() {
|
|
4326
6931
|
try {
|
|
4327
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
6961
|
+
err3(e instanceof Error ? e.message : String(e));
|
|
4357
6962
|
return null;
|
|
4358
6963
|
}
|
|
4359
6964
|
}
|
|
4360
|
-
function
|
|
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
|
-
|
|
6989
|
+
err3("codebase cloud-sync is not enabled \u2014 run `maind sync enable` first.");
|
|
4385
6990
|
return 1;
|
|
4386
6991
|
}
|
|
4387
|
-
|
|
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
|
-
|
|
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
|
|
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((
|
|
4585
|
-
process.stderr.write(`maind: fatal: ${
|
|
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
|
+
*/
|