@seanyao/roll 4.702.3 → 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/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v4.702.4 — 2026-07-02
6
+
7
+ ### 可见性
8
+ - `roll design` 默认输出现在会实时显示有界进展、逐张建卡事件和静默心跳,同时继续把完整原始输出写入 transcript;`--verbose` 与 `--raw` 也改为运行中实时输出,不再等 agent 退出后回放(FIX-1071)`[legacy-onboard]`
9
+
5
10
  ## v4.702.3 — 2026-07-02
6
11
 
7
12
  ### 稳定性
package/README.md CHANGED
@@ -201,7 +201,7 @@ with `roll loop resume` when ready.
201
201
  | `roll agent [migrate\|list\|cast]` | Agent Scope, installed-agent inventory, and role casting |
202
202
  | `roll backlog [sync\|block\|defer\|lint\|…]` | View, manage, lint, and sync pending tasks |
203
203
  | `roll config [lang\|prices\|tune\|…]` | Read/write configuration, model prices, and suggest-only tuning |
204
- | `roll design [--from-file <path>] [--agent <name>]` | Launch `$roll-design` interactively; detailed designs get a self-contained Design Review Page |
204
+ | `roll design [--from-file <path>] [--agent <name>] [--verbose\|--raw]` | Launch `$roll-design` with bounded live progress, card-created events, quiet heartbeats, raw transcript capture, and a final handoff |
205
205
  | `roll doctor [skills\|tools\|language]` | Diagnose install health, skills, tools, permissions, and language drift |
206
206
  | `roll help [--lang en\|zh] [name]` | View built-in Charter / guide docs; `roll --help` prints CLI usage |
207
207
  | `roll idea "<one-sentence description>"` | Capture and classify a new backlog card |
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.",
@@ -233650,7 +233650,7 @@ __export(showcase_exports, {
233650
233650
  resetSandbox: () => resetSandbox,
233651
233651
  showcaseCommand: () => showcaseCommand
233652
233652
  });
233653
- import { spawnSync as spawnSync16 } from "node:child_process";
233653
+ import { spawnSync as spawnSync15 } from "node:child_process";
233654
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";
233655
233655
  import { tmpdir as tmpdir10 } from "node:os";
233656
233656
  import { dirname as dirname49, join as join109 } from "node:path";
@@ -233722,7 +233722,7 @@ function runRoll(sandbox, rollHome4, args, opts = {}) {
233722
233722
  }
233723
233723
  const bin = rollBin3();
233724
233724
  const [cmd, cmdArgs] = bin === "roll" ? [bin, args] : [process.execPath, [bin, ...args]];
233725
- const r = spawnSync16(cmd, cmdArgs, {
233725
+ const r = spawnSync15(cmd, cmdArgs, {
233726
233726
  cwd: sandbox,
233727
233727
  env,
233728
233728
  encoding: "utf8",
@@ -262247,8 +262247,8 @@ function nextCommand(args) {
262247
262247
  // packages/cli/dist/commands/design.js
262248
262248
  init_dist();
262249
262249
  init_dist2();
262250
- import { spawnSync as spawnSync12 } from "node:child_process";
262251
- import { existsSync as existsSync85, mkdirSync as mkdirSync37, readFileSync as readFileSync78, renameSync as renameSync16, statSync as statSync31, writeFileSync as writeFileSync39 } from "node:fs";
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
262252
  import { dirname as dirname39, join as join88, relative as relative6, resolve as resolve9 } from "node:path";
262253
262253
 
262254
262254
  // packages/cli/dist/lib/review-page.js
@@ -262635,7 +262635,7 @@ function lookupEpic(target, cwd) {
262635
262635
  function readBacklogItems(cwd) {
262636
262636
  try {
262637
262637
  const content = readFileSync78(join88(cwd, ".roll", "backlog.md"), "utf8");
262638
- return parseBacklog(content).map((row2) => ({ id: row2.id }));
262638
+ return parseBacklog(content).map((row2) => ({ id: row2.id, desc: row2.desc }));
262639
262639
  } catch {
262640
262640
  return [];
262641
262641
  }
@@ -262691,37 +262691,203 @@ function formatSignal(sig) {
262691
262691
  const detail = sig.detail !== void 0 && sig.detail !== "" ? ` ${sig.detail}` : "";
262692
262692
  return `${fmtHhmmss(sig.ts)} ${sig.summary}${detail}`.trimEnd();
262693
262693
  }
262694
- function progressLines(agent, combined, startMs, verbose) {
262695
- 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);
262696
262756
  const state = newNormalizerState();
262697
- const out3 = [];
262698
- const lines3 = combined.split("\n");
262699
- for (let i = 0; i < lines3.length; i += 1) {
262700
- const line = lines3[i] ?? "";
262701
- const nowMs = startMs + i * 1e3;
262702
- 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);
262703
262783
  for (const sig of signals) {
262704
- const show = verbose || sig.tier === "A" || sig.tier === "B" || sig.kind === "say" && isQuestionLike(sig.summary);
262705
- if (show) {
262706
- 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 = "";
262843
+ }
262844
+ if (stderrBuffer !== "") {
262845
+ processLine(stderrBuffer);
262846
+ stderrBuffer = "";
262707
262847
  }
262848
+ scanCards();
262708
262849
  }
262709
- }
262710
- return out3;
262850
+ };
262711
262851
  }
262712
262852
  var defaultDeps = {
262713
262853
  cwd: process.cwd(),
262714
262854
  env: process.env,
262715
262855
  readLine: readLineFromStdin,
262716
262856
  now: () => Date.now(),
262717
- spawn: (bin, args, opts) => {
262718
- const r = spawnSync12(bin, args, { ...opts, stdio: ["inherit", "pipe", "pipe"], encoding: "utf8" });
262719
- return {
262720
- status: r.status ?? null,
262721
- signal: r.signal ?? null,
262722
- stdout: typeof r.stdout === "string" ? r.stdout : "",
262723
- stderr: typeof r.stderr === "string" ? r.stderr : ""
262724
- };
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
+ });
262725
262891
  }
262726
262892
  };
262727
262893
  function selectAgent(installed, forced, envAgent, primary, readLine) {
@@ -262909,20 +263075,35 @@ function designCommand(args, deps = {}) {
262909
263075
  beforeBacklog: readBacklogItems(d.cwd)
262910
263076
  };
262911
263077
  printStartBlock(ctx);
262912
- const result = d.spawn(cmd.bin, cmd.args, { cwd: d.cwd, env: d.env });
262913
- const rawTranscript = [result.stdout ?? "", result.stderr ?? ""].filter((s) => s !== "").join("\n");
262914
- writeFileSync39(runTranscript, rawTranscript, "utf8");
262915
- if (rawMode) {
262916
- if (rawTranscript !== "")
262917
- emit4(rawTranscript);
262918
- } else {
262919
- const lines3 = progressLines(agent, rawTranscript, startTs, verbose);
262920
- for (const line of lines3)
262921
- 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
+ });
262922
263105
  }
262923
- const statusCode = result.status ?? (result.signal === null ? 1 : 130);
262924
- printHandoff(ctx, statusCode, rawTranscript);
262925
- return statusCode;
263106
+ return finish(spawned);
262926
263107
  }
262927
263108
 
262928
263109
  // packages/cli/dist/commands/loop-watch.js
@@ -262930,7 +263111,7 @@ init_dist();
262930
263111
  init_dist2();
262931
263112
  init_dist3();
262932
263113
  init_render();
262933
- import { spawn as spawn8, spawnSync as spawnSync13 } from "node:child_process";
263114
+ import { spawn as spawn8, spawnSync as spawnSync12 } from "node:child_process";
262934
263115
  import { existsSync as existsSync86, readFileSync as readFileSync79 } from "node:fs";
262935
263116
  import { join as join89 } from "node:path";
262936
263117
  import { createInterface as createInterface4 } from "node:readline";
@@ -263091,13 +263272,13 @@ function realDeps7() {
263091
263272
  render: (input, opts) => streamThroughRenderer(input, process.stdout, opts),
263092
263273
  renderEvents: streamEvents,
263093
263274
  tmuxState: probeWatchTmuxState,
263094
- tmuxRun: (argv) => spawnSync13("tmux", argv, { stdio: "ignore" }).status === 0,
263275
+ tmuxRun: (argv) => spawnSync12("tmux", argv, { stdio: "ignore" }).status === 0,
263095
263276
  tmuxAttach: (session) => {
263096
- spawnSync13("tmux", ["attach-session", "-r", "-t", session], { stdio: "inherit" });
263277
+ spawnSync12("tmux", ["attach-session", "-r", "-t", session], { stdio: "inherit" });
263097
263278
  },
263098
263279
  hasTmux: () => {
263099
263280
  try {
263100
- return spawnSync13("tmux", ["-V"], { stdio: "ignore" }).status === 0;
263281
+ return spawnSync12("tmux", ["-V"], { stdio: "ignore" }).status === 0;
263101
263282
  } catch {
263102
263283
  return false;
263103
263284
  }
@@ -263108,10 +263289,10 @@ function realDeps7() {
263108
263289
  }
263109
263290
  function probeWatchTmuxState(slug3) {
263110
263291
  const session = watchSessionName(slug3);
263111
- 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;
263112
263293
  if (!sessionExists)
263113
263294
  return { sessionExists: false, watchWindowExists: false };
263114
- 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" });
263115
263296
  const windows = listed.status === 0 ? String(listed.stdout ?? "").split("\n").map((w) => w.trim()) : [];
263116
263297
  return { sessionExists: true, watchWindowExists: windows.includes("watch") };
263117
263298
  }
@@ -263488,14 +263669,14 @@ ${RECONCILE_PENDING_USAGE}
263488
263669
 
263489
263670
  // packages/cli/dist/commands/loop-review-resize.js
263490
263671
  init_dist2();
263491
- import { appendFileSync as appendFileSync14, mkdirSync as mkdirSync39 } from "node:fs";
263672
+ import { appendFileSync as appendFileSync15, mkdirSync as mkdirSync39 } from "node:fs";
263492
263673
  import { dirname as dirname41, join as join92 } from "node:path";
263493
263674
  init_dist2();
263494
263675
 
263495
263676
  // packages/cli/dist/commands/loop-self-downgrade.js
263496
263677
  init_dist2();
263497
263678
  init_dist3();
263498
- 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";
263499
263680
  import { dirname as dirname40, join as join91 } from "node:path";
263500
263681
  function realSelfDowngradeDeps() {
263501
263682
  return {
@@ -263610,7 +263791,7 @@ async function loopSelfDowngradeCommand(argv, deps = realSelfDowngradeDeps()) {
263610
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`;
263611
263792
  try {
263612
263793
  mkdirSync38(dirname40(alertsPath), { recursive: true });
263613
- appendFileSync13(alertsPath, `[${isoUtc(ts2)}] ALERT ${headline}
263794
+ appendFileSync14(alertsPath, `[${isoUtc(ts2)}] ALERT ${headline}
263614
263795
  `, "utf8");
263615
263796
  } catch {
263616
263797
  }
@@ -263713,7 +263894,7 @@ For each sub-story create its .roll/features/<epic>/<id>/spec.md. Do NOT edit th
263713
263894
  const alertsPath = (process.env["ROLL_LOOP_ALERT"] ?? "").trim() || join92(rt, `ALERT-${projectSlug3(projectPath3)}.md`);
263714
263895
  try {
263715
263896
  mkdirSync39(dirname41(alertsPath), { recursive: true });
263716
- appendFileSync14(alertsPath, `[${new Date(ts2).toISOString()}] ALERT ${message}
263897
+ appendFileSync15(alertsPath, `[${new Date(ts2).toISOString()}] ALERT ${message}
263717
263898
  `, "utf8");
263718
263899
  } catch {
263719
263900
  }
@@ -263813,7 +263994,7 @@ async function loopExhaustionSplitCommand(argv, deps = realExhaustionSplitDeps()
263813
263994
  init_dist2();
263814
263995
  init_dist();
263815
263996
  init_dist3();
263816
- 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";
263817
263998
  import { dirname as dirname46, join as join103 } from "node:path";
263818
263999
 
263819
264000
  // packages/cli/dist/runner/executor.js
@@ -263862,7 +264043,7 @@ function writeCycleRoleSummaryBestEffort(cycleId, eventsPath3, cycleLogDir) {
263862
264043
 
263863
264044
  // packages/cli/dist/runner/executor.js
263864
264045
  import { execFile as execFile10, execFileSync as execFileSync22 } from "node:child_process";
263865
- 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";
263866
264047
  import { homedir as homedir27 } from "node:os";
263867
264048
  import { dirname as dirname43, join as join100 } from "node:path";
263868
264049
  import { promisify as promisify10 } from "node:util";
@@ -264515,7 +264696,7 @@ function autoAttachScreenshotToAcMap(worktreeCwd, storyId, runDir) {
264515
264696
  // packages/cli/dist/runner/correction-actuator.js
264516
264697
  init_dist2();
264517
264698
  init_dist();
264518
- 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";
264519
264700
  import { dirname as dirname42, join as join98 } from "node:path";
264520
264701
  function readMode(projectPath3) {
264521
264702
  try {
@@ -264537,7 +264718,7 @@ function readEvents4(eventsPath3) {
264537
264718
  function appendEvent(eventsPath3, event) {
264538
264719
  try {
264539
264720
  mkdirSync42(dirname42(eventsPath3), { recursive: true });
264540
- appendFileSync15(eventsPath3, `${JSON.stringify(event)}
264721
+ appendFileSync16(eventsPath3, `${JSON.stringify(event)}
264541
264722
  `, "utf8");
264542
264723
  } catch {
264543
264724
  }
@@ -264545,7 +264726,7 @@ function appendEvent(eventsPath3, event) {
264545
264726
  function appendAlert2(alertsPath, msg6) {
264546
264727
  try {
264547
264728
  mkdirSync42(dirname42(alertsPath), { recursive: true });
264548
- appendFileSync15(alertsPath, `${msg6}
264729
+ appendFileSync16(alertsPath, `${msg6}
264549
264730
  `, "utf8");
264550
264731
  } catch {
264551
264732
  }
@@ -265333,7 +265514,7 @@ var ActivitySignalRecorder = class {
265333
265514
  }
265334
265515
  append(signals) {
265335
265516
  try {
265336
- 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");
265337
265518
  } catch {
265338
265519
  }
265339
265520
  }
@@ -265702,7 +265883,7 @@ function createCaptureMarkerSink(runDir, capture) {
265702
265883
  const record = (marker, result) => {
265703
265884
  try {
265704
265885
  mkdirSync44(dirname43(logPath), { recursive: true });
265705
- appendFileSync16(logPath, JSON.stringify({ marker, result }) + "\n", "utf8");
265886
+ appendFileSync17(logPath, JSON.stringify({ marker, result }) + "\n", "utf8");
265706
265887
  } catch {
265707
265888
  }
265708
265889
  };
@@ -265948,7 +266129,7 @@ ${skillBodyForSpawn}` : skillBodyForSpawn;
265948
266129
  stallDetector.markProgress();
265949
266130
  captureSink?.onChunk(d);
265950
266131
  try {
265951
- appendFileSync16(livePath, d);
266132
+ appendFileSync17(livePath, d);
265952
266133
  } catch {
265953
266134
  }
265954
266135
  signalRecorder.accept(d);
@@ -267546,7 +267727,7 @@ async function linkRollIntoWorktree(repoCwd, worktreePath) {
267546
267727
  const cur = existsSync95(exclude) ? readFileSync89(exclude, "utf8") : "";
267547
267728
  if (!/^\.roll$/m.test(cur)) {
267548
267729
  mkdirSync44(dirname43(exclude), { recursive: true });
267549
- appendFileSync16(exclude, `${cur === "" || cur.endsWith("\n") ? "" : "\n"}.roll
267730
+ appendFileSync17(exclude, `${cur === "" || cur.endsWith("\n") ? "" : "\n"}.roll
267550
267731
  `, "utf8");
267551
267732
  }
267552
267733
  } catch {
@@ -268120,7 +268301,7 @@ function nodePorts(opts) {
268120
268301
  }
268121
268302
  function appendAlertLine(alertsPath, message) {
268122
268303
  mkdirSync44(dirname43(alertsPath), { recursive: true });
268123
- appendFileSync16(alertsPath, `${message}
268304
+ appendFileSync17(alertsPath, `${message}
268124
268305
  `, "utf8");
268125
268306
  }
268126
268307
 
@@ -268463,7 +268644,7 @@ async function warnIfBinaryStale(rollHomeDir2, runningVersion, appendAlert3) {
268463
268644
  // packages/cli/dist/runner/correction-circuit.js
268464
268645
  init_dist2();
268465
268646
  init_dist();
268466
- 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";
268467
268648
  import { dirname as dirname45, join as join102 } from "node:path";
268468
268649
  function readLoopSafety(projectPath3) {
268469
268650
  try {
@@ -268487,7 +268668,7 @@ function alreadyTripped(events, verdict) {
268487
268668
  }
268488
268669
  function appendEvent2(eventsPath3, event) {
268489
268670
  mkdirSync46(dirname45(eventsPath3), { recursive: true });
268490
- appendFileSync17(eventsPath3, `${JSON.stringify(event)}
268671
+ appendFileSync18(eventsPath3, `${JSON.stringify(event)}
268491
268672
  `, "utf8");
268492
268673
  }
268493
268674
  function applyCorrectionCircuitBreaker(projectPath3, slug3, eventsPath3, alertsPath, nowSec2 = Math.floor(Date.now() / 1e3)) {
@@ -268513,7 +268694,7 @@ function applyCorrectionCircuitBreaker(projectPath3, slug3, eventsPath3, alertsP
268513
268694
  if (pauseWritten)
268514
268695
  writeFileSync48(pauseMarker, alertMsg, "utf8");
268515
268696
  mkdirSync46(dirname45(alertsPath), { recursive: true });
268516
- appendFileSync17(alertsPath, `${alertMsg}
268697
+ appendFileSync18(alertsPath, `${alertMsg}
268517
268698
  `, "utf8");
268518
268699
  appendEvent2(eventsPath3, {
268519
268700
  type: "correction:circuit_breaker",
@@ -268533,7 +268714,7 @@ function applyCorrectionCircuitBreaker(projectPath3, slug3, eventsPath3, alertsP
268533
268714
 
268534
268715
  // packages/cli/dist/commands/loop-run-once.js
268535
268716
  init_dist();
268536
- 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";
268537
268718
  import { lookup as lookup2 } from "node:dns/promises";
268538
268719
  function announceReport(projectPath3, slug3, storyId, opener = (p) => {
268539
268720
  try {
@@ -268679,7 +268860,7 @@ function writeCardSkipAlert(alertsPath, eventsPath3, cycleId, storyId, count) {
268679
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.
268680
268861
  `;
268681
268862
  try {
268682
- appendFileSync18(alertsPath, `${msg6}
268863
+ appendFileSync19(alertsPath, `${msg6}
268683
268864
  `, "utf8");
268684
268865
  } catch {
268685
268866
  }
@@ -268726,7 +268907,7 @@ function incrementConsecutiveFails(projectPath3, slug3, alertsPath, eventsPath3,
268726
268907
  `;
268727
268908
  try {
268728
268909
  writeFileSync49(pauseMarker, alertMsg, "utf8");
268729
- appendFileSync18(alertsPath, `${alertMsg}
268910
+ appendFileSync19(alertsPath, `${alertMsg}
268730
268911
  `, "utf8");
268731
268912
  const ts2 = Date.now();
268732
268913
  const bus = new EventBus();
@@ -268893,7 +269074,7 @@ function writeReviewerBlockedAlert(projectPath3, slug3, alertsPath, eventsPath3,
268893
269074
  ` : "") + `**Action**: ${fix}
268894
269075
  `;
268895
269076
  try {
268896
- appendFileSync18(alertsPath, `${msg6}
269077
+ appendFileSync19(alertsPath, `${msg6}
268897
269078
  `, "utf8");
268898
269079
  } catch {
268899
269080
  }
@@ -269044,10 +269225,10 @@ async function loopRunOnceCommand(args) {
269044
269225
  const headline = t(v3Catalog, lang10, "loop.egress_blocked", cycleId);
269045
269226
  try {
269046
269227
  const ts2 = (/* @__PURE__ */ new Date()).toISOString();
269047
- appendFileSync18(alertsPath, `[${ts2}] ALERT ${headline}
269228
+ appendFileSync19(alertsPath, `[${ts2}] ALERT ${headline}
269048
269229
  `, "utf8");
269049
269230
  for (const line of guardLines)
269050
- appendFileSync18(alertsPath, `[${ts2}] ALERT ${line}
269231
+ appendFileSync19(alertsPath, `[${ts2}] ALERT ${line}
269051
269232
  `, "utf8");
269052
269233
  } catch {
269053
269234
  }
@@ -269072,7 +269253,7 @@ loop run-once: ${repoCheck.detail !== "" ? `(${repoCheck.detail})` : ""}
269072
269253
  if (skillBody === null) {
269073
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`;
269074
269255
  try {
269075
- appendFileSync18(alertsPath, `${msg6}
269256
+ appendFileSync19(alertsPath, `${msg6}
269076
269257
  `, "utf8");
269077
269258
  } catch {
269078
269259
  }
@@ -269106,7 +269287,7 @@ loop run-once: \u627E\u4E0D\u5230 roll-loop SKILL.md \u2014 \u62D2\u7EDD\u76F2\u
269106
269287
  try {
269107
269288
  await warnIfBinaryStale(rollHome(), rollVersion(), (msg6) => {
269108
269289
  try {
269109
- appendFileSync18(alertsPath, `${msg6}
269290
+ appendFileSync19(alertsPath, `${msg6}
269110
269291
  `, "utf8");
269111
269292
  } catch {
269112
269293
  }
@@ -269344,7 +269525,7 @@ function isLoopPaused(projectPath3, slug3) {
269344
269525
  }
269345
269526
  function checkRepoPushable(projectPath3) {
269346
269527
  const git4 = (args) => {
269347
- const r = spawnSync14("git", args, { cwd: projectPath3, encoding: "utf8" });
269528
+ const r = spawnSync13("git", args, { cwd: projectPath3, encoding: "utf8" });
269348
269529
  return { code: r.status ?? 1, stderr: r.stderr ?? "" };
269349
269530
  };
269350
269531
  const inside = git4(["rev-parse", "--git-dir"]);
@@ -269376,7 +269557,7 @@ function writeRepoAlert(alertsPath, eventsPath3, cycleId, result) {
269376
269557
  **Action**: ${t(v3Catalog, lang10, "loop.no_remote")}
269377
269558
  `;
269378
269559
  try {
269379
- appendFileSync18(alertsPath, `${msg6}
269560
+ appendFileSync19(alertsPath, `${msg6}
269380
269561
  `, "utf8");
269381
269562
  } catch {
269382
269563
  }
@@ -269393,7 +269574,7 @@ function writeRepoAlert(alertsPath, eventsPath3, cycleId, result) {
269393
269574
 
269394
269575
  // packages/cli/dist/commands/offboard.js
269395
269576
  init_dist();
269396
- import { spawnSync as spawnSync15 } from "node:child_process";
269577
+ import { spawnSync as spawnSync14 } from "node:child_process";
269397
269578
  import { existsSync as existsSync100, readFileSync as readFileSync94, realpathSync as realpathSync14, renameSync as renameSync18, rmSync as rmSync17, writeFileSync as writeFileSync50 } from "node:fs";
269398
269579
  import { homedir as homedir28 } from "node:os";
269399
269580
  import { join as join104, resolve as resolve10 } from "node:path";
@@ -269442,13 +269623,13 @@ function loopInCycle2() {
269442
269623
  function runLaunchctl(args) {
269443
269624
  const readOnly = /* @__PURE__ */ new Set(["print", "print-disabled", "list", "version", "dumpstate", "examine"]);
269444
269625
  if (args[0] !== void 0 && readOnly.has(args[0])) {
269445
- return spawnSync15("launchctl", args, { stdio: "inherit" }).status ?? 1;
269626
+ return spawnSync14("launchctl", args, { stdio: "inherit" }).status ?? 1;
269446
269627
  }
269447
269628
  const canonical = join104(homedir28(), "Library", "LaunchAgents");
269448
269629
  const launchdDir = process.env["_LAUNCHD_DIR"] ?? canonical;
269449
269630
  if (launchdDir !== canonical)
269450
269631
  return 0;
269451
- return spawnSync15("launchctl", args, { stdio: "inherit" }).status ?? 1;
269632
+ return spawnSync14("launchctl", args, { stdio: "inherit" }).status ?? 1;
269452
269633
  }
269453
269634
  var SECTIONS = ["files_merged", "files_created", "dirs_created", "gitignore_entries_added", "launchd_plists_installed"];
269454
269635
  function parseChangeset(text2) {
@@ -271991,7 +272172,7 @@ ${c("dim", "\u2192 Running the golden-path showcase (real models; its verdict do
271991
272172
  // packages/cli/dist/commands/setup.js
271992
272173
  init_dist();
271993
272174
  init_render();
271994
- import { spawnSync as spawnSync17 } from "node:child_process";
272175
+ import { spawnSync as spawnSync16 } from "node:child_process";
271995
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";
271996
272177
  import { join as join111 } from "node:path";
271997
272178
  function err13(line) {
@@ -272098,13 +272279,13 @@ function runSetupStep(watch, fn) {
272098
272279
  return before === after ? "unchanged" : "changed";
272099
272280
  }
272100
272281
  function ensureHooksPath(repoPath) {
272101
- 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;
272102
272283
  if (!inRepo)
272103
272284
  return;
272104
- const cur = spawnSync17("git", ["-C", repoPath, "config", "core.hooksPath"], { encoding: "utf8" });
272285
+ const cur = spawnSync16("git", ["-C", repoPath, "config", "core.hooksPath"], { encoding: "utf8" });
272105
272286
  const current = cur.status === 0 ? (cur.stdout ?? "").trim() : "";
272106
272287
  if (current === "" || current === ".git/hooks") {
272107
- spawnSync17("git", ["-C", repoPath, "config", "core.hooksPath", "hooks"], { stdio: "ignore" });
272288
+ spawnSync16("git", ["-C", repoPath, "config", "core.hooksPath", "hooks"], { stdio: "ignore" });
272108
272289
  }
272109
272290
  }
272110
272291
  function peerEnsureStateDir() {
@@ -272127,7 +272308,7 @@ function submoduleGuard() {
272127
272308
  empty = true;
272128
272309
  }
272129
272310
  if (hasGit && hasMods && empty) {
272130
- spawnSync17("git", ["submodule", "update", "--init", "--recursive", "--quiet"], {
272311
+ spawnSync16("git", ["submodule", "update", "--init", "--recursive", "--quiet"], {
272131
272312
  cwd: pkg,
272132
272313
  stdio: "ignore"
272133
272314
  });
@@ -272308,8 +272489,8 @@ function setupCommand(args) {
272308
272489
  init_showcase2();
272309
272490
 
272310
272491
  // packages/cli/dist/commands/test.js
272311
- import { spawnSync as spawnSync18 } from "node:child_process";
272312
- import { appendFileSync as appendFileSync19, existsSync as existsSync108, mkdirSync as mkdirSync53, readFileSync as readFileSync102, rmSync as rmSync19, writeFileSync as writeFileSync56 } from "node:fs";
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";
272313
272494
  import { dirname as dirname50, join as join112, resolve as resolve11 } from "node:path";
272314
272495
  function pal7() {
272315
272496
  const noColor2 = (process.env["NO_COLOR"] ?? "") !== "";
@@ -272367,7 +272548,7 @@ function appendRollTestEvidence(frame, cmd, argv, status2, stdout, stderr) {
272367
272548
  try {
272368
272549
  const ts2 = (/* @__PURE__ */ new Date()).toISOString();
272369
272550
  const command = [cmd, ...argv];
272370
- appendFileSync19(join112(frame.evidenceDir, "roll-test-output.log"), [
272551
+ appendFileSync20(join112(frame.evidenceDir, "roll-test-output.log"), [
272371
272552
  `===== roll test ${ts2} exit=${status2} =====`,
272372
272553
  `$ ${command.join(" ")}`,
272373
272554
  "--- stdout ---",
@@ -272376,7 +272557,7 @@ function appendRollTestEvidence(frame, cmd, argv, status2, stdout, stderr) {
272376
272557
  stderr,
272377
272558
  ""
272378
272559
  ].join("\n"), "utf8");
272379
- appendFileSync19(join112(frame.evidenceDir, "roll-test-summary.txt"), JSON.stringify({
272560
+ appendFileSync20(join112(frame.evidenceDir, "roll-test-summary.txt"), JSON.stringify({
272380
272561
  ts: ts2,
272381
272562
  command,
272382
272563
  exitCode: status2,
@@ -272456,7 +272637,7 @@ function resetReleaseLock() {
272456
272637
  }
272457
272638
  function runForward(cmd, argv) {
272458
272639
  const frame = currentEvidenceFrame();
272459
- const r = spawnSync18(cmd, argv, { encoding: "utf8", env: childEnvForEvidence(frame) });
272640
+ const r = spawnSync17(cmd, argv, { encoding: "utf8", env: childEnvForEvidence(frame) });
272460
272641
  const stdout = typeof r.stdout === "string" ? r.stdout : "";
272461
272642
  const stderr = typeof r.stderr === "string" ? r.stderr : "";
272462
272643
  const status2 = r.status ?? 1;
@@ -272474,7 +272655,7 @@ function ensureSkillsSubmoduleReady() {
272474
272655
  if (existsSync108(required2))
272475
272656
  return true;
272476
272657
  if (existsSync108(join112(pkg, ".git")) && existsSync108(join112(pkg, ".gitmodules"))) {
272477
- spawnSync18("git", ["submodule", "update", "--init", "--recursive", "--quiet", "skills"], {
272658
+ spawnSync17("git", ["submodule", "update", "--init", "--recursive", "--quiet", "skills"], {
272478
272659
  cwd: pkg,
272479
272660
  stdio: "ignore"
272480
272661
  });
@@ -272980,7 +273161,7 @@ function tuneCommand(argv) {
272980
273161
 
272981
273162
  // packages/cli/dist/commands/update.js
272982
273163
  init_dist();
272983
- import { spawnSync as spawnSync19 } from "node:child_process";
273164
+ import { spawnSync as spawnSync18 } from "node:child_process";
272984
273165
  import { existsSync as existsSync111, mkdtempSync as mkdtempSync9, readFileSync as readFileSync105, rmSync as rmSync20 } from "node:fs";
272985
273166
  import { tmpdir as tmpdir11 } from "node:os";
272986
273167
  import { join as join116 } from "node:path";
@@ -273021,7 +273202,7 @@ function m6(key, ...args) {
273021
273202
  return t(v2Catalog, msgLang10(), key, ...args);
273022
273203
  }
273023
273204
  function runForward2(cmd, argv) {
273024
- const r = spawnSync19(cmd, argv, { encoding: "utf8" });
273205
+ const r = spawnSync18(cmd, argv, { encoding: "utf8" });
273025
273206
  if (typeof r.stdout === "string" && r.stdout !== "")
273026
273207
  process.stdout.write(r.stdout);
273027
273208
  if (typeof r.stderr === "string" && r.stderr !== "")
@@ -273032,7 +273213,7 @@ function resolveRemoteVersion() {
273032
273213
  const pinned = process.env["ROLL_VERSION"];
273033
273214
  if (pinned !== void 0 && pinned !== "")
273034
273215
  return pinned;
273035
- 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" });
273036
273217
  let latest = "";
273037
273218
  if (r.status === 0 && typeof r.stdout === "string") {
273038
273219
  const mm = /"tag_name"\s*:\s*"([^"]*)"/.exec(r.stdout);
@@ -273057,7 +273238,7 @@ function downloadAndInstallCurl(tag) {
273057
273238
  }
273058
273239
  info5("[roll] Extracting ...");
273059
273240
  const extractDir = join116(tmpDir, "extract");
273060
- spawnSync19("mkdir", ["-p", extractDir], { stdio: "ignore" });
273241
+ spawnSync18("mkdir", ["-p", extractDir], { stdio: "ignore" });
273061
273242
  const ex = runForward2("tar", [
273062
273243
  "-xzf",
273063
273244
  join116(tmpDir, "roll.tar.gz"),
@@ -273075,16 +273256,16 @@ function downloadAndInstallCurl(tag) {
273075
273256
  }
273076
273257
  }
273077
273258
  function checkInstalledVersionOrRetry() {
273078
- const expected = (spawnSync19("npm", ["view", "@seanyao/roll", "version"], { encoding: "utf8" }).stdout ?? "").trim();
273079
- 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();
273080
273261
  const installedTree = join116(pkgRoot, "@seanyao", "roll");
273081
273262
  const installed = treeVersion(installedTree);
273082
273263
  if (expected === "" || installed === "")
273083
273264
  return;
273084
273265
  if (installed !== expected) {
273085
273266
  warn5(m6("update.version_mismatch", installed, expected));
273086
- spawnSync19("npm", ["cache", "clean", "--force"], { stdio: "ignore" });
273087
- 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" });
273088
273269
  const after = treeVersion(installedTree);
273089
273270
  if (after !== "" && after !== expected)
273090
273271
  warn5(m6("update.still_mismatch", after));
@@ -273294,7 +273475,7 @@ function registerAll() {
273294
273475
  });
273295
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" });
273296
273477
  registerPorted("next", nextCommand, { help: NEXT_USAGE });
273297
- 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' });
273298
273479
  registerPorted("offboard", removedTopLevel("offboard"));
273299
273480
  registerPorted("setup", (args) => {
273300
273481
  if (args[0] === "skills") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seanyao/roll",
3
- "version": "4.702.3",
3
+ "version": "4.702.4",
4
4
  "description": "Roll — Roll out features with AI agents",
5
5
  "packageManager": "pnpm@11.1.3",
6
6
  "scripts": {