@seanyao/roll 4.710.2 → 4.710.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 +676 -433
- package/package.json +1 -1
package/dist/roll.mjs
CHANGED
|
@@ -8928,6 +8928,32 @@ var init_activity_signal = __esm({
|
|
|
8928
8928
|
}
|
|
8929
8929
|
});
|
|
8930
8930
|
|
|
8931
|
+
// packages/core/dist/loop/adversarial.js
|
|
8932
|
+
function adversarialNextStep(state, lastRound, cfg) {
|
|
8933
|
+
if (cfg.elapsedSec >= cfg.totalTimeoutSec) {
|
|
8934
|
+
return { kind: "stop", reason: "timeout" };
|
|
8935
|
+
}
|
|
8936
|
+
if (state.round >= cfg.maxRounds) {
|
|
8937
|
+
return { kind: "stop", reason: "max_rounds" };
|
|
8938
|
+
}
|
|
8939
|
+
if (lastRound === null) {
|
|
8940
|
+
return { kind: "attack" };
|
|
8941
|
+
}
|
|
8942
|
+
if (lastRound.newHole) {
|
|
8943
|
+
return { kind: "fix" };
|
|
8944
|
+
}
|
|
8945
|
+
const effectiveDry = state.dryStreak + 1;
|
|
8946
|
+
if (effectiveDry >= cfg.dryRoundsToStop) {
|
|
8947
|
+
return { kind: "stop", reason: "dry" };
|
|
8948
|
+
}
|
|
8949
|
+
return { kind: "attack" };
|
|
8950
|
+
}
|
|
8951
|
+
var init_adversarial = __esm({
|
|
8952
|
+
"packages/core/dist/loop/adversarial.js"() {
|
|
8953
|
+
"use strict";
|
|
8954
|
+
}
|
|
8955
|
+
});
|
|
8956
|
+
|
|
8931
8957
|
// packages/core/dist/loop/alert-loop.js
|
|
8932
8958
|
function alertFileName(slug3) {
|
|
8933
8959
|
return `ALERT-${slug3}.md`;
|
|
@@ -12977,19 +13003,40 @@ function cycleStep(state, event) {
|
|
|
12977
13003
|
{ kind: "resolve_route", storyId: event.storyId }
|
|
12978
13004
|
]
|
|
12979
13005
|
};
|
|
12980
|
-
case "route_resolved":
|
|
13006
|
+
case "route_resolved": {
|
|
13007
|
+
const execCtx = { ...state.ctx, agent: event.agent, model: event.model };
|
|
13008
|
+
const startCmd = { kind: "emit_event", event: cycleStartEvent(execCtx) };
|
|
13009
|
+
if (event.adversarial !== void 0) {
|
|
13010
|
+
const plan = event.adversarial;
|
|
13011
|
+
return {
|
|
13012
|
+
state: {
|
|
13013
|
+
...state,
|
|
13014
|
+
phase: "execute",
|
|
13015
|
+
attempt: 1,
|
|
13016
|
+
ctx: execCtx,
|
|
13017
|
+
adversarial: {
|
|
13018
|
+
plan,
|
|
13019
|
+
round: 0,
|
|
13020
|
+
dryStreak: 0,
|
|
13021
|
+
holesFound: 0,
|
|
13022
|
+
attackTests: [],
|
|
13023
|
+
inFlight: "test_author",
|
|
13024
|
+
implementedInitial: false
|
|
13025
|
+
}
|
|
13026
|
+
},
|
|
13027
|
+
commands: [startCmd, { kind: "spawn_role", role: "test_author", agent: plan.testAuthor, round: 0 }]
|
|
13028
|
+
};
|
|
13029
|
+
}
|
|
12981
13030
|
return {
|
|
12982
13031
|
state: {
|
|
12983
13032
|
...state,
|
|
12984
13033
|
phase: "execute",
|
|
12985
13034
|
attempt: 1,
|
|
12986
|
-
ctx:
|
|
13035
|
+
ctx: execCtx
|
|
12987
13036
|
},
|
|
12988
|
-
commands: [
|
|
12989
|
-
{ kind: "emit_event", event: cycleStartEvent({ ...state.ctx, agent: event.agent, model: event.model }) },
|
|
12990
|
-
{ kind: "spawn_agent", agent: event.agent, attempt: 1 }
|
|
12991
|
-
]
|
|
13037
|
+
commands: [startCmd, { kind: "spawn_agent", agent: event.agent, attempt: 1 }]
|
|
12992
13038
|
};
|
|
13039
|
+
}
|
|
12993
13040
|
case "route_pending":
|
|
12994
13041
|
return terminate({ ...state, phase: "route" }, "pending_rig_recovery", [
|
|
12995
13042
|
{ kind: "cleanup_environment" },
|
|
@@ -13026,6 +13073,83 @@ function cycleStep(state, event) {
|
|
|
13026
13073
|
commands: [{ kind: "capture_facts" }]
|
|
13027
13074
|
};
|
|
13028
13075
|
}
|
|
13076
|
+
case "role_exited": {
|
|
13077
|
+
const adv = state.adversarial;
|
|
13078
|
+
if (adv === void 0) {
|
|
13079
|
+
return { state, commands: [] };
|
|
13080
|
+
}
|
|
13081
|
+
const cid = state.ctx.cycleId;
|
|
13082
|
+
const sid = state.ctx.storyId ?? "";
|
|
13083
|
+
if (event.exit !== 0 || event.timedOut) {
|
|
13084
|
+
return {
|
|
13085
|
+
state: { ...state, phase: "reconcile", ctx: { ...state.ctx, agentExitCode: event.exit, agentTimedOut: event.timedOut } },
|
|
13086
|
+
commands: [{ kind: "capture_facts" }]
|
|
13087
|
+
};
|
|
13088
|
+
}
|
|
13089
|
+
const cfg = {
|
|
13090
|
+
maxRounds: adv.plan.maxRounds,
|
|
13091
|
+
dryRoundsToStop: adv.plan.dryRoundsToStop,
|
|
13092
|
+
elapsedSec: event.elapsedSec ?? 0,
|
|
13093
|
+
totalTimeoutSec: adv.plan.totalTimeoutSec
|
|
13094
|
+
};
|
|
13095
|
+
const terminatedCmd = (reason, rounds, holesFound2) => ({
|
|
13096
|
+
kind: "emit_event",
|
|
13097
|
+
event: { type: "adversarial:terminated", cycleId: cid, storyId: sid, reason, rounds, holesFound: holesFound2, ts: 0 }
|
|
13098
|
+
});
|
|
13099
|
+
if (adv.inFlight === "test_author") {
|
|
13100
|
+
return {
|
|
13101
|
+
state: { ...state, adversarial: { ...adv, inFlight: "implementer" } },
|
|
13102
|
+
commands: [
|
|
13103
|
+
{ kind: "emit_event", event: { type: "adversarial:test-authored", cycleId: cid, storyId: sid, agent: adv.plan.testAuthor, ts: 0 } },
|
|
13104
|
+
{ kind: "spawn_role", role: "implementer", agent: adv.plan.implementer, round: adv.round }
|
|
13105
|
+
]
|
|
13106
|
+
};
|
|
13107
|
+
}
|
|
13108
|
+
if (adv.inFlight === "implementer") {
|
|
13109
|
+
const step2 = adversarialNextStep({ round: adv.round, dryStreak: adv.dryStreak }, null, cfg);
|
|
13110
|
+
const cmds = [];
|
|
13111
|
+
if (!adv.implementedInitial) {
|
|
13112
|
+
cmds.push({
|
|
13113
|
+
kind: "emit_event",
|
|
13114
|
+
event: { type: "adversarial:implemented", cycleId: cid, storyId: sid, agent: adv.plan.implementer, round: adv.round, ts: 0 }
|
|
13115
|
+
});
|
|
13116
|
+
}
|
|
13117
|
+
if (step2.kind === "stop") {
|
|
13118
|
+
cmds.push(terminatedCmd(step2.reason, adv.round, adv.holesFound));
|
|
13119
|
+
cmds.push({ kind: "capture_facts" });
|
|
13120
|
+
return { state: { ...state, phase: "reconcile", adversarial: { ...adv, implementedInitial: true } }, commands: cmds };
|
|
13121
|
+
}
|
|
13122
|
+
const nextRound = adv.round + 1;
|
|
13123
|
+
cmds.push({ kind: "spawn_role", role: "attacker", agent: adv.plan.testAuthor, round: nextRound });
|
|
13124
|
+
return { state: { ...state, adversarial: { ...adv, round: nextRound, inFlight: "attacker", implementedInitial: true } }, commands: cmds };
|
|
13125
|
+
}
|
|
13126
|
+
const newHole = event.newHole === true;
|
|
13127
|
+
const holesFound = newHole ? adv.holesFound + 1 : adv.holesFound;
|
|
13128
|
+
const attackTests = newHole && event.attackTest !== void 0 && event.attackTest !== "" ? [...adv.attackTests, event.attackTest] : adv.attackTests;
|
|
13129
|
+
const reportedDryStreak = newHole ? 0 : adv.dryStreak + 1;
|
|
13130
|
+
const attackEvent = {
|
|
13131
|
+
kind: "emit_event",
|
|
13132
|
+
event: { type: "adversarial:attack-round", cycleId: cid, storyId: sid, agent: adv.plan.testAuthor, round: adv.round, newHole, dryStreak: reportedDryStreak, ts: 0 }
|
|
13133
|
+
};
|
|
13134
|
+
const step = adversarialNextStep({ round: adv.round, dryStreak: adv.dryStreak }, { newHole }, cfg);
|
|
13135
|
+
if (step.kind === "fix") {
|
|
13136
|
+
return {
|
|
13137
|
+
state: { ...state, adversarial: { ...adv, dryStreak: 0, holesFound, attackTests, inFlight: "implementer" } },
|
|
13138
|
+
commands: [attackEvent, { kind: "spawn_role", role: "implementer", agent: adv.plan.implementer, round: adv.round }]
|
|
13139
|
+
};
|
|
13140
|
+
}
|
|
13141
|
+
if (step.kind === "attack") {
|
|
13142
|
+
const nextRound = adv.round + 1;
|
|
13143
|
+
return {
|
|
13144
|
+
state: { ...state, adversarial: { ...adv, round: nextRound, dryStreak: reportedDryStreak, holesFound, attackTests, inFlight: "attacker" } },
|
|
13145
|
+
commands: [attackEvent, { kind: "spawn_role", role: "attacker", agent: adv.plan.testAuthor, round: nextRound }]
|
|
13146
|
+
};
|
|
13147
|
+
}
|
|
13148
|
+
return {
|
|
13149
|
+
state: { ...state, phase: "reconcile", adversarial: { ...adv, dryStreak: reportedDryStreak, holesFound, attackTests } },
|
|
13150
|
+
commands: [attackEvent, terminatedCmd(step.reason, adv.round, holesFound), { kind: "capture_facts" }]
|
|
13151
|
+
};
|
|
13152
|
+
}
|
|
13029
13153
|
case "facts_captured": {
|
|
13030
13154
|
const status2 = classifyCaptured(event.facts);
|
|
13031
13155
|
const nextCtx = status2 === "agent_internal" ? {
|
|
@@ -13231,6 +13355,7 @@ var init_orchestrator = __esm({
|
|
|
13231
13355
|
"use strict";
|
|
13232
13356
|
init_tracker();
|
|
13233
13357
|
init_builder_finalization();
|
|
13358
|
+
init_adversarial();
|
|
13234
13359
|
init_pr();
|
|
13235
13360
|
init_gate();
|
|
13236
13361
|
CYCLE_TIMEOUT_SEC = 2700;
|
|
@@ -13250,6 +13375,7 @@ var init_orchestrator = __esm({
|
|
|
13250
13375
|
route_resolved: ["route"],
|
|
13251
13376
|
route_pending: ["route"],
|
|
13252
13377
|
agent_exited: ["execute"],
|
|
13378
|
+
role_exited: ["execute"],
|
|
13253
13379
|
facts_captured: ["reconcile"],
|
|
13254
13380
|
published: ["publish"],
|
|
13255
13381
|
merge_polled: ["merge-wait", "publish"],
|
|
@@ -18020,6 +18146,7 @@ var init_dist2 = __esm({
|
|
|
18020
18146
|
init_bus();
|
|
18021
18147
|
init_infra_default3();
|
|
18022
18148
|
init_activity_signal();
|
|
18149
|
+
init_adversarial();
|
|
18023
18150
|
init_alert_loop();
|
|
18024
18151
|
init_branch_canary();
|
|
18025
18152
|
init_remote_branch_gc();
|
|
@@ -235788,9 +235915,9 @@ __export(showcase_exports, {
|
|
|
235788
235915
|
showcaseCommand: () => showcaseCommand
|
|
235789
235916
|
});
|
|
235790
235917
|
import { spawnSync as spawnSync17 } from "node:child_process";
|
|
235791
|
-
import { cpSync as cpSync3, existsSync as
|
|
235918
|
+
import { cpSync as cpSync3, existsSync as existsSync129, mkdirSync as mkdirSync71, mkdtempSync as mkdtempSync9, readdirSync as readdirSync50, readFileSync as readFileSync130, rmSync as rmSync24, statSync as statSync40, writeFileSync as writeFileSync71 } from "node:fs";
|
|
235792
235919
|
import { tmpdir as tmpdir12 } from "node:os";
|
|
235793
|
-
import { dirname as
|
|
235920
|
+
import { dirname as dirname71, join as join145 } from "node:path";
|
|
235794
235921
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
235795
235922
|
function parseArgs3(args) {
|
|
235796
235923
|
const opts = {
|
|
@@ -235829,11 +235956,11 @@ function parseArgs3(args) {
|
|
|
235829
235956
|
return opts;
|
|
235830
235957
|
}
|
|
235831
235958
|
function packageRoot() {
|
|
235832
|
-
let dir =
|
|
235959
|
+
let dir = dirname71(fileURLToPath3(import.meta.url));
|
|
235833
235960
|
for (let i = 0; i < 12; i++) {
|
|
235834
|
-
if (
|
|
235961
|
+
if (existsSync129(join145(dir, "conventions")))
|
|
235835
235962
|
return dir;
|
|
235836
|
-
const parent =
|
|
235963
|
+
const parent = dirname71(dir);
|
|
235837
235964
|
if (parent === dir)
|
|
235838
235965
|
break;
|
|
235839
235966
|
dir = parent;
|
|
@@ -235841,8 +235968,8 @@ function packageRoot() {
|
|
|
235841
235968
|
return dir;
|
|
235842
235969
|
}
|
|
235843
235970
|
function rollBin3() {
|
|
235844
|
-
const devPath =
|
|
235845
|
-
if (
|
|
235971
|
+
const devPath = join145(packageRoot(), "packages", "cli", "bin", "roll.js");
|
|
235972
|
+
if (existsSync129(devPath))
|
|
235846
235973
|
return devPath;
|
|
235847
235974
|
return "roll";
|
|
235848
235975
|
}
|
|
@@ -235869,30 +235996,30 @@ function runRoll(sandbox, rollHome4, args, opts = {}) {
|
|
|
235869
235996
|
}
|
|
235870
235997
|
function fileNonEmpty3(p) {
|
|
235871
235998
|
try {
|
|
235872
|
-
return
|
|
235999
|
+
return existsSync129(p) && statSync40(p).size > 0;
|
|
235873
236000
|
} catch {
|
|
235874
236001
|
return false;
|
|
235875
236002
|
}
|
|
235876
236003
|
}
|
|
235877
236004
|
function makeSandbox(sourceProject) {
|
|
235878
|
-
const root = mkdtempSync9(
|
|
235879
|
-
const sandbox =
|
|
235880
|
-
const rollHome4 =
|
|
236005
|
+
const root = mkdtempSync9(join145(tmpdir12(), "roll-showcase-"));
|
|
236006
|
+
const sandbox = join145(root, "project");
|
|
236007
|
+
const rollHome4 = join145(root, "home");
|
|
235881
236008
|
mkdirSync71(sandbox, { recursive: true });
|
|
235882
236009
|
mkdirSync71(rollHome4, { recursive: true });
|
|
235883
|
-
const srcRoll =
|
|
235884
|
-
if (
|
|
235885
|
-
cpSync3(srcRoll,
|
|
236010
|
+
const srcRoll = join145(sourceProject, ".roll");
|
|
236011
|
+
if (existsSync129(srcRoll)) {
|
|
236012
|
+
cpSync3(srcRoll, join145(sandbox, ".roll"), { recursive: true });
|
|
235886
236013
|
} else {
|
|
235887
|
-
mkdirSync71(
|
|
236014
|
+
mkdirSync71(join145(sandbox, ".roll", "features"), { recursive: true });
|
|
235888
236015
|
}
|
|
235889
236016
|
return { sandbox, rollHome: rollHome4 };
|
|
235890
236017
|
}
|
|
235891
236018
|
function findCardSpec2(sandbox, card) {
|
|
235892
|
-
const featuresDir =
|
|
236019
|
+
const featuresDir = join145(sandbox, ".roll", "features");
|
|
235893
236020
|
const candidates = [];
|
|
235894
236021
|
const walk2 = (dir, depth) => {
|
|
235895
|
-
if (depth > 3 || !
|
|
236022
|
+
if (depth > 3 || !existsSync129(dir))
|
|
235896
236023
|
return;
|
|
235897
236024
|
let entries = [];
|
|
235898
236025
|
try {
|
|
@@ -235901,7 +236028,7 @@ function findCardSpec2(sandbox, card) {
|
|
|
235901
236028
|
return;
|
|
235902
236029
|
}
|
|
235903
236030
|
for (const name of entries) {
|
|
235904
|
-
const full =
|
|
236031
|
+
const full = join145(dir, name);
|
|
235905
236032
|
let isDir4 = false;
|
|
235906
236033
|
try {
|
|
235907
236034
|
isDir4 = statSync40(full).isDirectory();
|
|
@@ -235909,8 +236036,8 @@ function findCardSpec2(sandbox, card) {
|
|
|
235909
236036
|
continue;
|
|
235910
236037
|
}
|
|
235911
236038
|
if (isDir4) {
|
|
235912
|
-
if (name === card &&
|
|
235913
|
-
candidates.push(
|
|
236039
|
+
if (name === card && existsSync129(join145(full, "spec.md")))
|
|
236040
|
+
candidates.push(join145(full, "spec.md"));
|
|
235914
236041
|
walk2(full, depth + 1);
|
|
235915
236042
|
}
|
|
235916
236043
|
}
|
|
@@ -235922,9 +236049,9 @@ function resetSandbox(sandbox, card) {
|
|
|
235922
236049
|
const notes = [];
|
|
235923
236050
|
let reset2 = false;
|
|
235924
236051
|
let ok12 = false;
|
|
235925
|
-
const backlogPath =
|
|
235926
|
-
if (
|
|
235927
|
-
const before =
|
|
236052
|
+
const backlogPath = join145(sandbox, ".roll", "backlog.md");
|
|
236053
|
+
if (existsSync129(backlogPath)) {
|
|
236054
|
+
const before = readFileSync130(backlogPath, "utf8");
|
|
235928
236055
|
const cardRow = before.split("\n").find((line) => line.startsWith("|") && line.includes(card));
|
|
235929
236056
|
const hadStatusToken = cardRow !== void 0 && statusMarkerRe(false).test(cardRow);
|
|
235930
236057
|
const alreadyTodo = cardRow !== void 0 && findStatusMarker(cardRow) === STATUS_MARKER.todo;
|
|
@@ -235951,24 +236078,24 @@ function resetSandbox(sandbox, card) {
|
|
|
235951
236078
|
} else {
|
|
235952
236079
|
notes.push("backlog: .roll/backlog.md absent");
|
|
235953
236080
|
}
|
|
235954
|
-
const pulseCmd =
|
|
235955
|
-
if (
|
|
235956
|
-
|
|
236081
|
+
const pulseCmd = join145(sandbox, "packages", "cli", "src", "commands", "pulse.ts");
|
|
236082
|
+
if (existsSync129(pulseCmd)) {
|
|
236083
|
+
rmSync24(pulseCmd, { force: true });
|
|
235957
236084
|
notes.push("removed prior pulse.ts surface");
|
|
235958
236085
|
}
|
|
235959
236086
|
return { ok: ok12, reset: reset2, notes };
|
|
235960
236087
|
}
|
|
235961
236088
|
function writeCasting(sandbox, casting) {
|
|
235962
|
-
const agentsPath =
|
|
235963
|
-
mkdirSync71(
|
|
236089
|
+
const agentsPath = join145(sandbox, ".roll", "agents.yaml");
|
|
236090
|
+
mkdirSync71(dirname71(agentsPath), { recursive: true });
|
|
235964
236091
|
writeFileSync71(agentsPath, castingAgentsYaml(casting), "utf8");
|
|
235965
236092
|
}
|
|
235966
236093
|
async function captureScreenshots(sandbox, card) {
|
|
235967
236094
|
const shots = [];
|
|
235968
236095
|
const infra = await Promise.resolve().then(() => (init_dist3(), dist_exports));
|
|
235969
|
-
const shotDir =
|
|
236096
|
+
const shotDir = join145(sandbox, ".roll", "showcase", card, "screenshots");
|
|
235970
236097
|
mkdirSync71(shotDir, { recursive: true });
|
|
235971
|
-
const cliOut =
|
|
236098
|
+
const cliOut = join145(shotDir, "pulse-cli.png");
|
|
235972
236099
|
const cli = await infra.captureScreenshot({
|
|
235973
236100
|
kind: "terminal",
|
|
235974
236101
|
out: cliOut,
|
|
@@ -235980,12 +236107,12 @@ async function captureScreenshots(sandbox, card) {
|
|
|
235980
236107
|
present: cli.taken && fileNonEmpty3(cliOut),
|
|
235981
236108
|
...cli.skipped !== void 0 ? { skipped: cli.skipped } : {}
|
|
235982
236109
|
});
|
|
235983
|
-
const nowPage =
|
|
235984
|
-
const webOut =
|
|
236110
|
+
const nowPage = join145(sandbox, ".roll", "features", "index.html");
|
|
236111
|
+
const webOut = join145(shotDir, "now-pulse-badge.png");
|
|
235985
236112
|
const web = await infra.captureScreenshot({
|
|
235986
236113
|
kind: "web",
|
|
235987
236114
|
out: webOut,
|
|
235988
|
-
url:
|
|
236115
|
+
url: existsSync129(nowPage) ? `file://${nowPage}#now` : "about:blank"
|
|
235989
236116
|
});
|
|
235990
236117
|
shots.push({
|
|
235991
236118
|
surface: "web",
|
|
@@ -235996,10 +236123,10 @@ async function captureScreenshots(sandbox, card) {
|
|
|
235996
236123
|
return shots;
|
|
235997
236124
|
}
|
|
235998
236125
|
function readBacklogStatus(sandbox, card) {
|
|
235999
|
-
const backlogPath =
|
|
236000
|
-
if (!
|
|
236126
|
+
const backlogPath = join145(sandbox, ".roll", "backlog.md");
|
|
236127
|
+
if (!existsSync129(backlogPath))
|
|
236001
236128
|
return void 0;
|
|
236002
|
-
for (const line of
|
|
236129
|
+
for (const line of readFileSync130(backlogPath, "utf8").split("\n")) {
|
|
236003
236130
|
if (line.startsWith("|") && line.includes(card)) {
|
|
236004
236131
|
const marker = findStatusMarker(line);
|
|
236005
236132
|
if (marker !== void 0)
|
|
@@ -236009,11 +236136,11 @@ function readBacklogStatus(sandbox, card) {
|
|
|
236009
236136
|
return void 0;
|
|
236010
236137
|
}
|
|
236011
236138
|
function readTruthLadder(sandbox, card) {
|
|
236012
|
-
const truthPath =
|
|
236013
|
-
if (!
|
|
236139
|
+
const truthPath = join145(sandbox, ".roll", "features", "truth.json");
|
|
236140
|
+
if (!existsSync129(truthPath))
|
|
236014
236141
|
return void 0;
|
|
236015
236142
|
try {
|
|
236016
|
-
const snap = JSON.parse(
|
|
236143
|
+
const snap = JSON.parse(readFileSync130(truthPath, "utf8"));
|
|
236017
236144
|
const row2 = (snap.stories ?? []).find((s) => s.id === card);
|
|
236018
236145
|
return row2?.ladder;
|
|
236019
236146
|
} catch {
|
|
@@ -236021,12 +236148,12 @@ function readTruthLadder(sandbox, card) {
|
|
|
236021
236148
|
}
|
|
236022
236149
|
}
|
|
236023
236150
|
function readTcrCommits(sandbox) {
|
|
236024
|
-
const runsPath3 =
|
|
236025
|
-
if (!
|
|
236151
|
+
const runsPath3 = join145(sandbox, ".roll", "loop", "runs.jsonl");
|
|
236152
|
+
if (!existsSync129(runsPath3))
|
|
236026
236153
|
return [];
|
|
236027
236154
|
const out3 = [];
|
|
236028
236155
|
try {
|
|
236029
|
-
const lines3 =
|
|
236156
|
+
const lines3 = readFileSync130(runsPath3, "utf8").trim().split("\n").filter(Boolean);
|
|
236030
236157
|
const last = lines3[lines3.length - 1];
|
|
236031
236158
|
if (last === void 0)
|
|
236032
236159
|
return [];
|
|
@@ -236105,7 +236232,7 @@ ${msg6}
|
|
|
236105
236232
|
const backlogStatus = readBacklogStatus(sandbox, card);
|
|
236106
236233
|
const truthLadder = readTruthLadder(sandbox, card);
|
|
236107
236234
|
const tcrCommits = readTcrCommits(sandbox);
|
|
236108
|
-
const reportPath =
|
|
236235
|
+
const reportPath = join145(sandbox, ".roll", "features");
|
|
236109
236236
|
const gate = parseAttestGate(attest.stdout + attest.stderr);
|
|
236110
236237
|
const run = {
|
|
236111
236238
|
casting,
|
|
@@ -236165,7 +236292,7 @@ ROLL_HOME: ${rollHome4}
|
|
|
236165
236292
|
return 1;
|
|
236166
236293
|
} finally {
|
|
236167
236294
|
if (!keepSandbox) {
|
|
236168
|
-
|
|
236295
|
+
rmSync24(dirname71(sandbox), { recursive: true, force: true });
|
|
236169
236296
|
}
|
|
236170
236297
|
}
|
|
236171
236298
|
}
|
|
@@ -237380,6 +237507,20 @@ function agentCredentialReadiness(agent, env = process.env, home) {
|
|
|
237380
237507
|
});
|
|
237381
237508
|
return { agent: canonical, requiredEnv, missingEnv, ok: missingEnv.length === 0 };
|
|
237382
237509
|
}
|
|
237510
|
+
function adversarialRolePrompt(role) {
|
|
237511
|
+
switch (role) {
|
|
237512
|
+
case "test_author":
|
|
237513
|
+
return "You are the test author. Write failing red tests from the AC acceptance contract; do not write production code and do not read the implementation.";
|
|
237514
|
+
case "implementer":
|
|
237515
|
+
return "You are the implementer. Write only production code to make the failing tests pass; do not modify, edit, touch, or change any test files.";
|
|
237516
|
+
case "attacker":
|
|
237517
|
+
return "You are the attacker. Add only new breaking tests, each targeting one untested failure mode; do not edit or modify existing tests or production code.";
|
|
237518
|
+
default: {
|
|
237519
|
+
const exhaustive = role;
|
|
237520
|
+
throw new Error(`adversarialRolePrompt: unknown role ${String(exhaustive)}`);
|
|
237521
|
+
}
|
|
237522
|
+
}
|
|
237523
|
+
}
|
|
237383
237524
|
function agentSpawnSupportsPurpose(spawn10, purpose) {
|
|
237384
237525
|
return spawn10.supportedPurposes?.includes(purpose) === true;
|
|
237385
237526
|
}
|
|
@@ -254671,8 +254812,8 @@ function writeSet(runtimeDir12, set) {
|
|
|
254671
254812
|
writeFileSync30(tmp, JSON.stringify([...set].sort(), null, 2), "utf8");
|
|
254672
254813
|
writeFileSync30(path, readFileSync55(tmp, "utf8"), "utf8");
|
|
254673
254814
|
try {
|
|
254674
|
-
const { rmSync:
|
|
254675
|
-
|
|
254815
|
+
const { rmSync: rmSync28 } = __require("node:fs");
|
|
254816
|
+
rmSync28(tmp, { force: true });
|
|
254676
254817
|
} catch {
|
|
254677
254818
|
}
|
|
254678
254819
|
}
|
|
@@ -271066,8 +271207,8 @@ async function loopExhaustionSplitCommand(argv, deps = realExhaustionSplitDeps()
|
|
|
271066
271207
|
init_dist2();
|
|
271067
271208
|
init_dist();
|
|
271068
271209
|
init_dist3();
|
|
271069
|
-
import { appendFileSync as appendFileSync22, existsSync as
|
|
271070
|
-
import { dirname as
|
|
271210
|
+
import { appendFileSync as appendFileSync22, existsSync as existsSync123, mkdirSync as mkdirSync67, readdirSync as readdirSync45, readFileSync as readFileSync124, writeFileSync as writeFileSync66 } from "node:fs";
|
|
271211
|
+
import { dirname as dirname68, join as join139 } from "node:path";
|
|
271071
271212
|
|
|
271072
271213
|
// packages/cli/dist/runner/executor.js
|
|
271073
271214
|
init_dist2();
|
|
@@ -272085,6 +272226,19 @@ function recordExecutionProfile(ports, cycleId, storyId, estMin) {
|
|
|
272085
272226
|
}
|
|
272086
272227
|
return profile;
|
|
272087
272228
|
}
|
|
272229
|
+
var DEFAULT_ADVERSARIAL_CFG = {
|
|
272230
|
+
maxRounds: 4,
|
|
272231
|
+
dryRoundsToStop: 2,
|
|
272232
|
+
totalTimeoutSec: 2700
|
|
272233
|
+
};
|
|
272234
|
+
function planAdversarial(profile, implementer, activeAgents) {
|
|
272235
|
+
if (profile !== "verified" && profile !== "designed")
|
|
272236
|
+
return void 0;
|
|
272237
|
+
const testAuthor = activeAgents.find((a) => a !== "" && a !== implementer);
|
|
272238
|
+
if (testAuthor === void 0)
|
|
272239
|
+
return void 0;
|
|
272240
|
+
return { testAuthor, implementer, ...DEFAULT_ADVERSARIAL_CFG };
|
|
272241
|
+
}
|
|
272088
272242
|
function writeEvaluatorArtifact(ports, ctx, signals) {
|
|
272089
272243
|
const profile = ctx.selectedProfile;
|
|
272090
272244
|
if (profile !== "verified" && profile !== "designed")
|
|
@@ -272580,7 +272734,16 @@ async function executeSetupCommand(cmd, ports, ctx) {
|
|
|
272580
272734
|
const selectedAgent = active.includes(r.agent) ? r.agent : active[0] ?? r.agent;
|
|
272581
272735
|
const selectedModel = selectedAgent === r.agent ? r.model : "";
|
|
272582
272736
|
const selectedProfile = recordExecutionProfile(ports, ctx.cycleId ?? "", cmd.storyId, estMin);
|
|
272583
|
-
|
|
272737
|
+
const adversarial = planAdversarial(selectedProfile, selectedAgent, active);
|
|
272738
|
+
return {
|
|
272739
|
+
event: {
|
|
272740
|
+
type: "route_resolved",
|
|
272741
|
+
agent: selectedAgent,
|
|
272742
|
+
model: selectedModel,
|
|
272743
|
+
...adversarial !== void 0 ? { adversarial } : {}
|
|
272744
|
+
},
|
|
272745
|
+
ctxPatch: { selectedProfile }
|
|
272746
|
+
};
|
|
272584
272747
|
}
|
|
272585
272748
|
// execute: spawn the agent (TCR commits happen inside the worktree). The
|
|
272586
272749
|
// exit code + timeout feed back as agent_exited; usage is captured for cost.
|
|
@@ -273721,32 +273884,107 @@ ${res.stderr}
|
|
|
273721
273884
|
}
|
|
273722
273885
|
}
|
|
273723
273886
|
|
|
273887
|
+
// packages/cli/dist/runner/spawn-role-handler.js
|
|
273888
|
+
import { existsSync as existsSync110, readFileSync as readFileSync112, rmSync as rmSync21 } from "node:fs";
|
|
273889
|
+
import { dirname as dirname61, join as join128 } from "node:path";
|
|
273890
|
+
function adversarialMarkerPath(ports, cycleId, round) {
|
|
273891
|
+
return join128(dirname61(ports.paths.eventsPath), `adversarial-${cycleId || "cycle"}-round-${round}.json`);
|
|
273892
|
+
}
|
|
273893
|
+
function readAttackMarker(path) {
|
|
273894
|
+
if (!existsSync110(path))
|
|
273895
|
+
return null;
|
|
273896
|
+
try {
|
|
273897
|
+
const parsed = JSON.parse(readFileSync112(path, "utf8"));
|
|
273898
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
273899
|
+
return null;
|
|
273900
|
+
const rec = parsed;
|
|
273901
|
+
const marker = {};
|
|
273902
|
+
if (typeof rec["newHole"] === "boolean")
|
|
273903
|
+
marker.newHole = rec["newHole"];
|
|
273904
|
+
if (typeof rec["attackTest"] === "string")
|
|
273905
|
+
marker.attackTest = rec["attackTest"];
|
|
273906
|
+
return marker;
|
|
273907
|
+
} catch {
|
|
273908
|
+
return null;
|
|
273909
|
+
}
|
|
273910
|
+
}
|
|
273911
|
+
async function executeSpawnRoleCommand(cmd, ports, ctx) {
|
|
273912
|
+
const markerPath2 = adversarialMarkerPath(ports, ctx.cycleId ?? "", cmd.round);
|
|
273913
|
+
try {
|
|
273914
|
+
rmSync21(markerPath2, { force: true });
|
|
273915
|
+
} catch {
|
|
273916
|
+
}
|
|
273917
|
+
const startSec = ports.clock();
|
|
273918
|
+
const rolePrompt = adversarialRolePrompt(cmd.role);
|
|
273919
|
+
const wallSec = readCycleTimeoutThresholds(ports.repoCwd).wallSec;
|
|
273920
|
+
const res = await ports.agentSpawn(cmd.agent, {
|
|
273921
|
+
purpose: cmd.role,
|
|
273922
|
+
cwd: ports.paths.worktreePath,
|
|
273923
|
+
skillBody: `${rolePrompt}
|
|
273924
|
+
|
|
273925
|
+
${ports.skillBody}`,
|
|
273926
|
+
writableRoots: agentWritableRoots(ports.repoCwd, ports.paths.alertsPath),
|
|
273927
|
+
timeoutMs: wallSec * 1e3,
|
|
273928
|
+
...ctx.model !== void 0 && ctx.model !== "" ? { model: ctx.model } : {},
|
|
273929
|
+
...ctx.storyId !== void 0 && ctx.storyId !== "" ? { storyId: ctx.storyId } : {},
|
|
273930
|
+
...ctx.evidenceRunDir !== void 0 ? { runDir: ctx.evidenceRunDir } : {},
|
|
273931
|
+
env: {
|
|
273932
|
+
...process.env,
|
|
273933
|
+
ROLL_LOOP_ALERT: ports.paths.alertsPath,
|
|
273934
|
+
ROLL_ADVERSARIAL_MARKER: markerPath2,
|
|
273935
|
+
...worktreeGitEnv(ports.paths.worktreePath, ports.repoCwd),
|
|
273936
|
+
...agentSpawnEnvironment(cmd.agent)
|
|
273937
|
+
}
|
|
273938
|
+
});
|
|
273939
|
+
const elapsedSec = ctx.startSec !== void 0 && ctx.startSec > 0 ? Math.max(0, ports.clock() - ctx.startSec) : Math.max(0, ports.clock() - startSec);
|
|
273940
|
+
let newHole;
|
|
273941
|
+
let attackTest;
|
|
273942
|
+
if (cmd.role === "attacker") {
|
|
273943
|
+
const marker = readAttackMarker(markerPath2);
|
|
273944
|
+
newHole = marker?.newHole === true;
|
|
273945
|
+
if (newHole && typeof marker?.attackTest === "string" && marker.attackTest !== "") {
|
|
273946
|
+
attackTest = marker.attackTest;
|
|
273947
|
+
}
|
|
273948
|
+
}
|
|
273949
|
+
return {
|
|
273950
|
+
event: {
|
|
273951
|
+
type: "role_exited",
|
|
273952
|
+
role: cmd.role,
|
|
273953
|
+
exit: res.exitCode,
|
|
273954
|
+
timedOut: res.timedOut,
|
|
273955
|
+
elapsedSec,
|
|
273956
|
+
...newHole !== void 0 ? { newHole } : {},
|
|
273957
|
+
...attackTest !== void 0 ? { attackTest } : {}
|
|
273958
|
+
}
|
|
273959
|
+
};
|
|
273960
|
+
}
|
|
273961
|
+
|
|
273724
273962
|
// packages/cli/dist/runner/capture-facts-handler.js
|
|
273725
273963
|
init_dist2();
|
|
273726
273964
|
init_dist();
|
|
273727
273965
|
import { execFile as execFile15 } from "node:child_process";
|
|
273728
|
-
import { existsSync as
|
|
273729
|
-
import { dirname as
|
|
273966
|
+
import { existsSync as existsSync115, mkdirSync as mkdirSync62, readFileSync as readFileSync117, writeFileSync as writeFileSync61 } from "node:fs";
|
|
273967
|
+
import { dirname as dirname64, join as join133 } from "node:path";
|
|
273730
273968
|
import { promisify as promisify15 } from "node:util";
|
|
273731
273969
|
|
|
273732
273970
|
// packages/cli/dist/runner/correction-actuator.js
|
|
273733
273971
|
init_dist2();
|
|
273734
273972
|
init_dist();
|
|
273735
|
-
import { appendFileSync as appendFileSync19, existsSync as
|
|
273736
|
-
import { dirname as
|
|
273973
|
+
import { appendFileSync as appendFileSync19, existsSync as existsSync111, mkdirSync as mkdirSync59, readFileSync as readFileSync113, readdirSync as readdirSync42, writeFileSync as writeFileSync58 } from "node:fs";
|
|
273974
|
+
import { dirname as dirname62, join as join129 } from "node:path";
|
|
273737
273975
|
function readMode(projectPath3) {
|
|
273738
273976
|
try {
|
|
273739
|
-
const path =
|
|
273740
|
-
if (!
|
|
273977
|
+
const path = join129(projectPath3, ".roll", "policy.yaml");
|
|
273978
|
+
if (!existsSync111(path))
|
|
273741
273979
|
return "conservative";
|
|
273742
|
-
return parsePolicy(
|
|
273980
|
+
return parsePolicy(readFileSync113(path, "utf8")).loopSafety.correctionActuator;
|
|
273743
273981
|
} catch {
|
|
273744
273982
|
return "conservative";
|
|
273745
273983
|
}
|
|
273746
273984
|
}
|
|
273747
273985
|
function readEvents7(eventsPath4) {
|
|
273748
273986
|
try {
|
|
273749
|
-
return
|
|
273987
|
+
return readFileSync113(eventsPath4, "utf8").split("\n").map(parseEventLine).filter((ev) => ev !== null);
|
|
273750
273988
|
} catch {
|
|
273751
273989
|
return [];
|
|
273752
273990
|
}
|
|
@@ -273776,7 +274014,7 @@ function reviewConsensus(events, cycleId) {
|
|
|
273776
274014
|
}
|
|
273777
274015
|
function appendEvent(eventsPath4, event) {
|
|
273778
274016
|
try {
|
|
273779
|
-
mkdirSync59(
|
|
274017
|
+
mkdirSync59(dirname62(eventsPath4), { recursive: true });
|
|
273780
274018
|
appendFileSync19(eventsPath4, `${JSON.stringify(event)}
|
|
273781
274019
|
`, "utf8");
|
|
273782
274020
|
} catch {
|
|
@@ -273784,7 +274022,7 @@ function appendEvent(eventsPath4, event) {
|
|
|
273784
274022
|
}
|
|
273785
274023
|
function appendAlert2(alertsPath, msg6) {
|
|
273786
274024
|
try {
|
|
273787
|
-
mkdirSync59(
|
|
274025
|
+
mkdirSync59(dirname62(alertsPath), { recursive: true });
|
|
273788
274026
|
appendFileSync19(alertsPath, `${msg6}
|
|
273789
274027
|
`, "utf8");
|
|
273790
274028
|
} catch {
|
|
@@ -273792,7 +274030,7 @@ function appendAlert2(alertsPath, msg6) {
|
|
|
273792
274030
|
}
|
|
273793
274031
|
function markStoryTodo(projectPath3, storyId) {
|
|
273794
274032
|
try {
|
|
273795
|
-
const path =
|
|
274033
|
+
const path = join129(projectPath3, ".roll", "backlog.md");
|
|
273796
274034
|
const store = new BacklogStore();
|
|
273797
274035
|
const snap = store.readBacklog(path);
|
|
273798
274036
|
const row2 = snap.items.find((it) => it.id === storyId);
|
|
@@ -273808,18 +274046,18 @@ function markStoryTodo(projectPath3, storyId) {
|
|
|
273808
274046
|
}
|
|
273809
274047
|
function storyEpic(projectPath3, storyId) {
|
|
273810
274048
|
try {
|
|
273811
|
-
const idx = JSON.parse(
|
|
274049
|
+
const idx = JSON.parse(readFileSync113(join129(projectPath3, ".roll", "index.json"), "utf8"));
|
|
273812
274050
|
const epic = idx[storyId];
|
|
273813
274051
|
if (typeof epic === "string" && epic.trim() !== "")
|
|
273814
274052
|
return epic;
|
|
273815
274053
|
} catch {
|
|
273816
274054
|
}
|
|
273817
274055
|
try {
|
|
273818
|
-
const features =
|
|
274056
|
+
const features = join129(projectPath3, ".roll", "features");
|
|
273819
274057
|
for (const d of readdirSync42(features, { withFileTypes: true })) {
|
|
273820
274058
|
if (!d.isDirectory())
|
|
273821
274059
|
continue;
|
|
273822
|
-
if (
|
|
274060
|
+
if (existsSync111(join129(features, d.name, storyId)))
|
|
273823
274061
|
return d.name;
|
|
273824
274062
|
}
|
|
273825
274063
|
} catch {
|
|
@@ -273828,7 +274066,7 @@ function storyEpic(projectPath3, storyId) {
|
|
|
273828
274066
|
}
|
|
273829
274067
|
function existingFixId(projectPath3, storyId, signal) {
|
|
273830
274068
|
try {
|
|
273831
|
-
const snap = new BacklogStore().readBacklog(
|
|
274069
|
+
const snap = new BacklogStore().readBacklog(join129(projectPath3, ".roll", "backlog.md"));
|
|
273832
274070
|
return snap.items.find((it) => {
|
|
273833
274071
|
const desc = it.desc.toLowerCase();
|
|
273834
274072
|
if (!it.id.startsWith("FIX-"))
|
|
@@ -273850,7 +274088,7 @@ function fixDescription(storyId, signal) {
|
|
|
273850
274088
|
}
|
|
273851
274089
|
function writeFixSpec(projectPath3, epic, fixId, decision) {
|
|
273852
274090
|
try {
|
|
273853
|
-
const dir =
|
|
274091
|
+
const dir = join129(projectPath3, ".roll", "features", epic, fixId);
|
|
273854
274092
|
mkdirSync59(dir, { recursive: true });
|
|
273855
274093
|
const body = [
|
|
273856
274094
|
"---",
|
|
@@ -273881,7 +274119,7 @@ function writeFixSpec(projectPath3, epic, fixId, decision) {
|
|
|
273881
274119
|
"- [ ] Leave the PR open for human merge approval",
|
|
273882
274120
|
""
|
|
273883
274121
|
].join("\n");
|
|
273884
|
-
writeFileSync58(
|
|
274122
|
+
writeFileSync58(join129(dir, "spec.md"), body, "utf8");
|
|
273885
274123
|
} catch {
|
|
273886
274124
|
}
|
|
273887
274125
|
}
|
|
@@ -273889,7 +274127,7 @@ function createFix(projectPath3, decision) {
|
|
|
273889
274127
|
const existing = existingFixId(projectPath3, decision.storyId, decision.signal);
|
|
273890
274128
|
if (existing !== void 0)
|
|
273891
274129
|
return { mutation: "existing_fix", fixId: existing };
|
|
273892
|
-
const path =
|
|
274130
|
+
const path = join129(projectPath3, ".roll", "backlog.md");
|
|
273893
274131
|
const store = new BacklogStore();
|
|
273894
274132
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
273895
274133
|
try {
|
|
@@ -273914,7 +274152,7 @@ function createFix(projectPath3, decision) {
|
|
|
273914
274152
|
}
|
|
273915
274153
|
function markStoryHold(projectPath3, storyId, reason) {
|
|
273916
274154
|
try {
|
|
273917
|
-
const path =
|
|
274155
|
+
const path = join129(projectPath3, ".roll", "backlog.md");
|
|
273918
274156
|
const store = new BacklogStore();
|
|
273919
274157
|
const snap = store.readBacklog(path);
|
|
273920
274158
|
const row2 = snap.items.find((it) => it.id === storyId);
|
|
@@ -273976,15 +274214,15 @@ function applyCorrectionAction(input) {
|
|
|
273976
274214
|
|
|
273977
274215
|
// packages/cli/dist/runner/pairing-gate.js
|
|
273978
274216
|
init_dist2();
|
|
273979
|
-
import { existsSync as
|
|
274217
|
+
import { existsSync as existsSync113, mkdirSync as mkdirSync60, readFileSync as readFileSync115, writeFileSync as writeFileSync59 } from "node:fs";
|
|
273980
274218
|
import { homedir as homedir29 } from "node:os";
|
|
273981
|
-
import { join as
|
|
274219
|
+
import { join as join131 } from "node:path";
|
|
273982
274220
|
|
|
273983
274221
|
// packages/cli/dist/runner/peer-gate.js
|
|
273984
274222
|
init_dist2();
|
|
273985
274223
|
import { execFile as execFile13 } from "node:child_process";
|
|
273986
|
-
import { existsSync as
|
|
273987
|
-
import { join as
|
|
274224
|
+
import { existsSync as existsSync112, readFileSync as readFileSync114, readdirSync as readdirSync43 } from "node:fs";
|
|
274225
|
+
import { join as join130 } from "node:path";
|
|
273988
274226
|
import { promisify as promisify13 } from "node:util";
|
|
273989
274227
|
var execFileAsync13 = promisify13(execFile13);
|
|
273990
274228
|
var HIGH_RISK = [/^\.github\/workflows\//, /^packages\/infra\/src\/(git|github|process)\.ts$/];
|
|
@@ -274014,8 +274252,8 @@ async function cycleChangedFiles(worktreeCwd) {
|
|
|
274014
274252
|
}
|
|
274015
274253
|
}
|
|
274016
274254
|
function peerEvidencePresent(runtimeDir12, cycleId) {
|
|
274017
|
-
const dir =
|
|
274018
|
-
if (!
|
|
274255
|
+
const dir = join130(runtimeDir12, "peer");
|
|
274256
|
+
if (!existsSync112(dir))
|
|
274019
274257
|
return false;
|
|
274020
274258
|
try {
|
|
274021
274259
|
return readdirSync43(dir).some((f) => f.startsWith(`cycle-${cycleId}.`));
|
|
@@ -274025,20 +274263,20 @@ function peerEvidencePresent(runtimeDir12, cycleId) {
|
|
|
274025
274263
|
}
|
|
274026
274264
|
function readPeerGateMode(repoCwd) {
|
|
274027
274265
|
try {
|
|
274028
|
-
const p =
|
|
274029
|
-
if (!
|
|
274266
|
+
const p = join130(repoCwd, ".roll", "policy.yaml");
|
|
274267
|
+
if (!existsSync112(p))
|
|
274030
274268
|
return "hard";
|
|
274031
|
-
return parsePolicy(
|
|
274269
|
+
return parsePolicy(readFileSync114(p, "utf8")).loopSafety.peerGate === "soft" ? "soft" : "hard";
|
|
274032
274270
|
} catch {
|
|
274033
274271
|
return "hard";
|
|
274034
274272
|
}
|
|
274035
274273
|
}
|
|
274036
274274
|
function readPeerOnPoolTimeout(repoCwd) {
|
|
274037
274275
|
try {
|
|
274038
|
-
const p =
|
|
274039
|
-
if (!
|
|
274276
|
+
const p = join130(repoCwd, ".roll", "policy.yaml");
|
|
274277
|
+
if (!existsSync112(p))
|
|
274040
274278
|
return "block";
|
|
274041
|
-
return parsePolicy(
|
|
274279
|
+
return parsePolicy(readFileSync114(p, "utf8")).loopSafety.peerOnPoolTimeout === "degrade" ? "degrade" : "block";
|
|
274042
274280
|
} catch {
|
|
274043
274281
|
return "block";
|
|
274044
274282
|
}
|
|
@@ -274080,9 +274318,9 @@ async function runPeerGate(worktreeCwd, runtimeDir12, cycleId, mode, sinks, opts
|
|
|
274080
274318
|
|
|
274081
274319
|
// packages/cli/dist/runner/pairing-gate.js
|
|
274082
274320
|
function readScopedAgentLayer2(path) {
|
|
274083
|
-
if (!
|
|
274321
|
+
if (!existsSync113(path))
|
|
274084
274322
|
return null;
|
|
274085
|
-
const text2 =
|
|
274323
|
+
const text2 = readFileSync115(path, "utf8");
|
|
274086
274324
|
if (!text2.includes("roll-agents/v1"))
|
|
274087
274325
|
return null;
|
|
274088
274326
|
const parsed = normalizeAgentScopeConfig(text2);
|
|
@@ -274092,10 +274330,10 @@ function readScopedAgentLayer2(path) {
|
|
|
274092
274330
|
return { config: parsed.config, path };
|
|
274093
274331
|
}
|
|
274094
274332
|
function loadScopedPairingConfig(projectDir, installed) {
|
|
274095
|
-
const rollHome4 = process.env["ROLL_HOME"] ??
|
|
274333
|
+
const rollHome4 = process.env["ROLL_HOME"] ?? join131(homedir29(), ".roll");
|
|
274096
274334
|
const layers = [
|
|
274097
|
-
readScopedAgentLayer2(
|
|
274098
|
-
readScopedAgentLayer2(
|
|
274335
|
+
readScopedAgentLayer2(join131(rollHome4, "agents.yaml")),
|
|
274336
|
+
readScopedAgentLayer2(join131(projectDir, ".roll", "agents.yaml"))
|
|
274099
274337
|
].filter((layer) => layer !== null);
|
|
274100
274338
|
if (layers.length === 0)
|
|
274101
274339
|
return null;
|
|
@@ -274127,9 +274365,9 @@ function loadPairingConfig(projectDir, installed, fallback) {
|
|
|
274127
274365
|
const scoped = loadScopedPairingConfig(projectDir, installed);
|
|
274128
274366
|
if (scoped !== null)
|
|
274129
274367
|
return scoped;
|
|
274130
|
-
const cfgPath =
|
|
274131
|
-
if (
|
|
274132
|
-
return { cfg: parsePairingConfig(
|
|
274368
|
+
const cfgPath = join131(projectDir, ".roll", "pairing.yaml");
|
|
274369
|
+
if (existsSync113(cfgPath))
|
|
274370
|
+
return { cfg: parsePairingConfig(readFileSync115(cfgPath, "utf8")), source: "legacy-pairing" };
|
|
274133
274371
|
return fallback === void 0 ? null : { cfg: fallback, source: "default-score" };
|
|
274134
274372
|
}
|
|
274135
274373
|
function enabledPairingStages(projectDir) {
|
|
@@ -274146,9 +274384,9 @@ function enabledPairingStages(projectDir) {
|
|
|
274146
274384
|
}
|
|
274147
274385
|
}
|
|
274148
274386
|
function evidencePath(runtimeDir12, cycleId, stage) {
|
|
274149
|
-
const dir =
|
|
274387
|
+
const dir = join131(runtimeDir12, "peer");
|
|
274150
274388
|
const name = stage === "code" ? `cycle-${cycleId}.pair.json` : `cycle-${cycleId}.${stage}.pair.json`;
|
|
274151
|
-
return
|
|
274389
|
+
return join131(dir, name);
|
|
274152
274390
|
}
|
|
274153
274391
|
var REVIEW_TIMEOUT_BASE_MS = 18e4;
|
|
274154
274392
|
var REVIEW_TIMEOUT_LARGE_MS = 3e5;
|
|
@@ -274335,7 +274573,7 @@ async function runPairing(projectDir, worktreeCwd, runtimeDir12, cycleId, workin
|
|
|
274335
274573
|
}
|
|
274336
274574
|
const { peer, review } = dispatched;
|
|
274337
274575
|
const path = evidencePath(runtimeDir12, cycleId, stage);
|
|
274338
|
-
mkdirSync60(
|
|
274576
|
+
mkdirSync60(join131(runtimeDir12, "peer"), { recursive: true });
|
|
274339
274577
|
writeFileSync59(path, JSON.stringify({ cycleId, workingAgent, peer, stage, ...review }, null, 2), "utf8");
|
|
274340
274578
|
deps.event({ type: "pair:verdict", cycleId, peer, verdict: review.verdict, findings: review.findings.length, cost: review.cost, stage, ts: deps.now() });
|
|
274341
274579
|
return { status: "reviewed", peer, verdict: review.verdict };
|
|
@@ -274466,7 +274704,7 @@ async function runScorePairing(projectDir, runtimeDir12, cycleId, workingAgent,
|
|
|
274466
274704
|
});
|
|
274467
274705
|
try {
|
|
274468
274706
|
const path = evidencePath(runtimeDir12, cycleId, scoreStage);
|
|
274469
|
-
mkdirSync60(
|
|
274707
|
+
mkdirSync60(join131(runtimeDir12, "peer"), { recursive: true });
|
|
274470
274708
|
writeFileSync59(path, JSON.stringify({ cycleId, workingAgent, peer, stage: scoreStage, score: scored.score, verdict: scored.verdict, rationale: scored.rationale, cost: scored.cost, sessionId: sessionId2 }, null, 2), "utf8");
|
|
274471
274709
|
deps.event({ type: "pair:score", cycleId, peer, score: scored.score, verdict: scored.verdict, cost: scored.cost, stage: scoreStage, ts: deps.now() });
|
|
274472
274710
|
} catch {
|
|
@@ -274605,7 +274843,7 @@ async function retryPeerConsult(worktreeCwd, runtimeDir12, cycleId, deps) {
|
|
|
274605
274843
|
}
|
|
274606
274844
|
const { peer, sameTypeFallback, review } = dispatched;
|
|
274607
274845
|
const path = evidencePath(runtimeDir12, cycleId, "code");
|
|
274608
|
-
mkdirSync60(
|
|
274846
|
+
mkdirSync60(join131(runtimeDir12, "peer"), { recursive: true });
|
|
274609
274847
|
writeFileSync59(path, JSON.stringify({ cycleId, workingAgent: working, peer, stage: "code", sameTypeFallback, ...review }, null, 2), "utf8");
|
|
274610
274848
|
deps.event({ type: "pair:verdict", cycleId, peer, verdict: review.verdict, findings: review.findings.length, cost: review.cost, stage: "code", ts: deps.now() });
|
|
274611
274849
|
return { status: "reviewed", peer, sameTypeFallback };
|
|
@@ -274636,8 +274874,8 @@ DIFF:
|
|
|
274636
274874
|
init_dist2();
|
|
274637
274875
|
init_dist();
|
|
274638
274876
|
import { execFile as execFile14 } from "node:child_process";
|
|
274639
|
-
import { existsSync as
|
|
274640
|
-
import { dirname as
|
|
274877
|
+
import { existsSync as existsSync114, mkdirSync as mkdirSync61, readFileSync as readFileSync116, writeFileSync as writeFileSync60 } from "node:fs";
|
|
274878
|
+
import { dirname as dirname63, join as join132 } from "node:path";
|
|
274641
274879
|
import { promisify as promisify14 } from "node:util";
|
|
274642
274880
|
var execFileAsync14 = promisify14(execFile14);
|
|
274643
274881
|
function createCapturePeerHelpers(params) {
|
|
@@ -274671,9 +274909,9 @@ function createCapturePeerHelpers(params) {
|
|
|
274671
274909
|
const key = `${peer}:${stage}`;
|
|
274672
274910
|
const attempt = (rawArtifactAttempts.get(key) ?? 0) + 1;
|
|
274673
274911
|
rawArtifactAttempts.set(key, attempt);
|
|
274674
|
-
const peerDir2 =
|
|
274912
|
+
const peerDir2 = join132(dirname63(ports.paths.eventsPath), "cycle-logs", ctx.cycleId ?? "cycle", "peer");
|
|
274675
274913
|
mkdirSync61(peerDir2, { recursive: true });
|
|
274676
|
-
const artifactPath2 =
|
|
274914
|
+
const artifactPath2 = join132(peerDir2, `${peer}.${stage}.attempt-${attempt}.raw.txt`);
|
|
274677
274915
|
writeFileSync60(artifactPath2, `--- stdout ---
|
|
274678
274916
|
${stdout}
|
|
274679
274917
|
--- stderr ---
|
|
@@ -274683,9 +274921,9 @@ ${stderr}
|
|
|
274683
274921
|
};
|
|
274684
274922
|
const computeAuthDiagnostics = () => {
|
|
274685
274923
|
try {
|
|
274686
|
-
if (!
|
|
274924
|
+
if (!existsSync114(ports.paths.eventsPath))
|
|
274687
274925
|
return excludedPeers([]);
|
|
274688
|
-
const events =
|
|
274926
|
+
const events = readFileSync116(ports.paths.eventsPath, "utf8").split("\n").map(parseEventLine).filter((e) => e !== null);
|
|
274689
274927
|
const cooldown = authCooldownExclusions(events);
|
|
274690
274928
|
for (const [peer, failures] of cooldown) {
|
|
274691
274929
|
ports.events.appendEvent(ports.paths.eventsPath, {
|
|
@@ -274821,7 +275059,7 @@ async function executeCaptureFactsCommand(cmd, ports, ctx) {
|
|
|
274821
275059
|
tcrCount
|
|
274822
275060
|
});
|
|
274823
275061
|
const peerGateMode = readPeerGateMode(ports.repoCwd);
|
|
274824
|
-
const runtimeDir12 =
|
|
275062
|
+
const runtimeDir12 = dirname64(ports.paths.eventsPath);
|
|
274825
275063
|
const cycleIdStr = ctx.cycleId ?? "";
|
|
274826
275064
|
const peerGateAllowedAgents = projectAllowedAgents(ports.repoCwd);
|
|
274827
275065
|
const peerGateInstalled = ports.installedAgents?.() ?? agentsInstalled(realAgentEnv());
|
|
@@ -274841,8 +275079,8 @@ async function executeCaptureFactsCommand(cmd, ports, ctx) {
|
|
|
274841
275079
|
{
|
|
274842
275080
|
let pairHistory;
|
|
274843
275081
|
try {
|
|
274844
|
-
if (
|
|
274845
|
-
const events =
|
|
275082
|
+
if (existsSync115(ports.paths.eventsPath)) {
|
|
275083
|
+
const events = readFileSync117(ports.paths.eventsPath, "utf8").split("\n").map(parseEventLine).filter((e) => e !== null);
|
|
274846
275084
|
pairHistory = pairingHistory(events);
|
|
274847
275085
|
}
|
|
274848
275086
|
} catch {
|
|
@@ -274862,7 +275100,7 @@ async function executeCaptureFactsCommand(cmd, ports, ctx) {
|
|
|
274862
275100
|
allowedAgents: peerGateAllowedAgents
|
|
274863
275101
|
};
|
|
274864
275102
|
for (const stage of enabledPairingStages(ports.repoCwd)) {
|
|
274865
|
-
await runPairing(ports.repoCwd, ports.paths.worktreePath,
|
|
275103
|
+
await runPairing(ports.repoCwd, ports.paths.worktreePath, dirname64(ports.paths.eventsPath), ctx.cycleId ?? "", ctx.agent ?? "", stage, pairingDeps);
|
|
274866
275104
|
}
|
|
274867
275105
|
}
|
|
274868
275106
|
let peerGate = await runPeerGate(ports.paths.worktreePath, runtimeDir12, cycleIdStr, peerGateMode, peerGateSinks, peerGateOpts);
|
|
@@ -274885,9 +275123,9 @@ async function executeCaptureFactsCommand(cmd, ports, ctx) {
|
|
|
274885
275123
|
}
|
|
274886
275124
|
if (peerBlocked && retry.status === "timeout" && readPeerOnPoolTimeout(ports.repoCwd) === "degrade") {
|
|
274887
275125
|
const how = retry.sameTypeFallback === true ? "same-type separate-session review" : "peer review";
|
|
274888
|
-
const unavailableDir =
|
|
275126
|
+
const unavailableDir = join133(runtimeDir12, "peer-unavailable");
|
|
274889
275127
|
mkdirSync62(unavailableDir, { recursive: true });
|
|
274890
|
-
writeFileSync61(
|
|
275128
|
+
writeFileSync61(join133(unavailableDir, `cycle-${cycleIdStr}.json`), JSON.stringify({
|
|
274891
275129
|
cycleId: cycleIdStr,
|
|
274892
275130
|
status: retry.status,
|
|
274893
275131
|
how,
|
|
@@ -275000,9 +275238,9 @@ ${res.stderr}`;
|
|
|
275000
275238
|
let goalLine = "";
|
|
275001
275239
|
let evalContractFormatted = "";
|
|
275002
275240
|
try {
|
|
275003
|
-
const specPath =
|
|
275004
|
-
if (
|
|
275005
|
-
const specText =
|
|
275241
|
+
const specPath = join133(cardArchiveDir(ports.repoCwd, storyId), "spec.md");
|
|
275242
|
+
if (existsSync115(specPath)) {
|
|
275243
|
+
const specText = readFileSync117(specPath, "utf8");
|
|
275006
275244
|
const title = (/^title:\s*(.+)$/m.exec(specText)?.[1] ?? "").trim();
|
|
275007
275245
|
if (title !== "")
|
|
275008
275246
|
goalLine = `Goal: ${title}
|
|
@@ -275016,7 +275254,7 @@ ${goalLine}Delivery: peer-reviewed cycle, scoring stage
|
|
|
275016
275254
|
Diff stat:
|
|
275017
275255
|
${diffStat}`;
|
|
275018
275256
|
const skill = storyId.startsWith("FIX-") || storyId.startsWith("BUG-") ? "roll-fix" : "roll-build";
|
|
275019
|
-
const scoreResult = await runScorePairing(ports.repoCwd,
|
|
275257
|
+
const scoreResult = await runScorePairing(ports.repoCwd, dirname64(ports.paths.eventsPath), ctx.cycleId ?? "", ctx.agent ?? "", storyId, skill, summary, {
|
|
275020
275258
|
installed: ports.installedAgents?.() ?? agentsInstalled(realAgentEnv()),
|
|
275021
275259
|
// Historical auth streaks do not shrink the fair candidate pool.
|
|
275022
275260
|
isAvailable: peerAvailable,
|
|
@@ -275181,25 +275419,25 @@ init_dist2();
|
|
|
275181
275419
|
init_dist();
|
|
275182
275420
|
init_dist3();
|
|
275183
275421
|
import { execFileSync as execFileSync30 } from "node:child_process";
|
|
275184
|
-
import { existsSync as
|
|
275185
|
-
import { dirname as
|
|
275422
|
+
import { existsSync as existsSync118, lstatSync as lstatSync10, realpathSync as realpathSync17, unlinkSync as unlinkSync5 } from "node:fs";
|
|
275423
|
+
import { dirname as dirname65, join as join135 } from "node:path";
|
|
275186
275424
|
|
|
275187
275425
|
// packages/cli/dist/runner/cycle-role-artifact-writer.js
|
|
275188
275426
|
init_dist();
|
|
275189
275427
|
init_dist2();
|
|
275190
|
-
import { existsSync as
|
|
275428
|
+
import { existsSync as existsSync116, readFileSync as readFileSync118, mkdirSync as mkdirSync63, writeFileSync as writeFileSync62 } from "node:fs";
|
|
275191
275429
|
function writeCycleRoleSummaryBestEffort(cycleId, eventsPath4, cycleLogDir) {
|
|
275192
275430
|
try {
|
|
275193
275431
|
if (!cycleId)
|
|
275194
275432
|
return;
|
|
275195
275433
|
let raw;
|
|
275196
275434
|
try {
|
|
275197
|
-
raw =
|
|
275435
|
+
raw = readFileSync118(eventsPath4, "utf-8");
|
|
275198
275436
|
} catch {
|
|
275199
275437
|
return;
|
|
275200
275438
|
}
|
|
275201
275439
|
const outDir = `${cycleLogDir}/${cycleId}`;
|
|
275202
|
-
if (!
|
|
275440
|
+
if (!existsSync116(outDir)) {
|
|
275203
275441
|
mkdirSync63(outDir, { recursive: true });
|
|
275204
275442
|
}
|
|
275205
275443
|
const lines3 = raw.split("\n").filter((l) => l.trim() !== "");
|
|
@@ -275224,8 +275462,8 @@ function writeCycleRoleSummaryBestEffort(cycleId, eventsPath4, cycleLogDir) {
|
|
|
275224
275462
|
}
|
|
275225
275463
|
|
|
275226
275464
|
// packages/cli/dist/runner/environment-cleanup.js
|
|
275227
|
-
import { existsSync as
|
|
275228
|
-
import { basename as basename19, join as
|
|
275465
|
+
import { existsSync as existsSync117, lstatSync as lstatSync9, mkdirSync as mkdirSync64, readFileSync as readFileSync119, readdirSync as readdirSync44, renameSync as renameSync24, rmSync as rmSync22 } from "node:fs";
|
|
275466
|
+
import { basename as basename19, join as join134, relative as relative11 } from "node:path";
|
|
275229
275467
|
var CLEANUP_TIMEOUT_MS = 1e4;
|
|
275230
275468
|
var HEAVY_CLEANUP_TERMINALS = ["idle", "done", "published", "orphan"];
|
|
275231
275469
|
var DEFAULT_CLEANUP_MANIFEST = {
|
|
@@ -275259,7 +275497,7 @@ var DEFAULT_CLEANUP_MANIFEST = {
|
|
|
275259
275497
|
function readCleanupManifest(manifestPath2) {
|
|
275260
275498
|
let text2;
|
|
275261
275499
|
try {
|
|
275262
|
-
text2 =
|
|
275500
|
+
text2 = readFileSync119(manifestPath2, "utf8");
|
|
275263
275501
|
} catch (error) {
|
|
275264
275502
|
const code = error.code;
|
|
275265
275503
|
if (code === "ENOENT")
|
|
@@ -275461,14 +275699,14 @@ function cleanupTimeoutResult(maxDurationMs) {
|
|
|
275461
275699
|
}
|
|
275462
275700
|
function resolvePattern(worktreePath, pattern, deadline, now2) {
|
|
275463
275701
|
if (!pattern.includes("**")) {
|
|
275464
|
-
const abs =
|
|
275702
|
+
const abs = join134(worktreePath, pattern);
|
|
275465
275703
|
return [abs];
|
|
275466
275704
|
}
|
|
275467
275705
|
const recursiveIdx = pattern.indexOf("**");
|
|
275468
275706
|
const prefix = pattern.slice(0, recursiveIdx);
|
|
275469
275707
|
const rest = pattern.slice(recursiveIdx + 2);
|
|
275470
|
-
const base =
|
|
275471
|
-
if (!
|
|
275708
|
+
const base = join134(worktreePath, prefix);
|
|
275709
|
+
if (!existsSync117(base))
|
|
275472
275710
|
return [];
|
|
275473
275711
|
const suffix = rest?.replace(/^\//, "") ?? "";
|
|
275474
275712
|
const matches = [];
|
|
@@ -275487,7 +275725,7 @@ function walkRecursive(dir, worktreePath, suffix, out3, deadline, now2) {
|
|
|
275487
275725
|
for (const entry of entries) {
|
|
275488
275726
|
if (now2() >= deadline)
|
|
275489
275727
|
return;
|
|
275490
|
-
const abs =
|
|
275728
|
+
const abs = join134(dir, entry);
|
|
275491
275729
|
const rel = relative11(worktreePath, abs);
|
|
275492
275730
|
if (suffix && rel.endsWith(suffix)) {
|
|
275493
275731
|
out3.push(abs);
|
|
@@ -275506,16 +275744,16 @@ function applyRule(worktreePath, cycleId, rule, absPath) {
|
|
|
275506
275744
|
return { rule: rule.name, path: absPath, ok: false, warning: "target outside worktree refused" };
|
|
275507
275745
|
}
|
|
275508
275746
|
try {
|
|
275509
|
-
if (!
|
|
275747
|
+
if (!existsSync117(absPath)) {
|
|
275510
275748
|
return { rule: rule.name, path: rel, ok: true };
|
|
275511
275749
|
}
|
|
275512
275750
|
} catch {
|
|
275513
275751
|
return { rule: rule.name, path: rel, ok: false, warning: "cannot stat target" };
|
|
275514
275752
|
}
|
|
275515
275753
|
if (rule.kind === "isolate") {
|
|
275516
|
-
const isolateRoot =
|
|
275754
|
+
const isolateRoot = join134(worktreePath, ".roll-cleanup", cycleId, rule.name);
|
|
275517
275755
|
const base = basename19(absPath);
|
|
275518
|
-
const dest =
|
|
275756
|
+
const dest = join134(isolateRoot, base);
|
|
275519
275757
|
try {
|
|
275520
275758
|
mkdirSync64(isolateRoot, { recursive: true });
|
|
275521
275759
|
renameSync24(absPath, dest);
|
|
@@ -275525,7 +275763,7 @@ function applyRule(worktreePath, cycleId, rule, absPath) {
|
|
|
275525
275763
|
}
|
|
275526
275764
|
}
|
|
275527
275765
|
try {
|
|
275528
|
-
|
|
275766
|
+
rmSync22(absPath, { recursive: true, force: true });
|
|
275529
275767
|
return { rule: rule.name, path: rel, ok: true };
|
|
275530
275768
|
} catch (err16) {
|
|
275531
275769
|
return { rule: rule.name, path: rel, ok: false, warning: `rm failed: ${err16}` };
|
|
@@ -275582,7 +275820,7 @@ async function executeTerminalCommand(cmd, ports, ctx) {
|
|
|
275582
275820
|
}
|
|
275583
275821
|
}
|
|
275584
275822
|
if (r.degraded === true && r.status === 0 && ctx.storyId !== void 0 && ctx.cycleId !== void 0) {
|
|
275585
|
-
const runtimeDir12 =
|
|
275823
|
+
const runtimeDir12 = dirname65(ports.paths.eventsPath);
|
|
275586
275824
|
addPendingPrCreate(runtimeDir12, {
|
|
275587
275825
|
storyId: ctx.storyId,
|
|
275588
275826
|
cycleId: ctx.cycleId,
|
|
@@ -275680,7 +275918,7 @@ async function executeTerminalCommand(cmd, ports, ctx) {
|
|
|
275680
275918
|
}
|
|
275681
275919
|
} catch {
|
|
275682
275920
|
}
|
|
275683
|
-
const manifestPath2 =
|
|
275921
|
+
const manifestPath2 = join135(ports.repoCwd, ".roll", "loop", "cleanup-manifest.yaml");
|
|
275684
275922
|
const manifest = resolveCleanupManifest(ports.paths.worktreePath, manifestPath2);
|
|
275685
275923
|
const results = applyCleanupManifest(ports.paths.worktreePath, ctx.cycleId, manifest, {
|
|
275686
275924
|
terminalStatus: cmd.terminalStatus,
|
|
@@ -275700,7 +275938,7 @@ async function executeTerminalCommand(cmd, ports, ctx) {
|
|
|
275700
275938
|
// pure worktree teardown again.
|
|
275701
275939
|
case "cleanup_worktree":
|
|
275702
275940
|
try {
|
|
275703
|
-
const dst =
|
|
275941
|
+
const dst = join135(ports.paths.worktreePath, ".roll");
|
|
275704
275942
|
if (lstatSync10(dst, { throwIfNoEntry: false })?.isSymbolicLink() === true)
|
|
275705
275943
|
unlinkSync5(dst);
|
|
275706
275944
|
} catch {
|
|
@@ -275725,7 +275963,7 @@ async function executeTerminalCommand(cmd, ports, ctx) {
|
|
|
275725
275963
|
});
|
|
275726
275964
|
ports.events.appendAlert(ports.paths.alertsPath, `FIX-1210: cycle ${cmd.cycleId} \u2014 core.worktree was pointing to "${repair.detail}" \u2014 auto-unset at terminal`);
|
|
275727
275965
|
}
|
|
275728
|
-
const metaRepair = repairCoreWorktreeContamination(
|
|
275966
|
+
const metaRepair = repairCoreWorktreeContamination(join135(ports.repoCwd, ".roll"));
|
|
275729
275967
|
if (metaRepair.healed) {
|
|
275730
275968
|
ports.events.appendEvent(ports.paths.eventsPath, {
|
|
275731
275969
|
type: "cycle:cleanup",
|
|
@@ -275754,7 +275992,7 @@ async function executeTerminalCommand(cmd, ports, ctx) {
|
|
|
275754
275992
|
const terminalStoryId = ctx.storyId ?? "";
|
|
275755
275993
|
if (terminalStoryId !== "") {
|
|
275756
275994
|
try {
|
|
275757
|
-
removeLease(
|
|
275995
|
+
removeLease(join135(dirname65(ports.paths.eventsPath), "story-leases.json"), terminalStoryId, "cycle");
|
|
275758
275996
|
} catch {
|
|
275759
275997
|
}
|
|
275760
275998
|
}
|
|
@@ -275854,7 +276092,7 @@ async function executeTerminalCommand(cmd, ports, ctx) {
|
|
|
275854
276092
|
await commitInRepoBacklog(ports, ctx, terminalStoryId, terminalMerged);
|
|
275855
276093
|
}
|
|
275856
276094
|
if (ctx.cycleId !== void 0) {
|
|
275857
|
-
const cycleLogDir =
|
|
276095
|
+
const cycleLogDir = join135(dirname65(ports.paths.eventsPath), "cycle-logs");
|
|
275858
276096
|
writeCycleRoleSummaryBestEffort(ctx.cycleId, ports.paths.eventsPath, cycleLogDir);
|
|
275859
276097
|
}
|
|
275860
276098
|
return {};
|
|
@@ -275875,8 +276113,8 @@ async function executeTerminalCommand(cmd, ports, ctx) {
|
|
|
275875
276113
|
}
|
|
275876
276114
|
function isInRepoRollLayout(worktreePath) {
|
|
275877
276115
|
try {
|
|
275878
|
-
const rollDir =
|
|
275879
|
-
if (!
|
|
276116
|
+
const rollDir = join135(worktreePath, ".roll");
|
|
276117
|
+
if (!existsSync118(rollDir))
|
|
275880
276118
|
return false;
|
|
275881
276119
|
const top = execFileSync30("git", ["-C", rollDir, "rev-parse", "--show-toplevel"], {
|
|
275882
276120
|
encoding: "utf8",
|
|
@@ -275893,9 +276131,9 @@ function isInRepoRollLayout(worktreePath) {
|
|
|
275893
276131
|
}
|
|
275894
276132
|
async function commitInRepoBacklog(ports, ctx, storyId, terminalMerged) {
|
|
275895
276133
|
const msg6 = `chore: ${storyId} status update (cycle ${ctx.cycleId})`;
|
|
275896
|
-
const backlogRel =
|
|
276134
|
+
const backlogRel = join135(".roll", "backlog.md");
|
|
275897
276135
|
try {
|
|
275898
|
-
if (!
|
|
276136
|
+
if (!existsSync118(join135(ports.repoCwd, backlogRel)))
|
|
275899
276137
|
return;
|
|
275900
276138
|
execFileSync30("git", ["add", "--", backlogRel], { cwd: ports.repoCwd, stdio: "ignore" });
|
|
275901
276139
|
const dirty = execFileSync30("git", ["status", "--porcelain", "--", backlogRel], {
|
|
@@ -275918,13 +276156,13 @@ async function commitInRepoBacklog(ports, ctx, storyId, terminalMerged) {
|
|
|
275918
276156
|
init_dist2();
|
|
275919
276157
|
init_dist3();
|
|
275920
276158
|
import { execFile as execFile16 } from "node:child_process";
|
|
275921
|
-
import { appendFileSync as appendFileSync20, existsSync as
|
|
275922
|
-
import { dirname as
|
|
276159
|
+
import { appendFileSync as appendFileSync20, existsSync as existsSync120, mkdirSync as mkdirSync65, readFileSync as readFileSync121, statSync as statSync38, writeFileSync as writeFileSync64 } from "node:fs";
|
|
276160
|
+
import { dirname as dirname66, join as join137 } from "node:path";
|
|
275923
276161
|
import { promisify as promisify16 } from "node:util";
|
|
275924
276162
|
|
|
275925
276163
|
// packages/cli/dist/runner/selfheal-budget.js
|
|
275926
|
-
import { existsSync as
|
|
275927
|
-
import { join as
|
|
276164
|
+
import { existsSync as existsSync119, readFileSync as readFileSync120, writeFileSync as writeFileSync63 } from "node:fs";
|
|
276165
|
+
import { join as join136 } from "node:path";
|
|
275928
276166
|
var SELFHEAL_AGENT_BUDGET = 2;
|
|
275929
276167
|
function selfHealBudget(env = process.env) {
|
|
275930
276168
|
const raw = (env["ROLL_LOOP_AGENT_RETRY_MAX"] ?? "").trim();
|
|
@@ -275938,14 +276176,14 @@ function autoRecoverEnabled(env = process.env) {
|
|
|
275938
276176
|
}
|
|
275939
276177
|
var EMPTY = { attempts: 0, triedAgents: [], lastReason: "" };
|
|
275940
276178
|
function stateFile2(runtimeDir12) {
|
|
275941
|
-
return
|
|
276179
|
+
return join136(runtimeDir12, "selfheal-cards.json");
|
|
275942
276180
|
}
|
|
275943
276181
|
function read2(runtimeDir12) {
|
|
275944
276182
|
try {
|
|
275945
276183
|
const p = stateFile2(runtimeDir12);
|
|
275946
|
-
if (!
|
|
276184
|
+
if (!existsSync119(p))
|
|
275947
276185
|
return { stories: {} };
|
|
275948
|
-
const o = JSON.parse(
|
|
276186
|
+
const o = JSON.parse(readFileSync120(p, "utf8"));
|
|
275949
276187
|
return { stories: o.stories !== void 0 && typeof o.stories === "object" ? o.stories : {} };
|
|
275950
276188
|
} catch {
|
|
275951
276189
|
return { stories: {} };
|
|
@@ -276024,13 +276262,13 @@ function nodePorts(opts) {
|
|
|
276024
276262
|
},
|
|
276025
276263
|
readText(absPath) {
|
|
276026
276264
|
try {
|
|
276027
|
-
return
|
|
276265
|
+
return readFileSync121(absPath, "utf8");
|
|
276028
276266
|
} catch {
|
|
276029
276267
|
return "";
|
|
276030
276268
|
}
|
|
276031
276269
|
},
|
|
276032
276270
|
writeText(absPath, text2) {
|
|
276033
|
-
mkdirSync65(
|
|
276271
|
+
mkdirSync65(dirname66(absPath), { recursive: true });
|
|
276034
276272
|
writeFileSync64(absPath, text2, "utf8");
|
|
276035
276273
|
}
|
|
276036
276274
|
};
|
|
@@ -276065,7 +276303,7 @@ function nodePorts(opts) {
|
|
|
276065
276303
|
mergedDelivery,
|
|
276066
276304
|
// FIX-1018: skip stories that already have locally-committed-but-unpublished
|
|
276067
276305
|
// work from a prior cycle. The executor reads the runtime file at pick time.
|
|
276068
|
-
pendingPublish: (storyId) => readPendingPublish(
|
|
276306
|
+
pendingPublish: (storyId) => readPendingPublish(dirname66(opts.paths.eventsPath)).has(storyId),
|
|
276069
276307
|
pendingMergeDelivery: (storyId) => {
|
|
276070
276308
|
const truth = deliveryTruth().get(storyId);
|
|
276071
276309
|
if (truth === void 0)
|
|
@@ -276213,10 +276451,10 @@ function nodePorts(opts) {
|
|
|
276213
276451
|
},
|
|
276214
276452
|
backlog: {
|
|
276215
276453
|
read(projectCwd) {
|
|
276216
|
-
const p =
|
|
276217
|
-
if (!
|
|
276454
|
+
const p = join137(projectCwd, ".roll", "backlog.md");
|
|
276455
|
+
if (!existsSync120(p))
|
|
276218
276456
|
return [];
|
|
276219
|
-
return parseBacklog(
|
|
276457
|
+
return parseBacklog(readFileSync121(p, "utf8"));
|
|
276220
276458
|
},
|
|
276221
276459
|
// FIX-198: the production binding was MISSING entirely (the optional
|
|
276222
276460
|
// chain made every In-Progress claim a silent no-op). ID-anchored mark
|
|
@@ -276224,8 +276462,8 @@ function nodePorts(opts) {
|
|
|
276224
276462
|
// never kill the cycle, the reconcile pass is the safety net.
|
|
276225
276463
|
markStatus(projectCwd, id, status2) {
|
|
276226
276464
|
try {
|
|
276227
|
-
const p =
|
|
276228
|
-
if (!
|
|
276465
|
+
const p = join137(projectCwd, ".roll", "backlog.md");
|
|
276466
|
+
if (!existsSync120(p))
|
|
276229
276467
|
return;
|
|
276230
276468
|
const store = new BacklogStore();
|
|
276231
276469
|
const snap = store.readBacklog(p);
|
|
@@ -276248,7 +276486,7 @@ function nodePorts(opts) {
|
|
|
276248
276486
|
return scoped;
|
|
276249
276487
|
const tier = classifyComplexity(estMin);
|
|
276250
276488
|
const routeDeps = opts.routeDeps;
|
|
276251
|
-
const rt = (process.env["ROLL_PROJECT_RUNTIME_DIR"] ?? "").trim() ||
|
|
276489
|
+
const rt = (process.env["ROLL_PROJECT_RUNTIME_DIR"] ?? "").trim() || join137(opts.repoCwd, ".roll", "loop");
|
|
276252
276490
|
const tried = storyId !== "" ? readSelfHeal(rt, storyId).triedAgents : [];
|
|
276253
276491
|
const dec = tried.length > 0 ? resolveRouteExcluding(tier, routeDeps, tried) ?? resolveRoute(tier, routeDeps) : resolveRoute(tier, routeDeps);
|
|
276254
276492
|
return { agent: dec.agent, model: dec.model ?? "" };
|
|
@@ -276256,7 +276494,7 @@ function nodePorts(opts) {
|
|
|
276256
276494
|
} : { resolve: () => ({ agent: "claude", model: "" }) },
|
|
276257
276495
|
evidence: {
|
|
276258
276496
|
openFrame(projectCwd, storyId, runId) {
|
|
276259
|
-
return openEvidenceFrame({ runDir:
|
|
276497
|
+
return openEvidenceFrame({ runDir: join137(cardArchiveDir(projectCwd, storyId), runId) }).runDir;
|
|
276260
276498
|
}
|
|
276261
276499
|
},
|
|
276262
276500
|
capture: {
|
|
@@ -276290,7 +276528,7 @@ function nodePorts(opts) {
|
|
|
276290
276528
|
};
|
|
276291
276529
|
}
|
|
276292
276530
|
function appendAlertLine(alertsPath, message) {
|
|
276293
|
-
mkdirSync65(
|
|
276531
|
+
mkdirSync65(dirname66(alertsPath), { recursive: true });
|
|
276294
276532
|
appendFileSync20(alertsPath, `${message}
|
|
276295
276533
|
`, "utf8");
|
|
276296
276534
|
}
|
|
@@ -276312,6 +276550,9 @@ async function executeCommand(cmd, ports, ctx) {
|
|
|
276312
276550
|
return executeSetupCommand(cmd, ports, ctx);
|
|
276313
276551
|
case "spawn_agent":
|
|
276314
276552
|
return executeSpawnAgentCommand(cmd, ports, ctx);
|
|
276553
|
+
// US-LOOP-102: adversarial role spawn (test_author/implementer/attacker).
|
|
276554
|
+
case "spawn_role":
|
|
276555
|
+
return executeSpawnRoleCommand(cmd, ports, ctx);
|
|
276315
276556
|
// layer). No feedback event (the orchestrator already transitioned).
|
|
276316
276557
|
case "kill_agent":
|
|
276317
276558
|
return {};
|
|
@@ -276356,13 +276597,13 @@ init_dist2();
|
|
|
276356
276597
|
init_dist2();
|
|
276357
276598
|
|
|
276358
276599
|
// packages/cli/dist/lib/cycle-attribution.js
|
|
276359
|
-
import { existsSync as
|
|
276600
|
+
import { existsSync as existsSync121, readFileSync as readFileSync122 } from "node:fs";
|
|
276360
276601
|
function readCycleAttributionFromEvents(eventsPath4, cycleId) {
|
|
276361
|
-
if (!
|
|
276602
|
+
if (!existsSync121(eventsPath4))
|
|
276362
276603
|
return {};
|
|
276363
276604
|
let content;
|
|
276364
276605
|
try {
|
|
276365
|
-
content =
|
|
276606
|
+
content = readFileSync122(eventsPath4, "utf8");
|
|
276366
276607
|
} catch {
|
|
276367
276608
|
return {};
|
|
276368
276609
|
}
|
|
@@ -276567,6 +276808,8 @@ function describeCommand(cmd) {
|
|
|
276567
276808
|
return `resolve_route \u2192 router.resolveRoute(${cmd.storyId})`;
|
|
276568
276809
|
case "spawn_agent":
|
|
276569
276810
|
return `spawn_agent \u2192 agentSpawn(${cmd.agent}, attempt ${cmd.attempt})`;
|
|
276811
|
+
case "spawn_role":
|
|
276812
|
+
return `spawn_role \u2192 agentSpawn(${cmd.agent} as ${cmd.role}, round ${cmd.round})`;
|
|
276570
276813
|
case "kill_agent":
|
|
276571
276814
|
return `kill_agent \u2192 SIGKILL (grace ${cmd.graceSec}s)`;
|
|
276572
276815
|
case "sleep_backoff":
|
|
@@ -276636,21 +276879,21 @@ function maybeSwitchAgent(deps) {
|
|
|
276636
276879
|
// packages/cli/dist/runner/correction-circuit.js
|
|
276637
276880
|
init_dist2();
|
|
276638
276881
|
init_dist();
|
|
276639
|
-
import { appendFileSync as appendFileSync21, existsSync as
|
|
276640
|
-
import { dirname as
|
|
276882
|
+
import { appendFileSync as appendFileSync21, existsSync as existsSync122, mkdirSync as mkdirSync66, readFileSync as readFileSync123, writeFileSync as writeFileSync65 } from "node:fs";
|
|
276883
|
+
import { dirname as dirname67, join as join138 } from "node:path";
|
|
276641
276884
|
function readLoopSafety(projectPath3) {
|
|
276642
276885
|
try {
|
|
276643
|
-
const path =
|
|
276644
|
-
if (!
|
|
276886
|
+
const path = join138(projectPath3, ".roll", "policy.yaml");
|
|
276887
|
+
if (!existsSync122(path))
|
|
276645
276888
|
return parsePolicy("").loopSafety;
|
|
276646
|
-
return parsePolicy(
|
|
276889
|
+
return parsePolicy(readFileSync123(path, "utf8")).loopSafety;
|
|
276647
276890
|
} catch {
|
|
276648
276891
|
return parsePolicy("").loopSafety;
|
|
276649
276892
|
}
|
|
276650
276893
|
}
|
|
276651
276894
|
function readEvents8(eventsPath4) {
|
|
276652
276895
|
try {
|
|
276653
|
-
return
|
|
276896
|
+
return readFileSync123(eventsPath4, "utf8").split("\n").map(parseEventLine).filter((ev) => ev !== null);
|
|
276654
276897
|
} catch {
|
|
276655
276898
|
return [];
|
|
276656
276899
|
}
|
|
@@ -276659,7 +276902,7 @@ function alreadyTripped(events, verdict) {
|
|
|
276659
276902
|
return events.some((ev) => ev.type === "correction:circuit_breaker" && ev.signal === verdict.signal && ev.threshold === verdict.threshold && (ev.storyId ?? "") === (verdict.storyId ?? ""));
|
|
276660
276903
|
}
|
|
276661
276904
|
function appendEvent2(eventsPath4, event) {
|
|
276662
|
-
mkdirSync66(
|
|
276905
|
+
mkdirSync66(dirname67(eventsPath4), { recursive: true });
|
|
276663
276906
|
appendFileSync21(eventsPath4, `${JSON.stringify(event)}
|
|
276664
276907
|
`, "utf8");
|
|
276665
276908
|
}
|
|
@@ -276673,8 +276916,8 @@ function applyCorrectionCircuitBreaker(projectPath3, slug3, eventsPath4, alertsP
|
|
|
276673
276916
|
return { status: "already_tripped", verdict };
|
|
276674
276917
|
const failure6 = classifyCorrectionFailure(verdict.signal);
|
|
276675
276918
|
const playbook = playbookForFailure(failure6.failureClass, failure6.rootCauseKey);
|
|
276676
|
-
const pauseMarker =
|
|
276677
|
-
const pauseWritten = !
|
|
276919
|
+
const pauseMarker = join138(projectPath3, ".roll", "loop", `PAUSE-${slug3}`);
|
|
276920
|
+
const pauseWritten = !existsSync122(pauseMarker);
|
|
276678
276921
|
const alertMsg = `# ALERT \u2014 correction circuit breaker tripped
|
|
276679
276922
|
|
|
276680
276923
|
**Reason**: ${verdict.reason}
|
|
@@ -276687,10 +276930,10 @@ function applyCorrectionCircuitBreaker(projectPath3, slug3, eventsPath4, alertsP
|
|
|
276687
276930
|
**Action**: loop paused to prevent unattended correction oscillation. Resume manually with \`roll loop resume\`.
|
|
276688
276931
|
`;
|
|
276689
276932
|
try {
|
|
276690
|
-
mkdirSync66(
|
|
276933
|
+
mkdirSync66(dirname67(pauseMarker), { recursive: true });
|
|
276691
276934
|
if (pauseWritten)
|
|
276692
276935
|
writeFileSync65(pauseMarker, alertMsg, "utf8");
|
|
276693
|
-
mkdirSync66(
|
|
276936
|
+
mkdirSync66(dirname67(alertsPath), { recursive: true });
|
|
276694
276937
|
appendFileSync21(alertsPath, `${alertMsg}
|
|
276695
276938
|
`, "utf8");
|
|
276696
276939
|
appendEvent2(eventsPath4, {
|
|
@@ -276723,23 +276966,23 @@ function announceReport(projectPath3, slug3, storyId, opener = (p) => {
|
|
|
276723
276966
|
}) {
|
|
276724
276967
|
if (storyId === "")
|
|
276725
276968
|
return null;
|
|
276726
|
-
const latest =
|
|
276727
|
-
const review =
|
|
276728
|
-
const legacyReport =
|
|
276729
|
-
const report =
|
|
276969
|
+
const latest = join139(cardArchiveDir(projectPath3, storyId), "latest");
|
|
276970
|
+
const review = join139(latest, reviewFileName(storyId));
|
|
276971
|
+
const legacyReport = join139(latest, reportFileName(storyId));
|
|
276972
|
+
const report = existsSync123(review) ? review : existsSync123(legacyReport) ? legacyReport : null;
|
|
276730
276973
|
if (report === null)
|
|
276731
276974
|
return null;
|
|
276732
276975
|
const label5 = currentLang() === "zh" ? "\u9A8C\u6536 Review Page" : "Acceptance Review Page";
|
|
276733
276976
|
process.stdout.write(`${label5}: ${report}
|
|
276734
276977
|
`);
|
|
276735
|
-
const muted =
|
|
276978
|
+
const muted = existsSync123(join139(projectPath3, ".roll", "loop", `mute-${slug3}`)) || existsSync123(join139(process.env["ROLL_SHARED_ROOT"] || join139(process.env["HOME"] ?? "", ".shared", "roll"), "loop", `mute-${slug3}`));
|
|
276736
276979
|
if (!muted)
|
|
276737
276980
|
opener(report);
|
|
276738
276981
|
return report;
|
|
276739
276982
|
}
|
|
276740
276983
|
function resetLiveLog(runtimeDirPath, cycleId) {
|
|
276741
276984
|
try {
|
|
276742
|
-
writeFileSync66(
|
|
276985
|
+
writeFileSync66(join139(runtimeDirPath, "live.log"), `=== cycle ${cycleId} ===
|
|
276743
276986
|
`, "utf8");
|
|
276744
276987
|
} catch {
|
|
276745
276988
|
}
|
|
@@ -276756,7 +276999,7 @@ function cycleSignalTeardown(paths, cycleId, branch, sig, deps = {}) {
|
|
|
276756
276999
|
}
|
|
276757
277000
|
let owned = false;
|
|
276758
277001
|
try {
|
|
276759
|
-
owned =
|
|
277002
|
+
owned = existsSync123(paths.lockPath) && readLockOwner(paths.lockPath)?.pid === pid;
|
|
276760
277003
|
} catch {
|
|
276761
277004
|
owned = false;
|
|
276762
277005
|
}
|
|
@@ -276859,7 +277102,7 @@ function makeCycleId(now2 = /* @__PURE__ */ new Date(), pid = process.pid) {
|
|
|
276859
277102
|
}
|
|
276860
277103
|
function runtimeDir11(projectPath3) {
|
|
276861
277104
|
const env = (process.env["ROLL_PROJECT_RUNTIME_DIR"] ?? "").trim();
|
|
276862
|
-
return env !== "" ? env :
|
|
277105
|
+
return env !== "" ? env : join139(projectPath3, ".roll", "loop");
|
|
276863
277106
|
}
|
|
276864
277107
|
var PAUSE_THRESHOLD = 3;
|
|
276865
277108
|
var GO_LOCK_STALE_SEC2 = 21600;
|
|
@@ -276891,11 +277134,11 @@ function writeCardSkipAlert(alertsPath, eventsPath4, cycleId, storyId, count) {
|
|
|
276891
277134
|
}
|
|
276892
277135
|
function incrementConsecutiveFails(projectPath3, slug3, alertsPath, eventsPath4, cycleId, storyId, terminal) {
|
|
276893
277136
|
const rt = runtimeDir11(projectPath3);
|
|
276894
|
-
const counterFile =
|
|
277137
|
+
const counterFile = join139(rt, "consecutive-fails");
|
|
276895
277138
|
let count = 0;
|
|
276896
277139
|
try {
|
|
276897
|
-
if (
|
|
276898
|
-
count = parseInt(
|
|
277140
|
+
if (existsSync123(counterFile)) {
|
|
277141
|
+
count = parseInt(readFileSync124(counterFile, "utf8").trim(), 10) || 0;
|
|
276899
277142
|
}
|
|
276900
277143
|
} catch {
|
|
276901
277144
|
}
|
|
@@ -276907,8 +277150,8 @@ function incrementConsecutiveFails(projectPath3, slug3, alertsPath, eventsPath4,
|
|
|
276907
277150
|
const threshold = readFailurePauseThreshold(projectPath3);
|
|
276908
277151
|
if (count < threshold)
|
|
276909
277152
|
return;
|
|
276910
|
-
const pauseMarker =
|
|
276911
|
-
if (
|
|
277153
|
+
const pauseMarker = join139(projectPath3, ".roll", "loop", `PAUSE-${slug3}`);
|
|
277154
|
+
if (existsSync123(pauseMarker))
|
|
276912
277155
|
return;
|
|
276913
277156
|
const alertMsg = `# ALERT \u2014 loop auto-paused after ${count} consecutive failures
|
|
276914
277157
|
|
|
@@ -276943,8 +277186,8 @@ loop run-once: \u8FDE\u7EED ${count} \u6B21\u5931\u8D25\u540E\u81EA\u52A8\u6682\
|
|
|
276943
277186
|
`);
|
|
276944
277187
|
}
|
|
276945
277188
|
function writeRootCausePause(projectPath3, slug3, alertsPath, eventsPath4, cycleId, attribution, count, snapshotPath2) {
|
|
276946
|
-
const pauseMarker =
|
|
276947
|
-
if (
|
|
277189
|
+
const pauseMarker = join139(projectPath3, ".roll", "loop", `PAUSE-${slug3}`);
|
|
277190
|
+
if (existsSync123(pauseMarker))
|
|
276948
277191
|
return;
|
|
276949
277192
|
const playbook = playbookForFailure(attribution.failureClass, attribution.rootCauseKey);
|
|
276950
277193
|
const alertMsg = `# ALERT \u2014 loop auto-paused on ${attribution.failureClass} failure
|
|
@@ -277005,10 +277248,10 @@ function handleNonCardFailure(projectPath3, slug3, alertsPath, eventsPath4, runt
|
|
|
277005
277248
|
}
|
|
277006
277249
|
function readFailurePauseThreshold(projectPath3) {
|
|
277007
277250
|
try {
|
|
277008
|
-
const policy =
|
|
277009
|
-
if (!
|
|
277251
|
+
const policy = join139(projectPath3, ".roll", "policy.yaml");
|
|
277252
|
+
if (!existsSync123(policy))
|
|
277010
277253
|
return PAUSE_THRESHOLD;
|
|
277011
|
-
return parsePolicy(
|
|
277254
|
+
return parsePolicy(readFileSync124(policy, "utf8")).loopSafety.maxConsecutiveFailures;
|
|
277012
277255
|
} catch {
|
|
277013
277256
|
return PAUSE_THRESHOLD;
|
|
277014
277257
|
}
|
|
@@ -277016,7 +277259,7 @@ function readFailurePauseThreshold(projectPath3) {
|
|
|
277016
277259
|
function resetConsecutiveFails(projectPath3) {
|
|
277017
277260
|
const rt = runtimeDir11(projectPath3);
|
|
277018
277261
|
try {
|
|
277019
|
-
writeFileSync66(
|
|
277262
|
+
writeFileSync66(join139(rt, "consecutive-fails"), "0", "utf8");
|
|
277020
277263
|
} catch {
|
|
277021
277264
|
}
|
|
277022
277265
|
}
|
|
@@ -277030,14 +277273,14 @@ loop run-once: ${storyId} \u2014 \u4EE3\u7406\u5168\u90E8\u8017\u5C3D(${failCoun
|
|
|
277030
277273
|
}
|
|
277031
277274
|
}
|
|
277032
277275
|
function idleCounterPath(projectPath3, slug3) {
|
|
277033
|
-
return
|
|
277276
|
+
return join139(runtimeDir11(projectPath3), `consecutive-idle-${slug3}`);
|
|
277034
277277
|
}
|
|
277035
277278
|
function incrementConsecutiveIdle(projectPath3, slug3) {
|
|
277036
277279
|
const file = idleCounterPath(projectPath3, slug3);
|
|
277037
277280
|
let count = 0;
|
|
277038
277281
|
try {
|
|
277039
|
-
if (
|
|
277040
|
-
count = parseInt(
|
|
277282
|
+
if (existsSync123(file)) {
|
|
277283
|
+
count = parseInt(readFileSync124(file, "utf8").trim(), 10) || 0;
|
|
277041
277284
|
}
|
|
277042
277285
|
} catch {
|
|
277043
277286
|
}
|
|
@@ -277103,9 +277346,9 @@ function readExternalBlock(eventsPath4, cycleId) {
|
|
|
277103
277346
|
const authDetails = [];
|
|
277104
277347
|
const networkDetails = [];
|
|
277105
277348
|
try {
|
|
277106
|
-
if (!
|
|
277349
|
+
if (!existsSync123(eventsPath4))
|
|
277107
277350
|
return null;
|
|
277108
|
-
for (const line of
|
|
277351
|
+
for (const line of readFileSync124(eventsPath4, "utf8").split("\n")) {
|
|
277109
277352
|
if (line.trim() === "" || !line.includes("agent:blocked"))
|
|
277110
277353
|
continue;
|
|
277111
277354
|
let e;
|
|
@@ -277167,8 +277410,8 @@ function writeReviewerBlockedAlert(projectPath3, slug3, alertsPath, eventsPath4,
|
|
|
277167
277410
|
} catch {
|
|
277168
277411
|
}
|
|
277169
277412
|
if (block.cause === "auth") {
|
|
277170
|
-
const pauseMarker =
|
|
277171
|
-
if (!
|
|
277413
|
+
const pauseMarker = join139(projectPath3, ".roll", "loop", `PAUSE-${slug3}`);
|
|
277414
|
+
if (!existsSync123(pauseMarker)) {
|
|
277172
277415
|
try {
|
|
277173
277416
|
writeFileSync66(pauseMarker, msg6, "utf8");
|
|
277174
277417
|
bus.appendEvent(eventsPath4, { type: "policy:safety_pause", loop: "ci", reason: `agent auth block: ${agents}`, ts: ts2 });
|
|
@@ -277187,15 +277430,15 @@ function readSkillBody3(projectPath3) {
|
|
|
277187
277430
|
}
|
|
277188
277431
|
function buildLoopRouteDeps(projectPath3) {
|
|
277189
277432
|
function readSlot(slot) {
|
|
277190
|
-
const agentsYaml =
|
|
277433
|
+
const agentsYaml = join139(projectPath3, ".roll", "agents.yaml");
|
|
277191
277434
|
try {
|
|
277192
|
-
return readSlotFromText(
|
|
277435
|
+
return readSlotFromText(readFileSync124(agentsYaml, "utf8"), slot);
|
|
277193
277436
|
} catch {
|
|
277194
277437
|
return void 0;
|
|
277195
277438
|
}
|
|
277196
277439
|
}
|
|
277197
277440
|
function firstInstalled() {
|
|
277198
|
-
const fromLocal = readField(
|
|
277441
|
+
const fromLocal = readField(join139(projectPath3, ".roll", "local.yaml"), /^agent:/);
|
|
277199
277442
|
if (fromLocal !== void 0)
|
|
277200
277443
|
return fromLocal;
|
|
277201
277444
|
return firstInstalledAgent(realAgentEnv());
|
|
@@ -277204,7 +277447,7 @@ function buildLoopRouteDeps(projectPath3) {
|
|
|
277204
277447
|
}
|
|
277205
277448
|
function readField(path, re) {
|
|
277206
277449
|
try {
|
|
277207
|
-
const text2 =
|
|
277450
|
+
const text2 = readFileSync124(path, "utf8");
|
|
277208
277451
|
for (const line of text2.split("\n")) {
|
|
277209
277452
|
const m7 = line.match(re);
|
|
277210
277453
|
if (m7 !== null) {
|
|
@@ -277236,9 +277479,9 @@ async function loopRunOnceCommand(args) {
|
|
|
277236
277479
|
try {
|
|
277237
277480
|
const markerIdx = id.path.indexOf(WORKTREE_MARKER);
|
|
277238
277481
|
const stableProjectPath = markerIdx !== -1 ? id.path.slice(0, markerIdx) : cwd;
|
|
277239
|
-
const stableRt =
|
|
277240
|
-
mkdirSync67(
|
|
277241
|
-
appendFileSync22(
|
|
277482
|
+
const stableRt = join139(stableProjectPath, ".roll", "loop");
|
|
277483
|
+
mkdirSync67(dirname68(stableRt), { recursive: true });
|
|
277484
|
+
appendFileSync22(join139(stableRt, `ALERT-${id.slug}.md`), `${msg6}
|
|
277242
277485
|
`, "utf8");
|
|
277243
277486
|
} catch {
|
|
277244
277487
|
}
|
|
@@ -277265,8 +277508,8 @@ async function loopRunOnceCommand(args) {
|
|
|
277265
277508
|
return 0;
|
|
277266
277509
|
}
|
|
277267
277510
|
const rt = runtimeDir11(id.path);
|
|
277268
|
-
const alertsPath =
|
|
277269
|
-
mkdirSync67(
|
|
277511
|
+
const alertsPath = join139(rt, `ALERT-${id.slug}.md`);
|
|
277512
|
+
mkdirSync67(dirname68(alertsPath), { recursive: true });
|
|
277270
277513
|
if (coreWorktreeHeal.healed) {
|
|
277271
277514
|
try {
|
|
277272
277515
|
appendFileSync22(alertsPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] ALERT FIX-1209: core.worktree was pointing to "${coreWorktreeHeal.detail}" \u2014 auto-unset before project identity resolution
|
|
@@ -277277,16 +277520,16 @@ async function loopRunOnceCommand(args) {
|
|
|
277277
277520
|
`);
|
|
277278
277521
|
}
|
|
277279
277522
|
const paths = {
|
|
277280
|
-
eventsPath:
|
|
277281
|
-
runsPath:
|
|
277523
|
+
eventsPath: join139(rt, "events.ndjson"),
|
|
277524
|
+
runsPath: join139(rt, "runs.jsonl"),
|
|
277282
277525
|
alertsPath,
|
|
277283
|
-
lockPath:
|
|
277284
|
-
heartbeatPath:
|
|
277285
|
-
worktreePath:
|
|
277526
|
+
lockPath: join139(rt, "inner.lock"),
|
|
277527
|
+
heartbeatPath: join139(rt, "heartbeat"),
|
|
277528
|
+
worktreePath: join139(rt, "worktrees", `cycle-${cycleId}`)
|
|
277286
277529
|
};
|
|
277287
277530
|
const allowedCards = parseAllowedCardsEnv();
|
|
277288
277531
|
if (allowedCards === void 0) {
|
|
277289
|
-
const goLockOwner = readLockOwner(
|
|
277532
|
+
const goLockOwner = readLockOwner(join139(rt, "go.lock"));
|
|
277290
277533
|
if (isOwnerHeld(goLockOwner, Math.floor(Date.now() / 1e3), GO_LOCK_STALE_SEC2)) {
|
|
277291
277534
|
const ts2 = Math.floor(Date.now() / 1e3);
|
|
277292
277535
|
new EventBus().appendEvent(paths.eventsPath, {
|
|
@@ -277370,7 +277613,7 @@ loop run-once: ${repoCheck.detail !== "" ? `(${repoCheck.detail})` : ""}
|
|
|
277370
277613
|
process.stderr.write(`loop run-once: roll-loop SKILL.md not found \u2014 refusing to spawn a blind agent (ALERT written)
|
|
277371
277614
|
loop run-once: \u627E\u4E0D\u5230 roll-loop SKILL.md \u2014 \u62D2\u7EDD\u76F2\u5F00 agent(\u5DF2\u5199 ALERT)
|
|
277372
277615
|
`);
|
|
277373
|
-
incrementConsecutiveFails(id.path, id.slug, alertsPath,
|
|
277616
|
+
incrementConsecutiveFails(id.path, id.slug, alertsPath, join139(rt, "events.ndjson"), cycleId, "", "skill_missing");
|
|
277374
277617
|
return 1;
|
|
277375
277618
|
}
|
|
277376
277619
|
const routeDeps = buildLoopRouteDeps(id.path);
|
|
@@ -277467,13 +277710,13 @@ loop run-once: \u8BC4\u5BA1\u5224\u5B9A ${resizeStory} \u8303\u56F4\u8FC7\u5927(
|
|
|
277467
277710
|
const idleCount = incrementConsecutiveIdle(id.path, id.slug);
|
|
277468
277711
|
try {
|
|
277469
277712
|
const bus = new EventBus();
|
|
277470
|
-
const backlogFile =
|
|
277713
|
+
const backlogFile = join139(id.path, ".roll", "backlog.md");
|
|
277471
277714
|
const nowSec2 = Math.floor(Date.now() / 1e3);
|
|
277472
277715
|
const outcome = await maybeEnterDormancy({
|
|
277473
277716
|
slug: id.slug,
|
|
277474
277717
|
count: idleCount,
|
|
277475
277718
|
resolveState: () => resolveLoopRunState(id.path, id.slug),
|
|
277476
|
-
readBacklog: () =>
|
|
277719
|
+
readBacklog: () => existsSync123(backlogFile) ? readFileSync124(backlogFile, "utf8") : "",
|
|
277477
277720
|
scheduler: createScheduler(process.platform, { uid: process.getuid?.() ?? 0 }),
|
|
277478
277721
|
loopLabel: launchdLabel("loop", id.slug),
|
|
277479
277722
|
now: () => (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -277481,8 +277724,8 @@ loop run-once: \u8BC4\u5BA1\u5224\u5B9A ${resizeStory} \u8303\u56F4\u8FC7\u5927(
|
|
|
277481
277724
|
writeDormant: (body) => writeDormantMarker(dormantMarkerPath(id.path, id.slug), body),
|
|
277482
277725
|
upsertDormantRun: () => bus.upsertRun(paths.runsPath, { storyId: "", cycleId }, buildRunRow({ kind: "append_run", status: "dormant", outcome: mapV2Status("dormant"), cycleId }, { cycleId, branch, loop: "ci" }, nowSec2)),
|
|
277483
277726
|
writePause: (reason) => {
|
|
277484
|
-
const p =
|
|
277485
|
-
mkdirSync67(
|
|
277727
|
+
const p = join139(id.path, ".roll", "loop", `PAUSE-${id.slug}`);
|
|
277728
|
+
mkdirSync67(dirname68(p), { recursive: true });
|
|
277486
277729
|
writeFileSync66(p, `# loop paused \u2014 dormancy bootout failed
|
|
277487
277730
|
|
|
277488
277731
|
${reason}
|
|
@@ -277523,7 +277766,7 @@ loop run-once: cycle ${cycleId} \u2192 ${externalBlock.cause}_blocked(\u53EF\u60
|
|
|
277523
277766
|
const failedAgent = (result.state?.ctx?.agent ?? "").trim();
|
|
277524
277767
|
const zeroTcr = tcr === 0 && (result.terminal === "gave_up" || result.terminal === "blocked");
|
|
277525
277768
|
if (sid !== "" && failedAgent !== "" && zeroTcr) {
|
|
277526
|
-
const backlogFile =
|
|
277769
|
+
const backlogFile = join139(id.path, ".roll", "backlog.md");
|
|
277527
277770
|
const bus = new EventBus();
|
|
277528
277771
|
const swapped = autoRecoverEnabled() ? maybeSwitchAgent({
|
|
277529
277772
|
runtimeDir: runtimeDir11(id.path),
|
|
@@ -277540,7 +277783,7 @@ loop run-once: cycle ${cycleId} \u2192 ${externalBlock.cause}_blocked(\u53EF\u60
|
|
|
277540
277783
|
emit: (ev) => bus.appendEvent(paths.eventsPath, ev),
|
|
277541
277784
|
remarkTodo: (storyId) => {
|
|
277542
277785
|
try {
|
|
277543
|
-
const content =
|
|
277786
|
+
const content = readFileSync124(backlogFile, "utf8");
|
|
277544
277787
|
const r = markStatus(content, storyId, STATUS_MARKER.todo);
|
|
277545
277788
|
if (r.count > 0)
|
|
277546
277789
|
writeFileSync66(backlogFile, r.content, "utf8");
|
|
@@ -277658,7 +277901,7 @@ async function isOffline(resolve14 = (h) => lookup2(h)) {
|
|
|
277658
277901
|
}
|
|
277659
277902
|
}
|
|
277660
277903
|
function isLoopPaused(projectPath3, slug3) {
|
|
277661
|
-
return
|
|
277904
|
+
return existsSync123(join139(projectPath3, ".roll", "loop", `PAUSE-${slug3}`));
|
|
277662
277905
|
}
|
|
277663
277906
|
function branchCanaryTrips(projectPath3, slug3, rt, alertsPath) {
|
|
277664
277907
|
let ephemeralBranchCount = 0;
|
|
@@ -277669,7 +277912,7 @@ function branchCanaryTrips(projectPath3, slug3, rt, alertsPath) {
|
|
|
277669
277912
|
}
|
|
277670
277913
|
let worktreeCount = 0;
|
|
277671
277914
|
try {
|
|
277672
|
-
worktreeCount = readdirSync45(
|
|
277915
|
+
worktreeCount = readdirSync45(join139(rt, "worktrees"), { withFileTypes: true }).filter((e) => e.isDirectory()).length;
|
|
277673
277916
|
} catch {
|
|
277674
277917
|
}
|
|
277675
277918
|
const parsed = parseInt(process.env["ROLL_BRANCH_CANARY_MAX"] ?? "", 10);
|
|
@@ -277681,7 +277924,7 @@ function branchCanaryTrips(projectPath3, slug3, rt, alertsPath) {
|
|
|
277681
277924
|
alreadyPaused: isLoopPaused(projectPath3, slug3)
|
|
277682
277925
|
});
|
|
277683
277926
|
if (verdict.shouldPause) {
|
|
277684
|
-
const pauseMarker =
|
|
277927
|
+
const pauseMarker = join139(projectPath3, ".roll", "loop", `PAUSE-${slug3}`);
|
|
277685
277928
|
const msg6 = `# ALERT \u2014 loop auto-paused: branch/worktree leak canary tripped (US-LOOP-096)
|
|
277686
277929
|
|
|
277687
277930
|
**Leak count**: ${verdict.total} (ephemeral branches ${ephemeralBranchCount} + worktrees ${worktreeCount}) > threshold ${threshold}
|
|
@@ -277689,7 +277932,7 @@ function branchCanaryTrips(projectPath3, slug3, rt, alertsPath) {
|
|
|
277689
277932
|
Inspect \`git branch\` / \`git worktree list\`, clean up, then: \`roll loop resume\`
|
|
277690
277933
|
`;
|
|
277691
277934
|
try {
|
|
277692
|
-
mkdirSync67(
|
|
277935
|
+
mkdirSync67(dirname68(pauseMarker), { recursive: true });
|
|
277693
277936
|
writeFileSync66(pauseMarker, msg6, "utf8");
|
|
277694
277937
|
} catch {
|
|
277695
277938
|
}
|
|
@@ -277756,16 +277999,16 @@ function checkCoreWorktreeContamination(cwd) {
|
|
|
277756
277999
|
const main = repairCoreWorktreeContamination(cwd);
|
|
277757
278000
|
if (main.healed)
|
|
277758
278001
|
return main;
|
|
277759
|
-
const meta8 = repairCoreWorktreeContamination(
|
|
278002
|
+
const meta8 = repairCoreWorktreeContamination(join139(cwd, ".roll"));
|
|
277760
278003
|
return meta8.healed ? { healed: true, detail: `roll-meta: ${meta8.detail}` } : meta8;
|
|
277761
278004
|
}
|
|
277762
278005
|
|
|
277763
278006
|
// packages/cli/dist/commands/offboard.js
|
|
277764
278007
|
init_dist();
|
|
277765
278008
|
import { spawnSync as spawnSync16 } from "node:child_process";
|
|
277766
|
-
import { existsSync as
|
|
278009
|
+
import { existsSync as existsSync124, readFileSync as readFileSync125, realpathSync as realpathSync18, renameSync as renameSync25, rmSync as rmSync23, writeFileSync as writeFileSync67 } from "node:fs";
|
|
277767
278010
|
import { homedir as homedir30 } from "node:os";
|
|
277768
|
-
import { join as
|
|
278011
|
+
import { join as join140, resolve as resolve11 } from "node:path";
|
|
277769
278012
|
function pal5() {
|
|
277770
278013
|
const noColor2 = (process.env["NO_COLOR"] ?? "") !== "";
|
|
277771
278014
|
return noColor2 ? { RED: "", GREEN: "", YELLOW: "", CYAN: "", BOLD: "", NC: "" } : {
|
|
@@ -277803,7 +278046,7 @@ function m4(key, ...args) {
|
|
|
277803
278046
|
return t(v2Catalog, msgLang7(), key, ...args);
|
|
277804
278047
|
}
|
|
277805
278048
|
function changesetPath2(projectDir) {
|
|
277806
|
-
return
|
|
278049
|
+
return join140(projectDir, ".roll", "onboard-changeset.yaml");
|
|
277807
278050
|
}
|
|
277808
278051
|
function loopInCycle2() {
|
|
277809
278052
|
return (process.env["ROLL_LOOP_AGENT"] ?? "") !== "" || (process.env["ROLL_CYCLE_LOG_RAW"] ?? "") !== "";
|
|
@@ -277813,7 +278056,7 @@ function runLaunchctl(args) {
|
|
|
277813
278056
|
if (args[0] !== void 0 && readOnly.has(args[0])) {
|
|
277814
278057
|
return spawnSync16("launchctl", args, { stdio: "inherit" }).status ?? 1;
|
|
277815
278058
|
}
|
|
277816
|
-
const canonical =
|
|
278059
|
+
const canonical = join140(homedir30(), "Library", "LaunchAgents");
|
|
277817
278060
|
const launchdDir = process.env["_LAUNCHD_DIR"] ?? canonical;
|
|
277818
278061
|
if (launchdDir !== canonical)
|
|
277819
278062
|
return 0;
|
|
@@ -277864,7 +278107,7 @@ function writeFileAtomic2(path, text2) {
|
|
|
277864
278107
|
writeFileSync67(tmp, text2);
|
|
277865
278108
|
renameSync25(tmp, path);
|
|
277866
278109
|
} catch (error) {
|
|
277867
|
-
|
|
278110
|
+
rmSync23(tmp, { force: true });
|
|
277868
278111
|
throw error;
|
|
277869
278112
|
}
|
|
277870
278113
|
}
|
|
@@ -277895,7 +278138,7 @@ function offboardCommand(args) {
|
|
|
277895
278138
|
projectDir = process.cwd();
|
|
277896
278139
|
}
|
|
277897
278140
|
const changeset = changesetPath2(projectDir);
|
|
277898
|
-
if (!
|
|
278141
|
+
if (!existsSync124(changeset)) {
|
|
277899
278142
|
err10(m4("offboard.no_changeset_en"));
|
|
277900
278143
|
err10(m4("offboard.no_changeset_zh"));
|
|
277901
278144
|
process.stderr.write("\n");
|
|
@@ -277909,7 +278152,7 @@ function offboardCommand(args) {
|
|
|
277909
278152
|
`);
|
|
277910
278153
|
return 1;
|
|
277911
278154
|
}
|
|
277912
|
-
const parsed = parseChangeset(
|
|
278155
|
+
const parsed = parseChangeset(readFileSync125(changeset, "utf8"));
|
|
277913
278156
|
if (!parsed.ok) {
|
|
277914
278157
|
err10(m4("offboard.failed_to_parse_changeset"));
|
|
277915
278158
|
return 1;
|
|
@@ -277994,9 +278237,9 @@ function offboardCommand(args) {
|
|
|
277994
278237
|
process.stdout.write(m4("offboard.applying_offboard") + "\n");
|
|
277995
278238
|
for (const item of mergedFiles) {
|
|
277996
278239
|
const path = resolveChangesetItem(projectDir, item);
|
|
277997
|
-
if (!
|
|
278240
|
+
if (!existsSync124(path))
|
|
277998
278241
|
continue;
|
|
277999
|
-
const before =
|
|
278242
|
+
const before = readFileSync125(path, "utf8");
|
|
278000
278243
|
const after = stripRollMergeBlocks(before);
|
|
278001
278244
|
if (after !== before) {
|
|
278002
278245
|
writeFileAtomic2(path, after);
|
|
@@ -278007,8 +278250,8 @@ function offboardCommand(args) {
|
|
|
278007
278250
|
for (const item of files) {
|
|
278008
278251
|
try {
|
|
278009
278252
|
const path = resolveChangesetItem(projectDir, item);
|
|
278010
|
-
|
|
278011
|
-
if (!
|
|
278253
|
+
rmSync23(path, { force: true });
|
|
278254
|
+
if (!existsSync124(path))
|
|
278012
278255
|
process.stdout.write(` removed file ${item}
|
|
278013
278256
|
`);
|
|
278014
278257
|
} catch {
|
|
@@ -278016,16 +278259,16 @@ function offboardCommand(args) {
|
|
|
278016
278259
|
}
|
|
278017
278260
|
for (const item of dirs) {
|
|
278018
278261
|
try {
|
|
278019
|
-
|
|
278262
|
+
rmSync23(resolveChangesetItem(projectDir, item), { recursive: true, force: true });
|
|
278020
278263
|
process.stdout.write(` removed dir ${item}
|
|
278021
278264
|
`);
|
|
278022
278265
|
} catch {
|
|
278023
278266
|
}
|
|
278024
278267
|
}
|
|
278025
278268
|
for (const item of giEntries) {
|
|
278026
|
-
const gi =
|
|
278027
|
-
if (
|
|
278028
|
-
const lines3 =
|
|
278269
|
+
const gi = join140(projectDir, ".gitignore");
|
|
278270
|
+
if (existsSync124(gi)) {
|
|
278271
|
+
const lines3 = readFileSync125(gi, "utf8").split("\n");
|
|
278029
278272
|
if (lines3.includes(item)) {
|
|
278030
278273
|
const kept = lines3.filter((l) => l !== item);
|
|
278031
278274
|
writeFileAtomic2(gi, kept.join("\n"));
|
|
@@ -278035,27 +278278,27 @@ function offboardCommand(args) {
|
|
|
278035
278278
|
}
|
|
278036
278279
|
}
|
|
278037
278280
|
for (const item of plists) {
|
|
278038
|
-
const plistPath =
|
|
278281
|
+
const plistPath = join140(homedir30(), "Library", "LaunchAgents", item);
|
|
278039
278282
|
const r = runLaunchctl(["unload", "-w", plistPath]);
|
|
278040
278283
|
if (r === 0)
|
|
278041
278284
|
process.stdout.write(` unloaded ${item}
|
|
278042
278285
|
`);
|
|
278043
|
-
|
|
278286
|
+
rmSync23(plistPath, { force: true });
|
|
278044
278287
|
}
|
|
278045
|
-
|
|
278288
|
+
rmSync23(changeset, { force: true });
|
|
278046
278289
|
ok11(m4("offboard.offboard_complete_offboard"));
|
|
278047
278290
|
return 0;
|
|
278048
278291
|
}
|
|
278049
278292
|
|
|
278050
278293
|
// packages/cli/dist/commands/prices.js
|
|
278051
278294
|
init_dist();
|
|
278052
|
-
import { existsSync as
|
|
278053
|
-
import { join as
|
|
278295
|
+
import { existsSync as existsSync126, readdirSync as readdirSync47, readFileSync as readFileSync127 } from "node:fs";
|
|
278296
|
+
import { join as join142 } from "node:path";
|
|
278054
278297
|
|
|
278055
278298
|
// packages/cli/dist/commands/prices-refresh.js
|
|
278056
278299
|
init_dist();
|
|
278057
|
-
import { existsSync as
|
|
278058
|
-
import { join as
|
|
278300
|
+
import { existsSync as existsSync125, mkdirSync as mkdirSync68, readdirSync as readdirSync46, readFileSync as readFileSync126, writeFileSync as writeFileSync68 } from "node:fs";
|
|
278301
|
+
import { join as join141 } from "node:path";
|
|
278059
278302
|
var FetchError = class extends Error {
|
|
278060
278303
|
constructor(message) {
|
|
278061
278304
|
super(message);
|
|
@@ -278276,13 +278519,13 @@ function vendorFromSnapshotName(name) {
|
|
|
278276
278519
|
return match[2] ?? "anthropic";
|
|
278277
278520
|
}
|
|
278278
278521
|
function latestSnapshotPath(snapshotDir, vendor) {
|
|
278279
|
-
if (!
|
|
278522
|
+
if (!existsSync125(snapshotDir))
|
|
278280
278523
|
return null;
|
|
278281
|
-
const snaps = readdirSync46(snapshotDir).filter((name) => SNAPSHOT_RE.test(name) && vendorFromSnapshotName(name) === vendor).sort().map((name) =>
|
|
278524
|
+
const snaps = readdirSync46(snapshotDir).filter((name) => SNAPSHOT_RE.test(name) && vendorFromSnapshotName(name) === vendor).sort().map((name) => join141(snapshotDir, name));
|
|
278282
278525
|
return snaps[snaps.length - 1] ?? null;
|
|
278283
278526
|
}
|
|
278284
278527
|
function readPrices(path) {
|
|
278285
|
-
const data = JSON.parse(
|
|
278528
|
+
const data = JSON.parse(readFileSync126(path, "utf8"));
|
|
278286
278529
|
return data.prices ?? {};
|
|
278287
278530
|
}
|
|
278288
278531
|
function diffPrices(oldPrices, newPrices) {
|
|
@@ -278375,7 +278618,7 @@ function snapshotJson(payload) {
|
|
|
278375
278618
|
function writeSnapshot(input) {
|
|
278376
278619
|
mkdirSync68(input.snapshotDir, { recursive: true });
|
|
278377
278620
|
const suffix = input.vendor === "anthropic" ? "" : `-${input.vendor}`;
|
|
278378
|
-
const dest =
|
|
278621
|
+
const dest = join141(input.snapshotDir, `snapshot-${input.effectiveAt}${suffix}.json`);
|
|
278379
278622
|
writeFileSync68(dest, snapshotJson({
|
|
278380
278623
|
version: input.effectiveAt,
|
|
278381
278624
|
effective_at: input.effectiveAt,
|
|
@@ -278447,7 +278690,7 @@ async function pricesRefreshCommand(args, deps = {}) {
|
|
|
278447
278690
|
} else {
|
|
278448
278691
|
vendor = "anthropic";
|
|
278449
278692
|
}
|
|
278450
|
-
const snapshotDir = deps.snapshotDir ??
|
|
278693
|
+
const snapshotDir = deps.snapshotDir ?? join141(repoRoot2(), "lib", "prices");
|
|
278451
278694
|
try {
|
|
278452
278695
|
const result = await refresh({ snapshotDir, vendor, url, deps });
|
|
278453
278696
|
if (result.action === "unchanged") {
|
|
@@ -278484,13 +278727,13 @@ async function pricesRefreshCommand(args, deps = {}) {
|
|
|
278484
278727
|
|
|
278485
278728
|
// packages/cli/dist/commands/prices.js
|
|
278486
278729
|
function loadSnapshots() {
|
|
278487
|
-
const dir =
|
|
278488
|
-
if (!
|
|
278730
|
+
const dir = join142(repoRoot2(), "lib", "prices");
|
|
278731
|
+
if (!existsSync126(dir)) {
|
|
278489
278732
|
throw new Error(`no price snapshots found in ${dir}; run \`roll prices refresh\``);
|
|
278490
278733
|
}
|
|
278491
278734
|
const files = readdirSync47(dir).filter((n) => n.startsWith("snapshot-") && n.endsWith(".json")).sort();
|
|
278492
278735
|
return files.map((name) => {
|
|
278493
|
-
const data = JSON.parse(
|
|
278736
|
+
const data = JSON.parse(readFileSync127(join142(dir, name), "utf8"));
|
|
278494
278737
|
for (const key of ["version", "effective_at", "source_url", "prices"]) {
|
|
278495
278738
|
if (data[key] === void 0)
|
|
278496
278739
|
throw new Error(`snapshot ${name} missing required key ${key}`);
|
|
@@ -278669,24 +278912,24 @@ init_dist3();
|
|
|
278669
278912
|
init_dist();
|
|
278670
278913
|
init_render();
|
|
278671
278914
|
import { execFileSync as execFileSync33 } from "node:child_process";
|
|
278672
|
-
import { mkdirSync as mkdirSync72, readFileSync as
|
|
278673
|
-
import { dirname as
|
|
278915
|
+
import { mkdirSync as mkdirSync72, readFileSync as readFileSync131, writeFileSync as writeFileSync72, existsSync as existsSync130 } from "node:fs";
|
|
278916
|
+
import { dirname as dirname72, join as join146 } from "node:path";
|
|
278674
278917
|
|
|
278675
278918
|
// packages/cli/dist/lib/release-consistency.js
|
|
278676
278919
|
init_dist2();
|
|
278677
278920
|
init_dist();
|
|
278678
278921
|
init_render();
|
|
278679
278922
|
import { execFileSync as execFileSync32 } from "node:child_process";
|
|
278680
|
-
import { existsSync as
|
|
278681
|
-
import { dirname as
|
|
278923
|
+
import { existsSync as existsSync128, mkdirSync as mkdirSync70, readFileSync as readFileSync129, readdirSync as readdirSync49, statSync as statSync39, writeFileSync as writeFileSync70 } from "node:fs";
|
|
278924
|
+
import { dirname as dirname70, join as join144 } from "node:path";
|
|
278682
278925
|
|
|
278683
278926
|
// packages/cli/dist/lib/consistency-audit.js
|
|
278684
278927
|
init_dist2();
|
|
278685
278928
|
init_dist3();
|
|
278686
278929
|
init_dist();
|
|
278687
278930
|
import { execFile as execFile17 } from "node:child_process";
|
|
278688
|
-
import { existsSync as
|
|
278689
|
-
import { dirname as
|
|
278931
|
+
import { existsSync as existsSync127, mkdirSync as mkdirSync69, readFileSync as readFileSync128, readdirSync as readdirSync48, writeFileSync as writeFileSync69 } from "node:fs";
|
|
278932
|
+
import { dirname as dirname69, join as join143 } from "node:path";
|
|
278690
278933
|
import { promisify as promisify17 } from "node:util";
|
|
278691
278934
|
init_dist();
|
|
278692
278935
|
init_dist();
|
|
@@ -278694,10 +278937,10 @@ var PROBE_CAP = 20;
|
|
|
278694
278937
|
var COUNT_WINDOW_SEC = 72 * 3600;
|
|
278695
278938
|
var execFileAsync17 = promisify17(execFile17);
|
|
278696
278939
|
function readJsonl(path) {
|
|
278697
|
-
if (!
|
|
278940
|
+
if (!existsSync127(path))
|
|
278698
278941
|
return [];
|
|
278699
278942
|
const out3 = [];
|
|
278700
|
-
for (const line of
|
|
278943
|
+
for (const line of readFileSync128(path, "utf8").split("\n")) {
|
|
278701
278944
|
if (line.trim() === "")
|
|
278702
278945
|
continue;
|
|
278703
278946
|
try {
|
|
@@ -278710,18 +278953,18 @@ function readJsonl(path) {
|
|
|
278710
278953
|
return out3;
|
|
278711
278954
|
}
|
|
278712
278955
|
function readJson(path) {
|
|
278713
|
-
if (!
|
|
278956
|
+
if (!existsSync127(path))
|
|
278714
278957
|
return null;
|
|
278715
278958
|
try {
|
|
278716
|
-
const parsed = JSON.parse(
|
|
278959
|
+
const parsed = JSON.parse(readFileSync128(path, "utf8"));
|
|
278717
278960
|
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : null;
|
|
278718
278961
|
} catch {
|
|
278719
278962
|
return null;
|
|
278720
278963
|
}
|
|
278721
278964
|
}
|
|
278722
278965
|
function hasScreenshotArtifact(reportPath) {
|
|
278723
|
-
const runDir =
|
|
278724
|
-
const manifest = readJson(
|
|
278966
|
+
const runDir = dirname69(reportPath);
|
|
278967
|
+
const manifest = readJson(join143(runDir, "evidence.json"));
|
|
278725
278968
|
if (manifest !== null) {
|
|
278726
278969
|
const screenshots = manifest["screenshots"];
|
|
278727
278970
|
if (Array.isArray(screenshots) && screenshots.some((x) => typeof x === "string" && x !== ""))
|
|
@@ -278737,8 +278980,8 @@ function hasScreenshotArtifact(reportPath) {
|
|
|
278737
278980
|
}
|
|
278738
278981
|
}
|
|
278739
278982
|
}
|
|
278740
|
-
const dir =
|
|
278741
|
-
if (!
|
|
278983
|
+
const dir = join143(runDir, "screenshots");
|
|
278984
|
+
if (!existsSync127(dir))
|
|
278742
278985
|
return false;
|
|
278743
278986
|
try {
|
|
278744
278987
|
return readdirSync48(dir).some((name) => /\.png$/i.test(name));
|
|
@@ -278747,7 +278990,7 @@ function hasScreenshotArtifact(reportPath) {
|
|
|
278747
278990
|
}
|
|
278748
278991
|
}
|
|
278749
278992
|
function hasMachineCaptureSkip2(reportPath) {
|
|
278750
|
-
const manifest = readJson(
|
|
278993
|
+
const manifest = readJson(join143(dirname69(reportPath), "evidence.json"));
|
|
278751
278994
|
const captures = manifest?.["captures"];
|
|
278752
278995
|
if (!Array.isArray(captures))
|
|
278753
278996
|
return false;
|
|
@@ -278774,18 +279017,18 @@ async function gatherAuditSnapshot(projectPath3, runtimeDir12, deps = {}) {
|
|
|
278774
279017
|
const nowSec2 = deps.nowSec ?? Math.floor(Date.now() / 1e3);
|
|
278775
279018
|
const snapshot = emptyAuditSnapshot(nowSec2, TERMINAL_SCHEMA_EPOCH_SEC);
|
|
278776
279019
|
const skipped2 = [];
|
|
278777
|
-
const backlogPath =
|
|
278778
|
-
if (
|
|
278779
|
-
snapshot.backlog = parseBacklog(
|
|
279020
|
+
const backlogPath = join143(projectPath3, ".roll", "backlog.md");
|
|
279021
|
+
if (existsSync127(backlogPath)) {
|
|
279022
|
+
snapshot.backlog = parseBacklog(readFileSync128(backlogPath, "utf8")).map((r) => ({ id: r.id, status: r.status }));
|
|
278780
279023
|
}
|
|
278781
279024
|
snapshot.index = readIndex(projectPath3);
|
|
278782
279025
|
snapshot.localMainAhead = deps.localMainAhead !== void 0 ? await deps.localMainAhead() : await gitLocalMainAhead(projectPath3);
|
|
278783
|
-
snapshot.runs = readJsonl(
|
|
279026
|
+
snapshot.runs = readJsonl(join143(runtimeDir12, "runs.jsonl"));
|
|
278784
279027
|
let eventFailed = 0;
|
|
278785
279028
|
const terminal = [];
|
|
278786
|
-
const eventsPath4 =
|
|
278787
|
-
if (
|
|
278788
|
-
for (const line of
|
|
279029
|
+
const eventsPath4 = join143(runtimeDir12, "events.ndjson");
|
|
279030
|
+
if (existsSync127(eventsPath4)) {
|
|
279031
|
+
for (const line of readFileSync128(eventsPath4, "utf8").split("\n")) {
|
|
278789
279032
|
const e = parseEventLine(line);
|
|
278790
279033
|
if (e === null)
|
|
278791
279034
|
continue;
|
|
@@ -278807,22 +279050,22 @@ async function gatherAuditSnapshot(projectPath3, runtimeDir12, deps = {}) {
|
|
|
278807
279050
|
if (!row2.status.includes("\u2705"))
|
|
278808
279051
|
continue;
|
|
278809
279052
|
const card = cardArchiveDir(projectPath3, row2.id);
|
|
278810
|
-
if (!
|
|
279053
|
+
if (!existsSync127(card))
|
|
278811
279054
|
continue;
|
|
278812
|
-
const reportPath =
|
|
278813
|
-
const specPath =
|
|
279055
|
+
const reportPath = join143(card, "latest", reportFileName(row2.id));
|
|
279056
|
+
const specPath = join143(card, "spec.md");
|
|
278814
279057
|
let noVisualSurface = false;
|
|
278815
|
-
if (
|
|
279058
|
+
if (existsSync127(specPath)) {
|
|
278816
279059
|
try {
|
|
278817
|
-
noVisualSurface = !hasVisualEvidenceAc(
|
|
279060
|
+
noVisualSurface = !hasVisualEvidenceAc(readFileSync128(specPath, "utf8"));
|
|
278818
279061
|
} catch {
|
|
278819
279062
|
}
|
|
278820
279063
|
}
|
|
278821
279064
|
snapshot.attest[row2.id] = {
|
|
278822
|
-
report:
|
|
278823
|
-
acMap:
|
|
278824
|
-
visualEvidence:
|
|
278825
|
-
machineSkip:
|
|
279065
|
+
report: existsSync127(reportPath),
|
|
279066
|
+
acMap: existsSync127(join143(card, "ac-map.json")),
|
|
279067
|
+
visualEvidence: existsSync127(reportPath) ? hasScreenshotArtifact(reportPath) : false,
|
|
279068
|
+
machineSkip: existsSync127(reportPath) ? hasMachineCaptureSkip2(reportPath) : false,
|
|
278826
279069
|
noVisualSurface
|
|
278827
279070
|
};
|
|
278828
279071
|
}
|
|
@@ -278906,16 +279149,16 @@ async function consistencyAuditCommand(args, deps = {}) {
|
|
|
278906
279149
|
const json = args.includes("--json");
|
|
278907
279150
|
const projectPath3 = process.cwd();
|
|
278908
279151
|
const rtEnv = (process.env["ROLL_PROJECT_RUNTIME_DIR"] ?? "").trim();
|
|
278909
|
-
const runtimeDir12 = rtEnv !== "" ? rtEnv :
|
|
279152
|
+
const runtimeDir12 = rtEnv !== "" ? rtEnv : join143(projectPath3, ".roll", "loop");
|
|
278910
279153
|
const { snapshot, skipped: skipped2 } = await gatherAuditSnapshot(projectPath3, runtimeDir12, deps);
|
|
278911
279154
|
const report = runConsistencyAudit(snapshot);
|
|
278912
279155
|
const nowMs2 = (deps.nowSec ?? Math.floor(Date.now() / 1e3)) * 1e3;
|
|
278913
279156
|
const dateTag = new Date(nowMs2).toISOString().slice(0, 10);
|
|
278914
|
-
const outDir =
|
|
279157
|
+
const outDir = join143(projectPath3, ".roll", "reports", "consistency");
|
|
278915
279158
|
try {
|
|
278916
279159
|
mkdirSync69(outDir, { recursive: true });
|
|
278917
|
-
writeFileSync69(
|
|
278918
|
-
writeFileSync69(
|
|
279160
|
+
writeFileSync69(join143(outDir, `${dateTag}.json`), JSON.stringify({ generatedAt: dateTag, ...report, skipped: skipped2 }, null, 1));
|
|
279161
|
+
writeFileSync69(join143(outDir, `${dateTag}.md`), renderMarkdown2(report, skipped2, dateTag));
|
|
278919
279162
|
} catch {
|
|
278920
279163
|
process.stderr.write("consistency audit: report write failed (scan still completed)\n");
|
|
278921
279164
|
}
|
|
@@ -278923,7 +279166,7 @@ async function consistencyAuditCommand(args, deps = {}) {
|
|
|
278923
279166
|
process.stdout.write(JSON.stringify({ ...report, skipped: skipped2 }, null, 1) + "\n");
|
|
278924
279167
|
} else {
|
|
278925
279168
|
process.stdout.write(`consistency audit (shadow): fail ${report.summary.fail} \xB7 warn ${report.summary.warn} \xB7 unknown ${report.summary.unknown} \xB7 grandfathered ${report.summary.grandfathered}
|
|
278926
|
-
\u4E00\u81F4\u6027\u5BA1\u8BA1(\u5F71\u5B50\u6A21\u5F0F): \u62A5\u544A\u5DF2\u5199\u5165 ${
|
|
279169
|
+
\u4E00\u81F4\u6027\u5BA1\u8BA1(\u5F71\u5B50\u6A21\u5F0F): \u62A5\u544A\u5DF2\u5199\u5165 ${join143(".roll", "reports", "consistency", `${dateTag}.md`)}
|
|
278927
279170
|
`);
|
|
278928
279171
|
for (const f of report.findings.filter((x) => x.severity === "fail").slice(0, 10)) {
|
|
278929
279172
|
process.stdout.write(` \u2717 ${f.rule} ${f.subject} \u2014 ${f.detail}
|
|
@@ -278962,7 +279205,7 @@ function escapeRegExp4(s) {
|
|
|
278962
279205
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
278963
279206
|
}
|
|
278964
279207
|
function readText(p) {
|
|
278965
|
-
return
|
|
279208
|
+
return readFileSync129(p, "utf8");
|
|
278966
279209
|
}
|
|
278967
279210
|
var COMMAND_SURFACE_REPLACEMENTS = /* @__PURE__ */ new Map([
|
|
278968
279211
|
["migrate", "npx @seanyao/roll@2 migrate"],
|
|
@@ -278980,7 +279223,7 @@ function lineNumberAt(text2, index) {
|
|
|
278980
279223
|
return text2.slice(0, index).split("\n").length;
|
|
278981
279224
|
}
|
|
278982
279225
|
function existingTextFiles(projectDir, rels) {
|
|
278983
|
-
return rels.map((rel) => ({ rel, abs:
|
|
279226
|
+
return rels.map((rel) => ({ rel, abs: join144(projectDir, rel) })).filter((f) => {
|
|
278984
279227
|
try {
|
|
278985
279228
|
return statSync39(f.abs).isFile();
|
|
278986
279229
|
} catch {
|
|
@@ -278991,7 +279234,7 @@ function existingTextFiles(projectDir, rels) {
|
|
|
278991
279234
|
function walkTextFiles(projectDir, relDir, extensions) {
|
|
278992
279235
|
const out3 = [];
|
|
278993
279236
|
const walk2 = (dirRel) => {
|
|
278994
|
-
const dirAbs =
|
|
279237
|
+
const dirAbs = join144(projectDir, dirRel);
|
|
278995
279238
|
let entries;
|
|
278996
279239
|
try {
|
|
278997
279240
|
entries = readdirSync49(dirAbs, { withFileTypes: true });
|
|
@@ -278999,7 +279242,7 @@ function walkTextFiles(projectDir, relDir, extensions) {
|
|
|
278999
279242
|
return;
|
|
279000
279243
|
}
|
|
279001
279244
|
for (const entry of entries) {
|
|
279002
|
-
const rel =
|
|
279245
|
+
const rel = join144(dirRel, entry.name);
|
|
279003
279246
|
if (entry.isDirectory()) {
|
|
279004
279247
|
walk2(rel);
|
|
279005
279248
|
continue;
|
|
@@ -279007,7 +279250,7 @@ function walkTextFiles(projectDir, relDir, extensions) {
|
|
|
279007
279250
|
const dot = entry.name.lastIndexOf(".");
|
|
279008
279251
|
const ext = dot === -1 ? "" : entry.name.slice(dot);
|
|
279009
279252
|
if (entry.isFile() && extensions.has(ext))
|
|
279010
|
-
out3.push({ rel, abs:
|
|
279253
|
+
out3.push({ rel, abs: join144(projectDir, rel) });
|
|
279011
279254
|
}
|
|
279012
279255
|
};
|
|
279013
279256
|
walk2(relDir);
|
|
@@ -279134,13 +279377,13 @@ var nodeFreshnessPort3 = {
|
|
|
279134
279377
|
},
|
|
279135
279378
|
readText(absPath) {
|
|
279136
279379
|
try {
|
|
279137
|
-
return
|
|
279380
|
+
return readFileSync129(absPath, "utf8");
|
|
279138
279381
|
} catch {
|
|
279139
279382
|
return "";
|
|
279140
279383
|
}
|
|
279141
279384
|
},
|
|
279142
279385
|
writeText(absPath, text2) {
|
|
279143
|
-
mkdirSync70(
|
|
279386
|
+
mkdirSync70(dirname70(absPath), { recursive: true });
|
|
279144
279387
|
writeFileSync70(absPath, text2, "utf8");
|
|
279145
279388
|
}
|
|
279146
279389
|
};
|
|
@@ -279179,13 +279422,13 @@ function mergeShasFromStatus(status2) {
|
|
|
279179
279422
|
return shas;
|
|
279180
279423
|
}
|
|
279181
279424
|
function findCardSpec(projectDir, id) {
|
|
279182
|
-
const featuresDir =
|
|
279425
|
+
const featuresDir = join144(projectDir, ".roll", "features");
|
|
279183
279426
|
try {
|
|
279184
279427
|
for (const epic of readdirSync49(featuresDir, { withFileTypes: true })) {
|
|
279185
279428
|
if (!epic.isDirectory())
|
|
279186
279429
|
continue;
|
|
279187
|
-
const spec =
|
|
279188
|
-
if (
|
|
279430
|
+
const spec = join144(featuresDir, epic.name, id, "spec.md");
|
|
279431
|
+
if (existsSync128(spec))
|
|
279189
279432
|
return spec;
|
|
279190
279433
|
}
|
|
279191
279434
|
} catch {
|
|
@@ -279203,13 +279446,13 @@ function cardChangelogExempt(projectDir, id) {
|
|
|
279203
279446
|
}
|
|
279204
279447
|
}
|
|
279205
279448
|
function checkFeaturesCatalog(projectDir) {
|
|
279206
|
-
const backlog =
|
|
279207
|
-
if (!
|
|
279449
|
+
const backlog = join144(projectDir, ".roll", "backlog.md");
|
|
279450
|
+
if (!existsSync128(backlog))
|
|
279208
279451
|
return { status: "pass", gaps: [] };
|
|
279209
279452
|
const backlogText = readText(backlog);
|
|
279210
279453
|
const gaps = [];
|
|
279211
|
-
const features =
|
|
279212
|
-
if (
|
|
279454
|
+
const features = join144(projectDir, ".roll", "features.md");
|
|
279455
|
+
if (existsSync128(features)) {
|
|
279213
279456
|
const featuresText = readText(features);
|
|
279214
279457
|
for (const featName of readDoneFeatures(backlogText).keys()) {
|
|
279215
279458
|
const escaped = escapeRegExp4(featName);
|
|
@@ -279232,8 +279475,8 @@ function checkFeaturesCatalog(projectDir) {
|
|
|
279232
279475
|
return { status: gaps.length === 0 ? "pass" : "fail", gaps };
|
|
279233
279476
|
}
|
|
279234
279477
|
function checkTruthLive(projectDir) {
|
|
279235
|
-
const backlog =
|
|
279236
|
-
if (!
|
|
279478
|
+
const backlog = join144(projectDir, ".roll", "backlog.md");
|
|
279479
|
+
if (!existsSync128(backlog))
|
|
279237
279480
|
return { status: "pass", gaps: [] };
|
|
279238
279481
|
const backlogText = readText(backlog);
|
|
279239
279482
|
const facts = backlogRowFacts(backlogText);
|
|
@@ -279269,19 +279512,19 @@ function checkTruthLive(projectDir) {
|
|
|
279269
279512
|
return { status: gaps.length === 0 ? "pass" : "fail", gaps };
|
|
279270
279513
|
}
|
|
279271
279514
|
function checkCards(projectDir) {
|
|
279272
|
-
const backlog =
|
|
279273
|
-
const featuresDir =
|
|
279274
|
-
if (!
|
|
279515
|
+
const backlog = join144(projectDir, ".roll", "backlog.md");
|
|
279516
|
+
const featuresDir = join144(projectDir, ".roll", "features");
|
|
279517
|
+
if (!existsSync128(backlog) || !existsSync128(featuresDir))
|
|
279275
279518
|
return { status: "pass", gaps: [] };
|
|
279276
279519
|
const cardEpic = /* @__PURE__ */ new Map();
|
|
279277
279520
|
try {
|
|
279278
279521
|
for (const epic of readdirSync49(featuresDir, { withFileTypes: true })) {
|
|
279279
279522
|
if (!epic.isDirectory())
|
|
279280
279523
|
continue;
|
|
279281
|
-
for (const card of readdirSync49(
|
|
279524
|
+
for (const card of readdirSync49(join144(featuresDir, epic.name), { withFileTypes: true })) {
|
|
279282
279525
|
if (!card.isDirectory())
|
|
279283
279526
|
continue;
|
|
279284
|
-
if (
|
|
279527
|
+
if (existsSync128(join144(featuresDir, epic.name, card.name, "spec.md")) && !cardEpic.has(card.name)) {
|
|
279285
279528
|
cardEpic.set(card.name, epic.name);
|
|
279286
279529
|
}
|
|
279287
279530
|
}
|
|
@@ -279291,7 +279534,7 @@ function checkCards(projectDir) {
|
|
|
279291
279534
|
}
|
|
279292
279535
|
const hasAcBlock = (epic, id) => {
|
|
279293
279536
|
try {
|
|
279294
|
-
const text2 = readText(
|
|
279537
|
+
const text2 = readText(join144(featuresDir, epic, id, "spec.md"));
|
|
279295
279538
|
return acForStory(text2, id, { fileOwned: true }).length > 0;
|
|
279296
279539
|
} catch {
|
|
279297
279540
|
return true;
|
|
@@ -279316,12 +279559,12 @@ function checkCards(projectDir) {
|
|
|
279316
279559
|
const ev = /\[evidence\]\(([^)]+)\)/.exec(line);
|
|
279317
279560
|
if (ev !== null) {
|
|
279318
279561
|
const target = (ev[1] ?? "").replace(/^\.roll\//, "");
|
|
279319
|
-
if (!
|
|
279562
|
+
if (!existsSync128(join144(projectDir, ".roll", target))) {
|
|
279320
279563
|
gaps.push(`Backlog row ${id} evidence link is broken: ${ev[1] ?? ""}`);
|
|
279321
279564
|
}
|
|
279322
279565
|
} else if (line.includes(STATUS_MARKER.done)) {
|
|
279323
279566
|
const epic = cardEpic.get(id) ?? "";
|
|
279324
|
-
if (!
|
|
279567
|
+
if (!existsSync128(join144(featuresDir, epic, id, "latest", `${id}-report.html`))) {
|
|
279325
279568
|
if (hasAcBlock(epic, id)) {
|
|
279326
279569
|
gaps.push(`Done backlog row ${id} has ACs but no attest report`);
|
|
279327
279570
|
} else {
|
|
@@ -279343,8 +279586,8 @@ function checkCards(projectDir) {
|
|
|
279343
279586
|
}
|
|
279344
279587
|
function checkDocs(projectDir) {
|
|
279345
279588
|
const gaps = checkTopLevelCommands(activeDocsFiles(projectDir), DOC_RETIRED_TOP_LEVEL_COMMANDS);
|
|
279346
|
-
const changelogPath =
|
|
279347
|
-
if (
|
|
279589
|
+
const changelogPath = join144(projectDir, "CHANGELOG.md");
|
|
279590
|
+
if (existsSync128(changelogPath)) {
|
|
279348
279591
|
const changelog = readText(changelogPath);
|
|
279349
279592
|
for (const id of releaseDeltaCardIds(projectDir)) {
|
|
279350
279593
|
const base = id.replace(/[a-z]$/, "");
|
|
@@ -279417,9 +279660,9 @@ function siteTokens(name) {
|
|
|
279417
279660
|
}
|
|
279418
279661
|
function checkSite(projectDir) {
|
|
279419
279662
|
const gaps = checkTopLevelCommands(activeSiteFiles(projectDir), SITE_HIDDEN_TOP_LEVEL_COMMANDS);
|
|
279420
|
-
const siteJs =
|
|
279421
|
-
const backlog =
|
|
279422
|
-
if (!
|
|
279663
|
+
const siteJs = join144(projectDir, "site", "roll-data.js");
|
|
279664
|
+
const backlog = join144(projectDir, ".roll", "backlog.md");
|
|
279665
|
+
if (!existsSync128(siteJs) || !existsSync128(backlog))
|
|
279423
279666
|
return { status: gaps.length === 0 ? "pass" : "fail", gaps };
|
|
279424
279667
|
const siteText = readText(siteJs);
|
|
279425
279668
|
const seenGuideRefs = /* @__PURE__ */ new Set();
|
|
@@ -279428,7 +279671,7 @@ function checkSite(projectDir) {
|
|
|
279428
279671
|
if (seenGuideRefs.has(rel))
|
|
279429
279672
|
continue;
|
|
279430
279673
|
seenGuideRefs.add(rel);
|
|
279431
|
-
if (!
|
|
279674
|
+
if (!existsSync128(join144(projectDir, rel))) {
|
|
279432
279675
|
gaps.push(`site/roll-data.js links a guide that does not exist: ${rel}`);
|
|
279433
279676
|
}
|
|
279434
279677
|
}
|
|
@@ -279469,7 +279712,7 @@ function listFiles2(dir) {
|
|
|
279469
279712
|
try {
|
|
279470
279713
|
return readdirSync49(dir).filter((n) => {
|
|
279471
279714
|
try {
|
|
279472
|
-
return statSync39(
|
|
279715
|
+
return statSync39(join144(dir, n)).isFile();
|
|
279473
279716
|
} catch {
|
|
279474
279717
|
return false;
|
|
279475
279718
|
}
|
|
@@ -279480,9 +279723,9 @@ function listFiles2(dir) {
|
|
|
279480
279723
|
}
|
|
279481
279724
|
function checkI18n(projectDir) {
|
|
279482
279725
|
const gaps = [];
|
|
279483
|
-
const guideEn =
|
|
279484
|
-
const guideZh =
|
|
279485
|
-
if (
|
|
279726
|
+
const guideEn = join144(projectDir, "guide", "en");
|
|
279727
|
+
const guideZh = join144(projectDir, "guide", "zh");
|
|
279728
|
+
if (existsSync128(guideEn) && existsSync128(guideZh)) {
|
|
279486
279729
|
const enFiles = new Set(listFiles2(guideEn));
|
|
279487
279730
|
const zhFiles = new Set(listFiles2(guideZh));
|
|
279488
279731
|
const enOnly = [...enFiles].filter((f) => !zhFiles.has(f)).sort();
|
|
@@ -279492,8 +279735,8 @@ function checkI18n(projectDir) {
|
|
|
279492
279735
|
for (const f of zhOnly)
|
|
279493
279736
|
gaps.push(`guide/zh/${f} has no corresponding guide/en/${f}`);
|
|
279494
279737
|
}
|
|
279495
|
-
const i18nDir =
|
|
279496
|
-
if (
|
|
279738
|
+
const i18nDir = join144(projectDir, "lib", "i18n");
|
|
279739
|
+
if (existsSync128(i18nDir)) {
|
|
279497
279740
|
const keysEn = /* @__PURE__ */ new Set();
|
|
279498
279741
|
const keysZh = /* @__PURE__ */ new Set();
|
|
279499
279742
|
let shFiles = [];
|
|
@@ -279503,7 +279746,7 @@ function checkI18n(projectDir) {
|
|
|
279503
279746
|
shFiles = [];
|
|
279504
279747
|
}
|
|
279505
279748
|
for (const name of shFiles) {
|
|
279506
|
-
const text2 = readText(
|
|
279749
|
+
const text2 = readText(join144(i18nDir, name));
|
|
279507
279750
|
for (const m7 of text2.matchAll(/_i18n_set\s+(en|zh)\s+([^\s]+)/g)) {
|
|
279508
279751
|
const lang10 = m7[1];
|
|
279509
279752
|
const key = m7[2] ?? "";
|
|
@@ -279543,7 +279786,7 @@ function rglobBats(dir) {
|
|
|
279543
279786
|
return;
|
|
279544
279787
|
}
|
|
279545
279788
|
for (const e of entries) {
|
|
279546
|
-
const full =
|
|
279789
|
+
const full = join144(d, e);
|
|
279547
279790
|
let st;
|
|
279548
279791
|
try {
|
|
279549
279792
|
st = statSync39(full);
|
|
@@ -279561,9 +279804,9 @@ function rglobBats(dir) {
|
|
|
279561
279804
|
}
|
|
279562
279805
|
function checkTests(projectDir) {
|
|
279563
279806
|
const gaps = [];
|
|
279564
|
-
const backlog =
|
|
279565
|
-
const testsDir =
|
|
279566
|
-
if (!
|
|
279807
|
+
const backlog = join144(projectDir, ".roll", "backlog.md");
|
|
279808
|
+
const testsDir = join144(projectDir, "tests");
|
|
279809
|
+
if (!existsSync128(backlog))
|
|
279567
279810
|
return { status: "pass", gaps: [] };
|
|
279568
279811
|
const backlogText = readText(backlog);
|
|
279569
279812
|
const allFeatures = /* @__PURE__ */ new Set();
|
|
@@ -279588,7 +279831,7 @@ function checkTests(projectDir) {
|
|
|
279588
279831
|
doneFeatures.push(currentFeature);
|
|
279589
279832
|
}
|
|
279590
279833
|
}
|
|
279591
|
-
const testFiles =
|
|
279834
|
+
const testFiles = existsSync128(testsDir) ? rglobBats(testsDir) : [];
|
|
279592
279835
|
if (testFiles.length === 0)
|
|
279593
279836
|
return { status: "pass", gaps: [] };
|
|
279594
279837
|
for (const feat of doneFeatures) {
|
|
@@ -279933,17 +280176,17 @@ function writeReleaseTestProof(exec) {
|
|
|
279933
280176
|
const cwd = exec("git", ["rev-parse", "--show-toplevel"]).trim();
|
|
279934
280177
|
const tree = exec("git", ["write-tree"]).trim();
|
|
279935
280178
|
const ts2 = Math.floor(Date.now() / 1e3);
|
|
279936
|
-
const proofPath =
|
|
279937
|
-
mkdirSync72(
|
|
280179
|
+
const proofPath = join146(cwd, ".roll", "last-test-pass");
|
|
280180
|
+
mkdirSync72(dirname72(proofPath), { recursive: true });
|
|
279938
280181
|
writeFileSync72(proofPath, JSON.stringify({ ts: ts2, tree, mode: "release", scope: "affected" }), "utf8");
|
|
279939
280182
|
}
|
|
279940
280183
|
function assertTestProofFresh(exec) {
|
|
279941
280184
|
const cwd = exec("git", ["rev-parse", "--show-toplevel"]).trim();
|
|
279942
|
-
const proofPath =
|
|
279943
|
-
if (!
|
|
280185
|
+
const proofPath = join146(cwd, ".roll", "last-test-pass");
|
|
280186
|
+
if (!existsSync130(proofPath)) {
|
|
279944
280187
|
throw new Error("test-pass proof missing \u2014 run `roll test` before committing");
|
|
279945
280188
|
}
|
|
279946
|
-
const body =
|
|
280189
|
+
const body = readFileSync131(proofPath, "utf8");
|
|
279947
280190
|
const tsMatch = /"ts":(\d+)/.exec(body);
|
|
279948
280191
|
const treeMatch = /"tree":"([^"]*)"/.exec(body);
|
|
279949
280192
|
const ts2 = tsMatch ? Number(tsMatch[1]) : NaN;
|
|
@@ -280020,7 +280263,7 @@ function realReleaseDeps() {
|
|
|
280020
280263
|
return {
|
|
280021
280264
|
version: (cwd) => {
|
|
280022
280265
|
try {
|
|
280023
|
-
const pkg = JSON.parse(
|
|
280266
|
+
const pkg = JSON.parse(readFileSync131(join146(cwd, "package.json"), "utf8"));
|
|
280024
280267
|
return typeof pkg.version === "string" ? pkg.version : "";
|
|
280025
280268
|
} catch {
|
|
280026
280269
|
return "";
|
|
@@ -280055,11 +280298,11 @@ function realReleaseDeps() {
|
|
|
280055
280298
|
return true;
|
|
280056
280299
|
}
|
|
280057
280300
|
},
|
|
280058
|
-
readChangelog: (cwd) =>
|
|
280059
|
-
writeChangelog: (cwd, text2) => writeFileSync72(
|
|
280301
|
+
readChangelog: (cwd) => readFileSync131(join146(cwd, "CHANGELOG.md"), "utf8"),
|
|
280302
|
+
writeChangelog: (cwd, text2) => writeFileSync72(join146(cwd, "CHANGELOG.md"), text2, "utf8"),
|
|
280060
280303
|
bumpVersion: (cwd, version) => {
|
|
280061
|
-
const path =
|
|
280062
|
-
const pkg = JSON.parse(
|
|
280304
|
+
const path = join146(cwd, "package.json");
|
|
280305
|
+
const pkg = JSON.parse(readFileSync131(path, "utf8"));
|
|
280063
280306
|
pkg["version"] = version;
|
|
280064
280307
|
writeFileSync72(path, `${JSON.stringify(pkg, null, 2)}
|
|
280065
280308
|
`, "utf8");
|
|
@@ -280076,7 +280319,7 @@ function realReleaseDeps() {
|
|
|
280076
280319
|
commitPushWithGate({
|
|
280077
280320
|
branch,
|
|
280078
280321
|
message,
|
|
280079
|
-
rollManaged:
|
|
280322
|
+
rollManaged: existsSync130(join146(cwd, ".roll")),
|
|
280080
280323
|
exec: (cmd, args) => execFileSync33(cmd, args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 6e5 })
|
|
280081
280324
|
});
|
|
280082
280325
|
},
|
|
@@ -280169,7 +280412,7 @@ function realReleaseDeps() {
|
|
|
280169
280412
|
recordReleaseFact: (cwd, tagName) => {
|
|
280170
280413
|
try {
|
|
280171
280414
|
const runtimeDir12 = (process.env["ROLL_PROJECT_RUNTIME_DIR"] ?? "").trim();
|
|
280172
|
-
const eventsPath4 = runtimeDir12 !== "" ?
|
|
280415
|
+
const eventsPath4 = runtimeDir12 !== "" ? join146(runtimeDir12, EVENTS_FILE) : join146(cwd, ".roll", "loop", EVENTS_FILE);
|
|
280173
280416
|
new EventBus().appendEvent(eventsPath4, {
|
|
280174
280417
|
type: "release:gate",
|
|
280175
280418
|
tag: tagName,
|
|
@@ -280398,15 +280641,15 @@ ${c("dim", "\u2192 Running the golden-path showcase (real models; its verdict do
|
|
|
280398
280641
|
init_dist();
|
|
280399
280642
|
init_render();
|
|
280400
280643
|
import { spawnSync as spawnSync19 } from "node:child_process";
|
|
280401
|
-
import { existsSync as
|
|
280402
|
-
import { join as
|
|
280644
|
+
import { existsSync as existsSync132, lstatSync as lstatSync12, mkdirSync as mkdirSync74, readFileSync as readFileSync133, readdirSync as readdirSync52, readlinkSync as readlinkSync3, statSync as statSync42 } from "node:fs";
|
|
280645
|
+
import { join as join148 } from "node:path";
|
|
280403
280646
|
|
|
280404
280647
|
// packages/cli/dist/lib/roll-capture-install.js
|
|
280405
280648
|
init_dist();
|
|
280406
280649
|
import { spawnSync as spawnSync18 } from "node:child_process";
|
|
280407
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
280650
|
+
import { chmodSync as chmodSync2, existsSync as existsSync131, lstatSync as lstatSync11, mkdirSync as mkdirSync73, mkdtempSync as mkdtempSync10, readdirSync as readdirSync51, readFileSync as readFileSync132, renameSync as renameSync26, rmSync as rmSync25, statSync as statSync41, writeFileSync as writeFileSync73 } from "node:fs";
|
|
280408
280651
|
import { homedir as homedir31 } from "node:os";
|
|
280409
|
-
import { join as
|
|
280652
|
+
import { join as join147 } from "node:path";
|
|
280410
280653
|
var RELEASE_API = "https://api.github.com/repos/seanyao/roll-capture/releases/latest";
|
|
280411
280654
|
var ASSET_NAME = "Roll-Capture.app.zip";
|
|
280412
280655
|
var APP_NAME2 = "Roll Capture.app";
|
|
@@ -280431,7 +280674,7 @@ function defaultRollCaptureInstallDeps() {
|
|
|
280431
280674
|
home: homedir31(),
|
|
280432
280675
|
uid: typeof process.getuid === "function" ? process.getuid() : void 0,
|
|
280433
280676
|
...platform3 === "darwin" && !isCi2(process.env) && process.env["ROLL_SKIP_CAPTURE_INSTALL"] !== "1" ? { hasAquaGUI: macosHasAquaGUI3(execFile18) } : {},
|
|
280434
|
-
exists:
|
|
280677
|
+
exists: existsSync131,
|
|
280435
280678
|
renamePath: renameSync26,
|
|
280436
280679
|
execFile: execFile18,
|
|
280437
280680
|
fetchLatestRelease: (timeoutMs) => defaultFetchLatestRelease(timeoutMs, process.env, execFile18),
|
|
@@ -280478,12 +280721,12 @@ async function installRollCapture(deps = defaultRollCaptureInstallDeps()) {
|
|
|
280478
280721
|
if (bytes.byteLength !== asset.size) {
|
|
280479
280722
|
return manual(`download size mismatch: expected ${asset.size} bytes, got ${bytes.byteLength}`, release.tagName);
|
|
280480
280723
|
}
|
|
280481
|
-
const applicationsDir =
|
|
280482
|
-
const targetApp =
|
|
280724
|
+
const applicationsDir = join147(deps.home, "Applications");
|
|
280725
|
+
const targetApp = join147(applicationsDir, APP_NAME2);
|
|
280483
280726
|
mkdirSync73(applicationsDir, { recursive: true });
|
|
280484
|
-
const workDir = mkdtempSync10(
|
|
280485
|
-
const zipPath =
|
|
280486
|
-
const extractDir =
|
|
280727
|
+
const workDir = mkdtempSync10(join147(applicationsDir, ".roll-capture-install-"));
|
|
280728
|
+
const zipPath = join147(workDir, ASSET_NAME);
|
|
280729
|
+
const extractDir = join147(workDir, "extract");
|
|
280487
280730
|
try {
|
|
280488
280731
|
mkdirSync73(extractDir, { recursive: true });
|
|
280489
280732
|
writeFileSync73(zipPath, bytes);
|
|
@@ -280503,7 +280746,7 @@ async function installRollCapture(deps = defaultRollCaptureInstallDeps()) {
|
|
|
280503
280746
|
} catch (error) {
|
|
280504
280747
|
return manual(`install failed: ${errorMessage(error)}`, release.tagName);
|
|
280505
280748
|
} finally {
|
|
280506
|
-
|
|
280749
|
+
rmSync25(workDir, { recursive: true, force: true });
|
|
280507
280750
|
}
|
|
280508
280751
|
}
|
|
280509
280752
|
function renderRollCaptureInstallResult(result, lang10) {
|
|
@@ -280640,7 +280883,7 @@ function macosHasAquaGUI3(execFile18) {
|
|
|
280640
280883
|
function findExtractedApp(dir) {
|
|
280641
280884
|
try {
|
|
280642
280885
|
for (const name of readdirSync51(dir)) {
|
|
280643
|
-
const candidate =
|
|
280886
|
+
const candidate = join147(dir, name);
|
|
280644
280887
|
const st = lstatSync11(candidate);
|
|
280645
280888
|
if (st.isSymbolicLink())
|
|
280646
280889
|
continue;
|
|
@@ -280658,10 +280901,10 @@ function findExtractedApp(dir) {
|
|
|
280658
280901
|
return null;
|
|
280659
280902
|
}
|
|
280660
280903
|
function findBundleExecutable(appPath) {
|
|
280661
|
-
const macosDir =
|
|
280904
|
+
const macosDir = join147(appPath, "Contents", "MacOS");
|
|
280662
280905
|
try {
|
|
280663
280906
|
for (const name of readdirSync51(macosDir)) {
|
|
280664
|
-
const candidate =
|
|
280907
|
+
const candidate = join147(macosDir, name);
|
|
280665
280908
|
const st = lstatSync11(candidate);
|
|
280666
280909
|
if (st.isSymbolicLink())
|
|
280667
280910
|
continue;
|
|
@@ -280677,7 +280920,7 @@ function replaceAppAtomically(app, targetApp, deps) {
|
|
|
280677
280920
|
const renamePath = deps.renamePath ?? renameSync26;
|
|
280678
280921
|
const backupApp = `${targetApp}.bak`;
|
|
280679
280922
|
const hadExisting = lstatExists(targetApp);
|
|
280680
|
-
|
|
280923
|
+
rmSync25(backupApp, { recursive: true, force: true });
|
|
280681
280924
|
if (!hadExisting) {
|
|
280682
280925
|
renamePath(app, targetApp);
|
|
280683
280926
|
return;
|
|
@@ -280689,10 +280932,10 @@ function replaceAppAtomically(app, targetApp, deps) {
|
|
|
280689
280932
|
backupCreated = true;
|
|
280690
280933
|
renamePath(app, targetApp);
|
|
280691
280934
|
targetReplaced = true;
|
|
280692
|
-
|
|
280935
|
+
rmSync25(backupApp, { recursive: true, force: true });
|
|
280693
280936
|
} catch (error) {
|
|
280694
280937
|
if (targetReplaced)
|
|
280695
|
-
|
|
280938
|
+
rmSync25(targetApp, { recursive: true, force: true });
|
|
280696
280939
|
if (backupCreated) {
|
|
280697
280940
|
try {
|
|
280698
280941
|
renamePath(backupApp, targetApp);
|
|
@@ -280744,13 +280987,13 @@ function enableNodeGlobalProxyFromEnv(env) {
|
|
|
280744
280987
|
}
|
|
280745
280988
|
}
|
|
280746
280989
|
function readInstalledVersion(appPath, deps) {
|
|
280747
|
-
const plistPath =
|
|
280990
|
+
const plistPath = join147(appPath, "Contents", "Info.plist");
|
|
280748
280991
|
const plutil = deps.execFile("plutil", ["-extract", "CFBundleShortVersionString", "raw", "-o", "-", plistPath]);
|
|
280749
280992
|
const raw = plutil.code === 0 ? plutil.stdout.trim() : "";
|
|
280750
280993
|
if (raw !== "")
|
|
280751
280994
|
return raw;
|
|
280752
280995
|
try {
|
|
280753
|
-
const text2 =
|
|
280996
|
+
const text2 = readFileSync132(plistPath, "utf8");
|
|
280754
280997
|
const match = /<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/.exec(text2);
|
|
280755
280998
|
return match?.[1];
|
|
280756
280999
|
} catch {
|
|
@@ -280778,7 +281021,7 @@ function manual(reason, releaseTag) {
|
|
|
280778
281021
|
}
|
|
280779
281022
|
function renderEn(result) {
|
|
280780
281023
|
if (result.status === "installed") {
|
|
280781
|
-
return `Roll Capture.app installed at ${result.appPath ??
|
|
281024
|
+
return `Roll Capture.app installed at ${result.appPath ?? join147("~", "Applications", APP_NAME2)}; open it once and grant Screen Recording permission.`;
|
|
280782
281025
|
}
|
|
280783
281026
|
if (result.status === "already-installed") {
|
|
280784
281027
|
const update = result.updateAvailable === true && result.releaseTag !== void 0 ? `; newer release ${result.releaseTag} is available` : "";
|
|
@@ -280790,7 +281033,7 @@ function renderEn(result) {
|
|
|
280790
281033
|
}
|
|
280791
281034
|
function renderZh(result) {
|
|
280792
281035
|
if (result.status === "installed") {
|
|
280793
|
-
return `Roll Capture.app \u5DF2\u5B89\u88C5\u5230 ${result.appPath ??
|
|
281036
|
+
return `Roll Capture.app \u5DF2\u5B89\u88C5\u5230 ${result.appPath ?? join147("~", "Applications", APP_NAME2)}\uFF1B\u8BF7\u6253\u5F00\u4E00\u6B21\u5E76\u6388\u4E88\u5C4F\u5E55\u5F55\u5236\u6743\u9650\u3002`;
|
|
280794
281037
|
}
|
|
280795
281038
|
if (result.status === "already-installed") {
|
|
280796
281039
|
const update = result.updateAvailable === true && result.releaseTag !== void 0 ? `\uFF1B\u6709\u65B0\u7248 ${result.releaseTag} \u53EF\u7528` : "";
|
|
@@ -280873,7 +281116,7 @@ function walk(dir, lines3) {
|
|
|
280873
281116
|
return;
|
|
280874
281117
|
}
|
|
280875
281118
|
for (const name of names) {
|
|
280876
|
-
const p =
|
|
281119
|
+
const p = join148(dir, name);
|
|
280877
281120
|
let isLink = false;
|
|
280878
281121
|
try {
|
|
280879
281122
|
isLink = lstatSync12(p).isSymbolicLink();
|
|
@@ -280903,7 +281146,7 @@ function walk(dir, lines3) {
|
|
|
280903
281146
|
}
|
|
280904
281147
|
function fileFingerprint(p) {
|
|
280905
281148
|
try {
|
|
280906
|
-
const buf =
|
|
281149
|
+
const buf = readFileSync133(p);
|
|
280907
281150
|
let sum = 0;
|
|
280908
281151
|
for (let i = 0; i < buf.length; i++)
|
|
280909
281152
|
sum = sum * 31 + (buf[i] ?? 0) >>> 0;
|
|
@@ -280933,18 +281176,18 @@ function ensureHooksPath(repoPath) {
|
|
|
280933
281176
|
}
|
|
280934
281177
|
}
|
|
280935
281178
|
function peerEnsureStateDir() {
|
|
280936
|
-
const base =
|
|
281179
|
+
const base = join148(rollHome(), ".peer-state");
|
|
280937
281180
|
mkdirSync74(base, { recursive: true });
|
|
280938
|
-
mkdirSync74(
|
|
281181
|
+
mkdirSync74(join148(base, "logs"), { recursive: true });
|
|
280939
281182
|
}
|
|
280940
281183
|
function tmuxPresent() {
|
|
280941
281184
|
return onPath("tmux");
|
|
280942
281185
|
}
|
|
280943
281186
|
function submoduleGuard() {
|
|
280944
281187
|
const pkg = rollPkgDir();
|
|
280945
|
-
const skills =
|
|
280946
|
-
const hasGit =
|
|
280947
|
-
const hasMods =
|
|
281188
|
+
const skills = join148(pkg, "skills");
|
|
281189
|
+
const hasGit = existsSync132(join148(pkg, ".git"));
|
|
281190
|
+
const hasMods = existsSync132(join148(pkg, ".gitmodules"));
|
|
280948
281191
|
let empty = true;
|
|
280949
281192
|
try {
|
|
280950
281193
|
empty = readdirSync52(skills).length === 0;
|
|
@@ -281061,7 +281304,7 @@ async function setupCommand(args) {
|
|
|
281061
281304
|
return 1;
|
|
281062
281305
|
}
|
|
281063
281306
|
}
|
|
281064
|
-
if (!
|
|
281307
|
+
if (!existsSync132(rollPkgConventions())) {
|
|
281065
281308
|
err13(m5("shared.convention_source_not_found_at_2", rollPkgConventions()));
|
|
281066
281309
|
err13(m5("shared.run_this_from_the_roll_repo"));
|
|
281067
281310
|
return 1;
|
|
@@ -281070,7 +281313,7 @@ async function setupCommand(args) {
|
|
|
281070
281313
|
const home = rollHome();
|
|
281071
281314
|
const aiDirsList = [".claude", ".kimi", ".kimi-code", ".codex", ".pi", ".agentrules", ".reasonix"];
|
|
281072
281315
|
const homeDir = process.env["HOME"] ?? "";
|
|
281073
|
-
const aiDirs = aiDirsList.map((d) =>
|
|
281316
|
+
const aiDirs = aiDirsList.map((d) => join148(homeDir, d)).join(":");
|
|
281074
281317
|
const steps = [];
|
|
281075
281318
|
const s1 = runSetupStep(home, () => {
|
|
281076
281319
|
installLocal(force);
|
|
@@ -281084,7 +281327,7 @@ async function setupCommand(args) {
|
|
|
281084
281327
|
syncSkills(force);
|
|
281085
281328
|
});
|
|
281086
281329
|
steps.push({ num: 3, label: "Install skills to ~/.claude", status: stateToMarker(s3, force) });
|
|
281087
|
-
const s4 = runSetupStep(
|
|
281330
|
+
const s4 = runSetupStep(join148(home, ".peer-state"), () => {
|
|
281088
281331
|
peerEnsureStateDir();
|
|
281089
281332
|
});
|
|
281090
281333
|
steps.push({ num: 4, label: "Initialize peer-review state directory", status: stateToMarker(s4, force) });
|
|
@@ -281151,8 +281394,8 @@ init_showcase2();
|
|
|
281151
281394
|
|
|
281152
281395
|
// packages/cli/dist/commands/test.js
|
|
281153
281396
|
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
281154
|
-
import { appendFileSync as appendFileSync23, existsSync as
|
|
281155
|
-
import { dirname as
|
|
281397
|
+
import { appendFileSync as appendFileSync23, existsSync as existsSync133, mkdirSync as mkdirSync75, readFileSync as readFileSync134, rmSync as rmSync26, writeFileSync as writeFileSync74 } from "node:fs";
|
|
281398
|
+
import { dirname as dirname73, join as join149, resolve as resolve12 } from "node:path";
|
|
281156
281399
|
function pal7() {
|
|
281157
281400
|
const noColor2 = (process.env["NO_COLOR"] ?? "") !== "";
|
|
281158
281401
|
return noColor2 ? { CYAN: "", GREEN: "", YELLOW: "", RED: "", NC: "" } : { CYAN: "\x1B[0;36m", GREEN: "\x1B[0;32m", YELLOW: "\x1B[0;33m", RED: "\x1B[0;31m", NC: "\x1B[0m" };
|
|
@@ -281173,12 +281416,12 @@ function currentEvidenceFrame() {
|
|
|
281173
281416
|
if (raw === "")
|
|
281174
281417
|
return null;
|
|
281175
281418
|
const runDir = resolve12(raw);
|
|
281176
|
-
if (!
|
|
281419
|
+
if (!existsSync133(runDir))
|
|
281177
281420
|
return null;
|
|
281178
281421
|
const frame = {
|
|
281179
281422
|
runDir,
|
|
281180
|
-
evidenceDir:
|
|
281181
|
-
screenshotsDir:
|
|
281423
|
+
evidenceDir: join149(runDir, "evidence"),
|
|
281424
|
+
screenshotsDir: join149(runDir, "screenshots")
|
|
281182
281425
|
};
|
|
281183
281426
|
try {
|
|
281184
281427
|
mkdirSync75(frame.evidenceDir, { recursive: true });
|
|
@@ -281209,7 +281452,7 @@ function appendRollTestEvidence(frame, cmd, argv, status2, stdout, stderr) {
|
|
|
281209
281452
|
try {
|
|
281210
281453
|
const ts2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
281211
281454
|
const command = [cmd, ...argv];
|
|
281212
|
-
appendFileSync23(
|
|
281455
|
+
appendFileSync23(join149(frame.evidenceDir, "roll-test-output.log"), [
|
|
281213
281456
|
`===== roll test ${ts2} exit=${status2} =====`,
|
|
281214
281457
|
`$ ${command.join(" ")}`,
|
|
281215
281458
|
"--- stdout ---",
|
|
@@ -281218,7 +281461,7 @@ function appendRollTestEvidence(frame, cmd, argv, status2, stdout, stderr) {
|
|
|
281218
281461
|
stderr,
|
|
281219
281462
|
""
|
|
281220
281463
|
].join("\n"), "utf8");
|
|
281221
|
-
appendFileSync23(
|
|
281464
|
+
appendFileSync23(join149(frame.evidenceDir, "roll-test-summary.txt"), JSON.stringify({
|
|
281222
281465
|
ts: ts2,
|
|
281223
281466
|
command,
|
|
281224
281467
|
exitCode: status2,
|
|
@@ -281229,12 +281472,12 @@ function appendRollTestEvidence(frame, cmd, argv, status2, stdout, stderr) {
|
|
|
281229
281472
|
}
|
|
281230
281473
|
}
|
|
281231
281474
|
function isolationGetType() {
|
|
281232
|
-
const file =
|
|
281233
|
-
if (!
|
|
281475
|
+
const file = join149(process.cwd(), ".roll", "local.yaml");
|
|
281476
|
+
if (!existsSync133(file))
|
|
281234
281477
|
return "none";
|
|
281235
281478
|
let text2;
|
|
281236
281479
|
try {
|
|
281237
|
-
text2 =
|
|
281480
|
+
text2 = readFileSync134(file, "utf8");
|
|
281238
281481
|
} catch {
|
|
281239
281482
|
return "none";
|
|
281240
281483
|
}
|
|
@@ -281282,19 +281525,19 @@ function resetLockPath() {
|
|
|
281282
281525
|
return ".roll/.iso-reset.lock";
|
|
281283
281526
|
}
|
|
281284
281527
|
function resetLockHeld() {
|
|
281285
|
-
return
|
|
281528
|
+
return existsSync133(resetLockPath());
|
|
281286
281529
|
}
|
|
281287
281530
|
function resetAcquireLock() {
|
|
281288
281531
|
const lock = resetLockPath();
|
|
281289
|
-
if (
|
|
281532
|
+
if (existsSync133(lock))
|
|
281290
281533
|
return false;
|
|
281291
|
-
mkdirSync75(
|
|
281534
|
+
mkdirSync75(dirname73(lock), { recursive: true });
|
|
281292
281535
|
writeFileSync74(lock, `${process.pid}
|
|
281293
281536
|
`);
|
|
281294
281537
|
return true;
|
|
281295
281538
|
}
|
|
281296
281539
|
function resetReleaseLock() {
|
|
281297
|
-
|
|
281540
|
+
rmSync26(resetLockPath(), { force: true });
|
|
281298
281541
|
}
|
|
281299
281542
|
function runForward(cmd, argv) {
|
|
281300
281543
|
const frame = currentEvidenceFrame();
|
|
@@ -281312,15 +281555,15 @@ function runForward(cmd, argv) {
|
|
|
281312
281555
|
}
|
|
281313
281556
|
function ensureSkillsSubmoduleReady() {
|
|
281314
281557
|
const pkg = rollPkgDir();
|
|
281315
|
-
const required2 =
|
|
281316
|
-
if (
|
|
281558
|
+
const required2 = join149(pkg, "skills", "roll-onboard", "SKILL.md");
|
|
281559
|
+
if (existsSync133(required2))
|
|
281317
281560
|
return true;
|
|
281318
|
-
if (
|
|
281561
|
+
if (existsSync133(join149(pkg, ".git")) && existsSync133(join149(pkg, ".gitmodules"))) {
|
|
281319
281562
|
spawnSync20("git", ["submodule", "update", "--init", "--recursive", "--quiet", "skills"], {
|
|
281320
281563
|
cwd: pkg,
|
|
281321
281564
|
stdio: "ignore"
|
|
281322
281565
|
});
|
|
281323
|
-
if (
|
|
281566
|
+
if (existsSync133(required2))
|
|
281324
281567
|
return true;
|
|
281325
281568
|
}
|
|
281326
281569
|
err14("roll test: skills submodule is empty");
|
|
@@ -281329,7 +281572,7 @@ function ensureSkillsSubmoduleReady() {
|
|
|
281329
281572
|
}
|
|
281330
281573
|
function isolationDispatch(method, args) {
|
|
281331
281574
|
const type = isolationGetType();
|
|
281332
|
-
if (type === "none" && !
|
|
281575
|
+
if (type === "none" && !existsSync133(join149(process.cwd(), ".roll", "local.yaml"))) {
|
|
281333
281576
|
infoErr("isolation: no test_isolation config, falling back to type=none (host)");
|
|
281334
281577
|
}
|
|
281335
281578
|
if (!SUPPORTED_TYPES.includes(type)) {
|
|
@@ -281425,7 +281668,7 @@ function testCommand(args) {
|
|
|
281425
281668
|
|
|
281426
281669
|
// packages/cli/dist/commands/tool.js
|
|
281427
281670
|
init_dist2();
|
|
281428
|
-
import { join as
|
|
281671
|
+
import { join as join150 } from "node:path";
|
|
281429
281672
|
var TOOL_USAGE = "Usage: roll tool status\n Show registered tools, input contracts, effective policy state, and requirement readiness.\n\u5C55\u793A\u5DF2\u6CE8\u518C\u5DE5\u5177\u3001\u5165\u53C2\u5951\u7EA6\u3001\u6709\u6548 policy \u72B6\u6001\u4E0E requirement \u5C31\u7EEA\u5EA6\u3002\n";
|
|
281430
281673
|
async function toolCommand(args) {
|
|
281431
281674
|
const sub = args[0] ?? "";
|
|
@@ -281443,7 +281686,7 @@ async function toolCommand(args) {
|
|
|
281443
281686
|
return 0;
|
|
281444
281687
|
}
|
|
281445
281688
|
async function collectToolRows(projectRoot3, requirementResolver = resolveRequirement) {
|
|
281446
|
-
const policy = new ToolPolicyEngine({ policyPath:
|
|
281689
|
+
const policy = new ToolPolicyEngine({ policyPath: join150(projectRoot3, ".roll", "policy.yaml") });
|
|
281447
281690
|
const rows = [];
|
|
281448
281691
|
for (const declaration of collectBuiltinToolDeclarations(projectRoot3)) {
|
|
281449
281692
|
const effective = await policy.resolve(declaration.id, declaration.defaults);
|
|
@@ -281505,8 +281748,8 @@ function pad5(value, width) {
|
|
|
281505
281748
|
// packages/cli/dist/commands/truth.js
|
|
281506
281749
|
init_dist();
|
|
281507
281750
|
init_dist2();
|
|
281508
|
-
import { statSync as statSync43, readFileSync as
|
|
281509
|
-
import { dirname as
|
|
281751
|
+
import { statSync as statSync43, readFileSync as readFileSync135, writeFileSync as writeFileSync75, mkdirSync as mkdirSync76, existsSync as existsSync134 } from "node:fs";
|
|
281752
|
+
import { dirname as dirname74, join as join151 } from "node:path";
|
|
281510
281753
|
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";
|
|
281511
281754
|
function formatTruth(t2, lang10) {
|
|
281512
281755
|
const lines3 = [];
|
|
@@ -281538,13 +281781,13 @@ var nodeFreshnessPort4 = {
|
|
|
281538
281781
|
},
|
|
281539
281782
|
readText(absPath) {
|
|
281540
281783
|
try {
|
|
281541
|
-
return
|
|
281784
|
+
return readFileSync135(absPath, "utf8");
|
|
281542
281785
|
} catch {
|
|
281543
281786
|
return "";
|
|
281544
281787
|
}
|
|
281545
281788
|
},
|
|
281546
281789
|
writeText(absPath, text2) {
|
|
281547
|
-
mkdirSync76(
|
|
281790
|
+
mkdirSync76(dirname74(absPath), { recursive: true });
|
|
281548
281791
|
writeFileSync75(absPath, text2, "utf8");
|
|
281549
281792
|
}
|
|
281550
281793
|
};
|
|
@@ -281552,8 +281795,8 @@ function truthAuditCommand(args, lang10) {
|
|
|
281552
281795
|
const json = args.includes("--json");
|
|
281553
281796
|
const cwd = process.cwd();
|
|
281554
281797
|
const nowSec2 = Math.floor(Date.now() / 1e3);
|
|
281555
|
-
const backlogPath =
|
|
281556
|
-
const backlogRows =
|
|
281798
|
+
const backlogPath = join151(cwd, ".roll", "backlog.md");
|
|
281799
|
+
const backlogRows = existsSync134(backlogPath) ? parseBacklog(readFileSync135(backlogPath, "utf8")).map((r) => ({ id: r.id, status: r.status })) : [];
|
|
281557
281800
|
const deliveries = ensureDeliveriesFresh(cwd, nodeFreshnessPort4, nodeExecPort);
|
|
281558
281801
|
const snapshot = emptyAuditSnapshot(nowSec2, TERMINAL_SCHEMA_EPOCH_SEC);
|
|
281559
281802
|
snapshot.backlog = backlogRows;
|
|
@@ -281638,8 +281881,8 @@ function truthCommand(args) {
|
|
|
281638
281881
|
|
|
281639
281882
|
// packages/cli/dist/commands/tune.js
|
|
281640
281883
|
init_dist2();
|
|
281641
|
-
import { existsSync as
|
|
281642
|
-
import { join as
|
|
281884
|
+
import { existsSync as existsSync135, readFileSync as readFileSync136 } from "node:fs";
|
|
281885
|
+
import { join as join152 } from "node:path";
|
|
281643
281886
|
function projectPath2() {
|
|
281644
281887
|
return (process.env["ROLL_MAIN_PROJECT"] ?? "").trim() || process.cwd();
|
|
281645
281888
|
}
|
|
@@ -281647,11 +281890,11 @@ function str6(v, dflt = "") {
|
|
|
281647
281890
|
return typeof v === "string" ? v : dflt;
|
|
281648
281891
|
}
|
|
281649
281892
|
function parseJsonl(path) {
|
|
281650
|
-
if (!
|
|
281893
|
+
if (!existsSync135(path))
|
|
281651
281894
|
return [];
|
|
281652
281895
|
let text2;
|
|
281653
281896
|
try {
|
|
281654
|
-
text2 =
|
|
281897
|
+
text2 = readFileSync136(path, "utf8");
|
|
281655
281898
|
} catch {
|
|
281656
281899
|
return [];
|
|
281657
281900
|
}
|
|
@@ -281782,9 +282025,9 @@ function tuneCommand(argv) {
|
|
|
281782
282025
|
if (argv[0] === "reset")
|
|
281783
282026
|
return printReset();
|
|
281784
282027
|
const proj = projectPath2();
|
|
281785
|
-
const loopDir2 =
|
|
281786
|
-
const runs = parseJsonl(
|
|
281787
|
-
const events = parseJsonl(
|
|
282028
|
+
const loopDir2 = join152(proj, ".roll", "loop");
|
|
282029
|
+
const runs = parseJsonl(join152(loopDir2, "runs.jsonl"));
|
|
282030
|
+
const events = parseJsonl(join152(loopDir2, "events.ndjson"));
|
|
281788
282031
|
const minSamplesRaw = flag(argv, "--min-samples");
|
|
281789
282032
|
const now2 = flag(argv, "--now") ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
281790
282033
|
const input = {
|
|
@@ -281823,9 +282066,9 @@ function tuneCommand(argv) {
|
|
|
281823
282066
|
// packages/cli/dist/commands/update.js
|
|
281824
282067
|
init_dist();
|
|
281825
282068
|
import { spawnSync as spawnSync21 } from "node:child_process";
|
|
281826
|
-
import { existsSync as
|
|
282069
|
+
import { existsSync as existsSync136, mkdtempSync as mkdtempSync11, readFileSync as readFileSync137, rmSync as rmSync27 } from "node:fs";
|
|
281827
282070
|
import { tmpdir as tmpdir13 } from "node:os";
|
|
281828
|
-
import { join as
|
|
282071
|
+
import { join as join153 } from "node:path";
|
|
281829
282072
|
function pal8() {
|
|
281830
282073
|
const noColor2 = (process.env["NO_COLOR"] ?? "") !== "";
|
|
281831
282074
|
return noColor2 ? { CYAN: "", GREEN: "", YELLOW: "", RED: "", BOLD: "", NC: "" } : {
|
|
@@ -281889,20 +282132,20 @@ function resolveRemoteVersion() {
|
|
|
281889
282132
|
}
|
|
281890
282133
|
function downloadAndInstallCurl(tag) {
|
|
281891
282134
|
const url = `https://github.com/seanyao/roll/archive/refs/tags/${tag}.tar.gz`;
|
|
281892
|
-
const tmpDir = mkdtempSync11(
|
|
282135
|
+
const tmpDir = mkdtempSync11(join153(tmpdir13(), "roll-update-"));
|
|
281893
282136
|
try {
|
|
281894
282137
|
info5(`[roll] Downloading roll ${tag} ...`);
|
|
281895
|
-
const dl = runForward2("curl", ["-fsSL", url, "-o",
|
|
282138
|
+
const dl = runForward2("curl", ["-fsSL", url, "-o", join153(tmpDir, "roll.tar.gz")]);
|
|
281896
282139
|
if (dl !== 0) {
|
|
281897
282140
|
err15(m6("update.curl_download_failed"));
|
|
281898
282141
|
return { ok: false };
|
|
281899
282142
|
}
|
|
281900
282143
|
info5("[roll] Extracting ...");
|
|
281901
|
-
const extractDir =
|
|
282144
|
+
const extractDir = join153(tmpDir, "extract");
|
|
281902
282145
|
spawnSync21("mkdir", ["-p", extractDir], { stdio: "ignore" });
|
|
281903
282146
|
const ex = runForward2("tar", [
|
|
281904
282147
|
"-xzf",
|
|
281905
|
-
|
|
282148
|
+
join153(tmpDir, "roll.tar.gz"),
|
|
281906
282149
|
"--strip-components=1",
|
|
281907
282150
|
"-C",
|
|
281908
282151
|
extractDir
|
|
@@ -281913,13 +282156,13 @@ function downloadAndInstallCurl(tag) {
|
|
|
281913
282156
|
}
|
|
281914
282157
|
return { ok: true, newVersion: treeVersion(extractDir) };
|
|
281915
282158
|
} finally {
|
|
281916
|
-
|
|
282159
|
+
rmSync27(tmpDir, { recursive: true, force: true });
|
|
281917
282160
|
}
|
|
281918
282161
|
}
|
|
281919
282162
|
function checkInstalledVersionOrRetry() {
|
|
281920
282163
|
const expected = (spawnSync21("npm", ["view", "@seanyao/roll", "version"], { encoding: "utf8" }).stdout ?? "").trim();
|
|
281921
282164
|
const pkgRoot = (spawnSync21("npm", ["root", "-g"], { encoding: "utf8" }).stdout ?? "").trim();
|
|
281922
|
-
const installedTree =
|
|
282165
|
+
const installedTree = join153(pkgRoot, "@seanyao", "roll");
|
|
281923
282166
|
const installed = treeVersion(installedTree);
|
|
281924
282167
|
if (expected === "" || installed === "")
|
|
281925
282168
|
return;
|
|
@@ -281933,18 +282176,18 @@ function checkInstalledVersionOrRetry() {
|
|
|
281933
282176
|
}
|
|
281934
282177
|
}
|
|
281935
282178
|
function invalidateUpdateCache() {
|
|
281936
|
-
|
|
282179
|
+
rmSync27(join153(rollHome(), ".update-check"), { force: true });
|
|
281937
282180
|
}
|
|
281938
282181
|
function showChangelog() {
|
|
281939
|
-
const changelog =
|
|
281940
|
-
if (!
|
|
282182
|
+
const changelog = join153(rollPkgDir(), "CHANGELOG.md");
|
|
282183
|
+
if (!existsSync136(changelog))
|
|
281941
282184
|
return;
|
|
281942
282185
|
const { BOLD: BOLD2, CYAN, NC } = pal8();
|
|
281943
282186
|
process.stdout.write(`${BOLD2}${m6("changelog.heading")}:${NC}
|
|
281944
282187
|
`);
|
|
281945
282188
|
let count = 0;
|
|
281946
282189
|
let inSection = false;
|
|
281947
|
-
for (const line of
|
|
282190
|
+
for (const line of readFileSync137(changelog, "utf8").split("\n")) {
|
|
281948
282191
|
if (/^## /.test(line)) {
|
|
281949
282192
|
count += 1;
|
|
281950
282193
|
if (count > 3)
|
|
@@ -281967,9 +282210,9 @@ async function updateCommand(args) {
|
|
|
281967
282210
|
}
|
|
281968
282211
|
info5(m6("update.current_version", rollVersion()));
|
|
281969
282212
|
let installMethod = "npm";
|
|
281970
|
-
const methodFile =
|
|
281971
|
-
if (
|
|
281972
|
-
installMethod =
|
|
282213
|
+
const methodFile = join153(rollPkgDir(), ".install-method");
|
|
282214
|
+
if (existsSync136(methodFile)) {
|
|
282215
|
+
installMethod = readFileSync137(methodFile, "utf8").trim() || "npm";
|
|
281973
282216
|
}
|
|
281974
282217
|
if (installMethod === "curl") {
|
|
281975
282218
|
info5(m6("update.upgrading_via_curl"));
|
|
@@ -282005,9 +282248,9 @@ async function updateCommand(args) {
|
|
|
282005
282248
|
|
|
282006
282249
|
// packages/cli/dist/commands/worktree-audit.js
|
|
282007
282250
|
import { execFileSync as execFileSync34 } from "node:child_process";
|
|
282008
|
-
import { readFileSync as
|
|
282251
|
+
import { readFileSync as readFileSync138 } from "node:fs";
|
|
282009
282252
|
import { homedir as homedir32 } from "node:os";
|
|
282010
|
-
import { basename as basename20, dirname as
|
|
282253
|
+
import { basename as basename20, dirname as dirname75, join as join154, relative as relative12, resolve as resolve13 } from "node:path";
|
|
282011
282254
|
function git5(args, cwd) {
|
|
282012
282255
|
try {
|
|
282013
282256
|
return execFileSync34("git", args, {
|
|
@@ -282022,7 +282265,7 @@ function git5(args, cwd) {
|
|
|
282022
282265
|
}
|
|
282023
282266
|
function readFileSafe(p) {
|
|
282024
282267
|
try {
|
|
282025
|
-
return
|
|
282268
|
+
return readFileSync138(p, "utf8");
|
|
282026
282269
|
} catch {
|
|
282027
282270
|
return null;
|
|
282028
282271
|
}
|
|
@@ -282033,7 +282276,7 @@ function classifyOwner(absPath, repoRoot3) {
|
|
|
282033
282276
|
const rp = resolve13(absPath);
|
|
282034
282277
|
if (rp.startsWith(loopRoot + "/") || rp === loopRoot)
|
|
282035
282278
|
return "loop";
|
|
282036
|
-
const repoParent =
|
|
282279
|
+
const repoParent = dirname75(resolve13(repoRoot3));
|
|
282037
282280
|
const rel = relative12(repoParent, rp);
|
|
282038
282281
|
if (!rel.startsWith("..")) {
|
|
282039
282282
|
const name = basename20(rp);
|
|
@@ -282142,7 +282385,7 @@ function countAhead(wtPath, deps) {
|
|
|
282142
282385
|
function isActiveCycle(cycleId, repoRoot3, deps) {
|
|
282143
282386
|
if (!cycleId)
|
|
282144
282387
|
return false;
|
|
282145
|
-
const lockPath2 =
|
|
282388
|
+
const lockPath2 = join154(repoRoot3, ".roll", "loop", "inner.lock");
|
|
282146
282389
|
const lock = deps.readFile ? deps.readFile(lockPath2) : readFileSafe(lockPath2);
|
|
282147
282390
|
if (lock) {
|
|
282148
282391
|
for (const line of lock.split("\n")) {
|
|
@@ -282153,7 +282396,7 @@ function isActiveCycle(cycleId, repoRoot3, deps) {
|
|
|
282153
282396
|
const nowSec2 = deps.nowSec?.() ?? Math.floor(Date.now() / 1e3);
|
|
282154
282397
|
const HEARTBEAT_STALE_SEC = 300;
|
|
282155
282398
|
try {
|
|
282156
|
-
const heartbeatPath =
|
|
282399
|
+
const heartbeatPath = join154(repoRoot3, ".roll", "loop", "heartbeat");
|
|
282157
282400
|
const hb = deps.readFile ? deps.readFile(heartbeatPath) : readFileSafe(heartbeatPath);
|
|
282158
282401
|
if (hb) {
|
|
282159
282402
|
for (const line of hb.split("\n")) {
|
|
@@ -282209,7 +282452,7 @@ function classifyDisposition(rec) {
|
|
|
282209
282452
|
function auditWorktrees(deps) {
|
|
282210
282453
|
const repoRoot3 = resolve13(deps.repoRoot);
|
|
282211
282454
|
const wtOutput = deps.git ? deps.git(["worktree", "list", "--porcelain"], repoRoot3) : git5(["worktree", "list", "--porcelain"], repoRoot3);
|
|
282212
|
-
const eventsPath4 =
|
|
282455
|
+
const eventsPath4 = join154(repoRoot3, ".roll", "loop", "events.ndjson");
|
|
282213
282456
|
const cycles = readCycleContext(eventsPath4, deps);
|
|
282214
282457
|
const entries = [];
|
|
282215
282458
|
let current = {};
|