@c-d-cc/reap 0.15.3 → 0.15.5

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
@@ -1943,9 +1943,6 @@ class ReapPaths {
1943
1943
  get backlog() {
1944
1944
  return join(this.life, "backlog");
1945
1945
  }
1946
- get mutations() {
1947
- return join(this.life, "mutations");
1948
- }
1949
1946
  artifact(name) {
1950
1947
  return join(this.life, name);
1951
1948
  }
@@ -9873,7 +9870,7 @@ async function compressLineageIfNeeded(paths, projectRoot) {
9873
9870
  }
9874
9871
  return result;
9875
9872
  }
9876
- var import_yaml2, LINEAGE_MAX_LINES = 5000, MIN_GENERATIONS_FOR_COMPRESSION = 5, LEVEL1_MAX_LINES = 40, LEVEL1_PROTECTED_COUNT = 3, LEVEL2_MIN_LEVEL1_COUNT = 100, LEVEL2_PROTECTED_COUNT = 9;
9873
+ var import_yaml2, LINEAGE_MAX_LINES = 1e4, MIN_GENERATIONS_FOR_COMPRESSION = 5, LEVEL1_MAX_LINES = 40, LEVEL1_PROTECTED_COUNT = 20, LEVEL2_MIN_LEVEL1_COUNT = 100, LEVEL2_PROTECTED_COUNT = 9;
9877
9874
  var init_compression = __esm(() => {
9878
9875
  init_fs();
9879
9876
  init_git();
@@ -9992,7 +9989,7 @@ var init_lineage = __esm(() => {
9992
9989
  // src/core/generation.ts
9993
9990
  import { createHash, randomBytes } from "crypto";
9994
9991
  import { hostname } from "os";
9995
- import { readdir as readdir9, mkdir as mkdir6, rename, unlink as unlink4 } from "fs/promises";
9992
+ import { readdir as readdir9, mkdir as mkdir6, unlink as unlink4 } from "fs/promises";
9996
9993
  import { join as join10 } from "path";
9997
9994
  function generateToken(genId, stage, phase) {
9998
9995
  const nonce = randomBytes(16).toString("hex");
@@ -10167,22 +10164,12 @@ class GenerationManager {
10167
10164
  if (!content)
10168
10165
  continue;
10169
10166
  const isConsumed = /status:\s*consumed/i.test(content) || /consumed:\s*true/i.test(content);
10170
- await writeTextFile(join10(backlogDir, entry), content);
10171
10167
  if (isConsumed) {
10168
+ await writeTextFile(join10(backlogDir, entry), content);
10172
10169
  await unlink4(join10(this.paths.backlog, entry));
10173
10170
  }
10174
10171
  }
10175
10172
  } catch {}
10176
- try {
10177
- const mutEntries = await readdir9(this.paths.mutations);
10178
- if (mutEntries.length > 0) {
10179
- const mutDir = join10(genDir, "mutations");
10180
- await mkdir6(mutDir, { recursive: true });
10181
- for (const entry of mutEntries) {
10182
- await rename(join10(this.paths.mutations, entry), join10(mutDir, entry));
10183
- }
10184
- }
10185
- } catch {}
10186
10173
  await writeTextFile(this.paths.currentYml, "");
10187
10174
  const compression = await compressLineageIfNeeded(this.paths, this.paths.projectRoot);
10188
10175
  return compression;
@@ -10214,7 +10201,7 @@ class GenerationManager {
10214
10201
  return `gen-${String(seq).padStart(3, "0")}`;
10215
10202
  }
10216
10203
  }
10217
- var import_yaml4, CURRENT_YML_HEADER = `# REAP MANAGED — Do not modify directly. Use reap run next/back/start/abort.
10204
+ var import_yaml4, CURRENT_YML_HEADER = `# REAP MANAGED — Do not modify directly. Use 'reap run <stage> --phase <phase>' to update.
10218
10205
  `;
10219
10206
  var init_generation = __esm(() => {
10220
10207
  init_lifecycle();
@@ -10238,6 +10225,9 @@ function checkLatestVersion() {
10238
10225
  return null;
10239
10226
  }
10240
10227
  }
10228
+ function getCurrentVersion() {
10229
+ return "0.15.5";
10230
+ }
10241
10231
  function formatVersionLine(current, skipCheck) {
10242
10232
  if (skipCheck) {
10243
10233
  return `REAP v${current}`;
@@ -10271,12 +10261,196 @@ function emitError(command, message, details) {
10271
10261
  process.exit(1);
10272
10262
  }
10273
10263
 
10264
+ // src/core/backlog.ts
10265
+ import { readdir as readdir14, mkdir as mkdir10 } from "fs/promises";
10266
+ import { join as join18 } from "path";
10267
+ async function scanBacklog(backlogDir) {
10268
+ let entries;
10269
+ try {
10270
+ entries = await readdir14(backlogDir);
10271
+ } catch {
10272
+ return [];
10273
+ }
10274
+ const items = [];
10275
+ for (const filename of entries) {
10276
+ if (!filename.endsWith(".md"))
10277
+ continue;
10278
+ const content = await readTextFile(join18(backlogDir, filename));
10279
+ if (!content)
10280
+ continue;
10281
+ const { frontmatter, body } = parseFrontmatter2(content);
10282
+ const title = body.match(/^#\s+(.+)/m)?.[1] ?? (frontmatter.title != null ? String(frontmatter.title) : filename.replace(/\.md$/, ""));
10283
+ items.push({
10284
+ filename,
10285
+ type: String(frontmatter.type ?? "task"),
10286
+ status: String(frontmatter.status ?? "pending"),
10287
+ consumedBy: frontmatter.consumedBy != null ? String(frontmatter.consumedBy) : undefined,
10288
+ target: frontmatter.target != null ? String(frontmatter.target) : undefined,
10289
+ title,
10290
+ body
10291
+ });
10292
+ }
10293
+ return items;
10294
+ }
10295
+ async function markBacklogConsumed(backlogDir, filename, genId) {
10296
+ const filePath = join18(backlogDir, filename);
10297
+ const content = await readTextFile(filePath);
10298
+ if (!content)
10299
+ return;
10300
+ const { frontmatter, body } = parseFrontmatter2(content);
10301
+ frontmatter.status = "consumed";
10302
+ frontmatter.consumedBy = genId;
10303
+ delete frontmatter.consumed;
10304
+ const newContent = `---
10305
+ ${import_yaml8.default.stringify(frontmatter).trim()}
10306
+ ---
10307
+ ${body}`;
10308
+ await writeTextFile(filePath, newContent);
10309
+ }
10310
+ async function revertBacklogConsumed(backlogDir, genId) {
10311
+ let entries;
10312
+ try {
10313
+ entries = await readdir14(backlogDir);
10314
+ } catch {
10315
+ return;
10316
+ }
10317
+ for (const filename of entries) {
10318
+ if (!filename.endsWith(".md"))
10319
+ continue;
10320
+ const filePath = join18(backlogDir, filename);
10321
+ const content = await readTextFile(filePath);
10322
+ if (!content)
10323
+ continue;
10324
+ const { frontmatter, body } = parseFrontmatter2(content);
10325
+ if (frontmatter.status === "consumed" && frontmatter.consumedBy === genId) {
10326
+ frontmatter.status = "pending";
10327
+ delete frontmatter.consumedBy;
10328
+ const newContent = `---
10329
+ ${import_yaml8.default.stringify(frontmatter).trim()}
10330
+ ---
10331
+ ${body}`;
10332
+ await writeTextFile(filePath, newContent);
10333
+ }
10334
+ }
10335
+ }
10336
+ function parseFrontmatter2(content) {
10337
+ const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
10338
+ if (!match)
10339
+ return { frontmatter: {}, body: content };
10340
+ try {
10341
+ return { frontmatter: import_yaml8.default.parse(match[1]) ?? {}, body: match[2] };
10342
+ } catch {
10343
+ return { frontmatter: {}, body: content };
10344
+ }
10345
+ }
10346
+ function toKebabCase(title) {
10347
+ return title.toLowerCase().replace(/[^a-z0-9가-힣\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
10348
+ }
10349
+ async function createBacklog(backlogDir, opts) {
10350
+ if (!VALID_BACKLOG_TYPES2.includes(opts.type)) {
10351
+ throw new Error(`Invalid backlog type: "${opts.type}". Allowed: ${VALID_BACKLOG_TYPES2.join(", ")}`);
10352
+ }
10353
+ const priority = opts.priority ?? "medium";
10354
+ const filename = `${toKebabCase(opts.title)}.md`;
10355
+ const frontmatter = {
10356
+ type: opts.type,
10357
+ status: "pending",
10358
+ priority
10359
+ };
10360
+ const bodyContent = opts.body ? `
10361
+ # ${opts.title}
10362
+
10363
+ ${opts.body}
10364
+ ` : `
10365
+ # ${opts.title}
10366
+ `;
10367
+ const content = `---
10368
+ ${import_yaml8.default.stringify(frontmatter).trim()}
10369
+ ---
10370
+ ${bodyContent}`;
10371
+ await mkdir10(backlogDir, { recursive: true });
10372
+ await writeTextFile(join18(backlogDir, filename), content);
10373
+ return filename;
10374
+ }
10375
+ var import_yaml8, VALID_BACKLOG_TYPES2;
10376
+ var init_backlog = __esm(() => {
10377
+ init_fs();
10378
+ import_yaml8 = __toESM(require_dist(), 1);
10379
+ VALID_BACKLOG_TYPES2 = ["genome-change", "environment-change", "task"];
10380
+ });
10381
+
10382
+ // src/cli/commands/make/backlog.ts
10383
+ var exports_backlog = {};
10384
+ __export(exports_backlog, {
10385
+ execute: () => execute
10386
+ });
10387
+ function parseFlags(argv) {
10388
+ const flags = {};
10389
+ for (let i = 0;i < argv.length; i++) {
10390
+ const arg = argv[i];
10391
+ if (arg.startsWith("--") && i + 1 < argv.length) {
10392
+ flags[arg.slice(2)] = argv[++i];
10393
+ }
10394
+ }
10395
+ return flags;
10396
+ }
10397
+ async function execute(paths, argv) {
10398
+ const flags = parseFlags(argv);
10399
+ if (!flags.type) {
10400
+ emitError("make", `--type is required. Allowed: ${VALID_BACKLOG_TYPES2.join(", ")}`);
10401
+ }
10402
+ if (!flags.title) {
10403
+ emitError("make", "--title is required.");
10404
+ }
10405
+ const filename = await createBacklog(paths.backlog, {
10406
+ type: flags.type,
10407
+ title: flags.title,
10408
+ body: flags.body,
10409
+ priority: flags.priority
10410
+ });
10411
+ emitOutput({
10412
+ status: "ok",
10413
+ command: "make",
10414
+ phase: "done",
10415
+ completed: ["backlog-create"],
10416
+ message: `Backlog created: ${filename}. Edit the file directly to add detailed content (headers, lists, code blocks, etc.).`,
10417
+ context: { filename, type: flags.type, title: flags.title, path: `${paths.backlog}/${filename}` }
10418
+ });
10419
+ }
10420
+ var init_backlog2 = __esm(() => {
10421
+ init_backlog();
10422
+ });
10423
+
10424
+ // src/cli/commands/make/index.ts
10425
+ var exports_make = {};
10426
+ __export(exports_make, {
10427
+ execute: () => execute2
10428
+ });
10429
+ async function execute2(paths, _phase, argv = []) {
10430
+ const target = argv[0];
10431
+ if (!target) {
10432
+ emitError("make", `Target required. Available: ${Object.keys(TARGETS).join(", ")}`);
10433
+ }
10434
+ const loader = TARGETS[target];
10435
+ if (!loader) {
10436
+ emitError("make", `Unknown target: "${target}". Available: ${Object.keys(TARGETS).join(", ")}`);
10437
+ }
10438
+ const mod = await loader();
10439
+ await mod.execute(paths, argv.slice(1));
10440
+ }
10441
+ var TARGETS;
10442
+ var init_make = __esm(() => {
10443
+ TARGETS = {
10444
+ backlog: () => Promise.resolve().then(() => (init_backlog2(), exports_backlog))
10445
+ };
10446
+ });
10447
+
10274
10448
  // src/cli/commands/run/next.ts
10275
10449
  var exports_next = {};
10276
10450
  __export(exports_next, {
10277
- execute: () => execute
10451
+ execute: () => execute3
10278
10452
  });
10279
- async function execute(paths, _phase) {
10453
+ async function execute3(paths, _phase) {
10280
10454
  const gm = new GenerationManager(paths);
10281
10455
  const state = await gm.current();
10282
10456
  if (!state) {
@@ -10352,14 +10526,14 @@ var init_merge_lifecycle = __esm(() => {
10352
10526
  });
10353
10527
 
10354
10528
  // src/core/hook-engine.ts
10355
- import { readdir as readdir14 } from "fs/promises";
10356
- import { join as join17 } from "path";
10529
+ import { readdir as readdir15 } from "fs/promises";
10530
+ import { join as join19 } from "path";
10357
10531
  import { execSync as execSync5 } from "child_process";
10358
10532
  async function executeHooks(hooksDir, event, projectRoot) {
10359
10533
  const hooks = await scanHooks(hooksDir, event);
10360
10534
  if (hooks.length === 0)
10361
10535
  return [];
10362
- const conditionsDir = join17(hooksDir, "conditions");
10536
+ const conditionsDir = join19(hooksDir, "conditions");
10363
10537
  const results = [];
10364
10538
  for (const hook of hooks) {
10365
10539
  const conditionMet = await evaluateCondition(conditionsDir, hook.condition, projectRoot);
@@ -10384,7 +10558,7 @@ async function executeHooks(hooksDir, event, projectRoot) {
10384
10558
  async function scanHooks(hooksDir, event) {
10385
10559
  let entries;
10386
10560
  try {
10387
- entries = await readdir14(hooksDir);
10561
+ entries = await readdir15(hooksDir);
10388
10562
  } catch {
10389
10563
  return [];
10390
10564
  }
@@ -10394,7 +10568,7 @@ async function scanHooks(hooksDir, event) {
10394
10568
  const match = filename.match(pattern);
10395
10569
  if (!match)
10396
10570
  continue;
10397
- const meta = await parseHookMeta(join17(hooksDir, filename), match[2]);
10571
+ const meta = await parseHookMeta(join19(hooksDir, filename), match[2]);
10398
10572
  hooks.push({
10399
10573
  filename,
10400
10574
  name: match[1],
@@ -10415,7 +10589,7 @@ async function parseHookMeta(filePath, ext) {
10415
10589
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
10416
10590
  if (fmMatch) {
10417
10591
  try {
10418
- const fm = import_yaml8.default.parse(fmMatch[1]) ?? {};
10592
+ const fm = import_yaml9.default.parse(fmMatch[1]) ?? {};
10419
10593
  return {
10420
10594
  condition: String(fm.condition ?? "always"),
10421
10595
  order: Number(fm.order ?? 50)
@@ -10441,7 +10615,7 @@ async function parseHookMeta(filePath, ext) {
10441
10615
  async function evaluateCondition(conditionsDir, conditionName, projectRoot) {
10442
10616
  if (conditionName === "always")
10443
10617
  return { met: true };
10444
- const scriptPath = join17(conditionsDir, `${conditionName}.sh`);
10618
+ const scriptPath = join19(conditionsDir, `${conditionName}.sh`);
10445
10619
  if (!await fileExists(scriptPath)) {
10446
10620
  return { met: false, reason: `condition script not found: ${conditionName}.sh` };
10447
10621
  }
@@ -10454,7 +10628,7 @@ async function evaluateCondition(conditionsDir, conditionName, projectRoot) {
10454
10628
  }
10455
10629
  async function executeShHook(hook, event, projectRoot, hooksDir) {
10456
10630
  try {
10457
- const stdout = execSync5(`bash "${join17(hooksDir, hook.filename)}"`, {
10631
+ const stdout = execSync5(`bash "${join19(hooksDir, hook.filename)}"`, {
10458
10632
  cwd: projectRoot,
10459
10633
  timeout: 60000,
10460
10634
  stdio: "pipe"
@@ -10480,7 +10654,7 @@ async function executeShHook(hook, event, projectRoot, hooksDir) {
10480
10654
  }
10481
10655
  }
10482
10656
  async function executeMdHook(hook, event, hooksDir) {
10483
- const content = await readTextFile(join17(hooksDir, hook.filename));
10657
+ const content = await readTextFile(join19(hooksDir, hook.filename));
10484
10658
  const body = content?.replace(/^---\n[\s\S]*?\n---\n?/, "").trim() ?? "";
10485
10659
  return {
10486
10660
  name: hook.name,
@@ -10490,16 +10664,111 @@ async function executeMdHook(hook, event, hooksDir) {
10490
10664
  content: body
10491
10665
  };
10492
10666
  }
10493
- var import_yaml8;
10667
+ var import_yaml9;
10494
10668
  var init_hook_engine = __esm(() => {
10495
10669
  init_fs();
10496
- import_yaml8 = __toESM(require_dist(), 1);
10670
+ import_yaml9 = __toESM(require_dist(), 1);
10671
+ });
10672
+
10673
+ // src/core/stage-transition.ts
10674
+ import { join as join20 } from "path";
10675
+ function verifyNonce(command, state, stage, phase) {
10676
+ if (!state.lastNonce) {
10677
+ return;
10678
+ }
10679
+ if (!state.expectedHash) {
10680
+ emitError(command, "Nonce transition error: lastNonce exists but expectedHash is missing. State may be corrupted.");
10681
+ }
10682
+ if (!verifyToken(state.lastNonce, state.id, stage, state.expectedHash, phase)) {
10683
+ emitError(command, `Nonce verification failed for ${stage}:${phase}. Re-run the previous phase to get a valid token.`);
10684
+ }
10685
+ state.lastNonce = undefined;
10686
+ state.expectedHash = undefined;
10687
+ state.phase = undefined;
10688
+ }
10689
+ function setNonce(state, stage, phase) {
10690
+ const { nonce, hash } = generateToken(state.id, stage, phase);
10691
+ state.lastNonce = nonce;
10692
+ state.expectedHash = hash;
10693
+ state.phase = phase;
10694
+ }
10695
+ async function performTransition(paths, state, saveFn) {
10696
+ const isMerge = state.type === "merge";
10697
+ let nextStage;
10698
+ if (isMerge) {
10699
+ nextStage = MergeLifeCycle.next(state.stage);
10700
+ } else {
10701
+ nextStage = LifeCycle.next(state.stage);
10702
+ }
10703
+ if (!nextStage) {
10704
+ throw new Error(`Cannot advance from '${state.stage}' — already at the last stage.`);
10705
+ }
10706
+ state.stage = nextStage;
10707
+ if (!state.timeline)
10708
+ state.timeline = [];
10709
+ state.timeline.push({ stage: nextStage, at: new Date().toISOString() });
10710
+ await saveFn(state);
10711
+ const artifactFile = isMerge ? MERGE_ARTIFACT[nextStage] : NORMAL_ARTIFACT[nextStage];
10712
+ if (artifactFile) {
10713
+ const templateDir = join20(__require("os").homedir(), ".reap", "templates");
10714
+ const templatePath = join20(templateDir, artifactFile);
10715
+ const destPath = paths.artifact(artifactFile);
10716
+ if (await fileExists(templatePath) && !await fileExists(destPath)) {
10717
+ const templateContent = await readTextFile(templatePath);
10718
+ if (templateContent) {
10719
+ await writeTextFile(destPath, templateContent);
10720
+ }
10721
+ }
10722
+ }
10723
+ const stageKey = isMerge && (nextStage === "validation" || nextStage === "completion") ? `${nextStage}:merge` : nextStage;
10724
+ const stageHookEvent = STAGE_HOOK[stageKey];
10725
+ const stageHookResults = stageHookEvent ? await executeHooks(paths.hooks, stageHookEvent, paths.projectRoot) : [];
10726
+ const transitionEvent = isMerge ? "onMergeTransited" : "onLifeTransited";
10727
+ const transitionHookResults = await executeHooks(paths.hooks, transitionEvent, paths.projectRoot);
10728
+ return {
10729
+ nextStage,
10730
+ artifactFile,
10731
+ stageHookResults,
10732
+ transitionHookResults
10733
+ };
10734
+ }
10735
+ var NORMAL_ARTIFACT, MERGE_ARTIFACT, STAGE_HOOK;
10736
+ var init_stage_transition = __esm(() => {
10737
+ init_lifecycle();
10738
+ init_merge_lifecycle();
10739
+ init_generation();
10740
+ init_fs();
10741
+ init_hook_engine();
10742
+ NORMAL_ARTIFACT = {
10743
+ planning: "02-planning.md",
10744
+ implementation: "03-implementation.md",
10745
+ validation: "04-validation.md",
10746
+ completion: "05-completion.md"
10747
+ };
10748
+ MERGE_ARTIFACT = {
10749
+ mate: "02-mate.md",
10750
+ merge: "03-merge.md",
10751
+ sync: "04-sync.md",
10752
+ validation: "05-validation.md",
10753
+ completion: "06-completion.md"
10754
+ };
10755
+ STAGE_HOOK = {
10756
+ planning: "onLifeObjected",
10757
+ implementation: "onLifePlanned",
10758
+ validation: "onLifeImplemented",
10759
+ completion: "onLifeValidated",
10760
+ mate: "onMergeDetected",
10761
+ merge: "onMergeMated",
10762
+ sync: "onMergeMerged",
10763
+ "validation:merge": "onMergeSynced",
10764
+ "completion:merge": "onMergeValidated"
10765
+ };
10497
10766
  });
10498
10767
 
10499
10768
  // src/cli/commands/run/back.ts
10500
10769
  var exports_back = {};
10501
10770
  __export(exports_back, {
10502
- execute: () => execute2
10771
+ execute: () => execute4
10503
10772
  });
10504
10773
  function getFlag(args, name) {
10505
10774
  const idx = args.indexOf(`--${name}`);
@@ -10518,7 +10787,7 @@ function getPositionals(args, valueFlags) {
10518
10787
  }
10519
10788
  return result;
10520
10789
  }
10521
- async function execute2(paths, phase, argv = []) {
10790
+ async function execute4(paths, phase, argv = []) {
10522
10791
  const gm = new GenerationManager(paths);
10523
10792
  const state = await gm.current();
10524
10793
  if (!state) {
@@ -10563,6 +10832,7 @@ async function execute2(paths, phase, argv = []) {
10563
10832
  const reason = getFlag(argv, "reason") ?? "No reason provided";
10564
10833
  const refs = (getFlag(argv, "refs") ?? "").split(",").filter(Boolean);
10565
10834
  state.stage = target;
10835
+ setNonce(state, target, "entry");
10566
10836
  state.timeline.push({
10567
10837
  stage: target,
10568
10838
  at: new Date().toISOString(),
@@ -10596,216 +10866,34 @@ var init_back = __esm(() => {
10596
10866
  init_lifecycle();
10597
10867
  init_merge_lifecycle();
10598
10868
  init_hook_engine();
10869
+ init_stage_transition();
10599
10870
  });
10600
10871
 
10601
- // src/core/stage-transition.ts
10602
- import { join as join18 } from "path";
10603
- function verifyNonce(command, state, stage, phase) {
10604
- if (!state.lastNonce) {
10605
- return;
10606
- }
10607
- if (!state.expectedHash) {
10608
- emitError(command, "Nonce transition error: lastNonce exists but expectedHash is missing. State may be corrupted.");
10609
- }
10610
- if (!verifyToken(state.lastNonce, state.id, stage, state.expectedHash, phase)) {
10611
- emitError(command, `Nonce verification failed for ${stage}:${phase}. Re-run the previous phase to get a valid token.`);
10872
+ // src/cli/commands/run/start.ts
10873
+ var exports_start = {};
10874
+ __export(exports_start, {
10875
+ execute: () => execute5
10876
+ });
10877
+ import { join as join21 } from "path";
10878
+ import { readdir as readdir16 } from "fs/promises";
10879
+ function getFlag2(args, name) {
10880
+ const idx = args.indexOf(`--${name}`);
10881
+ return idx !== -1 && args[idx + 1] ? args[idx + 1] : undefined;
10882
+ }
10883
+ function getPositionals2(args, valueFlags) {
10884
+ const result = [];
10885
+ for (let i = 0;i < args.length; i++) {
10886
+ if (args[i].startsWith("--")) {
10887
+ const flagName = args[i].slice(2);
10888
+ if (valueFlags.includes(flagName) && i + 1 < args.length)
10889
+ i++;
10890
+ continue;
10891
+ }
10892
+ result.push(args[i]);
10612
10893
  }
10613
- state.lastNonce = undefined;
10614
- state.expectedHash = undefined;
10615
- state.phase = undefined;
10894
+ return result;
10616
10895
  }
10617
- function setNonce(state, stage, phase) {
10618
- const { nonce, hash } = generateToken(state.id, stage, phase);
10619
- state.lastNonce = nonce;
10620
- state.expectedHash = hash;
10621
- state.phase = phase;
10622
- }
10623
- async function performTransition(paths, state, saveFn) {
10624
- const isMerge = state.type === "merge";
10625
- let nextStage;
10626
- if (isMerge) {
10627
- nextStage = MergeLifeCycle.next(state.stage);
10628
- } else {
10629
- nextStage = LifeCycle.next(state.stage);
10630
- }
10631
- if (!nextStage) {
10632
- throw new Error(`Cannot advance from '${state.stage}' — already at the last stage.`);
10633
- }
10634
- state.stage = nextStage;
10635
- if (!state.timeline)
10636
- state.timeline = [];
10637
- state.timeline.push({ stage: nextStage, at: new Date().toISOString() });
10638
- await saveFn(state);
10639
- const artifactFile = isMerge ? MERGE_ARTIFACT[nextStage] : NORMAL_ARTIFACT[nextStage];
10640
- if (artifactFile) {
10641
- const templateDir = join18(__require("os").homedir(), ".reap", "templates");
10642
- const templatePath = join18(templateDir, artifactFile);
10643
- const destPath = paths.artifact(artifactFile);
10644
- if (await fileExists(templatePath) && !await fileExists(destPath)) {
10645
- const templateContent = await readTextFile(templatePath);
10646
- if (templateContent) {
10647
- await writeTextFile(destPath, templateContent);
10648
- }
10649
- }
10650
- }
10651
- const stageKey = isMerge && (nextStage === "validation" || nextStage === "completion") ? `${nextStage}:merge` : nextStage;
10652
- const stageHookEvent = STAGE_HOOK[stageKey];
10653
- const stageHookResults = stageHookEvent ? await executeHooks(paths.hooks, stageHookEvent, paths.projectRoot) : [];
10654
- const transitionEvent = isMerge ? "onMergeTransited" : "onLifeTransited";
10655
- const transitionHookResults = await executeHooks(paths.hooks, transitionEvent, paths.projectRoot);
10656
- return {
10657
- nextStage,
10658
- artifactFile,
10659
- stageHookResults,
10660
- transitionHookResults
10661
- };
10662
- }
10663
- var NORMAL_ARTIFACT, MERGE_ARTIFACT, STAGE_HOOK;
10664
- var init_stage_transition = __esm(() => {
10665
- init_lifecycle();
10666
- init_merge_lifecycle();
10667
- init_generation();
10668
- init_fs();
10669
- init_hook_engine();
10670
- NORMAL_ARTIFACT = {
10671
- planning: "02-planning.md",
10672
- implementation: "03-implementation.md",
10673
- validation: "04-validation.md",
10674
- completion: "05-completion.md"
10675
- };
10676
- MERGE_ARTIFACT = {
10677
- mate: "02-mate.md",
10678
- merge: "03-merge.md",
10679
- sync: "04-sync.md",
10680
- validation: "05-validation.md",
10681
- completion: "06-completion.md"
10682
- };
10683
- STAGE_HOOK = {
10684
- planning: "onLifeObjected",
10685
- implementation: "onLifePlanned",
10686
- validation: "onLifeImplemented",
10687
- completion: "onLifeValidated",
10688
- mate: "onMergeDetected",
10689
- merge: "onMergeMated",
10690
- sync: "onMergeMerged",
10691
- "validation:merge": "onMergeSynced",
10692
- "completion:merge": "onMergeValidated"
10693
- };
10694
- });
10695
-
10696
- // src/core/backlog.ts
10697
- import { readdir as readdir15 } from "fs/promises";
10698
- import { join as join19 } from "path";
10699
- async function scanBacklog(backlogDir) {
10700
- let entries;
10701
- try {
10702
- entries = await readdir15(backlogDir);
10703
- } catch {
10704
- return [];
10705
- }
10706
- const items = [];
10707
- for (const filename of entries) {
10708
- if (!filename.endsWith(".md"))
10709
- continue;
10710
- const content = await readTextFile(join19(backlogDir, filename));
10711
- if (!content)
10712
- continue;
10713
- const { frontmatter, body } = parseFrontmatter2(content);
10714
- const title = body.match(/^#\s+(.+)/m)?.[1] ?? (frontmatter.title != null ? String(frontmatter.title) : filename.replace(/\.md$/, ""));
10715
- items.push({
10716
- filename,
10717
- type: String(frontmatter.type ?? "task"),
10718
- status: String(frontmatter.status ?? "pending"),
10719
- consumedBy: frontmatter.consumedBy != null ? String(frontmatter.consumedBy) : undefined,
10720
- target: frontmatter.target != null ? String(frontmatter.target) : undefined,
10721
- title,
10722
- body
10723
- });
10724
- }
10725
- return items;
10726
- }
10727
- async function markBacklogConsumed(backlogDir, filename, genId) {
10728
- const filePath = join19(backlogDir, filename);
10729
- const content = await readTextFile(filePath);
10730
- if (!content)
10731
- return;
10732
- const { frontmatter, body } = parseFrontmatter2(content);
10733
- frontmatter.status = "consumed";
10734
- frontmatter.consumedBy = genId;
10735
- delete frontmatter.consumed;
10736
- const newContent = `---
10737
- ${import_yaml9.default.stringify(frontmatter).trim()}
10738
- ---
10739
- ${body}`;
10740
- await writeTextFile(filePath, newContent);
10741
- }
10742
- async function revertBacklogConsumed(backlogDir, genId) {
10743
- let entries;
10744
- try {
10745
- entries = await readdir15(backlogDir);
10746
- } catch {
10747
- return;
10748
- }
10749
- for (const filename of entries) {
10750
- if (!filename.endsWith(".md"))
10751
- continue;
10752
- const filePath = join19(backlogDir, filename);
10753
- const content = await readTextFile(filePath);
10754
- if (!content)
10755
- continue;
10756
- const { frontmatter, body } = parseFrontmatter2(content);
10757
- if (frontmatter.status === "consumed" && frontmatter.consumedBy === genId) {
10758
- frontmatter.status = "pending";
10759
- delete frontmatter.consumedBy;
10760
- const newContent = `---
10761
- ${import_yaml9.default.stringify(frontmatter).trim()}
10762
- ---
10763
- ${body}`;
10764
- await writeTextFile(filePath, newContent);
10765
- }
10766
- }
10767
- }
10768
- function parseFrontmatter2(content) {
10769
- const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
10770
- if (!match)
10771
- return { frontmatter: {}, body: content };
10772
- try {
10773
- return { frontmatter: import_yaml9.default.parse(match[1]) ?? {}, body: match[2] };
10774
- } catch {
10775
- return { frontmatter: {}, body: content };
10776
- }
10777
- }
10778
- var import_yaml9;
10779
- var init_backlog = __esm(() => {
10780
- init_fs();
10781
- import_yaml9 = __toESM(require_dist(), 1);
10782
- });
10783
-
10784
- // src/cli/commands/run/start.ts
10785
- var exports_start = {};
10786
- __export(exports_start, {
10787
- execute: () => execute3
10788
- });
10789
- import { join as join20 } from "path";
10790
- import { readdir as readdir16 } from "fs/promises";
10791
- function getFlag2(args, name) {
10792
- const idx = args.indexOf(`--${name}`);
10793
- return idx !== -1 && args[idx + 1] ? args[idx + 1] : undefined;
10794
- }
10795
- function getPositionals2(args, valueFlags) {
10796
- const result = [];
10797
- for (let i = 0;i < args.length; i++) {
10798
- if (args[i].startsWith("--")) {
10799
- const flagName = args[i].slice(2);
10800
- if (valueFlags.includes(flagName) && i + 1 < args.length)
10801
- i++;
10802
- continue;
10803
- }
10804
- result.push(args[i]);
10805
- }
10806
- return result;
10807
- }
10808
- async function execute3(paths, phase, argv = []) {
10896
+ async function execute5(paths, phase, argv = []) {
10809
10897
  const positionals = getPositionals2(argv, ["backlog"]);
10810
10898
  const goal = positionals.join(" ") || undefined;
10811
10899
  const backlogFile = getFlag2(argv, "backlog");
@@ -10845,8 +10933,8 @@ async function execute3(paths, phase, argv = []) {
10845
10933
  if (backlogFile) {
10846
10934
  await markBacklogConsumed(paths.backlog, backlogFile, state.id);
10847
10935
  }
10848
- const templateDir = join20(__require("os").homedir(), ".reap", "templates");
10849
- const templatePath = join20(templateDir, "01-objective.md");
10936
+ const templateDir = join21(__require("os").homedir(), ".reap", "templates");
10937
+ const templatePath = join21(templateDir, "01-objective.md");
10850
10938
  const destPath = paths.artifact("01-objective.md");
10851
10939
  if (await fileExists(templatePath)) {
10852
10940
  let template = await readTextFile(templatePath);
@@ -10909,9 +10997,9 @@ var init_commit = () => {};
10909
10997
  // src/cli/commands/run/completion.ts
10910
10998
  var exports_completion = {};
10911
10999
  __export(exports_completion, {
10912
- execute: () => execute4
11000
+ execute: () => execute6
10913
11001
  });
10914
- import { join as join21 } from "path";
11002
+ import { join as join22 } from "path";
10915
11003
  import { execSync as execSync7 } from "child_process";
10916
11004
  function detectGenomeImpact(projectRoot) {
10917
11005
  const impact = {
@@ -10961,7 +11049,9 @@ function buildGenomeImpactPrompt(impact) {
10961
11049
  "",
10962
11050
  "",
10963
11051
  "## Genome/Environment Impact Detection",
10964
- "다음 변경이 감지되었습니다. genome-change 또는 environment-change backlog 작성이 필요한지 검토하라:",
11052
+ "다음 변경이 감지되었습니다. genome-change 또는 environment-change backlog 작성이 필요한지 검토하라.",
11053
+ "backlog 생성 시 반드시 `reap make backlog --type <type> --title <title> --body <body>` 명령을 사용하라. Write로 직접 파일을 생성하지 마라.",
11054
+ "생성된 backlog 파일에 상세 내용을 추가해야 하면, 생성 후 해당 파일을 편집하라.",
10965
11055
  "",
10966
11056
  ...lines
10967
11057
  ].join(`
@@ -10983,7 +11073,7 @@ ${h.content}`);
10983
11073
  ].join(`
10984
11074
  `);
10985
11075
  }
10986
- async function execute4(paths, phase) {
11076
+ async function execute6(paths, phase) {
10987
11077
  const gm = new GenerationManager(paths);
10988
11078
  const state = await gm.current();
10989
11079
  if (!state) {
@@ -11004,8 +11094,8 @@ async function execute4(paths, phase) {
11004
11094
  const implContent = await readTextFile(paths.artifact("03-implementation.md"));
11005
11095
  const destPath = paths.artifact("05-completion.md");
11006
11096
  if (!await fileExists(destPath)) {
11007
- const templateDir = join21(__require("os").homedir(), ".reap", "templates");
11008
- const templatePath = join21(templateDir, "05-completion.md");
11097
+ const templateDir = join22(__require("os").homedir(), ".reap", "templates");
11098
+ const templatePath = join22(templateDir, "05-completion.md");
11009
11099
  if (await fileExists(templatePath)) {
11010
11100
  const { writeTextFile: writeTextFile2 } = await Promise.resolve().then(() => (init_fs(), exports_fs));
11011
11101
  const template = await readTextFile(templatePath);
@@ -11094,9 +11184,9 @@ var init_completion = __esm(() => {
11094
11184
  // src/cli/commands/run/abort.ts
11095
11185
  var exports_abort = {};
11096
11186
  __export(exports_abort, {
11097
- execute: () => execute5
11187
+ execute: () => execute7
11098
11188
  });
11099
- import { join as join22 } from "path";
11189
+ import { join as join23 } from "path";
11100
11190
  import { readdir as readdir17, unlink as unlink6 } from "fs/promises";
11101
11191
  function getFlag3(args, name) {
11102
11192
  const idx = args.indexOf(`--${name}`);
@@ -11105,7 +11195,7 @@ function getFlag3(args, name) {
11105
11195
  function hasFlag(args, name) {
11106
11196
  return args.includes(`--${name}`);
11107
11197
  }
11108
- async function execute5(paths, phase, argv = []) {
11198
+ async function execute7(paths, phase, argv = []) {
11109
11199
  const gm = new GenerationManager(paths);
11110
11200
  const state = await gm.current();
11111
11201
  if (!state || !state.id) {
@@ -11172,7 +11262,7 @@ async function execute5(paths, phase, argv = []) {
11172
11262
  sourceAction === "stash" ? "git stash pop으로 코드 복구" : sourceAction === "hold" ? "코드 변경이 working tree에 유지됨" : sourceAction === "rollback" ? "코드 변경이 revert됨. objective부터 재시작 필요" : "소스 코드 변경 없음"
11173
11263
  ].filter((line) => line !== null).join(`
11174
11264
  `);
11175
- await writeTextFile(join22(paths.backlog, `aborted-${state.id}.md`), backlogContent);
11265
+ await writeTextFile(join23(paths.backlog, `aborted-${state.id}.md`), backlogContent);
11176
11266
  backlogSaved = true;
11177
11267
  }
11178
11268
  await revertBacklogConsumed(paths.backlog, state.id);
@@ -11180,7 +11270,7 @@ async function execute5(paths, phase, argv = []) {
11180
11270
  const lifeEntries = await readdir17(paths.life);
11181
11271
  for (const entry of lifeEntries) {
11182
11272
  if (/^\d{2}-[a-z]+(?:-[a-z]+)*\.md$/.test(entry)) {
11183
- await unlink6(join22(paths.life, entry));
11273
+ await unlink6(join23(paths.life, entry));
11184
11274
  }
11185
11275
  }
11186
11276
  } catch {}
@@ -11209,9 +11299,9 @@ var init_abort = __esm(() => {
11209
11299
  // src/cli/commands/run/push.ts
11210
11300
  var exports_push = {};
11211
11301
  __export(exports_push, {
11212
- execute: () => execute6
11302
+ execute: () => execute8
11213
11303
  });
11214
- async function execute6(paths, phase) {
11304
+ async function execute8(paths, phase) {
11215
11305
  const gm = new GenerationManager(paths);
11216
11306
  const state = await gm.current();
11217
11307
  if (!phase || phase === "check") {
@@ -11237,11 +11327,11 @@ var init_push = __esm(() => {
11237
11327
  // src/cli/commands/run/objective.ts
11238
11328
  var exports_objective = {};
11239
11329
  __export(exports_objective, {
11240
- execute: () => execute7
11330
+ execute: () => execute9
11241
11331
  });
11242
- import { join as join23 } from "path";
11332
+ import { join as join24 } from "path";
11243
11333
  import { readdir as readdir18 } from "fs/promises";
11244
- async function execute7(paths, phase) {
11334
+ async function execute9(paths, phase) {
11245
11335
  const gm = new GenerationManager(paths);
11246
11336
  const state = await gm.current();
11247
11337
  if (!state) {
@@ -11263,9 +11353,9 @@ async function execute7(paths, phase) {
11263
11353
  const genDirs = lineageEntries.filter((e) => e.startsWith("gen-")).sort();
11264
11354
  if (genDirs.length > 0) {
11265
11355
  const lastGen = genDirs[genDirs.length - 1];
11266
- prevCompletion = await readTextFile(join23(paths.lineage, lastGen, "05-completion.md"));
11356
+ prevCompletion = await readTextFile(join24(paths.lineage, lastGen, "05-completion.md"));
11267
11357
  if (!prevCompletion) {
11268
- const compressed = await readTextFile(join23(paths.lineage, `${lastGen}.md`));
11358
+ const compressed = await readTextFile(join24(paths.lineage, `${lastGen}.md`));
11269
11359
  if (compressed)
11270
11360
  prevCompletion = compressed.slice(0, 2000);
11271
11361
  }
@@ -11282,8 +11372,8 @@ async function execute7(paths, phase) {
11282
11372
  lineageCount = entries.filter((e) => e.startsWith("gen-")).length;
11283
11373
  } catch {}
11284
11374
  if (!isReentry) {
11285
- const templateDir = join23(__require("os").homedir(), ".reap", "templates");
11286
- const templatePath = join23(templateDir, "01-objective.md");
11375
+ const templateDir = join24(__require("os").homedir(), ".reap", "templates");
11376
+ const templatePath = join24(templateDir, "01-objective.md");
11287
11377
  if (await fileExists(templatePath)) {
11288
11378
  let template = await readTextFile(templatePath);
11289
11379
  if (template) {
@@ -11397,10 +11487,10 @@ var init_objective = __esm(() => {
11397
11487
  // src/cli/commands/run/planning.ts
11398
11488
  var exports_planning = {};
11399
11489
  __export(exports_planning, {
11400
- execute: () => execute8
11490
+ execute: () => execute10
11401
11491
  });
11402
- import { join as join24 } from "path";
11403
- async function execute8(paths, phase) {
11492
+ import { join as join25 } from "path";
11493
+ async function execute10(paths, phase) {
11404
11494
  const gm = new GenerationManager(paths);
11405
11495
  const state = await gm.current();
11406
11496
  if (!state) {
@@ -11425,8 +11515,8 @@ async function execute8(paths, phase) {
11425
11515
  const principlesContent = await readTextFile(paths.principles);
11426
11516
  const implContent = await readTextFile(paths.artifact("03-implementation.md"));
11427
11517
  if (!isReentry) {
11428
- const templateDir = join24(__require("os").homedir(), ".reap", "templates");
11429
- const templatePath = join24(templateDir, "02-planning.md");
11518
+ const templateDir = join25(__require("os").homedir(), ".reap", "templates");
11519
+ const templatePath = join25(templateDir, "02-planning.md");
11430
11520
  if (await fileExists(templatePath)) {
11431
11521
  const template = await readTextFile(templatePath);
11432
11522
  if (template)
@@ -11532,10 +11622,10 @@ var init_planning = __esm(() => {
11532
11622
  // src/cli/commands/run/implementation.ts
11533
11623
  var exports_implementation = {};
11534
11624
  __export(exports_implementation, {
11535
- execute: () => execute9
11625
+ execute: () => execute11
11536
11626
  });
11537
- import { join as join25 } from "path";
11538
- async function execute9(paths, phase) {
11627
+ import { join as join26 } from "path";
11628
+ async function execute11(paths, phase) {
11539
11629
  const gm = new GenerationManager(paths);
11540
11630
  const state = await gm.current();
11541
11631
  if (!state) {
@@ -11558,8 +11648,8 @@ async function execute9(paths, phase) {
11558
11648
  const conventionsContent = await readTextFile(paths.conventions);
11559
11649
  const constraintsContent = await readTextFile(paths.constraints);
11560
11650
  if (!isReentry) {
11561
- const templateDir = join25(__require("os").homedir(), ".reap", "templates");
11562
- const templatePath = join25(templateDir, "03-implementation.md");
11651
+ const templateDir = join26(__require("os").homedir(), ".reap", "templates");
11652
+ const templatePath = join26(templateDir, "03-implementation.md");
11563
11653
  if (await fileExists(templatePath)) {
11564
11654
  const template = await readTextFile(templatePath);
11565
11655
  if (template)
@@ -11664,10 +11754,10 @@ var init_implementation = __esm(() => {
11664
11754
  // src/cli/commands/run/validation.ts
11665
11755
  var exports_validation = {};
11666
11756
  __export(exports_validation, {
11667
- execute: () => execute10
11757
+ execute: () => execute12
11668
11758
  });
11669
- import { join as join26 } from "path";
11670
- async function execute10(paths, phase) {
11759
+ import { join as join27 } from "path";
11760
+ async function execute12(paths, phase) {
11671
11761
  const gm = new GenerationManager(paths);
11672
11762
  const state = await gm.current();
11673
11763
  if (!state) {
@@ -11691,8 +11781,8 @@ async function execute10(paths, phase) {
11691
11781
  const implContent = await readTextFile(implArtifact);
11692
11782
  const objectiveContent = await readTextFile(paths.artifact("01-objective.md"));
11693
11783
  if (!isReentry) {
11694
- const templateDir = join26(__require("os").homedir(), ".reap", "templates");
11695
- const templatePath = join26(templateDir, "04-validation.md");
11784
+ const templateDir = join27(__require("os").homedir(), ".reap", "templates");
11785
+ const templatePath = join27(templateDir, "04-validation.md");
11696
11786
  if (await fileExists(templatePath)) {
11697
11787
  const template = await readTextFile(templatePath);
11698
11788
  if (template)
@@ -11807,9 +11897,9 @@ var init_validation = __esm(() => {
11807
11897
  // src/cli/commands/run/evolve.ts
11808
11898
  var exports_evolve = {};
11809
11899
  __export(exports_evolve, {
11810
- execute: () => execute11
11900
+ execute: () => execute13
11811
11901
  });
11812
- function buildSubagentPrompt(paths, state, genomeSummaries, backlogSummary) {
11902
+ function buildSubagentPrompt(paths, state, genomeSummaries, backlogSummary, backlogFilenames = []) {
11813
11903
  const lines = [];
11814
11904
  lines.push("# REAP Subagent Instructions");
11815
11905
  lines.push("");
@@ -11847,6 +11937,15 @@ function buildSubagentPrompt(paths, state, genomeSummaries, backlogSummary) {
11847
11937
  lines.push("## Backlog");
11848
11938
  lines.push(backlogSummary || "(empty)");
11849
11939
  lines.push("");
11940
+ if (backlogFilenames.length > 0) {
11941
+ lines.push("## CRITICAL: Read the backlog file");
11942
+ lines.push("BEFORE starting objective, read the backlog file directly:");
11943
+ for (const fn of backlogFilenames) {
11944
+ lines.push(`\`.reap/life/backlog/${fn}\``);
11945
+ }
11946
+ lines.push("This file contains ALL implementation points. Do NOT skip any of them.");
11947
+ lines.push("");
11948
+ }
11850
11949
  lines.push("## Lifecycle Execution");
11851
11950
  lines.push("");
11852
11951
  if (!state || !state.id) {
@@ -11884,6 +11983,11 @@ function buildSubagentPrompt(paths, state, genomeSummaries, backlogSummary) {
11884
11983
  lines.push("- Use conventional commit format: `feat|fix|chore(scope): description`");
11885
11984
  lines.push("- Include the generation ID in the commit message.");
11886
11985
  lines.push("");
11986
+ lines.push("## Backlog Creation Rules");
11987
+ lines.push("- backlog 생성 시 반드시 `reap make backlog --type <type> --title <title> --body <body>` 명령을 사용하라.");
11988
+ lines.push("- Write 도구로 backlog 파일을 직접 생성하지 마라 (frontmatter 형식 오류 방지).");
11989
+ lines.push("- 생성된 backlog 파일에 상세 내용을 추가해야 하면, 생성 후 해당 파일을 편집하라.");
11990
+ lines.push("");
11887
11991
  lines.push("## Submodule Commit Rules");
11888
11992
  lines.push("- 커밋 전 반드시 `git -C tests status -s` 로 tests submodule의 dirty 상태를 확인하라.");
11889
11993
  lines.push("- dirty 파일이 있으면:");
@@ -11919,7 +12023,7 @@ function truncate(text, maxLen) {
11919
12023
  return "(not found)";
11920
12024
  return text.length <= maxLen ? text : text.slice(0, maxLen) + "...";
11921
12025
  }
11922
- async function execute11(paths, phase) {
12026
+ async function execute13(paths, phase) {
11923
12027
  const gm = new GenerationManager(paths);
11924
12028
  const state = await gm.current();
11925
12029
  if (!phase || phase === "start") {
@@ -11943,7 +12047,8 @@ async function execute11(paths, phase) {
11943
12047
  const pendingItems = backlogItems.filter((b) => b.status === "pending");
11944
12048
  const backlogSummary = pendingItems.length > 0 ? pendingItems.map((b) => `- [${b.type}] ${b.title}`).join(`
11945
12049
  `) : "(no pending items)";
11946
- const subagentPrompt = buildSubagentPrompt(paths, state, genomeSummaries, backlogSummary);
12050
+ const backlogFilenames = pendingItems.map((b) => b.filename);
12051
+ const subagentPrompt = buildSubagentPrompt(paths, state, genomeSummaries, backlogSummary, backlogFilenames);
11947
12052
  emitOutput({
11948
12053
  status: "prompt",
11949
12054
  command: "evolve",
@@ -12060,9 +12165,9 @@ var init_evolve = __esm(() => {
12060
12165
  // src/cli/commands/run/sync.ts
12061
12166
  var exports_sync = {};
12062
12167
  __export(exports_sync, {
12063
- execute: () => execute12
12168
+ execute: () => execute14
12064
12169
  });
12065
- async function execute12(paths, phase) {
12170
+ async function execute14(paths, phase) {
12066
12171
  emitOutput({
12067
12172
  status: "prompt",
12068
12173
  command: "sync",
@@ -12087,11 +12192,11 @@ var init_sync = () => {};
12087
12192
  // src/cli/commands/run/sync-genome.ts
12088
12193
  var exports_sync_genome = {};
12089
12194
  __export(exports_sync_genome, {
12090
- execute: () => execute13
12195
+ execute: () => execute15
12091
12196
  });
12092
12197
  import { readdir as readdir19 } from "fs/promises";
12093
- import { join as join27 } from "path";
12094
- async function execute13(paths, phase) {
12198
+ import { join as join28 } from "path";
12199
+ async function execute15(paths, phase) {
12095
12200
  const gm = new GenerationManager(paths);
12096
12201
  const state = await gm.current();
12097
12202
  const hasActiveGen = !!(state && state.id);
@@ -12105,7 +12210,7 @@ async function execute13(paths, phase) {
12105
12210
  const entries = await readdir19(paths.domain);
12106
12211
  for (const entry of entries) {
12107
12212
  if (entry.endsWith(".md")) {
12108
- const content = await readTextFile(join27(paths.domain, entry));
12213
+ const content = await readTextFile(join28(paths.domain, entry));
12109
12214
  if (content)
12110
12215
  domainFiles[entry] = content.slice(0, 1000);
12111
12216
  }
@@ -12190,11 +12295,11 @@ var init_sync_genome = __esm(() => {
12190
12295
  // src/cli/commands/run/sync-environment.ts
12191
12296
  var exports_sync_environment = {};
12192
12297
  __export(exports_sync_environment, {
12193
- execute: () => execute14
12298
+ execute: () => execute16
12194
12299
  });
12195
12300
  import { readdir as readdir20 } from "fs/promises";
12196
- import { join as join28 } from "path";
12197
- async function execute14(paths, phase) {
12301
+ import { join as join29 } from "path";
12302
+ async function execute16(paths, phase) {
12198
12303
  const gm = new GenerationManager(paths);
12199
12304
  const state = await gm.current();
12200
12305
  const hasActiveGen = !!(state && state.id);
@@ -12205,7 +12310,7 @@ async function execute14(paths, phase) {
12205
12310
  const docsEntries = await readdir20(paths.environmentDocs);
12206
12311
  for (const entry of docsEntries) {
12207
12312
  if (entry.endsWith(".md")) {
12208
- const content = await readTextFile(join28(paths.environmentDocs, entry));
12313
+ const content = await readTextFile(join29(paths.environmentDocs, entry));
12209
12314
  if (content)
12210
12315
  envDocs[entry] = content.slice(0, 1000);
12211
12316
  }
@@ -12213,7 +12318,7 @@ async function execute14(paths, phase) {
12213
12318
  } catch {}
12214
12319
  let linksContent = null;
12215
12320
  try {
12216
- linksContent = await readTextFile(join28(paths.environmentResources, "links.md"));
12321
+ linksContent = await readTextFile(join29(paths.environmentResources, "links.md"));
12217
12322
  } catch {}
12218
12323
  emitOutput({
12219
12324
  status: "prompt",
@@ -12283,9 +12388,9 @@ var init_sync_environment = __esm(() => {
12283
12388
  // src/cli/commands/run/help.ts
12284
12389
  var exports_help = {};
12285
12390
  __export(exports_help, {
12286
- execute: () => execute15
12391
+ execute: () => execute17
12287
12392
  });
12288
- import { join as join29 } from "path";
12393
+ import { join as join30 } from "path";
12289
12394
  function detectLanguage(configContent) {
12290
12395
  const raw = configContent?.match(/language:\s*(\S+)/)?.[1] ?? null;
12291
12396
  if (raw && raw in LANGUAGE_ALIASES)
@@ -12316,11 +12421,11 @@ function buildLines(versionDisplay, lang, stateDisplay) {
12316
12421
  CONFIG_LINE[lang]
12317
12422
  ];
12318
12423
  }
12319
- async function execute15(paths) {
12424
+ async function execute17(paths) {
12320
12425
  const gm = new GenerationManager(paths);
12321
12426
  const state = await gm.current();
12322
12427
  const configContent = await readTextFile(paths.config);
12323
- const installedVersion = "0.15.3";
12428
+ const installedVersion = "0.15.5";
12324
12429
  const autoUpdate = configContent?.match(/autoUpdate:\s*(true|false)/)?.[1] === "true";
12325
12430
  const versionDisplay = formatVersionLine(installedVersion, !autoUpdate);
12326
12431
  const rawLang = detectLanguage(configContent);
@@ -12331,7 +12436,7 @@ async function execute15(paths) {
12331
12436
  const stateDisplay = state?.id ? `Active: **${state.id}** — ${state.goal} (Stage: ${state.stage})` : "No active Generation → `/reap.start` or `/reap.evolve`";
12332
12437
  const lines = buildLines(versionDisplay, lang, stateDisplay);
12333
12438
  if (topic) {
12334
- const guidePath = join29(ReapPaths.packageHooksDir, "reap-guide.md");
12439
+ const guidePath = join30(ReapPaths.packageHooksDir, "reap-guide.md");
12335
12440
  const reapGuide = await readTextFile(guidePath) ?? "";
12336
12441
  emitOutput({
12337
12442
  status: "prompt",
@@ -12511,9 +12616,9 @@ var init_help = __esm(() => {
12511
12616
  // src/cli/commands/run/report.ts
12512
12617
  var exports_report = {};
12513
12618
  __export(exports_report, {
12514
- execute: () => execute16
12619
+ execute: () => execute18
12515
12620
  });
12516
- async function execute16(paths, phase) {
12621
+ async function execute18(paths, phase) {
12517
12622
  const gm = new GenerationManager(paths);
12518
12623
  const state = await gm.current();
12519
12624
  if (!phase || phase === "collect") {
@@ -12636,8 +12741,8 @@ var init_merge = __esm(() => {
12636
12741
  });
12637
12742
 
12638
12743
  // src/core/merge-generation.ts
12639
- import { readdir as readdir21, mkdir as mkdir10, unlink as unlink7 } from "fs/promises";
12640
- import { join as join30 } from "path";
12744
+ import { readdir as readdir21, mkdir as mkdir11, unlink as unlink7 } from "fs/promises";
12745
+ import { join as join31 } from "path";
12641
12746
 
12642
12747
  class MergeGenerationManager {
12643
12748
  paths;
@@ -12813,7 +12918,7 @@ class MergeGenerationManager {
12813
12918
  const goalSlug = state.goal.toLowerCase().replace(/[^a-z0-9가-힣]+/g, "-").replace(/^-|-$/g, "").slice(0, 30);
12814
12919
  const genDirName = `${state.id}-${goalSlug}`;
12815
12920
  const genDir = this.paths.generationDir(genDirName);
12816
- await mkdir10(genDir, { recursive: true });
12921
+ await mkdir11(genDir, { recursive: true });
12817
12922
  const meta = {
12818
12923
  id: state.id,
12819
12924
  type: "merge",
@@ -12823,12 +12928,12 @@ class MergeGenerationManager {
12823
12928
  startedAt: state.startedAt,
12824
12929
  completedAt: now
12825
12930
  };
12826
- await writeTextFile(join30(genDir, "meta.yml"), import_yaml10.default.stringify(meta));
12931
+ await writeTextFile(join31(genDir, "meta.yml"), import_yaml10.default.stringify(meta));
12827
12932
  const lifeEntries = await readdir21(this.paths.life);
12828
12933
  for (const entry of lifeEntries) {
12829
12934
  if (/^\d{2}-[a-z]+(?:-[a-z]+)*\.md$/.test(entry)) {
12830
- const srcPath = join30(this.paths.life, entry);
12831
- const destPath = join30(genDir, entry);
12935
+ const srcPath = join31(this.paths.life, entry);
12936
+ const destPath = join31(genDir, entry);
12832
12937
  let content = await readTextFile(srcPath);
12833
12938
  if (content && content.startsWith("# REAP MANAGED")) {
12834
12939
  content = content.replace(/^# REAP MANAGED[^\n]*\n/, "");
@@ -12837,18 +12942,18 @@ class MergeGenerationManager {
12837
12942
  await unlink7(srcPath);
12838
12943
  }
12839
12944
  }
12840
- const backlogDir = join30(genDir, "backlog");
12841
- await mkdir10(backlogDir, { recursive: true });
12945
+ const backlogDir = join31(genDir, "backlog");
12946
+ await mkdir11(backlogDir, { recursive: true });
12842
12947
  try {
12843
12948
  const backlogEntries = await readdir21(this.paths.backlog);
12844
12949
  for (const entry of backlogEntries) {
12845
- const content = await readTextFile(join30(this.paths.backlog, entry));
12950
+ const content = await readTextFile(join31(this.paths.backlog, entry));
12846
12951
  if (!content)
12847
12952
  continue;
12848
12953
  const isConsumed = /status:\s*consumed/i.test(content) || /consumed:\s*true/i.test(content);
12849
- await writeTextFile(join30(backlogDir, entry), content);
12954
+ await writeTextFile(join31(backlogDir, entry), content);
12850
12955
  if (isConsumed) {
12851
- await unlink7(join30(this.paths.backlog, entry));
12956
+ await unlink7(join31(this.paths.backlog, entry));
12852
12957
  }
12853
12958
  }
12854
12959
  } catch {}
@@ -12935,9 +13040,9 @@ var init_merge_generation = __esm(() => {
12935
13040
  // src/cli/commands/run/merge-start.ts
12936
13041
  var exports_merge_start = {};
12937
13042
  __export(exports_merge_start, {
12938
- execute: () => execute17
13043
+ execute: () => execute19
12939
13044
  });
12940
- async function execute17(paths, phase, argv = []) {
13045
+ async function execute19(paths, phase, argv = []) {
12941
13046
  const positionals = argv.filter((a) => !a.startsWith("--"));
12942
13047
  const targetBranchArg = positionals[0];
12943
13048
  const gm = new GenerationManager(paths);
@@ -13026,9 +13131,9 @@ var init_merge_start = __esm(() => {
13026
13131
  // src/cli/commands/run/merge-detect.ts
13027
13132
  var exports_merge_detect = {};
13028
13133
  __export(exports_merge_detect, {
13029
- execute: () => execute18
13134
+ execute: () => execute20
13030
13135
  });
13031
- async function execute18(paths, phase) {
13136
+ async function execute20(paths, phase) {
13032
13137
  const mgm = new MergeGenerationManager(paths);
13033
13138
  const state = await mgm.current();
13034
13139
  if (!state) {
@@ -13109,9 +13214,9 @@ var init_merge_detect = __esm(() => {
13109
13214
  // src/cli/commands/run/merge-mate.ts
13110
13215
  var exports_merge_mate = {};
13111
13216
  __export(exports_merge_mate, {
13112
- execute: () => execute19
13217
+ execute: () => execute21
13113
13218
  });
13114
- async function execute19(paths, phase) {
13219
+ async function execute21(paths, phase) {
13115
13220
  const mgm = new MergeGenerationManager(paths);
13116
13221
  const state = await mgm.current();
13117
13222
  if (!state) {
@@ -13209,9 +13314,9 @@ var init_merge_mate = __esm(() => {
13209
13314
  // src/cli/commands/run/merge-merge.ts
13210
13315
  var exports_merge_merge = {};
13211
13316
  __export(exports_merge_merge, {
13212
- execute: () => execute20
13317
+ execute: () => execute22
13213
13318
  });
13214
- async function execute20(paths, phase) {
13319
+ async function execute22(paths, phase) {
13215
13320
  const mgm = new MergeGenerationManager(paths);
13216
13321
  const state = await mgm.current();
13217
13322
  if (!state) {
@@ -13306,9 +13411,9 @@ var init_merge_merge = __esm(() => {
13306
13411
  // src/cli/commands/run/merge-sync.ts
13307
13412
  var exports_merge_sync = {};
13308
13413
  __export(exports_merge_sync, {
13309
- execute: () => execute21
13414
+ execute: () => execute23
13310
13415
  });
13311
- async function execute21(paths, phase) {
13416
+ async function execute23(paths, phase) {
13312
13417
  const mgm = new MergeGenerationManager(paths);
13313
13418
  const state = await mgm.current();
13314
13419
  if (!state) {
@@ -13414,9 +13519,9 @@ var init_merge_sync = __esm(() => {
13414
13519
  // src/cli/commands/run/merge-validation.ts
13415
13520
  var exports_merge_validation = {};
13416
13521
  __export(exports_merge_validation, {
13417
- execute: () => execute22
13522
+ execute: () => execute24
13418
13523
  });
13419
- async function execute22(paths, phase) {
13524
+ async function execute24(paths, phase) {
13420
13525
  const mgm = new MergeGenerationManager(paths);
13421
13526
  const state = await mgm.current();
13422
13527
  if (!state) {
@@ -13511,9 +13616,9 @@ var init_merge_validation = __esm(() => {
13511
13616
  // src/cli/commands/run/merge-completion.ts
13512
13617
  var exports_merge_completion = {};
13513
13618
  __export(exports_merge_completion, {
13514
- execute: () => execute23
13619
+ execute: () => execute25
13515
13620
  });
13516
- async function execute23(paths, phase) {
13621
+ async function execute25(paths, phase) {
13517
13622
  const mgm = new MergeGenerationManager(paths);
13518
13623
  const state = await mgm.current();
13519
13624
  if (!state) {
@@ -13602,9 +13707,9 @@ var init_merge_completion = __esm(() => {
13602
13707
  // src/cli/commands/run/merge-evolve.ts
13603
13708
  var exports_merge_evolve = {};
13604
13709
  __export(exports_merge_evolve, {
13605
- execute: () => execute24
13710
+ execute: () => execute26
13606
13711
  });
13607
- async function execute24(paths, phase) {
13712
+ async function execute26(paths, phase) {
13608
13713
  const mgm = new MergeGenerationManager(paths);
13609
13714
  const state = await mgm.current();
13610
13715
  if (!state) {
@@ -13688,9 +13793,9 @@ var init_merge_evolve = __esm(() => {
13688
13793
  // src/cli/commands/run/merge.ts
13689
13794
  var exports_merge = {};
13690
13795
  __export(exports_merge, {
13691
- execute: () => execute25
13796
+ execute: () => execute27
13692
13797
  });
13693
- async function execute25(paths, phase, argv = []) {
13798
+ async function execute27(paths, phase, argv = []) {
13694
13799
  const positionals = argv.filter((a) => !a.startsWith("--"));
13695
13800
  const targetBranchArg = positionals[0];
13696
13801
  const gm = new GenerationManager(paths);
@@ -13777,9 +13882,9 @@ var init_merge2 = __esm(() => {
13777
13882
  // src/cli/commands/run/evolve-recovery.ts
13778
13883
  var exports_evolve_recovery = {};
13779
13884
  __export(exports_evolve_recovery, {
13780
- execute: () => execute26
13885
+ execute: () => execute28
13781
13886
  });
13782
- import { join as join31 } from "path";
13887
+ import { join as join32 } from "path";
13783
13888
  import { readdir as readdir22 } from "fs/promises";
13784
13889
  function getFlag4(args, name) {
13785
13890
  const idx = args.indexOf(`--${name}`);
@@ -13802,12 +13907,12 @@ async function loadLineageArtifacts(paths, genId) {
13802
13907
  const completed = await listCompleted(paths);
13803
13908
  const genDir = completed.find((d) => d.startsWith(genId));
13804
13909
  if (genDir) {
13805
- const dirPath = join31(paths.lineage, genDir);
13910
+ const dirPath = join32(paths.lineage, genDir);
13806
13911
  const [objective, planning, implementation, completion] = await Promise.all([
13807
- readTextFile(join31(dirPath, "01-objective.md")),
13808
- readTextFile(join31(dirPath, "02-planning.md")),
13809
- readTextFile(join31(dirPath, "03-implementation.md")),
13810
- readTextFile(join31(dirPath, "05-completion.md"))
13912
+ readTextFile(join32(dirPath, "01-objective.md")),
13913
+ readTextFile(join32(dirPath, "02-planning.md")),
13914
+ readTextFile(join32(dirPath, "03-implementation.md")),
13915
+ readTextFile(join32(dirPath, "05-completion.md"))
13811
13916
  ]);
13812
13917
  return {
13813
13918
  objective: objective ?? "(not found)",
@@ -13820,7 +13925,7 @@ async function loadLineageArtifacts(paths, genId) {
13820
13925
  const entries = await readdir22(paths.lineage);
13821
13926
  const compressedFile = entries.find((e) => e.startsWith(genId) && e.endsWith(".md"));
13822
13927
  if (compressedFile) {
13823
- const content = await readTextFile(join31(paths.lineage, compressedFile));
13928
+ const content = await readTextFile(join32(paths.lineage, compressedFile));
13824
13929
  if (content) {
13825
13930
  return {
13826
13931
  objective: content,
@@ -13833,7 +13938,7 @@ async function loadLineageArtifacts(paths, genId) {
13833
13938
  } catch {}
13834
13939
  return null;
13835
13940
  }
13836
- async function execute26(paths, phase, argv = []) {
13941
+ async function execute28(paths, phase, argv = []) {
13837
13942
  const positionals = getPositionals3(argv, ["reason"]);
13838
13943
  const targetGenIds = positionals;
13839
13944
  const reason = getFlag4(argv, "reason");
@@ -13939,9 +14044,9 @@ var init_evolve_recovery = __esm(() => {
13939
14044
  // src/cli/commands/run/pull.ts
13940
14045
  var exports_pull = {};
13941
14046
  __export(exports_pull, {
13942
- execute: () => execute27
14047
+ execute: () => execute29
13943
14048
  });
13944
- async function execute27(paths, phase, argv = []) {
14049
+ async function execute29(paths, phase, argv = []) {
13945
14050
  const positionals = argv.filter((a) => !a.startsWith("--"));
13946
14051
  const targetBranchArg = positionals[0];
13947
14052
  const gm = new GenerationManager(paths);
@@ -14062,9 +14167,9 @@ var init_pull = __esm(() => {
14062
14167
  // src/cli/commands/run/config.ts
14063
14168
  var exports_config = {};
14064
14169
  __export(exports_config, {
14065
- execute: () => execute28
14170
+ execute: () => execute30
14066
14171
  });
14067
- async function execute28(paths) {
14172
+ async function execute30(paths) {
14068
14173
  const config = await ConfigManager.read(paths);
14069
14174
  const lines = [
14070
14175
  `REAP Configuration (${paths.config})`,
@@ -14096,9 +14201,9 @@ var init_config2 = __esm(() => {
14096
14201
  // src/cli/commands/run/update-genome.ts
14097
14202
  var exports_update_genome = {};
14098
14203
  __export(exports_update_genome, {
14099
- execute: () => execute29
14204
+ execute: () => execute31
14100
14205
  });
14101
- async function execute29(paths, phase) {
14206
+ async function execute31(paths, phase) {
14102
14207
  const gm = new GenerationManager(paths);
14103
14208
  const current = await gm.current();
14104
14209
  if (current !== null) {
@@ -14190,22 +14295,22 @@ var init_update_genome = __esm(() => {
14190
14295
  // src/cli/commands/run/refresh-knowledge.ts
14191
14296
  var exports_refresh_knowledge = {};
14192
14297
  __export(exports_refresh_knowledge, {
14193
- execute: () => execute30
14298
+ execute: () => execute32
14194
14299
  });
14195
- import { join as join32 } from "path";
14300
+ import { join as join33 } from "path";
14196
14301
  import { readdir as readdir23 } from "fs/promises";
14197
14302
  async function loadGenome(genomeDir) {
14198
14303
  let content = "";
14199
14304
  let l1Lines = 0;
14200
14305
  let smLimit = null;
14201
- const smContent = await readTextFile(join32(genomeDir, "source-map.md"));
14306
+ const smContent = await readTextFile(join33(genomeDir, "source-map.md"));
14202
14307
  if (smContent) {
14203
14308
  const limitMatch = smContent.match(/줄 수 한도:\s*~?(\d+)줄/);
14204
14309
  if (limitMatch)
14205
14310
  smLimit = parseInt(limitMatch[1], 10);
14206
14311
  }
14207
14312
  for (const file of L1_FILES) {
14208
- const fileContent = await readTextFile(join32(genomeDir, file));
14313
+ const fileContent = await readTextFile(join33(genomeDir, file));
14209
14314
  if (!fileContent)
14210
14315
  continue;
14211
14316
  const lines = fileContent.split(`
@@ -14227,14 +14332,14 @@ ${fileContent.split(`
14227
14332
  `;
14228
14333
  }
14229
14334
  }
14230
- const domainDir = join32(genomeDir, "domain");
14335
+ const domainDir = join33(genomeDir, "domain");
14231
14336
  if (await fileExists(domainDir)) {
14232
14337
  let l2Lines = 0;
14233
14338
  let l2Overflow = false;
14234
14339
  try {
14235
14340
  const domainFiles = (await readdir23(domainDir)).filter((f) => f.endsWith(".md")).sort();
14236
14341
  for (const file of domainFiles) {
14237
- const fileContent = await readTextFile(join32(domainDir, file));
14342
+ const fileContent = await readTextFile(join33(domainDir, file));
14238
14343
  if (!fileContent)
14239
14344
  continue;
14240
14345
  const lines = fileContent.split(`
@@ -14284,8 +14389,8 @@ function buildStrictSection(strict, genStage) {
14284
14389
  }
14285
14390
  return sections;
14286
14391
  }
14287
- async function execute30(paths) {
14288
- const guidePath = join32(ReapPaths.packageHooksDir, "reap-guide.md");
14392
+ async function execute32(paths) {
14393
+ const guidePath = join33(ReapPaths.packageHooksDir, "reap-guide.md");
14289
14394
  const reapGuide = await readTextFile(guidePath) || "";
14290
14395
  const { content: genomeContent } = await loadGenome(paths.genome);
14291
14396
  const envSummary = await readTextFile(paths.environmentSummary) || "";
@@ -14375,7 +14480,7 @@ async function runCommand(command, phase, argv = []) {
14375
14480
  try {
14376
14481
  const config = await ConfigManager.read(paths);
14377
14482
  if (config.autoIssueReport) {
14378
- const version = "0.15.3";
14483
+ const version = "0.15.5";
14379
14484
  const errMsg = err instanceof Error ? err.message : String(err);
14380
14485
  const title = `[auto] reap run ${command}: ${errMsg.slice(0, 80)}`;
14381
14486
  const body = [
@@ -14772,7 +14877,7 @@ class CodexAdapter {
14772
14877
  return join3(homedir3(), ".codex");
14773
14878
  }
14774
14879
  get commandsDir() {
14775
- return join3(this.userDir, "commands");
14880
+ return join3(this.userDir, "prompts");
14776
14881
  }
14777
14882
  get hooksJsonPath() {
14778
14883
  return join3(this.userDir, "hooks.json");
@@ -15257,7 +15362,7 @@ async function initProject(projectRoot, projectName, entryMode, preset, onProgre
15257
15362
  }
15258
15363
  const detectedLanguage = await AgentRegistry.readLanguage();
15259
15364
  const config = {
15260
- version: "0.15.3",
15365
+ version: "0.15.5",
15261
15366
  project: projectName,
15262
15367
  entryMode,
15263
15368
  strict: false,
@@ -15385,7 +15490,7 @@ init_config();
15385
15490
  init_fs();
15386
15491
  init_generation();
15387
15492
  var import_yaml5 = __toESM(require_dist(), 1);
15388
- import { readdir as readdir10, rename as rename2 } from "fs/promises";
15493
+ import { readdir as readdir10, rename } from "fs/promises";
15389
15494
  import { join as join11 } from "path";
15390
15495
  import { execSync as execSync2 } from "child_process";
15391
15496
  function estimateGenDates(lineagePath, dirName, fallbackDate) {
@@ -15474,7 +15579,7 @@ async function migrateLineage(paths) {
15474
15579
  const oldSlug = entry.dirName.replace(/^gen-\d{3}/, "");
15475
15580
  const newDirName = `${newId}${oldSlug}`;
15476
15581
  if (newDirName !== entry.dirName) {
15477
- await rename2(join11(paths.lineage, entry.dirName), join11(paths.lineage, newDirName));
15582
+ await rename(join11(paths.lineage, entry.dirName), join11(paths.lineage, newDirName));
15478
15583
  }
15479
15584
  prevId = newId;
15480
15585
  result.migrated.push(`${entry.dirName} → ${newDirName}`);
@@ -15866,7 +15971,7 @@ async function checkGenome(paths, errors, warnings) {
15866
15971
  continue;
15867
15972
  const lines = content.split(`
15868
15973
  `).length;
15869
- if (lines > GENOME_LINE_WARNING_THRESHOLD) {
15974
+ if (gf.name !== "source-map.md" && lines > GENOME_LINE_WARNING_THRESHOLD) {
15870
15975
  warnings.push(`genome/${gf.name}: ${lines} lines (exceeds ~${GENOME_LINE_WARNING_THRESHOLD} line guideline)`);
15871
15976
  }
15872
15977
  const stripped = content.split(`
@@ -16208,7 +16313,7 @@ async function updateProject(projectRoot, dryRun = false) {
16208
16313
  }
16209
16314
  } catch {}
16210
16315
  await migrateLegacyFiles(paths, dryRun, result);
16211
- const currentVersion = "0.15.3";
16316
+ const currentVersion = "0.15.5";
16212
16317
  const migrationResult = await MigrationRunner.run(paths, currentVersion, dryRun);
16213
16318
  for (const m of migrationResult.migrated) {
16214
16319
  result.updated.push(`[migration] ${m}`);
@@ -16293,6 +16398,72 @@ async function removeDirIfExists(dirPath, label, dryRun, result) {
16293
16398
  } catch {}
16294
16399
  }
16295
16400
 
16401
+ // src/core/notice.ts
16402
+ import { readFileSync } from "fs";
16403
+ import { join as join14 } from "path";
16404
+ var __dirname = "/home/runner/work/reap/reap/src/core";
16405
+ function extractLanguageSection(body, language) {
16406
+ const lang = language.toLowerCase();
16407
+ const pattern = new RegExp(`^## ${lang}\\s*$`, "im");
16408
+ const match = pattern.exec(body);
16409
+ if (!match)
16410
+ return null;
16411
+ const start = match.index + match[0].length;
16412
+ const rest = body.slice(start);
16413
+ const nextHeader = rest.search(/^## /m);
16414
+ const section = nextHeader === -1 ? rest : rest.slice(0, nextHeader);
16415
+ return section.trim() || null;
16416
+ }
16417
+ function findNoticeUrl(version) {
16418
+ try {
16419
+ const noticePath = join14(__dirname, "../../UPDATE_NOTICE.md");
16420
+ const content = readFileSync(noticePath, "utf-8");
16421
+ const versionTag = version.startsWith("v") ? version : `v${version}`;
16422
+ const pattern = new RegExp(`^- ${versionTag.replace(/\./g, "\\.")}:\\s*(.+)$`, "m");
16423
+ const match = pattern.exec(content);
16424
+ return match?.[1]?.trim() ?? null;
16425
+ } catch {
16426
+ return null;
16427
+ }
16428
+ }
16429
+ async function fetchDiscussionBody(url) {
16430
+ try {
16431
+ const match = url.match(/discussions\/(\d+)/);
16432
+ if (!match)
16433
+ return null;
16434
+ const res = await fetch(`https://api.github.com/repos/c-d-cc/reap/discussions/${match[1]}`, {
16435
+ headers: { Accept: "application/vnd.github+json" },
16436
+ signal: AbortSignal.timeout(5000)
16437
+ });
16438
+ if (!res.ok)
16439
+ return null;
16440
+ const data = await res.json();
16441
+ return data.body?.trim() ?? null;
16442
+ } catch {
16443
+ return null;
16444
+ }
16445
+ }
16446
+ async function fetchReleaseNotice(version, language) {
16447
+ const url = findNoticeUrl(version);
16448
+ if (!url)
16449
+ return null;
16450
+ const body = await fetchDiscussionBody(url);
16451
+ if (!body)
16452
+ return null;
16453
+ const versionTag = version.startsWith("v") ? version : `v${version}`;
16454
+ const section = extractLanguageSection(body, language);
16455
+ const content = section ?? body;
16456
+ if (!content)
16457
+ return null;
16458
+ return `
16459
+ --- Release Notes (${versionTag}) ---
16460
+ ${content}
16461
+ `;
16462
+ }
16463
+
16464
+ // src/cli/index.ts
16465
+ init_version();
16466
+
16296
16467
  // src/cli/commands/status.ts
16297
16468
  init_paths();
16298
16469
  init_generation();
@@ -16330,7 +16501,7 @@ init_lifecycle();
16330
16501
  init_fs();
16331
16502
  var import_yaml7 = __toESM(require_dist(), 1);
16332
16503
  import { mkdir as mkdir8, stat as stat4, copyFile } from "fs/promises";
16333
- import { join as join14 } from "path";
16504
+ import { join as join15 } from "path";
16334
16505
  async function checkProject(projectRoot) {
16335
16506
  const paths = new ReapPaths(projectRoot);
16336
16507
  const [structureResult, userLevelResult] = await Promise.all([
@@ -16376,7 +16547,7 @@ async function fixProject(projectRoot) {
16376
16547
  ];
16377
16548
  for (const gf of genomeFiles) {
16378
16549
  if (!await fileExists(gf.path)) {
16379
- const templateSrc = join14(ReapPaths.packageGenomeDir, gf.name);
16550
+ const templateSrc = join15(ReapPaths.packageGenomeDir, gf.name);
16380
16551
  if (await fileExists(templateSrc)) {
16381
16552
  await copyFile(templateSrc, gf.path);
16382
16553
  fixed.push(`Restored missing genome/${gf.name} from template`);
@@ -16418,7 +16589,7 @@ init_fs();
16418
16589
  init_paths();
16419
16590
  init_config();
16420
16591
  import { rm as rm4 } from "fs/promises";
16421
- import { join as join15 } from "path";
16592
+ import { join as join16 } from "path";
16422
16593
  async function getProjectName(projectRoot) {
16423
16594
  try {
16424
16595
  const paths = new ReapPaths(projectRoot);
@@ -16431,7 +16602,7 @@ async function getProjectName(projectRoot) {
16431
16602
  async function destroyProject(projectRoot) {
16432
16603
  const removed = [];
16433
16604
  const skipped = [];
16434
- const reapDir = join15(projectRoot, ".reap");
16605
+ const reapDir = join16(projectRoot, ".reap");
16435
16606
  if (await fileExists(reapDir)) {
16436
16607
  await rm4(reapDir, { recursive: true, force: true });
16437
16608
  removed.push(".reap/");
@@ -16450,7 +16621,7 @@ async function destroyProject(projectRoot) {
16450
16621
  return { removed, skipped };
16451
16622
  }
16452
16623
  async function cleanGitignore(projectRoot, removed, skipped) {
16453
- const gitignorePath = join15(projectRoot, ".gitignore");
16624
+ const gitignorePath = join16(projectRoot, ".gitignore");
16454
16625
  const content = await readTextFile(gitignorePath);
16455
16626
  if (content === null) {
16456
16627
  skipped.push(".gitignore (not found)");
@@ -16487,7 +16658,7 @@ init_paths();
16487
16658
  init_fs();
16488
16659
  init_generation();
16489
16660
  import { rm as rm5, readdir as readdir13, mkdir as mkdir9 } from "fs/promises";
16490
- import { join as join16 } from "path";
16661
+ import { join as join17 } from "path";
16491
16662
  async function hasActiveGeneration(projectRoot) {
16492
16663
  const paths = new ReapPaths(projectRoot);
16493
16664
  try {
@@ -16573,9 +16744,9 @@ async function compressLineage(paths, actions) {
16573
16744
  ].join(`
16574
16745
  `);
16575
16746
  for (const dir of genDirs) {
16576
- await rm5(join16(lineageDir, dir), { recursive: true, force: true });
16747
+ await rm5(join17(lineageDir, dir), { recursive: true, force: true });
16577
16748
  }
16578
- await writeTextFile(join16(lineageDir, `${epochId}.md`), summary);
16749
+ await writeTextFile(join17(lineageDir, `${epochId}.md`), summary);
16579
16750
  actions.push(`Lineage: ${genDirs.length}개 세대를 ${epochId}로 압축`);
16580
16751
  }
16581
16752
  async function cleanLife(paths, actions) {
@@ -16595,7 +16766,7 @@ async function cleanLife(paths, actions) {
16595
16766
  for (const entry of entries) {
16596
16767
  if (entry === "backlog")
16597
16768
  continue;
16598
- const entryPath = join16(lifeDir, entry);
16769
+ const entryPath = join17(lifeDir, entry);
16599
16770
  await rm5(entryPath, { recursive: true, force: true });
16600
16771
  removedCount++;
16601
16772
  }
@@ -16604,14 +16775,14 @@ async function cleanLife(paths, actions) {
16604
16775
  async function resetGenomeToTemplate(paths, actions) {
16605
16776
  const genomeFiles = ["principles.md", "conventions.md", "constraints.md", "source-map.md"];
16606
16777
  for (const file of genomeFiles) {
16607
- const templatePath = join16(ReapPaths.packageGenomeDir, file);
16608
- const destPath = join16(paths.genome, file);
16778
+ const templatePath = join17(ReapPaths.packageGenomeDir, file);
16779
+ const destPath = join17(paths.genome, file);
16609
16780
  try {
16610
16781
  const templateContent = await readTextFileOrThrow(templatePath);
16611
16782
  await writeTextFile(destPath, templateContent);
16612
16783
  } catch {}
16613
16784
  }
16614
- const envSummaryTemplate = join16(ReapPaths.packageTemplatesDir, "environment", "summary.md");
16785
+ const envSummaryTemplate = join17(ReapPaths.packageTemplatesDir, "environment", "summary.md");
16615
16786
  if (await fileExists(envSummaryTemplate)) {
16616
16787
  try {
16617
16788
  const content = await readTextFileOrThrow(envSummaryTemplate);
@@ -16627,8 +16798,8 @@ init_paths();
16627
16798
  init_fs();
16628
16799
  init_version();
16629
16800
  init_config();
16630
- import { join as join33 } from "path";
16631
- program.name("reap").description("REAP — Recursive Evolutionary Autonomous Pipeline").version("0.15.3");
16801
+ import { join as join34 } from "path";
16802
+ program.name("reap").description("REAP — Recursive Evolutionary Autonomous Pipeline").version("0.15.5");
16632
16803
  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) => {
16633
16804
  try {
16634
16805
  const cwd = process.cwd();
@@ -16685,7 +16856,7 @@ program.command("status").description("Show current project and Generation statu
16685
16856
  const paths = new ReapPaths(cwd);
16686
16857
  const config = await ConfigManager.read(paths);
16687
16858
  const skipCheck = config.autoUpdate === false;
16688
- const installedVersion = "0.15.3";
16859
+ const installedVersion = "0.15.5";
16689
16860
  const versionLine = formatVersionLine(installedVersion, skipCheck);
16690
16861
  console.log(`${versionLine} | Project: ${status.project} (${status.entryMode})`);
16691
16862
  console.log(`Completed Generations: ${status.totalGenerations}`);
@@ -16797,6 +16968,13 @@ Integrity: ${parts.join(", ")} (run 'reap fix --check' for details)`);
16797
16968
  Integrity: ✓ OK`);
16798
16969
  }
16799
16970
  } catch {}
16971
+ try {
16972
+ const version = getCurrentVersion();
16973
+ const lang = await AgentRegistry.readLanguage() ?? "en";
16974
+ const notice = await fetchReleaseNotice(version, lang);
16975
+ if (notice)
16976
+ console.log(notice);
16977
+ } catch {}
16800
16978
  } catch (e) {
16801
16979
  console.error(`Error: ${e.message}`);
16802
16980
  process.exit(1);
@@ -16810,10 +16988,10 @@ program.command("help").description("Show REAP commands, slash commands, and wor
16810
16988
  if (l === "korean" || l === "ko")
16811
16989
  lang = "ko";
16812
16990
  }
16813
- const helpDir = join33(ReapPaths.packageTemplatesDir, "help");
16814
- let helpText = await readTextFile(join33(helpDir, `${lang}.txt`));
16991
+ const helpDir = join34(ReapPaths.packageTemplatesDir, "help");
16992
+ let helpText = await readTextFile(join34(helpDir, `${lang}.txt`));
16815
16993
  if (!helpText)
16816
- helpText = await readTextFile(join33(helpDir, "en.txt"));
16994
+ helpText = await readTextFile(join34(helpDir, "en.txt"));
16817
16995
  if (!helpText) {
16818
16996
  console.log("Help file not found. Run 'reap update' to install templates.");
16819
16997
  return;
@@ -16917,6 +17095,22 @@ Clean complete. Run /reap.start to begin a new generation.`);
16917
17095
  process.exit(1);
16918
17096
  }
16919
17097
  });
17098
+ program.command("make <target>").description("Create REAP resources (e.g., backlog items)").allowUnknownOption().action(async (target, _options, cmd) => {
17099
+ try {
17100
+ const cwd = process.cwd();
17101
+ const paths = new ReapPaths(cwd);
17102
+ if (!await paths.isReapProject()) {
17103
+ console.error("Error: Not a REAP project. Run 'reap init' first.");
17104
+ process.exit(1);
17105
+ }
17106
+ const passArgs = [target, ...cmd.args.slice(1)];
17107
+ const { execute: execute33 } = await Promise.resolve().then(() => (init_make(), exports_make));
17108
+ await execute33(paths, undefined, passArgs);
17109
+ } catch (e) {
17110
+ console.error(`Error: ${e.message}`);
17111
+ process.exit(1);
17112
+ }
17113
+ });
16920
17114
  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) => {
16921
17115
  const rawArgs = cmd.args.slice(1);
16922
17116
  const passArgs = [];