@seanyao/roll 3.627.1 → 3.628.1

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,12 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v3.628.1 — 2026-06-28
6
+
7
+ ### 上手引导
8
+
9
+ - **`roll init` 给出的 PRD 下一步现在能直接运行**:`roll design --from-file <path>` 会校验输入文件并把 PRD/brief 绑定到 `$roll-design`,不再落到 usage。(#1065) `[legacy-onboard]`
10
+
5
11
  ## v3.627.1 — 2026-06-27
6
12
 
7
13
  ### 上手引导
package/README.md CHANGED
@@ -41,7 +41,8 @@ roll loop on # let AI work through the backlog (optional)
41
41
  `Already initialized` and `Next: roll status`; partial Roll projects get
42
42
  `roll init --repair`, while pre-2.0 layouts get migration guidance without writing files. Existing codebases route to
43
43
  `$roll-onboard`. PRD/docs-only workspaces are treated as new projects: Roll writes
44
- `.roll/brief.md` from the detected document and points to `roll design --from-file`.
44
+ `.roll/brief.md` from the detected document and points to
45
+ `roll design --from-file <detected-doc>`.
45
46
  Empty directories ask what you are building in an interactive terminal; in scripts
46
47
  and CI, plain `roll init` is read-only and `roll init --auto` writes a placeholder
47
48
  brief before pointing to `roll design`.
@@ -95,7 +96,7 @@ with `roll loop resume` when ready.
95
96
  | **Project · per repo** | |
96
97
  | `roll init` | Diagnose this directory and route to fresh scaffold, PRD/design handoff, existing-codebase onboard, repair, migration, or `roll status` |
97
98
  | `roll next` | Continue the init/onboard journey with one best next command: design, apply, repair, migrate, loop, or status |
98
- | `roll design [--agent <name>]` | Launch `$roll-design` interactively to turn requirements into a domain model + INVEST backlog |
99
+ | `roll design [--from-file <path>] [--agent <name>]` | Launch `$roll-design` interactively; `--from-file` binds a PRD/brief as the design input |
99
100
  | `roll offboard` | Remove Roll from this project |
100
101
  | `roll test [--where] [--reset]` | Run the test suite (routes through the isolation adapter; unknown types fail loud) |
101
102
  | `roll daemon <start\|stop\|status>` | Manage the read-only observability daemon (OPT-IN only; never auto-started) |
package/dist/roll.mjs CHANGED
@@ -2199,8 +2199,8 @@ var init_catalog_v3 = __esm({
2199
2199
  // `design.*` — explicit `roll design` entry point (US-ONBOARD-NUDGE-004).
2200
2200
  // Thin wrapper that launches the existing $roll-design skill interactively.
2201
2201
  "design.usage": {
2202
- en: "Usage: roll design [--agent <name>]\n Launch the $roll-design skill in an interactive agent conversation.\n `--agent` and `ROLL_DESIGN_AGENT` override the configured primary_agent.\n Unlike `roll init`, this command runs an LLM \u2014 run it only when you want to design.",
2203
- zh: "\u7528\u6CD5\uFF1Aroll design [--agent <name>]\n \u5728\u4EA4\u4E92\u5F0F agent \u5BF9\u8BDD\u4E2D\u542F\u52A8 $roll-design skill\u3002\n `--agent` \u4E0E `ROLL_DESIGN_AGENT` \u8986\u76D6\u5DF2\u914D\u7F6E\u7684 primary_agent\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"
2202
+ en: "Usage: roll design [--from-file <path>] [--agent <name>]\n Launch the $roll-design skill in an interactive agent conversation.\n `--from-file` binds a PRD/brief file as the design input.\n `--agent` and `ROLL_DESIGN_AGENT` override the configured primary_agent.\n Unlike `roll init`, this command runs an LLM \u2014 run it only when you want to design.",
2203
+ zh: "\u7528\u6CD5\uFF1Aroll design [--from-file <path>] [--agent <name>]\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 `--agent` \u4E0E `ROLL_DESIGN_AGENT` \u8986\u76D6\u5DF2\u914D\u7F6E\u7684 primary_agent\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"
2204
2204
  },
2205
2205
  "design.not_roll_project": {
2206
2206
  en: "This directory is not a Roll project (no .roll/). Run `roll init` first.",
@@ -2218,6 +2218,14 @@ var init_catalog_v3 = __esm({
2218
2218
  en: "Agent '%s' is unknown or not installed.",
2219
2219
  zh: "agent '%s' \u672A\u77E5\u6216\u672A\u5B89\u88C5\u3002"
2220
2220
  },
2221
+ "design.from_file_missing": {
2222
+ en: "`--from-file` requires a path.",
2223
+ zh: "`--from-file` \u9700\u8981\u4E00\u4E2A\u6587\u4EF6\u8DEF\u5F84\u3002"
2224
+ },
2225
+ "design.from_file_not_found": {
2226
+ en: "Design source file not found: %s",
2227
+ zh: "\u672A\u627E\u5230\u8BBE\u8BA1\u8F93\u5165\u6587\u4EF6\uFF1A%s"
2228
+ },
2221
2229
  // `setup.*` — primary agent selection during setup (US-ONBOARD-NUDGE-006).
2222
2230
  "setup.primary_prompt": {
2223
2231
  en: "Multiple AI agents detected. Pick a default:",
@@ -13611,7 +13619,7 @@ function isDaemonRunning(cwd, pidAlive = systemPidAlive) {
13611
13619
  return pidAlive(record.pid);
13612
13620
  }
13613
13621
  function spawnDaemon(cwd, opts) {
13614
- return new Promise((resolve9, reject) => {
13622
+ return new Promise((resolve10, reject) => {
13615
13623
  const host = opts.host ?? "127.0.0.1";
13616
13624
  const port = opts.port ?? 7077;
13617
13625
  const entrypoint = resolveCliEntrypoint(opts);
@@ -13652,7 +13660,7 @@ function spawnDaemon(cwd, opts) {
13652
13660
  finish(reject, new Error("Daemon child did not expose a pid"));
13653
13661
  return;
13654
13662
  }
13655
- finish(resolve9, { child, pid, address: addr });
13663
+ finish(resolve10, { child, pid, address: addr });
13656
13664
  }
13657
13665
  };
13658
13666
  const onErr = (data) => {
@@ -14633,16 +14641,16 @@ async function crontabRead() {
14633
14641
  }
14634
14642
  }
14635
14643
  async function crontabWrite(text2) {
14636
- return new Promise((resolve9, reject) => {
14644
+ return new Promise((resolve10, reject) => {
14637
14645
  const child = execFile4("crontab", ["-"], (err16) => {
14638
14646
  if (err16 === null) {
14639
- resolve9(0);
14647
+ resolve10(0);
14640
14648
  } else if (typeof err16.code === "number") {
14641
- resolve9(err16.code);
14649
+ resolve10(err16.code);
14642
14650
  } else if (err16.code === "ENOENT") {
14643
14651
  reject(err16);
14644
14652
  } else {
14645
- resolve9(1);
14653
+ resolve10(1);
14646
14654
  }
14647
14655
  });
14648
14656
  child.stdin?.end(text2);
@@ -16686,14 +16694,14 @@ var init_mcp = __esm({
16686
16694
  child.on("exit", () => this.rejectAll(new Error("MCP server exited")));
16687
16695
  }
16688
16696
  static async open(child) {
16689
- await new Promise((resolve9, reject) => {
16697
+ await new Promise((resolve10, reject) => {
16690
16698
  const onError = (cause) => {
16691
16699
  child.off("spawn", onSpawn);
16692
16700
  reject(cause);
16693
16701
  };
16694
16702
  const onSpawn = () => {
16695
16703
  child.off("error", onError);
16696
- resolve9();
16704
+ resolve10();
16697
16705
  };
16698
16706
  child.once("error", onError);
16699
16707
  child.once("spawn", onSpawn);
@@ -16722,8 +16730,8 @@ var init_mcp = __esm({
16722
16730
  const id = this.nextId;
16723
16731
  this.nextId += 1;
16724
16732
  const message = { jsonrpc: "2.0", id, method, params };
16725
- return new Promise((resolve9, reject) => {
16726
- this.pending.set(id, { resolve: resolve9, reject });
16733
+ return new Promise((resolve10, reject) => {
16734
+ this.pending.set(id, { resolve: resolve10, reject });
16727
16735
  this.write(message);
16728
16736
  });
16729
16737
  }
@@ -16818,7 +16826,7 @@ async function requestWithRedirects(url, input, deps, timeoutMs, redirects, star
16818
16826
  return response;
16819
16827
  }
16820
16828
  function requestOnce(url, input, deps, timeoutMs, startedAt) {
16821
- return new Promise((resolve9, reject) => {
16829
+ return new Promise((resolve10, reject) => {
16822
16830
  const proxy = proxyFor(url);
16823
16831
  const viaProxy = proxy !== void 0;
16824
16832
  const requestUrl = viaProxy ? proxy : url;
@@ -16840,7 +16848,7 @@ function requestOnce(url, input, deps, timeoutMs, startedAt) {
16840
16848
  });
16841
16849
  res.on("end", () => {
16842
16850
  clearTimeout(timer);
16843
- resolve9({
16851
+ resolve10({
16844
16852
  statusCode: res.statusCode ?? 0,
16845
16853
  headers: normalizeHeaders(res.headers),
16846
16854
  body: deps.redact(Buffer.concat(chunks).toString("utf8")),
@@ -16894,7 +16902,7 @@ function isTimeout(cause) {
16894
16902
  function delay(ms) {
16895
16903
  if (ms <= 0)
16896
16904
  return Promise.resolve();
16897
- return new Promise((resolve9) => setTimeout(resolve9, ms));
16905
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
16898
16906
  }
16899
16907
  function failure4(invocation, startedAt, endedAt, code, message, retryable, detail, attempt) {
16900
16908
  return {
@@ -25887,7 +25895,7 @@ ${lanes.join("\n")}
25887
25895
  return process.memoryUsage().heapUsed;
25888
25896
  },
25889
25897
  getFileSize(path) {
25890
- const stat = statSync35(path);
25898
+ const stat = statSync36(path);
25891
25899
  if (stat == null ? void 0 : stat.isFile()) {
25892
25900
  return stat.size;
25893
25901
  }
@@ -25931,7 +25939,7 @@ ${lanes.join("\n")}
25931
25939
  }
25932
25940
  };
25933
25941
  return nodeSystem;
25934
- function statSync35(path) {
25942
+ function statSync36(path) {
25935
25943
  try {
25936
25944
  return _fs.statSync(path, statSyncOptions);
25937
25945
  } catch {
@@ -25990,7 +25998,7 @@ ${lanes.join("\n")}
25990
25998
  activeSession.post("Profiler.stop", (err16, { profile }) => {
25991
25999
  var _a;
25992
26000
  if (!err16) {
25993
- if ((_a = statSync35(profilePath)) == null ? void 0 : _a.isDirectory()) {
26001
+ if ((_a = statSync36(profilePath)) == null ? void 0 : _a.isDirectory()) {
25994
26002
  profilePath = _path.join(profilePath, `${(/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-")}+P${process.pid}.cpuprofile`);
25995
26003
  }
25996
26004
  try {
@@ -26110,7 +26118,7 @@ ${lanes.join("\n")}
26110
26118
  let stat;
26111
26119
  if (typeof dirent === "string" || dirent.isSymbolicLink()) {
26112
26120
  const name = combinePaths(path, entry);
26113
- stat = statSync35(name);
26121
+ stat = statSync36(name);
26114
26122
  if (!stat) {
26115
26123
  continue;
26116
26124
  }
@@ -26134,7 +26142,7 @@ ${lanes.join("\n")}
26134
26142
  return matchFiles(path, extensions, excludes, includes, useCaseSensitiveFileNames2, process.cwd(), depth, getAccessibleFileSystemEntries, realpath2);
26135
26143
  }
26136
26144
  function fileSystemEntryExists(path, entryKind) {
26137
- const stat = statSync35(path);
26145
+ const stat = statSync36(path);
26138
26146
  if (!stat) {
26139
26147
  return false;
26140
26148
  }
@@ -26176,7 +26184,7 @@ ${lanes.join("\n")}
26176
26184
  }
26177
26185
  function getModifiedTime3(path) {
26178
26186
  var _a;
26179
- return (_a = statSync35(path)) == null ? void 0 : _a.mtime;
26187
+ return (_a = statSync36(path)) == null ? void 0 : _a.mtime;
26180
26188
  }
26181
26189
  function setModifiedTime(path, time) {
26182
26190
  try {
@@ -141529,7 +141537,7 @@ ${lanes.join("\n")}
141529
141537
  }
141530
141538
  }
141531
141539
  function createImportCallExpressionAMD(arg, containsLexicalThis) {
141532
- const resolve9 = factory2.createUniqueName("resolve");
141540
+ const resolve10 = factory2.createUniqueName("resolve");
141533
141541
  const reject = factory2.createUniqueName("reject");
141534
141542
  const parameters = [
141535
141543
  factory2.createParameterDeclaration(
@@ -141538,7 +141546,7 @@ ${lanes.join("\n")}
141538
141546
  /*dotDotDotToken*/
141539
141547
  void 0,
141540
141548
  /*name*/
141541
- resolve9
141549
+ resolve10
141542
141550
  ),
141543
141551
  factory2.createParameterDeclaration(
141544
141552
  /*modifiers*/
@@ -141555,7 +141563,7 @@ ${lanes.join("\n")}
141555
141563
  factory2.createIdentifier("require"),
141556
141564
  /*typeArguments*/
141557
141565
  void 0,
141558
- [factory2.createArrayLiteralExpression([arg || factory2.createOmittedExpression()]), resolve9, reject]
141566
+ [factory2.createArrayLiteralExpression([arg || factory2.createOmittedExpression()]), resolve10, reject]
141559
141567
  )
141560
141568
  )
141561
141569
  ]);
@@ -228486,8 +228494,8 @@ Additional information: BADCLIENT: Bad error code, ${badCode} not found in range
228486
228494
  installPackage(options) {
228487
228495
  this.packageInstallId++;
228488
228496
  const request = { kind: "installPackage", ...options, id: this.packageInstallId };
228489
- const promise = new Promise((resolve9, reject) => {
228490
- (this.packageInstalledPromise ?? (this.packageInstalledPromise = /* @__PURE__ */ new Map())).set(this.packageInstallId, { resolve: resolve9, reject });
228497
+ const promise = new Promise((resolve10, reject) => {
228498
+ (this.packageInstalledPromise ?? (this.packageInstalledPromise = /* @__PURE__ */ new Map())).set(this.packageInstallId, { resolve: resolve10, reject });
228491
228499
  });
228492
228500
  this.installer.send(request);
228493
228501
  return promise;
@@ -229468,7 +229476,7 @@ __export(showcase_exports, {
229468
229476
  showcaseCommand: () => showcaseCommand
229469
229477
  });
229470
229478
  import { spawnSync as spawnSync15 } from "node:child_process";
229471
- import { cpSync as cpSync2, existsSync as existsSync101, mkdirSync as mkdirSync49, mkdtempSync as mkdtempSync8, readdirSync as readdirSync39, readFileSync as readFileSync95, rmSync as rmSync19, statSync as statSync32, writeFileSync as writeFileSync51 } from "node:fs";
229479
+ import { cpSync as cpSync2, existsSync as existsSync101, mkdirSync as mkdirSync49, mkdtempSync as mkdtempSync8, readdirSync as readdirSync39, readFileSync as readFileSync95, rmSync as rmSync19, statSync as statSync33, writeFileSync as writeFileSync51 } from "node:fs";
229472
229480
  import { tmpdir as tmpdir10 } from "node:os";
229473
229481
  import { dirname as dirname47, join as join106 } from "node:path";
229474
229482
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -229549,7 +229557,7 @@ function runRoll(sandbox, rollHome4, args, opts = {}) {
229549
229557
  }
229550
229558
  function fileNonEmpty3(p) {
229551
229559
  try {
229552
- return existsSync101(p) && statSync32(p).size > 0;
229560
+ return existsSync101(p) && statSync33(p).size > 0;
229553
229561
  } catch {
229554
229562
  return false;
229555
229563
  }
@@ -229584,7 +229592,7 @@ function findCardSpec2(sandbox, card) {
229584
229592
  const full = join106(dir, name);
229585
229593
  let isDir4 = false;
229586
229594
  try {
229587
- isDir4 = statSync32(full).isDirectory();
229595
+ isDir4 = statSync33(full).isDirectory();
229588
229596
  } catch {
229589
229597
  continue;
229590
229598
  }
@@ -229982,7 +229990,7 @@ function networkNeeds(command, args) {
229982
229990
  }
229983
229991
  }
229984
229992
  function tcpConnect(host, port, timeoutMs) {
229985
- return new Promise((resolve9, reject) => {
229993
+ return new Promise((resolve10, reject) => {
229986
229994
  const socket = createConnection({ host, port });
229987
229995
  let settled = false;
229988
229996
  const done = (err16) => {
@@ -229994,7 +230002,7 @@ function tcpConnect(host, port, timeoutMs) {
229994
230002
  if (err16)
229995
230003
  reject(err16);
229996
230004
  else
229997
- resolve9();
230005
+ resolve10();
229998
230006
  };
229999
230007
  socket.setTimeout(timeoutMs, () => done(new Error("tcp timeout")));
230000
230008
  socket.once("connect", () => done());
@@ -230006,11 +230014,11 @@ async function networkReachable(probes = {}) {
230006
230014
  host: PROBE_HOST,
230007
230015
  port: PROBE_PORT
230008
230016
  };
230009
- const resolve9 = probes.resolve ?? ((h) => lookup(h));
230017
+ const resolve10 = probes.resolve ?? ((h) => lookup(h));
230010
230018
  const tcpProbe2 = probes.tcpProbe ?? (() => tcpConnect(target.host, target.port, TCP_TIMEOUT_MS));
230011
230019
  try {
230012
230020
  await Promise.race([
230013
- resolve9(target.host),
230021
+ resolve10(target.host),
230014
230022
  new Promise((_, rej) => {
230015
230023
  const timer = setTimeout(() => rej(new Error("dns timeout")), DNS_TIMEOUT_MS);
230016
230024
  if (typeof timer === "object")
@@ -230456,7 +230464,7 @@ function withAgentProfileEnv(agent, opts) {
230456
230464
  function spawnAndWait(bin, args, opts, pty = false) {
230457
230465
  process.stderr.write(`[runner] spawn ${bin} argv=${JSON.stringify(args.map((a) => a.length > 80 ? `${a.slice(0, 77)}...` : a))}
230458
230466
  `);
230459
- return new Promise((resolve9) => {
230467
+ return new Promise((resolve10) => {
230460
230468
  const child = spawn3(bin, args, {
230461
230469
  cwd: opts.cwd,
230462
230470
  env: childEnv(opts),
@@ -230492,7 +230500,7 @@ function spawnAndWait(bin, args, opts, pty = false) {
230492
230500
  liveAgents.delete(child);
230493
230501
  if (timer !== void 0)
230494
230502
  clearTimeout(timer);
230495
- resolve9(result);
230503
+ resolve10(result);
230496
230504
  };
230497
230505
  child.on("error", (e) => {
230498
230506
  settle({ stdout, stderr: `${stderr}${String(e)}
@@ -230519,13 +230527,13 @@ function realDeps() {
230519
230527
  sharedRoot: () => process.env["ROLL_SHARED_ROOT"] || join20(homedir5(), ".shared", "roll"),
230520
230528
  launchdDir: () => join20(homedir5(), "Library", "LaunchAgents"),
230521
230529
  scheduler: createScheduler(process.platform, { uid: process.getuid?.() ?? 501 }),
230522
- execRunner: (runner) => new Promise((resolve9) => {
230530
+ execRunner: (runner) => new Promise((resolve10) => {
230523
230531
  const child = spawn4("bash", [runner], {
230524
230532
  stdio: "inherit",
230525
230533
  env: { ...process.env, ROLL_LOOP_FORCE: "1" }
230526
230534
  });
230527
- child.on("exit", (code) => resolve9(code ?? 1));
230528
- child.on("error", () => resolve9(1));
230535
+ child.on("exit", (code) => resolve10(code ?? 1));
230536
+ child.on("error", () => resolve10(1));
230529
230537
  }),
230530
230538
  hasTmux: () => {
230531
230539
  try {
@@ -230536,7 +230544,7 @@ function realDeps() {
230536
230544
  },
230537
230545
  // The `loop now` inline observation: tail live.log while the cycle holds
230538
230546
  // the inner lock; Ctrl-C stops the TAIL only (the cycle lives in tmux).
230539
- observe: (rt) => new Promise((resolve9) => {
230547
+ observe: (rt) => new Promise((resolve10) => {
230540
230548
  const lock = join20(rt, "inner.lock");
230541
230549
  const tail3 = spawn4("tail", ["-n", "+1", "-F", join20(rt, "live.log")], { stdio: "inherit" });
230542
230550
  let sawLock = false;
@@ -230547,7 +230555,7 @@ function realDeps() {
230547
230555
  } catch {
230548
230556
  }
230549
230557
  process.removeListener("SIGINT", finish);
230550
- resolve9();
230558
+ resolve10();
230551
230559
  };
230552
230560
  const timer = setInterval(() => {
230553
230561
  if (existsSync16(lock))
@@ -242663,7 +242671,7 @@ function reviewTimeoutMs(diffChars) {
242663
242671
  async function firstValid(promises) {
242664
242672
  if (promises.length === 0)
242665
242673
  return null;
242666
- return new Promise((resolve9, reject) => {
242674
+ return new Promise((resolve10, reject) => {
242667
242675
  let pending = promises.length;
242668
242676
  let settled = false;
242669
242677
  let lastError;
@@ -242675,7 +242683,7 @@ async function firstValid(promises) {
242675
242683
  if (threw)
242676
242684
  reject(lastError);
242677
242685
  else
242678
- resolve9(null);
242686
+ resolve10(null);
242679
242687
  }
242680
242688
  };
242681
242689
  for (const p of promises) {
@@ -242684,7 +242692,7 @@ async function firstValid(promises) {
242684
242692
  return;
242685
242693
  if (value !== null) {
242686
242694
  settled = true;
242687
- resolve9(value);
242695
+ resolve10(value);
242688
242696
  return;
242689
242697
  }
242690
242698
  onNonResult();
@@ -243641,7 +243649,7 @@ function spawnPeerReviewAgent(input) {
243641
243649
  const cmd = textAgentArgv(input.agent, input.prompt);
243642
243650
  if (cmd === null)
243643
243651
  return Promise.resolve({ status: "error", reason: "unsupported_reviewer", stdout: "" });
243644
- return new Promise((resolve9) => {
243652
+ return new Promise((resolve10) => {
243645
243653
  let stdout = "";
243646
243654
  let stderr = "";
243647
243655
  let timedOut = false;
@@ -243659,7 +243667,7 @@ function spawnPeerReviewAgent(input) {
243659
243667
  settled = true;
243660
243668
  if (timer !== void 0)
243661
243669
  clearTimeout(timer);
243662
- resolve9(result);
243670
+ resolve10(result);
243663
243671
  };
243664
243672
  timer = setTimeout(() => {
243665
243673
  timedOut = true;
@@ -247831,8 +247839,8 @@ Sec-WebSocket-Accept: ${acceptKey}\r
247831
247839
  }
247832
247840
  }
247833
247841
  clients.clear();
247834
- return new Promise((resolve9) => {
247835
- server2.close(() => resolve9());
247842
+ return new Promise((resolve10) => {
247843
+ server2.close(() => resolve10());
247836
247844
  });
247837
247845
  };
247838
247846
  return {
@@ -249251,7 +249259,7 @@ function realDeps4() {
249251
249259
  startTmux: startGoTmux,
249252
249260
  followFeed: followGoLiveFeed,
249253
249261
  runOnce: realRunOnce,
249254
- sleep: (ms) => new Promise((resolve9) => setTimeout(resolve9, ms)),
249262
+ sleep: (ms) => new Promise((resolve10) => setTimeout(resolve10, ms)),
249255
249263
  externalTools: guideExternalToolSetup,
249256
249264
  preinstallChromium: () => {
249257
249265
  silentPreinstallChromium();
@@ -249528,7 +249536,7 @@ function startGoTmux(input) {
249528
249536
  }
249529
249537
  }
249530
249538
  function followGoLiveFeed(projectPath3, rollBin4) {
249531
- return new Promise((resolve9) => {
249539
+ return new Promise((resolve10) => {
249532
249540
  const cmd = rollBin4.endsWith(".js") || rollBin4.endsWith(".mjs") ? process.execPath : rollBin4;
249533
249541
  const args = rollBin4.endsWith(".js") || rollBin4.endsWith(".mjs") ? [rollBin4, "loop", "watch", "--since", "all"] : ["loop", "watch", "--since", "all"];
249534
249542
  const watch2 = spawn7(cmd, args, { cwd: projectPath3, stdio: ["ignore", "inherit", "inherit"] });
@@ -249538,7 +249546,7 @@ function followGoLiveFeed(projectPath3, rollBin4) {
249538
249546
  } catch {
249539
249547
  }
249540
249548
  process.removeListener("SIGINT", finish);
249541
- resolve9();
249549
+ resolve10();
249542
249550
  };
249543
249551
  process.on("SIGINT", finish);
249544
249552
  watch2.on("exit", finish);
@@ -249549,7 +249557,7 @@ function realRunOnce(input) {
249549
249557
  const bin = rollBin();
249550
249558
  const cmd = bin.endsWith(".js") || bin.endsWith(".mjs") ? process.execPath : bin;
249551
249559
  const args = cmd === process.execPath ? [bin, "loop", "run-once"] : ["loop", "run-once"];
249552
- return new Promise((resolve9) => {
249560
+ return new Promise((resolve10) => {
249553
249561
  const child = spawn7(cmd, args, {
249554
249562
  cwd: input.projectPath,
249555
249563
  detached: true,
@@ -249563,8 +249571,8 @@ function realRunOnce(input) {
249563
249571
  },
249564
249572
  stdio: "inherit"
249565
249573
  });
249566
- child.on("exit", (code) => resolve9(code ?? 1));
249567
- child.on("error", () => resolve9(1));
249574
+ child.on("exit", (code) => resolve10(code ?? 1));
249575
+ child.on("error", () => resolve10(1));
249568
249576
  });
249569
249577
  }
249570
249578
  function writeGoal(path, goal) {
@@ -254856,8 +254864,8 @@ function nextCommand(args) {
254856
254864
  // packages/cli/dist/commands/design.js
254857
254865
  init_dist();
254858
254866
  import { spawnSync as spawnSync10 } from "node:child_process";
254859
- import { existsSync as existsSync80 } from "node:fs";
254860
- import { join as join83 } from "node:path";
254867
+ import { existsSync as existsSync80, statSync as statSync28 } from "node:fs";
254868
+ import { join as join83, resolve as resolve7 } from "node:path";
254861
254869
  function lang8() {
254862
254870
  return currentLang();
254863
254871
  }
@@ -254865,17 +254873,24 @@ function emit3(line) {
254865
254873
  process.stderr.write(`${line}
254866
254874
  `);
254867
254875
  }
254868
- function readDesignPrompt() {
254876
+ function readDesignPrompt(fromFile) {
254869
254877
  const body = readSkillBody2("roll-design");
254870
254878
  if (body === null)
254871
254879
  return null;
254872
- return `Run the $roll-design skill below for this project. Follow it end-to-end.
254880
+ const handoff = fromFile === void 0 ? "" : [
254881
+ `The user invoked \`roll design --from-file ${fromFile}\`.`,
254882
+ `Use this product brief file as the design input: ${fromFile}`,
254883
+ "Read it before asking broad discovery questions, then run the $roll-design workflow.",
254884
+ ""
254885
+ ].join("\n");
254886
+ return `${handoff}Run the $roll-design skill below for this project. Follow it end-to-end.
254873
254887
 
254874
254888
  ${body}`;
254875
254889
  }
254876
- function parseAgentFlag(args) {
254890
+ function parseDesignFlags(args) {
254877
254891
  const rest = [];
254878
254892
  let agent;
254893
+ let fromFile;
254879
254894
  for (let i = 0; i < args.length; i += 1) {
254880
254895
  const a = args[i] ?? "";
254881
254896
  if (a === "--agent") {
@@ -254883,15 +254898,34 @@ function parseAgentFlag(args) {
254883
254898
  i += 1;
254884
254899
  } else if (a.startsWith("--agent=")) {
254885
254900
  agent = a.slice("--agent=".length);
254901
+ } else if (a === "--from-file") {
254902
+ const value = args[i + 1];
254903
+ if (value === void 0 || value === "" || value.startsWith("-")) {
254904
+ return { agent, fromFile, rest, error: "from_file_missing" };
254905
+ }
254906
+ fromFile = value;
254907
+ i += 1;
254908
+ } else if (a.startsWith("--from-file=")) {
254909
+ const value = a.slice("--from-file=".length);
254910
+ if (value === "")
254911
+ return { agent, fromFile, rest, error: "from_file_missing" };
254912
+ fromFile = value;
254886
254913
  } else {
254887
254914
  rest.push(a);
254888
254915
  }
254889
254916
  }
254890
- return { agent, rest };
254917
+ return { agent, fromFile, rest, error: null };
254891
254918
  }
254892
254919
  function isRollProject(cwd) {
254893
254920
  return existsSync80(join83(cwd, ".roll"));
254894
254921
  }
254922
+ function isRegularFile(path) {
254923
+ try {
254924
+ return statSync28(path).isFile();
254925
+ } catch {
254926
+ return false;
254927
+ }
254928
+ }
254895
254929
  var defaultDeps = {
254896
254930
  cwd: process.cwd(),
254897
254931
  env: process.env,
@@ -254948,7 +254982,13 @@ function designCommand(args, deps = {}) {
254948
254982
  `);
254949
254983
  return 0;
254950
254984
  }
254951
- const { agent: forced, rest } = parseAgentFlag(args);
254985
+ const { agent: forced, fromFile, rest, error: parseError } = parseDesignFlags(args);
254986
+ if (parseError === "from_file_missing") {
254987
+ emit3(t(v3Catalog, l, "design.from_file_missing"));
254988
+ process.stderr.write(`${t(v3Catalog, l, "design.usage")}
254989
+ `);
254990
+ return 1;
254991
+ }
254952
254992
  if (rest.some((a) => a.startsWith("-"))) {
254953
254993
  process.stderr.write(`${t(v3Catalog, l, "design.usage")}
254954
254994
  `);
@@ -254958,7 +254998,11 @@ function designCommand(args, deps = {}) {
254958
254998
  emit3(t(v3Catalog, l, "design.not_roll_project"));
254959
254999
  return 1;
254960
255000
  }
254961
- const prompt = readDesignPrompt();
255001
+ if (fromFile !== void 0 && !isRegularFile(resolve7(d.cwd, fromFile))) {
255002
+ emit3(t(v3Catalog, l, "design.from_file_not_found", fromFile));
255003
+ return 1;
255004
+ }
255005
+ const prompt = readDesignPrompt(fromFile);
254962
255006
  if (prompt === null) {
254963
255007
  emit3(t(v3Catalog, l, "design.skill_missing"));
254964
255008
  return 1;
@@ -255293,7 +255337,7 @@ init_dist3();
255293
255337
  init_dist2();
255294
255338
  init_dist();
255295
255339
  import { spawnSync as spawnSync12 } from "node:child_process";
255296
- import { existsSync as existsSync82, mkdirSync as mkdirSync33, readFileSync as readFileSync74, readdirSync as readdirSync30, renameSync as renameSync14, rmSync as rmSync14, statSync as statSync28, writeFileSync as writeFileSync33 } from "node:fs";
255340
+ import { existsSync as existsSync82, mkdirSync as mkdirSync33, readFileSync as readFileSync74, readdirSync as readdirSync30, renameSync as renameSync14, rmSync as rmSync14, statSync as statSync29, writeFileSync as writeFileSync33 } from "node:fs";
255297
255341
  import { homedir as homedir22 } from "node:os";
255298
255342
  import { basename as basename15, dirname as dirname33, join as join85 } from "node:path";
255299
255343
  function palette3() {
@@ -255372,7 +255416,7 @@ function realGcDeps() {
255372
255416
  }
255373
255417
  function fileMtimeSec(f) {
255374
255418
  try {
255375
- return Math.floor(statSync28(f).mtimeMs / 1e3);
255419
+ return Math.floor(statSync29(f).mtimeMs / 1e3);
255376
255420
  } catch {
255377
255421
  return 0;
255378
255422
  }
@@ -255387,7 +255431,7 @@ function plistWorkingDir(plistPath) {
255387
255431
  }
255388
255432
  function isDir3(p) {
255389
255433
  try {
255390
- return statSync28(p).isDirectory();
255434
+ return statSync29(p).isDirectory();
255391
255435
  } catch {
255392
255436
  return false;
255393
255437
  }
@@ -255532,7 +255576,7 @@ function loopGcCommand(args = [], deps = realGcDeps()) {
255532
255576
  }
255533
255577
  function statSafeIsFile(f) {
255534
255578
  try {
255535
- return statSync28(f).isFile();
255579
+ return statSync29(f).isFile();
255536
255580
  } catch {
255537
255581
  return false;
255538
255582
  }
@@ -256636,7 +256680,7 @@ init_dist2();
256636
256680
  init_dist();
256637
256681
  init_dist3();
256638
256682
  import { execFile as execFile10, execFileSync as execFileSync21 } from "node:child_process";
256639
- import { appendFileSync as appendFileSync16, existsSync as existsSync91, lstatSync as lstatSync4, mkdirSync as mkdirSync41, readdirSync as readdirSync34, readFileSync as readFileSync85, realpathSync as realpathSync11, rmSync as rmSync17, statSync as statSync30, symlinkSync as symlinkSync3, unlinkSync as unlinkSync3, writeFileSync as writeFileSync42 } from "node:fs";
256683
+ import { appendFileSync as appendFileSync16, existsSync as existsSync91, lstatSync as lstatSync4, mkdirSync as mkdirSync41, readdirSync as readdirSync34, readFileSync as readFileSync85, realpathSync as realpathSync11, rmSync as rmSync17, statSync as statSync31, symlinkSync as symlinkSync3, unlinkSync as unlinkSync3, writeFileSync as writeFileSync42 } from "node:fs";
256640
256684
  import { dirname as dirname40, join as join96 } from "node:path";
256641
256685
  import { promisify as promisify10 } from "node:util";
256642
256686
 
@@ -256699,8 +256743,8 @@ async function probeAgentReachable(agent, spawn11, opts = {}) {
256699
256743
  try {
256700
256744
  res = await Promise.race([
256701
256745
  spawn11(agent, { cwd, skillBody: `Reply with exactly: ${token}`, timeoutMs, bare: true }),
256702
- new Promise((resolve9) => {
256703
- setTimeout(() => resolve9(null), timeoutMs).unref();
256746
+ new Promise((resolve10) => {
256747
+ setTimeout(() => resolve10(null), timeoutMs).unref();
256704
256748
  })
256705
256749
  ]);
256706
256750
  } catch (e) {
@@ -256898,7 +256942,7 @@ function clearSelfHeal(runtimeDir9, storyId) {
256898
256942
 
256899
256943
  // packages/cli/dist/runner/usage-recovery.js
256900
256944
  init_dist2();
256901
- import { readFileSync as readFileSync82, readdirSync as readdirSync32, statSync as statSync29 } from "node:fs";
256945
+ import { readFileSync as readFileSync82, readdirSync as readdirSync32, statSync as statSync30 } from "node:fs";
256902
256946
  import { homedir as homedir23 } from "node:os";
256903
256947
  import { basename as basename16, join as join93 } from "node:path";
256904
256948
  function defaultPiSessionsRoot() {
@@ -256919,7 +256963,7 @@ function recoverPiUsage(worktreeCwd, sinceSec, sessionsRoot = defaultPiSessionsR
256919
256963
  for (const f of files) {
256920
256964
  const p = join93(dir, f);
256921
256965
  try {
256922
- if (sinceSec !== void 0 && statSync29(p).mtimeMs / 1e3 < sinceSec)
256966
+ if (sinceSec !== void 0 && statSync30(p).mtimeMs / 1e3 < sinceSec)
256923
256967
  continue;
256924
256968
  summaries.push(sumPiSession(readFileSync82(p, "utf8").split("\n")));
256925
256969
  } catch {
@@ -256966,7 +257010,7 @@ function recoverKimiUsage(worktreeCwd, sinceSec, sessionsRoot = defaultKimiSessi
256966
257010
  const summaries = [];
256967
257011
  for (const p of wireFiles) {
256968
257012
  try {
256969
- if (sinceSec !== void 0 && statSync29(p).mtimeMs / 1e3 < sinceSec)
257013
+ if (sinceSec !== void 0 && statSync30(p).mtimeMs / 1e3 < sinceSec)
256970
257014
  continue;
256971
257015
  summaries.push(sumKimiWire(readFileSync82(p, "utf8").split("\n")));
256972
257016
  } catch {
@@ -258241,7 +258285,7 @@ ${res.stderr}
258241
258285
  // FIX-319: review-only framing, no worker autorun directive
258242
258286
  ...ctx.evidenceRunDir !== void 0 ? { runDir: ctx.evidenceRunDir } : {}
258243
258287
  }),
258244
- new Promise((resolve9) => setTimeout(() => resolve9(null), timeoutMs).unref())
258288
+ new Promise((resolve10) => setTimeout(() => resolve10(null), timeoutMs).unref())
258245
258289
  ]);
258246
258290
  } catch (e) {
258247
258291
  const cause = await attributeBlockCause(peer, "error", e instanceof Error ? e.message : String(e), "review");
@@ -258371,7 +258415,7 @@ ${res.stderr}`, "review");
258371
258415
  timeoutMs,
258372
258416
  ...ctx.evidenceRunDir !== void 0 ? { runDir: ctx.evidenceRunDir } : {}
258373
258417
  }),
258374
- new Promise((resolve9) => setTimeout(() => resolve9(null), timeoutMs).unref())
258418
+ new Promise((resolve10) => setTimeout(() => resolve10(null), timeoutMs).unref())
258375
258419
  ]);
258376
258420
  } catch (e) {
258377
258421
  const detail = e instanceof Error ? e.message : String(e);
@@ -259564,7 +259608,7 @@ function nodePorts(opts) {
259564
259608
  const deliveryFreshness = {
259565
259609
  mtimeMs(absPath) {
259566
259610
  try {
259567
- return statSync30(absPath).mtimeMs;
259611
+ return statSync31(absPath).mtimeMs;
259568
259612
  } catch {
259569
259613
  return void 0;
259570
259614
  }
@@ -261041,10 +261085,10 @@ function autoGc(projectPath3) {
261041
261085
  }
261042
261086
  }
261043
261087
  }
261044
- async function isOffline(resolve9 = (h) => lookup2(h)) {
261088
+ async function isOffline(resolve10 = (h) => lookup2(h)) {
261045
261089
  try {
261046
261090
  await Promise.race([
261047
- resolve9("github.com"),
261091
+ resolve10("github.com"),
261048
261092
  new Promise((_, rej) => {
261049
261093
  const t3 = setTimeout(() => rej(new Error("dns timeout")), 1500);
261050
261094
  if (typeof t3 === "object")
@@ -261113,7 +261157,7 @@ init_dist();
261113
261157
  import { spawnSync as spawnSync14 } from "node:child_process";
261114
261158
  import { existsSync as existsSync96, readFileSync as readFileSync90, realpathSync as realpathSync12, renameSync as renameSync15, rmSync as rmSync18, writeFileSync as writeFileSync47 } from "node:fs";
261115
261159
  import { homedir as homedir24 } from "node:os";
261116
- import { join as join101, resolve as resolve7 } from "node:path";
261160
+ import { join as join101, resolve as resolve8 } from "node:path";
261117
261161
  function pal5() {
261118
261162
  const noColor2 = (process.env["NO_COLOR"] ?? "") !== "";
261119
261163
  return noColor2 ? { RED: "", GREEN: "", YELLOW: "", CYAN: "", BOLD: "", NC: "" } : {
@@ -261217,7 +261261,7 @@ function writeFileAtomic2(path, text2) {
261217
261261
  }
261218
261262
  }
261219
261263
  function resolveChangesetItem(projectDir, item) {
261220
- return item.startsWith("/") ? resolve7(item) : resolve7(projectDir, item);
261264
+ return item.startsWith("/") ? resolve8(item) : resolve8(projectDir, item);
261221
261265
  }
261222
261266
  var HELP4 = `Usage: roll offboard [--confirm]
261223
261267
  Preview (default) or apply (--confirm) the removal of every
@@ -261238,7 +261282,7 @@ function offboardCommand(args) {
261238
261282
  }
261239
261283
  let projectDir;
261240
261284
  try {
261241
- projectDir = realpathSync12(resolve7(process.cwd()));
261285
+ projectDir = realpathSync12(resolve8(process.cwd()));
261242
261286
  } catch {
261243
261287
  projectDir = process.cwd();
261244
261288
  }
@@ -262025,7 +262069,7 @@ init_dist2();
262025
262069
  init_dist();
262026
262070
  init_render();
262027
262071
  import { execFileSync as execFileSync23 } from "node:child_process";
262028
- import { existsSync as existsSync100, mkdirSync as mkdirSync48, readFileSync as readFileSync94, readdirSync as readdirSync38, statSync as statSync31, writeFileSync as writeFileSync50 } from "node:fs";
262072
+ import { existsSync as existsSync100, mkdirSync as mkdirSync48, readFileSync as readFileSync94, readdirSync as readdirSync38, statSync as statSync32, writeFileSync as writeFileSync50 } from "node:fs";
262029
262073
  import { dirname as dirname46, join as join105 } from "node:path";
262030
262074
 
262031
262075
  // packages/cli/dist/lib/consistency-audit.js
@@ -262329,7 +262373,7 @@ function lineNumberAt(text2, index) {
262329
262373
  function existingTextFiles(projectDir, rels) {
262330
262374
  return rels.map((rel) => ({ rel, abs: join105(projectDir, rel) })).filter((f) => {
262331
262375
  try {
262332
- return statSync31(f.abs).isFile();
262376
+ return statSync32(f.abs).isFile();
262333
262377
  } catch {
262334
262378
  return false;
262335
262379
  }
@@ -262473,7 +262517,7 @@ function backlogRowFacts(backlogText) {
262473
262517
  var nodeFreshnessPort2 = {
262474
262518
  mtimeMs(absPath) {
262475
262519
  try {
262476
- return statSync31(absPath).mtimeMs;
262520
+ return statSync32(absPath).mtimeMs;
262477
262521
  } catch {
262478
262522
  return void 0;
262479
262523
  }
@@ -262811,7 +262855,7 @@ function listFiles2(dir) {
262811
262855
  try {
262812
262856
  return readdirSync38(dir).filter((n) => {
262813
262857
  try {
262814
- return statSync31(join105(dir, n)).isFile();
262858
+ return statSync32(join105(dir, n)).isFile();
262815
262859
  } catch {
262816
262860
  return false;
262817
262861
  }
@@ -262888,7 +262932,7 @@ function rglobBats(dir) {
262888
262932
  const full = join105(d, e);
262889
262933
  let st;
262890
262934
  try {
262891
- st = statSync31(full);
262935
+ st = statSync32(full);
262892
262936
  } catch {
262893
262937
  continue;
262894
262938
  }
@@ -263698,7 +263742,7 @@ ${c("dim", "\u2192 Running the golden-path showcase (real models; its verdict do
263698
263742
  init_dist();
263699
263743
  init_render();
263700
263744
  import { spawnSync as spawnSync16 } from "node:child_process";
263701
- import { existsSync as existsSync103, lstatSync as lstatSync5, mkdirSync as mkdirSync50, readFileSync as readFileSync97, readdirSync as readdirSync40, readlinkSync as readlinkSync2, statSync as statSync33 } from "node:fs";
263745
+ import { existsSync as existsSync103, lstatSync as lstatSync5, mkdirSync as mkdirSync50, readFileSync as readFileSync97, readdirSync as readdirSync40, readlinkSync as readlinkSync2, statSync as statSync34 } from "node:fs";
263702
263746
  import { join as join108 } from "node:path";
263703
263747
  function err13(line) {
263704
263748
  const noColor2 = (process.env["NO_COLOR"] ?? "") !== "";
@@ -263736,7 +263780,7 @@ function setupSnapshot(watch2) {
263736
263780
  continue;
263737
263781
  let isDir4 = false;
263738
263782
  try {
263739
- isDir4 = statSync33(d).isDirectory();
263783
+ isDir4 = statSync34(d).isDirectory();
263740
263784
  } catch {
263741
263785
  isDir4 = false;
263742
263786
  }
@@ -263770,7 +263814,7 @@ function walk(dir, lines2) {
263770
263814
  }
263771
263815
  let st;
263772
263816
  try {
263773
- st = statSync33(p);
263817
+ st = statSync34(p);
263774
263818
  } catch {
263775
263819
  continue;
263776
263820
  }
@@ -264016,7 +264060,7 @@ init_showcase2();
264016
264060
  // packages/cli/dist/commands/test.js
264017
264061
  import { spawnSync as spawnSync17 } from "node:child_process";
264018
264062
  import { appendFileSync as appendFileSync20, existsSync as existsSync104, mkdirSync as mkdirSync51, readFileSync as readFileSync98, rmSync as rmSync20, writeFileSync as writeFileSync53 } from "node:fs";
264019
- import { dirname as dirname48, join as join109, resolve as resolve8 } from "node:path";
264063
+ import { dirname as dirname48, join as join109, resolve as resolve9 } from "node:path";
264020
264064
  function pal7() {
264021
264065
  const noColor2 = (process.env["NO_COLOR"] ?? "") !== "";
264022
264066
  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" };
@@ -264036,7 +264080,7 @@ function currentEvidenceFrame() {
264036
264080
  const raw = (process.env["ROLL_RUN_DIR"] ?? "").trim();
264037
264081
  if (raw === "")
264038
264082
  return null;
264039
- const runDir = resolve8(raw);
264083
+ const runDir = resolve9(raw);
264040
264084
  if (!existsSync104(runDir))
264041
264085
  return null;
264042
264086
  const frame = {
@@ -264369,7 +264413,7 @@ function pad4(value, width) {
264369
264413
  // packages/cli/dist/commands/truth.js
264370
264414
  init_dist();
264371
264415
  init_dist2();
264372
- import { statSync as statSync34, readFileSync as readFileSync99, writeFileSync as writeFileSync54, mkdirSync as mkdirSync52, existsSync as existsSync105 } from "node:fs";
264416
+ import { statSync as statSync35, readFileSync as readFileSync99, writeFileSync as writeFileSync54, mkdirSync as mkdirSync52, existsSync as existsSync105 } from "node:fs";
264373
264417
  import { dirname as dirname49, join as join111 } from "node:path";
264374
264418
  var TRUTH_USAGE = "Usage: roll truth <command>\n query <storyId> Deterministic delivery-truth query (structured, zero markdown parse).\n audit Bidirectional drift audit: backlog Done \u2194 projection truth.\n\u547D\u4EE4:\n query <storyId> \u7ED3\u6784\u5316\u4EA4\u4ED8\u771F\u76F8\u67E5\u8BE2\uFF08\u786E\u5B9A\u6027\uFF0C\u4E0D\u89E3\u6790 markdown\uFF09\n audit \u53CC\u5411\u6F02\u79FB\u5BA1\u8BA1\uFF1Abacklog Done \u2194 \u6295\u5F71\u771F\u76F8";
264375
264419
  function formatTruth(t3, lang11) {
@@ -264395,7 +264439,7 @@ function formatTruth(t3, lang11) {
264395
264439
  var nodeFreshnessPort3 = {
264396
264440
  mtimeMs(absPath) {
264397
264441
  try {
264398
- return statSync34(absPath).mtimeMs;
264442
+ return statSync35(absPath).mtimeMs;
264399
264443
  } catch {
264400
264444
  return void 0;
264401
264445
  }
@@ -264943,7 +264987,7 @@ function registerAll() {
264943
264987
  registerPorted("config", configCommand);
264944
264988
  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" });
264945
264989
  registerPorted("next", nextCommand, { help: NEXT_USAGE });
264946
- registerPorted("design", designCommand, { help: "Usage: roll design [--agent <name>]\n Launch $roll-design interactively.\n\u4EA4\u4E92\u5F0F\u542F\u52A8 $roll-design\u3002" });
264990
+ registerPorted("design", designCommand, { help: "Usage: roll design [--from-file <path>] [--agent <name>]\n Launch $roll-design interactively; --from-file binds a PRD/brief.\n\u4EA4\u4E92\u5F0F\u542F\u52A8 $roll-design\uFF1B--from-file \u7ED1\u5B9A PRD/brief\u3002" });
264947
264991
  registerPorted("offboard", offboardCommand);
264948
264992
  registerPorted("setup", (args) => {
264949
264993
  if (args[0] === "skills") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seanyao/roll",
3
- "version": "3.627.1",
3
+ "version": "3.628.1",
4
4
  "description": "Roll — Roll out features with AI agents",
5
5
  "packageManager": "pnpm@11.1.3",
6
6
  "scripts": {