@seanyao/roll 4.719.2 → 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 +5 -0
- package/dist/roll.mjs +366 -166
- 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";
|
|
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";
|
|
288772
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;
|
|
@@ -289189,10 +289342,57 @@ async function worktreeCleanupCommand(args, deps) {
|
|
|
289189
289342
|
home: deps?.home ?? homedir34(),
|
|
289190
289343
|
git: deps?.git,
|
|
289191
289344
|
readFile: deps?.readFile,
|
|
289345
|
+
readDir: deps?.readDir,
|
|
289192
289346
|
nowISO: deps?.nowISO,
|
|
289193
289347
|
nowSec: deps?.nowSec,
|
|
289194
289348
|
integrationBranch: deps?.integrationBranch
|
|
289195
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
|
+
}
|
|
289196
289396
|
const threshold = resolveThreshold();
|
|
289197
289397
|
const integrationBranch = fullDeps.integrationBranch ?? resolveIntegrationForCleanup(repoRoot3);
|
|
289198
289398
|
const auditNow = auditWorktrees(fullDeps);
|
|
@@ -289330,13 +289530,13 @@ function announceReport(projectPath3, slug3, storyId, opener = (p) => {
|
|
|
289330
289530
|
const latest = join158(cardArchiveDir(projectPath3, storyId), "latest");
|
|
289331
289531
|
const review = join158(latest, reviewFileName(storyId));
|
|
289332
289532
|
const legacyReport = join158(latest, reportFileName(storyId));
|
|
289333
|
-
const report =
|
|
289533
|
+
const report = existsSync135(review) ? review : existsSync135(legacyReport) ? legacyReport : null;
|
|
289334
289534
|
if (report === null)
|
|
289335
289535
|
return null;
|
|
289336
289536
|
const label5 = currentLang() === "zh" ? "\u9A8C\u6536 Review Page" : "Acceptance Review Page";
|
|
289337
289537
|
process.stdout.write(`${label5}: ${report}
|
|
289338
289538
|
`);
|
|
289339
|
-
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}`));
|
|
289340
289540
|
if (!muted)
|
|
289341
289541
|
opener(report);
|
|
289342
289542
|
return report;
|
|
@@ -289360,7 +289560,7 @@ function cycleSignalTeardown(paths, cycleId, branch, sig, deps = {}) {
|
|
|
289360
289560
|
}
|
|
289361
289561
|
let owned = false;
|
|
289362
289562
|
try {
|
|
289363
|
-
owned =
|
|
289563
|
+
owned = existsSync135(paths.lockPath) && readLockOwner(paths.lockPath)?.pid === pid;
|
|
289364
289564
|
} catch {
|
|
289365
289565
|
owned = false;
|
|
289366
289566
|
}
|
|
@@ -289505,7 +289705,7 @@ function incrementConsecutiveFails(projectPath3, slug3, alertsPath, eventsPath4,
|
|
|
289505
289705
|
const counterFile = join158(rt, "consecutive-fails");
|
|
289506
289706
|
let count = 0;
|
|
289507
289707
|
try {
|
|
289508
|
-
if (
|
|
289708
|
+
if (existsSync135(counterFile)) {
|
|
289509
289709
|
count = parseInt(readFileSync135(counterFile, "utf8").trim(), 10) || 0;
|
|
289510
289710
|
}
|
|
289511
289711
|
} catch {
|
|
@@ -289519,7 +289719,7 @@ function incrementConsecutiveFails(projectPath3, slug3, alertsPath, eventsPath4,
|
|
|
289519
289719
|
if (count < threshold)
|
|
289520
289720
|
return;
|
|
289521
289721
|
const pauseMarker = join158(projectPath3, ".roll", "loop", `PAUSE-${slug3}`);
|
|
289522
|
-
if (
|
|
289722
|
+
if (existsSync135(pauseMarker))
|
|
289523
289723
|
return;
|
|
289524
289724
|
const alertMsg = `# ALERT \u2014 loop auto-paused after ${count} consecutive failures
|
|
289525
289725
|
|
|
@@ -289555,7 +289755,7 @@ loop run-once: \u8FDE\u7EED ${count} \u6B21\u5931\u8D25\u540E\u81EA\u52A8\u6682\
|
|
|
289555
289755
|
}
|
|
289556
289756
|
function writeRootCausePause(projectPath3, slug3, alertsPath, eventsPath4, cycleId, attribution, count, snapshotPath2) {
|
|
289557
289757
|
const pauseMarker = join158(projectPath3, ".roll", "loop", `PAUSE-${slug3}`);
|
|
289558
|
-
if (
|
|
289758
|
+
if (existsSync135(pauseMarker))
|
|
289559
289759
|
return;
|
|
289560
289760
|
const playbook = playbookForFailure(attribution.failureClass, attribution.rootCauseKey);
|
|
289561
289761
|
const alertMsg = `# ALERT \u2014 loop auto-paused on ${attribution.failureClass} failure
|
|
@@ -289617,7 +289817,7 @@ function handleNonCardFailure(projectPath3, slug3, alertsPath, eventsPath4, runt
|
|
|
289617
289817
|
function readFailurePauseThreshold(projectPath3) {
|
|
289618
289818
|
try {
|
|
289619
289819
|
const policy = join158(projectPath3, ".roll", "policy.yaml");
|
|
289620
|
-
if (!
|
|
289820
|
+
if (!existsSync135(policy))
|
|
289621
289821
|
return PAUSE_THRESHOLD;
|
|
289622
289822
|
return parsePolicy(readFileSync135(policy, "utf8")).loopSafety.maxConsecutiveFailures;
|
|
289623
289823
|
} catch {
|
|
@@ -289647,7 +289847,7 @@ function incrementConsecutiveIdle(projectPath3, slug3) {
|
|
|
289647
289847
|
const file = idleCounterPath(projectPath3, slug3);
|
|
289648
289848
|
let count = 0;
|
|
289649
289849
|
try {
|
|
289650
|
-
if (
|
|
289850
|
+
if (existsSync135(file)) {
|
|
289651
289851
|
count = parseInt(readFileSync135(file, "utf8").trim(), 10) || 0;
|
|
289652
289852
|
}
|
|
289653
289853
|
} catch {
|
|
@@ -289717,7 +289917,7 @@ function readExternalBlock(eventsPath4, cycleId) {
|
|
|
289717
289917
|
const authDetails = [];
|
|
289718
289918
|
const networkDetails = [];
|
|
289719
289919
|
try {
|
|
289720
|
-
if (!
|
|
289920
|
+
if (!existsSync135(eventsPath4))
|
|
289721
289921
|
return null;
|
|
289722
289922
|
for (const line of readFileSync135(eventsPath4, "utf8").split("\n")) {
|
|
289723
289923
|
if (line.trim() === "" || !line.includes("agent:blocked"))
|
|
@@ -289782,7 +289982,7 @@ function writeReviewerBlockedAlert(projectPath3, slug3, alertsPath, eventsPath4,
|
|
|
289782
289982
|
}
|
|
289783
289983
|
if (block.cause === "auth") {
|
|
289784
289984
|
const pauseMarker = join158(projectPath3, ".roll", "loop", `PAUSE-${slug3}`);
|
|
289785
|
-
if (!
|
|
289985
|
+
if (!existsSync135(pauseMarker)) {
|
|
289786
289986
|
try {
|
|
289787
289987
|
writeFileSync72(pauseMarker, msg7, "utf8");
|
|
289788
289988
|
bus.appendEvent(eventsPath4, { type: "policy:safety_pause", loop: "ci", reason: `agent auth block: ${agents}`, ts: ts2 });
|
|
@@ -289810,7 +290010,7 @@ function buildLoopRouteDeps(projectPath3) {
|
|
|
289810
290010
|
}
|
|
289811
290011
|
return readRouteSlot(text2, slot);
|
|
289812
290012
|
} catch {
|
|
289813
|
-
if (
|
|
290013
|
+
if (existsSync135(agentsYaml)) {
|
|
289814
290014
|
throw new Error("legacy agent configuration is unsupported; run `roll agent migrate`");
|
|
289815
290015
|
}
|
|
289816
290016
|
return void 0;
|
|
@@ -290088,7 +290288,7 @@ loop run-once: \u8BC4\u5BA1\u5224\u5B9A ${resizeStory} \u8303\u56F4\u8FC7\u5927(
|
|
|
290088
290288
|
slug: id.slug,
|
|
290089
290289
|
count: idleCount,
|
|
290090
290290
|
resolveState: () => resolveLoopRunState(id.path, id.slug),
|
|
290091
|
-
readBacklog: () =>
|
|
290291
|
+
readBacklog: () => existsSync135(backlogFile) ? readFileSync135(backlogFile, "utf8") : "",
|
|
290092
290292
|
scheduler: createScheduler(process.platform, { uid: process.getuid?.() ?? 0 }),
|
|
290093
290293
|
loopLabel: launchdLabel("loop", id.slug),
|
|
290094
290294
|
now: () => (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -290277,7 +290477,7 @@ async function isOffline(resolve17 = (h) => lookup2(h)) {
|
|
|
290277
290477
|
}
|
|
290278
290478
|
}
|
|
290279
290479
|
function isLoopPaused(projectPath3, slug3) {
|
|
290280
|
-
return
|
|
290480
|
+
return existsSync135(join158(projectPath3, ".roll", "loop", `PAUSE-${slug3}`));
|
|
290281
290481
|
}
|
|
290282
290482
|
function branchCanaryTrips(projectPath3, slug3, rt, alertsPath) {
|
|
290283
290483
|
let ephemeralBranchCount = 0;
|
|
@@ -290288,7 +290488,7 @@ function branchCanaryTrips(projectPath3, slug3, rt, alertsPath) {
|
|
|
290288
290488
|
}
|
|
290289
290489
|
let worktreeCount = 0;
|
|
290290
290490
|
try {
|
|
290291
|
-
worktreeCount =
|
|
290491
|
+
worktreeCount = readdirSync49(join158(rt, "worktrees"), { withFileTypes: true }).filter((e) => e.isDirectory()).length;
|
|
290292
290492
|
} catch {
|
|
290293
290493
|
}
|
|
290294
290494
|
const parsed = parseInt(process.env["ROLL_BRANCH_CANARY_MAX"] ?? "", 10);
|
|
@@ -290396,7 +290596,7 @@ function checkCoreWorktreeContamination(cwd) {
|
|
|
290396
290596
|
// packages/cli/dist/commands/offboard.js
|
|
290397
290597
|
init_dist();
|
|
290398
290598
|
import { spawnSync as spawnSync16 } from "node:child_process";
|
|
290399
|
-
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";
|
|
290400
290600
|
import { homedir as homedir35 } from "node:os";
|
|
290401
290601
|
import { join as join159, resolve as resolve15 } from "node:path";
|
|
290402
290602
|
function pal4() {
|
|
@@ -290497,7 +290697,7 @@ function writeFileAtomic2(path, text2) {
|
|
|
290497
290697
|
writeFileSync73(tmp, text2);
|
|
290498
290698
|
renameSync29(tmp, path);
|
|
290499
290699
|
} catch (error) {
|
|
290500
|
-
|
|
290700
|
+
rmSync26(tmp, { force: true });
|
|
290501
290701
|
throw error;
|
|
290502
290702
|
}
|
|
290503
290703
|
}
|
|
@@ -290523,12 +290723,12 @@ function offboardCommand(args) {
|
|
|
290523
290723
|
}
|
|
290524
290724
|
let projectDir;
|
|
290525
290725
|
try {
|
|
290526
|
-
projectDir =
|
|
290726
|
+
projectDir = realpathSync21(resolve15(process.cwd()));
|
|
290527
290727
|
} catch {
|
|
290528
290728
|
projectDir = process.cwd();
|
|
290529
290729
|
}
|
|
290530
290730
|
const changeset = changesetPath2(projectDir);
|
|
290531
|
-
if (!
|
|
290731
|
+
if (!existsSync136(changeset)) {
|
|
290532
290732
|
err10(m4("offboard.no_changeset_en"));
|
|
290533
290733
|
err10(m4("offboard.no_changeset_zh"));
|
|
290534
290734
|
process.stderr.write("\n");
|
|
@@ -290627,7 +290827,7 @@ function offboardCommand(args) {
|
|
|
290627
290827
|
process.stdout.write(m4("offboard.applying_offboard") + "\n");
|
|
290628
290828
|
for (const item of mergedFiles) {
|
|
290629
290829
|
const path = resolveChangesetItem(projectDir, item);
|
|
290630
|
-
if (!
|
|
290830
|
+
if (!existsSync136(path))
|
|
290631
290831
|
continue;
|
|
290632
290832
|
const before = readFileSync136(path, "utf8");
|
|
290633
290833
|
const after = stripRollMergeBlocks(before);
|
|
@@ -290640,8 +290840,8 @@ function offboardCommand(args) {
|
|
|
290640
290840
|
for (const item of files) {
|
|
290641
290841
|
try {
|
|
290642
290842
|
const path = resolveChangesetItem(projectDir, item);
|
|
290643
|
-
|
|
290644
|
-
if (!
|
|
290843
|
+
rmSync26(path, { force: true });
|
|
290844
|
+
if (!existsSync136(path))
|
|
290645
290845
|
process.stdout.write(` removed file ${item}
|
|
290646
290846
|
`);
|
|
290647
290847
|
} catch {
|
|
@@ -290649,7 +290849,7 @@ function offboardCommand(args) {
|
|
|
290649
290849
|
}
|
|
290650
290850
|
for (const item of dirs) {
|
|
290651
290851
|
try {
|
|
290652
|
-
|
|
290852
|
+
rmSync26(resolveChangesetItem(projectDir, item), { recursive: true, force: true });
|
|
290653
290853
|
process.stdout.write(` removed dir ${item}
|
|
290654
290854
|
`);
|
|
290655
290855
|
} catch {
|
|
@@ -290657,7 +290857,7 @@ function offboardCommand(args) {
|
|
|
290657
290857
|
}
|
|
290658
290858
|
for (const item of giEntries) {
|
|
290659
290859
|
const gi = join159(projectDir, ".gitignore");
|
|
290660
|
-
if (
|
|
290860
|
+
if (existsSync136(gi)) {
|
|
290661
290861
|
const lines3 = readFileSync136(gi, "utf8").split("\n");
|
|
290662
290862
|
if (lines3.includes(item)) {
|
|
290663
290863
|
const kept = lines3.filter((l) => l !== item);
|
|
@@ -290673,21 +290873,21 @@ function offboardCommand(args) {
|
|
|
290673
290873
|
if (r === 0)
|
|
290674
290874
|
process.stdout.write(` unloaded ${item}
|
|
290675
290875
|
`);
|
|
290676
|
-
|
|
290876
|
+
rmSync26(plistPath, { force: true });
|
|
290677
290877
|
}
|
|
290678
|
-
|
|
290878
|
+
rmSync26(changeset, { force: true });
|
|
290679
290879
|
ok11(m4("offboard.offboard_complete_offboard"));
|
|
290680
290880
|
return 0;
|
|
290681
290881
|
}
|
|
290682
290882
|
|
|
290683
290883
|
// packages/cli/dist/commands/prices.js
|
|
290684
290884
|
init_dist();
|
|
290685
|
-
import { existsSync as
|
|
290885
|
+
import { existsSync as existsSync138, readdirSync as readdirSync51, readFileSync as readFileSync138 } from "node:fs";
|
|
290686
290886
|
import { join as join161 } from "node:path";
|
|
290687
290887
|
|
|
290688
290888
|
// packages/cli/dist/commands/prices-refresh.js
|
|
290689
290889
|
init_dist();
|
|
290690
|
-
import { existsSync as
|
|
290890
|
+
import { existsSync as existsSync137, mkdirSync as mkdirSync75, readdirSync as readdirSync50, readFileSync as readFileSync137, writeFileSync as writeFileSync74 } from "node:fs";
|
|
290691
290891
|
import { join as join160 } from "node:path";
|
|
290692
290892
|
var FetchError = class extends Error {
|
|
290693
290893
|
constructor(message) {
|
|
@@ -290909,9 +291109,9 @@ function vendorFromSnapshotName(name) {
|
|
|
290909
291109
|
return match[2] ?? "anthropic";
|
|
290910
291110
|
}
|
|
290911
291111
|
function latestSnapshotPath(snapshotDir, vendor) {
|
|
290912
|
-
if (!
|
|
291112
|
+
if (!existsSync137(snapshotDir))
|
|
290913
291113
|
return null;
|
|
290914
|
-
const snaps =
|
|
291114
|
+
const snaps = readdirSync50(snapshotDir).filter((name) => SNAPSHOT_RE.test(name) && vendorFromSnapshotName(name) === vendor).sort().map((name) => join160(snapshotDir, name));
|
|
290915
291115
|
return snaps[snaps.length - 1] ?? null;
|
|
290916
291116
|
}
|
|
290917
291117
|
function readPrices(path) {
|
|
@@ -291118,10 +291318,10 @@ async function pricesRefreshCommand(args, deps = {}) {
|
|
|
291118
291318
|
// packages/cli/dist/commands/prices.js
|
|
291119
291319
|
function loadSnapshots() {
|
|
291120
291320
|
const dir = join161(repoRoot2(), "lib", "prices");
|
|
291121
|
-
if (!
|
|
291321
|
+
if (!existsSync138(dir)) {
|
|
291122
291322
|
throw new Error(`no price snapshots found in ${dir}; run \`roll prices refresh\``);
|
|
291123
291323
|
}
|
|
291124
|
-
const files =
|
|
291324
|
+
const files = readdirSync51(dir).filter((n) => n.startsWith("snapshot-") && n.endsWith(".json")).sort();
|
|
291125
291325
|
return files.map((name) => {
|
|
291126
291326
|
const data = JSON.parse(readFileSync138(join161(dir, name), "utf8"));
|
|
291127
291327
|
for (const key of ["version", "effective_at", "source_url", "prices"]) {
|
|
@@ -291302,7 +291502,7 @@ init_dist3();
|
|
|
291302
291502
|
init_dist();
|
|
291303
291503
|
init_render();
|
|
291304
291504
|
import { execFileSync as execFileSync35 } from "node:child_process";
|
|
291305
|
-
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";
|
|
291306
291506
|
import { dirname as dirname78, join as join165 } from "node:path";
|
|
291307
291507
|
|
|
291308
291508
|
// packages/cli/dist/lib/release-consistency.js
|
|
@@ -291311,7 +291511,7 @@ init_dist3();
|
|
|
291311
291511
|
init_dist();
|
|
291312
291512
|
init_render();
|
|
291313
291513
|
import { execFileSync as execFileSync34 } from "node:child_process";
|
|
291314
|
-
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";
|
|
291315
291515
|
import { dirname as dirname76, join as join163 } from "node:path";
|
|
291316
291516
|
|
|
291317
291517
|
// packages/cli/dist/lib/consistency-audit.js
|
|
@@ -291319,7 +291519,7 @@ init_dist2();
|
|
|
291319
291519
|
init_dist3();
|
|
291320
291520
|
init_dist();
|
|
291321
291521
|
import { execFile as execFile19 } from "node:child_process";
|
|
291322
|
-
import { existsSync as
|
|
291522
|
+
import { existsSync as existsSync139, mkdirSync as mkdirSync76, readFileSync as readFileSync139, readdirSync as readdirSync52, writeFileSync as writeFileSync75 } from "node:fs";
|
|
291323
291523
|
import { dirname as dirname75, join as join162 } from "node:path";
|
|
291324
291524
|
import { promisify as promisify18 } from "node:util";
|
|
291325
291525
|
init_dist();
|
|
@@ -291328,7 +291528,7 @@ var PROBE_CAP = 20;
|
|
|
291328
291528
|
var COUNT_WINDOW_SEC = 72 * 3600;
|
|
291329
291529
|
var execFileAsync18 = promisify18(execFile19);
|
|
291330
291530
|
function readJsonl(path) {
|
|
291331
|
-
if (!
|
|
291531
|
+
if (!existsSync139(path))
|
|
291332
291532
|
return [];
|
|
291333
291533
|
const out3 = [];
|
|
291334
291534
|
for (const line of readFileSync139(path, "utf8").split("\n")) {
|
|
@@ -291344,7 +291544,7 @@ function readJsonl(path) {
|
|
|
291344
291544
|
return out3;
|
|
291345
291545
|
}
|
|
291346
291546
|
function readJson(path) {
|
|
291347
|
-
if (!
|
|
291547
|
+
if (!existsSync139(path))
|
|
291348
291548
|
return null;
|
|
291349
291549
|
try {
|
|
291350
291550
|
const parsed = JSON.parse(readFileSync139(path, "utf8"));
|
|
@@ -291372,10 +291572,10 @@ function hasScreenshotArtifact(reportPath) {
|
|
|
291372
291572
|
}
|
|
291373
291573
|
}
|
|
291374
291574
|
const dir = join162(runDir, "screenshots");
|
|
291375
|
-
if (!
|
|
291575
|
+
if (!existsSync139(dir))
|
|
291376
291576
|
return false;
|
|
291377
291577
|
try {
|
|
291378
|
-
return
|
|
291578
|
+
return readdirSync52(dir).some((name) => /\.png$/i.test(name));
|
|
291379
291579
|
} catch {
|
|
291380
291580
|
return false;
|
|
291381
291581
|
}
|
|
@@ -291409,7 +291609,7 @@ async function gatherAuditSnapshot(projectPath3, runtimeDir11, deps = {}) {
|
|
|
291409
291609
|
const snapshot = emptyAuditSnapshot(nowSec, TERMINAL_SCHEMA_EPOCH_SEC);
|
|
291410
291610
|
const skipped2 = [];
|
|
291411
291611
|
const backlogPath = join162(projectPath3, ".roll", "backlog.md");
|
|
291412
|
-
if (
|
|
291612
|
+
if (existsSync139(backlogPath)) {
|
|
291413
291613
|
snapshot.backlog = parseBacklog(readFileSync139(backlogPath, "utf8")).map((r) => ({ id: r.id, status: r.status }));
|
|
291414
291614
|
}
|
|
291415
291615
|
snapshot.index = readIndex(projectPath3);
|
|
@@ -291418,7 +291618,7 @@ async function gatherAuditSnapshot(projectPath3, runtimeDir11, deps = {}) {
|
|
|
291418
291618
|
let eventFailed = 0;
|
|
291419
291619
|
const terminal = [];
|
|
291420
291620
|
const eventsPath4 = join162(runtimeDir11, "events.ndjson");
|
|
291421
|
-
if (
|
|
291621
|
+
if (existsSync139(eventsPath4)) {
|
|
291422
291622
|
for (const line of readFileSync139(eventsPath4, "utf8").split("\n")) {
|
|
291423
291623
|
const e = parseEventLine(line);
|
|
291424
291624
|
if (e === null)
|
|
@@ -291441,22 +291641,22 @@ async function gatherAuditSnapshot(projectPath3, runtimeDir11, deps = {}) {
|
|
|
291441
291641
|
if (!row2.status.includes("\u2705"))
|
|
291442
291642
|
continue;
|
|
291443
291643
|
const card = cardArchiveDir(projectPath3, row2.id);
|
|
291444
|
-
if (!
|
|
291644
|
+
if (!existsSync139(card))
|
|
291445
291645
|
continue;
|
|
291446
291646
|
const reportPath = join162(card, "latest", reportFileName(row2.id));
|
|
291447
291647
|
const specPath = join162(card, "spec.md");
|
|
291448
291648
|
let noVisualSurface = false;
|
|
291449
|
-
if (
|
|
291649
|
+
if (existsSync139(specPath)) {
|
|
291450
291650
|
try {
|
|
291451
291651
|
noVisualSurface = !hasVisualEvidenceAc(readFileSync139(specPath, "utf8"));
|
|
291452
291652
|
} catch {
|
|
291453
291653
|
}
|
|
291454
291654
|
}
|
|
291455
291655
|
snapshot.attest[row2.id] = {
|
|
291456
|
-
report:
|
|
291457
|
-
acMap:
|
|
291458
|
-
visualEvidence:
|
|
291459
|
-
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,
|
|
291460
291660
|
noVisualSurface
|
|
291461
291661
|
};
|
|
291462
291662
|
}
|
|
@@ -291628,7 +291828,7 @@ function walkTextFiles(projectDir, relDir, extensions) {
|
|
|
291628
291828
|
const dirAbs = join163(projectDir, dirRel);
|
|
291629
291829
|
let entries;
|
|
291630
291830
|
try {
|
|
291631
|
-
entries =
|
|
291831
|
+
entries = readdirSync53(dirAbs, { withFileTypes: true });
|
|
291632
291832
|
} catch {
|
|
291633
291833
|
return;
|
|
291634
291834
|
}
|
|
@@ -291837,11 +292037,11 @@ function manualDirectMainDelivery(projectDir, id, mergeShas) {
|
|
|
291837
292037
|
function findCardSpec(projectDir, id) {
|
|
291838
292038
|
const featuresDir = join163(projectDir, ".roll", "features");
|
|
291839
292039
|
try {
|
|
291840
|
-
for (const epic of
|
|
292040
|
+
for (const epic of readdirSync53(featuresDir, { withFileTypes: true })) {
|
|
291841
292041
|
if (!epic.isDirectory())
|
|
291842
292042
|
continue;
|
|
291843
292043
|
const spec = join163(featuresDir, epic.name, id, "spec.md");
|
|
291844
|
-
if (
|
|
292044
|
+
if (existsSync140(spec))
|
|
291845
292045
|
return spec;
|
|
291846
292046
|
}
|
|
291847
292047
|
} catch {
|
|
@@ -291860,12 +292060,12 @@ function cardChangelogExempt(projectDir, id) {
|
|
|
291860
292060
|
}
|
|
291861
292061
|
function checkFeaturesCatalog(projectDir) {
|
|
291862
292062
|
const backlog = join163(projectDir, ".roll", "backlog.md");
|
|
291863
|
-
if (!
|
|
292063
|
+
if (!existsSync140(backlog))
|
|
291864
292064
|
return { status: "pass", gaps: [] };
|
|
291865
292065
|
const backlogText = readText(backlog);
|
|
291866
292066
|
const gaps = [];
|
|
291867
292067
|
const features = join163(projectDir, ".roll", "features.md");
|
|
291868
|
-
if (
|
|
292068
|
+
if (existsSync140(features)) {
|
|
291869
292069
|
const featuresText = readText(features);
|
|
291870
292070
|
for (const featName of readDoneFeatures(backlogText).keys()) {
|
|
291871
292071
|
const escaped = escapeRegExp4(featName);
|
|
@@ -291889,7 +292089,7 @@ function checkFeaturesCatalog(projectDir) {
|
|
|
291889
292089
|
}
|
|
291890
292090
|
function checkTruthLive(projectDir) {
|
|
291891
292091
|
const backlog = join163(projectDir, ".roll", "backlog.md");
|
|
291892
|
-
if (!
|
|
292092
|
+
if (!existsSync140(backlog))
|
|
291893
292093
|
return { status: "pass", gaps: [] };
|
|
291894
292094
|
const backlogText = readText(backlog);
|
|
291895
292095
|
const facts = backlogRowFacts(backlogText);
|
|
@@ -291934,17 +292134,17 @@ function checkTruthLive(projectDir) {
|
|
|
291934
292134
|
function checkCards(projectDir) {
|
|
291935
292135
|
const backlog = join163(projectDir, ".roll", "backlog.md");
|
|
291936
292136
|
const featuresDir = join163(projectDir, ".roll", "features");
|
|
291937
|
-
if (!
|
|
292137
|
+
if (!existsSync140(backlog) || !existsSync140(featuresDir))
|
|
291938
292138
|
return { status: "pass", gaps: [] };
|
|
291939
292139
|
const cardEpic = /* @__PURE__ */ new Map();
|
|
291940
292140
|
try {
|
|
291941
|
-
for (const epic of
|
|
292141
|
+
for (const epic of readdirSync53(featuresDir, { withFileTypes: true })) {
|
|
291942
292142
|
if (!epic.isDirectory())
|
|
291943
292143
|
continue;
|
|
291944
|
-
for (const card of
|
|
292144
|
+
for (const card of readdirSync53(join163(featuresDir, epic.name), { withFileTypes: true })) {
|
|
291945
292145
|
if (!card.isDirectory())
|
|
291946
292146
|
continue;
|
|
291947
|
-
if (
|
|
292147
|
+
if (existsSync140(join163(featuresDir, epic.name, card.name, "spec.md")) && !cardEpic.has(card.name)) {
|
|
291948
292148
|
cardEpic.set(card.name, epic.name);
|
|
291949
292149
|
}
|
|
291950
292150
|
}
|
|
@@ -291979,12 +292179,12 @@ function checkCards(projectDir) {
|
|
|
291979
292179
|
const ev = /\[evidence\]\(([^)]+)\)/.exec(line);
|
|
291980
292180
|
if (ev !== null) {
|
|
291981
292181
|
const target = (ev[1] ?? "").replace(/^\.roll\//, "");
|
|
291982
|
-
if (!
|
|
292182
|
+
if (!existsSync140(join163(projectDir, ".roll", target))) {
|
|
291983
292183
|
gaps.push(`Backlog row ${id} evidence link is broken: ${ev[1] ?? ""}`);
|
|
291984
292184
|
}
|
|
291985
292185
|
} else if (line.includes(STATUS_MARKER.done)) {
|
|
291986
292186
|
const epic = cardEpic.get(id) ?? "";
|
|
291987
|
-
if (!
|
|
292187
|
+
if (!existsSync140(join163(featuresDir, epic, id, "latest", `${id}-report.html`))) {
|
|
291988
292188
|
if (hasAcBlock(epic, id)) {
|
|
291989
292189
|
gaps.push(`Done backlog row ${id} has ACs but no attest report`);
|
|
291990
292190
|
} else {
|
|
@@ -292007,7 +292207,7 @@ function checkCards(projectDir) {
|
|
|
292007
292207
|
function checkDocs(projectDir) {
|
|
292008
292208
|
const gaps = checkTopLevelCommands(activeDocsFiles(projectDir), DOC_RETIRED_TOP_LEVEL_COMMANDS);
|
|
292009
292209
|
const changelogPath = join163(projectDir, "CHANGELOG.md");
|
|
292010
|
-
if (
|
|
292210
|
+
if (existsSync140(changelogPath)) {
|
|
292011
292211
|
const changelog = readText(changelogPath);
|
|
292012
292212
|
for (const id of releaseDeltaCardIds(projectDir)) {
|
|
292013
292213
|
const base = id.replace(/[a-z]$/, "");
|
|
@@ -292082,7 +292282,7 @@ function checkSite(projectDir) {
|
|
|
292082
292282
|
const gaps = checkTopLevelCommands(activeSiteFiles(projectDir), SITE_HIDDEN_TOP_LEVEL_COMMANDS);
|
|
292083
292283
|
const siteJs = join163(projectDir, "site", "roll-data.js");
|
|
292084
292284
|
const backlog = join163(projectDir, ".roll", "backlog.md");
|
|
292085
|
-
if (!
|
|
292285
|
+
if (!existsSync140(siteJs) || !existsSync140(backlog))
|
|
292086
292286
|
return { status: gaps.length === 0 ? "pass" : "fail", gaps };
|
|
292087
292287
|
const siteText = readText(siteJs);
|
|
292088
292288
|
const seenGuideRefs = /* @__PURE__ */ new Set();
|
|
@@ -292091,7 +292291,7 @@ function checkSite(projectDir) {
|
|
|
292091
292291
|
if (seenGuideRefs.has(rel2))
|
|
292092
292292
|
continue;
|
|
292093
292293
|
seenGuideRefs.add(rel2);
|
|
292094
|
-
if (!
|
|
292294
|
+
if (!existsSync140(join163(projectDir, rel2))) {
|
|
292095
292295
|
gaps.push(`site/roll-data.js links a guide that does not exist: ${rel2}`);
|
|
292096
292296
|
}
|
|
292097
292297
|
}
|
|
@@ -292130,7 +292330,7 @@ function checkSite(projectDir) {
|
|
|
292130
292330
|
}
|
|
292131
292331
|
function listFiles2(dir) {
|
|
292132
292332
|
try {
|
|
292133
|
-
return
|
|
292333
|
+
return readdirSync53(dir).filter((n) => {
|
|
292134
292334
|
try {
|
|
292135
292335
|
return statSync39(join163(dir, n)).isFile();
|
|
292136
292336
|
} catch {
|
|
@@ -292145,7 +292345,7 @@ function checkI18n(projectDir) {
|
|
|
292145
292345
|
const gaps = [];
|
|
292146
292346
|
const guideEn = join163(projectDir, "guide", "en");
|
|
292147
292347
|
const guideZh = join163(projectDir, "guide", "zh");
|
|
292148
|
-
if (
|
|
292348
|
+
if (existsSync140(guideEn) && existsSync140(guideZh)) {
|
|
292149
292349
|
const enFiles = new Set(listFiles2(guideEn));
|
|
292150
292350
|
const zhFiles = new Set(listFiles2(guideZh));
|
|
292151
292351
|
const enOnly = [...enFiles].filter((f) => !zhFiles.has(f)).sort();
|
|
@@ -292156,12 +292356,12 @@ function checkI18n(projectDir) {
|
|
|
292156
292356
|
gaps.push(`guide/zh/${f} has no corresponding guide/en/${f}`);
|
|
292157
292357
|
}
|
|
292158
292358
|
const i18nDir = join163(projectDir, "lib", "i18n");
|
|
292159
|
-
if (
|
|
292359
|
+
if (existsSync140(i18nDir)) {
|
|
292160
292360
|
const keysEn = /* @__PURE__ */ new Set();
|
|
292161
292361
|
const keysZh = /* @__PURE__ */ new Set();
|
|
292162
292362
|
let shFiles = [];
|
|
292163
292363
|
try {
|
|
292164
|
-
shFiles =
|
|
292364
|
+
shFiles = readdirSync53(i18nDir).filter((n) => n.endsWith(".sh")).sort();
|
|
292165
292365
|
} catch {
|
|
292166
292366
|
shFiles = [];
|
|
292167
292367
|
}
|
|
@@ -292201,7 +292401,7 @@ function rglobBats(dir) {
|
|
|
292201
292401
|
const walk2 = (d) => {
|
|
292202
292402
|
let entries = [];
|
|
292203
292403
|
try {
|
|
292204
|
-
entries =
|
|
292404
|
+
entries = readdirSync53(d);
|
|
292205
292405
|
} catch {
|
|
292206
292406
|
return;
|
|
292207
292407
|
}
|
|
@@ -292226,7 +292426,7 @@ function checkTests(projectDir) {
|
|
|
292226
292426
|
const gaps = [];
|
|
292227
292427
|
const backlog = join163(projectDir, ".roll", "backlog.md");
|
|
292228
292428
|
const testsDir = join163(projectDir, "tests");
|
|
292229
|
-
if (!
|
|
292429
|
+
if (!existsSync140(backlog))
|
|
292230
292430
|
return { status: "pass", gaps: [] };
|
|
292231
292431
|
const backlogText = readText(backlog);
|
|
292232
292432
|
const allFeatures = /* @__PURE__ */ new Set();
|
|
@@ -292251,7 +292451,7 @@ function checkTests(projectDir) {
|
|
|
292251
292451
|
doneFeatures.push(currentFeature);
|
|
292252
292452
|
}
|
|
292253
292453
|
}
|
|
292254
|
-
const testFiles =
|
|
292454
|
+
const testFiles = existsSync140(testsDir) ? rglobBats(testsDir) : [];
|
|
292255
292455
|
if (testFiles.length === 0)
|
|
292256
292456
|
return { status: "pass", gaps: [] };
|
|
292257
292457
|
for (const feat of doneFeatures) {
|
|
@@ -292603,7 +292803,7 @@ function writeReleaseTestProof(exec) {
|
|
|
292603
292803
|
function assertTestProofFresh(exec) {
|
|
292604
292804
|
const cwd = exec("git", ["rev-parse", "--show-toplevel"]).trim();
|
|
292605
292805
|
const proofPath = join165(cwd, ".roll", "last-test-pass");
|
|
292606
|
-
if (!
|
|
292806
|
+
if (!existsSync142(proofPath)) {
|
|
292607
292807
|
throw new Error("test-pass proof missing \u2014 run `roll test` before committing");
|
|
292608
292808
|
}
|
|
292609
292809
|
const body = readFileSync142(proofPath, "utf8");
|
|
@@ -292747,7 +292947,7 @@ function realReleaseDeps() {
|
|
|
292747
292947
|
commitPushWithGate({
|
|
292748
292948
|
branch,
|
|
292749
292949
|
message,
|
|
292750
|
-
rollManaged:
|
|
292950
|
+
rollManaged: existsSync142(join165(cwd, ".roll")),
|
|
292751
292951
|
exec: (cmd, args) => execFileSync35(cmd, args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 6e5 })
|
|
292752
292952
|
});
|
|
292753
292953
|
},
|
|
@@ -293072,13 +293272,13 @@ ${c("dim", "\u2192 Running the golden-path showcase (real models; its verdict do
|
|
|
293072
293272
|
init_dist();
|
|
293073
293273
|
init_render();
|
|
293074
293274
|
import { spawnSync as spawnSync19 } from "node:child_process";
|
|
293075
|
-
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";
|
|
293076
293276
|
import { join as join167 } from "node:path";
|
|
293077
293277
|
|
|
293078
293278
|
// packages/cli/dist/lib/roll-capture-install.js
|
|
293079
293279
|
init_dist();
|
|
293080
293280
|
import { spawnSync as spawnSync18 } from "node:child_process";
|
|
293081
|
-
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";
|
|
293082
293282
|
import { homedir as homedir36 } from "node:os";
|
|
293083
293283
|
import { join as join166 } from "node:path";
|
|
293084
293284
|
var RELEASE_API = "https://api.github.com/repos/seanyao/roll-capture/releases/latest";
|
|
@@ -293105,7 +293305,7 @@ function defaultRollCaptureInstallDeps() {
|
|
|
293105
293305
|
home: homedir36(),
|
|
293106
293306
|
uid: typeof process.getuid === "function" ? process.getuid() : void 0,
|
|
293107
293307
|
...platform3 === "darwin" && !isCi3(process.env) && process.env["ROLL_SKIP_CAPTURE_INSTALL"] !== "1" ? { hasAquaGUI: macosHasAquaGUI3(execFile20) } : {},
|
|
293108
|
-
exists:
|
|
293308
|
+
exists: existsSync143,
|
|
293109
293309
|
renamePath: renameSync30,
|
|
293110
293310
|
execFile: execFile20,
|
|
293111
293311
|
fetchLatestRelease: (timeoutMs) => defaultFetchLatestRelease(timeoutMs, process.env, execFile20),
|
|
@@ -293177,7 +293377,7 @@ async function installRollCapture(deps = defaultRollCaptureInstallDeps()) {
|
|
|
293177
293377
|
} catch (error) {
|
|
293178
293378
|
return manual(`install failed: ${errorMessage2(error)}`, release.tagName);
|
|
293179
293379
|
} finally {
|
|
293180
|
-
|
|
293380
|
+
rmSync28(workDir, { recursive: true, force: true });
|
|
293181
293381
|
}
|
|
293182
293382
|
}
|
|
293183
293383
|
function renderRollCaptureInstallResult(result2, lang10) {
|
|
@@ -293313,7 +293513,7 @@ function macosHasAquaGUI3(execFile20) {
|
|
|
293313
293513
|
}
|
|
293314
293514
|
function findExtractedApp(dir) {
|
|
293315
293515
|
try {
|
|
293316
|
-
for (const name of
|
|
293516
|
+
for (const name of readdirSync55(dir)) {
|
|
293317
293517
|
const candidate = join166(dir, name);
|
|
293318
293518
|
const st = lstatSync12(candidate);
|
|
293319
293519
|
if (st.isSymbolicLink())
|
|
@@ -293334,7 +293534,7 @@ function findExtractedApp(dir) {
|
|
|
293334
293534
|
function findBundleExecutable(appPath) {
|
|
293335
293535
|
const macosDir = join166(appPath, "Contents", "MacOS");
|
|
293336
293536
|
try {
|
|
293337
|
-
for (const name of
|
|
293537
|
+
for (const name of readdirSync55(macosDir)) {
|
|
293338
293538
|
const candidate = join166(macosDir, name);
|
|
293339
293539
|
const st = lstatSync12(candidate);
|
|
293340
293540
|
if (st.isSymbolicLink())
|
|
@@ -293351,7 +293551,7 @@ function replaceAppAtomically(app, targetApp, deps) {
|
|
|
293351
293551
|
const renamePath = deps.renamePath ?? renameSync30;
|
|
293352
293552
|
const backupApp = `${targetApp}.bak`;
|
|
293353
293553
|
const hadExisting = lstatExists(targetApp);
|
|
293354
|
-
|
|
293554
|
+
rmSync28(backupApp, { recursive: true, force: true });
|
|
293355
293555
|
if (!hadExisting) {
|
|
293356
293556
|
renamePath(app, targetApp);
|
|
293357
293557
|
return;
|
|
@@ -293363,10 +293563,10 @@ function replaceAppAtomically(app, targetApp, deps) {
|
|
|
293363
293563
|
backupCreated = true;
|
|
293364
293564
|
renamePath(app, targetApp);
|
|
293365
293565
|
targetReplaced = true;
|
|
293366
|
-
|
|
293566
|
+
rmSync28(backupApp, { recursive: true, force: true });
|
|
293367
293567
|
} catch (error) {
|
|
293368
293568
|
if (targetReplaced)
|
|
293369
|
-
|
|
293569
|
+
rmSync28(targetApp, { recursive: true, force: true });
|
|
293370
293570
|
if (backupCreated) {
|
|
293371
293571
|
try {
|
|
293372
293572
|
renamePath(backupApp, targetApp);
|
|
@@ -293542,7 +293742,7 @@ function setupSnapshot(watch) {
|
|
|
293542
293742
|
function walk(dir, lines3) {
|
|
293543
293743
|
let names;
|
|
293544
293744
|
try {
|
|
293545
|
-
names =
|
|
293745
|
+
names = readdirSync56(dir);
|
|
293546
293746
|
} catch {
|
|
293547
293747
|
return;
|
|
293548
293748
|
}
|
|
@@ -293617,11 +293817,11 @@ function tmuxPresent() {
|
|
|
293617
293817
|
function submoduleGuard() {
|
|
293618
293818
|
const pkg = rollPkgDir();
|
|
293619
293819
|
const skills = join167(pkg, "skills");
|
|
293620
|
-
const hasGit =
|
|
293621
|
-
const hasMods =
|
|
293820
|
+
const hasGit = existsSync144(join167(pkg, ".git"));
|
|
293821
|
+
const hasMods = existsSync144(join167(pkg, ".gitmodules"));
|
|
293622
293822
|
let empty = true;
|
|
293623
293823
|
try {
|
|
293624
|
-
empty =
|
|
293824
|
+
empty = readdirSync56(skills).length === 0;
|
|
293625
293825
|
} catch {
|
|
293626
293826
|
empty = true;
|
|
293627
293827
|
}
|
|
@@ -293735,7 +293935,7 @@ async function setupCommand2(args) {
|
|
|
293735
293935
|
return 1;
|
|
293736
293936
|
}
|
|
293737
293937
|
}
|
|
293738
|
-
if (!
|
|
293938
|
+
if (!existsSync144(rollPkgConventions())) {
|
|
293739
293939
|
err13(m5("shared.convention_source_not_found_at_2", rollPkgConventions()));
|
|
293740
293940
|
err13(m5("shared.run_this_from_the_roll_repo"));
|
|
293741
293941
|
return 1;
|
|
@@ -293826,7 +294026,7 @@ init_showcase2();
|
|
|
293826
294026
|
// packages/cli/dist/commands/test.js
|
|
293827
294027
|
init_dist2();
|
|
293828
294028
|
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
293829
|
-
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";
|
|
293830
294030
|
import { dirname as dirname79, join as join168, resolve as resolve16 } from "node:path";
|
|
293831
294031
|
function pal6() {
|
|
293832
294032
|
const noColor2 = (process.env["NO_COLOR"] ?? "") !== "";
|
|
@@ -293848,7 +294048,7 @@ function currentEvidenceFrame() {
|
|
|
293848
294048
|
if (raw === "")
|
|
293849
294049
|
return null;
|
|
293850
294050
|
const runDir = resolve16(raw);
|
|
293851
|
-
if (!
|
|
294051
|
+
if (!existsSync145(runDir))
|
|
293852
294052
|
return null;
|
|
293853
294053
|
const frame = {
|
|
293854
294054
|
runDir,
|
|
@@ -293905,7 +294105,7 @@ function appendRollTestEvidence(frame, cmd, argv, status2, stdout, stderr) {
|
|
|
293905
294105
|
}
|
|
293906
294106
|
function isolationGetType() {
|
|
293907
294107
|
const file = join168(process.cwd(), ".roll", "local.yaml");
|
|
293908
|
-
if (!
|
|
294108
|
+
if (!existsSync145(file))
|
|
293909
294109
|
return "none";
|
|
293910
294110
|
let text2;
|
|
293911
294111
|
try {
|
|
@@ -293957,11 +294157,11 @@ function resetLockPath() {
|
|
|
293957
294157
|
return ".roll/.iso-reset.lock";
|
|
293958
294158
|
}
|
|
293959
294159
|
function resetLockHeld() {
|
|
293960
|
-
return
|
|
294160
|
+
return existsSync145(resetLockPath());
|
|
293961
294161
|
}
|
|
293962
294162
|
function resetAcquireLock() {
|
|
293963
294163
|
const lock = resetLockPath();
|
|
293964
|
-
if (
|
|
294164
|
+
if (existsSync145(lock))
|
|
293965
294165
|
return false;
|
|
293966
294166
|
mkdirSync82(dirname79(lock), { recursive: true });
|
|
293967
294167
|
writeFileSync80(lock, `${process.pid}
|
|
@@ -293969,7 +294169,7 @@ function resetAcquireLock() {
|
|
|
293969
294169
|
return true;
|
|
293970
294170
|
}
|
|
293971
294171
|
function resetReleaseLock() {
|
|
293972
|
-
|
|
294172
|
+
rmSync29(resetLockPath(), { force: true });
|
|
293973
294173
|
}
|
|
293974
294174
|
function runForward(cmd, argv) {
|
|
293975
294175
|
const frame = currentEvidenceFrame();
|
|
@@ -293987,7 +294187,7 @@ function runForward(cmd, argv) {
|
|
|
293987
294187
|
}
|
|
293988
294188
|
function readTestScript(cwd) {
|
|
293989
294189
|
const p = join168(cwd, "package.json");
|
|
293990
|
-
if (!
|
|
294190
|
+
if (!existsSync145(p))
|
|
293991
294191
|
return void 0;
|
|
293992
294192
|
try {
|
|
293993
294193
|
const pkg = JSON.parse(readFileSync145(p, "utf8"));
|
|
@@ -294001,7 +294201,7 @@ function detectVitestVersion(cwd) {
|
|
|
294001
294201
|
let dir = cwd;
|
|
294002
294202
|
for (let i = 0; i < 6; i++) {
|
|
294003
294203
|
const vp = join168(dir, "node_modules", "vitest", "package.json");
|
|
294004
|
-
if (
|
|
294204
|
+
if (existsSync145(vp)) {
|
|
294005
294205
|
try {
|
|
294006
294206
|
const v = JSON.parse(readFileSync145(vp, "utf8")).version;
|
|
294007
294207
|
if (typeof v === "string")
|
|
@@ -294039,14 +294239,14 @@ function writeTestProof(cwd, mode, command) {
|
|
|
294039
294239
|
function ensureSkillsSubmoduleReady() {
|
|
294040
294240
|
const pkg = rollPkgDir();
|
|
294041
294241
|
const required2 = join168(pkg, "skills", "roll-onboard", "SKILL.md");
|
|
294042
|
-
if (
|
|
294242
|
+
if (existsSync145(required2))
|
|
294043
294243
|
return true;
|
|
294044
|
-
if (
|
|
294244
|
+
if (existsSync145(join168(pkg, ".git")) && existsSync145(join168(pkg, ".gitmodules"))) {
|
|
294045
294245
|
spawnSync20("git", ["submodule", "update", "--init", "--recursive", "--quiet", "skills"], {
|
|
294046
294246
|
cwd: pkg,
|
|
294047
294247
|
stdio: "ignore"
|
|
294048
294248
|
});
|
|
294049
|
-
if (
|
|
294249
|
+
if (existsSync145(required2))
|
|
294050
294250
|
return true;
|
|
294051
294251
|
}
|
|
294052
294252
|
err14("roll test: skills submodule is empty");
|
|
@@ -294055,7 +294255,7 @@ function ensureSkillsSubmoduleReady() {
|
|
|
294055
294255
|
}
|
|
294056
294256
|
function ensureNoneIsolation() {
|
|
294057
294257
|
const type = isolationGetType();
|
|
294058
|
-
if (type === "none" && !
|
|
294258
|
+
if (type === "none" && !existsSync145(join168(process.cwd(), ".roll", "local.yaml"))) {
|
|
294059
294259
|
infoErr("isolation: no test_isolation config, falling back to type=none (host)");
|
|
294060
294260
|
}
|
|
294061
294261
|
if (!SUPPORTED_TYPES.includes(type)) {
|
|
@@ -294170,7 +294370,7 @@ function testCommand(args) {
|
|
|
294170
294370
|
}
|
|
294171
294371
|
const cwd = process.cwd();
|
|
294172
294372
|
const resolution = resolveGateCommand({
|
|
294173
|
-
hasPackageJson:
|
|
294373
|
+
hasPackageJson: existsSync145(join168(cwd, "package.json")),
|
|
294174
294374
|
testScript: readTestScript(cwd),
|
|
294175
294375
|
vitestVersion: detectVitestVersion(cwd)
|
|
294176
294376
|
});
|
|
@@ -294596,7 +294796,7 @@ function emitRepair(json, outcome) {
|
|
|
294596
294796
|
// packages/cli/dist/commands/truth.js
|
|
294597
294797
|
init_dist();
|
|
294598
294798
|
init_dist2();
|
|
294599
|
-
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";
|
|
294600
294800
|
import { dirname as dirname81, join as join171 } from "node:path";
|
|
294601
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";
|
|
294602
294802
|
function formatTruth(t2, lang10) {
|
|
@@ -294644,7 +294844,7 @@ function truthAuditCommand(args, lang10) {
|
|
|
294644
294844
|
const cwd = process.cwd();
|
|
294645
294845
|
const nowSec = Math.floor(Date.now() / 1e3);
|
|
294646
294846
|
const backlogPath = join171(cwd, ".roll", "backlog.md");
|
|
294647
|
-
const backlogRows =
|
|
294847
|
+
const backlogRows = existsSync146(backlogPath) ? parseBacklog(readFileSync147(backlogPath, "utf8")).map((r) => ({ id: r.id, status: r.status })) : [];
|
|
294648
294848
|
const deliveries = ensureDeliveriesFresh(cwd, nodeFreshnessPort4, nodeExecPort);
|
|
294649
294849
|
const snapshot = emptyAuditSnapshot(nowSec, TERMINAL_SCHEMA_EPOCH_SEC);
|
|
294650
294850
|
snapshot.backlog = backlogRows;
|
|
@@ -294729,7 +294929,7 @@ function truthCommand(args) {
|
|
|
294729
294929
|
|
|
294730
294930
|
// packages/cli/dist/commands/tune.js
|
|
294731
294931
|
init_dist2();
|
|
294732
|
-
import { existsSync as
|
|
294932
|
+
import { existsSync as existsSync147, readFileSync as readFileSync148 } from "node:fs";
|
|
294733
294933
|
import { join as join172 } from "node:path";
|
|
294734
294934
|
function projectPath2() {
|
|
294735
294935
|
return (process.env["ROLL_MAIN_PROJECT"] ?? "").trim() || process.cwd();
|
|
@@ -294738,7 +294938,7 @@ function str6(v, dflt = "") {
|
|
|
294738
294938
|
return typeof v === "string" ? v : dflt;
|
|
294739
294939
|
}
|
|
294740
294940
|
function parseJsonl(path) {
|
|
294741
|
-
if (!
|
|
294941
|
+
if (!existsSync147(path))
|
|
294742
294942
|
return [];
|
|
294743
294943
|
let text2;
|
|
294744
294944
|
try {
|
|
@@ -294914,7 +295114,7 @@ function tuneCommand(argv) {
|
|
|
294914
295114
|
// packages/cli/dist/commands/update.js
|
|
294915
295115
|
init_dist();
|
|
294916
295116
|
import { spawnSync as spawnSync21 } from "node:child_process";
|
|
294917
|
-
import { existsSync as
|
|
295117
|
+
import { existsSync as existsSync148, mkdtempSync as mkdtempSync10, readFileSync as readFileSync149, rmSync as rmSync30 } from "node:fs";
|
|
294918
295118
|
import { tmpdir as tmpdir14 } from "node:os";
|
|
294919
295119
|
import { join as join173 } from "node:path";
|
|
294920
295120
|
function pal7() {
|
|
@@ -295004,7 +295204,7 @@ function downloadAndInstallCurl(tag) {
|
|
|
295004
295204
|
}
|
|
295005
295205
|
return { ok: true, newVersion: treeVersion(extractDir) };
|
|
295006
295206
|
} finally {
|
|
295007
|
-
|
|
295207
|
+
rmSync30(tmpDir, { recursive: true, force: true });
|
|
295008
295208
|
}
|
|
295009
295209
|
}
|
|
295010
295210
|
function checkInstalledVersionOrRetry() {
|
|
@@ -295024,11 +295224,11 @@ function checkInstalledVersionOrRetry() {
|
|
|
295024
295224
|
}
|
|
295025
295225
|
}
|
|
295026
295226
|
function invalidateUpdateCache() {
|
|
295027
|
-
|
|
295227
|
+
rmSync30(join173(rollHome(), ".update-check"), { force: true });
|
|
295028
295228
|
}
|
|
295029
295229
|
function showChangelog() {
|
|
295030
295230
|
const changelog = join173(rollPkgDir(), "CHANGELOG.md");
|
|
295031
|
-
if (!
|
|
295231
|
+
if (!existsSync148(changelog))
|
|
295032
295232
|
return;
|
|
295033
295233
|
const { BOLD: BOLD2, CYAN, NC } = pal7();
|
|
295034
295234
|
process.stdout.write(`${BOLD2}${m6("changelog.heading")}:${NC}
|
|
@@ -295059,7 +295259,7 @@ async function updateCommand(args) {
|
|
|
295059
295259
|
info5(m6("update.current_version", rollVersion()));
|
|
295060
295260
|
let installMethod = "npm";
|
|
295061
295261
|
const methodFile = join173(rollPkgDir(), ".install-method");
|
|
295062
|
-
if (
|
|
295262
|
+
if (existsSync148(methodFile)) {
|
|
295063
295263
|
installMethod = readFileSync149(methodFile, "utf8").trim() || "npm";
|
|
295064
295264
|
}
|
|
295065
295265
|
if (installMethod === "curl") {
|