@c-d-cc/reap 0.11.0 → 0.12.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/README.ja.md CHANGED
@@ -218,8 +218,8 @@ Machine A:
218
218
  | コマンド | 説明 |
219
219
  |----------|------|
220
220
  | `reap init <name>` | プロジェクト初期化。`.reap/`構造を作成 |
221
- | `reap status` | 現在のGeneration状態を確認(バージョン + 最新状況表示) |
222
- | `reap update` | コマンド/テンプレート/hookを最新バージョンに同期。`~/.claude/commands/`のレガシーを自動クリーンアップ |
221
+ | `reap status` | 現在のGeneration状態を確認 |
222
+ | `reap update` | コマンド/テンプレート/hookを最新バージョンに同期 |
223
223
  | `reap fix` | `.reap/`構造の診断と修復 |
224
224
  | `reap help` | CLIコマンド + スラッシュコマンド + ワークフロー概要を出力(バージョン + 最新状況表示) |
225
225
  | `reap run <cmd>` | スラッシュコマンドのスクリプトを直接実行(1行`.md`ラッパーが内部的に使用) |
@@ -251,6 +251,25 @@ autoSubagent: true # デフォルト: true
251
251
 
252
252
  Subagentは完全なコンテキストを受け取り、すべてのステージを自律的に実行します。本当にブロックされた場合のみユーザーに確認を求めます。
253
253
 
254
+ ### エラー時の自動Issue報告
255
+
256
+ `reap run`の実行中に予期しないエラーが発生した場合、`gh issue create`を通じてGitHub Issueを自動作成できます:
257
+
258
+ ```yaml
259
+ # .reap/config.yml
260
+ autoIssueReport: true # デフォルト: true(gh CLIがある場合)
261
+ ```
262
+
263
+ ### AI Migration Agent
264
+
265
+ `reap update`の実行時にプロジェクトと最新REAPバージョン間の構造的な差分(不足しているconfigフィールド、古いテンプレートなど)が検出されると、AI支援のマイグレーションプロンプトが表示されます。エージェントが差分を分析し、対話的に変更を適用するため、手動マイグレーションは不要です。
266
+
267
+ `reap init`ではすべてのconfigフィールドを明示的に宣言し、`reap update`時に不足しているフィールドは自動的に補完されます。
268
+
269
+ ### CLAUDE.md連携
270
+
271
+ `reap init`と`reap update`の実行時に、`.claude/CLAUDE.md`にREAP管理セクションを追加し、Claude Codeセッションに必要なプロジェクトコンテキストを提供します。
272
+
254
273
  ### スラッシュコマンド [↗](https://reap.cc/docs/command-reference)
255
274
 
256
275
  スラッシュコマンドが`.claude/commands/`にインストールされ、ワークフロー全体を駆動します:
@@ -270,6 +289,7 @@ Subagentは完全なコンテキストを受け取り、すべてのステージ
270
289
  | `/reap.sync` | GenomeとEnvironmentを同時に同期 |
271
290
  | `/reap.sync.genome` | ソースコードベースでGenomeを最新化 |
272
291
  | `/reap.sync.environment` | 外部環境依存関係の発見と文書化 |
292
+ | `/reap.config` | 現在のプロジェクト設定を表示 |
273
293
  | `/reap.report` | REAPプロジェクトにバグ/フィードバックを報告(プライバシー保護) |
274
294
  | `/reap.help` | 24+トピックのcontextual AIヘルプ |
275
295
  | `/reap.update` | REAPパッケージのアップグレード + コマンド/テンプレート/hook同期 |
@@ -403,7 +423,7 @@ my-project/
403
423
  ~/.claude/
404
424
  └── settings.json # SessionStart hookの登録
405
425
 
406
- .claude/commands/ # プロジェクトレベル(セッション開始時にsymlink)
426
+ .claude/commands/ # プロジェクトレベルのスラッシュコマンド
407
427
  └── reap.*.md # アクティブなスラッシュコマンド(`reap run <cmd>`を呼び出し)
408
428
  ```
409
429
 
package/README.ko.md CHANGED
@@ -218,8 +218,8 @@ Machine A:
218
218
  | 명령어 | 설명 |
219
219
  |--------|------|
220
220
  | `reap init <name>` | 프로젝트 초기화. `.reap/` 구조 생성 |
221
- | `reap status` | 현재 Generation 상태 확인 (버전 + 최신 여부 표시) |
222
- | `reap update` | 커맨드/템플릿/훅을 최신 버전으로 동기화. `~/.claude/commands/` 레거시 자동 정리 |
221
+ | `reap status` | 현재 Generation 상태 확인 |
222
+ | `reap update` | 커맨드/템플릿/훅을 최신 버전으로 동기화 |
223
223
  | `reap fix` | `.reap/` 구조 진단 및 복구 |
224
224
  | `reap help` | CLI 명령어 + 슬래시 커맨드 + 워크플로우 요약 출력 (버전 + 최신 여부 표시) |
225
225
  | `reap run <cmd>` | 슬래시 커맨드의 스크립트를 직접 실행 (1줄 `.md` wrapper가 내부적으로 사용) |
@@ -251,6 +251,25 @@ autoSubagent: true # 기본값: true
251
251
 
252
252
  Subagent는 전체 컨텍스트를 받아 모든 stage를 자율적으로 실행하며, 정말로 막혔을 때만 사용자에게 확인을 요청합니다.
253
253
 
254
+ ### 에러 시 자동 이슈 리포트
255
+
256
+ `reap run` 실행 중 예상치 못한 에러가 발생하면, `gh issue create`를 통해 GitHub Issue를 자동으로 생성할 수 있습니다:
257
+
258
+ ```yaml
259
+ # .reap/config.yml
260
+ autoIssueReport: true # 기본값: true (gh CLI가 있을 때)
261
+ ```
262
+
263
+ ### AI Migration Agent
264
+
265
+ `reap update` 실행 시 프로젝트와 최신 REAP 버전 사이의 구조적 차이(누락된 config 필드, 오래된 템플릿 등)가 감지되면, AI 기반 마이그레이션 프롬프트를 제공합니다. 에이전트가 차이를 분석하고 대화형으로 변경을 적용하므로 수동 마이그레이션이 필요 없습니다.
266
+
267
+ `reap init`도 모든 config 필드를 명시적으로 선언하며, `reap update` 시 누락된 필드는 자동으로 채워집니다.
268
+
269
+ ### CLAUDE.md 연동
270
+
271
+ `reap init`과 `reap update` 시 `.claude/CLAUDE.md`에 REAP 관리 섹션을 추가하여 Claude Code 세션에 필요한 프로젝트 컨텍스트를 제공합니다.
272
+
254
273
  ### Slash Commands
255
274
 
256
275
  Slash command가 `.claude/commands/`에 설치되어 전체 워크플로우를 구동합니다:
@@ -270,6 +289,7 @@ Slash command가 `.claude/commands/`에 설치되어 전체 워크플로우를
270
289
  | `/reap.sync` | Genome + Environment 동시 동기화 |
271
290
  | `/reap.sync.genome` | 소스 코드 기반 Genome 최신화 |
272
291
  | `/reap.sync.environment` | 외부 환경 의존성 탐색 및 문서화 |
292
+ | `/reap.config` | 현재 프로젝트 설정 표시 |
273
293
  | `/reap.report` | REAP 프로젝트에 버그/피드백 보고 (개인정보 보호) |
274
294
  | `/reap.help` | 24+ 주제의 contextual AI 도움말 |
275
295
  | `/reap.update` | REAP 패키지 업그레이드 + 커맨드/템플릿/훅 동기화 |
@@ -403,7 +423,7 @@ my-project/
403
423
  ~/.claude/
404
424
  └── settings.json # SessionStart hook 등록
405
425
 
406
- .claude/commands/ # 프로젝트 레벨 (세션 시작 시 symlink)
426
+ .claude/commands/ # 프로젝트 레벨 슬래시 커맨드
407
427
  └── reap.*.md # 활성 슬래시 커맨드 (`reap run <cmd>` 호출)
408
428
  ```
409
429
 
package/README.md CHANGED
@@ -250,6 +250,25 @@ autoSubagent: true # default: true
250
250
 
251
251
  The subagent receives the full context and runs autonomously through all stages, only surfacing when genuinely blocked.
252
252
 
253
+ ### Auto Issue Report
254
+
255
+ When an unexpected error occurs during `reap run`, REAP can automatically create a GitHub Issue via `gh issue create`. This is controlled by:
256
+
257
+ ```yaml
258
+ # .reap/config.yml
259
+ autoIssueReport: true # default: true (when gh CLI is available)
260
+ ```
261
+
262
+ ### AI Migration Agent
263
+
264
+ When `reap update` detects structural gaps between your project and the latest REAP version (e.g., missing config fields, outdated templates), it offers an AI-assisted migration prompt. The agent analyzes the differences and applies changes interactively — no manual migration needed.
265
+
266
+ `reap init` also ensures all config fields are explicitly declared, and `reap update` backfills any missing fields automatically.
267
+
268
+ ### CLAUDE.md Integration
269
+
270
+ During `reap init` and `reap update`, REAP adds a managed section to `.claude/CLAUDE.md` containing essential project context for Claude Code sessions.
271
+
253
272
  ### Slash Commands [↗](https://reap.cc/docs/command-reference)
254
273
 
255
274
  Slash commands are installed in `.claude/commands/` and drive the entire workflow:
@@ -269,6 +288,7 @@ Slash commands are installed in `.claude/commands/` and drive the entire workflo
269
288
  | `/reap.sync` | Synchronize both Genome and Environment |
270
289
  | `/reap.sync.genome` | Synchronize Genome with current source code |
271
290
  | `/reap.sync.environment` | Discover and document external environment dependencies |
291
+ | `/reap.config` | Display current project configuration |
272
292
  | `/reap.report` | Report a bug or feedback to the REAP project (privacy-safe) |
273
293
  | `/reap.help` | Contextual AI help with 24+ topics |
274
294
  | `/reap.update` | Upgrade REAP package + sync commands/templates/hooks |
package/README.zh-CN.md CHANGED
@@ -218,8 +218,8 @@ Machine A:
218
218
  | 命令 | 说明 |
219
219
  |------|------|
220
220
  | `reap init <name>` | 初始化项目。创建`.reap/`结构 |
221
- | `reap status` | 查看当前Generation状态(显示版本 + 最新状态) |
222
- | `reap update` | 将命令/模板/hook同步到最新版本。自动清理`~/.claude/commands/`旧版文件 |
221
+ | `reap status` | 查看当前Generation状态 |
222
+ | `reap update` | 将命令/模板/hook同步到最新版本 |
223
223
  | `reap fix` | 诊断和修复`.reap/`结构 |
224
224
  | `reap help` | 输出CLI命令 + 斜杠命令 + 工作流摘要(显示版本 + 最新状态) |
225
225
  | `reap run <cmd>` | 直接执行斜杠命令的脚本(由1行`.md` wrapper内部调用) |
@@ -251,6 +251,25 @@ autoSubagent: true # 默认值: true
251
251
 
252
252
  Subagent接收完整上下文后自主执行所有阶段,仅在确实遇到阻碍时才向用户确认。
253
253
 
254
+ ### 错误时自动Issue报告
255
+
256
+ 当`reap run`执行中发生意外错误时,可通过`gh issue create`自动创建GitHub Issue:
257
+
258
+ ```yaml
259
+ # .reap/config.yml
260
+ autoIssueReport: true # 默认值: true(检测到gh CLI时)
261
+ ```
262
+
263
+ ### AI Migration Agent
264
+
265
+ `reap update`执行时,如果检测到项目与最新REAP版本之间的结构性差异(缺失的config字段、过时的模板等),会提供AI辅助的迁移提示。代理分析差异并交互式地应用变更,无需手动迁移。
266
+
267
+ `reap init`会明确声明所有config字段,`reap update`时自动补全缺失字段。
268
+
269
+ ### CLAUDE.md集成
270
+
271
+ `reap init`和`reap update`执行时,会在`.claude/CLAUDE.md`中添加REAP管理段落,为Claude Code会话提供必要的项目上下文。
272
+
254
273
  ### 斜杠命令 [↗](https://reap.cc/docs/command-reference)
255
274
 
256
275
  斜杠命令安装在`.claude/commands/`中,驱动整个工作流:
@@ -270,6 +289,7 @@ Subagent接收完整上下文后自主执行所有阶段,仅在确实遇到阻
270
289
  | `/reap.sync` | 同时同步Genome和Environment |
271
290
  | `/reap.sync.genome` | 基于源代码同步Genome |
272
291
  | `/reap.sync.environment` | 发现和记录外部环境依赖 |
292
+ | `/reap.config` | 显示当前项目配置 |
273
293
  | `/reap.report` | 向REAP项目报告bug/反馈(隐私保护) |
274
294
  | `/reap.help` | 24+主题的上下文AI帮助 |
275
295
  | `/reap.update` | 升级REAP包 + 同步命令/模板/hook |
@@ -403,7 +423,7 @@ my-project/
403
423
  ~/.claude/
404
424
  └── settings.json # SessionStart hook注册
405
425
 
406
- .claude/commands/ # 项目级别(会话启动时symlink)
426
+ .claude/commands/ # 项目级斜杠命令
407
427
  └── reap.*.md # 活跃斜杠命令(调用`reap run <cmd>`)
408
428
  ```
409
429
 
package/dist/cli.js CHANGED
@@ -9020,6 +9020,26 @@ class ConfigManager {
9020
9020
  static resolveAutoSubagent(value) {
9021
9021
  return value !== false;
9022
9022
  }
9023
+ static async backfill(paths) {
9024
+ const config = await ConfigManager.read(paths);
9025
+ const added = [];
9026
+ const defaults = {
9027
+ strict: false,
9028
+ autoUpdate: true,
9029
+ autoSubagent: true,
9030
+ autoIssueReport: false
9031
+ };
9032
+ for (const [key, defaultValue] of Object.entries(defaults)) {
9033
+ if (config[key] === undefined) {
9034
+ config[key] = defaultValue;
9035
+ added.push(key);
9036
+ }
9037
+ }
9038
+ if (added.length > 0) {
9039
+ await ConfigManager.write(paths, config);
9040
+ }
9041
+ return { added };
9042
+ }
9023
9043
  static resolveStrict(strict) {
9024
9044
  if (strict === undefined || strict === false) {
9025
9045
  return { edit: false, merge: false };
@@ -10048,7 +10068,14 @@ class GenerationManager {
10048
10068
  const lifeEntries = await readdir7(this.paths.life);
10049
10069
  for (const entry of lifeEntries) {
10050
10070
  if (/^\d{2}-[a-z]+(?:-[a-z]+)*\.md$/.test(entry)) {
10051
- await rename(join8(this.paths.life, entry), join8(genDir, entry));
10071
+ const srcPath = join8(this.paths.life, entry);
10072
+ const destPath = join8(genDir, entry);
10073
+ let content = await readTextFile(srcPath);
10074
+ if (content && content.startsWith("# REAP MANAGED")) {
10075
+ content = content.replace(/^# REAP MANAGED[^\n]*\n/, "");
10076
+ }
10077
+ await writeTextFile(destPath, content ?? "");
10078
+ await unlink3(srcPath);
10052
10079
  }
10053
10080
  }
10054
10081
  const backlogDir = join8(genDir, "backlog");
@@ -10271,7 +10298,7 @@ async function parseHookMeta(filePath, ext) {
10271
10298
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
10272
10299
  if (fmMatch) {
10273
10300
  try {
10274
- const fm = import_yaml7.default.parse(fmMatch[1]) ?? {};
10301
+ const fm = import_yaml8.default.parse(fmMatch[1]) ?? {};
10275
10302
  return {
10276
10303
  condition: String(fm.condition ?? "always"),
10277
10304
  order: Number(fm.order ?? 50)
@@ -10346,10 +10373,10 @@ async function executeMdHook(hook, event, hooksDir) {
10346
10373
  content: body
10347
10374
  };
10348
10375
  }
10349
- var import_yaml7;
10376
+ var import_yaml8;
10350
10377
  var init_hook_engine = __esm(() => {
10351
10378
  init_fs();
10352
- import_yaml7 = __toESM(require_dist(), 1);
10379
+ import_yaml8 = __toESM(require_dist(), 1);
10353
10380
  });
10354
10381
 
10355
10382
  // src/cli/commands/run/next.ts
@@ -10571,7 +10598,7 @@ async function markBacklogConsumed(backlogDir, filename, genId) {
10571
10598
  frontmatter.consumedBy = genId;
10572
10599
  delete frontmatter.consumed;
10573
10600
  const newContent = `---
10574
- ${import_yaml8.default.stringify(frontmatter).trim()}
10601
+ ${import_yaml9.default.stringify(frontmatter).trim()}
10575
10602
  ---
10576
10603
  ${body}`;
10577
10604
  await writeTextFile(filePath, newContent);
@@ -10595,7 +10622,7 @@ async function revertBacklogConsumed(backlogDir, genId) {
10595
10622
  frontmatter.status = "pending";
10596
10623
  delete frontmatter.consumedBy;
10597
10624
  const newContent = `---
10598
- ${import_yaml8.default.stringify(frontmatter).trim()}
10625
+ ${import_yaml9.default.stringify(frontmatter).trim()}
10599
10626
  ---
10600
10627
  ${body}`;
10601
10628
  await writeTextFile(filePath, newContent);
@@ -10607,15 +10634,15 @@ function parseFrontmatter2(content) {
10607
10634
  if (!match)
10608
10635
  return { frontmatter: {}, body: content };
10609
10636
  try {
10610
- return { frontmatter: import_yaml8.default.parse(match[1]) ?? {}, body: match[2] };
10637
+ return { frontmatter: import_yaml9.default.parse(match[1]) ?? {}, body: match[2] };
10611
10638
  } catch {
10612
10639
  return { frontmatter: {}, body: content };
10613
10640
  }
10614
10641
  }
10615
- var import_yaml8;
10642
+ var import_yaml9;
10616
10643
  var init_backlog = __esm(() => {
10617
10644
  init_fs();
10618
- import_yaml8 = __toESM(require_dist(), 1);
10645
+ import_yaml9 = __toESM(require_dist(), 1);
10619
10646
  });
10620
10647
 
10621
10648
  // src/cli/commands/run/start.ts
@@ -11571,11 +11598,10 @@ function buildSubagentPrompt(paths, state, genomeSummaries, backlogSummary) {
11571
11598
  lines.push(" - `completion` -> `/reap.completion`");
11572
11599
  lines.push("3. Write the required artifact BEFORE completing the stage.");
11573
11600
  lines.push("4. Run the stage complete phase if applicable (e.g., `reap run <stage> --phase complete`).");
11574
- lines.push("5. Run `/reap.next` to advance to the next stage.");
11575
- lines.push("6. Repeat until `completion` stage is done.");
11601
+ lines.push("5. If current stage is NOT `completion`: run `/reap.next` to advance, then go to step 1.");
11602
+ lines.push("6. If current stage IS `completion`: `/reap.completion` auto-archives after genome phase. Done.");
11576
11603
  lines.push("");
11577
- lines.push("### Completion");
11578
- lines.push("- Run `/reap.completion` which handles: retrospective, genome updates, backlog consume, and archive.");
11604
+ lines.push("Note: `/reap.next` is a transition command, NOT a lifecycle stage.");
11579
11605
  lines.push("");
11580
11606
  lines.push("## Project");
11581
11607
  lines.push(`- Path: ${paths.projectRoot}`);
@@ -11950,77 +11976,226 @@ var exports_help = {};
11950
11976
  __export(exports_help, {
11951
11977
  execute: () => execute15
11952
11978
  });
11953
- async function execute15(paths, phase) {
11979
+ import { join as join24 } from "path";
11980
+ function detectLanguage(configContent) {
11981
+ const raw = configContent?.match(/language:\s*(\S+)/)?.[1] ?? null;
11982
+ if (raw && raw in LANGUAGE_ALIASES)
11983
+ return LANGUAGE_ALIASES[raw];
11984
+ return raw;
11985
+ }
11986
+ function isSupportedLanguage(lang) {
11987
+ return lang !== null && SUPPORTED_LANGUAGES.includes(lang);
11988
+ }
11989
+ function buildCommandTable(lang) {
11990
+ return [
11991
+ "| Command | Description |",
11992
+ "|---------|-------------|",
11993
+ ...Object.entries(COMMAND_DESCRIPTIONS).map(([cmd, descs]) => `| \`${cmd}\` | ${descs[lang]} |`)
11994
+ ];
11995
+ }
11996
+ function buildLines(versionDisplay, lang, stateDisplay) {
11997
+ return [
11998
+ versionDisplay,
11999
+ REAP_INTRO[lang],
12000
+ "",
12001
+ stateDisplay,
12002
+ "",
12003
+ ...buildCommandTable(lang),
12004
+ "",
12005
+ TOPICS_LINE[lang],
12006
+ "Usage: REAP_HELP_TOPIC=<topic> reap run help",
12007
+ CONFIG_LINE[lang]
12008
+ ];
12009
+ }
12010
+ async function execute15(paths) {
11954
12011
  const gm = new GenerationManager(paths);
11955
12012
  const state = await gm.current();
11956
12013
  const configContent = await readTextFile(paths.config);
11957
- const strict = configContent?.match(/strict:\s*(true|false)/)?.[1] === "true" ? "on" : "off";
11958
- const autoUpdate = configContent?.match(/autoUpdate:\s*(true|false)/)?.[1] === "true" ? "on" : "off";
11959
- const language = configContent?.match(/language:\s*(\w+)/)?.[1] ?? "ko";
11960
12014
  const configVersion = configContent?.match(/version:\s*([\d.]+)/)?.[1] ?? "0.0.0";
11961
- const skipCheck = autoUpdate !== "on";
11962
- const versionDisplay = formatVersionLine(configVersion, skipCheck);
12015
+ const autoUpdate = configContent?.match(/autoUpdate:\s*(true|false)/)?.[1] === "true";
12016
+ const versionDisplay = formatVersionLine(configVersion, !autoUpdate);
12017
+ const rawLang = detectLanguage(configContent);
12018
+ const supported = isSupportedLanguage(rawLang);
12019
+ const lang = supported ? rawLang : "en";
11963
12020
  const topic = process.env.REAP_HELP_TOPIC;
11964
- emitOutput({
11965
- status: "prompt",
11966
- command: "help",
11967
- phase: "respond",
11968
- completed: ["gate", "context-collect"],
11969
- context: {
11970
- hasActiveGeneration: !!(state && state.id),
11971
- generationId: state?.id,
11972
- goal: state?.goal,
11973
- stage: state?.stage,
11974
- version: configVersion,
11975
- versionDisplay,
11976
- config: { strict, autoUpdate, language },
11977
- topic: topic || null
11978
- },
11979
- prompt: [
11980
- "## Help Contextual Help",
11981
- "",
11982
- topic ? `Topic requested: "${topic}". Look up the topic from the known topics list below.` : "No specific topic. Show the basic help overview.",
11983
- "",
11984
- "### Basic Help (no topic)",
11985
- "Show REAP overview, current state, and command table.",
11986
- state?.id ? `> Current: **${state.id}** — ${state.goal} (Stage: ${state.stage})` : "> No active Generation -> `/reap.start` or `/reap.evolve`",
11987
- "",
11988
- "### Command Table",
11989
- "| Command | Description |",
11990
- "|---------|-------------|",
11991
- "| `/reap.start` | 새 Generation을 시작하고 goal을 설정 |",
11992
- "| `/reap.evolve` | 전체 lifecycle을 자율적으로 실행 |",
11993
- "| `/reap.objective` | 목표, 요구사항, 완료 기준을 정의 |",
11994
- "| `/reap.planning` | 태스크를 분해하고 구현 계획을 수립 |",
11995
- "| `/reap.implementation` | 계획에 따라 코드를 구현 |",
11996
- "| `/reap.validation` | 테스트 실행, 완료 기준 충족 여부를 검증 |",
11997
- "| `/reap.completion` | 회고, Genome 변경 반영, Generation 마무리 |",
11998
- "| `/reap.next` | 다음 stage로 전진 |",
11999
- "| `/reap.back` | 이전 stage로 회귀 |",
12000
- "| `/reap.status` | 프로젝트 상태 표시 |",
12001
- "| `/reap.sync` | Genome/Environment 동기화 |",
12002
- "| `/reap.update` | REAP 최신 버전 확인 및 업그레이드 |",
12003
- "| `/reap.help` | 도움말 |",
12004
- "| `/reap.push` | REAP 상태 검증 + git push |",
12005
- "| `/reap.report` | 버그/이슈 리포트 |",
12006
- "",
12007
- `${versionDisplay} | Strict: ${strict} | Auto-Update: ${autoUpdate} | Language: ${language}`,
12008
- "",
12009
- "### Topic Help",
12010
- "If a topic is provided, look up from these known topics:",
12011
- "- workflow/lifecycle, genome, backlog, strict, agents, hooks, config, evolve, regression, minor-fix, compression, merge/collaboration, author",
12012
- "- Command topics: start, objective, planning, implementation, validation, completion, next, back, sync, status, update, help, pull, push, merge.*",
12013
- "",
12014
- "For command-name topics: read `reap.{name}.md` from `~/.reap/commands/` or the template commands directory, then explain.",
12015
- "If the topic is NOT in the list: respond 'Unknown topic'."
12016
- ].join(`
12021
+ const stateDisplay = state?.id ? `Active: **${state.id}** — ${state.goal} (Stage: ${state.stage})` : "No active Generation → `/reap.start` or `/reap.evolve`";
12022
+ const lines = buildLines(versionDisplay, lang, stateDisplay);
12023
+ if (topic) {
12024
+ const guidePath = join24(ReapPaths.packageHooksDir, "reap-guide.md");
12025
+ const reapGuide = await readTextFile(guidePath) ?? "";
12026
+ emitOutput({
12027
+ status: "prompt",
12028
+ command: "help",
12029
+ phase: "respond",
12030
+ completed: ["gate", "context-collect"],
12031
+ context: { topic, reapGuide },
12032
+ message: lines.join(`
12033
+ `),
12034
+ prompt: [
12035
+ `Topic requested: "${topic}".`,
12036
+ "Look up from known topics: workflow/lifecycle, genome, backlog, strict, agents, hooks, config, evolve, regression, minor-fix, compression, merge/collaboration.",
12037
+ "Command topics: read `reap.{name}.md` from `~/.reap/commands/` or template commands directory, then explain.",
12038
+ "If the topic is NOT known: respond 'Unknown topic'.",
12039
+ "Use the reapGuide content in context as the primary knowledge source for explaining REAP topics."
12040
+ ].join(`
12017
12041
  `)
12018
- });
12042
+ });
12043
+ } else if (!supported && rawLang !== null) {
12044
+ emitOutput({
12045
+ status: "prompt",
12046
+ command: "help",
12047
+ phase: "respond",
12048
+ completed: ["gate", "context-collect"],
12049
+ message: lines.join(`
12050
+ `),
12051
+ prompt: [
12052
+ `The user's configured language is "${rawLang}", which is not natively supported.`,
12053
+ "Below is the help message in English. Translate the descriptions and intro text to the target language.",
12054
+ "Keep command names (e.g. /reap.start) and topic names in English.",
12055
+ `Target language: ${rawLang}`
12056
+ ].join(`
12057
+ `)
12058
+ });
12059
+ } else {
12060
+ emitOutput({
12061
+ status: "ok",
12062
+ command: "help",
12063
+ phase: "respond",
12064
+ completed: ["gate", "context-collect"],
12065
+ message: lines.join(`
12066
+ `)
12067
+ });
12068
+ }
12019
12069
  }
12070
+ var SUPPORTED_LANGUAGES, REAP_INTRO, COMMAND_DESCRIPTIONS, TOPICS_LINE, CONFIG_LINE, LANGUAGE_ALIASES;
12020
12071
  var init_help = __esm(() => {
12072
+ init_paths();
12021
12073
  init_generation();
12022
12074
  init_fs();
12023
12075
  init_version();
12076
+ SUPPORTED_LANGUAGES = ["en", "ko", "ja", "zh-CN"];
12077
+ REAP_INTRO = {
12078
+ en: "REAP (Recursive Evolutionary Autonomous Pipeline) — A development pipeline that evolves software generation by generation through AI+Human collaboration.",
12079
+ ko: "REAP (Recursive Evolutionary Autonomous Pipeline) — AI+Human 협업으로 소프트웨어를 세대 단위로 진화시키는 개발 파이프라인.",
12080
+ ja: "REAP (Recursive Evolutionary Autonomous Pipeline) — AI+Humanの協業でソフトウェアを世代単位で進化させる開発パイプライン。",
12081
+ "zh-CN": "REAP (Recursive Evolutionary Autonomous Pipeline) — 通过AI+Human协作,以世代为单位进化软件的开发管道。"
12082
+ };
12083
+ COMMAND_DESCRIPTIONS = {
12084
+ "/reap.start": {
12085
+ en: "Start a new Generation and set the goal",
12086
+ ko: "새 Generation을 시작하고 goal을 설정",
12087
+ ja: "新しいGenerationを開始し、ゴールを設定",
12088
+ "zh-CN": "开始新的Generation并设定目标"
12089
+ },
12090
+ "/reap.evolve": {
12091
+ en: "Run the entire lifecycle autonomously",
12092
+ ko: "전체 lifecycle을 자율적으로 실행",
12093
+ ja: "ライフサイクル全体を自律的に実行",
12094
+ "zh-CN": "自主运行整个生命周期"
12095
+ },
12096
+ "/reap.objective": {
12097
+ en: "Define goals, requirements, and completion criteria",
12098
+ ko: "목표, 요구사항, 완료 기준을 정의",
12099
+ ja: "目標、要件、完了基準を定義",
12100
+ "zh-CN": "定义目标、需求和完成标准"
12101
+ },
12102
+ "/reap.planning": {
12103
+ en: "Decompose tasks and create an implementation plan",
12104
+ ko: "태스크를 분해하고 구현 계획을 수립",
12105
+ ja: "タスクを分解し、実装計画を策定",
12106
+ "zh-CN": "分解任务并制定实施计划"
12107
+ },
12108
+ "/reap.implementation": {
12109
+ en: "Implement code according to the plan",
12110
+ ko: "계획에 따라 코드를 구현",
12111
+ ja: "計画に従ってコードを実装",
12112
+ "zh-CN": "按照计划实现代码"
12113
+ },
12114
+ "/reap.validation": {
12115
+ en: "Run tests and verify completion criteria are met",
12116
+ ko: "테스트 실행, 완료 기준 충족 여부를 검증",
12117
+ ja: "テストを実行し、完了基準の充足を検証",
12118
+ "zh-CN": "运行测试,验证是否满足完成标准"
12119
+ },
12120
+ "/reap.completion": {
12121
+ en: "Retrospective, apply Genome changes, finalize Generation",
12122
+ ko: "회고, Genome 변경 반영, Generation 마무리",
12123
+ ja: "振り返り、Genome変更を反映、Generationを完了",
12124
+ "zh-CN": "回顾,应用Genome变更,完成Generation"
12125
+ },
12126
+ "/reap.next": {
12127
+ en: "Advance to the next stage",
12128
+ ko: "다음 stage로 전진",
12129
+ ja: "次のステージへ進む",
12130
+ "zh-CN": "进入下一阶段"
12131
+ },
12132
+ "/reap.back": {
12133
+ en: "Return to the previous stage",
12134
+ ko: "이전 stage로 회귀",
12135
+ ja: "前のステージへ戻る",
12136
+ "zh-CN": "返回上一阶段"
12137
+ },
12138
+ "/reap.status": {
12139
+ en: "Show project status",
12140
+ ko: "프로젝트 상태 표시",
12141
+ ja: "プロジェクトの状態を表示",
12142
+ "zh-CN": "显示项目状态"
12143
+ },
12144
+ "/reap.config": {
12145
+ en: "Show current project settings",
12146
+ ko: "현재 프로젝트 설정 표시",
12147
+ ja: "現在のプロジェクト設定を表示",
12148
+ "zh-CN": "显示当前项目设置"
12149
+ },
12150
+ "/reap.sync": {
12151
+ en: "Synchronize Genome/Environment",
12152
+ ko: "Genome/Environment 동기화",
12153
+ ja: "Genome/Environmentを同期",
12154
+ "zh-CN": "同步Genome/Environment"
12155
+ },
12156
+ "/reap.update": {
12157
+ en: "Check for latest REAP version and upgrade",
12158
+ ko: "REAP 최신 버전 확인 및 업그레이드",
12159
+ ja: "REAP最新バージョンの確認とアップグレード",
12160
+ "zh-CN": "检查REAP最新版本并升级"
12161
+ },
12162
+ "/reap.help": {
12163
+ en: "Help",
12164
+ ko: "도움말",
12165
+ ja: "ヘルプ",
12166
+ "zh-CN": "帮助"
12167
+ },
12168
+ "/reap.push": {
12169
+ en: "Validate REAP state + git push",
12170
+ ko: "REAP 상태 검증 + git push",
12171
+ ja: "REAP状態検証 + git push",
12172
+ "zh-CN": "验证REAP状态 + git push"
12173
+ },
12174
+ "/reap.report": {
12175
+ en: "Bug/issue report",
12176
+ ko: "버그/이슈 리포트",
12177
+ ja: "バグ/イシューレポート",
12178
+ "zh-CN": "Bug/问题报告"
12179
+ }
12180
+ };
12181
+ TOPICS_LINE = {
12182
+ en: "Topics: workflow, lifecycle, genome, backlog, strict, agents, hooks, config, evolve, regression, minor-fix, compression, merge, collaboration, start, objective, planning, implementation, validation, completion, next, back, sync, status, update, help, pull, push, abort, report",
12183
+ ko: "Topics: workflow, lifecycle, genome, backlog, strict, agents, hooks, config, evolve, regression, minor-fix, compression, merge, collaboration, start, objective, planning, implementation, validation, completion, next, back, sync, status, update, help, pull, push, abort, report",
12184
+ ja: "Topics: workflow, lifecycle, genome, backlog, strict, agents, hooks, config, evolve, regression, minor-fix, compression, merge, collaboration, start, objective, planning, implementation, validation, completion, next, back, sync, status, update, help, pull, push, abort, report",
12185
+ "zh-CN": "Topics: workflow, lifecycle, genome, backlog, strict, agents, hooks, config, evolve, regression, minor-fix, compression, merge, collaboration, start, objective, planning, implementation, validation, completion, next, back, sync, status, update, help, pull, push, abort, report"
12186
+ };
12187
+ CONFIG_LINE = {
12188
+ en: "Settings: /reap.config",
12189
+ ko: "설정 확인: /reap.config",
12190
+ ja: "設定確認: /reap.config",
12191
+ "zh-CN": "查看设置: /reap.config"
12192
+ };
12193
+ LANGUAGE_ALIASES = {
12194
+ korean: "ko",
12195
+ english: "en",
12196
+ japanese: "ja",
12197
+ chinese: "zh-CN"
12198
+ };
12024
12199
  });
12025
12200
 
12026
12201
  // src/cli/commands/run/report.ts
@@ -12031,12 +12206,7 @@ __export(exports_report, {
12031
12206
  async function execute16(paths, phase) {
12032
12207
  const gm = new GenerationManager(paths);
12033
12208
  const state = await gm.current();
12034
- const configContent = await readTextFile(paths.config);
12035
12209
  if (!phase || phase === "collect") {
12036
- const autoIssueReport = configContent?.match(/autoIssueReport:\s*false/);
12037
- if (autoIssueReport) {
12038
- emitError("report", "Issue reporting is disabled. Set `autoIssueReport: true` in .reap/config.yml to enable.");
12039
- }
12040
12210
  emitOutput({
12041
12211
  status: "prompt",
12042
12212
  command: "report",
@@ -12088,7 +12258,6 @@ async function execute16(paths, phase) {
12088
12258
  }
12089
12259
  var init_report = __esm(() => {
12090
12260
  init_generation();
12091
- init_fs();
12092
12261
  });
12093
12262
 
12094
12263
  // src/core/merge.ts
@@ -12158,7 +12327,7 @@ var init_merge = __esm(() => {
12158
12327
 
12159
12328
  // src/core/merge-generation.ts
12160
12329
  import { readdir as readdir17, mkdir as mkdir8, rename as rename3 } from "fs/promises";
12161
- import { join as join24 } from "path";
12330
+ import { join as join25 } from "path";
12162
12331
 
12163
12332
  class MergeGenerationManager {
12164
12333
  paths;
@@ -12169,7 +12338,7 @@ class MergeGenerationManager {
12169
12338
  const content = await readTextFile(this.paths.currentYml);
12170
12339
  if (content === null || !content.trim())
12171
12340
  return null;
12172
- const state = import_yaml9.default.parse(content);
12341
+ const state = import_yaml10.default.parse(content);
12173
12342
  if (!state.type)
12174
12343
  state.type = "normal";
12175
12344
  if (!state.parents)
@@ -12202,7 +12371,7 @@ class MergeGenerationManager {
12202
12371
  genomeHash,
12203
12372
  commonAncestor: commonAncestor ?? undefined
12204
12373
  };
12205
- await writeTextFile(this.paths.currentYml, import_yaml9.default.stringify(state));
12374
+ await writeTextFile(this.paths.currentYml, import_yaml10.default.stringify(state));
12206
12375
  return state;
12207
12376
  }
12208
12377
  async createFromBranch(targetBranch, projectRoot) {
@@ -12246,7 +12415,7 @@ class MergeGenerationManager {
12246
12415
  genomeHash,
12247
12416
  commonAncestor: commonAncestor ?? undefined
12248
12417
  };
12249
- await writeTextFile(this.paths.currentYml, import_yaml9.default.stringify(state));
12418
+ await writeTextFile(this.paths.currentYml, import_yaml10.default.stringify(state));
12250
12419
  return { state, report };
12251
12420
  }
12252
12421
  async resolveLatestGenId(branch, cwd) {
@@ -12271,7 +12440,7 @@ class MergeGenerationManager {
12271
12440
  const content = gitShow(ref, metaFile, cwd);
12272
12441
  if (content) {
12273
12442
  try {
12274
- const meta = import_yaml9.default.parse(content);
12443
+ const meta = import_yaml10.default.parse(content);
12275
12444
  if (meta?.id)
12276
12445
  metas.push(meta);
12277
12446
  } catch {}
@@ -12318,7 +12487,7 @@ class MergeGenerationManager {
12318
12487
  if (!state.timeline)
12319
12488
  state.timeline = [];
12320
12489
  state.timeline.push({ stage: next, at: new Date().toISOString() });
12321
- await writeTextFile(this.paths.currentYml, import_yaml9.default.stringify(state));
12490
+ await writeTextFile(this.paths.currentYml, import_yaml10.default.stringify(state));
12322
12491
  return state;
12323
12492
  }
12324
12493
  async complete() {
@@ -12344,19 +12513,19 @@ class MergeGenerationManager {
12344
12513
  startedAt: state.startedAt,
12345
12514
  completedAt: now
12346
12515
  };
12347
- await writeTextFile(join24(genDir, "meta.yml"), import_yaml9.default.stringify(meta));
12516
+ await writeTextFile(join25(genDir, "meta.yml"), import_yaml10.default.stringify(meta));
12348
12517
  const lifeEntries = await readdir17(this.paths.life);
12349
12518
  for (const entry of lifeEntries) {
12350
12519
  if (/^\d{2}-[a-z]+(?:-[a-z]+)*\.md$/.test(entry)) {
12351
- await rename3(join24(this.paths.life, entry), join24(genDir, entry));
12520
+ await rename3(join25(this.paths.life, entry), join25(genDir, entry));
12352
12521
  }
12353
12522
  }
12354
- const backlogDir = join24(genDir, "backlog");
12523
+ const backlogDir = join25(genDir, "backlog");
12355
12524
  await mkdir8(backlogDir, { recursive: true });
12356
12525
  try {
12357
12526
  const backlogEntries = await readdir17(this.paths.backlog);
12358
12527
  for (const entry of backlogEntries) {
12359
- await rename3(join24(this.paths.backlog, entry), join24(backlogDir, entry));
12528
+ await rename3(join25(this.paths.backlog, entry), join25(backlogDir, entry));
12360
12529
  }
12361
12530
  } catch {}
12362
12531
  await writeTextFile(this.paths.currentYml, "");
@@ -12364,7 +12533,7 @@ class MergeGenerationManager {
12364
12533
  return compression;
12365
12534
  }
12366
12535
  async save(state) {
12367
- await writeTextFile(this.paths.currentYml, import_yaml9.default.stringify(state));
12536
+ await writeTextFile(this.paths.currentYml, import_yaml10.default.stringify(state));
12368
12537
  }
12369
12538
  }
12370
12539
  function canFastForward(localLatestId, remoteLatestId, allMetas) {
@@ -12426,7 +12595,7 @@ function findCommonAncestor(idA, idB, metas) {
12426
12595
  }
12427
12596
  return null;
12428
12597
  }
12429
- var import_yaml9;
12598
+ var import_yaml10;
12430
12599
  var init_merge_generation = __esm(() => {
12431
12600
  init_merge_lifecycle();
12432
12601
  init_compression();
@@ -12436,7 +12605,7 @@ var init_merge_generation = __esm(() => {
12436
12605
  init_merge();
12437
12606
  init_lineage();
12438
12607
  init_compression();
12439
- import_yaml9 = __toESM(require_dist(), 1);
12608
+ import_yaml10 = __toESM(require_dist(), 1);
12440
12609
  });
12441
12610
 
12442
12611
  // src/cli/commands/run/merge-start.ts
@@ -13307,11 +13476,46 @@ var init_pull = __esm(() => {
13307
13476
  init_merge_generation();
13308
13477
  });
13309
13478
 
13479
+ // src/cli/commands/run/config.ts
13480
+ var exports_config = {};
13481
+ __export(exports_config, {
13482
+ execute: () => execute27
13483
+ });
13484
+ async function execute27(paths) {
13485
+ const config = await ConfigManager.read(paths);
13486
+ const lines = [
13487
+ `REAP Configuration (${paths.config})`,
13488
+ "",
13489
+ ` version: ${config.version}`,
13490
+ ` project: ${config.project}`,
13491
+ ` entryMode: ${config.entryMode}`,
13492
+ ` strict: ${config.strict ?? false}`,
13493
+ ` language: ${config.language ?? "(not set)"}`,
13494
+ ` autoUpdate: ${config.autoUpdate ?? true}`,
13495
+ ` autoSubagent: ${config.autoSubagent ?? true}`,
13496
+ ` autoIssueReport: ${config.autoIssueReport ?? false}`,
13497
+ "",
13498
+ "Edit .reap/config.yml to change settings."
13499
+ ].join(`
13500
+ `);
13501
+ emitOutput({
13502
+ status: "ok",
13503
+ command: "config",
13504
+ phase: "show",
13505
+ completed: ["read-config"],
13506
+ message: lines
13507
+ });
13508
+ }
13509
+ var init_config2 = __esm(() => {
13510
+ init_config();
13511
+ });
13512
+
13310
13513
  // src/cli/commands/run/index.ts
13311
13514
  var exports_run = {};
13312
13515
  __export(exports_run, {
13313
13516
  runCommand: () => runCommand
13314
13517
  });
13518
+ import { execSync as execSync6 } from "child_process";
13315
13519
  async function runCommand(command, phase) {
13316
13520
  const cwd = process.cwd();
13317
13521
  const paths = new ReapPaths(cwd);
@@ -13322,12 +13526,33 @@ async function runCommand(command, phase) {
13322
13526
  if (!loader) {
13323
13527
  emitError(command, `Unknown command: ${command}. Available: ${Object.keys(COMMANDS).join(", ")}`);
13324
13528
  }
13325
- const mod = await loader();
13326
- await mod.execute(paths, phase);
13529
+ try {
13530
+ const mod = await loader();
13531
+ await mod.execute(paths, phase);
13532
+ } catch (err) {
13533
+ try {
13534
+ const config = await ConfigManager.read(paths);
13535
+ if (config.autoIssueReport) {
13536
+ const version = "0.12.0";
13537
+ const errMsg = err instanceof Error ? err.message : String(err);
13538
+ const title = `[auto] reap run ${command}: ${errMsg.slice(0, 80)}`;
13539
+ const body = [
13540
+ `**REAP Version**: ${version}`,
13541
+ `**Command**: reap run ${command}${phase ? ` --phase ${phase}` : ""}`,
13542
+ `**Error**: ${errMsg}`,
13543
+ `**OS**: ${process.platform} ${process.arch}`,
13544
+ `**Node**: ${process.version}`
13545
+ ].join("\\n");
13546
+ execSync6(`gh issue create --repo c-d-cc/reap --title "${title}" --label "auto-reported,bug" --body "${body}"`, { stdio: "ignore", timeout: 1e4 });
13547
+ }
13548
+ } catch {}
13549
+ emitError(command, err instanceof Error ? err.message : String(err));
13550
+ }
13327
13551
  }
13328
13552
  var COMMANDS;
13329
13553
  var init_run = __esm(() => {
13330
13554
  init_paths();
13555
+ init_config();
13331
13556
  COMMANDS = {
13332
13557
  next: () => Promise.resolve().then(() => (init_next(), exports_next)),
13333
13558
  back: () => Promise.resolve().then(() => (init_back(), exports_back)),
@@ -13354,7 +13579,8 @@ var init_run = __esm(() => {
13354
13579
  "merge-completion": () => Promise.resolve().then(() => (init_merge_completion(), exports_merge_completion)),
13355
13580
  "merge-evolve": () => Promise.resolve().then(() => (init_merge_evolve(), exports_merge_evolve)),
13356
13581
  merge: () => Promise.resolve().then(() => (init_merge2(), exports_merge)),
13357
- pull: () => Promise.resolve().then(() => (init_pull(), exports_pull))
13582
+ pull: () => Promise.resolve().then(() => (init_pull(), exports_pull)),
13583
+ config: () => Promise.resolve().then(() => (init_config2(), exports_config))
13358
13584
  };
13359
13585
  });
13360
13586
 
@@ -13572,6 +13798,30 @@ class ClaudeCodeAdapter {
13572
13798
  } catch {}
13573
13799
  return removed;
13574
13800
  }
13801
+ async setupClaudeMd(projectRoot) {
13802
+ const claudeMdPath = join2(projectRoot, ".claude", "CLAUDE.md");
13803
+ const marker = "# REAP Project";
13804
+ const reapSection = `# REAP Project
13805
+ This project uses REAP. Session-start hook loads project knowledge on session start.
13806
+ If context was compacted and REAP knowledge is lost, re-run the session-start hook.
13807
+ `;
13808
+ await mkdir(join2(projectRoot, ".claude"), { recursive: true });
13809
+ const existing = await readTextFile(claudeMdPath);
13810
+ if (existing === null) {
13811
+ await writeTextFile(claudeMdPath, reapSection);
13812
+ return { action: "created" };
13813
+ }
13814
+ if (existing.includes(marker)) {
13815
+ const updated = existing.replace(/# REAP Project[\s\S]*?(?=\n# |\n*$)/, reapSection.trim());
13816
+ if (updated === existing)
13817
+ return { action: "skipped" };
13818
+ await writeTextFile(claudeMdPath, updated);
13819
+ return { action: "updated" };
13820
+ }
13821
+ await writeTextFile(claudeMdPath, reapSection + `
13822
+ ` + existing);
13823
+ return { action: "created" };
13824
+ }
13575
13825
  getHookEntry() {
13576
13826
  const sessionStartPath = join2(ReapPaths.packageHooksDir, "session-start.cjs");
13577
13827
  return {
@@ -13832,7 +14082,8 @@ var COMMAND_NAMES = [
13832
14082
  "reap.merge.evolve",
13833
14083
  "reap.merge",
13834
14084
  "reap.pull",
13835
- "reap.push"
14085
+ "reap.push",
14086
+ "reap.config"
13836
14087
  ];
13837
14088
  async function initProject(projectRoot, projectName, entryMode, preset, onProgress) {
13838
14089
  const log = onProgress ?? (() => {});
@@ -13866,11 +14117,15 @@ async function initProject(projectRoot, projectName, entryMode, preset, onProgre
13866
14117
  if (!hasGhCli) {
13867
14118
  log("GitHub CLI(gh) not found. Install from https://cli.github.com for auto issue reporting.");
13868
14119
  }
14120
+ const detectedLanguage = await AgentRegistry.readLanguage();
13869
14121
  const config = {
13870
- version: "0.11.0",
14122
+ version: "0.12.0",
13871
14123
  project: projectName,
13872
14124
  entryMode,
14125
+ strict: false,
14126
+ ...detectedLanguage && { language: detectedLanguage },
13873
14127
  autoUpdate: true,
14128
+ autoSubagent: true,
13874
14129
  autoIssueReport: hasGhCli,
13875
14130
  ...preset && { preset }
13876
14131
  };
@@ -13929,6 +14184,10 @@ async function initProject(projectRoot, projectName, entryMode, preset, onProgre
13929
14184
  await adapter.installCommands(COMMAND_NAMES, sourceDir);
13930
14185
  log(` Registering session hook for ${adapter.displayName}...`);
13931
14186
  await adapter.registerSessionHook();
14187
+ if (typeof adapter.setupClaudeMd === "function") {
14188
+ const mdResult = await adapter.setupClaudeMd(projectRoot);
14189
+ log(` .claude/CLAUDE.md: ${mdResult.action}`);
14190
+ }
13932
14191
  }
13933
14192
  if (detectedAgents.length === 0) {
13934
14193
  log(" No AI agents detected.");
@@ -14159,6 +14418,140 @@ class MigrationRunner {
14159
14418
  }
14160
14419
  }
14161
14420
 
14421
+ // src/core/migration-spec.ts
14422
+ init_fs();
14423
+ var import_yaml6 = __toESM(require_dist(), 1);
14424
+ import { existsSync as existsSync2 } from "fs";
14425
+ function buildMigrationSpec(paths) {
14426
+ const sections = [];
14427
+ sections.push(`## Config fields (config.yml)
14428
+
14429
+ | Field | Type | Required | Default |
14430
+ |-------|------|----------|---------|
14431
+ | version | string | yes | — |
14432
+ | project | string | yes | — |
14433
+ | entryMode | greenfield \\| migration \\| adoption | yes | — |
14434
+ | stack | string | no | — |
14435
+ | preset | string | no | — |
14436
+ | agents | AgentName[] | no | auto-detect |
14437
+ | language | string | no | — |
14438
+ | autoUpdate | boolean | no | true |
14439
+ | autoSubagent | boolean | no | true |
14440
+ | autoIssueReport | boolean | no | false |
14441
+ | strict | boolean \\| { edit?: boolean; merge?: boolean } | no | false |`);
14442
+ sections.push(`## Expected directory structure
14443
+
14444
+ .reap/
14445
+ ├── config.yml
14446
+ ├── genome/
14447
+ │ ├── principles.md
14448
+ │ ├── conventions.md
14449
+ │ ├── constraints.md
14450
+ │ ├── source-map.md
14451
+ │ └── domain/
14452
+ ├── environment/
14453
+ │ ├── summary.md
14454
+ │ ├── docs/
14455
+ │ └── resources/
14456
+ ├── life/
14457
+ │ ├── current.yml
14458
+ │ ├── backlog/
14459
+ │ ├── 01-objective.md
14460
+ │ ├── 02-planning.md
14461
+ │ ├── 03-implementation.md
14462
+ │ ├── 04-validation.md
14463
+ │ └── 05-completion.md
14464
+ ├── lineage/
14465
+ │ └── gen-NNN-hash/ or gen-NNN-hash.md
14466
+ └── hooks/
14467
+ ├── conditions/
14468
+ └── {event}.{name}.{sh|md}`);
14469
+ sections.push(`## Slash commands (29)
14470
+
14471
+ reap.objective, reap.planning, reap.implementation,
14472
+ reap.validation, reap.completion, reap.evolve,
14473
+ reap.start, reap.next, reap.back, reap.abort,
14474
+ reap.status, reap.sync, reap.sync.genome, reap.sync.environment,
14475
+ reap.help, reap.update, reap.report,
14476
+ reap.merge.start, reap.merge.detect, reap.merge.mate,
14477
+ reap.merge.merge, reap.merge.sync, reap.merge.validation,
14478
+ reap.merge.completion, reap.merge.evolve,
14479
+ reap.merge,
14480
+ reap.pull, reap.push,
14481
+ reap.config`);
14482
+ sections.push(`## Hooks format
14483
+
14484
+ File naming: {event}.{name}.{md|sh}
14485
+ Location: .reap/hooks/
14486
+
14487
+ Frontmatter (md hooks):
14488
+ ---
14489
+ event: onLifeStarted
14490
+ name: my-hook
14491
+ description: What this hook does
14492
+ ---
14493
+
14494
+ Condition files: .reap/hooks/conditions/{name}.yml`);
14495
+ sections.push(`## Project root: ${paths.projectRoot}`);
14496
+ return sections.join(`
14497
+
14498
+ `);
14499
+ }
14500
+ async function detectMigrationGaps(paths) {
14501
+ const gaps = [];
14502
+ const configContent = await readTextFile(paths.config);
14503
+ if (configContent === null) {
14504
+ gaps.push("config.yml missing");
14505
+ } else {
14506
+ try {
14507
+ const config = import_yaml6.default.parse(configContent);
14508
+ if (!config?.version)
14509
+ gaps.push("config.yml: missing required field 'version'");
14510
+ if (!config?.project)
14511
+ gaps.push("config.yml: missing required field 'project'");
14512
+ if (!config?.entryMode)
14513
+ gaps.push("config.yml: missing required field 'entryMode'");
14514
+ } catch {
14515
+ gaps.push("config.yml: invalid YAML");
14516
+ }
14517
+ }
14518
+ if (!existsSync2(paths.genome)) {
14519
+ gaps.push("genome/ directory missing");
14520
+ } else {
14521
+ const genomeFiles = [
14522
+ { path: paths.principles, label: "genome/principles.md" },
14523
+ { path: paths.conventions, label: "genome/conventions.md" },
14524
+ { path: paths.constraints, label: "genome/constraints.md" },
14525
+ { path: paths.sourceMap, label: "genome/source-map.md" }
14526
+ ];
14527
+ for (const { path, label } of genomeFiles) {
14528
+ if (!existsSync2(path)) {
14529
+ gaps.push(`${label} missing`);
14530
+ }
14531
+ }
14532
+ }
14533
+ if (!existsSync2(paths.environment)) {
14534
+ gaps.push("environment/ directory missing");
14535
+ }
14536
+ if (!existsSync2(paths.life)) {
14537
+ gaps.push("life/ directory missing");
14538
+ } else {
14539
+ if (!existsSync2(paths.backlog)) {
14540
+ gaps.push("life/backlog/ directory missing");
14541
+ }
14542
+ }
14543
+ if (!existsSync2(paths.lineage)) {
14544
+ gaps.push("lineage/ directory missing");
14545
+ }
14546
+ if (!existsSync2(paths.hooks)) {
14547
+ gaps.push("hooks/ directory missing");
14548
+ }
14549
+ if (!existsSync2(paths.hookConditions)) {
14550
+ gaps.push("hooks/conditions/ directory missing");
14551
+ }
14552
+ return gaps;
14553
+ }
14554
+
14162
14555
  // src/cli/commands/update.ts
14163
14556
  function selfUpgrade() {
14164
14557
  try {
@@ -14278,7 +14671,23 @@ async function updateProject(projectRoot, dryRun = false) {
14278
14671
  result.skipped.push(`[${adapter.displayName}] session hook`);
14279
14672
  }
14280
14673
  }
14674
+ for (const adapter of adapters) {
14675
+ if (typeof adapter.setupClaudeMd === "function") {
14676
+ const mdResult = await adapter.setupClaudeMd(projectRoot);
14677
+ if (mdResult.action !== "skipped") {
14678
+ result.updated.push(`[${adapter.displayName}] .claude/CLAUDE.md (${mdResult.action})`);
14679
+ } else {
14680
+ result.skipped.push(`[${adapter.displayName}] .claude/CLAUDE.md`);
14681
+ }
14682
+ }
14683
+ }
14281
14684
  if (await paths.isReapProject()) {
14685
+ if (!dryRun) {
14686
+ const backfillResult = await ConfigManager.backfill(paths);
14687
+ if (backfillResult.added.length > 0) {
14688
+ result.updated.push(`Config: added ${backfillResult.added.join(", ")}`);
14689
+ }
14690
+ }
14282
14691
  const projectClaudeCommands = join10(paths.projectRoot, ".claude", "commands");
14283
14692
  await mkdir6(projectClaudeCommands, { recursive: true });
14284
14693
  const reapCmdFiles = (await readdir9(ReapPaths.userReapCommands)).filter((f) => f.startsWith("reap.") && f.endsWith(".md"));
@@ -14309,7 +14718,7 @@ async function updateProject(projectRoot, dryRun = false) {
14309
14718
  result.skipped.push(`.claude/commands/ (${reapCmdFiles.length} unchanged)`);
14310
14719
  }
14311
14720
  await migrateLegacyFiles(paths, dryRun, result);
14312
- const currentVersion = "0.11.0";
14721
+ const currentVersion = "0.12.0";
14313
14722
  const migrationResult = await MigrationRunner.run(paths, currentVersion, dryRun);
14314
14723
  for (const m of migrationResult.migrated) {
14315
14724
  result.updated.push(`[migration] ${m}`);
@@ -14320,6 +14729,17 @@ async function updateProject(projectRoot, dryRun = false) {
14320
14729
  for (const e of migrationResult.errors) {
14321
14730
  result.removed.push(`[migration error] ${e}`);
14322
14731
  }
14732
+ const gaps = await detectMigrationGaps(paths);
14733
+ if (gaps.length > 0) {
14734
+ const spec = buildMigrationSpec(paths);
14735
+ console.log(JSON.stringify({
14736
+ status: "prompt",
14737
+ command: "migrate",
14738
+ gaps,
14739
+ spec,
14740
+ prompt: "Analyze the gaps between current .reap/ structure and expected structure. Fix each gap after user confirmation."
14741
+ }, null, 2));
14742
+ }
14323
14743
  if (migrationResult.errors.length > 0 && config?.autoIssueReport) {
14324
14744
  try {
14325
14745
  const { execSync: execSync3 } = await import("child_process");
@@ -14415,7 +14835,7 @@ async function getStatus(projectRoot) {
14415
14835
  init_paths();
14416
14836
  init_lifecycle();
14417
14837
  init_fs();
14418
- var import_yaml6 = __toESM(require_dist(), 1);
14838
+ var import_yaml7 = __toESM(require_dist(), 1);
14419
14839
  import { mkdir as mkdir7, stat as stat3, copyFile } from "fs/promises";
14420
14840
  import { join as join11 } from "path";
14421
14841
  async function dirExists(path) {
@@ -14468,7 +14888,7 @@ async function fixProject(projectRoot) {
14468
14888
  if (currentContent !== null) {
14469
14889
  if (currentContent.trim()) {
14470
14890
  try {
14471
- const state = import_yaml6.default.parse(currentContent);
14891
+ const state = import_yaml7.default.parse(currentContent);
14472
14892
  if (!state.stage || !LifeCycle.isValid(state.stage)) {
14473
14893
  issues.push(`Invalid stage "${state.stage}" in current.yml. Valid stages: ${LifeCycle.stages().join(", ")}. Manual correction required.`);
14474
14894
  }
@@ -14495,8 +14915,8 @@ init_paths();
14495
14915
  init_fs();
14496
14916
  init_version();
14497
14917
  init_config();
14498
- import { join as join25 } from "path";
14499
- program.name("reap").description("REAP — Recursive Evolutionary Autonomous Pipeline").version("0.11.0");
14918
+ import { join as join26 } from "path";
14919
+ program.name("reap").description("REAP — Recursive Evolutionary Autonomous Pipeline").version("0.12.0");
14500
14920
  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) => {
14501
14921
  try {
14502
14922
  const cwd = process.cwd();
@@ -14504,9 +14924,9 @@ program.command("init").description("Initialize a new REAP project (Genesis)").a
14504
14924
  let mode = options.mode;
14505
14925
  const modeExplicit = process.argv.some((a) => a === "-m" || a === "--mode");
14506
14926
  if (!modeExplicit && mode === "greenfield") {
14507
- const { existsSync: existsSync2 } = __require("fs");
14927
+ const { existsSync: existsSync3 } = __require("fs");
14508
14928
  const signals = ["package.json", "go.mod", "Cargo.toml", "pom.xml", "pyproject.toml", "Makefile", "CMakeLists.txt"];
14509
- const hasExistingProject = signals.some((f) => existsSync2(__require("path").join(cwd, f)));
14929
+ const hasExistingProject = signals.some((f) => existsSync3(__require("path").join(cwd, f)));
14510
14930
  if (hasExistingProject) {
14511
14931
  mode = "adoption";
14512
14932
  console.log(`Existing project detected. Automatically using adoption mode.`);
@@ -14630,10 +15050,10 @@ program.command("help").description("Show REAP commands, slash commands, and wor
14630
15050
  if (l === "korean" || l === "ko")
14631
15051
  lang = "ko";
14632
15052
  }
14633
- const helpDir = join25(ReapPaths.packageTemplatesDir, "help");
14634
- let helpText = await readTextFile(join25(helpDir, `${lang}.txt`));
15053
+ const helpDir = join26(ReapPaths.packageTemplatesDir, "help");
15054
+ let helpText = await readTextFile(join26(helpDir, `${lang}.txt`));
14635
15055
  if (!helpText)
14636
- helpText = await readTextFile(join25(helpDir, "en.txt"));
15056
+ helpText = await readTextFile(join26(helpDir, "en.txt"));
14637
15057
  if (!helpText) {
14638
15058
  console.log("Help file not found. Run 'reap update' to install templates.");
14639
15059
  return;
@@ -0,0 +1,5 @@
1
+ ---
2
+ description: "REAP Config — Show current project configuration"
3
+ ---
4
+
5
+ Run `reap run config` and follow the stdout instructions exactly.
@@ -156,21 +156,21 @@ REAP supports multiple AI agents simultaneously through the AgentAdapter abstrac
156
156
 
157
157
  ## Execution Flow
158
158
 
159
+ **Lifecycle stages** (5 stages, in order):
159
160
  ```
160
- 1. /reap.startStart a new Generation
161
- 2. /reap.objective → Define goal + requirements
162
- 3. /reap.next
163
- 4. /reap.planning → Task decomposition + implementation plan
164
- 5. /reap.next
165
- 6. /reap.implementation → Code implementation
166
- 7. /reap.next
167
- 8. /reap.validation → Verification
168
- 9. /reap.next
169
- 10. /reap.completion → Retrospective + genome updates
170
- 11. /reap.next → Archiving, generation ends
161
+ objective planning implementation validation → completion
171
162
  ```
172
163
 
173
- Each slash command follows a 3-step structure: Gate (precondition check) → Steps (work execution) → Artifact generation.
164
+ **Execution sequence**:
165
+ 1. `/reap.start` — Create a new Generation
166
+ 2. `/reap.objective` — Define goal + requirements → `/reap.next`
167
+ 3. `/reap.planning` — Task decomposition + plan → `/reap.next`
168
+ 4. `/reap.implementation` — Code implementation → `/reap.next`
169
+ 5. `/reap.validation` — Verification → `/reap.next`
170
+ 6. `/reap.completion` — Retrospective + genome updates + archiving (auto)
171
+
172
+ `/reap.next` is a **transition command**, not a lifecycle stage. It advances `current.yml` to the next stage.
173
+ `/reap.completion` auto-archives after the genome phase — no separate `/reap.next` needed at the end.
174
174
 
175
175
  ## Language
176
176
 
@@ -204,3 +204,4 @@ When `strict: true` is set in `.reap/config.yml`, the AI agent enforces code mod
204
204
  4. **Genome is the authoritative source of truth.** When making any decision about architecture, conventions, constraints, or domain rules, ALWAYS consult the Genome first. If you observe code that contradicts the Genome, flag it as a potential `genome-change` backlog item. Do NOT silently ignore discrepancies.
205
205
  5. **Keep Genome fresh.** If you notice the Genome is missing information about current code patterns, or contains outdated information, inform the human and suggest `/reap.sync`. The human may choose to defer sync — respect that choice, but always flag the staleness.
206
206
  6. **Report malfunctions.** If you detect unexpected behavior during REAP operations (state inconsistency, command failure, corrupted files), suggest `/reap.report` to the user. This helps improve REAP for everyone.
207
+ - If `reap run` returns an unexpected error (not a gate failure), and the error repeats 2+ times, automatically run `/reap.report`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c-d-cc/reap",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Recursive Evolutionary Autonomous Pipeline — AI and humans evolve software across generations",
5
5
  "type": "module",
6
6
  "license": "MIT",