@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.
Files changed (3) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/roll.mjs +676 -433
  3. 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: { ...state.ctx, agent: event.agent, model: event.model }
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 existsSync128, mkdirSync as mkdirSync71, mkdtempSync as mkdtempSync9, readdirSync as readdirSync50, readFileSync as readFileSync129, rmSync as rmSync23, statSync as statSync40, writeFileSync as writeFileSync71 } from "node:fs";
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 dirname70, join as join144 } from "node:path";
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 = dirname70(fileURLToPath3(import.meta.url));
235959
+ let dir = dirname71(fileURLToPath3(import.meta.url));
235833
235960
  for (let i = 0; i < 12; i++) {
235834
- if (existsSync128(join144(dir, "conventions")))
235961
+ if (existsSync129(join145(dir, "conventions")))
235835
235962
  return dir;
235836
- const parent = dirname70(dir);
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 = join144(packageRoot(), "packages", "cli", "bin", "roll.js");
235845
- if (existsSync128(devPath))
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 existsSync128(p) && statSync40(p).size > 0;
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(join144(tmpdir12(), "roll-showcase-"));
235879
- const sandbox = join144(root, "project");
235880
- const rollHome4 = join144(root, "home");
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 = join144(sourceProject, ".roll");
235884
- if (existsSync128(srcRoll)) {
235885
- cpSync3(srcRoll, join144(sandbox, ".roll"), { recursive: true });
236010
+ const srcRoll = join145(sourceProject, ".roll");
236011
+ if (existsSync129(srcRoll)) {
236012
+ cpSync3(srcRoll, join145(sandbox, ".roll"), { recursive: true });
235886
236013
  } else {
235887
- mkdirSync71(join144(sandbox, ".roll", "features"), { recursive: true });
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 = join144(sandbox, ".roll", "features");
236019
+ const featuresDir = join145(sandbox, ".roll", "features");
235893
236020
  const candidates = [];
235894
236021
  const walk2 = (dir, depth) => {
235895
- if (depth > 3 || !existsSync128(dir))
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 = join144(dir, name);
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 && existsSync128(join144(full, "spec.md")))
235913
- candidates.push(join144(full, "spec.md"));
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 = join144(sandbox, ".roll", "backlog.md");
235926
- if (existsSync128(backlogPath)) {
235927
- const before = readFileSync129(backlogPath, "utf8");
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 = join144(sandbox, "packages", "cli", "src", "commands", "pulse.ts");
235955
- if (existsSync128(pulseCmd)) {
235956
- rmSync23(pulseCmd, { force: true });
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 = join144(sandbox, ".roll", "agents.yaml");
235963
- mkdirSync71(dirname70(agentsPath), { recursive: true });
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 = join144(sandbox, ".roll", "showcase", card, "screenshots");
236096
+ const shotDir = join145(sandbox, ".roll", "showcase", card, "screenshots");
235970
236097
  mkdirSync71(shotDir, { recursive: true });
235971
- const cliOut = join144(shotDir, "pulse-cli.png");
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 = join144(sandbox, ".roll", "features", "index.html");
235984
- const webOut = join144(shotDir, "now-pulse-badge.png");
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: existsSync128(nowPage) ? `file://${nowPage}#now` : "about:blank"
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 = join144(sandbox, ".roll", "backlog.md");
236000
- if (!existsSync128(backlogPath))
236126
+ const backlogPath = join145(sandbox, ".roll", "backlog.md");
236127
+ if (!existsSync129(backlogPath))
236001
236128
  return void 0;
236002
- for (const line of readFileSync129(backlogPath, "utf8").split("\n")) {
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 = join144(sandbox, ".roll", "features", "truth.json");
236013
- if (!existsSync128(truthPath))
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(readFileSync129(truthPath, "utf8"));
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 = join144(sandbox, ".roll", "loop", "runs.jsonl");
236025
- if (!existsSync128(runsPath3))
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 = readFileSync129(runsPath3, "utf8").trim().split("\n").filter(Boolean);
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 = join144(sandbox, ".roll", "features");
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
- rmSync23(dirname70(sandbox), { recursive: true, force: true });
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: rmSync27 } = __require("node:fs");
254675
- rmSync27(tmp, { force: true });
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 existsSync122, mkdirSync as mkdirSync67, readdirSync as readdirSync45, readFileSync as readFileSync123, writeFileSync as writeFileSync66 } from "node:fs";
271070
- import { dirname as dirname67, join as join138 } from "node:path";
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
- return { event: { type: "route_resolved", agent: selectedAgent, model: selectedModel }, ctxPatch: { selectedProfile } };
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 existsSync114, mkdirSync as mkdirSync62, readFileSync as readFileSync116, writeFileSync as writeFileSync61 } from "node:fs";
273729
- import { dirname as dirname63, join as join132 } from "node:path";
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 existsSync110, mkdirSync as mkdirSync59, readFileSync as readFileSync112, readdirSync as readdirSync42, writeFileSync as writeFileSync58 } from "node:fs";
273736
- import { dirname as dirname61, join as join128 } from "node:path";
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 = join128(projectPath3, ".roll", "policy.yaml");
273740
- if (!existsSync110(path))
273977
+ const path = join129(projectPath3, ".roll", "policy.yaml");
273978
+ if (!existsSync111(path))
273741
273979
  return "conservative";
273742
- return parsePolicy(readFileSync112(path, "utf8")).loopSafety.correctionActuator;
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 readFileSync112(eventsPath4, "utf8").split("\n").map(parseEventLine).filter((ev) => ev !== null);
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(dirname61(eventsPath4), { recursive: true });
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(dirname61(alertsPath), { recursive: true });
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 = join128(projectPath3, ".roll", "backlog.md");
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(readFileSync112(join128(projectPath3, ".roll", "index.json"), "utf8"));
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 = join128(projectPath3, ".roll", "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 (existsSync110(join128(features, d.name, storyId)))
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(join128(projectPath3, ".roll", "backlog.md"));
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 = join128(projectPath3, ".roll", "features", epic, fixId);
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(join128(dir, "spec.md"), body, "utf8");
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 = join128(projectPath3, ".roll", "backlog.md");
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 = join128(projectPath3, ".roll", "backlog.md");
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 existsSync112, mkdirSync as mkdirSync60, readFileSync as readFileSync114, writeFileSync as writeFileSync59 } from "node:fs";
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 join130 } from "node:path";
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 existsSync111, readFileSync as readFileSync113, readdirSync as readdirSync43 } from "node:fs";
273987
- import { join as join129 } from "node:path";
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 = join129(runtimeDir12, "peer");
274018
- if (!existsSync111(dir))
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 = join129(repoCwd, ".roll", "policy.yaml");
274029
- if (!existsSync111(p))
274266
+ const p = join130(repoCwd, ".roll", "policy.yaml");
274267
+ if (!existsSync112(p))
274030
274268
  return "hard";
274031
- return parsePolicy(readFileSync113(p, "utf8")).loopSafety.peerGate === "soft" ? "soft" : "hard";
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 = join129(repoCwd, ".roll", "policy.yaml");
274039
- if (!existsSync111(p))
274276
+ const p = join130(repoCwd, ".roll", "policy.yaml");
274277
+ if (!existsSync112(p))
274040
274278
  return "block";
274041
- return parsePolicy(readFileSync113(p, "utf8")).loopSafety.peerOnPoolTimeout === "degrade" ? "degrade" : "block";
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 (!existsSync112(path))
274321
+ if (!existsSync113(path))
274084
274322
  return null;
274085
- const text2 = readFileSync114(path, "utf8");
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"] ?? join130(homedir29(), ".roll");
274333
+ const rollHome4 = process.env["ROLL_HOME"] ?? join131(homedir29(), ".roll");
274096
274334
  const layers = [
274097
- readScopedAgentLayer2(join130(rollHome4, "agents.yaml")),
274098
- readScopedAgentLayer2(join130(projectDir, ".roll", "agents.yaml"))
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 = join130(projectDir, ".roll", "pairing.yaml");
274131
- if (existsSync112(cfgPath))
274132
- return { cfg: parsePairingConfig(readFileSync114(cfgPath, "utf8")), source: "legacy-pairing" };
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 = join130(runtimeDir12, "peer");
274387
+ const dir = join131(runtimeDir12, "peer");
274150
274388
  const name = stage === "code" ? `cycle-${cycleId}.pair.json` : `cycle-${cycleId}.${stage}.pair.json`;
274151
- return join130(dir, name);
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(join130(runtimeDir12, "peer"), { recursive: true });
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(join130(runtimeDir12, "peer"), { recursive: true });
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(join130(runtimeDir12, "peer"), { recursive: true });
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 existsSync113, mkdirSync as mkdirSync61, readFileSync as readFileSync115, writeFileSync as writeFileSync60 } from "node:fs";
274640
- import { dirname as dirname62, join as join131 } from "node:path";
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 = join131(dirname62(ports.paths.eventsPath), "cycle-logs", ctx.cycleId ?? "cycle", "peer");
274912
+ const peerDir2 = join132(dirname63(ports.paths.eventsPath), "cycle-logs", ctx.cycleId ?? "cycle", "peer");
274675
274913
  mkdirSync61(peerDir2, { recursive: true });
274676
- const artifactPath2 = join131(peerDir2, `${peer}.${stage}.attempt-${attempt}.raw.txt`);
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 (!existsSync113(ports.paths.eventsPath))
274924
+ if (!existsSync114(ports.paths.eventsPath))
274687
274925
  return excludedPeers([]);
274688
- const events = readFileSync115(ports.paths.eventsPath, "utf8").split("\n").map(parseEventLine).filter((e) => e !== null);
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 = dirname63(ports.paths.eventsPath);
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 (existsSync114(ports.paths.eventsPath)) {
274845
- const events = readFileSync116(ports.paths.eventsPath, "utf8").split("\n").map(parseEventLine).filter((e) => e !== null);
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, dirname63(ports.paths.eventsPath), ctx.cycleId ?? "", ctx.agent ?? "", stage, pairingDeps);
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 = join132(runtimeDir12, "peer-unavailable");
275126
+ const unavailableDir = join133(runtimeDir12, "peer-unavailable");
274889
275127
  mkdirSync62(unavailableDir, { recursive: true });
274890
- writeFileSync61(join132(unavailableDir, `cycle-${cycleIdStr}.json`), JSON.stringify({
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 = join132(cardArchiveDir(ports.repoCwd, storyId), "spec.md");
275004
- if (existsSync114(specPath)) {
275005
- const specText = readFileSync116(specPath, "utf8");
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, dirname63(ports.paths.eventsPath), ctx.cycleId ?? "", ctx.agent ?? "", storyId, skill, summary, {
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 existsSync117, lstatSync as lstatSync10, realpathSync as realpathSync17, unlinkSync as unlinkSync5 } from "node:fs";
275185
- import { dirname as dirname64, join as join134 } from "node:path";
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 existsSync115, readFileSync as readFileSync117, mkdirSync as mkdirSync63, writeFileSync as writeFileSync62 } from "node:fs";
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 = readFileSync117(eventsPath4, "utf-8");
275435
+ raw = readFileSync118(eventsPath4, "utf-8");
275198
275436
  } catch {
275199
275437
  return;
275200
275438
  }
275201
275439
  const outDir = `${cycleLogDir}/${cycleId}`;
275202
- if (!existsSync115(outDir)) {
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 existsSync116, lstatSync as lstatSync9, mkdirSync as mkdirSync64, readFileSync as readFileSync118, readdirSync as readdirSync44, renameSync as renameSync24, rmSync as rmSync21 } from "node:fs";
275228
- import { basename as basename19, join as join133, relative as relative11 } from "node:path";
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 = readFileSync118(manifestPath2, "utf8");
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 = join133(worktreePath, pattern);
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 = join133(worktreePath, prefix);
275471
- if (!existsSync116(base))
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 = join133(dir, entry);
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 (!existsSync116(absPath)) {
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 = join133(worktreePath, ".roll-cleanup", cycleId, rule.name);
275754
+ const isolateRoot = join134(worktreePath, ".roll-cleanup", cycleId, rule.name);
275517
275755
  const base = basename19(absPath);
275518
- const dest = join133(isolateRoot, base);
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
- rmSync21(absPath, { recursive: true, force: true });
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 = dirname64(ports.paths.eventsPath);
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 = join134(ports.repoCwd, ".roll", "loop", "cleanup-manifest.yaml");
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 = join134(ports.paths.worktreePath, ".roll");
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(join134(ports.repoCwd, ".roll"));
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(join134(dirname64(ports.paths.eventsPath), "story-leases.json"), terminalStoryId, "cycle");
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 = join134(dirname64(ports.paths.eventsPath), "cycle-logs");
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 = join134(worktreePath, ".roll");
275879
- if (!existsSync117(rollDir))
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 = join134(".roll", "backlog.md");
276134
+ const backlogRel = join135(".roll", "backlog.md");
275897
276135
  try {
275898
- if (!existsSync117(join134(ports.repoCwd, backlogRel)))
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 existsSync119, mkdirSync as mkdirSync65, readFileSync as readFileSync120, statSync as statSync38, writeFileSync as writeFileSync64 } from "node:fs";
275922
- import { dirname as dirname65, join as join136 } from "node:path";
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 existsSync118, readFileSync as readFileSync119, writeFileSync as writeFileSync63 } from "node:fs";
275927
- import { join as join135 } from "node:path";
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 join135(runtimeDir12, "selfheal-cards.json");
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 (!existsSync118(p))
276184
+ if (!existsSync119(p))
275947
276185
  return { stories: {} };
275948
- const o = JSON.parse(readFileSync119(p, "utf8"));
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 readFileSync120(absPath, "utf8");
276265
+ return readFileSync121(absPath, "utf8");
276028
276266
  } catch {
276029
276267
  return "";
276030
276268
  }
276031
276269
  },
276032
276270
  writeText(absPath, text2) {
276033
- mkdirSync65(dirname65(absPath), { recursive: true });
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(dirname65(opts.paths.eventsPath)).has(storyId),
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 = join136(projectCwd, ".roll", "backlog.md");
276217
- if (!existsSync119(p))
276454
+ const p = join137(projectCwd, ".roll", "backlog.md");
276455
+ if (!existsSync120(p))
276218
276456
  return [];
276219
- return parseBacklog(readFileSync120(p, "utf8"));
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 = join136(projectCwd, ".roll", "backlog.md");
276228
- if (!existsSync119(p))
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() || join136(opts.repoCwd, ".roll", "loop");
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: join136(cardArchiveDir(projectCwd, storyId), runId) }).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(dirname65(alertsPath), { recursive: true });
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 existsSync120, readFileSync as readFileSync121 } from "node:fs";
276600
+ import { existsSync as existsSync121, readFileSync as readFileSync122 } from "node:fs";
276360
276601
  function readCycleAttributionFromEvents(eventsPath4, cycleId) {
276361
- if (!existsSync120(eventsPath4))
276602
+ if (!existsSync121(eventsPath4))
276362
276603
  return {};
276363
276604
  let content;
276364
276605
  try {
276365
- content = readFileSync121(eventsPath4, "utf8");
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 existsSync121, mkdirSync as mkdirSync66, readFileSync as readFileSync122, writeFileSync as writeFileSync65 } from "node:fs";
276640
- import { dirname as dirname66, join as join137 } from "node:path";
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 = join137(projectPath3, ".roll", "policy.yaml");
276644
- if (!existsSync121(path))
276886
+ const path = join138(projectPath3, ".roll", "policy.yaml");
276887
+ if (!existsSync122(path))
276645
276888
  return parsePolicy("").loopSafety;
276646
- return parsePolicy(readFileSync122(path, "utf8")).loopSafety;
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 readFileSync122(eventsPath4, "utf8").split("\n").map(parseEventLine).filter((ev) => ev !== null);
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(dirname66(eventsPath4), { recursive: true });
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 = join137(projectPath3, ".roll", "loop", `PAUSE-${slug3}`);
276677
- const pauseWritten = !existsSync121(pauseMarker);
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(dirname66(pauseMarker), { recursive: true });
276933
+ mkdirSync66(dirname67(pauseMarker), { recursive: true });
276691
276934
  if (pauseWritten)
276692
276935
  writeFileSync65(pauseMarker, alertMsg, "utf8");
276693
- mkdirSync66(dirname66(alertsPath), { recursive: true });
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 = join138(cardArchiveDir(projectPath3, storyId), "latest");
276727
- const review = join138(latest, reviewFileName(storyId));
276728
- const legacyReport = join138(latest, reportFileName(storyId));
276729
- const report = existsSync122(review) ? review : existsSync122(legacyReport) ? legacyReport : null;
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 = existsSync122(join138(projectPath3, ".roll", "loop", `mute-${slug3}`)) || existsSync122(join138(process.env["ROLL_SHARED_ROOT"] || join138(process.env["HOME"] ?? "", ".shared", "roll"), "loop", `mute-${slug3}`));
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(join138(runtimeDirPath, "live.log"), `=== cycle ${cycleId} ===
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 = existsSync122(paths.lockPath) && readLockOwner(paths.lockPath)?.pid === pid;
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 : join138(projectPath3, ".roll", "loop");
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 = join138(rt, "consecutive-fails");
277137
+ const counterFile = join139(rt, "consecutive-fails");
276895
277138
  let count = 0;
276896
277139
  try {
276897
- if (existsSync122(counterFile)) {
276898
- count = parseInt(readFileSync123(counterFile, "utf8").trim(), 10) || 0;
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 = join138(projectPath3, ".roll", "loop", `PAUSE-${slug3}`);
276911
- if (existsSync122(pauseMarker))
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 = join138(projectPath3, ".roll", "loop", `PAUSE-${slug3}`);
276947
- if (existsSync122(pauseMarker))
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 = join138(projectPath3, ".roll", "policy.yaml");
277009
- if (!existsSync122(policy))
277251
+ const policy = join139(projectPath3, ".roll", "policy.yaml");
277252
+ if (!existsSync123(policy))
277010
277253
  return PAUSE_THRESHOLD;
277011
- return parsePolicy(readFileSync123(policy, "utf8")).loopSafety.maxConsecutiveFailures;
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(join138(rt, "consecutive-fails"), "0", "utf8");
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 join138(runtimeDir11(projectPath3), `consecutive-idle-${slug3}`);
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 (existsSync122(file)) {
277040
- count = parseInt(readFileSync123(file, "utf8").trim(), 10) || 0;
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 (!existsSync122(eventsPath4))
277349
+ if (!existsSync123(eventsPath4))
277107
277350
  return null;
277108
- for (const line of readFileSync123(eventsPath4, "utf8").split("\n")) {
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 = join138(projectPath3, ".roll", "loop", `PAUSE-${slug3}`);
277171
- if (!existsSync122(pauseMarker)) {
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 = join138(projectPath3, ".roll", "agents.yaml");
277433
+ const agentsYaml = join139(projectPath3, ".roll", "agents.yaml");
277191
277434
  try {
277192
- return readSlotFromText(readFileSync123(agentsYaml, "utf8"), slot);
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(join138(projectPath3, ".roll", "local.yaml"), /^agent:/);
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 = readFileSync123(path, "utf8");
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 = join138(stableProjectPath, ".roll", "loop");
277240
- mkdirSync67(dirname67(stableRt), { recursive: true });
277241
- appendFileSync22(join138(stableRt, `ALERT-${id.slug}.md`), `${msg6}
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 = join138(rt, `ALERT-${id.slug}.md`);
277269
- mkdirSync67(dirname67(alertsPath), { recursive: true });
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: join138(rt, "events.ndjson"),
277281
- runsPath: join138(rt, "runs.jsonl"),
277523
+ eventsPath: join139(rt, "events.ndjson"),
277524
+ runsPath: join139(rt, "runs.jsonl"),
277282
277525
  alertsPath,
277283
- lockPath: join138(rt, "inner.lock"),
277284
- heartbeatPath: join138(rt, "heartbeat"),
277285
- worktreePath: join138(rt, "worktrees", `cycle-${cycleId}`)
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(join138(rt, "go.lock"));
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, join138(rt, "events.ndjson"), cycleId, "", "skill_missing");
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 = join138(id.path, ".roll", "backlog.md");
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: () => existsSync122(backlogFile) ? readFileSync123(backlogFile, "utf8") : "",
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 = join138(id.path, ".roll", "loop", `PAUSE-${id.slug}`);
277485
- mkdirSync67(dirname67(p), { recursive: true });
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 = join138(id.path, ".roll", "backlog.md");
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 = readFileSync123(backlogFile, "utf8");
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 existsSync122(join138(projectPath3, ".roll", "loop", `PAUSE-${slug3}`));
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(join138(rt, "worktrees"), { withFileTypes: true }).filter((e) => e.isDirectory()).length;
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 = join138(projectPath3, ".roll", "loop", `PAUSE-${slug3}`);
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(dirname67(pauseMarker), { recursive: true });
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(join138(cwd, ".roll"));
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 existsSync123, readFileSync as readFileSync124, realpathSync as realpathSync18, renameSync as renameSync25, rmSync as rmSync22, writeFileSync as writeFileSync67 } from "node:fs";
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 join139, resolve as resolve11 } from "node:path";
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 join139(projectDir, ".roll", "onboard-changeset.yaml");
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 = join139(homedir30(), "Library", "LaunchAgents");
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
- rmSync22(tmp, { force: true });
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 (!existsSync123(changeset)) {
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(readFileSync124(changeset, "utf8"));
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 (!existsSync123(path))
278240
+ if (!existsSync124(path))
277998
278241
  continue;
277999
- const before = readFileSync124(path, "utf8");
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
- rmSync22(path, { force: true });
278011
- if (!existsSync123(path))
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
- rmSync22(resolveChangesetItem(projectDir, item), { recursive: true, force: true });
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 = join139(projectDir, ".gitignore");
278027
- if (existsSync123(gi)) {
278028
- const lines3 = readFileSync124(gi, "utf8").split("\n");
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 = join139(homedir30(), "Library", "LaunchAgents", item);
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
- rmSync22(plistPath, { force: true });
278286
+ rmSync23(plistPath, { force: true });
278044
278287
  }
278045
- rmSync22(changeset, { force: true });
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 existsSync125, readdirSync as readdirSync47, readFileSync as readFileSync126 } from "node:fs";
278053
- import { join as join141 } from "node:path";
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 existsSync124, mkdirSync as mkdirSync68, readdirSync as readdirSync46, readFileSync as readFileSync125, writeFileSync as writeFileSync68 } from "node:fs";
278058
- import { join as join140 } from "node:path";
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 (!existsSync124(snapshotDir))
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) => join140(snapshotDir, 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(readFileSync125(path, "utf8"));
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 = join140(input.snapshotDir, `snapshot-${input.effectiveAt}${suffix}.json`);
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 ?? join140(repoRoot2(), "lib", "prices");
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 = join141(repoRoot2(), "lib", "prices");
278488
- if (!existsSync125(dir)) {
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(readFileSync126(join141(dir, name), "utf8"));
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 readFileSync130, writeFileSync as writeFileSync72, existsSync as existsSync129 } from "node:fs";
278673
- import { dirname as dirname71, join as join145 } from "node:path";
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 existsSync127, mkdirSync as mkdirSync70, readFileSync as readFileSync128, readdirSync as readdirSync49, statSync as statSync39, writeFileSync as writeFileSync70 } from "node:fs";
278681
- import { dirname as dirname69, join as join143 } from "node:path";
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 existsSync126, mkdirSync as mkdirSync69, readFileSync as readFileSync127, readdirSync as readdirSync48, writeFileSync as writeFileSync69 } from "node:fs";
278689
- import { dirname as dirname68, join as join142 } from "node:path";
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 (!existsSync126(path))
278940
+ if (!existsSync127(path))
278698
278941
  return [];
278699
278942
  const out3 = [];
278700
- for (const line of readFileSync127(path, "utf8").split("\n")) {
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 (!existsSync126(path))
278956
+ if (!existsSync127(path))
278714
278957
  return null;
278715
278958
  try {
278716
- const parsed = JSON.parse(readFileSync127(path, "utf8"));
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 = dirname68(reportPath);
278724
- const manifest = readJson(join142(runDir, "evidence.json"));
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 = join142(runDir, "screenshots");
278741
- if (!existsSync126(dir))
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(join142(dirname68(reportPath), "evidence.json"));
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 = join142(projectPath3, ".roll", "backlog.md");
278778
- if (existsSync126(backlogPath)) {
278779
- snapshot.backlog = parseBacklog(readFileSync127(backlogPath, "utf8")).map((r) => ({ id: r.id, status: r.status }));
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(join142(runtimeDir12, "runs.jsonl"));
279026
+ snapshot.runs = readJsonl(join143(runtimeDir12, "runs.jsonl"));
278784
279027
  let eventFailed = 0;
278785
279028
  const terminal = [];
278786
- const eventsPath4 = join142(runtimeDir12, "events.ndjson");
278787
- if (existsSync126(eventsPath4)) {
278788
- for (const line of readFileSync127(eventsPath4, "utf8").split("\n")) {
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 (!existsSync126(card))
279053
+ if (!existsSync127(card))
278811
279054
  continue;
278812
- const reportPath = join142(card, "latest", reportFileName(row2.id));
278813
- const specPath = join142(card, "spec.md");
279055
+ const reportPath = join143(card, "latest", reportFileName(row2.id));
279056
+ const specPath = join143(card, "spec.md");
278814
279057
  let noVisualSurface = false;
278815
- if (existsSync126(specPath)) {
279058
+ if (existsSync127(specPath)) {
278816
279059
  try {
278817
- noVisualSurface = !hasVisualEvidenceAc(readFileSync127(specPath, "utf8"));
279060
+ noVisualSurface = !hasVisualEvidenceAc(readFileSync128(specPath, "utf8"));
278818
279061
  } catch {
278819
279062
  }
278820
279063
  }
278821
279064
  snapshot.attest[row2.id] = {
278822
- report: existsSync126(reportPath),
278823
- acMap: existsSync126(join142(card, "ac-map.json")),
278824
- visualEvidence: existsSync126(reportPath) ? hasScreenshotArtifact(reportPath) : false,
278825
- machineSkip: existsSync126(reportPath) ? hasMachineCaptureSkip2(reportPath) : false,
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 : join142(projectPath3, ".roll", "loop");
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 = join142(projectPath3, ".roll", "reports", "consistency");
279157
+ const outDir = join143(projectPath3, ".roll", "reports", "consistency");
278915
279158
  try {
278916
279159
  mkdirSync69(outDir, { recursive: true });
278917
- writeFileSync69(join142(outDir, `${dateTag}.json`), JSON.stringify({ generatedAt: dateTag, ...report, skipped: skipped2 }, null, 1));
278918
- writeFileSync69(join142(outDir, `${dateTag}.md`), renderMarkdown2(report, skipped2, dateTag));
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 ${join142(".roll", "reports", "consistency", `${dateTag}.md`)}
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 readFileSync128(p, "utf8");
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: join143(projectDir, rel) })).filter((f) => {
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 = join143(projectDir, dirRel);
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 = join143(dirRel, entry.name);
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: join143(projectDir, rel) });
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 readFileSync128(absPath, "utf8");
279380
+ return readFileSync129(absPath, "utf8");
279138
279381
  } catch {
279139
279382
  return "";
279140
279383
  }
279141
279384
  },
279142
279385
  writeText(absPath, text2) {
279143
- mkdirSync70(dirname69(absPath), { recursive: true });
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 = join143(projectDir, ".roll", "features");
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 = join143(featuresDir, epic.name, id, "spec.md");
279188
- if (existsSync127(spec))
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 = join143(projectDir, ".roll", "backlog.md");
279207
- if (!existsSync127(backlog))
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 = join143(projectDir, ".roll", "features.md");
279212
- if (existsSync127(features)) {
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 = join143(projectDir, ".roll", "backlog.md");
279236
- if (!existsSync127(backlog))
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 = join143(projectDir, ".roll", "backlog.md");
279273
- const featuresDir = join143(projectDir, ".roll", "features");
279274
- if (!existsSync127(backlog) || !existsSync127(featuresDir))
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(join143(featuresDir, epic.name), { withFileTypes: true })) {
279524
+ for (const card of readdirSync49(join144(featuresDir, epic.name), { withFileTypes: true })) {
279282
279525
  if (!card.isDirectory())
279283
279526
  continue;
279284
- if (existsSync127(join143(featuresDir, epic.name, card.name, "spec.md")) && !cardEpic.has(card.name)) {
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(join143(featuresDir, epic, id, "spec.md"));
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 (!existsSync127(join143(projectDir, ".roll", target))) {
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 (!existsSync127(join143(featuresDir, epic, id, "latest", `${id}-report.html`))) {
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 = join143(projectDir, "CHANGELOG.md");
279347
- if (existsSync127(changelogPath)) {
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 = join143(projectDir, "site", "roll-data.js");
279421
- const backlog = join143(projectDir, ".roll", "backlog.md");
279422
- if (!existsSync127(siteJs) || !existsSync127(backlog))
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 (!existsSync127(join143(projectDir, rel))) {
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(join143(dir, n)).isFile();
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 = join143(projectDir, "guide", "en");
279484
- const guideZh = join143(projectDir, "guide", "zh");
279485
- if (existsSync127(guideEn) && existsSync127(guideZh)) {
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 = join143(projectDir, "lib", "i18n");
279496
- if (existsSync127(i18nDir)) {
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(join143(i18nDir, name));
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 = join143(d, e);
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 = join143(projectDir, ".roll", "backlog.md");
279565
- const testsDir = join143(projectDir, "tests");
279566
- if (!existsSync127(backlog))
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 = existsSync127(testsDir) ? rglobBats(testsDir) : [];
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 = join145(cwd, ".roll", "last-test-pass");
279937
- mkdirSync72(dirname71(proofPath), { recursive: true });
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 = join145(cwd, ".roll", "last-test-pass");
279943
- if (!existsSync129(proofPath)) {
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 = readFileSync130(proofPath, "utf8");
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(readFileSync130(join145(cwd, "package.json"), "utf8"));
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) => readFileSync130(join145(cwd, "CHANGELOG.md"), "utf8"),
280059
- writeChangelog: (cwd, text2) => writeFileSync72(join145(cwd, "CHANGELOG.md"), text2, "utf8"),
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 = join145(cwd, "package.json");
280062
- const pkg = JSON.parse(readFileSync130(path, "utf8"));
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: existsSync129(join145(cwd, ".roll")),
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 !== "" ? join145(runtimeDir12, EVENTS_FILE) : join145(cwd, ".roll", "loop", EVENTS_FILE);
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 existsSync131, lstatSync as lstatSync12, mkdirSync as mkdirSync74, readFileSync as readFileSync132, readdirSync as readdirSync52, readlinkSync as readlinkSync3, statSync as statSync42 } from "node:fs";
280402
- import { join as join147 } from "node:path";
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 existsSync130, lstatSync as lstatSync11, mkdirSync as mkdirSync73, mkdtempSync as mkdtempSync10, readdirSync as readdirSync51, readFileSync as readFileSync131, renameSync as renameSync26, rmSync as rmSync24, statSync as statSync41, writeFileSync as writeFileSync73 } from "node:fs";
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 join146 } from "node:path";
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: existsSync130,
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 = join146(deps.home, "Applications");
280482
- const targetApp = join146(applicationsDir, APP_NAME2);
280724
+ const applicationsDir = join147(deps.home, "Applications");
280725
+ const targetApp = join147(applicationsDir, APP_NAME2);
280483
280726
  mkdirSync73(applicationsDir, { recursive: true });
280484
- const workDir = mkdtempSync10(join146(applicationsDir, ".roll-capture-install-"));
280485
- const zipPath = join146(workDir, ASSET_NAME);
280486
- const extractDir = join146(workDir, "extract");
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
- rmSync24(workDir, { recursive: true, force: true });
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 = join146(dir, name);
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 = join146(appPath, "Contents", "MacOS");
280904
+ const macosDir = join147(appPath, "Contents", "MacOS");
280662
280905
  try {
280663
280906
  for (const name of readdirSync51(macosDir)) {
280664
- const candidate = join146(macosDir, name);
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
- rmSync24(backupApp, { recursive: true, force: true });
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
- rmSync24(backupApp, { recursive: true, force: true });
280935
+ rmSync25(backupApp, { recursive: true, force: true });
280693
280936
  } catch (error) {
280694
280937
  if (targetReplaced)
280695
- rmSync24(targetApp, { recursive: true, force: true });
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 = join146(appPath, "Contents", "Info.plist");
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 = readFileSync131(plistPath, "utf8");
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 ?? join146("~", "Applications", APP_NAME2)}; open it once and grant Screen Recording permission.`;
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 ?? join146("~", "Applications", APP_NAME2)}\uFF1B\u8BF7\u6253\u5F00\u4E00\u6B21\u5E76\u6388\u4E88\u5C4F\u5E55\u5F55\u5236\u6743\u9650\u3002`;
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 = join147(dir, name);
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 = readFileSync132(p);
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 = join147(rollHome(), ".peer-state");
281179
+ const base = join148(rollHome(), ".peer-state");
280937
281180
  mkdirSync74(base, { recursive: true });
280938
- mkdirSync74(join147(base, "logs"), { recursive: true });
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 = join147(pkg, "skills");
280946
- const hasGit = existsSync131(join147(pkg, ".git"));
280947
- const hasMods = existsSync131(join147(pkg, ".gitmodules"));
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 (!existsSync131(rollPkgConventions())) {
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) => join147(homeDir, d)).join(":");
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(join147(home, ".peer-state"), () => {
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 existsSync132, mkdirSync as mkdirSync75, readFileSync as readFileSync133, rmSync as rmSync25, writeFileSync as writeFileSync74 } from "node:fs";
281155
- import { dirname as dirname72, join as join148, resolve as resolve12 } from "node:path";
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 (!existsSync132(runDir))
281419
+ if (!existsSync133(runDir))
281177
281420
  return null;
281178
281421
  const frame = {
281179
281422
  runDir,
281180
- evidenceDir: join148(runDir, "evidence"),
281181
- screenshotsDir: join148(runDir, "screenshots")
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(join148(frame.evidenceDir, "roll-test-output.log"), [
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(join148(frame.evidenceDir, "roll-test-summary.txt"), JSON.stringify({
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 = join148(process.cwd(), ".roll", "local.yaml");
281233
- if (!existsSync132(file))
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 = readFileSync133(file, "utf8");
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 existsSync132(resetLockPath());
281528
+ return existsSync133(resetLockPath());
281286
281529
  }
281287
281530
  function resetAcquireLock() {
281288
281531
  const lock = resetLockPath();
281289
- if (existsSync132(lock))
281532
+ if (existsSync133(lock))
281290
281533
  return false;
281291
- mkdirSync75(dirname72(lock), { recursive: true });
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
- rmSync25(resetLockPath(), { force: true });
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 = join148(pkg, "skills", "roll-onboard", "SKILL.md");
281316
- if (existsSync132(required2))
281558
+ const required2 = join149(pkg, "skills", "roll-onboard", "SKILL.md");
281559
+ if (existsSync133(required2))
281317
281560
  return true;
281318
- if (existsSync132(join148(pkg, ".git")) && existsSync132(join148(pkg, ".gitmodules"))) {
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 (existsSync132(required2))
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" && !existsSync132(join148(process.cwd(), ".roll", "local.yaml"))) {
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 join149 } from "node:path";
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: join149(projectRoot3, ".roll", "policy.yaml") });
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 readFileSync134, writeFileSync as writeFileSync75, mkdirSync as mkdirSync76, existsSync as existsSync133 } from "node:fs";
281509
- import { dirname as dirname73, join as join150 } from "node:path";
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 readFileSync134(absPath, "utf8");
281784
+ return readFileSync135(absPath, "utf8");
281542
281785
  } catch {
281543
281786
  return "";
281544
281787
  }
281545
281788
  },
281546
281789
  writeText(absPath, text2) {
281547
- mkdirSync76(dirname73(absPath), { recursive: true });
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 = join150(cwd, ".roll", "backlog.md");
281556
- const backlogRows = existsSync133(backlogPath) ? parseBacklog(readFileSync134(backlogPath, "utf8")).map((r) => ({ id: r.id, status: r.status })) : [];
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 existsSync134, readFileSync as readFileSync135 } from "node:fs";
281642
- import { join as join151 } from "node:path";
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 (!existsSync134(path))
281893
+ if (!existsSync135(path))
281651
281894
  return [];
281652
281895
  let text2;
281653
281896
  try {
281654
- text2 = readFileSync135(path, "utf8");
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 = join151(proj, ".roll", "loop");
281786
- const runs = parseJsonl(join151(loopDir2, "runs.jsonl"));
281787
- const events = parseJsonl(join151(loopDir2, "events.ndjson"));
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 existsSync135, mkdtempSync as mkdtempSync11, readFileSync as readFileSync136, rmSync as rmSync26 } from "node:fs";
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 join152 } from "node:path";
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(join152(tmpdir13(), "roll-update-"));
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", join152(tmpDir, "roll.tar.gz")]);
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 = join152(tmpDir, "extract");
282144
+ const extractDir = join153(tmpDir, "extract");
281902
282145
  spawnSync21("mkdir", ["-p", extractDir], { stdio: "ignore" });
281903
282146
  const ex = runForward2("tar", [
281904
282147
  "-xzf",
281905
- join152(tmpDir, "roll.tar.gz"),
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
- rmSync26(tmpDir, { recursive: true, force: true });
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 = join152(pkgRoot, "@seanyao", "roll");
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
- rmSync26(join152(rollHome(), ".update-check"), { force: true });
282179
+ rmSync27(join153(rollHome(), ".update-check"), { force: true });
281937
282180
  }
281938
282181
  function showChangelog() {
281939
- const changelog = join152(rollPkgDir(), "CHANGELOG.md");
281940
- if (!existsSync135(changelog))
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 readFileSync136(changelog, "utf8").split("\n")) {
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 = join152(rollPkgDir(), ".install-method");
281971
- if (existsSync135(methodFile)) {
281972
- installMethod = readFileSync136(methodFile, "utf8").trim() || "npm";
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 readFileSync137 } from "node:fs";
282251
+ import { readFileSync as readFileSync138 } from "node:fs";
282009
282252
  import { homedir as homedir32 } from "node:os";
282010
- import { basename as basename20, dirname as dirname74, join as join153, relative as relative12, resolve as resolve13 } from "node:path";
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 readFileSync137(p, "utf8");
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 = dirname74(resolve13(repoRoot3));
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 = join153(repoRoot3, ".roll", "loop", "inner.lock");
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 = join153(repoRoot3, ".roll", "loop", "heartbeat");
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 = join153(repoRoot3, ".roll", "loop", "events.ndjson");
282455
+ const eventsPath4 = join154(repoRoot3, ".roll", "loop", "events.ndjson");
282213
282456
  const cycles = readCycleContext(eventsPath4, deps);
282214
282457
  const entries = [];
282215
282458
  let current = {};