@seanyao/roll 4.702.2 → 4.702.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/roll.mjs CHANGED
@@ -2240,8 +2240,8 @@ var init_catalog_v3 = __esm({
2240
2240
  // `design.*` — explicit `roll design` entry point (US-ONBOARD-NUDGE-004 / FIX-1055).
2241
2241
  // Thin wrapper that launches the existing $roll-design skill interactively.
2242
2242
  "design.usage": {
2243
- en: 'Usage: roll design [--from-file <path> | "<requirement>"] [--agent <name>] [--verbose|--raw]\n Launch the $roll-design skill in an interactive agent conversation.\n `--from-file` binds a PRD/brief file as the design input.\n `"<requirement>"` binds a free-text design target; it cannot be combined with `--from-file`.\n `--agent` and `ROLL_DESIGN_AGENT` override only this design session; scoped roles live in ~/.roll/agents.yaml and .roll/agents.yaml.\n `--verbose` shows tier-C assistant text; `--raw` dumps the full transcript.\n Unlike `roll init`, this command runs an LLM \u2014 run it only when you want to design.',
2244
- zh: '\u7528\u6CD5\uFF1Aroll design [--from-file <path> | "<requirement>"] [--agent <name>] [--verbose|--raw]\n \u5728\u4EA4\u4E92\u5F0F agent \u5BF9\u8BDD\u4E2D\u542F\u52A8 $roll-design skill\u3002\n `--from-file` \u4F1A\u628A PRD/brief \u6587\u4EF6\u7ED1\u5B9A\u4E3A\u8BBE\u8BA1\u8F93\u5165\u3002\n `"<requirement>"` \u4F1A\u7ED1\u5B9A\u81EA\u7531\u6587\u672C\u8BBE\u8BA1\u76EE\u6807\uFF1B\u4E0D\u80FD\u4E0E `--from-file` \u6DF7\u7528\u3002\n `--agent` \u4E0E `ROLL_DESIGN_AGENT` \u53EA\u8986\u76D6\u672C\u6B21 design session\uFF1Bscoped roles \u4F4D\u4E8E ~/.roll/agents.yaml \u548C .roll/agents.yaml\u3002\n `--verbose` \u663E\u793A tier-C assistant \u6587\u672C\uFF1B`--raw` \u8F93\u51FA\u5B8C\u6574\u539F\u59CB\u8BB0\u5F55\u3002\n \u4E0E `roll init` \u4E0D\u540C\uFF0C\u672C\u547D\u4EE4\u4F1A\u8FD0\u884C LLM\u2014\u2014\u53EA\u5728\u9700\u8981\u8BBE\u8BA1\u65F6\u6267\u884C\u3002'
2243
+ en: 'Usage: roll design [--from-file <path> | "<requirement>"] [--agent <name>] [--verbose|--raw]\n Launch the $roll-design skill in an interactive agent conversation.\n Default output streams bounded live progress, card-created events, quiet heartbeats, and the final handoff while preserving the raw transcript.\n `--from-file` binds a PRD/brief file as the design input.\n `"<requirement>"` binds a free-text design target; it cannot be combined with `--from-file`.\n `--agent` and `ROLL_DESIGN_AGENT` override only this design session; scoped roles live in ~/.roll/agents.yaml and .roll/agents.yaml.\n `--verbose` streams lower-priority normalized activity; `--raw` streams the raw child output live.\n Unlike `roll init`, this command runs an LLM \u2014 run it only when you want to design.',
2244
+ zh: '\u7528\u6CD5\uFF1Aroll design [--from-file <path> | "<requirement>"] [--agent <name>] [--verbose|--raw]\n \u5728\u4EA4\u4E92\u5F0F agent \u5BF9\u8BDD\u4E2D\u542F\u52A8 $roll-design skill\u3002\n \u9ED8\u8BA4\u8F93\u51FA\u4F1A\u5B9E\u65F6\u663E\u793A\u6709\u754C\u8FDB\u5C55\u3001\u5EFA\u5361\u4E8B\u4EF6\u3001\u9759\u9ED8\u5FC3\u8DF3\u548C\u6700\u7EC8\u4EA4\u4ED8\uFF0C\u540C\u65F6\u4FDD\u7559\u5B8C\u6574\u539F\u59CB\u8BB0\u5F55\u3002\n `--from-file` \u4F1A\u628A PRD/brief \u6587\u4EF6\u7ED1\u5B9A\u4E3A\u8BBE\u8BA1\u8F93\u5165\u3002\n `"<requirement>"` \u4F1A\u7ED1\u5B9A\u81EA\u7531\u6587\u672C\u8BBE\u8BA1\u76EE\u6807\uFF1B\u4E0D\u80FD\u4E0E `--from-file` \u6DF7\u7528\u3002\n `--agent` \u4E0E `ROLL_DESIGN_AGENT` \u53EA\u8986\u76D6\u672C\u6B21 design session\uFF1Bscoped roles \u4F4D\u4E8E ~/.roll/agents.yaml \u548C .roll/agents.yaml\u3002\n `--verbose` \u5B9E\u65F6\u663E\u793A\u8F83\u4F4E\u4F18\u5148\u7EA7\u7684\u89C4\u8303\u5316\u6D3B\u52A8\uFF1B`--raw` \u5B9E\u65F6\u8F93\u51FA\u5B50\u8FDB\u7A0B\u539F\u59CB\u6D41\u3002\n \u4E0E `roll init` \u4E0D\u540C\uFF0C\u672C\u547D\u4EE4\u4F1A\u8FD0\u884C LLM\u2014\u2014\u53EA\u5728\u9700\u8981\u8BBE\u8BA1\u65F6\u6267\u884C\u3002'
2245
2245
  },
2246
2246
  "design.not_roll_project": {
2247
2247
  en: "This directory is not a Roll project (no .roll/). Run `roll init` first.",
@@ -12475,6 +12475,12 @@ function signalLabel(ev) {
12475
12475
  return `pair ${clean2(ev.peer)} ${ev.cause}`;
12476
12476
  case "pair:excluded":
12477
12477
  return `pair ${clean2(ev.agent)} excluded ${ev.cause} (${ev.failures})`;
12478
+ case "agent:retry":
12479
+ return `retry ${clean2(ev.fromAgent)} \u2192 ${clean2(ev.toAgent)} (${clean2(ev.reason)})`;
12480
+ case "goal:gate_tripped":
12481
+ return `paused ${clean2(ev.reason)} (${ev.gate})`;
12482
+ case "goal:state":
12483
+ return `goal ${clean2(ev.to)} ${clean2(ev.reason)}`;
12478
12484
  default:
12479
12485
  return void 0;
12480
12486
  }
@@ -12486,6 +12492,20 @@ function summarizeWatchEvents(lines3, durableLookup, nowMs) {
12486
12492
  const summary = { tcrCount: 0, hasEnd: false };
12487
12493
  const events = [];
12488
12494
  let seen = false;
12495
+ const resetCycleScope = (cycleId) => {
12496
+ if (summary.cycleId === cycleId)
12497
+ return;
12498
+ summary.cycleId = cycleId;
12499
+ summary.storyId = void 0;
12500
+ summary.agent = void 0;
12501
+ summary.phase = void 0;
12502
+ summary.tcrCount = 0;
12503
+ summary.outcome = void 0;
12504
+ summary.hasEnd = false;
12505
+ summary.acceptedScore = void 0;
12506
+ summary.attest = void 0;
12507
+ summary.lastPr = void 0;
12508
+ };
12489
12509
  for (const line of lines3) {
12490
12510
  const ev = parseEventLine(line);
12491
12511
  if (ev === null)
@@ -12493,26 +12513,26 @@ function summarizeWatchEvents(lines3, durableLookup, nowMs) {
12493
12513
  events.push(ev);
12494
12514
  seen = true;
12495
12515
  if (ev.type === "cycle:start") {
12496
- summary.cycleId = ev.cycleId;
12516
+ resetCycleScope(ev.cycleId);
12497
12517
  summary.storyId = ev.storyId;
12498
12518
  summary.agent = ev.agent;
12499
- summary.phase = void 0;
12500
- summary.tcrCount = 0;
12501
- summary.outcome = void 0;
12502
- summary.hasEnd = false;
12503
- summary.acceptedScore = void 0;
12504
- summary.attest = void 0;
12505
- summary.lastPr = void 0;
12506
12519
  } else if (ev.type === "cycle:phase") {
12507
- summary.cycleId = ev.cycleId;
12520
+ resetCycleScope(ev.cycleId);
12508
12521
  summary.phase = ev.phase;
12509
12522
  } else if (ev.type === "cycle:tcr") {
12510
- summary.cycleId = ev.cycleId;
12523
+ resetCycleScope(ev.cycleId);
12511
12524
  summary.tcrCount += 1;
12512
- } else if (ev.type === "cycle:end" || ev.type === "cycle:terminal") {
12513
- summary.cycleId = ev.cycleId;
12525
+ } else if (ev.type === "cycle:end") {
12526
+ resetCycleScope(ev.cycleId);
12527
+ summary.outcome = ev.outcome;
12528
+ summary.hasEnd = true;
12529
+ } else if (ev.type === "cycle:terminal") {
12530
+ resetCycleScope(ev.cycleId);
12531
+ summary.storyId = ev.storyId;
12532
+ summary.agent = ev.agent;
12514
12533
  summary.outcome = ev.outcome;
12515
12534
  summary.hasEnd = true;
12535
+ summary.tcrCount = ev.tcr.present ? ev.tcr.value : 0;
12516
12536
  }
12517
12537
  if (ev.type === "pair:score") {
12518
12538
  summary.acceptedScore = { peer: ev.peer, score: ev.score, verdict: ev.verdict };
@@ -12584,7 +12604,7 @@ function renderWatchStatusSummary(summary, nowMs) {
12584
12604
  const story = summary.storyId !== void 0 && summary.storyId !== "" ? summary.storyId : "story unknown";
12585
12605
  const agent = summary.agent !== void 0 && summary.agent !== "" ? summary.agent : "agent unknown";
12586
12606
  const phase = summary.phase !== void 0 ? `phase ${summary.phase}` : "phase unknown";
12587
- const classification = summary.classification !== void 0 ? summary.classification : "active";
12607
+ const classification = summary.classification !== void 0 ? summary.classification : summary.hasEnd ? "ended" : "active";
12588
12608
  const tcr = `${summary.tcrCount} TCR`;
12589
12609
  const parts = [`status ${phase}`, classification, quietText(summary, nowMs), story, agent, cycle];
12590
12610
  if (summary.microStep !== void 0) {
@@ -12656,11 +12676,18 @@ function previousTransitionLine(previous) {
12656
12676
  return ` previous: ${parts.join(" \xB7 ")}`;
12657
12677
  }
12658
12678
  function nextTransitionLine(current, ctx) {
12679
+ if (current.storyId === void 0 || current.storyId === "") {
12680
+ const outcome = current.hasEnd ? current.outcome ?? "unknown" : "no active story";
12681
+ return ` next: no runnable work \xB7 ${outcome}`;
12682
+ }
12659
12683
  const story = current.storyId !== void 0 && current.storyId !== "" ? current.storyId : "story unknown";
12660
12684
  const brief = current.storyId !== void 0 && current.storyId !== "" ? ctx?.storyBrief?.(current.storyId) ?? "brief unavailable" : "brief unavailable";
12661
12685
  return ` next: ${story} \xB7 ${brief}`;
12662
12686
  }
12663
12687
  function builderTransitionLine(current, ctx) {
12688
+ if (current.storyId === void 0 || current.storyId === "") {
12689
+ return " builder: none \xB7 no story/agent selected";
12690
+ }
12664
12691
  const route = current.storyId !== void 0 && current.storyId !== "" ? ctx?.routeReason?.(current.storyId) : void 0;
12665
12692
  if (route !== void 0) {
12666
12693
  return ` builder: ${route.agent} \xB7 selected by ${route.reason}`;
@@ -18793,16 +18820,16 @@ async function crontabRead() {
18793
18820
  }
18794
18821
  }
18795
18822
  async function crontabWrite(text2) {
18796
- return new Promise((resolve11, reject) => {
18823
+ return new Promise((resolve12, reject) => {
18797
18824
  const child = execFile4("crontab", ["-"], (err16) => {
18798
18825
  if (err16 === null) {
18799
- resolve11(0);
18826
+ resolve12(0);
18800
18827
  } else if (typeof err16.code === "number") {
18801
- resolve11(err16.code);
18828
+ resolve12(err16.code);
18802
18829
  } else if (err16.code === "ENOENT") {
18803
18830
  reject(err16);
18804
18831
  } else {
18805
- resolve11(1);
18832
+ resolve12(1);
18806
18833
  }
18807
18834
  });
18808
18835
  child.stdin?.end(text2);
@@ -20846,14 +20873,14 @@ var init_mcp = __esm({
20846
20873
  child.on("exit", () => this.rejectAll(new Error("MCP server exited")));
20847
20874
  }
20848
20875
  static async open(child) {
20849
- await new Promise((resolve11, reject) => {
20876
+ await new Promise((resolve12, reject) => {
20850
20877
  const onError = (cause) => {
20851
20878
  child.off("spawn", onSpawn);
20852
20879
  reject(cause);
20853
20880
  };
20854
20881
  const onSpawn = () => {
20855
20882
  child.off("error", onError);
20856
- resolve11();
20883
+ resolve12();
20857
20884
  };
20858
20885
  child.once("error", onError);
20859
20886
  child.once("spawn", onSpawn);
@@ -20882,8 +20909,8 @@ var init_mcp = __esm({
20882
20909
  const id = this.nextId;
20883
20910
  this.nextId += 1;
20884
20911
  const message = { jsonrpc: "2.0", id, method, params };
20885
- return new Promise((resolve11, reject) => {
20886
- this.pending.set(id, { resolve: resolve11, reject });
20912
+ return new Promise((resolve12, reject) => {
20913
+ this.pending.set(id, { resolve: resolve12, reject });
20887
20914
  this.write(message);
20888
20915
  });
20889
20916
  }
@@ -20978,7 +21005,7 @@ async function requestWithRedirects(url, input, deps, timeoutMs, redirects, star
20978
21005
  return response;
20979
21006
  }
20980
21007
  function requestOnce(url, input, deps, timeoutMs, startedAt) {
20981
- return new Promise((resolve11, reject) => {
21008
+ return new Promise((resolve12, reject) => {
20982
21009
  const proxy = proxyFor(url);
20983
21010
  const viaProxy = proxy !== void 0;
20984
21011
  const requestUrl = viaProxy ? proxy : url;
@@ -21000,7 +21027,7 @@ function requestOnce(url, input, deps, timeoutMs, startedAt) {
21000
21027
  });
21001
21028
  res.on("end", () => {
21002
21029
  clearTimeout(timer);
21003
- resolve11({
21030
+ resolve12({
21004
21031
  statusCode: res.statusCode ?? 0,
21005
21032
  headers: normalizeHeaders(res.headers),
21006
21033
  body: deps.redact(Buffer.concat(chunks).toString("utf8")),
@@ -21054,7 +21081,7 @@ function isTimeout(cause) {
21054
21081
  function delay(ms) {
21055
21082
  if (ms <= 0)
21056
21083
  return Promise.resolve();
21057
- return new Promise((resolve11) => setTimeout(resolve11, ms));
21084
+ return new Promise((resolve12) => setTimeout(resolve12, ms));
21058
21085
  }
21059
21086
  function failure5(invocation, startedAt, endedAt, code, message, retryable, detail, attempt) {
21060
21087
  return {
@@ -145685,7 +145712,7 @@ ${lanes.join("\n")}
145685
145712
  }
145686
145713
  }
145687
145714
  function createImportCallExpressionAMD(arg, containsLexicalThis) {
145688
- const resolve11 = factory2.createUniqueName("resolve");
145715
+ const resolve12 = factory2.createUniqueName("resolve");
145689
145716
  const reject = factory2.createUniqueName("reject");
145690
145717
  const parameters = [
145691
145718
  factory2.createParameterDeclaration(
@@ -145694,7 +145721,7 @@ ${lanes.join("\n")}
145694
145721
  /*dotDotDotToken*/
145695
145722
  void 0,
145696
145723
  /*name*/
145697
- resolve11
145724
+ resolve12
145698
145725
  ),
145699
145726
  factory2.createParameterDeclaration(
145700
145727
  /*modifiers*/
@@ -145711,7 +145738,7 @@ ${lanes.join("\n")}
145711
145738
  factory2.createIdentifier("require"),
145712
145739
  /*typeArguments*/
145713
145740
  void 0,
145714
- [factory2.createArrayLiteralExpression([arg || factory2.createOmittedExpression()]), resolve11, reject]
145741
+ [factory2.createArrayLiteralExpression([arg || factory2.createOmittedExpression()]), resolve12, reject]
145715
145742
  )
145716
145743
  )
145717
145744
  ]);
@@ -232642,8 +232669,8 @@ Additional information: BADCLIENT: Bad error code, ${badCode} not found in range
232642
232669
  installPackage(options) {
232643
232670
  this.packageInstallId++;
232644
232671
  const request = { kind: "installPackage", ...options, id: this.packageInstallId };
232645
- const promise = new Promise((resolve11, reject) => {
232646
- (this.packageInstalledPromise ?? (this.packageInstalledPromise = /* @__PURE__ */ new Map())).set(this.packageInstallId, { resolve: resolve11, reject });
232672
+ const promise = new Promise((resolve12, reject) => {
232673
+ (this.packageInstalledPromise ?? (this.packageInstalledPromise = /* @__PURE__ */ new Map())).set(this.packageInstallId, { resolve: resolve12, reject });
232647
232674
  });
232648
232675
  this.installer.send(request);
232649
232676
  return promise;
@@ -232936,10 +232963,10 @@ __export(structure_scan_exports, {
232936
232963
  });
232937
232964
  import { createHash as createHash5 } from "node:crypto";
232938
232965
  import { existsSync as existsSync63, readFileSync as readFileSync59 } from "node:fs";
232939
- import { basename as basename13, dirname as dirname32, extname, join as join65, relative as relative5, resolve as resolve6, sep as sep4 } from "node:path";
232966
+ import { basename as basename13, dirname as dirname32, extname, join as join65, relative as relative5, resolve as resolve7, sep as sep4 } from "node:path";
232940
232967
  function buildStaticProjectGraph(input) {
232941
- const root = resolve6(input.root);
232942
- const tsconfigPaths = input.tsconfigPath ? [resolve6(root, input.tsconfigPath)] : findTsconfigs(root);
232968
+ const root = resolve7(input.root);
232969
+ const tsconfigPaths = input.tsconfigPath ? [resolve7(root, input.tsconfigPath)] : findTsconfigs(root);
232943
232970
  if (tsconfigPaths.length === 0) {
232944
232971
  return emptyGraph(root, "No tsconfig.json found for Dream structure scan");
232945
232972
  }
@@ -233086,7 +233113,7 @@ function createLanguageServiceHost(fileNames, options) {
233086
233113
  };
233087
233114
  }
233088
233115
  function normalizePath(root, path) {
233089
- return relative5(root, resolve6(path)).split(sep4).join("/");
233116
+ return relative5(root, resolve7(path)).split(sep4).join("/");
233090
233117
  }
233091
233118
  function isExcluded(root, path) {
233092
233119
  const rel = normalizePath(root, path);
@@ -233200,7 +233227,7 @@ function importEdges(root, sourceFile) {
233200
233227
  function resolveModulePath(root, containingFile, specifier) {
233201
233228
  if (!specifier.startsWith("."))
233202
233229
  return void 0;
233203
- const base = resolve6(dirname32(containingFile), specifier);
233230
+ const base = resolve7(dirname32(containingFile), specifier);
233204
233231
  for (const suffix of [".ts", ".tsx", ".mts", ".cts", "/index.ts"]) {
233205
233232
  const candidate = `${base}${suffix}`;
233206
233233
  if (existsSync63(candidate))
@@ -233623,7 +233650,7 @@ __export(showcase_exports, {
233623
233650
  resetSandbox: () => resetSandbox,
233624
233651
  showcaseCommand: () => showcaseCommand
233625
233652
  });
233626
- import { spawnSync as spawnSync16 } from "node:child_process";
233653
+ import { spawnSync as spawnSync15 } from "node:child_process";
233627
233654
  import { cpSync as cpSync2, existsSync as existsSync105, mkdirSync as mkdirSync51, mkdtempSync as mkdtempSync8, readdirSync as readdirSync41, readFileSync as readFileSync99, rmSync as rmSync18, statSync as statSync35, writeFileSync as writeFileSync54 } from "node:fs";
233628
233655
  import { tmpdir as tmpdir10 } from "node:os";
233629
233656
  import { dirname as dirname49, join as join109 } from "node:path";
@@ -233695,7 +233722,7 @@ function runRoll(sandbox, rollHome4, args, opts = {}) {
233695
233722
  }
233696
233723
  const bin = rollBin3();
233697
233724
  const [cmd, cmdArgs] = bin === "roll" ? [bin, args] : [process.execPath, [bin, ...args]];
233698
- const r = spawnSync16(cmd, cmdArgs, {
233725
+ const r = spawnSync15(cmd, cmdArgs, {
233699
233726
  cwd: sandbox,
233700
233727
  env,
233701
233728
  encoding: "utf8",
@@ -234138,7 +234165,7 @@ function networkNeeds(command, args) {
234138
234165
  }
234139
234166
  }
234140
234167
  function tcpConnect(host, port, timeoutMs) {
234141
- return new Promise((resolve11, reject) => {
234168
+ return new Promise((resolve12, reject) => {
234142
234169
  const socket = createConnection({ host, port });
234143
234170
  let settled = false;
234144
234171
  const done = (err16) => {
@@ -234150,7 +234177,7 @@ function tcpConnect(host, port, timeoutMs) {
234150
234177
  if (err16)
234151
234178
  reject(err16);
234152
234179
  else
234153
- resolve11();
234180
+ resolve12();
234154
234181
  };
234155
234182
  socket.setTimeout(timeoutMs, () => done(new Error("tcp timeout")));
234156
234183
  socket.once("connect", () => done());
@@ -234162,11 +234189,11 @@ async function networkReachable(probes = {}) {
234162
234189
  host: PROBE_HOST,
234163
234190
  port: PROBE_PORT
234164
234191
  };
234165
- const resolve11 = probes.resolve ?? ((h) => lookup(h));
234192
+ const resolve12 = probes.resolve ?? ((h) => lookup(h));
234166
234193
  const tcpProbe2 = probes.tcpProbe ?? (() => tcpConnect(target.host, target.port, TCP_TIMEOUT_MS));
234167
234194
  try {
234168
234195
  await Promise.race([
234169
- resolve11(target.host),
234196
+ resolve12(target.host),
234170
234197
  new Promise((_, rej) => {
234171
234198
  const timer = setTimeout(() => rej(new Error("dns timeout")), DNS_TIMEOUT_MS);
234172
234199
  if (typeof timer === "object")
@@ -234473,7 +234500,7 @@ init_dist2();
234473
234500
  import { spawn as spawn2 } from "node:child_process";
234474
234501
  import { existsSync as existsSync15, readFileSync as readFileSync12, realpathSync as realpathSync2, unlinkSync, writeFileSync as writeFileSync6 } from "node:fs";
234475
234502
  import { homedir as homedir4 } from "node:os";
234476
- import { join as join18 } from "node:path";
234503
+ import { join as join18, resolve as resolve5 } from "node:path";
234477
234504
  var liveAgents = /* @__PURE__ */ new Set();
234478
234505
  function killLiveAgents(signal = "SIGKILL") {
234479
234506
  let n = 0;
@@ -234799,12 +234826,28 @@ function evidenceFrameEnv(runDir) {
234799
234826
  };
234800
234827
  }
234801
234828
  var INHERITED_GIT_ENV_KEYS = ["GIT_DIR", "GIT_WORK_TREE", "GIT_COMMON_DIR", "GIT_INDEX_FILE"];
234829
+ function worktreeGitEnv(cwd) {
234830
+ const gitPath = join18(cwd, ".git");
234831
+ if (!existsSync15(gitPath))
234832
+ return {};
234833
+ try {
234834
+ const text2 = readFileSync12(gitPath, "utf8");
234835
+ const match = /^gitdir:\s*(.+)\s*$/m.exec(text2);
234836
+ if (match?.[1] !== void 0 && match[1].trim() !== "") {
234837
+ return { GIT_DIR: resolve5(cwd, match[1].trim()), GIT_WORK_TREE: cwd };
234838
+ }
234839
+ } catch {
234840
+ return { GIT_DIR: gitPath, GIT_WORK_TREE: cwd };
234841
+ }
234842
+ return {};
234843
+ }
234802
234844
  function childEnv(opts) {
234803
234845
  const env = { ...opts.env ?? process.env };
234804
234846
  for (const key of INHERITED_GIT_ENV_KEYS)
234805
234847
  delete env[key];
234806
234848
  env.PWD = opts.cwd;
234807
234849
  delete env.OLDPWD;
234850
+ Object.assign(env, worktreeGitEnv(opts.cwd));
234808
234851
  return opts.runDir !== void 0 && opts.runDir !== "" ? { ...env, ...evidenceFrameEnv(opts.runDir) } : env;
234809
234852
  }
234810
234853
  function withAgentProfileEnv(agent, opts) {
@@ -234820,7 +234863,7 @@ function withAgentProfileEnv(agent, opts) {
234820
234863
  function spawnAndWait(bin, args, opts, pty = false) {
234821
234864
  process.stderr.write(`[runner] spawn ${bin} argv=${JSON.stringify(args.map((a) => a.length > 80 ? `${a.slice(0, 77)}...` : a))}
234822
234865
  `);
234823
- return new Promise((resolve11) => {
234866
+ return new Promise((resolve12) => {
234824
234867
  const child = spawn2(bin, args, {
234825
234868
  cwd: opts.cwd,
234826
234869
  env: childEnv(opts),
@@ -234863,7 +234906,7 @@ function spawnAndWait(bin, args, opts, pty = false) {
234863
234906
  opts.cleanup?.();
234864
234907
  } catch {
234865
234908
  }
234866
- resolve11(result);
234909
+ resolve12(result);
234867
234910
  };
234868
234911
  child.on("error", (e) => {
234869
234912
  settle({ stdout, stderr: `${stderr}${String(e)}
@@ -234890,13 +234933,13 @@ function realDeps() {
234890
234933
  sharedRoot: () => process.env["ROLL_SHARED_ROOT"] || join19(homedir5(), ".shared", "roll"),
234891
234934
  launchdDir: () => join19(homedir5(), "Library", "LaunchAgents"),
234892
234935
  scheduler: createScheduler(process.platform, { uid: process.getuid?.() ?? 501 }),
234893
- execRunner: (runner) => new Promise((resolve11) => {
234936
+ execRunner: (runner) => new Promise((resolve12) => {
234894
234937
  const child = spawn3("bash", [runner], {
234895
234938
  stdio: "inherit",
234896
234939
  env: { ...process.env, ROLL_LOOP_FORCE: "1" }
234897
234940
  });
234898
- child.on("exit", (code) => resolve11(code ?? 1));
234899
- child.on("error", () => resolve11(1));
234941
+ child.on("exit", (code) => resolve12(code ?? 1));
234942
+ child.on("error", () => resolve12(1));
234900
234943
  }),
234901
234944
  hasTmux: () => {
234902
234945
  try {
@@ -234907,7 +234950,7 @@ function realDeps() {
234907
234950
  },
234908
234951
  // The `loop now` inline observation: tail live.log while the cycle holds
234909
234952
  // the inner lock; Ctrl-C stops the TAIL only (the cycle lives in tmux).
234910
- observe: (rt) => new Promise((resolve11) => {
234953
+ observe: (rt) => new Promise((resolve12) => {
234911
234954
  const lock = join19(rt, "inner.lock");
234912
234955
  const tail3 = spawn3("tail", ["-n", "+1", "-F", join19(rt, "live.log")], { stdio: "inherit" });
234913
234956
  let sawLock = false;
@@ -234918,7 +234961,7 @@ function realDeps() {
234918
234961
  } catch {
234919
234962
  }
234920
234963
  process.removeListener("SIGINT", finish);
234921
- resolve11();
234964
+ resolve12();
234922
234965
  };
234923
234966
  const timer = setInterval(() => {
234924
234967
  if (existsSync16(lock))
@@ -249779,13 +249822,13 @@ function followSupervisorCollabStream(projectPath3, noColor2) {
249779
249822
  const tickLimit = envOptionalPositiveInt("ROLL_SUPERVISOR_COLLAB_WATCH_TICKS");
249780
249823
  let renderedCycles = 0;
249781
249824
  let ticks = 0;
249782
- return new Promise((resolve11) => {
249825
+ return new Promise((resolve12) => {
249783
249826
  let timer;
249784
249827
  const stop = (code) => {
249785
249828
  if (timer !== void 0)
249786
249829
  clearInterval(timer);
249787
249830
  process.removeListener("SIGINT", onSigint);
249788
- resolve11(code);
249831
+ resolve12(code);
249789
249832
  };
249790
249833
  const onSigint = () => stop(130);
249791
249834
  const tick = () => {
@@ -249876,7 +249919,7 @@ function unknownSupervisorLiveFlag(args) {
249876
249919
  function followSupervisorLiveBoard(projectPath3, intervalMs) {
249877
249920
  const tickLimit = envOptionalPositiveInt("ROLL_SUPERVISOR_LIVE_WATCH_TICKS");
249878
249921
  let ticks = 0;
249879
- return new Promise((resolve11) => {
249922
+ return new Promise((resolve12) => {
249880
249923
  let timer;
249881
249924
  let stopped = false;
249882
249925
  const stop = (code) => {
@@ -249887,7 +249930,7 @@ function followSupervisorLiveBoard(projectPath3, intervalMs) {
249887
249930
  clearInterval(timer);
249888
249931
  process.removeListener("SIGINT", onSigint);
249889
249932
  process.stdout.write("\x1B[?25h");
249890
- resolve11(code);
249933
+ resolve12(code);
249891
249934
  };
249892
249935
  const onSigint = () => stop(130);
249893
249936
  const tick = () => {
@@ -251053,7 +251096,7 @@ function spawnPeerReviewAgent(input) {
251053
251096
  const cmd = textAgentArgv(input.agent, input.prompt);
251054
251097
  if (cmd === null)
251055
251098
  return Promise.resolve({ status: "error", reason: "unsupported_reviewer", stdout: "" });
251056
- return new Promise((resolve11) => {
251099
+ return new Promise((resolve12) => {
251057
251100
  let stdout = "";
251058
251101
  let stderr = "";
251059
251102
  let timedOut = false;
@@ -251071,7 +251114,7 @@ function spawnPeerReviewAgent(input) {
251071
251114
  settled = true;
251072
251115
  if (timer !== void 0)
251073
251116
  clearTimeout(timer);
251074
- resolve11(result);
251117
+ resolve12(result);
251075
251118
  };
251076
251119
  timer = setTimeout(() => {
251077
251120
  timedOut = true;
@@ -251681,7 +251724,7 @@ function realDeps5() {
251681
251724
  startTmux: startGoTmux,
251682
251725
  followFeed: followGoLiveFeed,
251683
251726
  runOnce: realRunOnce,
251684
- sleep: (ms) => new Promise((resolve11) => setTimeout(resolve11, ms)),
251727
+ sleep: (ms) => new Promise((resolve12) => setTimeout(resolve12, ms)),
251685
251728
  externalTools: guideExternalToolSetup,
251686
251729
  preinstallChromium: () => {
251687
251730
  silentPreinstallChromium();
@@ -251726,6 +251769,59 @@ function eventsPath(projectPath3) {
251726
251769
  function runsPath2(projectPath3) {
251727
251770
  return join55(runtimeDir5(projectPath3), "runs.jsonl");
251728
251771
  }
251772
+ function parsePorcelainPath(line) {
251773
+ const raw = line.length > 3 ? line.slice(3).trim() : line.trim();
251774
+ const target = raw.includes(" -> ") ? raw.split(" -> ").at(-1) ?? raw : raw;
251775
+ return target.replace(/^"|"$/g, "").replace(/\/$/, "");
251776
+ }
251777
+ function gitDirtyPaths(projectPath3) {
251778
+ const result = spawnSync8("git", ["status", "--porcelain", "--untracked-files=all"], {
251779
+ cwd: projectPath3,
251780
+ encoding: "utf8",
251781
+ stdio: ["ignore", "pipe", "ignore"]
251782
+ });
251783
+ if (result.status !== 0)
251784
+ return [];
251785
+ return String(result.stdout ?? "").split("\n").map((line) => line.trimEnd()).filter((line) => line.trim() !== "").map(parsePorcelainPath).filter((path) => path !== ".roll/loop" && !path.startsWith(".roll/loop/")).slice(0, 50);
251786
+ }
251787
+ function isBootstrapArtifactPath(path) {
251788
+ if (path === "AGENTS.md" || path === "CLAUDE.md" || path === ".cursor-rules" || path === "project_rules.md")
251789
+ return true;
251790
+ if (path === ".roll" || path.startsWith(".roll/"))
251791
+ return true;
251792
+ if (path === ".claude" || path.startsWith(".claude/"))
251793
+ return true;
251794
+ return false;
251795
+ }
251796
+ function classifyBootstrapArtifacts(paths) {
251797
+ const files = paths.filter((path) => path.trim() !== "");
251798
+ if (files.length === 0)
251799
+ return { kind: "none", files: [] };
251800
+ return files.every(isBootstrapArtifactPath) ? { kind: "bootstrap_only", files } : { kind: "mixed", files };
251801
+ }
251802
+ function bootstrapArtifactsMessage(files) {
251803
+ const shown = files.slice(0, 12).join(", ");
251804
+ const more = files.length > 12 ? `, ... +${files.length - 12} more` : "";
251805
+ return [
251806
+ "roll loop go: bootstrap_artifacts_unconfirmed",
251807
+ ` files: ${shown}${more}`,
251808
+ " These files define project conventions/backlog metadata. Confirm their ownership before running builders:",
251809
+ " - commit them to the product repo if they are product truth",
251810
+ " - commit private Roll metadata inside .roll/roll-meta when applicable",
251811
+ " - ignore/externalize them by project policy",
251812
+ " - or clean them up and re-run init/design",
251813
+ " Then rerun: roll loop go",
251814
+ "",
251815
+ "roll loop go: bootstrap_artifacts_unconfirmed",
251816
+ " \u8FD9\u4E9B\u6587\u4EF6\u5B9A\u4E49\u9879\u76EE\u7EA6\u5B9A/backlog \u5143\u6570\u636E\u3002\u5148\u786E\u8BA4\u5F52\u5C5E\uFF0C\u518D\u542F\u52A8 builder\uFF1A",
251817
+ " - \u5C5E\u4E8E\u4EA7\u54C1\u4E8B\u5B9E\u5C31\u63D0\u4EA4\u5230\u4EA7\u54C1\u4ED3",
251818
+ " - \u5C5E\u4E8E\u79C1\u6709 Roll \u5143\u6570\u636E\u5C31\u63D0\u4EA4\u5230 .roll/roll-meta",
251819
+ " - \u6309\u9879\u76EE\u7EA6\u5B9A ignore/\u5916\u7F6E",
251820
+ " - \u6216\u6E05\u7406\u540E\u91CD\u8DD1 init/design",
251821
+ " \u7136\u540E\u518D\u8FD0\u884C\uFF1Aroll loop go",
251822
+ ""
251823
+ ].join("\n");
251824
+ }
251729
251825
  function parseOptions(args) {
251730
251826
  let scope = { kind: "all" };
251731
251827
  let maxCycles;
@@ -251958,7 +252054,7 @@ function startGoTmux(input) {
251958
252054
  }
251959
252055
  }
251960
252056
  function followGoLiveFeed(projectPath3, rollBin4) {
251961
- return new Promise((resolve11) => {
252057
+ return new Promise((resolve12) => {
251962
252058
  const cmd = rollBin4.endsWith(".js") || rollBin4.endsWith(".mjs") ? process.execPath : rollBin4;
251963
252059
  const args = rollBin4.endsWith(".js") || rollBin4.endsWith(".mjs") ? [rollBin4, "loop", "watch", "--since", "all"] : ["loop", "watch", "--since", "all"];
251964
252060
  const watch = spawn7(cmd, args, { cwd: projectPath3, stdio: ["ignore", "inherit", "inherit"] });
@@ -251968,7 +252064,7 @@ function followGoLiveFeed(projectPath3, rollBin4) {
251968
252064
  } catch {
251969
252065
  }
251970
252066
  process.removeListener("SIGINT", finish);
251971
- resolve11();
252067
+ resolve12();
251972
252068
  };
251973
252069
  process.on("SIGINT", finish);
251974
252070
  watch.on("exit", finish);
@@ -251979,7 +252075,7 @@ function realRunOnce(input) {
251979
252075
  const bin = rollBin();
251980
252076
  const cmd = bin.endsWith(".js") || bin.endsWith(".mjs") ? process.execPath : bin;
251981
252077
  const args = cmd === process.execPath ? [bin, "loop", "run-once"] : ["loop", "run-once"];
251982
- return new Promise((resolve11) => {
252078
+ return new Promise((resolve12) => {
251983
252079
  const child = spawn7(cmd, args, {
251984
252080
  cwd: input.projectPath,
251985
252081
  detached: true,
@@ -251993,8 +252089,8 @@ function realRunOnce(input) {
251993
252089
  },
251994
252090
  stdio: "inherit"
251995
252091
  });
251996
- child.on("exit", (code) => resolve11(code ?? 1));
251997
- child.on("error", () => resolve11(1));
252092
+ child.on("exit", (code) => resolve12(code ?? 1));
252093
+ child.on("error", () => resolve12(1));
251998
252094
  });
251999
252095
  }
252000
252096
  function writeGoal(path, goal) {
@@ -252822,6 +252918,14 @@ async function runGoWorker(id, opts, deps) {
252822
252918
  stopReason2 = preProgressGate.reason;
252823
252919
  break;
252824
252920
  }
252921
+ const bootstrap = classifyBootstrapArtifacts(gitDirtyPaths(id.path));
252922
+ if (bootstrap.kind === "bootstrap_only") {
252923
+ stopReason2 = "bootstrap_artifacts_unconfirmed";
252924
+ appendGoalGate(bus, evPath, sid, "progress", "paused", stopReason2, { files: bootstrap.files.join(", "), count: bootstrap.files.length }, deps.nowSec());
252925
+ process.stdout.write(bootstrapArtifactsMessage(bootstrap.files));
252926
+ goal = pauseGoal(id.path, bus, stopReason2, deps.nowIso(), deps.nowSec()) ?? goal;
252927
+ break;
252928
+ }
252825
252929
  const allowedCards = allowedCardsForScope(id.path, goal, progress);
252826
252930
  if (allScopeCardsSkipped(id.path, goal, progress)) {
252827
252931
  stopReason2 = "no_progress_on_all_cards";
@@ -253975,7 +254079,7 @@ function renderDesignNudge(lang10) {
253975
254079
  init_dist2();
253976
254080
  init_dist();
253977
254081
  import { existsSync as existsSync59, readdirSync as readdirSync24, readFileSync as readFileSync56, statSync as statSync22 } from "node:fs";
253978
- import { relative as relative4, resolve as resolve5 } from "node:path";
254082
+ import { relative as relative4, resolve as resolve6 } from "node:path";
253979
254083
  var IGNORE_DIRS = /* @__PURE__ */ new Set([
253980
254084
  ".git",
253981
254085
  "node_modules",
@@ -253997,23 +254101,23 @@ function walkMarkdownFiles(dir, out3, includeGenerated) {
253997
254101
  continue;
253998
254102
  if (!includeGenerated && (entry.name === ".roll" || entry.name === "archive"))
253999
254103
  continue;
254000
- walkMarkdownFiles(resolve5(dir, entry.name), out3, includeGenerated);
254104
+ walkMarkdownFiles(resolve6(dir, entry.name), out3, includeGenerated);
254001
254105
  } else if (entry.isFile() && isMarkdownFile(entry.name)) {
254002
- out3.push(resolve5(dir, entry.name));
254106
+ out3.push(resolve6(dir, entry.name));
254003
254107
  }
254004
254108
  }
254005
254109
  }
254006
254110
  function defaultScanRoots(root, includeGenerated) {
254007
254111
  const roots = [];
254008
254112
  for (const rel of ["AGENTS.md", "roll.md", "conventions", "skills", "guide"]) {
254009
- const abs = resolve5(root, rel);
254113
+ const abs = resolve6(root, rel);
254010
254114
  if (!existsSync59(abs))
254011
254115
  continue;
254012
254116
  roots.push(abs);
254013
254117
  }
254014
254118
  if (includeGenerated) {
254015
254119
  for (const rel of [".roll", "archive"]) {
254016
- const abs = resolve5(root, rel);
254120
+ const abs = resolve6(root, rel);
254017
254121
  if (existsSync59(abs))
254018
254122
  roots.push(abs);
254019
254123
  }
@@ -256854,7 +256958,7 @@ function renderAiClients(out3, clients) {
256854
256958
  }
256855
256959
  out3.push(" " + pad(nameCol, 14) + pad(c("dim", cl.cfg_file), 14) + pad(syncCol, 14) + c("dim", String(cl.skills)));
256856
256960
  if (cl.sync === "out-of-sync" || cl.sync === "missing") {
256857
- out3.push(" " + c("dim", "fix: ") + c("blue", `roll setup -f ${cl.name}`));
256961
+ out3.push(" " + c("dim", "fix: ") + c("blue", "roll setup -f"));
256858
256962
  }
256859
256963
  }
256860
256964
  out3.push("", hr(), "");
@@ -257180,7 +257284,7 @@ function collectAgentPanel(projectPath3, deps = defaultAgentPanelDeps()) {
257180
257284
  costUsd72h: Number(s.cost.toFixed(4)),
257181
257285
  files,
257182
257286
  syncStale: isInstalled && stale,
257183
- ...isInstalled && stale ? { setupCmd: `roll setup -f ${name}` } : {}
257287
+ ...isInstalled && stale ? { setupCmd: "roll setup -f" } : {}
257184
257288
  });
257185
257289
  }
257186
257290
  rows.sort((a, b) => Number(b.installed) - Number(a.installed) || b.cycles72h - a.cycles72h || a.name.localeCompare(b.name));
@@ -258049,7 +258153,7 @@ function collectLoopHeartbeat(deps) {
258049
258153
  // packages/cli/dist/lib/git-hooks.js
258050
258154
  import { execFileSync as execFileSync20 } from "node:child_process";
258051
258155
  import { readdirSync as readdirSync29 } from "node:fs";
258052
- import { isAbsolute, join as join77, resolve as resolve7 } from "node:path";
258156
+ import { isAbsolute, join as join77, resolve as resolve8 } from "node:path";
258053
258157
  var HOOK_DESCRIPTIONS = {
258054
258158
  "pre-commit": {
258055
258159
  en: "TCR proof gate before commit",
@@ -258111,11 +258215,11 @@ function resolveHooksPath(projectPath3) {
258111
258215
  if (configured !== "" && configured !== ".git/hooks") {
258112
258216
  return {
258113
258217
  displayPath: configured,
258114
- fsPath: isAbsolute(configured) ? configured : resolve7(projectPath3, configured)
258218
+ fsPath: isAbsolute(configured) ? configured : resolve8(projectPath3, configured)
258115
258219
  };
258116
258220
  }
258117
258221
  const gitPath = gitOutput3(projectPath3, ["rev-parse", "--git-path", "hooks"]);
258118
- const fsPath = gitPath === "" ? join77(projectPath3, ".git", "hooks") : isAbsolute(gitPath) ? gitPath : resolve7(projectPath3, gitPath);
258222
+ const fsPath = gitPath === "" ? join77(projectPath3, ".git", "hooks") : isAbsolute(gitPath) ? gitPath : resolve8(projectPath3, gitPath);
258119
258223
  return {
258120
258224
  displayPath: configured === "" ? ".git/hooks" : configured,
258121
258225
  fsPath
@@ -260053,6 +260157,91 @@ function registerProject(projectDir) {
260053
260157
  } catch {
260054
260158
  }
260055
260159
  }
260160
+ var ROLL_OWNED_GIT_PATHS = [
260161
+ "AGENTS.md",
260162
+ ".claude/CLAUDE.md",
260163
+ ".roll/.version",
260164
+ ".roll/agents.yaml",
260165
+ ".roll/backlog.md",
260166
+ ".roll/brief.md",
260167
+ ".roll/briefs",
260168
+ ".roll/domain",
260169
+ ".roll/domain/context-map.md",
260170
+ ".roll/features",
260171
+ ".roll/features.md",
260172
+ ".roll/init-diagnosis.yaml",
260173
+ ".roll/onboard-changeset.yaml",
260174
+ ".roll/onboard-plan.yaml",
260175
+ ".roll/tech-analysis.md",
260176
+ ".roll/test-assessment.md",
260177
+ ".gitignore"
260178
+ ];
260179
+ function runGit(projectDir, args) {
260180
+ const result = spawnSync11("git", args, {
260181
+ cwd: projectDir,
260182
+ encoding: "utf8",
260183
+ stdio: ["ignore", "pipe", "pipe"]
260184
+ });
260185
+ return {
260186
+ ok: result.status === 0,
260187
+ stdout: String(result.stdout ?? ""),
260188
+ stderr: String(result.stderr ?? "")
260189
+ };
260190
+ }
260191
+ function existingRollOwnedPaths(projectDir) {
260192
+ return ROLL_OWNED_GIT_PATHS.filter((rel) => existsSync83(join86(projectDir, rel.replace(/\/$/, ""))));
260193
+ }
260194
+ function printGitFinalizeManual(reason, command) {
260195
+ warn4(`Roll meta git finalize needs manual follow-up: ${reason}`);
260196
+ process.stderr.write(` ${command}
260197
+ `);
260198
+ }
260199
+ function finalizeRollOwnedGit(projectDir) {
260200
+ if (!runGit(projectDir, ["rev-parse", "--is-inside-work-tree"]).ok)
260201
+ return;
260202
+ const topLevel = runGit(projectDir, ["rev-parse", "--show-toplevel"]);
260203
+ if (!topLevel.ok)
260204
+ return;
260205
+ if (realpathSync11(projectDir) !== realpathSync11(topLevel.stdout.trim()))
260206
+ return;
260207
+ const paths = existingRollOwnedPaths(projectDir);
260208
+ if (paths.length === 0)
260209
+ return;
260210
+ if (!runGit(projectDir, ["diff", "--cached", "--quiet"]).ok) {
260211
+ printGitFinalizeManual("existing staged changes; auto commit skipped", `git add -A -f -- ${paths.join(" ")} && git commit -m 'roll init: commit Roll-owned meta files'`);
260212
+ return;
260213
+ }
260214
+ const add = runGit(projectDir, ["add", "-A", "-f", "--", ...paths]);
260215
+ if (!add.ok) {
260216
+ printGitFinalizeManual("git add failed", `git add -A -f -- ${paths.join(" ")}`);
260217
+ return;
260218
+ }
260219
+ if (runGit(projectDir, ["diff", "--cached", "--quiet", "--", ...paths]).ok)
260220
+ return;
260221
+ const commit2 = runGit(projectDir, ["commit", "-m", "roll init: commit Roll-owned meta files"]);
260222
+ if (!commit2.ok) {
260223
+ printGitFinalizeManual("git commit failed", "git commit -m 'roll init: commit Roll-owned meta files' -- AGENTS.md .roll .claude .gitignore");
260224
+ return;
260225
+ }
260226
+ const sha = runGit(projectDir, ["rev-parse", "--short", "HEAD"]).stdout.trim();
260227
+ ok10(`Roll meta committed${sha !== "" ? `: ${sha}` : ""}`);
260228
+ const branch = runGit(projectDir, ["rev-parse", "--abbrev-ref", "HEAD"]).stdout.trim();
260229
+ if (branch === "" || branch === "HEAD") {
260230
+ printGitFinalizeManual("detached HEAD; push skipped", "git push origin HEAD");
260231
+ return;
260232
+ }
260233
+ const remotes = runGit(projectDir, ["remote"]).stdout.split("\n").filter((line) => line.trim() !== "");
260234
+ if (!remotes.includes("origin")) {
260235
+ printGitFinalizeManual("origin remote is not configured; push skipped", `git push -u origin ${branch}`);
260236
+ return;
260237
+ }
260238
+ const push2 = runGit(projectDir, ["push", "-u", "origin", branch]);
260239
+ if (!push2.ok) {
260240
+ printGitFinalizeManual("git push failed", `git push -u origin ${branch}`);
260241
+ return;
260242
+ }
260243
+ ok10(`Roll meta pushed: origin/${branch}`);
260244
+ }
260056
260245
  function err9(line) {
260057
260246
  const { RED, NC } = pal4();
260058
260247
  process.stderr.write(`${RED}[roll]${NC} ${line}
@@ -260914,6 +261103,7 @@ function initRepair(projectDir, facts, diagnosis2, opts = {}) {
260914
261103
  recordCreatedFileIfNeeded(projectDir, changeset, ".roll/.version", stampExisted);
260915
261104
  printMergeSummary(summary);
260916
261105
  ok10("Repair complete.");
261106
+ finalizeRollOwnedGit(projectDir);
260917
261107
  return 0;
260918
261108
  }
260919
261109
  function initApply(projectDir, opts = {}) {
@@ -261029,6 +261219,7 @@ function initApply(projectDir, opts = {}) {
261029
261219
  registerProject(projectDir);
261030
261220
  process.stdout.write("\n");
261031
261221
  ok10(m3("init.onboard_apply_complete_onboard"));
261222
+ finalizeRollOwnedGit(projectDir);
261032
261223
  return 0;
261033
261224
  } catch (error) {
261034
261225
  err9(m32("init.onboard_apply_failed"));
@@ -261859,6 +262050,7 @@ function initCommand(args, deps = {}) {
261859
262050
  registerProject(projectDir);
261860
262051
  const shouldNudge = detectDesignHandoff(projectDir).shouldNudge;
261861
262052
  emitInitUi(projectDir, hasAgents, syncStatus, summary, shouldNudge, repairMode ? "repair" : void 0, conciergeNextItems(brief, initDiagnosis));
262053
+ finalizeRollOwnedGit(projectDir);
261862
262054
  void err9;
261863
262055
  return 0;
261864
262056
  }
@@ -262055,9 +262247,9 @@ function nextCommand(args) {
262055
262247
  // packages/cli/dist/commands/design.js
262056
262248
  init_dist();
262057
262249
  init_dist2();
262058
- import { spawnSync as spawnSync12 } from "node:child_process";
262059
- import { existsSync as existsSync85, mkdirSync as mkdirSync37, readFileSync as readFileSync78, renameSync as renameSync16, statSync as statSync31, writeFileSync as writeFileSync39 } from "node:fs";
262060
- import { dirname as dirname39, join as join88, relative as relative6, resolve as resolve8 } from "node:path";
262250
+ import { spawn as spawnChild } from "node:child_process";
262251
+ import { appendFileSync as appendFileSync13, existsSync as existsSync85, mkdirSync as mkdirSync37, readFileSync as readFileSync78, renameSync as renameSync16, statSync as statSync31, writeFileSync as writeFileSync39 } from "node:fs";
262252
+ import { dirname as dirname39, join as join88, relative as relative6, resolve as resolve9 } from "node:path";
262061
262253
 
262062
262254
  // packages/cli/dist/lib/review-page.js
262063
262255
  init_dist2();
@@ -262443,7 +262635,7 @@ function lookupEpic(target, cwd) {
262443
262635
  function readBacklogItems(cwd) {
262444
262636
  try {
262445
262637
  const content = readFileSync78(join88(cwd, ".roll", "backlog.md"), "utf8");
262446
- return parseBacklog(content).map((row2) => ({ id: row2.id }));
262638
+ return parseBacklog(content).map((row2) => ({ id: row2.id, desc: row2.desc }));
262447
262639
  } catch {
262448
262640
  return [];
262449
262641
  }
@@ -262466,7 +262658,7 @@ function renderDesignReviewPageForTarget(ctx, cardsCreated) {
262466
262658
  return;
262467
262659
  const base = join88(".roll", "features", epic, ctx.target);
262468
262660
  const md = join88(base, "spec.md");
262469
- const absMd = resolve8(ctx.cwd, md);
262661
+ const absMd = resolve9(ctx.cwd, md);
262470
262662
  if (!existsSync85(absMd) || !hasDetailedDesign(absMd))
262471
262663
  return;
262472
262664
  const markdown = readFileSync78(absMd, "utf8");
@@ -262481,7 +262673,7 @@ function renderDesignReviewPageForTarget(ctx, cardsCreated) {
262481
262673
  markdown,
262482
262674
  lang: ctx.lang
262483
262675
  });
262484
- const out3 = resolve8(ctx.cwd, base, "design-review.html");
262676
+ const out3 = resolve9(ctx.cwd, base, "design-review.html");
262485
262677
  mkdirSync37(dirname39(out3), { recursive: true });
262486
262678
  const tmp = `${out3}.tmp`;
262487
262679
  writeFileSync39(tmp, html, "utf8");
@@ -262499,37 +262691,203 @@ function formatSignal(sig) {
262499
262691
  const detail = sig.detail !== void 0 && sig.detail !== "" ? ` ${sig.detail}` : "";
262500
262692
  return `${fmtHhmmss(sig.ts)} ${sig.summary}${detail}`.trimEnd();
262501
262693
  }
262502
- function progressLines(agent, combined, startMs, verbose) {
262503
- const normalizer = normalizerFor(agent);
262694
+ function isPromiseLike(value) {
262695
+ return typeof value.then === "function";
262696
+ }
262697
+ function isDesignNoise(text2) {
262698
+ const s = text2.trim();
262699
+ if (s === "")
262700
+ return true;
262701
+ if (/^\?\?\s/.test(s))
262702
+ return true;
262703
+ if (/^\s*-\s*\[\s*\]\s+/.test(s))
262704
+ return true;
262705
+ return /\$roll-design|roll-design contract|ID generation algorithm|Who writes the data|encrypted reasoning/i.test(s);
262706
+ }
262707
+ function isMeaningfulDesignSay(summary) {
262708
+ return /\b(reading|planning|designing|writing|validating|recovering|handoff|backlog|spec|artifact|context|contexts|created|card)\b/i.test(summary);
262709
+ }
262710
+ function shouldShowSignal(sig, verbose) {
262711
+ const joined = `${sig.summary} ${sig.detail ?? ""}`;
262712
+ if (isDesignNoise(joined))
262713
+ return false;
262714
+ if (verbose)
262715
+ return true;
262716
+ if (sig.tier === "A" || sig.tier === "B")
262717
+ return true;
262718
+ if (sig.kind === "say" && isMeaningfulDesignSay(sig.summary))
262719
+ return true;
262720
+ return sig.kind === "say" && isQuestionLike(sig.summary);
262721
+ }
262722
+ function formatDuration(ms) {
262723
+ const total = Math.max(0, Math.round(ms / 1e3));
262724
+ const m7 = Math.floor(total / 60);
262725
+ const s = total % 60;
262726
+ if (m7 === 0)
262727
+ return `${s}s`;
262728
+ return `${m7}m ${String(s).padStart(2, "0")}s`;
262729
+ }
262730
+ function formatBytes(bytes) {
262731
+ if (bytes < 1024)
262732
+ return `${bytes} B`;
262733
+ if (bytes < 1024 * 1024)
262734
+ return `${Math.round(bytes / 1024)} KB`;
262735
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
262736
+ }
262737
+ function transcriptSize(path) {
262738
+ try {
262739
+ return statSync31(path).size;
262740
+ } catch {
262741
+ return 0;
262742
+ }
262743
+ }
262744
+ function splitCardDescription(desc) {
262745
+ const clean3 = desc.replace(/\s+/g, " ").trim();
262746
+ const solves = /\s+·\s+solves\s+/i.exec(clean3);
262747
+ if (solves !== null) {
262748
+ const title = clean3.slice(0, solves.index).trim();
262749
+ const problem = clean3.slice(solves.index + solves[0].length).trim();
262750
+ return { title: title || clean3, problem: problem || title || clean3 };
262751
+ }
262752
+ return { title: clean3 || "Untitled card", problem: clean3 || "the design gap" };
262753
+ }
262754
+ function createLiveProgress(ctx, deps, opts) {
262755
+ const normalizer = normalizerFor(ctx.agent);
262504
262756
  const state = newNormalizerState();
262505
- const out3 = [];
262506
- const lines3 = combined.split("\n");
262507
- for (let i = 0; i < lines3.length; i += 1) {
262508
- const line = lines3[i] ?? "";
262509
- const nowMs = startMs + i * 1e3;
262510
- const signals = normalizer.normalize(line, state, nowMs);
262757
+ const emittedCards = /* @__PURE__ */ new Set();
262758
+ const knownBefore = new Set(ctx.beforeBacklog.map((row2) => row2.id));
262759
+ let stdoutBuffer = "";
262760
+ let stderrBuffer = "";
262761
+ let rawTranscript = "";
262762
+ let sawLiveOutput = false;
262763
+ let lastPrintedTs = ctx.startTs;
262764
+ let heartbeat;
262765
+ const scanCards = () => {
262766
+ if (opts.raw)
262767
+ return;
262768
+ for (const item of readBacklogItems(ctx.cwd)) {
262769
+ if (knownBefore.has(item.id) || emittedCards.has(item.id))
262770
+ continue;
262771
+ emittedCards.add(item.id);
262772
+ const { title, problem } = splitCardDescription(item.desc);
262773
+ const ts2 = deps.now();
262774
+ lastPrintedTs = ts2;
262775
+ emit4(`${fmtHhmmss(ts2)} card created: ${item.id} \u2014 ${title} \xB7 solves ${problem}`);
262776
+ }
262777
+ };
262778
+ const processLine = (line) => {
262779
+ if (opts.raw)
262780
+ return;
262781
+ const ts2 = deps.now();
262782
+ const signals = normalizer.normalize(line, state, ts2);
262511
262783
  for (const sig of signals) {
262512
- const show = verbose || sig.tier === "A" || sig.tier === "B" || sig.kind === "say" && isQuestionLike(sig.summary);
262513
- if (show) {
262514
- out3.push(formatSignal(sig));
262784
+ if (!shouldShowSignal(sig, opts.verbose))
262785
+ continue;
262786
+ lastPrintedTs = sig.ts;
262787
+ emit4(formatSignal(sig));
262788
+ }
262789
+ };
262790
+ const ingest = (chunk, stream) => {
262791
+ if (chunk === "")
262792
+ return;
262793
+ sawLiveOutput = true;
262794
+ rawTranscript += chunk;
262795
+ appendFileSync13(ctx.transcriptPath, chunk, "utf8");
262796
+ if (opts.raw) {
262797
+ process.stderr.write(chunk);
262798
+ return;
262799
+ }
262800
+ const next = (stream === "stdout" ? stdoutBuffer : stderrBuffer) + chunk;
262801
+ const parts = next.split(/\n/);
262802
+ const complete = parts.slice(0, -1);
262803
+ for (const line of complete)
262804
+ processLine(line);
262805
+ if (stream === "stdout")
262806
+ stdoutBuffer = parts[parts.length - 1] ?? "";
262807
+ else
262808
+ stderrBuffer = parts[parts.length - 1] ?? "";
262809
+ scanCards();
262810
+ };
262811
+ const emitHeartbeat = () => {
262812
+ if (opts.raw)
262813
+ return;
262814
+ const ts2 = deps.now();
262815
+ if (ts2 - lastPrintedTs < deps.heartbeatMs)
262816
+ return;
262817
+ lastPrintedTs = ts2;
262818
+ emit4(`${fmtHhmmss(ts2)} heartbeat: still designing \xB7 elapsed ${formatDuration(ts2 - ctx.startTs)} \xB7 transcript ${formatBytes(transcriptSize(ctx.transcriptPath))} \xB7 cards observed ${emittedCards.size}`);
262819
+ };
262820
+ return {
262821
+ get sawLiveOutput() {
262822
+ return sawLiveOutput;
262823
+ },
262824
+ get rawTranscript() {
262825
+ return rawTranscript;
262826
+ },
262827
+ startHeartbeat: () => {
262828
+ if (opts.raw)
262829
+ return;
262830
+ heartbeat = setInterval(emitHeartbeat, deps.heartbeatMs);
262831
+ heartbeat.unref?.();
262832
+ },
262833
+ stopHeartbeat: () => {
262834
+ if (heartbeat !== void 0)
262835
+ clearInterval(heartbeat);
262836
+ },
262837
+ ingestStdout: (chunk) => ingest(chunk, "stdout"),
262838
+ ingestStderr: (chunk) => ingest(chunk, "stderr"),
262839
+ flush: () => {
262840
+ if (stdoutBuffer !== "") {
262841
+ processLine(stdoutBuffer);
262842
+ stdoutBuffer = "";
262515
262843
  }
262844
+ if (stderrBuffer !== "") {
262845
+ processLine(stderrBuffer);
262846
+ stderrBuffer = "";
262847
+ }
262848
+ scanCards();
262516
262849
  }
262517
- }
262518
- return out3;
262850
+ };
262519
262851
  }
262520
262852
  var defaultDeps = {
262521
262853
  cwd: process.cwd(),
262522
262854
  env: process.env,
262523
262855
  readLine: readLineFromStdin,
262524
262856
  now: () => Date.now(),
262525
- spawn: (bin, args, opts) => {
262526
- const r = spawnSync12(bin, args, { ...opts, stdio: ["inherit", "pipe", "pipe"], encoding: "utf8" });
262527
- return {
262528
- status: r.status ?? null,
262529
- signal: r.signal ?? null,
262530
- stdout: typeof r.stdout === "string" ? r.stdout : "",
262531
- stderr: typeof r.stderr === "string" ? r.stderr : ""
262532
- };
262857
+ heartbeatMs: 6e4,
262858
+ spawn: (bin, args, opts, live) => {
262859
+ return new Promise((resolveSpawn) => {
262860
+ const child = spawnChild(bin, args, { ...opts, stdio: ["inherit", "pipe", "pipe"] });
262861
+ let stdout = "";
262862
+ let stderr = "";
262863
+ let settled = false;
262864
+ const finish = (result) => {
262865
+ if (settled)
262866
+ return;
262867
+ settled = true;
262868
+ resolveSpawn(result);
262869
+ };
262870
+ child.stdout?.setEncoding("utf8");
262871
+ child.stderr?.setEncoding("utf8");
262872
+ child.stdout?.on("data", (chunk) => {
262873
+ stdout += chunk;
262874
+ live?.onStdout(chunk);
262875
+ });
262876
+ child.stderr?.on("data", (chunk) => {
262877
+ stderr += chunk;
262878
+ live?.onStderr(chunk);
262879
+ });
262880
+ child.on("error", (err16) => {
262881
+ const message = `${err16 instanceof Error ? err16.message : String(err16)}
262882
+ `;
262883
+ stderr += message;
262884
+ live?.onStderr(message);
262885
+ finish({ status: 1, signal: null, stdout, stderr });
262886
+ });
262887
+ child.on("close", (code, signal) => {
262888
+ finish({ status: code, signal, stdout, stderr });
262889
+ });
262890
+ });
262533
262891
  }
262534
262892
  };
262535
262893
  function selectAgent(installed, forced, envAgent, primary, readLine) {
@@ -262594,12 +262952,12 @@ function printHandoff(ctx, statusCode, rawTranscript) {
262594
262952
  const md = join88(base, "spec.md");
262595
262953
  const reviewHtml = join88(base, "design-review.html");
262596
262954
  const html = join88(base, "spec.html");
262597
- if (existsSync85(resolve8(ctx.cwd, md))) {
262598
- designPath = hasDetailedDesign(resolve8(ctx.cwd, md)) ? `${md}#detailed-design` : md;
262955
+ if (existsSync85(resolve9(ctx.cwd, md))) {
262956
+ designPath = hasDetailedDesign(resolve9(ctx.cwd, md)) ? `${md}#detailed-design` : md;
262599
262957
  }
262600
- if (existsSync85(resolve8(ctx.cwd, reviewHtml)))
262958
+ if (existsSync85(resolve9(ctx.cwd, reviewHtml)))
262601
262959
  reviewPagePath = reviewHtml;
262602
- else if (existsSync85(resolve8(ctx.cwd, html)))
262960
+ else if (existsSync85(resolve9(ctx.cwd, html)))
262603
262961
  reviewPagePath = html;
262604
262962
  }
262605
262963
  let status2;
@@ -262664,7 +263022,7 @@ function designCommand(args, deps = {}) {
262664
263022
  emit4(t(v3Catalog, l, "design.not_roll_project"));
262665
263023
  return 1;
262666
263024
  }
262667
- if (fromFile !== void 0 && !isRegularFile(resolve8(d.cwd, fromFile))) {
263025
+ if (fromFile !== void 0 && !isRegularFile(resolve9(d.cwd, fromFile))) {
262668
263026
  emit4(t(v3Catalog, l, "design.from_file_not_found", fromFile));
262669
263027
  return 1;
262670
263028
  }
@@ -262717,20 +263075,35 @@ function designCommand(args, deps = {}) {
262717
263075
  beforeBacklog: readBacklogItems(d.cwd)
262718
263076
  };
262719
263077
  printStartBlock(ctx);
262720
- const result = d.spawn(cmd.bin, cmd.args, { cwd: d.cwd, env: d.env });
262721
- const rawTranscript = [result.stdout ?? "", result.stderr ?? ""].filter((s) => s !== "").join("\n");
262722
- writeFileSync39(runTranscript, rawTranscript, "utf8");
262723
- if (rawMode) {
262724
- if (rawTranscript !== "")
262725
- emit4(rawTranscript);
262726
- } else {
262727
- const lines3 = progressLines(agent, rawTranscript, startTs, verbose);
262728
- for (const line of lines3)
262729
- emit4(line);
263078
+ const live = createLiveProgress(ctx, d, { raw: rawMode, verbose });
263079
+ live.startHeartbeat();
263080
+ const finish = (result) => {
263081
+ if (!live.sawLiveOutput) {
263082
+ live.ingestStdout(result.stdout ?? "");
263083
+ live.ingestStderr(result.stderr ?? "");
263084
+ } else {
263085
+ const stdout = result.stdout ?? "";
263086
+ const stderr = result.stderr ?? "";
263087
+ if (stdout !== "" && !live.rawTranscript.includes(stdout))
263088
+ live.ingestStdout(stdout);
263089
+ if (stderr !== "" && !live.rawTranscript.includes(stderr))
263090
+ live.ingestStderr(stderr);
263091
+ }
263092
+ live.stopHeartbeat();
263093
+ live.flush();
263094
+ const statusCode = result.status ?? (result.signal === null ? 1 : 130);
263095
+ printHandoff(ctx, statusCode, live.rawTranscript);
263096
+ return statusCode;
263097
+ };
263098
+ const spawned = d.spawn(cmd.bin, cmd.args, { cwd: d.cwd, env: d.env }, { onStdout: live.ingestStdout, onStderr: live.ingestStderr });
263099
+ if (isPromiseLike(spawned)) {
263100
+ return spawned.then(finish, (err16) => {
263101
+ live.ingestStderr(`${err16 instanceof Error ? err16.message : String(err16)}
263102
+ `);
263103
+ return finish({ status: 1, signal: null });
263104
+ });
262730
263105
  }
262731
- const statusCode = result.status ?? (result.signal === null ? 1 : 130);
262732
- printHandoff(ctx, statusCode, rawTranscript);
262733
- return statusCode;
263106
+ return finish(spawned);
262734
263107
  }
262735
263108
 
262736
263109
  // packages/cli/dist/commands/loop-watch.js
@@ -262738,7 +263111,7 @@ init_dist();
262738
263111
  init_dist2();
262739
263112
  init_dist3();
262740
263113
  init_render();
262741
- import { spawn as spawn8, spawnSync as spawnSync13 } from "node:child_process";
263114
+ import { spawn as spawn8, spawnSync as spawnSync12 } from "node:child_process";
262742
263115
  import { existsSync as existsSync86, readFileSync as readFileSync79 } from "node:fs";
262743
263116
  import { join as join89 } from "node:path";
262744
263117
  import { createInterface as createInterface4 } from "node:readline";
@@ -262899,13 +263272,13 @@ function realDeps7() {
262899
263272
  render: (input, opts) => streamThroughRenderer(input, process.stdout, opts),
262900
263273
  renderEvents: streamEvents,
262901
263274
  tmuxState: probeWatchTmuxState,
262902
- tmuxRun: (argv) => spawnSync13("tmux", argv, { stdio: "ignore" }).status === 0,
263275
+ tmuxRun: (argv) => spawnSync12("tmux", argv, { stdio: "ignore" }).status === 0,
262903
263276
  tmuxAttach: (session) => {
262904
- spawnSync13("tmux", ["attach-session", "-r", "-t", session], { stdio: "inherit" });
263277
+ spawnSync12("tmux", ["attach-session", "-r", "-t", session], { stdio: "inherit" });
262905
263278
  },
262906
263279
  hasTmux: () => {
262907
263280
  try {
262908
- return spawnSync13("tmux", ["-V"], { stdio: "ignore" }).status === 0;
263281
+ return spawnSync12("tmux", ["-V"], { stdio: "ignore" }).status === 0;
262909
263282
  } catch {
262910
263283
  return false;
262911
263284
  }
@@ -262916,10 +263289,10 @@ function realDeps7() {
262916
263289
  }
262917
263290
  function probeWatchTmuxState(slug3) {
262918
263291
  const session = watchSessionName(slug3);
262919
- const sessionExists = spawnSync13("tmux", ["has-session", "-t", session], { stdio: "ignore" }).status === 0;
263292
+ const sessionExists = spawnSync12("tmux", ["has-session", "-t", session], { stdio: "ignore" }).status === 0;
262920
263293
  if (!sessionExists)
262921
263294
  return { sessionExists: false, watchWindowExists: false };
262922
- const listed = spawnSync13("tmux", ["list-windows", "-t", session, "-F", "#{window_name}"], { encoding: "utf8" });
263295
+ const listed = spawnSync12("tmux", ["list-windows", "-t", session, "-F", "#{window_name}"], { encoding: "utf8" });
262923
263296
  const windows = listed.status === 0 ? String(listed.stdout ?? "").split("\n").map((w) => w.trim()) : [];
262924
263297
  return { sessionExists: true, watchWindowExists: windows.includes("watch") };
262925
263298
  }
@@ -263296,14 +263669,14 @@ ${RECONCILE_PENDING_USAGE}
263296
263669
 
263297
263670
  // packages/cli/dist/commands/loop-review-resize.js
263298
263671
  init_dist2();
263299
- import { appendFileSync as appendFileSync14, mkdirSync as mkdirSync39 } from "node:fs";
263672
+ import { appendFileSync as appendFileSync15, mkdirSync as mkdirSync39 } from "node:fs";
263300
263673
  import { dirname as dirname41, join as join92 } from "node:path";
263301
263674
  init_dist2();
263302
263675
 
263303
263676
  // packages/cli/dist/commands/loop-self-downgrade.js
263304
263677
  init_dist2();
263305
263678
  init_dist3();
263306
- import { appendFileSync as appendFileSync13, existsSync as existsSync87, mkdirSync as mkdirSync38, readFileSync as readFileSync80, readdirSync as readdirSync32 } from "node:fs";
263679
+ import { appendFileSync as appendFileSync14, existsSync as existsSync87, mkdirSync as mkdirSync38, readFileSync as readFileSync80, readdirSync as readdirSync32 } from "node:fs";
263307
263680
  import { dirname as dirname40, join as join91 } from "node:path";
263308
263681
  function realSelfDowngradeDeps() {
263309
263682
  return {
@@ -263418,7 +263791,7 @@ async function loopSelfDowngradeCommand(argv, deps = realSelfDowngradeDeps()) {
263418
263791
  const headline = plan.capReason === "chain-cap" ? `${parentId} hit the self-downgrade chain cap (chain_depth=${plan.chainDepth} \u2265 ${CHAIN_DEPTH_CAP}) \u2014 held for human triage` : `${parentId} could not be split into \u22652 sub-stories (irreducible) \u2014 held for human triage`;
263419
263792
  try {
263420
263793
  mkdirSync38(dirname40(alertsPath), { recursive: true });
263421
- appendFileSync13(alertsPath, `[${isoUtc(ts2)}] ALERT ${headline}
263794
+ appendFileSync14(alertsPath, `[${isoUtc(ts2)}] ALERT ${headline}
263422
263795
  `, "utf8");
263423
263796
  } catch {
263424
263797
  }
@@ -263521,7 +263894,7 @@ For each sub-story create its .roll/features/<epic>/<id>/spec.md. Do NOT edit th
263521
263894
  const alertsPath = (process.env["ROLL_LOOP_ALERT"] ?? "").trim() || join92(rt, `ALERT-${projectSlug3(projectPath3)}.md`);
263522
263895
  try {
263523
263896
  mkdirSync39(dirname41(alertsPath), { recursive: true });
263524
- appendFileSync14(alertsPath, `[${new Date(ts2).toISOString()}] ALERT ${message}
263897
+ appendFileSync15(alertsPath, `[${new Date(ts2).toISOString()}] ALERT ${message}
263525
263898
  `, "utf8");
263526
263899
  } catch {
263527
263900
  }
@@ -263621,7 +263994,7 @@ async function loopExhaustionSplitCommand(argv, deps = realExhaustionSplitDeps()
263621
263994
  init_dist2();
263622
263995
  init_dist();
263623
263996
  init_dist3();
263624
- import { appendFileSync as appendFileSync18, existsSync as existsSync99, mkdirSync as mkdirSync47, readFileSync as readFileSync93, writeFileSync as writeFileSync49 } from "node:fs";
263997
+ import { appendFileSync as appendFileSync19, existsSync as existsSync99, mkdirSync as mkdirSync47, readFileSync as readFileSync93, writeFileSync as writeFileSync49 } from "node:fs";
263625
263998
  import { dirname as dirname46, join as join103 } from "node:path";
263626
263999
 
263627
264000
  // packages/cli/dist/runner/executor.js
@@ -263670,7 +264043,7 @@ function writeCycleRoleSummaryBestEffort(cycleId, eventsPath3, cycleLogDir) {
263670
264043
 
263671
264044
  // packages/cli/dist/runner/executor.js
263672
264045
  import { execFile as execFile10, execFileSync as execFileSync22 } from "node:child_process";
263673
- import { appendFileSync as appendFileSync16, existsSync as existsSync95, lstatSync as lstatSync5, mkdirSync as mkdirSync44, readdirSync as readdirSync36, readFileSync as readFileSync89, realpathSync as realpathSync13, renameSync as renameSync17, rmSync as rmSync16, statSync as statSync33, symlinkSync as symlinkSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync46 } from "node:fs";
264046
+ import { appendFileSync as appendFileSync17, existsSync as existsSync95, lstatSync as lstatSync5, mkdirSync as mkdirSync44, readdirSync as readdirSync36, readFileSync as readFileSync89, realpathSync as realpathSync13, renameSync as renameSync17, rmSync as rmSync16, statSync as statSync33, symlinkSync as symlinkSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync46 } from "node:fs";
263674
264047
  import { homedir as homedir27 } from "node:os";
263675
264048
  import { dirname as dirname43, join as join100 } from "node:path";
263676
264049
  import { promisify as promisify10 } from "node:util";
@@ -263734,8 +264107,8 @@ async function probeAgentReachable(agent, spawn10, opts = {}) {
263734
264107
  try {
263735
264108
  res = await Promise.race([
263736
264109
  spawn10(agent, { cwd, skillBody: `Reply with exactly: ${token}`, timeoutMs, bare: true }),
263737
- new Promise((resolve11) => {
263738
- setTimeout(() => resolve11(null), timeoutMs).unref();
264110
+ new Promise((resolve12) => {
264111
+ setTimeout(() => resolve12(null), timeoutMs).unref();
263739
264112
  })
263740
264113
  ]);
263741
264114
  } catch (e) {
@@ -264323,7 +264696,7 @@ function autoAttachScreenshotToAcMap(worktreeCwd, storyId, runDir) {
264323
264696
  // packages/cli/dist/runner/correction-actuator.js
264324
264697
  init_dist2();
264325
264698
  init_dist();
264326
- import { appendFileSync as appendFileSync15, existsSync as existsSync93, mkdirSync as mkdirSync42, readFileSync as readFileSync87, readdirSync as readdirSync35, writeFileSync as writeFileSync44 } from "node:fs";
264699
+ import { appendFileSync as appendFileSync16, existsSync as existsSync93, mkdirSync as mkdirSync42, readFileSync as readFileSync87, readdirSync as readdirSync35, writeFileSync as writeFileSync44 } from "node:fs";
264327
264700
  import { dirname as dirname42, join as join98 } from "node:path";
264328
264701
  function readMode(projectPath3) {
264329
264702
  try {
@@ -264345,7 +264718,7 @@ function readEvents4(eventsPath3) {
264345
264718
  function appendEvent(eventsPath3, event) {
264346
264719
  try {
264347
264720
  mkdirSync42(dirname42(eventsPath3), { recursive: true });
264348
- appendFileSync15(eventsPath3, `${JSON.stringify(event)}
264721
+ appendFileSync16(eventsPath3, `${JSON.stringify(event)}
264349
264722
  `, "utf8");
264350
264723
  } catch {
264351
264724
  }
@@ -264353,7 +264726,7 @@ function appendEvent(eventsPath3, event) {
264353
264726
  function appendAlert2(alertsPath, msg6) {
264354
264727
  try {
264355
264728
  mkdirSync42(dirname42(alertsPath), { recursive: true });
264356
- appendFileSync15(alertsPath, `${msg6}
264729
+ appendFileSync16(alertsPath, `${msg6}
264357
264730
  `, "utf8");
264358
264731
  } catch {
264359
264732
  }
@@ -264621,7 +264994,7 @@ function reviewTimeoutMs(diffChars) {
264621
264994
  async function firstValid(promises) {
264622
264995
  if (promises.length === 0)
264623
264996
  return null;
264624
- return new Promise((resolve11, reject) => {
264997
+ return new Promise((resolve12, reject) => {
264625
264998
  let pending = promises.length;
264626
264999
  let settled = false;
264627
265000
  let lastError;
@@ -264633,7 +265006,7 @@ async function firstValid(promises) {
264633
265006
  if (threw)
264634
265007
  reject(lastError);
264635
265008
  else
264636
- resolve11(null);
265009
+ resolve12(null);
264637
265010
  }
264638
265011
  };
264639
265012
  for (const p of promises) {
@@ -264642,7 +265015,7 @@ async function firstValid(promises) {
264642
265015
  return;
264643
265016
  if (value !== null) {
264644
265017
  settled = true;
264645
- resolve11(value);
265018
+ resolve12(value);
264646
265019
  return;
264647
265020
  }
264648
265021
  onNonResult();
@@ -265025,7 +265398,7 @@ DIFF:
265025
265398
 
265026
265399
  // packages/cli/dist/runner/executor.js
265027
265400
  var execFileAsync10 = promisify10(execFile10);
265028
- function parsePorcelainPath(line) {
265401
+ function parsePorcelainPath2(line) {
265029
265402
  const raw = line.length > 3 ? line.slice(3).trim() : line.trim();
265030
265403
  const target = raw.includes(" -> ") ? raw.split(" -> ").at(-1) ?? raw : raw;
265031
265404
  return target.replace(/^"|"$/g, "");
@@ -265036,7 +265409,7 @@ async function checkMainDirty(repoCwd) {
265036
265409
  cwd: repoCwd,
265037
265410
  encoding: "utf8"
265038
265411
  });
265039
- return stdout.split("\n").map((line) => line.trimEnd()).filter((line) => line.trim() !== "").map(parsePorcelainPath).filter((path) => path !== ".roll" && !path.startsWith(".roll/")).slice(0, 50);
265412
+ return stdout.split("\n").map((line) => line.trimEnd()).filter((line) => line.trim() !== "").map(parsePorcelainPath2).filter((path) => path !== ".roll" && !path.startsWith(".roll/")).slice(0, 50);
265040
265413
  } catch {
265041
265414
  return [];
265042
265415
  }
@@ -265141,7 +265514,7 @@ var ActivitySignalRecorder = class {
265141
265514
  }
265142
265515
  append(signals) {
265143
265516
  try {
265144
- appendFileSync16(this.signalPath, signals.map((sig) => JSON.stringify(sig)).join("\n") + "\n", "utf8");
265517
+ appendFileSync17(this.signalPath, signals.map((sig) => JSON.stringify(sig)).join("\n") + "\n", "utf8");
265145
265518
  } catch {
265146
265519
  }
265147
265520
  }
@@ -265510,7 +265883,7 @@ function createCaptureMarkerSink(runDir, capture) {
265510
265883
  const record = (marker, result) => {
265511
265884
  try {
265512
265885
  mkdirSync44(dirname43(logPath), { recursive: true });
265513
- appendFileSync16(logPath, JSON.stringify({ marker, result }) + "\n", "utf8");
265886
+ appendFileSync17(logPath, JSON.stringify({ marker, result }) + "\n", "utf8");
265514
265887
  } catch {
265515
265888
  }
265516
265889
  };
@@ -265756,7 +266129,7 @@ ${skillBodyForSpawn}` : skillBodyForSpawn;
265756
266129
  stallDetector.markProgress();
265757
266130
  captureSink?.onChunk(d);
265758
266131
  try {
265759
- appendFileSync16(livePath, d);
266132
+ appendFileSync17(livePath, d);
265760
266133
  } catch {
265761
266134
  }
265762
266135
  signalRecorder.accept(d);
@@ -265995,7 +266368,7 @@ ${stderr}
265995
266368
  // FIX-319: review-only framing, no worker autorun directive
265996
266369
  ...ctx.evidenceRunDir !== void 0 ? { runDir: ctx.evidenceRunDir } : {}
265997
266370
  }),
265998
- new Promise((resolve11) => setTimeout(() => resolve11(null), timeoutMs).unref())
266371
+ new Promise((resolve12) => setTimeout(() => resolve12(null), timeoutMs).unref())
265999
266372
  ]);
266000
266373
  } catch (e) {
266001
266374
  const detail = e instanceof Error ? e.message : String(e);
@@ -266135,7 +266508,7 @@ ${res.stderr}`;
266135
266508
  timeoutMs,
266136
266509
  ...ctx.evidenceRunDir !== void 0 ? { runDir: ctx.evidenceRunDir } : {}
266137
266510
  }),
266138
- new Promise((resolve11) => setTimeout(() => resolve11(null), timeoutMs).unref())
266511
+ new Promise((resolve12) => setTimeout(() => resolve12(null), timeoutMs).unref())
266139
266512
  ]);
266140
266513
  } catch (e) {
266141
266514
  const detail = e instanceof Error ? e.message : String(e);
@@ -267354,7 +267727,7 @@ async function linkRollIntoWorktree(repoCwd, worktreePath) {
267354
267727
  const cur = existsSync95(exclude) ? readFileSync89(exclude, "utf8") : "";
267355
267728
  if (!/^\.roll$/m.test(cur)) {
267356
267729
  mkdirSync44(dirname43(exclude), { recursive: true });
267357
- appendFileSync16(exclude, `${cur === "" || cur.endsWith("\n") ? "" : "\n"}.roll
267730
+ appendFileSync17(exclude, `${cur === "" || cur.endsWith("\n") ? "" : "\n"}.roll
267358
267731
  `, "utf8");
267359
267732
  }
267360
267733
  } catch {
@@ -267928,7 +268301,7 @@ function nodePorts(opts) {
267928
268301
  }
267929
268302
  function appendAlertLine(alertsPath, message) {
267930
268303
  mkdirSync44(dirname43(alertsPath), { recursive: true });
267931
- appendFileSync16(alertsPath, `${message}
268304
+ appendFileSync17(alertsPath, `${message}
267932
268305
  `, "utf8");
267933
268306
  }
267934
268307
 
@@ -268271,7 +268644,7 @@ async function warnIfBinaryStale(rollHomeDir2, runningVersion, appendAlert3) {
268271
268644
  // packages/cli/dist/runner/correction-circuit.js
268272
268645
  init_dist2();
268273
268646
  init_dist();
268274
- import { appendFileSync as appendFileSync17, existsSync as existsSync98, mkdirSync as mkdirSync46, readFileSync as readFileSync92, writeFileSync as writeFileSync48 } from "node:fs";
268647
+ import { appendFileSync as appendFileSync18, existsSync as existsSync98, mkdirSync as mkdirSync46, readFileSync as readFileSync92, writeFileSync as writeFileSync48 } from "node:fs";
268275
268648
  import { dirname as dirname45, join as join102 } from "node:path";
268276
268649
  function readLoopSafety(projectPath3) {
268277
268650
  try {
@@ -268295,7 +268668,7 @@ function alreadyTripped(events, verdict) {
268295
268668
  }
268296
268669
  function appendEvent2(eventsPath3, event) {
268297
268670
  mkdirSync46(dirname45(eventsPath3), { recursive: true });
268298
- appendFileSync17(eventsPath3, `${JSON.stringify(event)}
268671
+ appendFileSync18(eventsPath3, `${JSON.stringify(event)}
268299
268672
  `, "utf8");
268300
268673
  }
268301
268674
  function applyCorrectionCircuitBreaker(projectPath3, slug3, eventsPath3, alertsPath, nowSec2 = Math.floor(Date.now() / 1e3)) {
@@ -268321,7 +268694,7 @@ function applyCorrectionCircuitBreaker(projectPath3, slug3, eventsPath3, alertsP
268321
268694
  if (pauseWritten)
268322
268695
  writeFileSync48(pauseMarker, alertMsg, "utf8");
268323
268696
  mkdirSync46(dirname45(alertsPath), { recursive: true });
268324
- appendFileSync17(alertsPath, `${alertMsg}
268697
+ appendFileSync18(alertsPath, `${alertMsg}
268325
268698
  `, "utf8");
268326
268699
  appendEvent2(eventsPath3, {
268327
268700
  type: "correction:circuit_breaker",
@@ -268341,7 +268714,7 @@ function applyCorrectionCircuitBreaker(projectPath3, slug3, eventsPath3, alertsP
268341
268714
 
268342
268715
  // packages/cli/dist/commands/loop-run-once.js
268343
268716
  init_dist();
268344
- import { execFileSync as execFileSync23, spawn as spawn9, spawnSync as spawnSync14 } from "node:child_process";
268717
+ import { execFileSync as execFileSync23, spawn as spawn9, spawnSync as spawnSync13 } from "node:child_process";
268345
268718
  import { lookup as lookup2 } from "node:dns/promises";
268346
268719
  function announceReport(projectPath3, slug3, storyId, opener = (p) => {
268347
268720
  try {
@@ -268487,7 +268860,7 @@ function writeCardSkipAlert(alertsPath, eventsPath3, cycleId, storyId, count) {
268487
268860
  **Action**: investigate ${storyId} (it likely needs a smaller split, a spec fix, or manual delivery). Once addressed, remove it from \`.roll/loop/skip-cards.json\` (or just fix the card) to re-arm it.
268488
268861
  `;
268489
268862
  try {
268490
- appendFileSync18(alertsPath, `${msg6}
268863
+ appendFileSync19(alertsPath, `${msg6}
268491
268864
  `, "utf8");
268492
268865
  } catch {
268493
268866
  }
@@ -268534,7 +268907,7 @@ function incrementConsecutiveFails(projectPath3, slug3, alertsPath, eventsPath3,
268534
268907
  `;
268535
268908
  try {
268536
268909
  writeFileSync49(pauseMarker, alertMsg, "utf8");
268537
- appendFileSync18(alertsPath, `${alertMsg}
268910
+ appendFileSync19(alertsPath, `${alertMsg}
268538
268911
  `, "utf8");
268539
268912
  const ts2 = Date.now();
268540
268913
  const bus = new EventBus();
@@ -268701,7 +269074,7 @@ function writeReviewerBlockedAlert(projectPath3, slug3, alertsPath, eventsPath3,
268701
269074
  ` : "") + `**Action**: ${fix}
268702
269075
  `;
268703
269076
  try {
268704
- appendFileSync18(alertsPath, `${msg6}
269077
+ appendFileSync19(alertsPath, `${msg6}
268705
269078
  `, "utf8");
268706
269079
  } catch {
268707
269080
  }
@@ -268852,10 +269225,10 @@ async function loopRunOnceCommand(args) {
268852
269225
  const headline = t(v3Catalog, lang10, "loop.egress_blocked", cycleId);
268853
269226
  try {
268854
269227
  const ts2 = (/* @__PURE__ */ new Date()).toISOString();
268855
- appendFileSync18(alertsPath, `[${ts2}] ALERT ${headline}
269228
+ appendFileSync19(alertsPath, `[${ts2}] ALERT ${headline}
268856
269229
  `, "utf8");
268857
269230
  for (const line of guardLines)
268858
- appendFileSync18(alertsPath, `[${ts2}] ALERT ${line}
269231
+ appendFileSync19(alertsPath, `[${ts2}] ALERT ${line}
268859
269232
  `, "utf8");
268860
269233
  } catch {
268861
269234
  }
@@ -268880,7 +269253,7 @@ loop run-once: ${repoCheck.detail !== "" ? `(${repoCheck.detail})` : ""}
268880
269253
  if (skillBody === null) {
268881
269254
  const msg6 = `[${(/* @__PURE__ */ new Date()).toISOString()}] ALERT loop run-once: roll-loop SKILL.md not found (checked ROLL_LOOP_SKILL, .roll/skills/, skills/) \u2014 cycle ${cycleId} refused to start`;
268882
269255
  try {
268883
- appendFileSync18(alertsPath, `${msg6}
269256
+ appendFileSync19(alertsPath, `${msg6}
268884
269257
  `, "utf8");
268885
269258
  } catch {
268886
269259
  }
@@ -268914,7 +269287,7 @@ loop run-once: \u627E\u4E0D\u5230 roll-loop SKILL.md \u2014 \u62D2\u7EDD\u76F2\u
268914
269287
  try {
268915
269288
  await warnIfBinaryStale(rollHome(), rollVersion(), (msg6) => {
268916
269289
  try {
268917
- appendFileSync18(alertsPath, `${msg6}
269290
+ appendFileSync19(alertsPath, `${msg6}
268918
269291
  `, "utf8");
268919
269292
  } catch {
268920
269293
  }
@@ -269132,10 +269505,10 @@ function autoGc(projectPath3) {
269132
269505
  }
269133
269506
  }
269134
269507
  }
269135
- async function isOffline(resolve11 = (h) => lookup2(h)) {
269508
+ async function isOffline(resolve12 = (h) => lookup2(h)) {
269136
269509
  try {
269137
269510
  await Promise.race([
269138
- resolve11("github.com"),
269511
+ resolve12("github.com"),
269139
269512
  new Promise((_, rej) => {
269140
269513
  const t2 = setTimeout(() => rej(new Error("dns timeout")), 1500);
269141
269514
  if (typeof t2 === "object")
@@ -269152,7 +269525,7 @@ function isLoopPaused(projectPath3, slug3) {
269152
269525
  }
269153
269526
  function checkRepoPushable(projectPath3) {
269154
269527
  const git4 = (args) => {
269155
- const r = spawnSync14("git", args, { cwd: projectPath3, encoding: "utf8" });
269528
+ const r = spawnSync13("git", args, { cwd: projectPath3, encoding: "utf8" });
269156
269529
  return { code: r.status ?? 1, stderr: r.stderr ?? "" };
269157
269530
  };
269158
269531
  const inside = git4(["rev-parse", "--git-dir"]);
@@ -269184,7 +269557,7 @@ function writeRepoAlert(alertsPath, eventsPath3, cycleId, result) {
269184
269557
  **Action**: ${t(v3Catalog, lang10, "loop.no_remote")}
269185
269558
  `;
269186
269559
  try {
269187
- appendFileSync18(alertsPath, `${msg6}
269560
+ appendFileSync19(alertsPath, `${msg6}
269188
269561
  `, "utf8");
269189
269562
  } catch {
269190
269563
  }
@@ -269201,10 +269574,10 @@ function writeRepoAlert(alertsPath, eventsPath3, cycleId, result) {
269201
269574
 
269202
269575
  // packages/cli/dist/commands/offboard.js
269203
269576
  init_dist();
269204
- import { spawnSync as spawnSync15 } from "node:child_process";
269577
+ import { spawnSync as spawnSync14 } from "node:child_process";
269205
269578
  import { existsSync as existsSync100, readFileSync as readFileSync94, realpathSync as realpathSync14, renameSync as renameSync18, rmSync as rmSync17, writeFileSync as writeFileSync50 } from "node:fs";
269206
269579
  import { homedir as homedir28 } from "node:os";
269207
- import { join as join104, resolve as resolve9 } from "node:path";
269580
+ import { join as join104, resolve as resolve10 } from "node:path";
269208
269581
  function pal5() {
269209
269582
  const noColor2 = (process.env["NO_COLOR"] ?? "") !== "";
269210
269583
  return noColor2 ? { RED: "", GREEN: "", YELLOW: "", CYAN: "", BOLD: "", NC: "" } : {
@@ -269250,13 +269623,13 @@ function loopInCycle2() {
269250
269623
  function runLaunchctl(args) {
269251
269624
  const readOnly = /* @__PURE__ */ new Set(["print", "print-disabled", "list", "version", "dumpstate", "examine"]);
269252
269625
  if (args[0] !== void 0 && readOnly.has(args[0])) {
269253
- return spawnSync15("launchctl", args, { stdio: "inherit" }).status ?? 1;
269626
+ return spawnSync14("launchctl", args, { stdio: "inherit" }).status ?? 1;
269254
269627
  }
269255
269628
  const canonical = join104(homedir28(), "Library", "LaunchAgents");
269256
269629
  const launchdDir = process.env["_LAUNCHD_DIR"] ?? canonical;
269257
269630
  if (launchdDir !== canonical)
269258
269631
  return 0;
269259
- return spawnSync15("launchctl", args, { stdio: "inherit" }).status ?? 1;
269632
+ return spawnSync14("launchctl", args, { stdio: "inherit" }).status ?? 1;
269260
269633
  }
269261
269634
  var SECTIONS = ["files_merged", "files_created", "dirs_created", "gitignore_entries_added", "launchd_plists_installed"];
269262
269635
  function parseChangeset(text2) {
@@ -269308,7 +269681,7 @@ function writeFileAtomic2(path, text2) {
269308
269681
  }
269309
269682
  }
269310
269683
  function resolveChangesetItem(projectDir, item) {
269311
- return item.startsWith("/") ? resolve9(item) : resolve9(projectDir, item);
269684
+ return item.startsWith("/") ? resolve10(item) : resolve10(projectDir, item);
269312
269685
  }
269313
269686
  var HELP3 = `Usage: roll offboard [--confirm]
269314
269687
  Preview (default) or apply (--confirm) the removal of every
@@ -269329,7 +269702,7 @@ function offboardCommand(args) {
269329
269702
  }
269330
269703
  let projectDir;
269331
269704
  try {
269332
- projectDir = realpathSync14(resolve9(process.cwd()));
269705
+ projectDir = realpathSync14(resolve10(process.cwd()));
269333
269706
  } catch {
269334
269707
  projectDir = process.cwd();
269335
269708
  }
@@ -271799,7 +272172,7 @@ ${c("dim", "\u2192 Running the golden-path showcase (real models; its verdict do
271799
272172
  // packages/cli/dist/commands/setup.js
271800
272173
  init_dist();
271801
272174
  init_render();
271802
- import { spawnSync as spawnSync17 } from "node:child_process";
272175
+ import { spawnSync as spawnSync16 } from "node:child_process";
271803
272176
  import { existsSync as existsSync107, lstatSync as lstatSync6, mkdirSync as mkdirSync52, readFileSync as readFileSync101, readdirSync as readdirSync42, readlinkSync as readlinkSync3, statSync as statSync36 } from "node:fs";
271804
272177
  import { join as join111 } from "node:path";
271805
272178
  function err13(line) {
@@ -271906,13 +272279,13 @@ function runSetupStep(watch, fn) {
271906
272279
  return before === after ? "unchanged" : "changed";
271907
272280
  }
271908
272281
  function ensureHooksPath(repoPath) {
271909
- const inRepo = spawnSync17("git", ["-C", repoPath, "rev-parse", "--git-dir"], { stdio: "ignore" }).status === 0;
272282
+ const inRepo = spawnSync16("git", ["-C", repoPath, "rev-parse", "--git-dir"], { stdio: "ignore" }).status === 0;
271910
272283
  if (!inRepo)
271911
272284
  return;
271912
- const cur = spawnSync17("git", ["-C", repoPath, "config", "core.hooksPath"], { encoding: "utf8" });
272285
+ const cur = spawnSync16("git", ["-C", repoPath, "config", "core.hooksPath"], { encoding: "utf8" });
271913
272286
  const current = cur.status === 0 ? (cur.stdout ?? "").trim() : "";
271914
272287
  if (current === "" || current === ".git/hooks") {
271915
- spawnSync17("git", ["-C", repoPath, "config", "core.hooksPath", "hooks"], { stdio: "ignore" });
272288
+ spawnSync16("git", ["-C", repoPath, "config", "core.hooksPath", "hooks"], { stdio: "ignore" });
271916
272289
  }
271917
272290
  }
271918
272291
  function peerEnsureStateDir() {
@@ -271935,7 +272308,7 @@ function submoduleGuard() {
271935
272308
  empty = true;
271936
272309
  }
271937
272310
  if (hasGit && hasMods && empty) {
271938
- spawnSync17("git", ["submodule", "update", "--init", "--recursive", "--quiet"], {
272311
+ spawnSync16("git", ["submodule", "update", "--init", "--recursive", "--quiet"], {
271939
272312
  cwd: pkg,
271940
272313
  stdio: "ignore"
271941
272314
  });
@@ -272116,9 +272489,9 @@ function setupCommand(args) {
272116
272489
  init_showcase2();
272117
272490
 
272118
272491
  // packages/cli/dist/commands/test.js
272119
- import { spawnSync as spawnSync18 } from "node:child_process";
272120
- import { appendFileSync as appendFileSync19, existsSync as existsSync108, mkdirSync as mkdirSync53, readFileSync as readFileSync102, rmSync as rmSync19, writeFileSync as writeFileSync56 } from "node:fs";
272121
- import { dirname as dirname50, join as join112, resolve as resolve10 } from "node:path";
272492
+ import { spawnSync as spawnSync17 } from "node:child_process";
272493
+ import { appendFileSync as appendFileSync20, existsSync as existsSync108, mkdirSync as mkdirSync53, readFileSync as readFileSync102, rmSync as rmSync19, writeFileSync as writeFileSync56 } from "node:fs";
272494
+ import { dirname as dirname50, join as join112, resolve as resolve11 } from "node:path";
272122
272495
  function pal7() {
272123
272496
  const noColor2 = (process.env["NO_COLOR"] ?? "") !== "";
272124
272497
  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" };
@@ -272138,7 +272511,7 @@ function currentEvidenceFrame() {
272138
272511
  const raw = (process.env["ROLL_RUN_DIR"] ?? "").trim();
272139
272512
  if (raw === "")
272140
272513
  return null;
272141
- const runDir = resolve10(raw);
272514
+ const runDir = resolve11(raw);
272142
272515
  if (!existsSync108(runDir))
272143
272516
  return null;
272144
272517
  const frame = {
@@ -272175,7 +272548,7 @@ function appendRollTestEvidence(frame, cmd, argv, status2, stdout, stderr) {
272175
272548
  try {
272176
272549
  const ts2 = (/* @__PURE__ */ new Date()).toISOString();
272177
272550
  const command = [cmd, ...argv];
272178
- appendFileSync19(join112(frame.evidenceDir, "roll-test-output.log"), [
272551
+ appendFileSync20(join112(frame.evidenceDir, "roll-test-output.log"), [
272179
272552
  `===== roll test ${ts2} exit=${status2} =====`,
272180
272553
  `$ ${command.join(" ")}`,
272181
272554
  "--- stdout ---",
@@ -272184,7 +272557,7 @@ function appendRollTestEvidence(frame, cmd, argv, status2, stdout, stderr) {
272184
272557
  stderr,
272185
272558
  ""
272186
272559
  ].join("\n"), "utf8");
272187
- appendFileSync19(join112(frame.evidenceDir, "roll-test-summary.txt"), JSON.stringify({
272560
+ appendFileSync20(join112(frame.evidenceDir, "roll-test-summary.txt"), JSON.stringify({
272188
272561
  ts: ts2,
272189
272562
  command,
272190
272563
  exitCode: status2,
@@ -272264,7 +272637,7 @@ function resetReleaseLock() {
272264
272637
  }
272265
272638
  function runForward(cmd, argv) {
272266
272639
  const frame = currentEvidenceFrame();
272267
- const r = spawnSync18(cmd, argv, { encoding: "utf8", env: childEnvForEvidence(frame) });
272640
+ const r = spawnSync17(cmd, argv, { encoding: "utf8", env: childEnvForEvidence(frame) });
272268
272641
  const stdout = typeof r.stdout === "string" ? r.stdout : "";
272269
272642
  const stderr = typeof r.stderr === "string" ? r.stderr : "";
272270
272643
  const status2 = r.status ?? 1;
@@ -272282,7 +272655,7 @@ function ensureSkillsSubmoduleReady() {
272282
272655
  if (existsSync108(required2))
272283
272656
  return true;
272284
272657
  if (existsSync108(join112(pkg, ".git")) && existsSync108(join112(pkg, ".gitmodules"))) {
272285
- spawnSync18("git", ["submodule", "update", "--init", "--recursive", "--quiet", "skills"], {
272658
+ spawnSync17("git", ["submodule", "update", "--init", "--recursive", "--quiet", "skills"], {
272286
272659
  cwd: pkg,
272287
272660
  stdio: "ignore"
272288
272661
  });
@@ -272788,7 +273161,7 @@ function tuneCommand(argv) {
272788
273161
 
272789
273162
  // packages/cli/dist/commands/update.js
272790
273163
  init_dist();
272791
- import { spawnSync as spawnSync19 } from "node:child_process";
273164
+ import { spawnSync as spawnSync18 } from "node:child_process";
272792
273165
  import { existsSync as existsSync111, mkdtempSync as mkdtempSync9, readFileSync as readFileSync105, rmSync as rmSync20 } from "node:fs";
272793
273166
  import { tmpdir as tmpdir11 } from "node:os";
272794
273167
  import { join as join116 } from "node:path";
@@ -272829,7 +273202,7 @@ function m6(key, ...args) {
272829
273202
  return t(v2Catalog, msgLang10(), key, ...args);
272830
273203
  }
272831
273204
  function runForward2(cmd, argv) {
272832
- const r = spawnSync19(cmd, argv, { encoding: "utf8" });
273205
+ const r = spawnSync18(cmd, argv, { encoding: "utf8" });
272833
273206
  if (typeof r.stdout === "string" && r.stdout !== "")
272834
273207
  process.stdout.write(r.stdout);
272835
273208
  if (typeof r.stderr === "string" && r.stderr !== "")
@@ -272840,7 +273213,7 @@ function resolveRemoteVersion() {
272840
273213
  const pinned = process.env["ROLL_VERSION"];
272841
273214
  if (pinned !== void 0 && pinned !== "")
272842
273215
  return pinned;
272843
- const r = spawnSync19("curl", ["-fsSL", "-H", "Accept: application/vnd.github+json", "https://api.github.com/repos/seanyao/roll/releases/latest"], { encoding: "utf8" });
273216
+ const r = spawnSync18("curl", ["-fsSL", "-H", "Accept: application/vnd.github+json", "https://api.github.com/repos/seanyao/roll/releases/latest"], { encoding: "utf8" });
272844
273217
  let latest = "";
272845
273218
  if (r.status === 0 && typeof r.stdout === "string") {
272846
273219
  const mm = /"tag_name"\s*:\s*"([^"]*)"/.exec(r.stdout);
@@ -272865,7 +273238,7 @@ function downloadAndInstallCurl(tag) {
272865
273238
  }
272866
273239
  info5("[roll] Extracting ...");
272867
273240
  const extractDir = join116(tmpDir, "extract");
272868
- spawnSync19("mkdir", ["-p", extractDir], { stdio: "ignore" });
273241
+ spawnSync18("mkdir", ["-p", extractDir], { stdio: "ignore" });
272869
273242
  const ex = runForward2("tar", [
272870
273243
  "-xzf",
272871
273244
  join116(tmpDir, "roll.tar.gz"),
@@ -272883,16 +273256,16 @@ function downloadAndInstallCurl(tag) {
272883
273256
  }
272884
273257
  }
272885
273258
  function checkInstalledVersionOrRetry() {
272886
- const expected = (spawnSync19("npm", ["view", "@seanyao/roll", "version"], { encoding: "utf8" }).stdout ?? "").trim();
272887
- const pkgRoot = (spawnSync19("npm", ["root", "-g"], { encoding: "utf8" }).stdout ?? "").trim();
273259
+ const expected = (spawnSync18("npm", ["view", "@seanyao/roll", "version"], { encoding: "utf8" }).stdout ?? "").trim();
273260
+ const pkgRoot = (spawnSync18("npm", ["root", "-g"], { encoding: "utf8" }).stdout ?? "").trim();
272888
273261
  const installedTree = join116(pkgRoot, "@seanyao", "roll");
272889
273262
  const installed = treeVersion(installedTree);
272890
273263
  if (expected === "" || installed === "")
272891
273264
  return;
272892
273265
  if (installed !== expected) {
272893
273266
  warn5(m6("update.version_mismatch", installed, expected));
272894
- spawnSync19("npm", ["cache", "clean", "--force"], { stdio: "ignore" });
272895
- spawnSync19("npm", ["install", "-g", "@seanyao/roll@latest"], { stdio: "ignore" });
273267
+ spawnSync18("npm", ["cache", "clean", "--force"], { stdio: "ignore" });
273268
+ spawnSync18("npm", ["install", "-g", "@seanyao/roll@latest"], { stdio: "ignore" });
272896
273269
  const after = treeVersion(installedTree);
272897
273270
  if (after !== "" && after !== expected)
272898
273271
  warn5(m6("update.still_mismatch", after));
@@ -273102,7 +273475,7 @@ function registerAll() {
273102
273475
  });
273103
273476
  registerPorted("init", initCommand, { help: "Usage: roll init [--auto|--repair|--apply]\n Diagnose this project and route to scaffold, PRD design, existing-codebase onboard, repair, migration, or roll status.\n --auto: apply deterministic fresh-project scaffolding in non-interactive runs.\n --repair: repair partial Roll markers only.\n --apply: validate and apply a reviewed existing-codebase onboard plan.\n\u8BCA\u65AD\u9879\u76EE\u5E76\u8DEF\u7531\u5230\u9AA8\u67B6\u3001PRD \u8BBE\u8BA1\u3001\u5DF2\u6709\u4EE3\u7801\u5E93\u63A5\u5165\u3001\u4FEE\u590D\u3001\u8FC1\u79FB\u6216 roll status\u3002\n --apply\uFF1A\u6821\u9A8C\u5E76\u5E94\u7528\u5DF2\u5BA1\u9605\u7684\u5DF2\u6709\u4EE3\u7801\u5E93\u63A5\u5165\u8BA1\u5212\u3002" });
273104
273477
  registerPorted("next", nextCommand, { help: NEXT_USAGE });
273105
- registerPorted("design", designCommand, { help: 'Usage: roll design [--from-file <path> | "<requirement>"] [--agent <name>] [--verbose|--raw]\n Launch $roll-design interactively; --from-file binds a PRD/brief; quoted text binds a free-text requirement; --raw dumps the full transcript.\n\u4EA4\u4E92\u5F0F\u542F\u52A8 $roll-design\uFF1B--from-file \u7ED1\u5B9A PRD/brief\uFF1B\u5F15\u53F7\u6587\u672C\u7ED1\u5B9A\u81EA\u7531\u6587\u672C\u9700\u6C42\uFF1B--raw \u8F93\u51FA\u5B8C\u6574\u539F\u59CB\u8BB0\u5F55\u3002' });
273478
+ registerPorted("design", designCommand, { help: 'Usage: roll design [--from-file <path> | "<requirement>"] [--agent <name>] [--verbose|--raw]\n Launch $roll-design interactively with bounded live progress, card-created events, quiet heartbeats, and final handoff; --verbose streams lower-priority normalized activity; --raw streams raw child output live.\n\u4EA4\u4E92\u5F0F\u542F\u52A8 $roll-design\uFF1B\u9ED8\u8BA4\u5B9E\u65F6\u663E\u793A\u6709\u754C\u8FDB\u5C55\u3001\u5EFA\u5361\u4E8B\u4EF6\u3001\u9759\u9ED8\u5FC3\u8DF3\u548C\u6700\u7EC8\u4EA4\u4ED8\uFF1B--verbose \u663E\u793A\u66F4\u591A\u89C4\u8303\u5316\u6D3B\u52A8\uFF1B--raw \u5B9E\u65F6\u8F93\u51FA\u539F\u59CB\u6D41\u3002' });
273106
273479
  registerPorted("offboard", removedTopLevel("offboard"));
273107
273480
  registerPorted("setup", (args) => {
273108
273481
  if (args[0] === "skills") {
@@ -273114,7 +273487,7 @@ function registerAll() {
273114
273487
  if (args[0] === "offboard")
273115
273488
  return offboardCommand(args.slice(1));
273116
273489
  return setupCommand(args);
273117
- }, { help: "Usage: roll setup [skills|offboard]\n Install roll conventions/templates for this machine, or remove recorded Roll artifacts.\n\u672C\u673A\u5B89\u88C5\u6A21\u677F\uFF0C\u6216\u79FB\u9664\u8BB0\u5F55\u8FC7\u7684 Roll \u4EA7\u7269\u3002" });
273490
+ }, { help: "Usage: roll setup [-f|--force] [--reselect]\n roll setup skills [args...]\n roll setup offboard [args...]\n Install or re-sync Roll conventions/templates for this machine; use -f to force refresh.\n\u672C\u673A\u5B89\u88C5\u6216\u91CD\u65B0\u540C\u6B65 Roll \u6A21\u677F\u4E0E\u7EA6\u5B9A\uFF1B-f \u5F3A\u5236\u5237\u65B0\u3002" });
273118
273491
  registerPorted("ci", (args) => {
273119
273492
  if (args.includes("--wait"))
273120
273493
  return ciWaitCommand(args);