@c-d-cc/reap 0.16.1 → 0.16.3

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.de.md CHANGED
@@ -30,7 +30,7 @@ REAP ist eine generationsbasierte Entwicklungspipeline, in der KI und Menschen z
30
30
  - [Konfiguration](#konfiguration-)
31
31
  - [Upgrade von v0.15](#upgrade-von-v015)
32
32
 
33
- ## Was ist REAP?
33
+ ## Was ist REAP? [↗](https://reap.cc/docs/introduction)
34
34
 
35
35
  Sind Ihnen bei der Entwicklung mit KI-Agenten schon einmal diese Probleme begegnet?
36
36
 
@@ -59,7 +59,7 @@ npm install -g @c-d-cc/reap
59
59
 
60
60
  > **Voraussetzungen**: [Node.js](https://nodejs.org) v18+, [Claude Code](https://claude.ai/claude-code) CLI.
61
61
 
62
- ## Schnellstart
62
+ ## Schnellstart [↗](https://reap.cc/docs/quick-start)
63
63
 
64
64
  Öffnen Sie Ihren KI-Agenten (Claude Code) und verwenden Sie Slash Commands:
65
65
 
@@ -202,7 +202,7 @@ N Generationen für autonome Ausführung vorab genehmigen:
202
202
  - Bei erkannter Unsicherheit oder Risiko pausiert der Cruise-Modus und fordert menschliches Feedback an
203
203
  - Nach Abschluss aller N Generationen überprüft der Mensch das Ergebnis
204
204
 
205
- ## Slash Commands
205
+ ## Slash Commands [↗](https://reap.cc/docs/command-reference)
206
206
 
207
207
  | Befehl | Beschreibung |
208
208
  |--------|-------------|
@@ -283,7 +283,7 @@ Wichtige Einstellungen:
283
283
  - **`strictMerge`**: Beschränkt direktes git pull/push/merge — verwenden Sie stattdessen `/reap.pull`, `/reap.push`, `/reap.merge`.
284
284
  - **`agentClient`**: Bestimmt, welcher Adapter für die Skill-Bereitstellung verwendet wird.
285
285
 
286
- ## Upgrade von v0.15
286
+ ## Upgrade von v0.15 [↗](https://reap.cc/docs/migration-guide)
287
287
 
288
288
  REAP v0.16 ist eine vollständige Neuentwicklung, basierend auf der [Self-Evolving Pipeline](https://reap.cc/docs/self-evolving)-Architektur.
289
289
 
@@ -336,7 +336,7 @@ Alle v0.15-Dateien werden unter `.reap/v15/` aufbewahrt. Nach Überprüfung der
336
336
  **Vision-Ebene hinzugefügt:**
337
337
  - `vision/goals.md` — Langfristige Ziele, lückengetriebene Zielauswahl in der Adapt-Phase
338
338
  - `vision/memory/` — 3-stufiges Gedächtnis (longterm, midterm, shortterm) für generationsübergreifenden Kontext
339
- - `vision/docs/` — Planungsdokumente und Spezifikationen
339
+ - `vision/design/` — Planungsdokumente und Spezifikationen
340
340
 
341
341
  **Genome umstrukturiert (3 Dateien):**
342
342
  - `application.md` — Projektidentität, Architektur, Konventionen, Einschränkungen
package/README.ja.md CHANGED
@@ -30,7 +30,7 @@ REAPは、AIと人間が協力してソフトウェアを構築・進化させ
30
30
  - [設定](#設定-)
31
31
  - [v0.15からのアップグレード](#v015からのアップグレード)
32
32
 
33
- ## REAPとは?
33
+ ## REAPとは? [↗](https://reap.cc/docs/introduction)
34
34
 
35
35
  AIエージェントを使った開発で、こんな問題に遭遇したことはありませんか?
36
36
 
@@ -59,7 +59,7 @@ npm install -g @c-d-cc/reap
59
59
 
60
60
  > **要件**: [Node.js](https://nodejs.org) v18以上、[Claude Code](https://claude.ai/claude-code) CLI。
61
61
 
62
- ## クイックスタート
62
+ ## クイックスタート [↗](https://reap.cc/docs/quick-start)
63
63
 
64
64
  AIエージェント(Claude Code)を開き、スラッシュコマンドを使います:
65
65
 
@@ -202,7 +202,7 @@ N世代分の自律実行を事前承認:
202
202
  - 不確実性やリスクが検出された場合、cruise を一時停止して人間のフィードバックを要求
203
203
  - 全N世代の完了後、人間がバッチをレビュー
204
204
 
205
- ## スラッシュコマンド
205
+ ## スラッシュコマンド [↗](https://reap.cc/docs/command-reference)
206
206
 
207
207
  | コマンド | 説明 |
208
208
  |----------|------|
@@ -283,7 +283,7 @@ agentClient: claude-code # AIエージェントクライアント
283
283
  - **`strictMerge`**: 直接の git pull/push/merge を制限します — 代わりに `/reap.pull`、`/reap.push`、`/reap.merge` を使用してください。
284
284
  - **`agentClient`**: スキルのデプロイに使用するアダプターを決定します。
285
285
 
286
- ## v0.15からのアップグレード
286
+ ## v0.15からのアップグレード [↗](https://reap.cc/docs/migration-guide)
287
287
 
288
288
  REAP v0.16 は [Self-Evolving Pipeline](https://reap.cc/docs/self-evolving) アーキテクチャに基づく完全な書き直しです。
289
289
 
@@ -336,7 +336,7 @@ REAP v0.16 は [Self-Evolving Pipeline](https://reap.cc/docs/self-evolving) ア
336
336
  **Vision レイヤーの追加:**
337
337
  - `vision/goals.md` — 長期目標、adapt フェーズでのギャップ駆動目標選択
338
338
  - `vision/memory/` — 3層メモリ(longterm, midterm, shortterm)によるジェネレーション間コンテキスト
339
- - `vision/docs/` — 計画ドキュメントと仕様書
339
+ - `vision/design/` — 計画ドキュメントと仕様書
340
340
 
341
341
  **Genome の再構成(3ファイル):**
342
342
  - `application.md` — プロジェクトのアイデンティティ、アーキテクチャ、コンベンション、制約
package/README.ko.md CHANGED
@@ -30,7 +30,7 @@ REAP는 AI와 인간이 협력하여 소프트웨어를 구축하고 진화시
30
30
  - [설정](#설정-)
31
31
  - [v0.15에서 업그레이드](#v015에서-업그레이드)
32
32
 
33
- ## REAP란 무엇인가?
33
+ ## REAP란 무엇인가? [↗](https://reap.cc/docs/introduction)
34
34
 
35
35
  AI 에이전트와 개발할 때 이런 문제를 겪어 본 적 있으신가요?
36
36
 
@@ -59,7 +59,7 @@ npm install -g @c-d-cc/reap
59
59
 
60
60
  > **요구 사항**: [Node.js](https://nodejs.org) v18+, [Claude Code](https://claude.ai/claude-code) CLI.
61
61
 
62
- ## 빠른 시작
62
+ ## 빠른 시작 [↗](https://reap.cc/docs/quick-start)
63
63
 
64
64
  AI 에이전트(Claude Code)를 열고 슬래시 명령어를 사용하세요:
65
65
 
@@ -202,7 +202,7 @@ N개 세대를 사전 승인하여 자율 실행:
202
202
  - 불확실성이나 위험이 감지되면 cruise가 일시 정지하고 인간 피드백을 요청
203
203
  - N개 세대 모두 완료 후 인간이 일괄 검토
204
204
 
205
- ## 슬래시 명령어
205
+ ## 슬래시 명령어 [↗](https://reap.cc/docs/command-reference)
206
206
 
207
207
  | 명령어 | 설명 |
208
208
  |--------|------|
@@ -283,7 +283,7 @@ agentClient: claude-code # AI 에이전트 클라이언트
283
283
  - **`strictMerge`**: 직접 git pull/push/merge를 제한합니다 — 대신 `/reap.pull`, `/reap.push`, `/reap.merge`를 사용하세요.
284
284
  - **`agentClient`**: 스킬 배포에 사용할 어댑터를 결정합니다.
285
285
 
286
- ## v0.15에서 업그레이드
286
+ ## v0.15에서 업그레이드 [↗](https://reap.cc/docs/migration-guide)
287
287
 
288
288
  REAP v0.16은 [Self-Evolving Pipeline](https://reap.cc/docs/self-evolving) 아키텍처를 기반으로 완전히 재작성되었습니다.
289
289
 
@@ -336,7 +336,7 @@ REAP v0.16은 [Self-Evolving Pipeline](https://reap.cc/docs/self-evolving) 아
336
336
  **Vision 레이어 추가:**
337
337
  - `vision/goals.md` — 장기 목표, 적응 단계에서 간극 기반 목표 선택
338
338
  - `vision/memory/` — 3계층 메모리 (longterm, midterm, shortterm), 세대 간 컨텍스트 유지
339
- - `vision/docs/` — 기획 문서 및 스펙
339
+ - `vision/design/` — 기획 문서 및 스펙
340
340
 
341
341
  **Genome 재구성 (3파일):**
342
342
  - `application.md` — 프로젝트 정체성, 아키텍처, 컨벤션, 제약 조건
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- > [한국어](README.ko.md) | [日本語](README.ja.md) | [简体中文](README.zh-CN.md) | [Deutsch](README.de.md)
1
+ > [한국어](https://github.com/c-d-cc/reap/blob/main/README.ko.md) | [日本語](https://github.com/c-d-cc/reap/blob/main/README.ja.md) | [简体中文](https://github.com/c-d-cc/reap/blob/main/README.zh-CN.md) | [Deutsch](https://github.com/c-d-cc/reap/blob/main/README.de.md)
2
2
 
3
3
  <p align="center">
4
4
  <img src="https://raw.githubusercontent.com/c-d-cc/reap/main/media/logo.png" alt="REAP" width="80" height="80" />
@@ -32,7 +32,7 @@ REAP is a generation-based development pipeline where AI and humans collaborate
32
32
  - [Configuration](#configuration-)
33
33
  - [Upgrading from v0.15](#upgrading-from-v015)
34
34
 
35
- ## What is REAP?
35
+ ## What is REAP? [↗](https://reap.cc/docs/introduction)
36
36
 
37
37
  Have you ever run into these problems when developing with AI agents?
38
38
 
@@ -61,7 +61,7 @@ npm install -g @c-d-cc/reap
61
61
 
62
62
  > **Requirements**: [Node.js](https://nodejs.org) v18+, [Claude Code](https://claude.ai/claude-code) CLI.
63
63
 
64
- ## Quick Start
64
+ ## Quick Start [↗](https://reap.cc/docs/quick-start)
65
65
 
66
66
  Open your AI agent (Claude Code) and use slash commands:
67
67
 
@@ -204,7 +204,7 @@ Pre-approve N generations for autonomous execution:
204
204
  - If uncertainty or risk is detected, cruise pauses and requests human feedback
205
205
  - After all N generations complete, human reviews the batch
206
206
 
207
- ## Slash Commands
207
+ ## Slash Commands [↗](https://reap.cc/docs/command-reference)
208
208
 
209
209
  | Command | Description |
210
210
  |---------|-------------|
@@ -284,7 +284,7 @@ Key settings:
284
284
  - **`strictMerge`**: Restricts direct git pull/push/merge — use `/reap.pull`, `/reap.push`, `/reap.merge` instead.
285
285
  - **`agentClient`**: Determines which adapter is used for skill deployment.
286
286
 
287
- ## Upgrading from v0.15
287
+ ## Upgrading from v0.15 [↗](https://reap.cc/docs/migration-guide)
288
288
 
289
289
  REAP v0.16 is a complete rewrite built on the [Self-Evolving Pipeline](https://reap.cc/docs/self-evolving) architecture.
290
290
 
@@ -337,7 +337,7 @@ All v0.15 files are preserved at `.reap/v15/`. After verifying the migration, yo
337
337
  **Vision layer added:**
338
338
  - `vision/goals.md` — long-term objectives, gap-driven goal selection at adapt phase
339
339
  - `vision/memory/` — 3-tier memory (longterm, midterm, shortterm) for cross-generation context
340
- - `vision/docs/` — planning documents and specs
340
+ - `vision/design/` — planning documents and specs
341
341
 
342
342
  **Genome restructured (3 files):**
343
343
  - `application.md` — project identity, architecture, conventions, constraints
package/README.zh-CN.md CHANGED
@@ -30,7 +30,7 @@ REAP 是一个基于代际迭代的开发管道,AI 与人类协作构建和进
30
30
  - [配置](#配置-)
31
31
  - [从 v0.15 升级](#从-v015-升级)
32
32
 
33
- ## 什么是 REAP?
33
+ ## 什么是 REAP? [↗](https://reap.cc/docs/introduction)
34
34
 
35
35
  在使用 AI 智能体进行开发时,你是否遇到过以下问题?
36
36
 
@@ -59,7 +59,7 @@ npm install -g @c-d-cc/reap
59
59
 
60
60
  > **前提条件**:[Node.js](https://nodejs.org) v18+,[Claude Code](https://claude.ai/claude-code) CLI。
61
61
 
62
- ## 快速开始
62
+ ## 快速开始 [↗](https://reap.cc/docs/quick-start)
63
63
 
64
64
  打开你的 AI 智能体(Claude Code)并使用斜杠命令:
65
65
 
@@ -202,7 +202,7 @@ AI 根据当前上下文的明确程度调整其沟通风格:
202
202
  - 如果检测到不确定性或风险,cruise 暂停并请求人类反馈
203
203
  - 所有 N 个代际迭代完成后,人类审阅整批结果
204
204
 
205
- ## 斜杠命令
205
+ ## 斜杠命令 [↗](https://reap.cc/docs/command-reference)
206
206
 
207
207
  | 命令 | 描述 |
208
208
  |------|------|
@@ -283,7 +283,7 @@ agentClient: claude-code # AI 智能体客户端
283
283
  - **`strictMerge`**:限制直接 git pull/push/merge——请改用 `/reap.pull`、`/reap.push`、`/reap.merge`。
284
284
  - **`agentClient`**:决定使用哪个适配器进行技能部署。
285
285
 
286
- ## 从 v0.15 升级
286
+ ## 从 v0.15 升级 [↗](https://reap.cc/docs/migration-guide)
287
287
 
288
288
  REAP v0.16 是基于[自进化管道](https://reap.cc/docs/self-evolving)架构的完全重写。
289
289
 
@@ -336,7 +336,7 @@ REAP v0.16 是基于[自进化管道](https://reap.cc/docs/self-evolving)架构
336
336
  **新增 Vision 层:**
337
337
  - `vision/goals.md` — 长期目标,在适应阶段进行差距驱动的目标选择
338
338
  - `vision/memory/` — 3层记忆(longterm、midterm、shortterm)用于跨代际迭代的上下文
339
- - `vision/docs/` — 规划文档和规范
339
+ - `vision/design/` — 规划文档和规范
340
340
 
341
341
  **Genome 重构(3个文件):**
342
342
  - `application.md` — 项目身份、架构、规范、约束
package/RELEASE_NOTICE.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Release Notices
2
2
 
3
+ ## v0.16.3
4
+ ### en
5
+ Rename vision/docs to vision/design to avoid confusion with root docs/. Add Design section to Vision (separate from Memory for independent design documents). Add Evaluator Agent design doc. Fix README language links for npm compatibility.
6
+ ### ko
7
+ vision/docs를 vision/design으로 리네이밍하여 루트 docs/와의 혼동 방지. Vision에 Design 섹션 추가 (Memory와 구분되는 독립 설계 문서 공간). Evaluator Agent 설계 문서 추가. npm 호환을 위해 README 언어 링크 수정.
8
+
9
+ ## v0.16.2
10
+ ### en
11
+ Add `reap make hook` CLI command for creating hooks with correct format. Restore default hook conditions (always, has-code-changes, version-bumped). Remove outdated Presets and Session Context Loading from docs.
12
+ ### ko
13
+ `reap make hook` CLI 커맨드 추가 — 올바른 형식의 hook 파일 생성. 기본 hook conditions 복원 (always, has-code-changes, version-bumped). docs에서 outdated된 Presets, Session Context Loading 섹션 제거.
14
+
15
+ ## v0.16.1
16
+ ### en
17
+ Fix npm README images not displaying. Restore SPA routing for docs site (404.html fallback). Fix broken docs links in README. Add docs workflow trigger paths.
18
+ ### ko
19
+ npm README 이미지 미표시 수정. docs 사이트 SPA 라우팅 복원 (404.html fallback). README 문서 링크 수정. docs workflow 트리거 경로 추가.
20
+
3
21
  ## v0.16.0
4
22
  ### en
5
23
  First v0.16.0 release. Major rewrite from v0.15 — new lifecycle engine, nonce-based stage verification, 2-level lineage compression, merge lifecycle, and adapter-based agent client support.
package/dist/cli/index.js CHANGED
@@ -7098,7 +7098,7 @@ async function checkDirectoryStructure(paths, errors) {
7098
7098
  { path: paths.environmentDomain, name: "environment/domain/" },
7099
7099
  { path: paths.environmentResources, name: "environment/resources/" },
7100
7100
  { path: paths.environmentDocs, name: "environment/docs/" },
7101
- { path: paths.visionDocs, name: "vision/docs/" },
7101
+ { path: paths.visionDesign, name: "vision/design/" },
7102
7102
  { path: paths.memory, name: "vision/memory/" }
7103
7103
  ];
7104
7104
  for (const dir of requiredDirs) {
@@ -7542,6 +7542,7 @@ __export(exports_common, {
7542
7542
  });
7543
7543
  import { join as join3, dirname as dirname2 } from "path";
7544
7544
  import { fileURLToPath } from "url";
7545
+ import { readdir as readdir2, copyFile, chmod } from "fs/promises";
7545
7546
  function distPath(...segments) {
7546
7547
  const __dirname2 = dirname2(fileURLToPath(import.meta.url));
7547
7548
  return join3(__dirname2, "..", "templates", ...segments);
@@ -7558,7 +7559,7 @@ async function initCommon(paths, projectName) {
7558
7559
  await ensureDir(paths.backlog);
7559
7560
  await ensureDir(paths.lineage);
7560
7561
  await ensureDir(paths.vision);
7561
- await ensureDir(paths.visionDocs);
7562
+ await ensureDir(paths.visionDesign);
7562
7563
  await ensureDir(paths.memory);
7563
7564
  await ensureDir(paths.hooks);
7564
7565
  const config = {
@@ -7583,6 +7584,7 @@ async function initCommon(paths, projectName) {
7583
7584
  `);
7584
7585
  await writeTextFile(paths.memoryShortterm, `# Shortterm Memory
7585
7586
  `);
7587
+ await installHookTemplates(paths.hooks);
7586
7588
  await ensureClaudeMd(paths.root, projectName);
7587
7589
  return config;
7588
7590
  }
@@ -7645,6 +7647,33 @@ async function ensureClaudeMd(root, projectName) {
7645
7647
  return "created";
7646
7648
  }
7647
7649
  }
7650
+ async function installHookTemplates(hooksDir) {
7651
+ const templateDir = distPath("hooks");
7652
+ const conditionsTemplateDir = join3(templateDir, "conditions");
7653
+ const conditionsDir = join3(hooksDir, "conditions");
7654
+ await ensureDir(conditionsDir);
7655
+ try {
7656
+ const conditionFiles = await readdir2(conditionsTemplateDir);
7657
+ for (const file of conditionFiles) {
7658
+ const dest = join3(conditionsDir, file);
7659
+ if (!await fileExists(dest)) {
7660
+ await copyFile(join3(conditionsTemplateDir, file), dest);
7661
+ await chmod(dest, 493);
7662
+ }
7663
+ }
7664
+ } catch {}
7665
+ try {
7666
+ const hookFiles = await readdir2(templateDir);
7667
+ for (const file of hookFiles) {
7668
+ if (!file.endsWith(".example"))
7669
+ continue;
7670
+ const dest = join3(hooksDir, file);
7671
+ if (!await fileExists(dest)) {
7672
+ await copyFile(join3(templateDir, file), dest);
7673
+ }
7674
+ }
7675
+ } catch {}
7676
+ }
7648
7677
  var import_yaml2, DEFAULT_INVARIANTS = `# Invariants
7649
7678
 
7650
7679
  > Absolute constraints. Human-only modification.
@@ -7668,7 +7697,7 @@ var init_common = __esm(() => {
7668
7697
 
7669
7698
  // src/cli/index.ts
7670
7699
  import { readFileSync as readFileSync4 } from "fs";
7671
- import { join as join23, dirname as dirname9 } from "path";
7700
+ import { join as join24, dirname as dirname9 } from "path";
7672
7701
  import { fileURLToPath as fileURLToPath7 } from "url";
7673
7702
 
7674
7703
  // src/libs/cli.ts
@@ -8359,7 +8388,7 @@ class Command {
8359
8388
  var program = new Command;
8360
8389
 
8361
8390
  // src/cli/commands/init/index.ts
8362
- import { readdir as readdir4 } from "fs/promises";
8391
+ import { readdir as readdir5 } from "fs/promises";
8363
8392
  import { join as join6 } from "path";
8364
8393
 
8365
8394
  // src/core/paths.ts
@@ -8391,7 +8420,7 @@ function createPaths(root) {
8391
8420
  lineage: join(reap, "lineage"),
8392
8421
  vision,
8393
8422
  visionGoals: join(vision, "goals.md"),
8394
- visionDocs: join(vision, "docs"),
8423
+ visionDesign: join(vision, "design"),
8395
8424
  memory,
8396
8425
  memoryLongterm: join(memory, "longterm.md"),
8397
8426
  memoryMidterm: join(memory, "midterm.md"),
@@ -8540,7 +8569,7 @@ init_common();
8540
8569
 
8541
8570
  // src/core/scanner.ts
8542
8571
  init_fs();
8543
- import { readdir as readdir2, stat as stat2 } from "fs/promises";
8572
+ import { readdir as readdir3, stat as stat2 } from "fs/promises";
8544
8573
  import { join as join4, relative } from "path";
8545
8574
  async function scanCodebase(root) {
8546
8575
  let packageJson = null;
@@ -8585,7 +8614,7 @@ async function buildTree(root, dir, depth) {
8585
8614
  return [];
8586
8615
  let entries;
8587
8616
  try {
8588
- entries = await readdir2(dir);
8617
+ entries = await readdir3(dir);
8589
8618
  } catch {
8590
8619
  return [];
8591
8620
  }
@@ -8923,7 +8952,7 @@ async function execute3(paths) {
8923
8952
  // src/cli/commands/migrate.ts
8924
8953
  init_fs();
8925
8954
  var import_yaml4 = __toESM(require_dist(), 1);
8926
- import { readdir as readdir3, cp, rename, rm as rm2 } from "fs/promises";
8955
+ import { readdir as readdir4, cp, rename, rm as rm2 } from "fs/promises";
8927
8956
  import { join as join5, dirname as dirname3 } from "path";
8928
8957
  import { execSync as execSync2 } from "child_process";
8929
8958
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -9200,7 +9229,7 @@ async function scanV15Structure(paths) {
9200
9229
  const genomeDir = join5(paths.reap, "v15", "genome");
9201
9230
  const currentGenomeDir = paths.genome;
9202
9231
  try {
9203
- const entries = await readdir3(currentGenomeDir);
9232
+ const entries = await readdir4(currentGenomeDir);
9204
9233
  for (const e of entries) {
9205
9234
  if (e.endsWith(".md"))
9206
9235
  genomeFiles.push(e);
@@ -9209,7 +9238,7 @@ async function scanV15Structure(paths) {
9209
9238
  const domainFiles = [];
9210
9239
  const domainDir = join5(currentGenomeDir, "domain");
9211
9240
  try {
9212
- const entries = await readdir3(domainDir);
9241
+ const entries = await readdir4(domainDir);
9213
9242
  for (const e of entries) {
9214
9243
  if (e.endsWith(".md"))
9215
9244
  domainFiles.push(e);
@@ -9217,18 +9246,18 @@ async function scanV15Structure(paths) {
9217
9246
  } catch {}
9218
9247
  let lineageCount = 0;
9219
9248
  try {
9220
- const entries = await readdir3(paths.lineage);
9249
+ const entries = await readdir4(paths.lineage);
9221
9250
  lineageCount = entries.filter((e) => e.startsWith("gen-")).length;
9222
9251
  } catch {}
9223
9252
  let backlogCount = 0;
9224
9253
  try {
9225
- const entries = await readdir3(paths.backlog);
9254
+ const entries = await readdir4(paths.backlog);
9226
9255
  backlogCount = entries.filter((e) => e.endsWith(".md")).length;
9227
9256
  } catch {}
9228
9257
  const hooks = [];
9229
9258
  const hooksMappingNeeded = [];
9230
9259
  try {
9231
- const entries = await readdir3(paths.hooks);
9260
+ const entries = await readdir4(paths.hooks);
9232
9261
  for (const e of entries) {
9233
9262
  if (e.startsWith("on") && (e.endsWith(".sh") || e.endsWith(".md"))) {
9234
9263
  hooks.push(e);
@@ -9458,7 +9487,7 @@ async function executeMain(paths) {
9458
9487
  const domainFiles = [];
9459
9488
  const v15DomainDir = join5(v15Dir, "genome", "domain");
9460
9489
  try {
9461
- const entries = await readdir3(v15DomainDir);
9490
+ const entries = await readdir4(v15DomainDir);
9462
9491
  domainFiles.push(...entries.filter((e) => e.endsWith(".md")));
9463
9492
  } catch {}
9464
9493
  await step("environment-copy", async () => {
@@ -9469,7 +9498,7 @@ async function executeMain(paths) {
9469
9498
  const v15EnvDomain = join5(v15Dir, "environment", "domain");
9470
9499
  if (await fileExists(v15EnvDomain)) {
9471
9500
  try {
9472
- const entries = await readdir3(v15EnvDomain);
9501
+ const entries = await readdir4(v15EnvDomain);
9473
9502
  for (const e of entries) {
9474
9503
  await cp(join5(v15EnvDomain, e), join5(paths.environmentDomain, e), { recursive: true });
9475
9504
  }
@@ -9478,7 +9507,7 @@ async function executeMain(paths) {
9478
9507
  const v15EnvResources = join5(v15Dir, "environment", "resources");
9479
9508
  if (await fileExists(v15EnvResources)) {
9480
9509
  try {
9481
- const entries = await readdir3(v15EnvResources);
9510
+ const entries = await readdir4(v15EnvResources);
9482
9511
  for (const e of entries) {
9483
9512
  await cp(join5(v15EnvResources, e), join5(paths.environmentResources, e), { recursive: true });
9484
9513
  }
@@ -9487,7 +9516,7 @@ async function executeMain(paths) {
9487
9516
  const v15EnvDocs = join5(v15Dir, "environment", "docs");
9488
9517
  if (await fileExists(v15EnvDocs)) {
9489
9518
  try {
9490
- const entries = await readdir3(v15EnvDocs);
9519
+ const entries = await readdir4(v15EnvDocs);
9491
9520
  for (const e of entries) {
9492
9521
  await cp(join5(v15EnvDocs, e), join5(paths.environmentDocs, e), { recursive: true });
9493
9522
  }
@@ -9510,7 +9539,7 @@ async function executeMain(paths) {
9510
9539
  const v15Lineage = join5(v15Dir, "lineage");
9511
9540
  if (await fileExists(v15Lineage)) {
9512
9541
  try {
9513
- const entries = await readdir3(v15Lineage);
9542
+ const entries = await readdir4(v15Lineage);
9514
9543
  for (const e of entries) {
9515
9544
  await cp(join5(v15Lineage, e), join5(paths.lineage, e), { recursive: true });
9516
9545
  }
@@ -9521,7 +9550,7 @@ async function executeMain(paths) {
9521
9550
  const v15Backlog = join5(v15Dir, "life", "backlog");
9522
9551
  if (await fileExists(v15Backlog)) {
9523
9552
  try {
9524
- const entries = await readdir3(v15Backlog);
9553
+ const entries = await readdir4(v15Backlog);
9525
9554
  for (const e of entries) {
9526
9555
  await cp(join5(v15Backlog, e), join5(paths.backlog, e), { recursive: true });
9527
9556
  }
@@ -9534,7 +9563,7 @@ async function executeMain(paths) {
9534
9563
  const v15Hooks = join5(v15Dir, "hooks");
9535
9564
  if (await fileExists(v15Hooks)) {
9536
9565
  try {
9537
- const entries = await readdir3(v15Hooks);
9566
+ const entries = await readdir4(v15Hooks);
9538
9567
  for (const e of entries) {
9539
9568
  if (e === "conditions") {
9540
9569
  const condSrc = join5(v15Hooks, "conditions");
@@ -9733,17 +9762,17 @@ async function executeComplete(paths) {
9733
9762
  await clearMigrationState(paths);
9734
9763
  let lineageCount = 0;
9735
9764
  try {
9736
- const entries = await readdir3(paths.lineage);
9765
+ const entries = await readdir4(paths.lineage);
9737
9766
  lineageCount = entries.filter((e) => e.startsWith("gen-")).length;
9738
9767
  } catch {}
9739
9768
  let backlogCount = 0;
9740
9769
  try {
9741
- const entries = await readdir3(paths.backlog);
9770
+ const entries = await readdir4(paths.backlog);
9742
9771
  backlogCount = entries.filter((e) => e.endsWith(".md")).length;
9743
9772
  } catch {}
9744
9773
  let hookCount = 0;
9745
9774
  try {
9746
- const entries = await readdir3(paths.hooks);
9775
+ const entries = await readdir4(paths.hooks);
9747
9776
  hookCount = entries.filter((e) => e.startsWith("on")).length;
9748
9777
  } catch {}
9749
9778
  emitOutput({
@@ -9836,7 +9865,7 @@ async function detectMode(root) {
9836
9865
  }
9837
9866
  let entries;
9838
9867
  try {
9839
- entries = await readdir4(root);
9868
+ entries = await readdir5(root);
9840
9869
  } catch {
9841
9870
  return "greenfield";
9842
9871
  }
@@ -9877,7 +9906,7 @@ async function execute5(projectName, mode, repair, migrate, phase) {
9877
9906
 
9878
9907
  // src/cli/commands/status.ts
9879
9908
  var import_yaml5 = __toESM(require_dist(), 1);
9880
- import { readdir as readdir5 } from "fs/promises";
9909
+ import { readdir as readdir6 } from "fs/promises";
9881
9910
  init_fs();
9882
9911
  init_integrity();
9883
9912
  async function execute6() {
@@ -9898,7 +9927,7 @@ async function execute6() {
9898
9927
  }
9899
9928
  let completedGenerations = 0;
9900
9929
  try {
9901
- const entries = await readdir5(paths.lineage);
9930
+ const entries = await readdir6(paths.lineage);
9902
9931
  completedGenerations = entries.filter((e) => e.startsWith("gen-")).length;
9903
9932
  } catch {}
9904
9933
  const hasGenome = {
@@ -9963,7 +9992,7 @@ init_fs();
9963
9992
  var import_yaml6 = __toESM(require_dist(), 1);
9964
9993
  import { createHash as createHash2 } from "crypto";
9965
9994
  import { hostname } from "os";
9966
- import { readdir as readdir6 } from "fs/promises";
9995
+ import { readdir as readdir7 } from "fs/promises";
9967
9996
 
9968
9997
  // src/core/nonce.ts
9969
9998
  import { createHash, randomBytes } from "crypto";
@@ -10042,7 +10071,7 @@ class GenerationManager {
10042
10071
  }
10043
10072
  async countLineage() {
10044
10073
  try {
10045
- const entries = await readdir6(this.paths.lineage);
10074
+ const entries = await readdir7(this.paths.lineage);
10046
10075
  return entries.filter((e) => e.startsWith("gen-")).length;
10047
10076
  } catch {
10048
10077
  return 0;
@@ -10050,7 +10079,7 @@ class GenerationManager {
10050
10079
  }
10051
10080
  async lastGenerationIds() {
10052
10081
  try {
10053
- const entries = await readdir6(this.paths.lineage);
10082
+ const entries = await readdir7(this.paths.lineage);
10054
10083
  const gens = entries.filter((e) => e.startsWith("gen-")).sort();
10055
10084
  if (gens.length === 0)
10056
10085
  return [];
@@ -10073,7 +10102,7 @@ init_fs();
10073
10102
  // src/core/hooks.ts
10074
10103
  init_fs();
10075
10104
  var import_yaml7 = __toESM(require_dist(), 1);
10076
- import { readdir as readdir7 } from "fs/promises";
10105
+ import { readdir as readdir8 } from "fs/promises";
10077
10106
  import { join as join7 } from "path";
10078
10107
  import { execSync as execSync4 } from "child_process";
10079
10108
  async function executeHooks(hooksDir, event, projectRoot) {
@@ -10105,7 +10134,7 @@ async function executeHooks(hooksDir, event, projectRoot) {
10105
10134
  async function scanHooks(hooksDir, event) {
10106
10135
  let entries;
10107
10136
  try {
10108
- entries = await readdir7(hooksDir);
10137
+ entries = await readdir8(hooksDir);
10109
10138
  } catch {
10110
10139
  return [];
10111
10140
  }
@@ -10214,12 +10243,12 @@ async function executeMdHook(hook, event, hooksDir) {
10214
10243
 
10215
10244
  // src/core/backlog.ts
10216
10245
  init_fs();
10217
- import { readdir as readdir8 } from "fs/promises";
10246
+ import { readdir as readdir9 } from "fs/promises";
10218
10247
  import { join as join8 } from "path";
10219
10248
  async function scanBacklog(backlogDir) {
10220
10249
  let entries;
10221
10250
  try {
10222
- entries = await readdir8(backlogDir);
10251
+ entries = await readdir9(backlogDir);
10223
10252
  } catch {
10224
10253
  return [];
10225
10254
  }
@@ -10422,7 +10451,7 @@ Then run: reap run start --phase create --goal "<goal>" [--backlog <filename>]`
10422
10451
 
10423
10452
  // src/cli/commands/run/learning.ts
10424
10453
  init_fs();
10425
- import { readdir as readdir9 } from "fs/promises";
10454
+ import { readdir as readdir10 } from "fs/promises";
10426
10455
  import { join as join11 } from "path";
10427
10456
 
10428
10457
  // src/core/lifecycle.ts
@@ -10590,7 +10619,7 @@ async function performMergeTransition(state, gm, paths) {
10590
10619
  init_fs();
10591
10620
  import { join as join10, dirname as dirname4 } from "path";
10592
10621
  import { fileURLToPath as fileURLToPath3 } from "url";
10593
- import { copyFile } from "fs/promises";
10622
+ import { copyFile as copyFile2 } from "fs/promises";
10594
10623
  var STAGE_ARTIFACTS2 = {
10595
10624
  learning: "01-learning.md",
10596
10625
  planning: "02-planning.md",
@@ -10620,7 +10649,7 @@ async function copyArtifactTemplate(stage, artifactPath, isMerge) {
10620
10649
  if (!await fileExists(templatePath))
10621
10650
  return;
10622
10651
  await ensureDir(dirname4(destPath));
10623
- await copyFile(templatePath, destPath);
10652
+ await copyFile2(templatePath, destPath);
10624
10653
  }
10625
10654
 
10626
10655
  // src/cli/commands/run/learning.ts
@@ -10648,7 +10677,7 @@ async function execute8(paths, phase) {
10648
10677
  let prevCompletion = null;
10649
10678
  let prevFitness = null;
10650
10679
  try {
10651
- const lineageEntries = await readdir9(paths.lineage);
10680
+ const lineageEntries = await readdir10(paths.lineage);
10652
10681
  const genDirs = lineageEntries.filter((e) => e.startsWith("gen-")).sort();
10653
10682
  if (genDirs.length > 0) {
10654
10683
  const lastGen = genDirs[genDirs.length - 1];
@@ -11065,12 +11094,12 @@ init_fs();
11065
11094
  init_fs();
11066
11095
  var import_yaml9 = __toESM(require_dist(), 1);
11067
11096
  import { join as join13 } from "path";
11068
- import { readdir as readdir11, rm as rm4, unlink } from "fs/promises";
11097
+ import { readdir as readdir12, rm as rm4, unlink } from "fs/promises";
11069
11098
 
11070
11099
  // src/core/compression.ts
11071
11100
  init_fs();
11072
11101
  var import_yaml8 = __toESM(require_dist(), 1);
11073
- import { readdir as readdir10, rm as rm3 } from "fs/promises";
11102
+ import { readdir as readdir11, rm as rm3 } from "fs/promises";
11074
11103
  import { join as join12 } from "path";
11075
11104
  var LEVEL1_THRESHOLD = 20;
11076
11105
  var PROTECTED_RECENT = 20;
@@ -11078,7 +11107,7 @@ var LEVEL2_THRESHOLD = 100;
11078
11107
  async function compressLineage(lineageDir) {
11079
11108
  let entries;
11080
11109
  try {
11081
- entries = await readdir10(lineageDir);
11110
+ entries = await readdir11(lineageDir);
11082
11111
  } catch {
11083
11112
  return 0;
11084
11113
  }
@@ -11132,7 +11161,7 @@ async function compressLineage(lineageDir) {
11132
11161
  async function compressToEpoch(lineageDir) {
11133
11162
  let entries;
11134
11163
  try {
11135
- entries = await readdir10(lineageDir);
11164
+ entries = await readdir11(lineageDir);
11136
11165
  } catch {
11137
11166
  return 0;
11138
11167
  }
@@ -11237,7 +11266,7 @@ async function archiveGeneration(paths, state, fitnessFeedback) {
11237
11266
  const goalSlug = state.goal.toLowerCase().replace(/[^a-z0-9가-힣]+/g, "-").slice(0, 40).replace(/-+$/, "");
11238
11267
  const archiveDir = join13(paths.lineage, `${state.id}-${goalSlug}`);
11239
11268
  await ensureDir(archiveDir);
11240
- const lifeEntries = await readdir11(paths.life);
11269
+ const lifeEntries = await readdir12(paths.life);
11241
11270
  for (const entry of lifeEntries) {
11242
11271
  if (entry === "current.yml" || entry === "backlog")
11243
11272
  continue;
@@ -11986,7 +12015,7 @@ async function execute12(paths, phase, feedback) {
11986
12015
 
11987
12016
  // src/cli/commands/run/evolve.ts
11988
12017
  var import_yaml12 = __toESM(require_dist(), 1);
11989
- import { readdir as readdir12 } from "fs/promises";
12018
+ import { readdir as readdir13 } from "fs/promises";
11990
12019
  init_fs();
11991
12020
 
11992
12021
  // src/core/prompt.ts
@@ -12245,7 +12274,7 @@ async function collectClarityInput(paths, generationType) {
12245
12274
  const highPriorityBacklog = pendingItems.filter((b) => b.priority === "high").length;
12246
12275
  let lineageCount = 0;
12247
12276
  try {
12248
- const entries = await readdir12(paths.lineage);
12277
+ const entries = await readdir13(paths.lineage);
12249
12278
  lineageCount = entries.filter((e) => e.endsWith(".md")).length;
12250
12279
  } catch {}
12251
12280
  const [hasShortterm, hasMidterm, hasLongterm] = await Promise.all([
@@ -12392,7 +12421,7 @@ async function execute15(paths) {
12392
12421
  }
12393
12422
 
12394
12423
  // src/cli/commands/run/abort.ts
12395
- import { readdir as readdir13, rm as rm5 } from "fs/promises";
12424
+ import { readdir as readdir14, rm as rm5 } from "fs/promises";
12396
12425
  import { join as join14 } from "path";
12397
12426
  init_fs();
12398
12427
  function parseExtra(extra) {
@@ -12464,7 +12493,7 @@ createdAt: ${new Date().toISOString()}
12464
12493
  savedBacklogFile = filename;
12465
12494
  }
12466
12495
  const revertedCount = await revertBacklogConsumed(paths.backlog, id);
12467
- const lifeEntries = await readdir13(paths.life);
12496
+ const lifeEntries = await readdir14(paths.life);
12468
12497
  for (const entry of lifeEntries) {
12469
12498
  if (entry === "backlog")
12470
12499
  continue;
@@ -13339,32 +13368,114 @@ async function execute25(stage, options) {
13339
13368
  }
13340
13369
  }
13341
13370
 
13342
- // src/cli/commands/make.ts
13371
+ // src/cli/commands/make/index.ts
13343
13372
  init_integrity();
13373
+
13374
+ // src/cli/commands/make/backlog.ts
13375
+ async function makeBacklog(paths, options) {
13376
+ if (!options.type || !options.title) {
13377
+ emitError("make", 'Usage: reap make backlog --type <type> --title "<title>" [--body "<body>"] [--priority <priority>]');
13378
+ }
13379
+ const filename = await createBacklog(paths.backlog, {
13380
+ type: options.type,
13381
+ title: options.title,
13382
+ body: options.body,
13383
+ priority: options.priority
13384
+ });
13385
+ emitOutput({
13386
+ status: "ok",
13387
+ command: "make",
13388
+ context: { resource: "backlog", filename },
13389
+ message: `Backlog item created: ${filename}`,
13390
+ prompt: `The backlog file has been created with template sections (Problem, Solution, Files to Change). You MUST now use the Edit tool to fill in these sections with concrete content. Do not leave <!-- --> placeholders.`
13391
+ });
13392
+ }
13393
+
13394
+ // src/cli/commands/make/hook.ts
13395
+ import { join as join15 } from "path";
13396
+ import { chmod as chmod2 } from "fs/promises";
13397
+ init_fs();
13398
+ var VALID_EVENTS = [
13399
+ "onLifeStarted",
13400
+ "onLifeLearned",
13401
+ "onLifePlanned",
13402
+ "onLifeImplemented",
13403
+ "onLifeValidated",
13404
+ "onLifeCompleted",
13405
+ "onLifeTransited",
13406
+ "onMergeStarted",
13407
+ "onMergeDetected",
13408
+ "onMergeMated",
13409
+ "onMergeMerged",
13410
+ "onMergeReconciled",
13411
+ "onMergeValidated",
13412
+ "onMergeCompleted",
13413
+ "onMergeTransited"
13414
+ ];
13415
+ async function makeHook(paths, options) {
13416
+ const event = options.event;
13417
+ const name = options.name;
13418
+ const type = options.type ?? "md";
13419
+ const condition = options.condition ?? "always";
13420
+ const order = parseInt(options.order ?? "50", 10);
13421
+ if (!event || !VALID_EVENTS.includes(event)) {
13422
+ emitError("make", `Invalid or missing --event. Valid events:
13423
+ ${VALID_EVENTS.join(`
13424
+ `)}`);
13425
+ }
13426
+ if (!name || !/^[a-zA-Z0-9_-]+$/.test(name)) {
13427
+ emitError("make", "Invalid or missing --name. Use alphanumeric, dash, or underscore only.");
13428
+ }
13429
+ if (type !== "sh" && type !== "md") {
13430
+ emitError("make", "Invalid --type. Use 'sh' or 'md'.");
13431
+ }
13432
+ const filename = `${event}.${name}.${type}`;
13433
+ const filePath = join15(paths.hooks, filename);
13434
+ await ensureDir(paths.hooks);
13435
+ if (await fileExists(filePath)) {
13436
+ emitError("make", `Hook already exists: ${filename}`);
13437
+ }
13438
+ const content = type === "sh" ? `#!/usr/bin/env bash
13439
+ # condition: ${condition}
13440
+ # order: ${order}
13441
+
13442
+ # TODO: Add your hook logic here
13443
+ echo "${event}.${name} executed"
13444
+ ` : `---
13445
+ condition: ${condition}
13446
+ order: ${order}
13447
+ ---
13448
+
13449
+ <!-- TODO: Add your hook prompt here -->
13450
+ <!-- This prompt will be executed by the AI agent when the ${event} event fires. -->
13451
+ `;
13452
+ await writeTextFile(filePath, content);
13453
+ if (type === "sh") {
13454
+ await chmod2(filePath, 493);
13455
+ }
13456
+ const prompt = type === "sh" ? `Hook file created: ${filename}. You MUST now use the Edit tool to replace the TODO placeholder with the actual shell commands this hook should execute.` : `Hook file created: ${filename}. You MUST now use the Edit tool to replace the TODO placeholder with the actual AI prompt instructions this hook should execute when the ${event} event fires.`;
13457
+ emitOutput({
13458
+ status: "ok",
13459
+ command: "make",
13460
+ context: { resource: "hook", filename, event, name, type, condition, order },
13461
+ message: `Hook created: ${filename}`,
13462
+ prompt
13463
+ });
13464
+ }
13465
+
13466
+ // src/cli/commands/make/index.ts
13467
+ var RESOURCES = ["backlog", "hook"];
13344
13468
  async function execute26(resource, options) {
13345
13469
  const paths = createPaths(process.cwd());
13346
13470
  if (await detectV15(paths)) {
13347
13471
  emitError("make", "This project uses REAP v0.15 structure. Run '/reap.update' to upgrade to v0.16.");
13348
13472
  }
13349
13473
  if (resource === "backlog") {
13350
- if (!options.type || !options.title) {
13351
- emitError("make", 'Usage: reap make backlog --type <type> --title "<title>" [--body "<body>"] [--priority <priority>]');
13352
- }
13353
- const filename = await createBacklog(paths.backlog, {
13354
- type: options.type,
13355
- title: options.title,
13356
- body: options.body,
13357
- priority: options.priority
13358
- });
13359
- emitOutput({
13360
- status: "ok",
13361
- command: "make",
13362
- context: { resource: "backlog", filename },
13363
- message: `Backlog item created: ${filename}`,
13364
- prompt: `The backlog file has been created with template sections (Problem, Solution, Files to Change). You MUST now use the Edit tool to fill in these sections with concrete content. Do not leave <!-- --> placeholders.`
13365
- });
13474
+ await makeBacklog(paths, options);
13475
+ } else if (resource === "hook") {
13476
+ await makeHook(paths, options);
13366
13477
  } else {
13367
- emitError("make", `Unknown resource '${resource}'. Available: backlog`);
13478
+ emitError("make", `Unknown resource '${resource}'. Available: ${RESOURCES.join(", ")}`);
13368
13479
  }
13369
13480
  }
13370
13481
 
@@ -13390,30 +13501,30 @@ async function execute27(count) {
13390
13501
 
13391
13502
  // src/adapters/claude-code/install.ts
13392
13503
  init_fs();
13393
- import { readdir as readdir14, cp as cp2, unlink as unlink2, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
13394
- import { join as join15, dirname as dirname5 } from "path";
13504
+ import { readdir as readdir15, cp as cp2, unlink as unlink2, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
13505
+ import { join as join16, dirname as dirname5 } from "path";
13395
13506
  import { fileURLToPath as fileURLToPath4 } from "url";
13396
13507
  import { homedir as homedir3 } from "os";
13397
13508
  var __dirname2 = dirname5(fileURLToPath4(import.meta.url));
13398
- var SKILLS_DIR = __dirname2.includes("dist") ? join15(__dirname2, "..", "adapters", "claude-code", "skills") : join15(__dirname2, "skills");
13509
+ var SKILLS_DIR = __dirname2.includes("dist") ? join16(__dirname2, "..", "adapters", "claude-code", "skills") : join16(__dirname2, "skills");
13399
13510
  var SKILL_PATTERN = /^reap\..+\.md$/;
13400
13511
  async function cleanupStaleSkills(targetDir) {
13401
- const files = await readdir14(targetDir);
13512
+ const files = await readdir15(targetDir);
13402
13513
  const staleFiles = files.filter((f) => SKILL_PATTERN.test(f));
13403
13514
  for (const file of staleFiles) {
13404
- await unlink2(join15(targetDir, file));
13515
+ await unlink2(join16(targetDir, file));
13405
13516
  }
13406
13517
  return staleFiles;
13407
13518
  }
13408
13519
  async function installSkills(_projectRoot) {
13409
- const targetDir = join15(homedir3(), ".claude", "commands");
13520
+ const targetDir = join16(homedir3(), ".claude", "commands");
13410
13521
  await ensureDir(targetDir);
13411
13522
  const cleaned = await cleanupStaleSkills(targetDir);
13412
- const files = await readdir14(SKILLS_DIR);
13523
+ const files = await readdir15(SKILLS_DIR);
13413
13524
  const mdFiles = files.filter((f) => f.endsWith(".md"));
13414
13525
  let installed = 0;
13415
13526
  for (const file of mdFiles) {
13416
- await cp2(join15(SKILLS_DIR, file), join15(targetDir, file));
13527
+ await cp2(join16(SKILLS_DIR, file), join16(targetDir, file));
13417
13528
  installed++;
13418
13529
  }
13419
13530
  await installReapGuide();
@@ -13433,29 +13544,29 @@ async function installSkills(_projectRoot) {
13433
13544
  });
13434
13545
  }
13435
13546
  async function installAgents() {
13436
- const agentsDir = join15(homedir3(), ".claude", "agents");
13547
+ const agentsDir = join16(homedir3(), ".claude", "agents");
13437
13548
  await ensureDir(agentsDir);
13438
- const templateDir = __dirname2.includes("dist") ? join15(__dirname2, "..", "templates", "agents") : join15(__dirname2, "..", "..", "templates", "agents");
13549
+ const templateDir = __dirname2.includes("dist") ? join16(__dirname2, "..", "templates", "agents") : join16(__dirname2, "..", "..", "templates", "agents");
13439
13550
  try {
13440
- const files = await readdir14(templateDir);
13551
+ const files = await readdir15(templateDir);
13441
13552
  for (const file of files) {
13442
13553
  if (file.endsWith(".md")) {
13443
- await cp2(join15(templateDir, file), join15(agentsDir, file));
13554
+ await cp2(join16(templateDir, file), join16(agentsDir, file));
13444
13555
  }
13445
13556
  }
13446
13557
  } catch {}
13447
13558
  }
13448
13559
  async function installReapGuide() {
13449
- const reapHome = join15(homedir3(), ".reap");
13560
+ const reapHome = join16(homedir3(), ".reap");
13450
13561
  await ensureDir(reapHome);
13451
- const templateDir = __dirname2.includes("dist") ? join15(__dirname2, "..", "templates") : join15(__dirname2, "..", "..", "templates");
13452
- const src = join15(templateDir, "reap-guide.md");
13562
+ const templateDir = __dirname2.includes("dist") ? join16(__dirname2, "..", "templates") : join16(__dirname2, "..", "..", "templates");
13563
+ const src = join16(templateDir, "reap-guide.md");
13453
13564
  if (await fileExists(src)) {
13454
- await cp2(src, join15(reapHome, "reap-guide.md"));
13565
+ await cp2(src, join16(reapHome, "reap-guide.md"));
13455
13566
  }
13456
13567
  }
13457
13568
  async function registerCleanupHook() {
13458
- const settingsPath = join15(homedir3(), ".claude", "settings.json");
13569
+ const settingsPath = join16(homedir3(), ".claude", "settings.json");
13459
13570
  const hookCommand = "reap check-version 2>/dev/null || true";
13460
13571
  try {
13461
13572
  let settings = {};
@@ -13493,7 +13604,7 @@ async function execute28() {
13493
13604
  // src/cli/commands/fix.ts
13494
13605
  var import_yaml16 = __toESM(require_dist(), 1);
13495
13606
  import { mkdir as mkdir3, stat as stat3 } from "fs/promises";
13496
- import { join as join16, dirname as dirname6 } from "path";
13607
+ import { join as join17, dirname as dirname6 } from "path";
13497
13608
  import { fileURLToPath as fileURLToPath5 } from "url";
13498
13609
  import { homedir as homedir4 } from "os";
13499
13610
  init_fs();
@@ -13575,13 +13686,13 @@ async function fixProject(projectRoot) {
13575
13686
  issues.push(`genome/${gf.name} is missing. Run 'reap init --repair' to restore.`);
13576
13687
  }
13577
13688
  }
13578
- const guidePath = join16(homedir4(), ".reap", "reap-guide.md");
13689
+ const guidePath = join17(homedir4(), ".reap", "reap-guide.md");
13579
13690
  if (!await fileExists(guidePath)) {
13580
13691
  const __dir = dirname6(fileURLToPath5(import.meta.url));
13581
- const srcGuide = await readTextFile(join16(__dir, "..", "templates", "reap-guide.md"));
13692
+ const srcGuide = await readTextFile(join17(__dir, "..", "templates", "reap-guide.md"));
13582
13693
  if (srcGuide) {
13583
13694
  const { ensureDir: ensDir } = await Promise.resolve().then(() => (init_fs(), exports_fs));
13584
- await ensDir(join16(homedir4(), ".reap"));
13695
+ await ensDir(join17(homedir4(), ".reap"));
13585
13696
  await writeTextFile(guidePath, srcGuide);
13586
13697
  fixed.push("Restored missing ~/.reap/reap-guide.md");
13587
13698
  } else {
@@ -13607,7 +13718,7 @@ async function fixProject(projectRoot) {
13607
13718
  fixed.push(`Created missing vision/memory/${mf.name}`);
13608
13719
  }
13609
13720
  }
13610
- const claudeMdPath = join16(paths.root, "CLAUDE.md");
13721
+ const claudeMdPath = join17(paths.root, "CLAUDE.md");
13611
13722
  const claudeMd = await readTextFile(claudeMdPath);
13612
13723
  if (!claudeMd || !claudeMd.includes(".reap/genome/")) {
13613
13724
  const { ensureClaudeMd: ensureClaudeMd2 } = await Promise.resolve().then(() => (init_common(), exports_common));
@@ -13663,7 +13774,7 @@ async function execute29(check) {
13663
13774
  // src/cli/commands/destroy.ts
13664
13775
  var import_yaml17 = __toESM(require_dist(), 1);
13665
13776
  import { rm as rm6 } from "fs/promises";
13666
- import { join as join17 } from "path";
13777
+ import { join as join18 } from "path";
13667
13778
  init_fs();
13668
13779
  init_integrity();
13669
13780
  async function getProjectName(projectRoot) {
@@ -13681,7 +13792,7 @@ async function getProjectName(projectRoot) {
13681
13792
  async function destroyProject(projectRoot) {
13682
13793
  const removed = [];
13683
13794
  const skipped = [];
13684
- const reapDir = join17(projectRoot, ".reap");
13795
+ const reapDir = join18(projectRoot, ".reap");
13685
13796
  if (await fileExists(reapDir)) {
13686
13797
  await rm6(reapDir, { recursive: true, force: true });
13687
13798
  removed.push(".reap/");
@@ -13693,7 +13804,7 @@ async function destroyProject(projectRoot) {
13693
13804
  return { removed, skipped };
13694
13805
  }
13695
13806
  async function cleanClaudeMd(projectRoot, removed, skipped) {
13696
- const claudeMdPath = join17(projectRoot, "CLAUDE.md");
13807
+ const claudeMdPath = join18(projectRoot, "CLAUDE.md");
13697
13808
  const content = await readTextFile(claudeMdPath);
13698
13809
  if (content === null) {
13699
13810
  skipped.push("CLAUDE.md (not found)");
@@ -13718,7 +13829,7 @@ async function cleanClaudeMd(projectRoot, removed, skipped) {
13718
13829
  }
13719
13830
  }
13720
13831
  async function cleanGitignore(projectRoot, removed, skipped) {
13721
- const gitignorePath = join17(projectRoot, ".gitignore");
13832
+ const gitignorePath = join18(projectRoot, ".gitignore");
13722
13833
  const content = await readTextFile(gitignorePath);
13723
13834
  if (content === null) {
13724
13835
  skipped.push(".gitignore (not found)");
@@ -13782,8 +13893,8 @@ async function execute30(confirm) {
13782
13893
  }
13783
13894
 
13784
13895
  // src/cli/commands/clean.ts
13785
- import { rm as rm7, readdir as readdir15, mkdir as mkdir4 } from "fs/promises";
13786
- import { join as join18 } from "path";
13896
+ import { rm as rm7, readdir as readdir16, mkdir as mkdir4 } from "fs/promises";
13897
+ import { join as join19 } from "path";
13787
13898
  init_fs();
13788
13899
  init_integrity();
13789
13900
  async function cleanProject(projectRoot, options) {
@@ -13810,7 +13921,7 @@ async function cleanLineage(lineageDir, mode, actions) {
13810
13921
  }
13811
13922
  let entries;
13812
13923
  try {
13813
- entries = await readdir15(lineageDir);
13924
+ entries = await readdir16(lineageDir);
13814
13925
  } catch {
13815
13926
  actions.push("Lineage: read failed (skip)");
13816
13927
  return;
@@ -13822,7 +13933,7 @@ async function cleanLineage(lineageDir, mode, actions) {
13822
13933
  }
13823
13934
  if (mode === "delete") {
13824
13935
  for (const entry of entries) {
13825
- await rm7(join18(lineageDir, entry), { recursive: true, force: true });
13936
+ await rm7(join19(lineageDir, entry), { recursive: true, force: true });
13826
13937
  }
13827
13938
  actions.push(`Lineage: deleted ${entries.length} item(s)`);
13828
13939
  } else {
@@ -13838,9 +13949,9 @@ async function cleanLineage(lineageDir, mode, actions) {
13838
13949
  ].join(`
13839
13950
  `);
13840
13951
  for (const dir of genDirs) {
13841
- await rm7(join18(lineageDir, dir), { recursive: true, force: true });
13952
+ await rm7(join19(lineageDir, dir), { recursive: true, force: true });
13842
13953
  }
13843
- await writeTextFile(join18(lineageDir, `${epochId}.md`), summary);
13954
+ await writeTextFile(join19(lineageDir, `${epochId}.md`), summary);
13844
13955
  actions.push(`Lineage: compressed ${genDirs.length} generation(s) into ${epochId}`);
13845
13956
  }
13846
13957
  }
@@ -13851,7 +13962,7 @@ async function cleanLife(lifeDir, actions) {
13851
13962
  }
13852
13963
  let entries;
13853
13964
  try {
13854
- entries = await readdir15(lifeDir);
13965
+ entries = await readdir16(lifeDir);
13855
13966
  } catch {
13856
13967
  actions.push("Life: read failed (skip)");
13857
13968
  return;
@@ -13860,7 +13971,7 @@ async function cleanLife(lifeDir, actions) {
13860
13971
  for (const entry of entries) {
13861
13972
  if (entry === "backlog")
13862
13973
  continue;
13863
- await rm7(join18(lifeDir, entry), { recursive: true, force: true });
13974
+ await rm7(join19(lifeDir, entry), { recursive: true, force: true });
13864
13975
  removedCount++;
13865
13976
  }
13866
13977
  actions.push(`Life: cleaned ${removedCount} file(s)`);
@@ -13923,11 +14034,11 @@ init_integrity();
13923
14034
  var import_yaml18 = __toESM(require_dist(), 1);
13924
14035
  import { execSync as execSync6 } from "child_process";
13925
14036
  import { readFileSync as readFileSync2 } from "fs";
13926
- import { join as join20 } from "path";
14037
+ import { join as join21 } from "path";
13927
14038
 
13928
14039
  // src/core/notice.ts
13929
14040
  import { readFileSync } from "fs";
13930
- import { join as join19, dirname as dirname7 } from "path";
14041
+ import { join as join20, dirname as dirname7 } from "path";
13931
14042
  function findPackageRoot() {
13932
14043
  try {
13933
14044
  const pkgPath = __require.resolve("@c-d-cc/reap/package.json");
@@ -13948,7 +14059,7 @@ var LANG_MAP = {
13948
14059
  };
13949
14060
  function fetchReleaseNotice(version, language) {
13950
14061
  try {
13951
- const noticePath = join19(findPackageRoot(), "RELEASE_NOTICE.md");
14062
+ const noticePath = join20(findPackageRoot(), "RELEASE_NOTICE.md");
13952
14063
  const content = readFileSync(noticePath, "utf-8");
13953
14064
  const versionTag = version.startsWith("v") ? version : `v${version}`;
13954
14065
  const versionPattern = new RegExp(`^## ${versionTag.replace(/\./g, "\\.")}\\s*$`, "m");
@@ -14100,7 +14211,7 @@ async function execute32() {
14100
14211
  const result = performAutoUpdate(root);
14101
14212
  if (result.action === "upgraded" && result.to) {
14102
14213
  try {
14103
- const configPath = join20(root, ".reap", "config.yml");
14214
+ const configPath = join21(root, ".reap", "config.yml");
14104
14215
  const configContent = readFileSync2(configPath, "utf-8");
14105
14216
  const config = import_yaml18.default.parse(configContent);
14106
14217
  const language = config?.language ?? "english";
@@ -14149,7 +14260,7 @@ async function execute33() {
14149
14260
  // src/cli/commands/update.ts
14150
14261
  var import_yaml20 = __toESM(require_dist(), 1);
14151
14262
  import { readFileSync as readFileSync3 } from "fs";
14152
- import { join as join21, dirname as dirname8 } from "path";
14263
+ import { join as join22, dirname as dirname8 } from "path";
14153
14264
  import { fileURLToPath as fileURLToPath6 } from "url";
14154
14265
  init_fs();
14155
14266
  init_integrity();
@@ -14157,7 +14268,7 @@ init_common();
14157
14268
  function getPackageVersion() {
14158
14269
  try {
14159
14270
  const __dir = dirname8(fileURLToPath6(import.meta.url));
14160
- for (const rel of [join21(__dir, "..", "..", "package.json"), join21(__dir, "..", "package.json")]) {
14271
+ for (const rel of [join22(__dir, "..", "..", "package.json"), join22(__dir, "..", "package.json")]) {
14161
14272
  try {
14162
14273
  return JSON.parse(readFileSync3(rel, "utf-8")).version;
14163
14274
  } catch {}
@@ -14185,7 +14296,7 @@ function getRequiredDirs(paths) {
14185
14296
  paths.backlog,
14186
14297
  paths.lineage,
14187
14298
  paths.vision,
14188
- paths.visionDocs,
14299
+ paths.visionDesign,
14189
14300
  paths.memory,
14190
14301
  paths.hooks
14191
14302
  ];
@@ -14305,7 +14416,7 @@ async function execute34(phase, postUpgrade) {
14305
14416
  }
14306
14417
 
14307
14418
  // src/cli/commands/help.ts
14308
- import { join as join22 } from "path";
14419
+ import { join as join23 } from "path";
14309
14420
  init_fs();
14310
14421
  var SUPPORTED_LANGUAGES = ["en", "ko", "ja", "zh-CN"];
14311
14422
  var LANGUAGE_ALIASES = {
@@ -14477,7 +14588,7 @@ async function execute35(topic) {
14477
14588
  const stateDisplay = buildStateDisplay(state, lang);
14478
14589
  const lines = buildHelpLines(lang, stateDisplay);
14479
14590
  if (topic) {
14480
- const reapGuidePath = join22(paths.reap, "reap-guide.md");
14591
+ const reapGuidePath = join23(paths.reap, "reap-guide.md");
14481
14592
  const reapGuide = await readTextFile(reapGuidePath) ?? "";
14482
14593
  emitOutput({
14483
14594
  status: "prompt",
@@ -14523,14 +14634,14 @@ async function execute35(topic) {
14523
14634
  function readVersion() {
14524
14635
  const __dir = dirname9(fileURLToPath7(import.meta.url));
14525
14636
  let version = "0.0.0";
14526
- for (const rel of [join23(__dir, "..", "..", "package.json"), join23(__dir, "..", "package.json")]) {
14637
+ for (const rel of [join24(__dir, "..", "..", "package.json"), join24(__dir, "..", "package.json")]) {
14527
14638
  try {
14528
14639
  version = JSON.parse(readFileSync4(rel, "utf-8")).version;
14529
14640
  break;
14530
14641
  } catch {}
14531
14642
  }
14532
14643
  try {
14533
- const hash = readFileSync4(join23(__dir, "..", ".dev-build"), "utf-8").trim();
14644
+ const hash = readFileSync4(join24(__dir, "..", ".dev-build"), "utf-8").trim();
14534
14645
  if (hash)
14535
14646
  version += `+dev.${hash}`;
14536
14647
  } catch {}
@@ -14547,7 +14658,7 @@ program2.command("status").description("Show current project status").action(asy
14547
14658
  program2.command("run <stage>").description("Run a lifecycle stage (start, learning, planning, ...)").option("--phase <phase>", "Stage phase (work, complete, reflect, fitness, adapt, commit)").option("--goal <goal>", "Goal for start command").option("--type <type>", "Generation type (embryo, normal, merge)").option("--parents <parents>", "Parent generation IDs for merge (comma-separated)").option("--feedback <feedback>", "Fitness feedback text").option("--reason <reason>", "Reason for back regression or abort").option("--backlog <backlog>", "Backlog filename to consume for this generation").option("--source-action <sourceAction>", "Source action for abort (rollback, stash, hold, none)").option("--save-backlog", "Save progress to backlog on abort").action(async (stage, options) => {
14548
14659
  await execute25(stage, options);
14549
14660
  });
14550
- program2.command("make <resource>").description("Create a resource from template (backlog)").option("--type <type>", "Backlog type (genome-change, environment-change, task)").option("--title <title>", "Resource title").option("--body <body>", "Optional description body").option("--priority <priority>", "Priority (high, medium, low)").action(async (resource, options) => {
14661
+ program2.command("make <resource>").description("Create a resource from template (backlog, hook)").option("--type <type>", "Resource type (backlog: genome-change/environment-change/task, hook: sh/md)").option("--title <title>", "Resource title").option("--body <body>", "Optional description body").option("--priority <priority>", "Priority (high, medium, low)").option("--event <event>", "Hook event (e.g. onLifeCompleted)").option("--name <name>", "Hook name").option("--condition <condition>", "Hook condition (default: always)").option("--order <order>", "Hook execution order (default: 50)").action(async (resource, options) => {
14551
14662
  await execute26(resource, options);
14552
14663
  });
14553
14664
  program2.command("cruise <count>").description("Enable cruise mode for N generations").action(async (count) => {
@@ -84,11 +84,20 @@ Decision rule: "If a new agent in the next session doesn't know about this chang
84
84
 
85
85
  ## Vision
86
86
 
87
- Vision consists of Goals and Memory.
87
+ Vision consists of Goals, Memory, and Design.
88
88
 
89
89
  ### Goals (`vision/goals.md`)
90
90
  Long-term project objectives. During the adapt phase, gap analysis against goals determines the next generation's direction.
91
91
 
92
+ Goals cleanup: goals.md is a space for **future** objectives, not an archive of past achievements. When completed items (`[x]`) accumulate and the document loses focus as a forward-looking plan, propose specific items for removal to the human for approval. This is a contextual judgment — recently completed items may still have reference value, while long-stable items can be cleared. Always get human confirmation before removing.
93
+
94
+ ### Design (`vision/design/`)
95
+ Space for project design documents. Distinction from Memory:
96
+ - **Design** — Documents with a specific scope (architecture designs, feature specs, etc.). Managed as independent documents.
97
+ - **Memory** — General-purpose context records (lessons, progress, handoff). Single file per tier.
98
+
99
+ Decision rule: "Is this content worth documenting as an independent topic?" → Yes = Design, No = Memory.
100
+
92
101
  ### Memory (`vision/memory/`)
93
102
  Free-form space for the AI to record project-related knowledge. 3-tier structure:
94
103
  - **longterm.md** — Project lifetime. Recurring lessons, decision backgrounds, architecture rationale
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+ # Always true — hook always executes
3
+ exit 0
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+ # True if src/ files were changed in the most recent commit
3
+ # Exit 0 = condition met, Exit 1 = condition not met
4
+ last_commit=$(git log -1 --format="%H" 2>/dev/null)
5
+ if [ -z "$last_commit" ]; then
6
+ exit 1
7
+ fi
8
+ changes=$(git diff-tree --no-commit-id --name-only -r "$last_commit" -- src/ 2>/dev/null)
9
+ if [ -n "$changes" ]; then
10
+ exit 0
11
+ else
12
+ exit 1
13
+ fi
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env bash
2
+ # True if package.json version differs from the last git tag
3
+ # Exit 0 = version was bumped, Exit 1 = same version
4
+ last_tag=$(git describe --tags --abbrev=0 2>/dev/null)
5
+ if [ -z "$last_tag" ]; then
6
+ exit 1
7
+ fi
8
+ tag_version="${last_tag#v}"
9
+ pkg_version=$(node -e "console.log(require('./package.json').version)" 2>/dev/null)
10
+ if [ -z "$pkg_version" ]; then
11
+ exit 1
12
+ fi
13
+ if [ "$tag_version" != "$pkg_version" ]; then
14
+ exit 0
15
+ else
16
+ exit 1
17
+ fi
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env bash
2
+ # condition: always
3
+ # order: 90
4
+ #
5
+ # Example: Send a notification when a generation completes.
6
+ # Rename this file to remove .example suffix to activate.
7
+ #
8
+ # onCompleted.notify.sh
9
+
10
+ echo "Generation completed at $(date)"
11
+ # osascript -e 'display notification "Generation done" with title "REAP"'
@@ -0,0 +1,17 @@
1
+ ---
2
+ condition: has-code-changes
3
+ order: 50
4
+ ---
5
+
6
+ <!--
7
+ Example: AI-driven code review after generation completes.
8
+ Rename this file to remove .example suffix to activate.
9
+
10
+ Filename: onCompleted.review.md
11
+ -->
12
+
13
+ Review the changes made in this generation:
14
+
15
+ 1. Check for any code quality issues
16
+ 2. Verify test coverage for new code
17
+ 3. Report findings to the user
@@ -212,6 +212,17 @@ Merge: `onMergeStarted`, `onMergeDetected`, `onMergeMated`, `onMergeMerged`, `on
212
212
 
213
213
  Conditions are executable scripts in `.reap/hooks/conditions/`. Exit code 0 = condition met, non-zero = skip. If no condition is specified, the hook always runs (default: `always`).
214
214
 
215
+ Default conditions (installed by `reap init`):
216
+ - `always` — Always true
217
+ - `has-code-changes` — True if the last commit changed `src/`
218
+ - `version-bumped` — True if `package.json` version differs from the last git tag
219
+
220
+ ### Creating Hooks
221
+
222
+ **Always use the CLI to create hooks**: `reap make hook --event <event> --name <name> [--type md|sh] [--condition <condition>] [--order <order>]`. Never create hook files directly — the CLI ensures correct filename convention and frontmatter format.
223
+
224
+ After creating a hook, fill in the TODO placeholder with your hook logic (for `.sh`) or prompt (for `.md`).
225
+
215
226
  ## Slash Commands
216
227
 
217
228
  All REAP interactions go through `/reap.*` slash commands. These are the primary interface for both users and AI agents.
@@ -241,6 +252,7 @@ All REAP interactions go through `/reap.*` slash commands. These are the primary
241
252
 
242
253
  ## CLI Commands (no slash command equivalent)
243
254
  - `reap make backlog --type <type> --title <title> [--body <body>] [--priority <priority>]` — Create backlog item (type: genome-change, environment-change, task)
255
+ - `reap make hook --event <event> --name <name> [--type md|sh] [--condition <condition>] [--order <order>]` — Create hook file with correct naming and frontmatter
244
256
  - `reap cruise <count>` — Set cruise mode (pre-approve N generations for autonomous execution)
245
257
  - `reap update` — Update project structure to match current REAP version (v0.15 migrate, v0.16 sync)
246
258
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c-d-cc/reap",
3
- "version": "0.16.1",
3
+ "version": "0.16.3",
4
4
  "description": "Recursive Evolutionary Autonomous Pipeline — AI and humans evolve software across generations",
5
5
  "type": "module",
6
6
  "bin": {