@c-d-cc/reap 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -9947,10 +9947,19 @@ var init_lineage = __esm(() => {
9947
9947
  });
9948
9948
 
9949
9949
  // src/core/generation.ts
9950
- import { createHash } from "crypto";
9950
+ import { createHash, randomBytes } from "crypto";
9951
9951
  import { hostname } from "os";
9952
9952
  import { readdir as readdir7, mkdir as mkdir4, rename, unlink as unlink3 } from "fs/promises";
9953
9953
  import { join as join8 } from "path";
9954
+ function generateStageToken(genId, stage) {
9955
+ const nonce = randomBytes(16).toString("hex");
9956
+ const hash = createHash("sha256").update(nonce + genId + stage).digest("hex");
9957
+ return { nonce, hash };
9958
+ }
9959
+ function verifyStageToken(token, genId, stage, expectedHash) {
9960
+ const computed = createHash("sha256").update(token + genId + stage).digest("hex");
9961
+ return computed === expectedHash;
9962
+ }
9954
9963
  function generateGenHash(parents, goal, genomeHash, machineId, startedAt) {
9955
9964
  const input = JSON.stringify({ parents, goal, genomeHash, machineId, startedAt });
9956
9965
  return createHash("sha256").update(input).digest("hex").slice(0, 6);
@@ -10391,6 +10400,16 @@ async function execute(paths, _phase) {
10391
10400
  if (!state) {
10392
10401
  emitError("next", "No active Generation. Run /reap.start first.");
10393
10402
  }
10403
+ if (state.expectedTokenHash) {
10404
+ const args = process.argv.slice(2);
10405
+ const nonce = args.find((a) => !a.startsWith("-") && a !== "run" && a !== "next");
10406
+ if (!nonce) {
10407
+ emitError("next", `Stage transition blocked: no token provided. The stage command outputs a nonce that must be passed to /reap.next. Example: /reap.next <nonce>. This ensures the stage command was actually executed — you cannot skip stages.`);
10408
+ }
10409
+ if (!verifyStageToken(nonce, state.id, state.stage, state.expectedTokenHash)) {
10410
+ emitError("next", `Token verification failed. The provided nonce does not match. Re-run the current stage command (reap run ${state.stage}) to get a valid token. You cannot forge or guess the token.`);
10411
+ }
10412
+ }
10394
10413
  const isMerge = state.type === "merge";
10395
10414
  let nextStage;
10396
10415
  if (isMerge) {
@@ -10405,6 +10424,7 @@ async function execute(paths, _phase) {
10405
10424
  if (!state.timeline)
10406
10425
  state.timeline = [];
10407
10426
  state.timeline.push({ stage: nextStage, at: new Date().toISOString() });
10427
+ state.expectedTokenHash = undefined;
10408
10428
  await gm.save(state);
10409
10429
  const artifactFile = isMerge ? MERGE_ARTIFACT[nextStage] : NORMAL_ARTIFACT[nextStage];
10410
10430
  if (artifactFile) {
@@ -10439,7 +10459,7 @@ async function execute(paths, _phase) {
10439
10459
  status: "ok",
10440
10460
  command: "next",
10441
10461
  phase: "done",
10442
- completed: ["gate", "advance-stage", "create-artifact", "hooks"],
10462
+ completed: ["gate", "nonce-verify", "advance-stage", "create-artifact", "hooks"],
10443
10463
  context: {
10444
10464
  generationId: state.id,
10445
10465
  previousStage,
@@ -10478,7 +10498,24 @@ var exports_back = {};
10478
10498
  __export(exports_back, {
10479
10499
  execute: () => execute2
10480
10500
  });
10481
- async function execute2(paths, phase) {
10501
+ function getFlag(args, name) {
10502
+ const idx = args.indexOf(`--${name}`);
10503
+ return idx !== -1 && args[idx + 1] ? args[idx + 1] : undefined;
10504
+ }
10505
+ function getPositionals(args, valueFlags) {
10506
+ const result = [];
10507
+ for (let i = 0;i < args.length; i++) {
10508
+ if (args[i].startsWith("--")) {
10509
+ const flagName = args[i].slice(2);
10510
+ if (valueFlags.includes(flagName) && i + 1 < args.length)
10511
+ i++;
10512
+ continue;
10513
+ }
10514
+ result.push(args[i]);
10515
+ }
10516
+ return result;
10517
+ }
10518
+ async function execute2(paths, phase, argv = []) {
10482
10519
  const gm = new GenerationManager(paths);
10483
10520
  const state = await gm.current();
10484
10521
  if (!state) {
@@ -10500,16 +10537,17 @@ async function execute2(paths, phase) {
10500
10537
  type: state.type,
10501
10538
  id: state.id
10502
10539
  },
10503
- prompt: "Ask the human: (1) target stage (default: previous stage), (2) reason for regression, (3) related refs. Then run: reap run back --phase apply. Pass via env: REAP_BACK_TARGET, REAP_BACK_REASON, REAP_BACK_REFS (comma-separated).",
10540
+ prompt: 'Ask the human: (1) target stage (default: previous stage), (2) reason for regression, (3) related refs. Then run: reap run back --phase apply <target-stage> --reason "<reason>" --refs "<a,b,c>"',
10504
10541
  nextCommand: "reap run back --phase apply"
10505
10542
  });
10506
10543
  }
10507
10544
  if (phase === "apply") {
10508
10545
  const originalStage = state.stage;
10509
- const targetEnv = process.env.REAP_BACK_TARGET;
10546
+ const positionals = getPositionals(argv, ["reason", "refs"]);
10547
+ const targetArg = positionals[0];
10510
10548
  let target;
10511
- if (targetEnv) {
10512
- target = targetEnv;
10549
+ if (targetArg) {
10550
+ target = targetArg;
10513
10551
  } else if (isMerge) {
10514
10552
  target = MergeLifeCycle.prev(state.stage);
10515
10553
  } else {
@@ -10519,8 +10557,8 @@ async function execute2(paths, phase) {
10519
10557
  if (!canTransition) {
10520
10558
  emitError("back", `Cannot regress from '${originalStage}' to '${target}'.`);
10521
10559
  }
10522
- const reason = process.env.REAP_BACK_REASON ?? "No reason provided";
10523
- const refs = (process.env.REAP_BACK_REFS ?? "").split(",").filter(Boolean);
10560
+ const reason = getFlag(argv, "reason") ?? "No reason provided";
10561
+ const refs = (getFlag(argv, "refs") ?? "").split(",").filter(Boolean);
10524
10562
  state.stage = target;
10525
10563
  state.timeline.push({
10526
10564
  stage: target,
@@ -10652,7 +10690,27 @@ __export(exports_start, {
10652
10690
  });
10653
10691
  import { join as join15 } from "path";
10654
10692
  import { readdir as readdir12 } from "fs/promises";
10655
- async function execute3(paths, phase) {
10693
+ function getFlag2(args, name) {
10694
+ const idx = args.indexOf(`--${name}`);
10695
+ return idx !== -1 && args[idx + 1] ? args[idx + 1] : undefined;
10696
+ }
10697
+ function getPositionals2(args, valueFlags) {
10698
+ const result = [];
10699
+ for (let i = 0;i < args.length; i++) {
10700
+ if (args[i].startsWith("--")) {
10701
+ const flagName = args[i].slice(2);
10702
+ if (valueFlags.includes(flagName) && i + 1 < args.length)
10703
+ i++;
10704
+ continue;
10705
+ }
10706
+ result.push(args[i]);
10707
+ }
10708
+ return result;
10709
+ }
10710
+ async function execute3(paths, phase, argv = []) {
10711
+ const positionals = getPositionals2(argv, ["backlog"]);
10712
+ const goal = positionals.join(" ") || undefined;
10713
+ const backlogFile = getFlag2(argv, "backlog");
10656
10714
  const gm = new GenerationManager(paths);
10657
10715
  if (!phase || phase === "scan") {
10658
10716
  const state = await gm.current();
@@ -10666,14 +10724,13 @@ async function execute3(paths, phase) {
10666
10724
  phase: "collect-goal",
10667
10725
  completed: ["gate", "backlog-scan"],
10668
10726
  context: { backlogItems },
10669
- prompt: backlogItems.length > 0 ? "Present the backlog items to the human. Ask: select one or enter a new goal. Set REAP_START_GOAL and optionally REAP_START_BACKLOG_FILE (selected backlog filename). Then run: reap run start --phase create" : "Ask the human for the goal of this generation. Set REAP_START_GOAL. Then run: reap run start --phase create",
10727
+ prompt: backlogItems.length > 0 ? 'Present the backlog items to the human. Ask: select one or enter a new goal. Then run: reap run start --phase create "<goal>" (add --backlog <filename> if selected from backlog)' : 'Ask the human for the goal of this generation. Then run: reap run start --phase create "<goal>"',
10670
10728
  nextCommand: "reap run start --phase create"
10671
10729
  });
10672
10730
  }
10673
10731
  if (phase === "create") {
10674
- const goal = process.env.REAP_START_GOAL;
10675
10732
  if (!goal) {
10676
- emitError("start", "REAP_START_GOAL environment variable is required.");
10733
+ emitError("start", 'Goal is required. Usage: reap run start --phase create "<goal>"');
10677
10734
  }
10678
10735
  const existing = await gm.current();
10679
10736
  if (existing && existing.id) {
@@ -10685,7 +10742,9 @@ async function execute3(paths, phase) {
10685
10742
  genomeVersion = lineageEntries.filter((e) => e.startsWith("gen-")).length + 1;
10686
10743
  } catch {}
10687
10744
  const state = await gm.create(goal, genomeVersion);
10688
- const backlogFile = process.env.REAP_START_BACKLOG_FILE;
10745
+ const { nonce, hash } = generateStageToken(state.id, state.stage);
10746
+ state.expectedTokenHash = hash;
10747
+ await gm.save(state);
10689
10748
  if (backlogFile) {
10690
10749
  await markBacklogConsumed(paths.backlog, backlogFile, state.id);
10691
10750
  }
@@ -10897,7 +10956,14 @@ __export(exports_abort, {
10897
10956
  });
10898
10957
  import { join as join17 } from "path";
10899
10958
  import { readdir as readdir13, unlink as unlink5 } from "fs/promises";
10900
- async function execute5(paths, phase) {
10959
+ function getFlag3(args, name) {
10960
+ const idx = args.indexOf(`--${name}`);
10961
+ return idx !== -1 && args[idx + 1] ? args[idx + 1] : undefined;
10962
+ }
10963
+ function hasFlag(args, name) {
10964
+ return args.includes(`--${name}`);
10965
+ }
10966
+ async function execute5(paths, phase, argv = []) {
10901
10967
  const gm = new GenerationManager(paths);
10902
10968
  const state = await gm.current();
10903
10969
  if (!state || !state.id) {
@@ -10923,17 +10989,16 @@ async function execute5(paths, phase) {
10923
10989
  " - If changes: offer rollback / stash / hold.",
10924
10990
  " - If no changes: skip.",
10925
10991
  "Ask: 'Goal과 진행 상황을 backlog에 저장할까요? (yes/no)'",
10926
- "Set env vars: REAP_ABORT_REASON, REAP_ABORT_SOURCE_ACTION (rollback|stash|hold|none), REAP_ABORT_SAVE_BACKLOG (yes|no).",
10927
- "Then run: reap run abort --phase execute"
10992
+ 'Then run: reap run abort --phase execute --reason "<reason>" --source-action <rollback|stash|hold|none> [--save-backlog]'
10928
10993
  ].join(`
10929
10994
  `),
10930
10995
  nextCommand: "reap run abort --phase execute"
10931
10996
  });
10932
10997
  }
10933
10998
  if (phase === "execute") {
10934
- const reason = process.env.REAP_ABORT_REASON ?? "No reason provided";
10935
- const sourceAction = process.env.REAP_ABORT_SOURCE_ACTION ?? "none";
10936
- const saveBacklog = process.env.REAP_ABORT_SAVE_BACKLOG === "yes";
10999
+ const reason = getFlag3(argv, "reason") ?? "No reason provided";
11000
+ const sourceAction = getFlag3(argv, "source-action") ?? "none";
11001
+ const saveBacklog = hasFlag(argv, "save-backlog");
10937
11002
  let backlogSaved = false;
10938
11003
  if (saveBacklog) {
10939
11004
  const objectiveContent = await readTextFile(paths.artifact("01-objective.md"));
@@ -11152,6 +11217,9 @@ async function execute7(paths, phase) {
11152
11217
  if (!content || content.length < 50) {
11153
11218
  emitError("objective", "01-objective.md appears incomplete (too short). Fill in the objective before completing.");
11154
11219
  }
11220
+ const { nonce, hash } = generateStageToken(state.id, state.stage);
11221
+ state.expectedTokenHash = hash;
11222
+ await gm.save(state);
11155
11223
  const hookResults = await executeHooks(paths.hooks, "onLifeObjected", paths.projectRoot);
11156
11224
  emitOutput({
11157
11225
  status: "ok",
@@ -11162,7 +11230,7 @@ async function execute7(paths, phase) {
11162
11230
  id: state.id,
11163
11231
  hookResults
11164
11232
  },
11165
- message: "Objective stage complete. Proceed to the Planning stage with /reap.next."
11233
+ message: `Objective stage complete. Advance with: /reap.next ${nonce}`
11166
11234
  });
11167
11235
  }
11168
11236
  }
@@ -11274,6 +11342,9 @@ async function execute8(paths, phase) {
11274
11342
  if (!content || content.length < 50) {
11275
11343
  emitError("planning", "02-planning.md appears incomplete. Fill in the plan before completing.");
11276
11344
  }
11345
+ const { nonce, hash } = generateStageToken(state.id, state.stage);
11346
+ state.expectedTokenHash = hash;
11347
+ await gm.save(state);
11277
11348
  const hookResults = await executeHooks(paths.hooks, "onLifePlanned", paths.projectRoot);
11278
11349
  emitOutput({
11279
11350
  status: "ok",
@@ -11284,7 +11355,7 @@ async function execute8(paths, phase) {
11284
11355
  id: state.id,
11285
11356
  hookResults
11286
11357
  },
11287
- message: "Planning stage complete. Proceed to the Implementation stage with /reap.next."
11358
+ message: `Planning stage complete. Advance with: /reap.next ${nonce}`
11288
11359
  });
11289
11360
  }
11290
11361
  }
@@ -11392,6 +11463,9 @@ async function execute9(paths, phase) {
11392
11463
  if (!await fileExists(artifactPath)) {
11393
11464
  emitError("implementation", "03-implementation.md does not exist. Complete the implementation work first.");
11394
11465
  }
11466
+ const { nonce, hash } = generateStageToken(state.id, state.stage);
11467
+ state.expectedTokenHash = hash;
11468
+ await gm.save(state);
11395
11469
  const hookResults = await executeHooks(paths.hooks, "onLifeImplemented", paths.projectRoot);
11396
11470
  emitOutput({
11397
11471
  status: "ok",
@@ -11402,7 +11476,7 @@ async function execute9(paths, phase) {
11402
11476
  id: state.id,
11403
11477
  hookResults
11404
11478
  },
11405
- message: "Implementation stage complete. Proceed to the Validation stage with /reap.next."
11479
+ message: `Implementation stage complete. Advance with: /reap.next ${nonce}`
11406
11480
  });
11407
11481
  }
11408
11482
  }
@@ -11521,6 +11595,9 @@ async function execute10(paths, phase) {
11521
11595
  if (!await fileExists(artifactPath)) {
11522
11596
  emitError("validation", "04-validation.md does not exist. Complete the validation work first.");
11523
11597
  }
11598
+ const { nonce, hash } = generateStageToken(state.id, state.stage);
11599
+ state.expectedTokenHash = hash;
11600
+ await gm.save(state);
11524
11601
  const hookResults = await executeHooks(paths.hooks, "onLifeValidated", paths.projectRoot);
11525
11602
  emitOutput({
11526
11603
  status: "ok",
@@ -11531,7 +11608,7 @@ async function execute10(paths, phase) {
11531
11608
  id: state.id,
11532
11609
  hookResults
11533
11610
  },
11534
- message: "Validation stage complete. Proceed to the Completion stage with /reap.next."
11611
+ message: `Validation stage complete. Advance with: /reap.next ${nonce}`
11535
11612
  });
11536
11613
  }
11537
11614
  }
@@ -11606,6 +11683,12 @@ function buildSubagentPrompt(paths, state, genomeSummaries, backlogSummary) {
11606
11683
  lines.push("## Project");
11607
11684
  lines.push(`- Path: ${paths.projectRoot}`);
11608
11685
  lines.push("");
11686
+ lines.push("## Stage Chain Token");
11687
+ lines.push("- Each stage command returns a `stageToken` in its output context.");
11688
+ lines.push("- You MUST pass this token to `/reap.next --token <TOKEN>` (or set `REAP_STAGE_TOKEN` env var).");
11689
+ lines.push("- Without a valid token, stage transition will be REJECTED.");
11690
+ lines.push("- If token is missing or mismatched, re-run the current stage command to obtain a new token.");
11691
+ lines.push("");
11609
11692
  lines.push("## Commit Rules");
11610
11693
  lines.push("- Create a git commit after implementation and after completion.");
11611
11694
  lines.push("- Use conventional commit format: `feat|fix|chore(scope): description`");
@@ -12003,7 +12086,7 @@ function buildLines(versionDisplay, lang, stateDisplay) {
12003
12086
  ...buildCommandTable(lang),
12004
12087
  "",
12005
12088
  TOPICS_LINE[lang],
12006
- "Usage: REAP_HELP_TOPIC=<topic> reap run help",
12089
+ "Usage: /reap.help <topic>",
12007
12090
  CONFIG_LINE[lang]
12008
12091
  ];
12009
12092
  }
@@ -12017,7 +12100,8 @@ async function execute15(paths) {
12017
12100
  const rawLang = detectLanguage(configContent);
12018
12101
  const supported = isSupportedLanguage(rawLang);
12019
12102
  const lang = supported ? rawLang : "en";
12020
- const topic = process.env.REAP_HELP_TOPIC;
12103
+ const args = process.argv.slice(2).filter((a) => !a.startsWith("-") && a !== "run" && a !== "help");
12104
+ const topic = args[0] || undefined;
12021
12105
  const stateDisplay = state?.id ? `Active: **${state.id}** — ${state.goal} (Stage: ${state.stage})` : "No active Generation → `/reap.start` or `/reap.evolve`";
12022
12106
  const lines = buildLines(versionDisplay, lang, stateDisplay);
12023
12107
  if (topic) {
@@ -12613,7 +12697,9 @@ var exports_merge_start = {};
12613
12697
  __export(exports_merge_start, {
12614
12698
  execute: () => execute17
12615
12699
  });
12616
- async function execute17(paths, phase) {
12700
+ async function execute17(paths, phase, argv = []) {
12701
+ const positionals = argv.filter((a) => !a.startsWith("--"));
12702
+ const targetBranchArg = positionals[0];
12617
12703
  const gm = new GenerationManager(paths);
12618
12704
  if (!phase || phase === "collect") {
12619
12705
  const state = await gm.current();
@@ -12629,14 +12715,14 @@ async function execute17(paths, phase) {
12629
12715
  context: {
12630
12716
  currentBranch
12631
12717
  },
12632
- prompt: "Ask the human for the target branch to merge. Set REAP_MERGE_TARGET_BRANCH to the branch name. Then run: reap run merge-start --phase create",
12718
+ prompt: "Ask the human for the target branch to merge. Then run: reap run merge-start --phase create <branch-name>",
12633
12719
  nextCommand: "reap run merge-start --phase create"
12634
12720
  });
12635
12721
  }
12636
12722
  if (phase === "create") {
12637
- const targetBranch = process.env.REAP_MERGE_TARGET_BRANCH;
12723
+ const targetBranch = targetBranchArg;
12638
12724
  if (!targetBranch) {
12639
- emitError("merge-start", "REAP_MERGE_TARGET_BRANCH environment variable is required.");
12725
+ emitError("merge-start", "Target branch is required. Usage: reap run merge-start --phase create <branch>");
12640
12726
  }
12641
12727
  const existing = await gm.current();
12642
12728
  if (existing && existing.id) {
@@ -13269,7 +13355,9 @@ var exports_merge = {};
13269
13355
  __export(exports_merge, {
13270
13356
  execute: () => execute25
13271
13357
  });
13272
- async function execute25(paths, phase) {
13358
+ async function execute25(paths, phase, argv = []) {
13359
+ const positionals = argv.filter((a) => !a.startsWith("--"));
13360
+ const targetBranchArg = positionals[0];
13273
13361
  const gm = new GenerationManager(paths);
13274
13362
  if (!phase || phase === "detect") {
13275
13363
  const state = await gm.current();
@@ -13288,17 +13376,16 @@ async function execute25(paths, phase) {
13288
13376
  "## Merge -- Full Merge Generation for a Local Branch",
13289
13377
  "",
13290
13378
  "Ask the human for the target branch to merge.",
13291
- "Set REAP_MERGE_TARGET_BRANCH to the branch name.",
13292
- "Then run: reap run merge --phase check"
13379
+ "Then run: reap run merge --phase check <branch-name>"
13293
13380
  ].join(`
13294
13381
  `),
13295
13382
  nextCommand: "reap run merge --phase check"
13296
13383
  });
13297
13384
  }
13298
13385
  if (phase === "check") {
13299
- const targetBranch = process.env.REAP_MERGE_TARGET_BRANCH;
13386
+ const targetBranch = targetBranchArg;
13300
13387
  if (!targetBranch) {
13301
- emitError("merge", "REAP_MERGE_TARGET_BRANCH environment variable is required.");
13388
+ emitError("merge", "Target branch is required. Usage: reap run merge --phase check <branch>");
13302
13389
  }
13303
13390
  if (!gitRefExists(targetBranch, paths.projectRoot)) {
13304
13391
  emitError("merge", `Branch "${targetBranch}" does not exist.`);
@@ -13313,7 +13400,7 @@ async function execute25(paths, phase) {
13313
13400
  phase: "start-merge",
13314
13401
  completed: ["gate", "branch-verify"],
13315
13402
  context: { targetBranch, currentBranch },
13316
- prompt: `No lineage found. Run /reap.merge.start with REAP_MERGE_TARGET_BRANCH=${targetBranch} to begin the merge generation, then /reap.merge.evolve.`,
13403
+ prompt: `No lineage found. Run /reap.merge.start ${targetBranch} to begin the merge generation, then /reap.merge.evolve.`,
13317
13404
  nextCommand: `reap run merge-start --phase create`
13318
13405
  });
13319
13406
  return;
@@ -13336,9 +13423,8 @@ async function execute25(paths, phase) {
13336
13423
  `Current branch: ${currentBranch}`,
13337
13424
  "",
13338
13425
  "Execute the following sequence:",
13339
- `1. Set REAP_MERGE_TARGET_BRANCH=${targetBranch}`,
13340
- "2. Run /reap.merge.start (creates merge generation + detect report)",
13341
- "3. Run /reap.merge.evolve (runs detect -> mate -> merge -> sync -> validation -> completion)",
13426
+ `1. Run /reap.merge.start ${targetBranch} (creates merge generation + detect report)`,
13427
+ "2. Run /reap.merge.evolve (runs detect -> mate -> merge -> sync -> validation -> completion)",
13342
13428
  "",
13343
13429
  "The merge generation will be archived upon completion."
13344
13430
  ].join(`
@@ -13358,7 +13444,9 @@ var exports_pull = {};
13358
13444
  __export(exports_pull, {
13359
13445
  execute: () => execute26
13360
13446
  });
13361
- async function execute26(paths, phase) {
13447
+ async function execute26(paths, phase, argv = []) {
13448
+ const positionals = argv.filter((a) => !a.startsWith("--"));
13449
+ const targetBranchArg = positionals[0];
13362
13450
  const gm = new GenerationManager(paths);
13363
13451
  if (!phase || phase === "fetch") {
13364
13452
  const state = await gm.current();
@@ -13378,17 +13466,16 @@ async function execute26(paths, phase) {
13378
13466
  "",
13379
13467
  "1. Run `git fetch origin`",
13380
13468
  "2. Ask the human for the target remote branch (e.g., `origin/main`)",
13381
- "3. Set REAP_PULL_TARGET_BRANCH to the branch name",
13382
- "4. Then run: reap run pull --phase check"
13469
+ "3. Then run: reap run pull --phase check <branch-name>"
13383
13470
  ].join(`
13384
13471
  `),
13385
13472
  nextCommand: "reap run pull --phase check"
13386
13473
  });
13387
13474
  }
13388
13475
  if (phase === "check") {
13389
- const targetBranch = process.env.REAP_PULL_TARGET_BRANCH;
13476
+ const targetBranch = targetBranchArg;
13390
13477
  if (!targetBranch) {
13391
- emitError("pull", "REAP_PULL_TARGET_BRANCH environment variable is required.");
13478
+ emitError("pull", "Target branch is required. Usage: reap run pull --phase check <branch>");
13392
13479
  }
13393
13480
  if (!gitRefExists(targetBranch, paths.projectRoot)) {
13394
13481
  emitError("pull", `Branch "${targetBranch}" does not exist. Run \`git fetch\` first.`);
@@ -13459,10 +13546,9 @@ async function execute26(paths, phase) {
13459
13546
  "## Branches have diverged -- full merge required",
13460
13547
  "",
13461
13548
  "Execute the following sequence:",
13462
- `1. Set REAP_MERGE_TARGET_BRANCH=${targetBranch}`,
13463
- "2. Run /reap.merge.start (creates merge generation + detect report)",
13464
- "3. Run /reap.merge.evolve (runs detect -> mate -> merge -> sync -> validation -> completion)",
13465
- "4. Run `git submodule update --init` after merge completes"
13549
+ `1. Run /reap.merge.start ${targetBranch} (creates merge generation + detect report)`,
13550
+ "2. Run /reap.merge.evolve (runs detect -> mate -> merge -> sync -> validation -> completion)",
13551
+ "3. Run `git submodule update --init` after merge completes"
13466
13552
  ].join(`
13467
13553
  `)
13468
13554
  });
@@ -13516,7 +13602,7 @@ __export(exports_run, {
13516
13602
  runCommand: () => runCommand
13517
13603
  });
13518
13604
  import { execSync as execSync6 } from "child_process";
13519
- async function runCommand(command, phase) {
13605
+ async function runCommand(command, phase, argv = []) {
13520
13606
  const cwd = process.cwd();
13521
13607
  const paths = new ReapPaths(cwd);
13522
13608
  if (!await paths.isReapProject()) {
@@ -13528,12 +13614,12 @@ async function runCommand(command, phase) {
13528
13614
  }
13529
13615
  try {
13530
13616
  const mod = await loader();
13531
- await mod.execute(paths, phase);
13617
+ await mod.execute(paths, phase, argv);
13532
13618
  } catch (err) {
13533
13619
  try {
13534
13620
  const config = await ConfigManager.read(paths);
13535
13621
  if (config.autoIssueReport) {
13536
- const version = "0.12.0";
13622
+ const version = "0.13.0";
13537
13623
  const errMsg = err instanceof Error ? err.message : String(err);
13538
13624
  const title = `[auto] reap run ${command}: ${errMsg.slice(0, 80)}`;
13539
13625
  const body = [
@@ -14119,7 +14205,7 @@ async function initProject(projectRoot, projectName, entryMode, preset, onProgre
14119
14205
  }
14120
14206
  const detectedLanguage = await AgentRegistry.readLanguage();
14121
14207
  const config = {
14122
- version: "0.12.0",
14208
+ version: "0.13.0",
14123
14209
  project: projectName,
14124
14210
  entryMode,
14125
14211
  strict: false,
@@ -14718,7 +14804,7 @@ async function updateProject(projectRoot, dryRun = false) {
14718
14804
  result.skipped.push(`.claude/commands/ (${reapCmdFiles.length} unchanged)`);
14719
14805
  }
14720
14806
  await migrateLegacyFiles(paths, dryRun, result);
14721
- const currentVersion = "0.12.0";
14807
+ const currentVersion = "0.13.0";
14722
14808
  const migrationResult = await MigrationRunner.run(paths, currentVersion, dryRun);
14723
14809
  for (const m of migrationResult.migrated) {
14724
14810
  result.updated.push(`[migration] ${m}`);
@@ -14916,7 +15002,7 @@ init_fs();
14916
15002
  init_version();
14917
15003
  init_config();
14918
15004
  import { join as join26 } from "path";
14919
- program.name("reap").description("REAP — Recursive Evolutionary Autonomous Pipeline").version("0.12.0");
15005
+ program.name("reap").description("REAP — Recursive Evolutionary Autonomous Pipeline").version("0.13.0");
14920
15006
  program.command("init").description("Initialize a new REAP project (Genesis)").argument("[project-name]", "Project name (defaults to current directory name)").option("-m, --mode <mode>", "Entry mode: greenfield, migration, adoption", "greenfield").option("-p, --preset <preset>", "Bootstrap with a genome preset (e.g., bun-hono-react)").action(async (projectName, options) => {
14921
15007
  try {
14922
15008
  const cwd = process.cwd();
@@ -15060,8 +15146,17 @@ program.command("help").description("Show REAP commands, slash commands, and wor
15060
15146
  }
15061
15147
  console.log(helpText);
15062
15148
  });
15063
- program.command("run <command>").description("Run a REAP command script (internal, used by slash commands)").option("--phase <phase>", "Start from a specific phase").action(async (command, options) => {
15149
+ program.command("run <command>").description("Run a REAP command script (internal, used by slash commands)").option("--phase <phase>", "Start from a specific phase").allowUnknownOption().action(async (command, options, cmd) => {
15150
+ const rawArgs = cmd.args.slice(1);
15151
+ const passArgs = [];
15152
+ for (let i = 0;i < rawArgs.length; i++) {
15153
+ if (rawArgs[i] === "--phase") {
15154
+ i++;
15155
+ continue;
15156
+ }
15157
+ passArgs.push(rawArgs[i]);
15158
+ }
15064
15159
  const { runCommand: runCommand2 } = await Promise.resolve().then(() => (init_run(), exports_run));
15065
- await runCommand2(command, options.phase);
15160
+ await runCommand2(command, options.phase, passArgs);
15066
15161
  });
15067
15162
  program.parse();
@@ -2,4 +2,4 @@
2
2
  description: "REAP Abort — Abort the current generation and return to initial state"
3
3
  ---
4
4
 
5
- Run `reap run abort` and follow the stdout instructions exactly.
5
+ Run `reap run abort $ARGUMENTS` and follow the stdout instructions exactly.
@@ -2,4 +2,4 @@
2
2
  description: "REAP Back — Return to a previous lifecycle stage"
3
3
  ---
4
4
 
5
- Run `reap run back` and follow the stdout instructions exactly.
5
+ Run `reap run back $ARGUMENTS` and follow the stdout instructions exactly.
@@ -2,4 +2,4 @@
2
2
  description: "REAP Help — Contextual help based on current state"
3
3
  ---
4
4
 
5
- Run `reap run help` and follow the stdout instructions exactly.
5
+ Run `reap run help $ARGUMENTS` and follow the stdout instructions exactly.
@@ -2,4 +2,4 @@
2
2
  description: "REAP Merge — Run a full merge generation for a local branch"
3
3
  ---
4
4
 
5
- Run `reap run merge` and follow the stdout instructions exactly.
5
+ Run `reap run merge $ARGUMENTS` and follow the stdout instructions exactly.
@@ -2,4 +2,4 @@
2
2
  description: "REAP Merge Start — Start a merge generation to combine divergent branches"
3
3
  ---
4
4
 
5
- Run `reap run merge-start` and follow the stdout instructions exactly.
5
+ Run `reap run merge-start $ARGUMENTS` and follow the stdout instructions exactly.
@@ -2,4 +2,4 @@
2
2
  description: "REAP Next — Advance to the next lifecycle stage"
3
3
  ---
4
4
 
5
- Run `reap run next` and follow the stdout instructions exactly.
5
+ Run `reap run next $ARGUMENTS` and follow the stdout instructions exactly.
@@ -2,4 +2,4 @@
2
2
  description: "REAP Pull — Fetch remote, detect divergence, and run a full merge generation"
3
3
  ---
4
4
 
5
- Run `reap run pull` and follow the stdout instructions exactly.
5
+ Run `reap run pull $ARGUMENTS` and follow the stdout instructions exactly.
@@ -2,4 +2,4 @@
2
2
  description: "REAP Start — Start a new Generation"
3
3
  ---
4
4
 
5
- Run `reap run start` and follow the stdout instructions exactly.
5
+ Run `reap run start $ARGUMENTS` and follow the stdout instructions exactly.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c-d-cc/reap",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Recursive Evolutionary Autonomous Pipeline — AI and humans evolve software across generations",
5
5
  "type": "module",
6
6
  "license": "MIT",