@seanyao/roll 4.719.1 → 4.719.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/roll.mjs +393 -186
- package/package.json +1 -1
package/dist/roll.mjs
CHANGED
|
@@ -7285,8 +7285,8 @@ function writeSyncBlock(original, block) {
|
|
|
7285
7285
|
}
|
|
7286
7286
|
}
|
|
7287
7287
|
if (start === -1) {
|
|
7288
|
-
const
|
|
7289
|
-
return `${text2}${
|
|
7288
|
+
const sep9 = text2.endsWith("\n\n") || text2 === "" ? "" : text2.endsWith("\n") ? "\n" : "\n\n";
|
|
7289
|
+
return `${text2}${sep9}${block}
|
|
7290
7290
|
`;
|
|
7291
7291
|
}
|
|
7292
7292
|
let end = start + 1;
|
|
@@ -16195,7 +16195,7 @@ function parseFlowMap2(body) {
|
|
|
16195
16195
|
}
|
|
16196
16196
|
return out3;
|
|
16197
16197
|
}
|
|
16198
|
-
function splitTopLevel(s,
|
|
16198
|
+
function splitTopLevel(s, sep9) {
|
|
16199
16199
|
const parts = [];
|
|
16200
16200
|
let depth = 0;
|
|
16201
16201
|
let cur = "";
|
|
@@ -16204,7 +16204,7 @@ function splitTopLevel(s, sep8) {
|
|
|
16204
16204
|
depth++;
|
|
16205
16205
|
else if (ch === "}")
|
|
16206
16206
|
depth = Math.max(0, depth - 1);
|
|
16207
|
-
if (ch ===
|
|
16207
|
+
if (ch === sep9 && depth === 0) {
|
|
16208
16208
|
parts.push(cur);
|
|
16209
16209
|
cur = "";
|
|
16210
16210
|
} else {
|
|
@@ -31174,15 +31174,15 @@ var init_mcp = __esm({
|
|
|
31174
31174
|
}
|
|
31175
31175
|
}
|
|
31176
31176
|
tryParseMessage() {
|
|
31177
|
-
const
|
|
31178
|
-
if (
|
|
31177
|
+
const sep9 = this.buffer.indexOf("\r\n\r\n");
|
|
31178
|
+
if (sep9 < 0)
|
|
31179
31179
|
return void 0;
|
|
31180
|
-
const header = this.buffer.slice(0,
|
|
31180
|
+
const header = this.buffer.slice(0, sep9).toString("utf8");
|
|
31181
31181
|
const length = /^Content-Length:\s*(\d+)$/im.exec(header)?.[1];
|
|
31182
31182
|
if (length === void 0)
|
|
31183
31183
|
return void 0;
|
|
31184
31184
|
const bodyLength = Number.parseInt(length, 10);
|
|
31185
|
-
const start =
|
|
31185
|
+
const start = sep9 + 4;
|
|
31186
31186
|
if (this.buffer.length < start + bodyLength)
|
|
31187
31187
|
return void 0;
|
|
31188
31188
|
const body = this.buffer.slice(start, start + bodyLength);
|
|
@@ -80311,11 +80311,11 @@ ${lanes.join("\n")}
|
|
|
80311
80311
|
if (i < rootLength) {
|
|
80312
80312
|
return void 0;
|
|
80313
80313
|
}
|
|
80314
|
-
const
|
|
80315
|
-
if (
|
|
80314
|
+
const sep9 = directory.lastIndexOf(directorySeparator, i - 1);
|
|
80315
|
+
if (sep9 === -1) {
|
|
80316
80316
|
return void 0;
|
|
80317
80317
|
}
|
|
80318
|
-
return directory.substr(0, Math.max(
|
|
80318
|
+
return directory.substr(0, Math.max(sep9, rootLength));
|
|
80319
80319
|
}
|
|
80320
80320
|
}
|
|
80321
80321
|
}
|
|
@@ -244439,7 +244439,7 @@ __export(showcase_exports, {
|
|
|
244439
244439
|
showcaseCommand: () => showcaseCommand
|
|
244440
244440
|
});
|
|
244441
244441
|
import { spawnSync as spawnSync17 } from "node:child_process";
|
|
244442
|
-
import { cpSync as cpSync2, existsSync as
|
|
244442
|
+
import { cpSync as cpSync2, existsSync as existsSync141, mkdirSync as mkdirSync78, mkdtempSync as mkdtempSync8, readdirSync as readdirSync54, readFileSync as readFileSync141, rmSync as rmSync27, statSync as statSync40, writeFileSync as writeFileSync77 } from "node:fs";
|
|
244443
244443
|
import { tmpdir as tmpdir13 } from "node:os";
|
|
244444
244444
|
import { dirname as dirname77, join as join164 } from "node:path";
|
|
244445
244445
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
@@ -244482,7 +244482,7 @@ function parseArgs3(args) {
|
|
|
244482
244482
|
function packageRoot() {
|
|
244483
244483
|
let dir = dirname77(fileURLToPath3(import.meta.url));
|
|
244484
244484
|
for (let i = 0; i < 12; i++) {
|
|
244485
|
-
if (
|
|
244485
|
+
if (existsSync141(join164(dir, "conventions")))
|
|
244486
244486
|
return dir;
|
|
244487
244487
|
const parent = dirname77(dir);
|
|
244488
244488
|
if (parent === dir)
|
|
@@ -244493,7 +244493,7 @@ function packageRoot() {
|
|
|
244493
244493
|
}
|
|
244494
244494
|
function rollBin3() {
|
|
244495
244495
|
const devPath = join164(packageRoot(), "packages", "cli", "bin", "roll.js");
|
|
244496
|
-
if (
|
|
244496
|
+
if (existsSync141(devPath))
|
|
244497
244497
|
return devPath;
|
|
244498
244498
|
return "roll";
|
|
244499
244499
|
}
|
|
@@ -244520,7 +244520,7 @@ function runRoll(sandbox, rollHome4, args, opts = {}) {
|
|
|
244520
244520
|
}
|
|
244521
244521
|
function fileNonEmpty3(p) {
|
|
244522
244522
|
try {
|
|
244523
|
-
return
|
|
244523
|
+
return existsSync141(p) && statSync40(p).size > 0;
|
|
244524
244524
|
} catch {
|
|
244525
244525
|
return false;
|
|
244526
244526
|
}
|
|
@@ -244532,7 +244532,7 @@ function makeSandbox(sourceProject) {
|
|
|
244532
244532
|
mkdirSync78(sandbox, { recursive: true });
|
|
244533
244533
|
mkdirSync78(rollHome4, { recursive: true });
|
|
244534
244534
|
const srcRoll = join164(sourceProject, ".roll");
|
|
244535
|
-
if (
|
|
244535
|
+
if (existsSync141(srcRoll)) {
|
|
244536
244536
|
cpSync2(srcRoll, join164(sandbox, ".roll"), { recursive: true });
|
|
244537
244537
|
} else {
|
|
244538
244538
|
mkdirSync78(join164(sandbox, ".roll", "features"), { recursive: true });
|
|
@@ -244543,11 +244543,11 @@ function findCardSpec2(sandbox, card) {
|
|
|
244543
244543
|
const featuresDir = join164(sandbox, ".roll", "features");
|
|
244544
244544
|
const candidates = [];
|
|
244545
244545
|
const walk2 = (dir, depth) => {
|
|
244546
|
-
if (depth > 3 || !
|
|
244546
|
+
if (depth > 3 || !existsSync141(dir))
|
|
244547
244547
|
return;
|
|
244548
244548
|
let entries = [];
|
|
244549
244549
|
try {
|
|
244550
|
-
entries =
|
|
244550
|
+
entries = readdirSync54(dir);
|
|
244551
244551
|
} catch {
|
|
244552
244552
|
return;
|
|
244553
244553
|
}
|
|
@@ -244560,7 +244560,7 @@ function findCardSpec2(sandbox, card) {
|
|
|
244560
244560
|
continue;
|
|
244561
244561
|
}
|
|
244562
244562
|
if (isDir4) {
|
|
244563
|
-
if (name === card &&
|
|
244563
|
+
if (name === card && existsSync141(join164(full, "spec.md")))
|
|
244564
244564
|
candidates.push(join164(full, "spec.md"));
|
|
244565
244565
|
walk2(full, depth + 1);
|
|
244566
244566
|
}
|
|
@@ -244574,7 +244574,7 @@ function resetSandbox(sandbox, card) {
|
|
|
244574
244574
|
let reset2 = false;
|
|
244575
244575
|
let ok12 = false;
|
|
244576
244576
|
const backlogPath = join164(sandbox, ".roll", "backlog.md");
|
|
244577
|
-
if (
|
|
244577
|
+
if (existsSync141(backlogPath)) {
|
|
244578
244578
|
const before = readFileSync141(backlogPath, "utf8");
|
|
244579
244579
|
const cardRow = before.split("\n").find((line) => line.startsWith("|") && line.includes(card));
|
|
244580
244580
|
const hadStatusToken = cardRow !== void 0 && statusMarkerRe(false).test(cardRow);
|
|
@@ -244603,8 +244603,8 @@ function resetSandbox(sandbox, card) {
|
|
|
244603
244603
|
notes.push("backlog: .roll/backlog.md absent");
|
|
244604
244604
|
}
|
|
244605
244605
|
const pulseCmd = join164(sandbox, "packages", "cli", "src", "commands", "pulse.ts");
|
|
244606
|
-
if (
|
|
244607
|
-
|
|
244606
|
+
if (existsSync141(pulseCmd)) {
|
|
244607
|
+
rmSync27(pulseCmd, { force: true });
|
|
244608
244608
|
notes.push("removed prior pulse.ts surface");
|
|
244609
244609
|
}
|
|
244610
244610
|
return { ok: ok12, reset: reset2, notes };
|
|
@@ -244636,7 +244636,7 @@ async function captureScreenshots(sandbox, card) {
|
|
|
244636
244636
|
const web = await infra.captureScreenshot({
|
|
244637
244637
|
kind: "web",
|
|
244638
244638
|
out: webOut,
|
|
244639
|
-
url:
|
|
244639
|
+
url: existsSync141(nowPage) ? `file://${nowPage}#now` : "about:blank"
|
|
244640
244640
|
});
|
|
244641
244641
|
shots.push({
|
|
244642
244642
|
surface: "web",
|
|
@@ -244648,7 +244648,7 @@ async function captureScreenshots(sandbox, card) {
|
|
|
244648
244648
|
}
|
|
244649
244649
|
function readBacklogStatus(sandbox, card) {
|
|
244650
244650
|
const backlogPath = join164(sandbox, ".roll", "backlog.md");
|
|
244651
|
-
if (!
|
|
244651
|
+
if (!existsSync141(backlogPath))
|
|
244652
244652
|
return void 0;
|
|
244653
244653
|
for (const line of readFileSync141(backlogPath, "utf8").split("\n")) {
|
|
244654
244654
|
if (line.startsWith("|") && line.includes(card)) {
|
|
@@ -244661,7 +244661,7 @@ function readBacklogStatus(sandbox, card) {
|
|
|
244661
244661
|
}
|
|
244662
244662
|
function readTruthLadder(sandbox, card) {
|
|
244663
244663
|
const truthPath = join164(sandbox, ".roll", "features", "truth.json");
|
|
244664
|
-
if (!
|
|
244664
|
+
if (!existsSync141(truthPath))
|
|
244665
244665
|
return void 0;
|
|
244666
244666
|
try {
|
|
244667
244667
|
const snap = JSON.parse(readFileSync141(truthPath, "utf8"));
|
|
@@ -244673,7 +244673,7 @@ function readTruthLadder(sandbox, card) {
|
|
|
244673
244673
|
}
|
|
244674
244674
|
function readTcrCommits(sandbox) {
|
|
244675
244675
|
const runsPath3 = join164(sandbox, ".roll", "loop", "runs.jsonl");
|
|
244676
|
-
if (!
|
|
244676
|
+
if (!existsSync141(runsPath3))
|
|
244677
244677
|
return [];
|
|
244678
244678
|
const out3 = [];
|
|
244679
244679
|
try {
|
|
@@ -244816,7 +244816,7 @@ ROLL_HOME: ${rollHome4}
|
|
|
244816
244816
|
return 1;
|
|
244817
244817
|
} finally {
|
|
244818
244818
|
if (!keepSandbox) {
|
|
244819
|
-
|
|
244819
|
+
rmSync27(dirname77(sandbox), { recursive: true, force: true });
|
|
244820
244820
|
}
|
|
244821
244821
|
}
|
|
244822
244822
|
}
|
|
@@ -259883,9 +259883,9 @@ function writeFeatureStub(issue, featuresDir, epic = "backlog-lifecycle") {
|
|
|
259883
259883
|
if (existsSync47(path)) {
|
|
259884
259884
|
const existing = readFileSync47(path, "utf8");
|
|
259885
259885
|
const block = ac ? ac + "\n" : "";
|
|
259886
|
-
const
|
|
259886
|
+
const sep9 = existing.endsWith("\n") || existing === "" ? "" : "\n";
|
|
259887
259887
|
if (block)
|
|
259888
|
-
appendFileSync5(path,
|
|
259888
|
+
appendFileSync5(path, sep9 + block);
|
|
259889
259889
|
return path;
|
|
259890
259890
|
}
|
|
259891
259891
|
writeFileSync26(path, featureStubContent(issue));
|
|
@@ -262225,8 +262225,8 @@ function writeSet(runtimeDir11, set) {
|
|
|
262225
262225
|
writeFileSync30(tmp, JSON.stringify([...set].sort(), null, 2), "utf8");
|
|
262226
262226
|
writeFileSync30(path, readFileSync53(tmp, "utf8"), "utf8");
|
|
262227
262227
|
try {
|
|
262228
|
-
const { rmSync:
|
|
262229
|
-
|
|
262228
|
+
const { rmSync: rmSync31 } = __require("node:fs");
|
|
262229
|
+
rmSync31(tmp, { force: true });
|
|
262230
262230
|
} catch {
|
|
262231
262231
|
}
|
|
262232
262232
|
}
|
|
@@ -271420,8 +271420,8 @@ function topBar(input) {
|
|
|
271420
271420
|
const switcher = multi ? `<div class="proj-switch" style="position:relative;flex:none;"><button type="button" id="proj-switch-btn" class="proj-switch-btn" aria-haspopup="menu" aria-expanded="false" style="display:flex;align-items:center;gap:9px;cursor:pointer;background:transparent;border:0;padding:5px 7px;border-radius:8px;">` + dot + projName + `<span class="proj-caret" style="${MONO}font-size:9px;color:#8f98ad;flex:none;transition:transform .18s;">\u25BE</span></button><div id="proj-menu" class="proj-menu" role="menu" aria-label="switch project \xB7 \u5207\u6362\u9879\u76EE" hidden style="position:absolute;top:42px;left:0;min-width:240px;background:rgba(27,34,56,.99);border:1px solid #313a55;border-radius:10px;padding:6px;box-shadow:0 10px 30px rgba(7,10,20,.5);z-index:40;"><div style="${MONO}font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:#6f7892;padding:6px 13px 8px;">${esc4(input.brand.name)} \xB7 ${bi("this machine", "\u8FD9\u53F0\u673A\u5668")}</div>` + menuItems + `</div></div>` : `<a href="${homeHref}" class="proj-switch-btn" style="display:flex;align-items:center;gap:9px;cursor:pointer;flex:none;text-decoration:none;padding:5px 7px;">` + dot + projName + `</a>`;
|
|
271421
271421
|
const crumbsNav = `<nav style="flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:9px;${MONO}font-size:12px;color:#8f98ad;overflow:hidden;" aria-label="machine layer \xB7 \u673A\u5668\u5C42"><span style="${MONO}font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:#5b6480;flex:none;">${bi("Machine", "\u673A\u5668")}</span>` + MACHINE_NAV.map((m7, i) => {
|
|
271422
271422
|
const active = input.machinePage === m7.key;
|
|
271423
|
-
const
|
|
271424
|
-
return
|
|
271423
|
+
const sep9 = i > 0 ? `<span style="color:#3a4360;flex:none;">\xB7</span>` : "";
|
|
271424
|
+
return sep9 + `<a class="mach-link${active ? " on" : ""}" data-machine="${m7.key}" href="${esc4(m7.href)}"${active ? ' aria-current="page"' : ""} style="text-decoration:none;color:${active ? "#fff" : "#8f98ad"};font-weight:${active ? "600" : "400"};white-space:nowrap;flex:none;">${bi(m7.en, m7.zh)}</a>`;
|
|
271425
271425
|
}).join("") + `</nav>`;
|
|
271426
271426
|
const releaseTag = input.snapshot.release?.latestTag;
|
|
271427
271427
|
const releaseBadge = releaseTag !== void 0 && releaseTag !== "" ? `<span style="${MONO}font-size:11px;color:#6f7892;letter-spacing:.02em;white-space:nowrap;">${bi("release", "\u53D1\u7248")} <b style="color:#cfd5e3;font-weight:600;">${esc4(releaseTag)}</b></span>` : "";
|
|
@@ -277700,11 +277700,11 @@ function printMergeSummary(summary) {
|
|
|
277700
277700
|
function summaryAction(summary, file) {
|
|
277701
277701
|
for (let index = summary.length - 1; index >= 0; index -= 1) {
|
|
277702
277702
|
const entry = summary[index] ?? "";
|
|
277703
|
-
const
|
|
277704
|
-
if (
|
|
277703
|
+
const sep9 = entry.indexOf("|");
|
|
277704
|
+
if (sep9 < 0)
|
|
277705
277705
|
continue;
|
|
277706
|
-
if (entry.slice(
|
|
277707
|
-
return entry.slice(0,
|
|
277706
|
+
if (entry.slice(sep9 + 1) === file)
|
|
277707
|
+
return entry.slice(0, sep9);
|
|
277708
277708
|
}
|
|
277709
277709
|
return null;
|
|
277710
277710
|
}
|
|
@@ -278249,10 +278249,10 @@ function emitInitUi(projectDir, hasAgents, syncStatus, summary, shouldNudge, mod
|
|
|
278249
278249
|
lines3.push(" " + c(iconColor, icon) + " " + c(iconColor, fLabel, { bold: true }));
|
|
278250
278250
|
const nudgeMsg = shouldNudge ? renderDesignNudge(msgLang6())[0] ?? "" : "";
|
|
278251
278251
|
const nudgePair = shouldNudge && nudgeMsg !== "" ? (() => {
|
|
278252
|
-
const
|
|
278253
|
-
if (
|
|
278252
|
+
const sep9 = nudgeMsg.indexOf(" \u2014 ");
|
|
278253
|
+
if (sep9 < 0)
|
|
278254
278254
|
return [nudgeMsg, ""];
|
|
278255
|
-
return [nudgeMsg.slice(0,
|
|
278255
|
+
return [nudgeMsg.slice(0, sep9), nudgeMsg.slice(sep9 + 3)];
|
|
278256
278256
|
})() : void 0;
|
|
278257
278257
|
const nextItems = nextItemsOverride ?? (hasAgents ? [
|
|
278258
278258
|
...nudgePair ? [nudgePair] : [],
|
|
@@ -281224,7 +281224,7 @@ async function loopExhaustionSplitCommand(argv, deps = realExhaustionSplitDeps()
|
|
|
281224
281224
|
init_dist2();
|
|
281225
281225
|
init_dist();
|
|
281226
281226
|
init_dist3();
|
|
281227
|
-
import { appendFileSync as appendFileSync21, existsSync as
|
|
281227
|
+
import { appendFileSync as appendFileSync21, existsSync as existsSync135, mkdirSync as mkdirSync74, readdirSync as readdirSync49, readFileSync as readFileSync135, writeFileSync as writeFileSync72 } from "node:fs";
|
|
281228
281228
|
import { dirname as dirname74, join as join158 } from "node:path";
|
|
281229
281229
|
|
|
281230
281230
|
// packages/cli/dist/runner/executor.js
|
|
@@ -288367,7 +288367,7 @@ function applyCorrectionCircuitBreaker(projectPath3, slug3, eventsPath4, alertsP
|
|
|
288367
288367
|
init_dist2();
|
|
288368
288368
|
init_dist3();
|
|
288369
288369
|
import { execFileSync as execFileSync31 } from "node:child_process";
|
|
288370
|
-
import { readFileSync as readFileSync133 } from "node:fs";
|
|
288370
|
+
import { readFileSync as readFileSync133, readdirSync as readdirSync48, realpathSync as realpathSync20 } from "node:fs";
|
|
288371
288371
|
import { homedir as homedir33 } from "node:os";
|
|
288372
288372
|
import { basename as basename22, dirname as dirname72, join as join156, relative as relative13, resolve as resolve13 } from "node:path";
|
|
288373
288373
|
function git3(args, cwd) {
|
|
@@ -288437,6 +288437,60 @@ function extractCycleId(dirName) {
|
|
|
288437
288437
|
const m7 = /^(cycle-\d{8}-\d{6}-\d+)$/.exec(dirName);
|
|
288438
288438
|
return m7 ? m7[1] : void 0;
|
|
288439
288439
|
}
|
|
288440
|
+
var ORPHAN_DELIVERED_OUTCOMES = /* @__PURE__ */ new Set(["delivered", "merged"]);
|
|
288441
|
+
function realpathSafe2(p) {
|
|
288442
|
+
try {
|
|
288443
|
+
return realpathSync20(p);
|
|
288444
|
+
} catch {
|
|
288445
|
+
return p;
|
|
288446
|
+
}
|
|
288447
|
+
}
|
|
288448
|
+
function defaultReadDirNames(dir) {
|
|
288449
|
+
try {
|
|
288450
|
+
return readdirSync48(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
288451
|
+
} catch {
|
|
288452
|
+
return [];
|
|
288453
|
+
}
|
|
288454
|
+
}
|
|
288455
|
+
function scanOrphanLoopWorktrees(repoRoot3, registeredPaths, cycles, deps) {
|
|
288456
|
+
const worktreesDir = join156(repoRoot3, ".roll", "loop", "worktrees");
|
|
288457
|
+
const names = deps.readDir ? deps.readDir(worktreesDir) : defaultReadDirNames(worktreesDir);
|
|
288458
|
+
const out3 = [];
|
|
288459
|
+
for (const name of [...names].sort()) {
|
|
288460
|
+
const absPath = resolve13(join156(worktreesDir, name));
|
|
288461
|
+
if (registeredPaths.has(realpathSafe2(absPath)))
|
|
288462
|
+
continue;
|
|
288463
|
+
const cycleId = extractCycleId(name);
|
|
288464
|
+
const ce = cycleId ? cycles.get(cycleId) : void 0;
|
|
288465
|
+
const outcome = ce?.outcome;
|
|
288466
|
+
const active = isActiveCycle(cycleId, repoRoot3, deps);
|
|
288467
|
+
const rec = {
|
|
288468
|
+
path: absPath,
|
|
288469
|
+
owner: "loop",
|
|
288470
|
+
...cycleId ? { cycleId } : {},
|
|
288471
|
+
...ce?.storyId ? { storyId: ce.storyId } : {},
|
|
288472
|
+
...outcome ? { outcome } : {},
|
|
288473
|
+
dirtyTracked: "unknown",
|
|
288474
|
+
// no git metadata for a deregistered dir
|
|
288475
|
+
dirtyUntracked: "unknown",
|
|
288476
|
+
ahead: null,
|
|
288477
|
+
mergeEvidence: { kind: "none" },
|
|
288478
|
+
active,
|
|
288479
|
+
disposition: "preserved_orphan",
|
|
288480
|
+
reason: ""
|
|
288481
|
+
};
|
|
288482
|
+
if (active) {
|
|
288483
|
+
rec.reason = "orphan loop dir with an active cycle lock; never reclaimed";
|
|
288484
|
+
} else if (outcome && ORPHAN_DELIVERED_OUTCOMES.has(outcome)) {
|
|
288485
|
+
rec.disposition = "orphan_reclaimable";
|
|
288486
|
+
rec.reason = `orphan loop dir (deregistered from git); owning cycle outcome '${outcome}' is delivered \u2014 bounded reclaim`;
|
|
288487
|
+
} else {
|
|
288488
|
+
rec.reason = `orphan loop dir (deregistered from git); delivery not provable (cycle outcome '${outcome ?? "unknown"}') \u2014 preserved, reclaim manually after review`;
|
|
288489
|
+
}
|
|
288490
|
+
out3.push(rec);
|
|
288491
|
+
}
|
|
288492
|
+
return out3;
|
|
288493
|
+
}
|
|
288440
288494
|
function detectDirty(wtPath, deps) {
|
|
288441
288495
|
try {
|
|
288442
288496
|
const g = deps.git ?? git3;
|
|
@@ -288637,6 +288691,10 @@ function auditWorktrees(deps) {
|
|
|
288637
288691
|
baseRec.reason = disp.reason;
|
|
288638
288692
|
records.push(baseRec);
|
|
288639
288693
|
}
|
|
288694
|
+
const registeredLoopPaths = new Set(records.map((r) => realpathSafe2(resolve13(r.path))));
|
|
288695
|
+
for (const orphan of scanOrphanLoopWorktrees(repoRoot3, registeredLoopPaths, cycles, deps)) {
|
|
288696
|
+
records.push(orphan);
|
|
288697
|
+
}
|
|
288640
288698
|
let ephemeralBranches = [];
|
|
288641
288699
|
try {
|
|
288642
288700
|
const g = deps.git ?? git3;
|
|
@@ -288695,7 +288753,9 @@ function renderHuman(output) {
|
|
|
288695
288753
|
"preserved_unpublished",
|
|
288696
288754
|
"preserved_dirty_no_tcr",
|
|
288697
288755
|
"preserved_needs_review",
|
|
288756
|
+
"preserved_orphan",
|
|
288698
288757
|
"disposable_candidate",
|
|
288758
|
+
"orphan_reclaimable",
|
|
288699
288759
|
"external_unmanaged"
|
|
288700
288760
|
];
|
|
288701
288761
|
for (const disp of order) {
|
|
@@ -288767,12 +288827,24 @@ function worktreeAuditCommand(args, deps) {
|
|
|
288767
288827
|
init_dist2();
|
|
288768
288828
|
import { execFileSync as execFileSync32 } from "node:child_process";
|
|
288769
288829
|
import { homedir as homedir34 } from "node:os";
|
|
288770
|
-
import { appendFileSync as appendFileSync20, mkdirSync as mkdirSync73 } from "node:fs";
|
|
288771
|
-
import { dirname as dirname73, join as join157, relative as relative14, resolve as resolve14 } from "node:path";
|
|
288772
|
-
var MERGED_KINDS = /* @__PURE__ */ new Set(["ancestor", "
|
|
288830
|
+
import { appendFileSync as appendFileSync20, existsSync as existsSync134, mkdirSync as mkdirSync73, rmSync as rmSync25 } from "node:fs";
|
|
288831
|
+
import { dirname as dirname73, join as join157, relative as relative14, resolve as resolve14, sep as sep8 } from "node:path";
|
|
288832
|
+
var MERGED_KINDS = /* @__PURE__ */ new Set(["ancestor", "patch_equivalent"]);
|
|
288773
288833
|
function isSafelyDisposable(rec) {
|
|
288774
288834
|
return rec.owner === "loop" && rec.active === false && rec.dirtyTracked === false && rec.disposition === "disposable_candidate" && MERGED_KINDS.has(rec.mergeEvidence.kind) && typeof rec.head === "string" && rec.head.length > 0;
|
|
288775
288835
|
}
|
|
288836
|
+
function isReclaimableOrphan(rec) {
|
|
288837
|
+
return rec.owner === "loop" && rec.active === false && rec.disposition === "orphan_reclaimable";
|
|
288838
|
+
}
|
|
288839
|
+
function isBoundedLoopWorktreeDir(repoRoot3, path) {
|
|
288840
|
+
const base = resolve14(join157(repoRoot3, ".roll", "loop", "worktrees"));
|
|
288841
|
+
const abs = resolve14(path);
|
|
288842
|
+
if (abs === base)
|
|
288843
|
+
return false;
|
|
288844
|
+
if (!abs.startsWith(base + sep8))
|
|
288845
|
+
return false;
|
|
288846
|
+
return dirname73(abs) === base;
|
|
288847
|
+
}
|
|
288776
288848
|
var PROTECTED_BRANCHES = /* @__PURE__ */ new Set(["main", "master", "HEAD"]);
|
|
288777
288849
|
function resolveStandaloneMergedBranches(audit, deps) {
|
|
288778
288850
|
const out3 = [];
|
|
@@ -288797,20 +288869,25 @@ function planWorktreeCleanup(audit, threshold, standaloneMergedBranches = []) {
|
|
|
288797
288869
|
const loopWorktrees = audit.records.filter((r) => r.owner === "loop");
|
|
288798
288870
|
const canaryTotal = audit.ephemeralBranches.length + loopWorktrees.length;
|
|
288799
288871
|
const excess = canaryTotal - threshold;
|
|
288800
|
-
const pool = audit.records.filter(isSafelyDisposable).sort((a, b) => a.path.localeCompare(b.path));
|
|
288872
|
+
const pool = audit.records.filter((r) => isSafelyDisposable(r) || isReclaimableOrphan(r)).sort((a, b) => a.path.localeCompare(b.path));
|
|
288801
288873
|
const branchPool = [...standaloneMergedBranches].sort((a, b) => a.branch.localeCompare(b.branch));
|
|
288802
288874
|
const excessN = excess > 0 ? excess : 0;
|
|
288803
288875
|
const chosen = pool.slice(0, Math.min(excessN, pool.length));
|
|
288804
288876
|
const remainingExcess = excessN - chosen.length;
|
|
288805
288877
|
const chosenBranches = branchPool.slice(0, Math.min(remainingExcess, branchPool.length));
|
|
288806
288878
|
const chosenPaths = new Set(chosen.map((r) => r.path));
|
|
288807
|
-
const candidates = chosen.map((r) =>
|
|
288808
|
-
|
|
288809
|
-
|
|
288810
|
-
|
|
288811
|
-
|
|
288812
|
-
|
|
288813
|
-
|
|
288879
|
+
const candidates = chosen.map((r) => {
|
|
288880
|
+
const orphan = isReclaimableOrphan(r);
|
|
288881
|
+
return {
|
|
288882
|
+
path: r.path,
|
|
288883
|
+
...r.cycleId ? { cycleId: r.cycleId } : {},
|
|
288884
|
+
...r.branch ? { branch: r.branch } : {},
|
|
288885
|
+
// An orphan has no registered HEAD; apply skips the head check for rm_dir.
|
|
288886
|
+
expectedHead: orphan ? "" : r.head,
|
|
288887
|
+
reason: orphan ? "orphan_reclaimable" : "disposable_candidate",
|
|
288888
|
+
reclaim: orphan ? "rm_dir" : "git_worktree"
|
|
288889
|
+
};
|
|
288890
|
+
});
|
|
288814
288891
|
const preserved = audit.records.filter((r) => !chosenPaths.has(r.path)).map((r) => ({ path: r.path, disposition: r.disposition, reason: r.reason }));
|
|
288815
288892
|
const countedWorktrees = loopWorktrees.map((r) => ({
|
|
288816
288893
|
path: r.path,
|
|
@@ -288841,13 +288918,47 @@ function defaultRemoveBranch(repositoryRoot, branch) {
|
|
|
288841
288918
|
return { ok: true, detail: "" };
|
|
288842
288919
|
}
|
|
288843
288920
|
function defaultRemoveWorktree(repositoryRoot, path) {
|
|
288921
|
+
let gitErr = "";
|
|
288844
288922
|
try {
|
|
288845
288923
|
execFileSync32("git", ["-C", repositoryRoot, "worktree", "remove", "--force", path], {
|
|
288846
288924
|
encoding: "utf8",
|
|
288847
288925
|
stdio: ["ignore", "pipe", "pipe"]
|
|
288848
288926
|
});
|
|
288849
288927
|
} catch (err16) {
|
|
288850
|
-
|
|
288928
|
+
gitErr = err16 instanceof Error ? err16.message : String(err16);
|
|
288929
|
+
}
|
|
288930
|
+
if (existsSync134(path)) {
|
|
288931
|
+
if (!isBoundedLoopWorktreeDir(repositoryRoot, path)) {
|
|
288932
|
+
return { ok: false, detail: gitErr || `refused: ${path} is outside .roll/loop/worktrees` };
|
|
288933
|
+
}
|
|
288934
|
+
try {
|
|
288935
|
+
rmSync25(path, { recursive: true, force: true });
|
|
288936
|
+
} catch (e) {
|
|
288937
|
+
return { ok: false, detail: gitErr || (e instanceof Error ? e.message : String(e)) };
|
|
288938
|
+
}
|
|
288939
|
+
} else if (gitErr) {
|
|
288940
|
+
return { ok: false, detail: gitErr };
|
|
288941
|
+
}
|
|
288942
|
+
try {
|
|
288943
|
+
execFileSync32("git", ["-C", repositoryRoot, "worktree", "prune", "--expire", "now"], {
|
|
288944
|
+
encoding: "utf8",
|
|
288945
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
288946
|
+
});
|
|
288947
|
+
} catch {
|
|
288948
|
+
}
|
|
288949
|
+
return { ok: true, detail: "" };
|
|
288950
|
+
}
|
|
288951
|
+
function defaultReclaimOrphanDir(repositoryRoot, path) {
|
|
288952
|
+
if (!isBoundedLoopWorktreeDir(repositoryRoot, path)) {
|
|
288953
|
+
return { ok: false, detail: `refused: ${path} is outside .roll/loop/worktrees` };
|
|
288954
|
+
}
|
|
288955
|
+
if (!existsSync134(path)) {
|
|
288956
|
+
return { ok: false, detail: "missing: orphan dir already gone" };
|
|
288957
|
+
}
|
|
288958
|
+
try {
|
|
288959
|
+
rmSync25(path, { recursive: true, force: true });
|
|
288960
|
+
} catch (e) {
|
|
288961
|
+
return { ok: false, detail: e instanceof Error ? e.message : String(e) };
|
|
288851
288962
|
}
|
|
288852
288963
|
try {
|
|
288853
288964
|
execFileSync32("git", ["-C", repositoryRoot, "worktree", "prune", "--expire", "now"], {
|
|
@@ -288862,6 +288973,7 @@ async function applyWorktreeCleanup(plan, options) {
|
|
|
288862
288973
|
const repositoryRoot = resolve14(options.repositoryRoot);
|
|
288863
288974
|
const auditFn = options.audit ?? (() => auditWorktrees({ repoRoot: repositoryRoot, home: homedir34() }));
|
|
288864
288975
|
const removeFn = options.removeWorktree ?? defaultRemoveWorktree;
|
|
288976
|
+
const reclaimOrphanFn = options.reclaimOrphanDir ?? defaultReclaimOrphanDir;
|
|
288865
288977
|
const removeBranchFn = options.removeBranch ?? defaultRemoveBranch;
|
|
288866
288978
|
const emit4 = options.emit ?? (() => {
|
|
288867
288979
|
});
|
|
@@ -288877,17 +288989,47 @@ async function applyWorktreeCleanup(plan, options) {
|
|
|
288877
288989
|
emit4({ type: "worktree_cleanup_refused", path: candidate.path, reason, ts: nowMs2() });
|
|
288878
288990
|
};
|
|
288879
288991
|
if (!rec) {
|
|
288880
|
-
refuse("missing: worktree no longer registered (already removed or pruned)");
|
|
288881
|
-
continue;
|
|
288882
|
-
}
|
|
288883
|
-
if (rec.head !== candidate.expectedHead) {
|
|
288884
|
-
refuse(`changed-head: expected ${candidate.expectedHead}, found ${rec.head ?? "none"}`);
|
|
288992
|
+
refuse(candidate.reclaim === "rm_dir" ? "missing: orphan dir no longer present (already reclaimed)" : "missing: worktree no longer registered (already removed or pruned)");
|
|
288885
288993
|
continue;
|
|
288886
288994
|
}
|
|
288887
288995
|
if (rec.active) {
|
|
288888
288996
|
refuse("active: worktree activated concurrently (fresh lock/heartbeat)");
|
|
288889
288997
|
continue;
|
|
288890
288998
|
}
|
|
288999
|
+
if (candidate.reclaim === "rm_dir") {
|
|
289000
|
+
if (!isReclaimableOrphan(rec)) {
|
|
289001
|
+
refuse(`disposition: fresh audit reports '${rec.disposition}' (orphan no longer provably delivered)`);
|
|
289002
|
+
continue;
|
|
289003
|
+
}
|
|
289004
|
+
const removal2 = {
|
|
289005
|
+
path: rec.path,
|
|
289006
|
+
expectedHead: "",
|
|
289007
|
+
reclaim: "rm_dir",
|
|
289008
|
+
...rec.cycleId ? { cycleId: rec.cycleId } : {}
|
|
289009
|
+
};
|
|
289010
|
+
if (options.dryRun) {
|
|
289011
|
+
removed.push(removal2);
|
|
289012
|
+
continue;
|
|
289013
|
+
}
|
|
289014
|
+
const result3 = reclaimOrphanFn(repositoryRoot, rec.path);
|
|
289015
|
+
if (!result3.ok) {
|
|
289016
|
+
refuse(`reclaim-failed: ${result3.detail}`);
|
|
289017
|
+
continue;
|
|
289018
|
+
}
|
|
289019
|
+
removed.push(removal2);
|
|
289020
|
+
emit4({
|
|
289021
|
+
type: "worktree_cleanup_applied",
|
|
289022
|
+
path: rec.path,
|
|
289023
|
+
expectedHead: "",
|
|
289024
|
+
...rec.cycleId ? { cycleId: rec.cycleId } : {},
|
|
289025
|
+
ts: nowMs2()
|
|
289026
|
+
});
|
|
289027
|
+
continue;
|
|
289028
|
+
}
|
|
289029
|
+
if (rec.head !== candidate.expectedHead) {
|
|
289030
|
+
refuse(`changed-head: expected ${candidate.expectedHead}, found ${rec.head ?? "none"}`);
|
|
289031
|
+
continue;
|
|
289032
|
+
}
|
|
288891
289033
|
if (rec.dirtyTracked === true) {
|
|
288892
289034
|
refuse("dirty: tracked changes appeared after planning");
|
|
288893
289035
|
continue;
|
|
@@ -288903,6 +289045,7 @@ async function applyWorktreeCleanup(plan, options) {
|
|
|
288903
289045
|
const removal = {
|
|
288904
289046
|
path: rec.path,
|
|
288905
289047
|
expectedHead: candidate.expectedHead,
|
|
289048
|
+
reclaim: "git_worktree",
|
|
288906
289049
|
...rec.branch ? { branch: rec.branch } : {},
|
|
288907
289050
|
...rec.cycleId ? { cycleId: rec.cycleId } : {}
|
|
288908
289051
|
};
|
|
@@ -289058,12 +289201,22 @@ function renderPlanHuman(plan, mode) {
|
|
|
289058
289201
|
lines3.push(`minimal candidate set (${plan.canaryTotal} \u2192 ${plan.projectedTotal})`);
|
|
289059
289202
|
for (const c2 of plan.candidates) {
|
|
289060
289203
|
const tags = [c2.branch, c2.cycleId].filter(Boolean).join(" ");
|
|
289061
|
-
|
|
289204
|
+
const label5 = c2.reclaim === "rm_dir" ? "orphan_reclaimable \xB7 bounded rm" : "disposable_candidate";
|
|
289205
|
+
const kind = c2.reclaim === "rm_dir" ? "orphan " : "worktree";
|
|
289206
|
+
lines3.push(` ${kind} ${rel(c2.path)}${tags ? " " + tags : ""} [${label5}]`);
|
|
289062
289207
|
}
|
|
289063
289208
|
for (const b of plan.branchCandidates) {
|
|
289064
289209
|
lines3.push(` branch ${b.branch} ${b.expectedSha.slice(0, 9)} [merged: ${b.mergeKind}]`);
|
|
289065
289210
|
}
|
|
289066
289211
|
lines3.push("");
|
|
289212
|
+
const preservedOrphans = plan.preserved.filter((p) => p.disposition === "preserved_orphan");
|
|
289213
|
+
if (preservedOrphans.length > 0) {
|
|
289214
|
+
lines3.push(`preserved orphan dirs (${preservedOrphans.length}) \u2014 visible + counted, never auto-deleted`);
|
|
289215
|
+
for (const p of preservedOrphans)
|
|
289216
|
+
lines3.push(` ${rel(p.path)} \u2014 ${p.reason}`);
|
|
289217
|
+
lines3.push(" Reclaim one after review with: roll worktree cleanup --reclaim-orphan <path>");
|
|
289218
|
+
lines3.push("");
|
|
289219
|
+
}
|
|
289067
289220
|
if (mode === "dry-run") {
|
|
289068
289221
|
lines3.push("Dry run \u2014 no git state changed.");
|
|
289069
289222
|
lines3.push("Apply the audited set with: roll worktree cleanup --apply");
|
|
@@ -289104,7 +289257,7 @@ function renderResultHuman(result2) {
|
|
|
289104
289257
|
}
|
|
289105
289258
|
return lines3.join("\n").trimEnd() + "\n";
|
|
289106
289259
|
}
|
|
289107
|
-
var CLEANUP_USAGE = "Usage: roll worktree cleanup [--dry-run | --apply] [--json] [--repo <path>]\n Safely recover from branch/worktree canary pressure using the worktree\n audit as the SOLE authority. Removes ONLY inactive, merged, clean\n `disposable_candidate` loop worktrees, plus (FIX-1454) standalone ephemeral\n branches that are verifiably merged (ancestor of the integration branch or a\n merged GitHub PR) and attached to no worktree \u2014 never a path/ref that is\n merely old or counted, and never a preserved (unpublished / dirty / active /\n external / current / protected / unmerged) one.\n\n Always dry-run first. Default (no flag) is --dry-run.\n --dry-run print counted refs/dirs, audit dispositions, and the minimal\n candidate set to clear pressure. Never mutates git state.\n --apply re-run the audit before EVERY removal; remove only revalidated\n candidates via git, prune registration, emit events. A changed\n head / new dirt / missing path / concurrent activation fails\n closed (no substitution). Then resume explicitly: roll loop resume\n --json emit the schema-1 plan (dry-run) or result (apply) as JSON\n --repo override the project root (default: current directory)\n\n \u5B89\u5168\u6E05\u7406:\u4EC5\u79FB\u9664\u5BA1\u8BA1\u5224\u5B9A\u4E3A\u5DF2\u5408\u5E76\u3001\u5E72\u51C0\u3001\u975E\u6D3B\u8DC3\u7684 disposable_candidate;\n \u5148\u8DD1 --dry-run,\u518D --apply,\u6700\u540E\u624B\u52A8 roll loop resume\u3002";
|
|
289260
|
+
var CLEANUP_USAGE = "Usage: roll worktree cleanup [--dry-run | --apply] [--json] [--repo <path>]\n Safely recover from branch/worktree canary pressure using the worktree\n audit as the SOLE authority. Removes ONLY inactive, merged, clean\n `disposable_candidate` loop worktrees, plus (FIX-1454) standalone ephemeral\n branches that are verifiably merged (ancestor of the integration branch or a\n merged GitHub PR) and attached to no worktree \u2014 never a path/ref that is\n merely old or counted, and never a preserved (unpublished / dirty / active /\n external / current / protected / unmerged) one.\n\n Always dry-run first. Default (no flag) is --dry-run.\n --dry-run print counted refs/dirs, audit dispositions, and the minimal\n candidate set to clear pressure. Never mutates git state.\n --apply re-run the audit before EVERY removal; remove only revalidated\n candidates via git, prune registration, emit events. A changed\n head / new dirt / missing path / concurrent activation fails\n closed (no substitution). Then resume explicitly: roll loop resume\n --json emit the schema-1 plan (dry-run) or result (apply) as JSON\n --repo override the project root (default: current directory)\n --reclaim-orphan <path> (FIX-1460) bounded-rm ONE named orphan loop dir\n (deregistered from git; delivery not auto-provable) after you\n review it. Fails closed unless it is an inactive loop orphan\n inside .roll/loop/worktrees. Auto-reclaim of provably-delivered\n orphans happens under --apply.\n\n \u5B89\u5168\u6E05\u7406:\u4EC5\u79FB\u9664\u5BA1\u8BA1\u5224\u5B9A\u4E3A\u5DF2\u5408\u5E76\u3001\u5E72\u51C0\u3001\u975E\u6D3B\u8DC3\u7684 disposable_candidate;\n \u5148\u8DD1 --dry-run,\u518D --apply,\u6700\u540E\u624B\u52A8 roll loop resume\u3002";
|
|
289108
289261
|
function resolveThreshold() {
|
|
289109
289262
|
const parsed = parseInt(process.env["ROLL_BRANCH_CANARY_MAX"] ?? "", 10);
|
|
289110
289263
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_BRANCH_CANARY_MAX;
|
|
@@ -289112,6 +289265,21 @@ function resolveThreshold() {
|
|
|
289112
289265
|
function gitCap(repoRoot3, args) {
|
|
289113
289266
|
return execFileSync32("git", ["-C", repoRoot3, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
289114
289267
|
}
|
|
289268
|
+
function classifyBranchMerge(branch, integrationBranch, git5) {
|
|
289269
|
+
if (git5(["merge-base", "--is-ancestor", branch, integrationBranch]).ok)
|
|
289270
|
+
return "ancestor";
|
|
289271
|
+
const cherry = git5(["cherry", integrationBranch, branch]);
|
|
289272
|
+
if (!cherry.ok)
|
|
289273
|
+
return null;
|
|
289274
|
+
const lines3 = cherry.stdout.split("\n").map((l) => l.trim()).filter((l) => l !== "");
|
|
289275
|
+
if (lines3.length === 0)
|
|
289276
|
+
return null;
|
|
289277
|
+
if (lines3.some((l) => l.startsWith("+")))
|
|
289278
|
+
return null;
|
|
289279
|
+
if (lines3.every((l) => l.startsWith("-")))
|
|
289280
|
+
return "patch_equivalent";
|
|
289281
|
+
return null;
|
|
289282
|
+
}
|
|
289115
289283
|
function buildStandaloneBranchDeps(repoRoot3, audit, integrationBranch) {
|
|
289116
289284
|
const attachedBranches = new Set(audit.records.filter((r) => r.owner === "loop" && typeof r.branch === "string" && r.branch !== "").map((r) => r.branch.replace(/^refs\/heads\//, "")));
|
|
289117
289285
|
let currentBranch2 = null;
|
|
@@ -289130,27 +289298,19 @@ function buildStandaloneBranchDeps(repoRoot3, audit, integrationBranch) {
|
|
|
289130
289298
|
return null;
|
|
289131
289299
|
}
|
|
289132
289300
|
},
|
|
289133
|
-
|
|
289134
|
-
|
|
289135
|
-
|
|
289136
|
-
|
|
289137
|
-
|
|
289138
|
-
|
|
289301
|
+
// FIX-1458 (#1465): delivery is proven ONLY by fresh git patch evidence via
|
|
289302
|
+
// classifyBranchMerge (ancestor OR `git cherry` patch-equivalence). A merged
|
|
289303
|
+
// GitHub PR is deliberately NOT consulted: a squash merge leaves the exact
|
|
289304
|
+
// branch tips undelivered, so authorizing deletion on a merged PR alone
|
|
289305
|
+
// silently discards unique commits (US-ORG-003/007/004 in the report).
|
|
289306
|
+
branchMerge: (branch) => classifyBranchMerge(branch, integrationBranch, (args) => {
|
|
289139
289307
|
try {
|
|
289140
|
-
|
|
289141
|
-
|
|
289142
|
-
|
|
289143
|
-
}
|
|
289144
|
-
} catch {
|
|
289145
|
-
}
|
|
289146
|
-
try {
|
|
289147
|
-
const n = execFileSync32("gh", ["pr", "list", "--head", branch, "--state", "merged", "--json", "number", "--jq", "length"], { cwd: repoRoot3, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
289148
|
-
if (parseInt(n, 10) > 0)
|
|
289149
|
-
return "pr_merged";
|
|
289150
|
-
} catch {
|
|
289308
|
+
return { ok: true, stdout: gitCap(repoRoot3, args) };
|
|
289309
|
+
} catch (err16) {
|
|
289310
|
+
const stdout = typeof err16.stdout === "string" ? err16.stdout : "";
|
|
289311
|
+
return { ok: false, stdout };
|
|
289151
289312
|
}
|
|
289152
|
-
|
|
289153
|
-
}
|
|
289313
|
+
})
|
|
289154
289314
|
};
|
|
289155
289315
|
}
|
|
289156
289316
|
function resolveIntegrationForCleanup(repoRoot3) {
|
|
@@ -289182,10 +289342,57 @@ async function worktreeCleanupCommand(args, deps) {
|
|
|
289182
289342
|
home: deps?.home ?? homedir34(),
|
|
289183
289343
|
git: deps?.git,
|
|
289184
289344
|
readFile: deps?.readFile,
|
|
289345
|
+
readDir: deps?.readDir,
|
|
289185
289346
|
nowISO: deps?.nowISO,
|
|
289186
289347
|
nowSec: deps?.nowSec,
|
|
289187
289348
|
integrationBranch: deps?.integrationBranch
|
|
289188
289349
|
};
|
|
289350
|
+
const reclaimIdx = args.indexOf("--reclaim-orphan");
|
|
289351
|
+
if (reclaimIdx >= 0) {
|
|
289352
|
+
const named2 = args[reclaimIdx + 1];
|
|
289353
|
+
if (!named2) {
|
|
289354
|
+
process.stderr.write("roll worktree cleanup: --reclaim-orphan requires a <path>.\n");
|
|
289355
|
+
return 2;
|
|
289356
|
+
}
|
|
289357
|
+
const fresh = auditWorktrees(fullDeps);
|
|
289358
|
+
const target = resolve14(named2);
|
|
289359
|
+
const rec = fresh.records.find((r2) => resolve14(r2.path) === target);
|
|
289360
|
+
if (!rec) {
|
|
289361
|
+
process.stderr.write(`refused: ${named2} is not in the worktree audit.
|
|
289362
|
+
`);
|
|
289363
|
+
return 2;
|
|
289364
|
+
}
|
|
289365
|
+
if (rec.owner !== "loop") {
|
|
289366
|
+
process.stderr.write(`refused: ${named2} is not a loop worktree (owner=${rec.owner}).
|
|
289367
|
+
`);
|
|
289368
|
+
return 2;
|
|
289369
|
+
}
|
|
289370
|
+
if (rec.active) {
|
|
289371
|
+
process.stderr.write(`refused: ${named2} has an active cycle lock.
|
|
289372
|
+
`);
|
|
289373
|
+
return 2;
|
|
289374
|
+
}
|
|
289375
|
+
if (rec.disposition !== "orphan_reclaimable" && rec.disposition !== "preserved_orphan") {
|
|
289376
|
+
process.stderr.write(`refused: ${named2} audits as '${rec.disposition}', not an orphan dir \u2014 use --apply for registered worktrees.
|
|
289377
|
+
`);
|
|
289378
|
+
return 2;
|
|
289379
|
+
}
|
|
289380
|
+
if (!isBoundedLoopWorktreeDir(repoRoot3, rec.path)) {
|
|
289381
|
+
process.stderr.write(`refused: ${named2} is outside .roll/loop/worktrees.
|
|
289382
|
+
`);
|
|
289383
|
+
return 2;
|
|
289384
|
+
}
|
|
289385
|
+
const reclaimFn = deps?.reclaimOrphanDir ?? defaultReclaimOrphanDir;
|
|
289386
|
+
const r = reclaimFn(repoRoot3, rec.path);
|
|
289387
|
+
if (!r.ok) {
|
|
289388
|
+
process.stderr.write(`reclaim-failed: ${r.detail}
|
|
289389
|
+
`);
|
|
289390
|
+
return 1;
|
|
289391
|
+
}
|
|
289392
|
+
process.stdout.write(`reclaimed orphan dir: ${rec.path}
|
|
289393
|
+
`);
|
|
289394
|
+
return 0;
|
|
289395
|
+
}
|
|
289189
289396
|
const threshold = resolveThreshold();
|
|
289190
289397
|
const integrationBranch = fullDeps.integrationBranch ?? resolveIntegrationForCleanup(repoRoot3);
|
|
289191
289398
|
const auditNow = auditWorktrees(fullDeps);
|
|
@@ -289323,13 +289530,13 @@ function announceReport(projectPath3, slug3, storyId, opener = (p) => {
|
|
|
289323
289530
|
const latest = join158(cardArchiveDir(projectPath3, storyId), "latest");
|
|
289324
289531
|
const review = join158(latest, reviewFileName(storyId));
|
|
289325
289532
|
const legacyReport = join158(latest, reportFileName(storyId));
|
|
289326
|
-
const report =
|
|
289533
|
+
const report = existsSync135(review) ? review : existsSync135(legacyReport) ? legacyReport : null;
|
|
289327
289534
|
if (report === null)
|
|
289328
289535
|
return null;
|
|
289329
289536
|
const label5 = currentLang() === "zh" ? "\u9A8C\u6536 Review Page" : "Acceptance Review Page";
|
|
289330
289537
|
process.stdout.write(`${label5}: ${report}
|
|
289331
289538
|
`);
|
|
289332
|
-
const muted =
|
|
289539
|
+
const muted = existsSync135(join158(projectPath3, ".roll", "loop", `mute-${slug3}`)) || existsSync135(join158(process.env["ROLL_SHARED_ROOT"] || join158(process.env["HOME"] ?? "", ".shared", "roll"), "loop", `mute-${slug3}`));
|
|
289333
289540
|
if (!muted)
|
|
289334
289541
|
opener(report);
|
|
289335
289542
|
return report;
|
|
@@ -289353,7 +289560,7 @@ function cycleSignalTeardown(paths, cycleId, branch, sig, deps = {}) {
|
|
|
289353
289560
|
}
|
|
289354
289561
|
let owned = false;
|
|
289355
289562
|
try {
|
|
289356
|
-
owned =
|
|
289563
|
+
owned = existsSync135(paths.lockPath) && readLockOwner(paths.lockPath)?.pid === pid;
|
|
289357
289564
|
} catch {
|
|
289358
289565
|
owned = false;
|
|
289359
289566
|
}
|
|
@@ -289498,7 +289705,7 @@ function incrementConsecutiveFails(projectPath3, slug3, alertsPath, eventsPath4,
|
|
|
289498
289705
|
const counterFile = join158(rt, "consecutive-fails");
|
|
289499
289706
|
let count = 0;
|
|
289500
289707
|
try {
|
|
289501
|
-
if (
|
|
289708
|
+
if (existsSync135(counterFile)) {
|
|
289502
289709
|
count = parseInt(readFileSync135(counterFile, "utf8").trim(), 10) || 0;
|
|
289503
289710
|
}
|
|
289504
289711
|
} catch {
|
|
@@ -289512,7 +289719,7 @@ function incrementConsecutiveFails(projectPath3, slug3, alertsPath, eventsPath4,
|
|
|
289512
289719
|
if (count < threshold)
|
|
289513
289720
|
return;
|
|
289514
289721
|
const pauseMarker = join158(projectPath3, ".roll", "loop", `PAUSE-${slug3}`);
|
|
289515
|
-
if (
|
|
289722
|
+
if (existsSync135(pauseMarker))
|
|
289516
289723
|
return;
|
|
289517
289724
|
const alertMsg = `# ALERT \u2014 loop auto-paused after ${count} consecutive failures
|
|
289518
289725
|
|
|
@@ -289548,7 +289755,7 @@ loop run-once: \u8FDE\u7EED ${count} \u6B21\u5931\u8D25\u540E\u81EA\u52A8\u6682\
|
|
|
289548
289755
|
}
|
|
289549
289756
|
function writeRootCausePause(projectPath3, slug3, alertsPath, eventsPath4, cycleId, attribution, count, snapshotPath2) {
|
|
289550
289757
|
const pauseMarker = join158(projectPath3, ".roll", "loop", `PAUSE-${slug3}`);
|
|
289551
|
-
if (
|
|
289758
|
+
if (existsSync135(pauseMarker))
|
|
289552
289759
|
return;
|
|
289553
289760
|
const playbook = playbookForFailure(attribution.failureClass, attribution.rootCauseKey);
|
|
289554
289761
|
const alertMsg = `# ALERT \u2014 loop auto-paused on ${attribution.failureClass} failure
|
|
@@ -289610,7 +289817,7 @@ function handleNonCardFailure(projectPath3, slug3, alertsPath, eventsPath4, runt
|
|
|
289610
289817
|
function readFailurePauseThreshold(projectPath3) {
|
|
289611
289818
|
try {
|
|
289612
289819
|
const policy = join158(projectPath3, ".roll", "policy.yaml");
|
|
289613
|
-
if (!
|
|
289820
|
+
if (!existsSync135(policy))
|
|
289614
289821
|
return PAUSE_THRESHOLD;
|
|
289615
289822
|
return parsePolicy(readFileSync135(policy, "utf8")).loopSafety.maxConsecutiveFailures;
|
|
289616
289823
|
} catch {
|
|
@@ -289640,7 +289847,7 @@ function incrementConsecutiveIdle(projectPath3, slug3) {
|
|
|
289640
289847
|
const file = idleCounterPath(projectPath3, slug3);
|
|
289641
289848
|
let count = 0;
|
|
289642
289849
|
try {
|
|
289643
|
-
if (
|
|
289850
|
+
if (existsSync135(file)) {
|
|
289644
289851
|
count = parseInt(readFileSync135(file, "utf8").trim(), 10) || 0;
|
|
289645
289852
|
}
|
|
289646
289853
|
} catch {
|
|
@@ -289710,7 +289917,7 @@ function readExternalBlock(eventsPath4, cycleId) {
|
|
|
289710
289917
|
const authDetails = [];
|
|
289711
289918
|
const networkDetails = [];
|
|
289712
289919
|
try {
|
|
289713
|
-
if (!
|
|
289920
|
+
if (!existsSync135(eventsPath4))
|
|
289714
289921
|
return null;
|
|
289715
289922
|
for (const line of readFileSync135(eventsPath4, "utf8").split("\n")) {
|
|
289716
289923
|
if (line.trim() === "" || !line.includes("agent:blocked"))
|
|
@@ -289775,7 +289982,7 @@ function writeReviewerBlockedAlert(projectPath3, slug3, alertsPath, eventsPath4,
|
|
|
289775
289982
|
}
|
|
289776
289983
|
if (block.cause === "auth") {
|
|
289777
289984
|
const pauseMarker = join158(projectPath3, ".roll", "loop", `PAUSE-${slug3}`);
|
|
289778
|
-
if (!
|
|
289985
|
+
if (!existsSync135(pauseMarker)) {
|
|
289779
289986
|
try {
|
|
289780
289987
|
writeFileSync72(pauseMarker, msg7, "utf8");
|
|
289781
289988
|
bus.appendEvent(eventsPath4, { type: "policy:safety_pause", loop: "ci", reason: `agent auth block: ${agents}`, ts: ts2 });
|
|
@@ -289803,7 +290010,7 @@ function buildLoopRouteDeps(projectPath3) {
|
|
|
289803
290010
|
}
|
|
289804
290011
|
return readRouteSlot(text2, slot);
|
|
289805
290012
|
} catch {
|
|
289806
|
-
if (
|
|
290013
|
+
if (existsSync135(agentsYaml)) {
|
|
289807
290014
|
throw new Error("legacy agent configuration is unsupported; run `roll agent migrate`");
|
|
289808
290015
|
}
|
|
289809
290016
|
return void 0;
|
|
@@ -290081,7 +290288,7 @@ loop run-once: \u8BC4\u5BA1\u5224\u5B9A ${resizeStory} \u8303\u56F4\u8FC7\u5927(
|
|
|
290081
290288
|
slug: id.slug,
|
|
290082
290289
|
count: idleCount,
|
|
290083
290290
|
resolveState: () => resolveLoopRunState(id.path, id.slug),
|
|
290084
|
-
readBacklog: () =>
|
|
290291
|
+
readBacklog: () => existsSync135(backlogFile) ? readFileSync135(backlogFile, "utf8") : "",
|
|
290085
290292
|
scheduler: createScheduler(process.platform, { uid: process.getuid?.() ?? 0 }),
|
|
290086
290293
|
loopLabel: launchdLabel("loop", id.slug),
|
|
290087
290294
|
now: () => (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -290270,7 +290477,7 @@ async function isOffline(resolve17 = (h) => lookup2(h)) {
|
|
|
290270
290477
|
}
|
|
290271
290478
|
}
|
|
290272
290479
|
function isLoopPaused(projectPath3, slug3) {
|
|
290273
|
-
return
|
|
290480
|
+
return existsSync135(join158(projectPath3, ".roll", "loop", `PAUSE-${slug3}`));
|
|
290274
290481
|
}
|
|
290275
290482
|
function branchCanaryTrips(projectPath3, slug3, rt, alertsPath) {
|
|
290276
290483
|
let ephemeralBranchCount = 0;
|
|
@@ -290281,7 +290488,7 @@ function branchCanaryTrips(projectPath3, slug3, rt, alertsPath) {
|
|
|
290281
290488
|
}
|
|
290282
290489
|
let worktreeCount = 0;
|
|
290283
290490
|
try {
|
|
290284
|
-
worktreeCount =
|
|
290491
|
+
worktreeCount = readdirSync49(join158(rt, "worktrees"), { withFileTypes: true }).filter((e) => e.isDirectory()).length;
|
|
290285
290492
|
} catch {
|
|
290286
290493
|
}
|
|
290287
290494
|
const parsed = parseInt(process.env["ROLL_BRANCH_CANARY_MAX"] ?? "", 10);
|
|
@@ -290389,7 +290596,7 @@ function checkCoreWorktreeContamination(cwd) {
|
|
|
290389
290596
|
// packages/cli/dist/commands/offboard.js
|
|
290390
290597
|
init_dist();
|
|
290391
290598
|
import { spawnSync as spawnSync16 } from "node:child_process";
|
|
290392
|
-
import { existsSync as
|
|
290599
|
+
import { existsSync as existsSync136, readFileSync as readFileSync136, realpathSync as realpathSync21, renameSync as renameSync29, rmSync as rmSync26, writeFileSync as writeFileSync73 } from "node:fs";
|
|
290393
290600
|
import { homedir as homedir35 } from "node:os";
|
|
290394
290601
|
import { join as join159, resolve as resolve15 } from "node:path";
|
|
290395
290602
|
function pal4() {
|
|
@@ -290490,7 +290697,7 @@ function writeFileAtomic2(path, text2) {
|
|
|
290490
290697
|
writeFileSync73(tmp, text2);
|
|
290491
290698
|
renameSync29(tmp, path);
|
|
290492
290699
|
} catch (error) {
|
|
290493
|
-
|
|
290700
|
+
rmSync26(tmp, { force: true });
|
|
290494
290701
|
throw error;
|
|
290495
290702
|
}
|
|
290496
290703
|
}
|
|
@@ -290516,12 +290723,12 @@ function offboardCommand(args) {
|
|
|
290516
290723
|
}
|
|
290517
290724
|
let projectDir;
|
|
290518
290725
|
try {
|
|
290519
|
-
projectDir =
|
|
290726
|
+
projectDir = realpathSync21(resolve15(process.cwd()));
|
|
290520
290727
|
} catch {
|
|
290521
290728
|
projectDir = process.cwd();
|
|
290522
290729
|
}
|
|
290523
290730
|
const changeset = changesetPath2(projectDir);
|
|
290524
|
-
if (!
|
|
290731
|
+
if (!existsSync136(changeset)) {
|
|
290525
290732
|
err10(m4("offboard.no_changeset_en"));
|
|
290526
290733
|
err10(m4("offboard.no_changeset_zh"));
|
|
290527
290734
|
process.stderr.write("\n");
|
|
@@ -290620,7 +290827,7 @@ function offboardCommand(args) {
|
|
|
290620
290827
|
process.stdout.write(m4("offboard.applying_offboard") + "\n");
|
|
290621
290828
|
for (const item of mergedFiles) {
|
|
290622
290829
|
const path = resolveChangesetItem(projectDir, item);
|
|
290623
|
-
if (!
|
|
290830
|
+
if (!existsSync136(path))
|
|
290624
290831
|
continue;
|
|
290625
290832
|
const before = readFileSync136(path, "utf8");
|
|
290626
290833
|
const after = stripRollMergeBlocks(before);
|
|
@@ -290633,8 +290840,8 @@ function offboardCommand(args) {
|
|
|
290633
290840
|
for (const item of files) {
|
|
290634
290841
|
try {
|
|
290635
290842
|
const path = resolveChangesetItem(projectDir, item);
|
|
290636
|
-
|
|
290637
|
-
if (!
|
|
290843
|
+
rmSync26(path, { force: true });
|
|
290844
|
+
if (!existsSync136(path))
|
|
290638
290845
|
process.stdout.write(` removed file ${item}
|
|
290639
290846
|
`);
|
|
290640
290847
|
} catch {
|
|
@@ -290642,7 +290849,7 @@ function offboardCommand(args) {
|
|
|
290642
290849
|
}
|
|
290643
290850
|
for (const item of dirs) {
|
|
290644
290851
|
try {
|
|
290645
|
-
|
|
290852
|
+
rmSync26(resolveChangesetItem(projectDir, item), { recursive: true, force: true });
|
|
290646
290853
|
process.stdout.write(` removed dir ${item}
|
|
290647
290854
|
`);
|
|
290648
290855
|
} catch {
|
|
@@ -290650,7 +290857,7 @@ function offboardCommand(args) {
|
|
|
290650
290857
|
}
|
|
290651
290858
|
for (const item of giEntries) {
|
|
290652
290859
|
const gi = join159(projectDir, ".gitignore");
|
|
290653
|
-
if (
|
|
290860
|
+
if (existsSync136(gi)) {
|
|
290654
290861
|
const lines3 = readFileSync136(gi, "utf8").split("\n");
|
|
290655
290862
|
if (lines3.includes(item)) {
|
|
290656
290863
|
const kept = lines3.filter((l) => l !== item);
|
|
@@ -290666,21 +290873,21 @@ function offboardCommand(args) {
|
|
|
290666
290873
|
if (r === 0)
|
|
290667
290874
|
process.stdout.write(` unloaded ${item}
|
|
290668
290875
|
`);
|
|
290669
|
-
|
|
290876
|
+
rmSync26(plistPath, { force: true });
|
|
290670
290877
|
}
|
|
290671
|
-
|
|
290878
|
+
rmSync26(changeset, { force: true });
|
|
290672
290879
|
ok11(m4("offboard.offboard_complete_offboard"));
|
|
290673
290880
|
return 0;
|
|
290674
290881
|
}
|
|
290675
290882
|
|
|
290676
290883
|
// packages/cli/dist/commands/prices.js
|
|
290677
290884
|
init_dist();
|
|
290678
|
-
import { existsSync as
|
|
290885
|
+
import { existsSync as existsSync138, readdirSync as readdirSync51, readFileSync as readFileSync138 } from "node:fs";
|
|
290679
290886
|
import { join as join161 } from "node:path";
|
|
290680
290887
|
|
|
290681
290888
|
// packages/cli/dist/commands/prices-refresh.js
|
|
290682
290889
|
init_dist();
|
|
290683
|
-
import { existsSync as
|
|
290890
|
+
import { existsSync as existsSync137, mkdirSync as mkdirSync75, readdirSync as readdirSync50, readFileSync as readFileSync137, writeFileSync as writeFileSync74 } from "node:fs";
|
|
290684
290891
|
import { join as join160 } from "node:path";
|
|
290685
290892
|
var FetchError = class extends Error {
|
|
290686
290893
|
constructor(message) {
|
|
@@ -290902,9 +291109,9 @@ function vendorFromSnapshotName(name) {
|
|
|
290902
291109
|
return match[2] ?? "anthropic";
|
|
290903
291110
|
}
|
|
290904
291111
|
function latestSnapshotPath(snapshotDir, vendor) {
|
|
290905
|
-
if (!
|
|
291112
|
+
if (!existsSync137(snapshotDir))
|
|
290906
291113
|
return null;
|
|
290907
|
-
const snaps =
|
|
291114
|
+
const snaps = readdirSync50(snapshotDir).filter((name) => SNAPSHOT_RE.test(name) && vendorFromSnapshotName(name) === vendor).sort().map((name) => join160(snapshotDir, name));
|
|
290908
291115
|
return snaps[snaps.length - 1] ?? null;
|
|
290909
291116
|
}
|
|
290910
291117
|
function readPrices(path) {
|
|
@@ -291111,10 +291318,10 @@ async function pricesRefreshCommand(args, deps = {}) {
|
|
|
291111
291318
|
// packages/cli/dist/commands/prices.js
|
|
291112
291319
|
function loadSnapshots() {
|
|
291113
291320
|
const dir = join161(repoRoot2(), "lib", "prices");
|
|
291114
|
-
if (!
|
|
291321
|
+
if (!existsSync138(dir)) {
|
|
291115
291322
|
throw new Error(`no price snapshots found in ${dir}; run \`roll prices refresh\``);
|
|
291116
291323
|
}
|
|
291117
|
-
const files =
|
|
291324
|
+
const files = readdirSync51(dir).filter((n) => n.startsWith("snapshot-") && n.endsWith(".json")).sort();
|
|
291118
291325
|
return files.map((name) => {
|
|
291119
291326
|
const data = JSON.parse(readFileSync138(join161(dir, name), "utf8"));
|
|
291120
291327
|
for (const key of ["version", "effective_at", "source_url", "prices"]) {
|
|
@@ -291295,7 +291502,7 @@ init_dist3();
|
|
|
291295
291502
|
init_dist();
|
|
291296
291503
|
init_render();
|
|
291297
291504
|
import { execFileSync as execFileSync35 } from "node:child_process";
|
|
291298
|
-
import { mkdirSync as mkdirSync79, readFileSync as readFileSync142, writeFileSync as writeFileSync78, existsSync as
|
|
291505
|
+
import { mkdirSync as mkdirSync79, readFileSync as readFileSync142, writeFileSync as writeFileSync78, existsSync as existsSync142 } from "node:fs";
|
|
291299
291506
|
import { dirname as dirname78, join as join165 } from "node:path";
|
|
291300
291507
|
|
|
291301
291508
|
// packages/cli/dist/lib/release-consistency.js
|
|
@@ -291304,7 +291511,7 @@ init_dist3();
|
|
|
291304
291511
|
init_dist();
|
|
291305
291512
|
init_render();
|
|
291306
291513
|
import { execFileSync as execFileSync34 } from "node:child_process";
|
|
291307
|
-
import { existsSync as
|
|
291514
|
+
import { existsSync as existsSync140, mkdirSync as mkdirSync77, readFileSync as readFileSync140, readdirSync as readdirSync53, statSync as statSync39, writeFileSync as writeFileSync76 } from "node:fs";
|
|
291308
291515
|
import { dirname as dirname76, join as join163 } from "node:path";
|
|
291309
291516
|
|
|
291310
291517
|
// packages/cli/dist/lib/consistency-audit.js
|
|
@@ -291312,7 +291519,7 @@ init_dist2();
|
|
|
291312
291519
|
init_dist3();
|
|
291313
291520
|
init_dist();
|
|
291314
291521
|
import { execFile as execFile19 } from "node:child_process";
|
|
291315
|
-
import { existsSync as
|
|
291522
|
+
import { existsSync as existsSync139, mkdirSync as mkdirSync76, readFileSync as readFileSync139, readdirSync as readdirSync52, writeFileSync as writeFileSync75 } from "node:fs";
|
|
291316
291523
|
import { dirname as dirname75, join as join162 } from "node:path";
|
|
291317
291524
|
import { promisify as promisify18 } from "node:util";
|
|
291318
291525
|
init_dist();
|
|
@@ -291321,7 +291528,7 @@ var PROBE_CAP = 20;
|
|
|
291321
291528
|
var COUNT_WINDOW_SEC = 72 * 3600;
|
|
291322
291529
|
var execFileAsync18 = promisify18(execFile19);
|
|
291323
291530
|
function readJsonl(path) {
|
|
291324
|
-
if (!
|
|
291531
|
+
if (!existsSync139(path))
|
|
291325
291532
|
return [];
|
|
291326
291533
|
const out3 = [];
|
|
291327
291534
|
for (const line of readFileSync139(path, "utf8").split("\n")) {
|
|
@@ -291337,7 +291544,7 @@ function readJsonl(path) {
|
|
|
291337
291544
|
return out3;
|
|
291338
291545
|
}
|
|
291339
291546
|
function readJson(path) {
|
|
291340
|
-
if (!
|
|
291547
|
+
if (!existsSync139(path))
|
|
291341
291548
|
return null;
|
|
291342
291549
|
try {
|
|
291343
291550
|
const parsed = JSON.parse(readFileSync139(path, "utf8"));
|
|
@@ -291365,10 +291572,10 @@ function hasScreenshotArtifact(reportPath) {
|
|
|
291365
291572
|
}
|
|
291366
291573
|
}
|
|
291367
291574
|
const dir = join162(runDir, "screenshots");
|
|
291368
|
-
if (!
|
|
291575
|
+
if (!existsSync139(dir))
|
|
291369
291576
|
return false;
|
|
291370
291577
|
try {
|
|
291371
|
-
return
|
|
291578
|
+
return readdirSync52(dir).some((name) => /\.png$/i.test(name));
|
|
291372
291579
|
} catch {
|
|
291373
291580
|
return false;
|
|
291374
291581
|
}
|
|
@@ -291402,7 +291609,7 @@ async function gatherAuditSnapshot(projectPath3, runtimeDir11, deps = {}) {
|
|
|
291402
291609
|
const snapshot = emptyAuditSnapshot(nowSec, TERMINAL_SCHEMA_EPOCH_SEC);
|
|
291403
291610
|
const skipped2 = [];
|
|
291404
291611
|
const backlogPath = join162(projectPath3, ".roll", "backlog.md");
|
|
291405
|
-
if (
|
|
291612
|
+
if (existsSync139(backlogPath)) {
|
|
291406
291613
|
snapshot.backlog = parseBacklog(readFileSync139(backlogPath, "utf8")).map((r) => ({ id: r.id, status: r.status }));
|
|
291407
291614
|
}
|
|
291408
291615
|
snapshot.index = readIndex(projectPath3);
|
|
@@ -291411,7 +291618,7 @@ async function gatherAuditSnapshot(projectPath3, runtimeDir11, deps = {}) {
|
|
|
291411
291618
|
let eventFailed = 0;
|
|
291412
291619
|
const terminal = [];
|
|
291413
291620
|
const eventsPath4 = join162(runtimeDir11, "events.ndjson");
|
|
291414
|
-
if (
|
|
291621
|
+
if (existsSync139(eventsPath4)) {
|
|
291415
291622
|
for (const line of readFileSync139(eventsPath4, "utf8").split("\n")) {
|
|
291416
291623
|
const e = parseEventLine(line);
|
|
291417
291624
|
if (e === null)
|
|
@@ -291434,22 +291641,22 @@ async function gatherAuditSnapshot(projectPath3, runtimeDir11, deps = {}) {
|
|
|
291434
291641
|
if (!row2.status.includes("\u2705"))
|
|
291435
291642
|
continue;
|
|
291436
291643
|
const card = cardArchiveDir(projectPath3, row2.id);
|
|
291437
|
-
if (!
|
|
291644
|
+
if (!existsSync139(card))
|
|
291438
291645
|
continue;
|
|
291439
291646
|
const reportPath = join162(card, "latest", reportFileName(row2.id));
|
|
291440
291647
|
const specPath = join162(card, "spec.md");
|
|
291441
291648
|
let noVisualSurface = false;
|
|
291442
|
-
if (
|
|
291649
|
+
if (existsSync139(specPath)) {
|
|
291443
291650
|
try {
|
|
291444
291651
|
noVisualSurface = !hasVisualEvidenceAc(readFileSync139(specPath, "utf8"));
|
|
291445
291652
|
} catch {
|
|
291446
291653
|
}
|
|
291447
291654
|
}
|
|
291448
291655
|
snapshot.attest[row2.id] = {
|
|
291449
|
-
report:
|
|
291450
|
-
acMap:
|
|
291451
|
-
visualEvidence:
|
|
291452
|
-
machineSkip:
|
|
291656
|
+
report: existsSync139(reportPath),
|
|
291657
|
+
acMap: existsSync139(join162(card, "ac-map.json")),
|
|
291658
|
+
visualEvidence: existsSync139(reportPath) ? hasScreenshotArtifact(reportPath) : false,
|
|
291659
|
+
machineSkip: existsSync139(reportPath) ? hasMachineCaptureSkip2(reportPath) : false,
|
|
291453
291660
|
noVisualSurface
|
|
291454
291661
|
};
|
|
291455
291662
|
}
|
|
@@ -291621,7 +291828,7 @@ function walkTextFiles(projectDir, relDir, extensions) {
|
|
|
291621
291828
|
const dirAbs = join163(projectDir, dirRel);
|
|
291622
291829
|
let entries;
|
|
291623
291830
|
try {
|
|
291624
|
-
entries =
|
|
291831
|
+
entries = readdirSync53(dirAbs, { withFileTypes: true });
|
|
291625
291832
|
} catch {
|
|
291626
291833
|
return;
|
|
291627
291834
|
}
|
|
@@ -291830,11 +292037,11 @@ function manualDirectMainDelivery(projectDir, id, mergeShas) {
|
|
|
291830
292037
|
function findCardSpec(projectDir, id) {
|
|
291831
292038
|
const featuresDir = join163(projectDir, ".roll", "features");
|
|
291832
292039
|
try {
|
|
291833
|
-
for (const epic of
|
|
292040
|
+
for (const epic of readdirSync53(featuresDir, { withFileTypes: true })) {
|
|
291834
292041
|
if (!epic.isDirectory())
|
|
291835
292042
|
continue;
|
|
291836
292043
|
const spec = join163(featuresDir, epic.name, id, "spec.md");
|
|
291837
|
-
if (
|
|
292044
|
+
if (existsSync140(spec))
|
|
291838
292045
|
return spec;
|
|
291839
292046
|
}
|
|
291840
292047
|
} catch {
|
|
@@ -291853,12 +292060,12 @@ function cardChangelogExempt(projectDir, id) {
|
|
|
291853
292060
|
}
|
|
291854
292061
|
function checkFeaturesCatalog(projectDir) {
|
|
291855
292062
|
const backlog = join163(projectDir, ".roll", "backlog.md");
|
|
291856
|
-
if (!
|
|
292063
|
+
if (!existsSync140(backlog))
|
|
291857
292064
|
return { status: "pass", gaps: [] };
|
|
291858
292065
|
const backlogText = readText(backlog);
|
|
291859
292066
|
const gaps = [];
|
|
291860
292067
|
const features = join163(projectDir, ".roll", "features.md");
|
|
291861
|
-
if (
|
|
292068
|
+
if (existsSync140(features)) {
|
|
291862
292069
|
const featuresText = readText(features);
|
|
291863
292070
|
for (const featName of readDoneFeatures(backlogText).keys()) {
|
|
291864
292071
|
const escaped = escapeRegExp4(featName);
|
|
@@ -291882,7 +292089,7 @@ function checkFeaturesCatalog(projectDir) {
|
|
|
291882
292089
|
}
|
|
291883
292090
|
function checkTruthLive(projectDir) {
|
|
291884
292091
|
const backlog = join163(projectDir, ".roll", "backlog.md");
|
|
291885
|
-
if (!
|
|
292092
|
+
if (!existsSync140(backlog))
|
|
291886
292093
|
return { status: "pass", gaps: [] };
|
|
291887
292094
|
const backlogText = readText(backlog);
|
|
291888
292095
|
const facts = backlogRowFacts(backlogText);
|
|
@@ -291927,17 +292134,17 @@ function checkTruthLive(projectDir) {
|
|
|
291927
292134
|
function checkCards(projectDir) {
|
|
291928
292135
|
const backlog = join163(projectDir, ".roll", "backlog.md");
|
|
291929
292136
|
const featuresDir = join163(projectDir, ".roll", "features");
|
|
291930
|
-
if (!
|
|
292137
|
+
if (!existsSync140(backlog) || !existsSync140(featuresDir))
|
|
291931
292138
|
return { status: "pass", gaps: [] };
|
|
291932
292139
|
const cardEpic = /* @__PURE__ */ new Map();
|
|
291933
292140
|
try {
|
|
291934
|
-
for (const epic of
|
|
292141
|
+
for (const epic of readdirSync53(featuresDir, { withFileTypes: true })) {
|
|
291935
292142
|
if (!epic.isDirectory())
|
|
291936
292143
|
continue;
|
|
291937
|
-
for (const card of
|
|
292144
|
+
for (const card of readdirSync53(join163(featuresDir, epic.name), { withFileTypes: true })) {
|
|
291938
292145
|
if (!card.isDirectory())
|
|
291939
292146
|
continue;
|
|
291940
|
-
if (
|
|
292147
|
+
if (existsSync140(join163(featuresDir, epic.name, card.name, "spec.md")) && !cardEpic.has(card.name)) {
|
|
291941
292148
|
cardEpic.set(card.name, epic.name);
|
|
291942
292149
|
}
|
|
291943
292150
|
}
|
|
@@ -291972,12 +292179,12 @@ function checkCards(projectDir) {
|
|
|
291972
292179
|
const ev = /\[evidence\]\(([^)]+)\)/.exec(line);
|
|
291973
292180
|
if (ev !== null) {
|
|
291974
292181
|
const target = (ev[1] ?? "").replace(/^\.roll\//, "");
|
|
291975
|
-
if (!
|
|
292182
|
+
if (!existsSync140(join163(projectDir, ".roll", target))) {
|
|
291976
292183
|
gaps.push(`Backlog row ${id} evidence link is broken: ${ev[1] ?? ""}`);
|
|
291977
292184
|
}
|
|
291978
292185
|
} else if (line.includes(STATUS_MARKER.done)) {
|
|
291979
292186
|
const epic = cardEpic.get(id) ?? "";
|
|
291980
|
-
if (!
|
|
292187
|
+
if (!existsSync140(join163(featuresDir, epic, id, "latest", `${id}-report.html`))) {
|
|
291981
292188
|
if (hasAcBlock(epic, id)) {
|
|
291982
292189
|
gaps.push(`Done backlog row ${id} has ACs but no attest report`);
|
|
291983
292190
|
} else {
|
|
@@ -292000,7 +292207,7 @@ function checkCards(projectDir) {
|
|
|
292000
292207
|
function checkDocs(projectDir) {
|
|
292001
292208
|
const gaps = checkTopLevelCommands(activeDocsFiles(projectDir), DOC_RETIRED_TOP_LEVEL_COMMANDS);
|
|
292002
292209
|
const changelogPath = join163(projectDir, "CHANGELOG.md");
|
|
292003
|
-
if (
|
|
292210
|
+
if (existsSync140(changelogPath)) {
|
|
292004
292211
|
const changelog = readText(changelogPath);
|
|
292005
292212
|
for (const id of releaseDeltaCardIds(projectDir)) {
|
|
292006
292213
|
const base = id.replace(/[a-z]$/, "");
|
|
@@ -292075,7 +292282,7 @@ function checkSite(projectDir) {
|
|
|
292075
292282
|
const gaps = checkTopLevelCommands(activeSiteFiles(projectDir), SITE_HIDDEN_TOP_LEVEL_COMMANDS);
|
|
292076
292283
|
const siteJs = join163(projectDir, "site", "roll-data.js");
|
|
292077
292284
|
const backlog = join163(projectDir, ".roll", "backlog.md");
|
|
292078
|
-
if (!
|
|
292285
|
+
if (!existsSync140(siteJs) || !existsSync140(backlog))
|
|
292079
292286
|
return { status: gaps.length === 0 ? "pass" : "fail", gaps };
|
|
292080
292287
|
const siteText = readText(siteJs);
|
|
292081
292288
|
const seenGuideRefs = /* @__PURE__ */ new Set();
|
|
@@ -292084,7 +292291,7 @@ function checkSite(projectDir) {
|
|
|
292084
292291
|
if (seenGuideRefs.has(rel2))
|
|
292085
292292
|
continue;
|
|
292086
292293
|
seenGuideRefs.add(rel2);
|
|
292087
|
-
if (!
|
|
292294
|
+
if (!existsSync140(join163(projectDir, rel2))) {
|
|
292088
292295
|
gaps.push(`site/roll-data.js links a guide that does not exist: ${rel2}`);
|
|
292089
292296
|
}
|
|
292090
292297
|
}
|
|
@@ -292123,7 +292330,7 @@ function checkSite(projectDir) {
|
|
|
292123
292330
|
}
|
|
292124
292331
|
function listFiles2(dir) {
|
|
292125
292332
|
try {
|
|
292126
|
-
return
|
|
292333
|
+
return readdirSync53(dir).filter((n) => {
|
|
292127
292334
|
try {
|
|
292128
292335
|
return statSync39(join163(dir, n)).isFile();
|
|
292129
292336
|
} catch {
|
|
@@ -292138,7 +292345,7 @@ function checkI18n(projectDir) {
|
|
|
292138
292345
|
const gaps = [];
|
|
292139
292346
|
const guideEn = join163(projectDir, "guide", "en");
|
|
292140
292347
|
const guideZh = join163(projectDir, "guide", "zh");
|
|
292141
|
-
if (
|
|
292348
|
+
if (existsSync140(guideEn) && existsSync140(guideZh)) {
|
|
292142
292349
|
const enFiles = new Set(listFiles2(guideEn));
|
|
292143
292350
|
const zhFiles = new Set(listFiles2(guideZh));
|
|
292144
292351
|
const enOnly = [...enFiles].filter((f) => !zhFiles.has(f)).sort();
|
|
@@ -292149,12 +292356,12 @@ function checkI18n(projectDir) {
|
|
|
292149
292356
|
gaps.push(`guide/zh/${f} has no corresponding guide/en/${f}`);
|
|
292150
292357
|
}
|
|
292151
292358
|
const i18nDir = join163(projectDir, "lib", "i18n");
|
|
292152
|
-
if (
|
|
292359
|
+
if (existsSync140(i18nDir)) {
|
|
292153
292360
|
const keysEn = /* @__PURE__ */ new Set();
|
|
292154
292361
|
const keysZh = /* @__PURE__ */ new Set();
|
|
292155
292362
|
let shFiles = [];
|
|
292156
292363
|
try {
|
|
292157
|
-
shFiles =
|
|
292364
|
+
shFiles = readdirSync53(i18nDir).filter((n) => n.endsWith(".sh")).sort();
|
|
292158
292365
|
} catch {
|
|
292159
292366
|
shFiles = [];
|
|
292160
292367
|
}
|
|
@@ -292194,7 +292401,7 @@ function rglobBats(dir) {
|
|
|
292194
292401
|
const walk2 = (d) => {
|
|
292195
292402
|
let entries = [];
|
|
292196
292403
|
try {
|
|
292197
|
-
entries =
|
|
292404
|
+
entries = readdirSync53(d);
|
|
292198
292405
|
} catch {
|
|
292199
292406
|
return;
|
|
292200
292407
|
}
|
|
@@ -292219,7 +292426,7 @@ function checkTests(projectDir) {
|
|
|
292219
292426
|
const gaps = [];
|
|
292220
292427
|
const backlog = join163(projectDir, ".roll", "backlog.md");
|
|
292221
292428
|
const testsDir = join163(projectDir, "tests");
|
|
292222
|
-
if (!
|
|
292429
|
+
if (!existsSync140(backlog))
|
|
292223
292430
|
return { status: "pass", gaps: [] };
|
|
292224
292431
|
const backlogText = readText(backlog);
|
|
292225
292432
|
const allFeatures = /* @__PURE__ */ new Set();
|
|
@@ -292244,7 +292451,7 @@ function checkTests(projectDir) {
|
|
|
292244
292451
|
doneFeatures.push(currentFeature);
|
|
292245
292452
|
}
|
|
292246
292453
|
}
|
|
292247
|
-
const testFiles =
|
|
292454
|
+
const testFiles = existsSync140(testsDir) ? rglobBats(testsDir) : [];
|
|
292248
292455
|
if (testFiles.length === 0)
|
|
292249
292456
|
return { status: "pass", gaps: [] };
|
|
292250
292457
|
for (const feat of doneFeatures) {
|
|
@@ -292596,7 +292803,7 @@ function writeReleaseTestProof(exec) {
|
|
|
292596
292803
|
function assertTestProofFresh(exec) {
|
|
292597
292804
|
const cwd = exec("git", ["rev-parse", "--show-toplevel"]).trim();
|
|
292598
292805
|
const proofPath = join165(cwd, ".roll", "last-test-pass");
|
|
292599
|
-
if (!
|
|
292806
|
+
if (!existsSync142(proofPath)) {
|
|
292600
292807
|
throw new Error("test-pass proof missing \u2014 run `roll test` before committing");
|
|
292601
292808
|
}
|
|
292602
292809
|
const body = readFileSync142(proofPath, "utf8");
|
|
@@ -292740,7 +292947,7 @@ function realReleaseDeps() {
|
|
|
292740
292947
|
commitPushWithGate({
|
|
292741
292948
|
branch,
|
|
292742
292949
|
message,
|
|
292743
|
-
rollManaged:
|
|
292950
|
+
rollManaged: existsSync142(join165(cwd, ".roll")),
|
|
292744
292951
|
exec: (cmd, args) => execFileSync35(cmd, args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 6e5 })
|
|
292745
292952
|
});
|
|
292746
292953
|
},
|
|
@@ -293065,13 +293272,13 @@ ${c("dim", "\u2192 Running the golden-path showcase (real models; its verdict do
|
|
|
293065
293272
|
init_dist();
|
|
293066
293273
|
init_render();
|
|
293067
293274
|
import { spawnSync as spawnSync19 } from "node:child_process";
|
|
293068
|
-
import { existsSync as
|
|
293275
|
+
import { existsSync as existsSync144, lstatSync as lstatSync13, mkdirSync as mkdirSync81, readFileSync as readFileSync144, readdirSync as readdirSync56, readlinkSync as readlinkSync3, statSync as statSync42 } from "node:fs";
|
|
293069
293276
|
import { join as join167 } from "node:path";
|
|
293070
293277
|
|
|
293071
293278
|
// packages/cli/dist/lib/roll-capture-install.js
|
|
293072
293279
|
init_dist();
|
|
293073
293280
|
import { spawnSync as spawnSync18 } from "node:child_process";
|
|
293074
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
293281
|
+
import { chmodSync as chmodSync2, existsSync as existsSync143, lstatSync as lstatSync12, mkdirSync as mkdirSync80, mkdtempSync as mkdtempSync9, readdirSync as readdirSync55, readFileSync as readFileSync143, renameSync as renameSync30, rmSync as rmSync28, statSync as statSync41, writeFileSync as writeFileSync79 } from "node:fs";
|
|
293075
293282
|
import { homedir as homedir36 } from "node:os";
|
|
293076
293283
|
import { join as join166 } from "node:path";
|
|
293077
293284
|
var RELEASE_API = "https://api.github.com/repos/seanyao/roll-capture/releases/latest";
|
|
@@ -293098,7 +293305,7 @@ function defaultRollCaptureInstallDeps() {
|
|
|
293098
293305
|
home: homedir36(),
|
|
293099
293306
|
uid: typeof process.getuid === "function" ? process.getuid() : void 0,
|
|
293100
293307
|
...platform3 === "darwin" && !isCi3(process.env) && process.env["ROLL_SKIP_CAPTURE_INSTALL"] !== "1" ? { hasAquaGUI: macosHasAquaGUI3(execFile20) } : {},
|
|
293101
|
-
exists:
|
|
293308
|
+
exists: existsSync143,
|
|
293102
293309
|
renamePath: renameSync30,
|
|
293103
293310
|
execFile: execFile20,
|
|
293104
293311
|
fetchLatestRelease: (timeoutMs) => defaultFetchLatestRelease(timeoutMs, process.env, execFile20),
|
|
@@ -293170,7 +293377,7 @@ async function installRollCapture(deps = defaultRollCaptureInstallDeps()) {
|
|
|
293170
293377
|
} catch (error) {
|
|
293171
293378
|
return manual(`install failed: ${errorMessage2(error)}`, release.tagName);
|
|
293172
293379
|
} finally {
|
|
293173
|
-
|
|
293380
|
+
rmSync28(workDir, { recursive: true, force: true });
|
|
293174
293381
|
}
|
|
293175
293382
|
}
|
|
293176
293383
|
function renderRollCaptureInstallResult(result2, lang10) {
|
|
@@ -293306,7 +293513,7 @@ function macosHasAquaGUI3(execFile20) {
|
|
|
293306
293513
|
}
|
|
293307
293514
|
function findExtractedApp(dir) {
|
|
293308
293515
|
try {
|
|
293309
|
-
for (const name of
|
|
293516
|
+
for (const name of readdirSync55(dir)) {
|
|
293310
293517
|
const candidate = join166(dir, name);
|
|
293311
293518
|
const st = lstatSync12(candidate);
|
|
293312
293519
|
if (st.isSymbolicLink())
|
|
@@ -293327,7 +293534,7 @@ function findExtractedApp(dir) {
|
|
|
293327
293534
|
function findBundleExecutable(appPath) {
|
|
293328
293535
|
const macosDir = join166(appPath, "Contents", "MacOS");
|
|
293329
293536
|
try {
|
|
293330
|
-
for (const name of
|
|
293537
|
+
for (const name of readdirSync55(macosDir)) {
|
|
293331
293538
|
const candidate = join166(macosDir, name);
|
|
293332
293539
|
const st = lstatSync12(candidate);
|
|
293333
293540
|
if (st.isSymbolicLink())
|
|
@@ -293344,7 +293551,7 @@ function replaceAppAtomically(app, targetApp, deps) {
|
|
|
293344
293551
|
const renamePath = deps.renamePath ?? renameSync30;
|
|
293345
293552
|
const backupApp = `${targetApp}.bak`;
|
|
293346
293553
|
const hadExisting = lstatExists(targetApp);
|
|
293347
|
-
|
|
293554
|
+
rmSync28(backupApp, { recursive: true, force: true });
|
|
293348
293555
|
if (!hadExisting) {
|
|
293349
293556
|
renamePath(app, targetApp);
|
|
293350
293557
|
return;
|
|
@@ -293356,10 +293563,10 @@ function replaceAppAtomically(app, targetApp, deps) {
|
|
|
293356
293563
|
backupCreated = true;
|
|
293357
293564
|
renamePath(app, targetApp);
|
|
293358
293565
|
targetReplaced = true;
|
|
293359
|
-
|
|
293566
|
+
rmSync28(backupApp, { recursive: true, force: true });
|
|
293360
293567
|
} catch (error) {
|
|
293361
293568
|
if (targetReplaced)
|
|
293362
|
-
|
|
293569
|
+
rmSync28(targetApp, { recursive: true, force: true });
|
|
293363
293570
|
if (backupCreated) {
|
|
293364
293571
|
try {
|
|
293365
293572
|
renamePath(backupApp, targetApp);
|
|
@@ -293535,7 +293742,7 @@ function setupSnapshot(watch) {
|
|
|
293535
293742
|
function walk(dir, lines3) {
|
|
293536
293743
|
let names;
|
|
293537
293744
|
try {
|
|
293538
|
-
names =
|
|
293745
|
+
names = readdirSync56(dir);
|
|
293539
293746
|
} catch {
|
|
293540
293747
|
return;
|
|
293541
293748
|
}
|
|
@@ -293610,11 +293817,11 @@ function tmuxPresent() {
|
|
|
293610
293817
|
function submoduleGuard() {
|
|
293611
293818
|
const pkg = rollPkgDir();
|
|
293612
293819
|
const skills = join167(pkg, "skills");
|
|
293613
|
-
const hasGit =
|
|
293614
|
-
const hasMods =
|
|
293820
|
+
const hasGit = existsSync144(join167(pkg, ".git"));
|
|
293821
|
+
const hasMods = existsSync144(join167(pkg, ".gitmodules"));
|
|
293615
293822
|
let empty = true;
|
|
293616
293823
|
try {
|
|
293617
|
-
empty =
|
|
293824
|
+
empty = readdirSync56(skills).length === 0;
|
|
293618
293825
|
} catch {
|
|
293619
293826
|
empty = true;
|
|
293620
293827
|
}
|
|
@@ -293728,7 +293935,7 @@ async function setupCommand2(args) {
|
|
|
293728
293935
|
return 1;
|
|
293729
293936
|
}
|
|
293730
293937
|
}
|
|
293731
|
-
if (!
|
|
293938
|
+
if (!existsSync144(rollPkgConventions())) {
|
|
293732
293939
|
err13(m5("shared.convention_source_not_found_at_2", rollPkgConventions()));
|
|
293733
293940
|
err13(m5("shared.run_this_from_the_roll_repo"));
|
|
293734
293941
|
return 1;
|
|
@@ -293819,7 +294026,7 @@ init_showcase2();
|
|
|
293819
294026
|
// packages/cli/dist/commands/test.js
|
|
293820
294027
|
init_dist2();
|
|
293821
294028
|
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
293822
|
-
import { appendFileSync as appendFileSync22, existsSync as
|
|
294029
|
+
import { appendFileSync as appendFileSync22, existsSync as existsSync145, mkdirSync as mkdirSync82, readFileSync as readFileSync145, rmSync as rmSync29, writeFileSync as writeFileSync80 } from "node:fs";
|
|
293823
294030
|
import { dirname as dirname79, join as join168, resolve as resolve16 } from "node:path";
|
|
293824
294031
|
function pal6() {
|
|
293825
294032
|
const noColor2 = (process.env["NO_COLOR"] ?? "") !== "";
|
|
@@ -293841,7 +294048,7 @@ function currentEvidenceFrame() {
|
|
|
293841
294048
|
if (raw === "")
|
|
293842
294049
|
return null;
|
|
293843
294050
|
const runDir = resolve16(raw);
|
|
293844
|
-
if (!
|
|
294051
|
+
if (!existsSync145(runDir))
|
|
293845
294052
|
return null;
|
|
293846
294053
|
const frame = {
|
|
293847
294054
|
runDir,
|
|
@@ -293898,7 +294105,7 @@ function appendRollTestEvidence(frame, cmd, argv, status2, stdout, stderr) {
|
|
|
293898
294105
|
}
|
|
293899
294106
|
function isolationGetType() {
|
|
293900
294107
|
const file = join168(process.cwd(), ".roll", "local.yaml");
|
|
293901
|
-
if (!
|
|
294108
|
+
if (!existsSync145(file))
|
|
293902
294109
|
return "none";
|
|
293903
294110
|
let text2;
|
|
293904
294111
|
try {
|
|
@@ -293950,11 +294157,11 @@ function resetLockPath() {
|
|
|
293950
294157
|
return ".roll/.iso-reset.lock";
|
|
293951
294158
|
}
|
|
293952
294159
|
function resetLockHeld() {
|
|
293953
|
-
return
|
|
294160
|
+
return existsSync145(resetLockPath());
|
|
293954
294161
|
}
|
|
293955
294162
|
function resetAcquireLock() {
|
|
293956
294163
|
const lock = resetLockPath();
|
|
293957
|
-
if (
|
|
294164
|
+
if (existsSync145(lock))
|
|
293958
294165
|
return false;
|
|
293959
294166
|
mkdirSync82(dirname79(lock), { recursive: true });
|
|
293960
294167
|
writeFileSync80(lock, `${process.pid}
|
|
@@ -293962,7 +294169,7 @@ function resetAcquireLock() {
|
|
|
293962
294169
|
return true;
|
|
293963
294170
|
}
|
|
293964
294171
|
function resetReleaseLock() {
|
|
293965
|
-
|
|
294172
|
+
rmSync29(resetLockPath(), { force: true });
|
|
293966
294173
|
}
|
|
293967
294174
|
function runForward(cmd, argv) {
|
|
293968
294175
|
const frame = currentEvidenceFrame();
|
|
@@ -293980,7 +294187,7 @@ function runForward(cmd, argv) {
|
|
|
293980
294187
|
}
|
|
293981
294188
|
function readTestScript(cwd) {
|
|
293982
294189
|
const p = join168(cwd, "package.json");
|
|
293983
|
-
if (!
|
|
294190
|
+
if (!existsSync145(p))
|
|
293984
294191
|
return void 0;
|
|
293985
294192
|
try {
|
|
293986
294193
|
const pkg = JSON.parse(readFileSync145(p, "utf8"));
|
|
@@ -293994,7 +294201,7 @@ function detectVitestVersion(cwd) {
|
|
|
293994
294201
|
let dir = cwd;
|
|
293995
294202
|
for (let i = 0; i < 6; i++) {
|
|
293996
294203
|
const vp = join168(dir, "node_modules", "vitest", "package.json");
|
|
293997
|
-
if (
|
|
294204
|
+
if (existsSync145(vp)) {
|
|
293998
294205
|
try {
|
|
293999
294206
|
const v = JSON.parse(readFileSync145(vp, "utf8")).version;
|
|
294000
294207
|
if (typeof v === "string")
|
|
@@ -294032,14 +294239,14 @@ function writeTestProof(cwd, mode, command) {
|
|
|
294032
294239
|
function ensureSkillsSubmoduleReady() {
|
|
294033
294240
|
const pkg = rollPkgDir();
|
|
294034
294241
|
const required2 = join168(pkg, "skills", "roll-onboard", "SKILL.md");
|
|
294035
|
-
if (
|
|
294242
|
+
if (existsSync145(required2))
|
|
294036
294243
|
return true;
|
|
294037
|
-
if (
|
|
294244
|
+
if (existsSync145(join168(pkg, ".git")) && existsSync145(join168(pkg, ".gitmodules"))) {
|
|
294038
294245
|
spawnSync20("git", ["submodule", "update", "--init", "--recursive", "--quiet", "skills"], {
|
|
294039
294246
|
cwd: pkg,
|
|
294040
294247
|
stdio: "ignore"
|
|
294041
294248
|
});
|
|
294042
|
-
if (
|
|
294249
|
+
if (existsSync145(required2))
|
|
294043
294250
|
return true;
|
|
294044
294251
|
}
|
|
294045
294252
|
err14("roll test: skills submodule is empty");
|
|
@@ -294048,7 +294255,7 @@ function ensureSkillsSubmoduleReady() {
|
|
|
294048
294255
|
}
|
|
294049
294256
|
function ensureNoneIsolation() {
|
|
294050
294257
|
const type = isolationGetType();
|
|
294051
|
-
if (type === "none" && !
|
|
294258
|
+
if (type === "none" && !existsSync145(join168(process.cwd(), ".roll", "local.yaml"))) {
|
|
294052
294259
|
infoErr("isolation: no test_isolation config, falling back to type=none (host)");
|
|
294053
294260
|
}
|
|
294054
294261
|
if (!SUPPORTED_TYPES.includes(type)) {
|
|
@@ -294163,7 +294370,7 @@ function testCommand(args) {
|
|
|
294163
294370
|
}
|
|
294164
294371
|
const cwd = process.cwd();
|
|
294165
294372
|
const resolution = resolveGateCommand({
|
|
294166
|
-
hasPackageJson:
|
|
294373
|
+
hasPackageJson: existsSync145(join168(cwd, "package.json")),
|
|
294167
294374
|
testScript: readTestScript(cwd),
|
|
294168
294375
|
vitestVersion: detectVitestVersion(cwd)
|
|
294169
294376
|
});
|
|
@@ -294589,7 +294796,7 @@ function emitRepair(json, outcome) {
|
|
|
294589
294796
|
// packages/cli/dist/commands/truth.js
|
|
294590
294797
|
init_dist();
|
|
294591
294798
|
init_dist2();
|
|
294592
|
-
import { statSync as statSync43, readFileSync as readFileSync147, writeFileSync as writeFileSync82, mkdirSync as mkdirSync84, existsSync as
|
|
294799
|
+
import { statSync as statSync43, readFileSync as readFileSync147, writeFileSync as writeFileSync82, mkdirSync as mkdirSync84, existsSync as existsSync146 } from "node:fs";
|
|
294593
294800
|
import { dirname as dirname81, join as join171 } from "node:path";
|
|
294594
294801
|
var TRUTH_USAGE = "Usage: roll truth <command>\n query <storyId> Deterministic delivery-truth query (structured, zero markdown parse).\n audit Bidirectional drift audit: backlog Done \u2194 projection truth.\n\u547D\u4EE4:\n query <storyId> \u7ED3\u6784\u5316\u4EA4\u4ED8\u771F\u76F8\u67E5\u8BE2\uFF08\u786E\u5B9A\u6027\uFF0C\u4E0D\u89E3\u6790 markdown\uFF09\n audit \u53CC\u5411\u6F02\u79FB\u5BA1\u8BA1\uFF1Abacklog Done \u2194 \u6295\u5F71\u771F\u76F8";
|
|
294595
294802
|
function formatTruth(t2, lang10) {
|
|
@@ -294637,7 +294844,7 @@ function truthAuditCommand(args, lang10) {
|
|
|
294637
294844
|
const cwd = process.cwd();
|
|
294638
294845
|
const nowSec = Math.floor(Date.now() / 1e3);
|
|
294639
294846
|
const backlogPath = join171(cwd, ".roll", "backlog.md");
|
|
294640
|
-
const backlogRows =
|
|
294847
|
+
const backlogRows = existsSync146(backlogPath) ? parseBacklog(readFileSync147(backlogPath, "utf8")).map((r) => ({ id: r.id, status: r.status })) : [];
|
|
294641
294848
|
const deliveries = ensureDeliveriesFresh(cwd, nodeFreshnessPort4, nodeExecPort);
|
|
294642
294849
|
const snapshot = emptyAuditSnapshot(nowSec, TERMINAL_SCHEMA_EPOCH_SEC);
|
|
294643
294850
|
snapshot.backlog = backlogRows;
|
|
@@ -294722,7 +294929,7 @@ function truthCommand(args) {
|
|
|
294722
294929
|
|
|
294723
294930
|
// packages/cli/dist/commands/tune.js
|
|
294724
294931
|
init_dist2();
|
|
294725
|
-
import { existsSync as
|
|
294932
|
+
import { existsSync as existsSync147, readFileSync as readFileSync148 } from "node:fs";
|
|
294726
294933
|
import { join as join172 } from "node:path";
|
|
294727
294934
|
function projectPath2() {
|
|
294728
294935
|
return (process.env["ROLL_MAIN_PROJECT"] ?? "").trim() || process.cwd();
|
|
@@ -294731,7 +294938,7 @@ function str6(v, dflt = "") {
|
|
|
294731
294938
|
return typeof v === "string" ? v : dflt;
|
|
294732
294939
|
}
|
|
294733
294940
|
function parseJsonl(path) {
|
|
294734
|
-
if (!
|
|
294941
|
+
if (!existsSync147(path))
|
|
294735
294942
|
return [];
|
|
294736
294943
|
let text2;
|
|
294737
294944
|
try {
|
|
@@ -294907,7 +295114,7 @@ function tuneCommand(argv) {
|
|
|
294907
295114
|
// packages/cli/dist/commands/update.js
|
|
294908
295115
|
init_dist();
|
|
294909
295116
|
import { spawnSync as spawnSync21 } from "node:child_process";
|
|
294910
|
-
import { existsSync as
|
|
295117
|
+
import { existsSync as existsSync148, mkdtempSync as mkdtempSync10, readFileSync as readFileSync149, rmSync as rmSync30 } from "node:fs";
|
|
294911
295118
|
import { tmpdir as tmpdir14 } from "node:os";
|
|
294912
295119
|
import { join as join173 } from "node:path";
|
|
294913
295120
|
function pal7() {
|
|
@@ -294997,7 +295204,7 @@ function downloadAndInstallCurl(tag) {
|
|
|
294997
295204
|
}
|
|
294998
295205
|
return { ok: true, newVersion: treeVersion(extractDir) };
|
|
294999
295206
|
} finally {
|
|
295000
|
-
|
|
295207
|
+
rmSync30(tmpDir, { recursive: true, force: true });
|
|
295001
295208
|
}
|
|
295002
295209
|
}
|
|
295003
295210
|
function checkInstalledVersionOrRetry() {
|
|
@@ -295017,11 +295224,11 @@ function checkInstalledVersionOrRetry() {
|
|
|
295017
295224
|
}
|
|
295018
295225
|
}
|
|
295019
295226
|
function invalidateUpdateCache() {
|
|
295020
|
-
|
|
295227
|
+
rmSync30(join173(rollHome(), ".update-check"), { force: true });
|
|
295021
295228
|
}
|
|
295022
295229
|
function showChangelog() {
|
|
295023
295230
|
const changelog = join173(rollPkgDir(), "CHANGELOG.md");
|
|
295024
|
-
if (!
|
|
295231
|
+
if (!existsSync148(changelog))
|
|
295025
295232
|
return;
|
|
295026
295233
|
const { BOLD: BOLD2, CYAN, NC } = pal7();
|
|
295027
295234
|
process.stdout.write(`${BOLD2}${m6("changelog.heading")}:${NC}
|
|
@@ -295052,7 +295259,7 @@ async function updateCommand(args) {
|
|
|
295052
295259
|
info5(m6("update.current_version", rollVersion()));
|
|
295053
295260
|
let installMethod = "npm";
|
|
295054
295261
|
const methodFile = join173(rollPkgDir(), ".install-method");
|
|
295055
|
-
if (
|
|
295262
|
+
if (existsSync148(methodFile)) {
|
|
295056
295263
|
installMethod = readFileSync149(methodFile, "utf8").trim() || "npm";
|
|
295057
295264
|
}
|
|
295058
295265
|
if (installMethod === "curl") {
|