@c-d-cc/reap 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -8918,6 +8918,9 @@ class ReapPaths {
|
|
|
8918
8918
|
static get userReapTemplates() {
|
|
8919
8919
|
return join(ReapPaths.userReapDir, "templates");
|
|
8920
8920
|
}
|
|
8921
|
+
static get userReapCommands() {
|
|
8922
|
+
return join(ReapPaths.userReapDir, "commands");
|
|
8923
|
+
}
|
|
8921
8924
|
static get packageTemplatesDir() {
|
|
8922
8925
|
const dir = dirname(fileURLToPath(import.meta.url));
|
|
8923
8926
|
const distPath = join(dir, "templates");
|
|
@@ -9045,12 +9048,22 @@ class ClaudeCodeAdapter {
|
|
|
9045
9048
|
return this.commandsDir;
|
|
9046
9049
|
}
|
|
9047
9050
|
async installCommands(commandNames, sourceDir) {
|
|
9048
|
-
await mkdir(
|
|
9051
|
+
await mkdir(ReapPaths.userReapCommands, { recursive: true });
|
|
9049
9052
|
for (const cmd of commandNames) {
|
|
9050
9053
|
const src = join2(sourceDir, `${cmd}.md`);
|
|
9051
|
-
const dest = join2(
|
|
9054
|
+
const dest = join2(ReapPaths.userReapCommands, `${cmd}.md`);
|
|
9052
9055
|
await writeTextFile(dest, await readTextFileOrThrow(src));
|
|
9053
9056
|
}
|
|
9057
|
+
await mkdir(this.commandsDir, { recursive: true });
|
|
9058
|
+
for (const cmd of commandNames) {
|
|
9059
|
+
const dest = join2(this.commandsDir, `${cmd}.md`);
|
|
9060
|
+
const redirectContent = `---
|
|
9061
|
+
description: "REAP — redirected to ~/.reap/commands/"
|
|
9062
|
+
---
|
|
9063
|
+
Read \`~/.reap/commands/${cmd}.md\` and follow the instructions there.
|
|
9064
|
+
`;
|
|
9065
|
+
await writeTextFile(dest, redirectContent);
|
|
9066
|
+
}
|
|
9054
9067
|
}
|
|
9055
9068
|
async removeStaleCommands(validNames) {
|
|
9056
9069
|
try {
|
|
@@ -9265,12 +9278,22 @@ class OpenCodeAdapter {
|
|
|
9265
9278
|
return this.commandsDir;
|
|
9266
9279
|
}
|
|
9267
9280
|
async installCommands(commandNames, sourceDir) {
|
|
9268
|
-
await mkdir2(
|
|
9281
|
+
await mkdir2(ReapPaths.userReapCommands, { recursive: true });
|
|
9269
9282
|
for (const cmd of commandNames) {
|
|
9270
9283
|
const src = join3(sourceDir, `${cmd}.md`);
|
|
9271
|
-
const dest = join3(
|
|
9284
|
+
const dest = join3(ReapPaths.userReapCommands, `${cmd}.md`);
|
|
9272
9285
|
await writeTextFile(dest, await readTextFileOrThrow(src));
|
|
9273
9286
|
}
|
|
9287
|
+
await mkdir2(this.commandsDir, { recursive: true });
|
|
9288
|
+
for (const cmd of commandNames) {
|
|
9289
|
+
const dest = join3(this.commandsDir, `${cmd}.md`);
|
|
9290
|
+
const redirectContent = `---
|
|
9291
|
+
description: "REAP — redirected to ~/.reap/commands/"
|
|
9292
|
+
---
|
|
9293
|
+
Read \`~/.reap/commands/${cmd}.md\` and follow the instructions there.
|
|
9294
|
+
`;
|
|
9295
|
+
await writeTextFile(dest, redirectContent);
|
|
9296
|
+
}
|
|
9274
9297
|
}
|
|
9275
9298
|
async removeStaleCommands(validNames) {
|
|
9276
9299
|
try {
|
|
@@ -10330,21 +10353,41 @@ async function updateProject(projectRoot, dryRun = false) {
|
|
|
10330
10353
|
const adapters = await AgentRegistry.getActiveAdapters(config ?? undefined);
|
|
10331
10354
|
const commandsDir = ReapPaths.packageCommandsDir;
|
|
10332
10355
|
const commandFiles = await readdir8(commandsDir);
|
|
10356
|
+
await mkdir6(ReapPaths.userReapCommands, { recursive: true });
|
|
10357
|
+
for (const file of commandFiles) {
|
|
10358
|
+
if (!file.endsWith(".md"))
|
|
10359
|
+
continue;
|
|
10360
|
+
const src = await readTextFileOrThrow(join9(commandsDir, file));
|
|
10361
|
+
const dest = join9(ReapPaths.userReapCommands, file);
|
|
10362
|
+
const existing = await readTextFile(dest);
|
|
10363
|
+
if (existing !== null && existing === src) {
|
|
10364
|
+
result.skipped.push(`~/.reap/commands/${file}`);
|
|
10365
|
+
} else {
|
|
10366
|
+
if (!dryRun)
|
|
10367
|
+
await writeTextFile(dest, src);
|
|
10368
|
+
result.updated.push(`~/.reap/commands/${file}`);
|
|
10369
|
+
}
|
|
10370
|
+
}
|
|
10333
10371
|
for (const adapter of adapters) {
|
|
10334
10372
|
const agentCmdDir = adapter.getCommandsDir();
|
|
10335
10373
|
const label = `${adapter.displayName}`;
|
|
10336
10374
|
for (const file of commandFiles) {
|
|
10337
10375
|
if (!file.endsWith(".md"))
|
|
10338
10376
|
continue;
|
|
10339
|
-
const
|
|
10377
|
+
const cmdName = file.replace(/\.md$/, "");
|
|
10378
|
+
const redirectContent = `---
|
|
10379
|
+
description: "REAP — redirected to ~/.reap/commands/"
|
|
10380
|
+
---
|
|
10381
|
+
Read \`~/.reap/commands/${cmdName}.md\` and follow the instructions there.
|
|
10382
|
+
`;
|
|
10340
10383
|
const dest = join9(agentCmdDir, file);
|
|
10341
10384
|
const existingContent = await readTextFile(dest);
|
|
10342
|
-
if (existingContent !== null && existingContent ===
|
|
10385
|
+
if (existingContent !== null && existingContent === redirectContent) {
|
|
10343
10386
|
result.skipped.push(`[${label}] commands/${file}`);
|
|
10344
10387
|
} else {
|
|
10345
10388
|
if (!dryRun) {
|
|
10346
10389
|
await mkdir6(agentCmdDir, { recursive: true });
|
|
10347
|
-
await writeTextFile(dest,
|
|
10390
|
+
await writeTextFile(dest, redirectContent);
|
|
10348
10391
|
}
|
|
10349
10392
|
result.updated.push(`[${label}] commands/${file}`);
|
|
10350
10393
|
}
|
|
@@ -10589,7 +10632,7 @@ async function fixProject(projectRoot) {
|
|
|
10589
10632
|
|
|
10590
10633
|
// src/cli/index.ts
|
|
10591
10634
|
import { join as join10 } from "path";
|
|
10592
|
-
program.name("reap").description("REAP — Recursive Evolutionary Autonomous Pipeline").version("0.
|
|
10635
|
+
program.name("reap").description("REAP — Recursive Evolutionary Autonomous Pipeline").version("0.7.0");
|
|
10593
10636
|
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) => {
|
|
10594
10637
|
try {
|
|
10595
10638
|
const cwd = process.cwd();
|
|
@@ -56,8 +56,14 @@ Genome(`.reap/genome/`)에 프로젝트의 설계 원칙과 규칙을 기록하
|
|
|
56
56
|
| `/reap.sync` | 현재 소스코드와 Genome 간 차이를 분석하고 동기화 |
|
|
57
57
|
| `/reap.update` | REAP 최신 버전 확인 및 업그레이드 |
|
|
58
58
|
| `/reap.help` | 도움말. `/reap.help {topic}`으로 주제별 상세 설명 |
|
|
59
|
+
| | **Collaboration** |
|
|
60
|
+
| `/reap.pull {branch}` | fetch + divergence 감지 + merge generation 자동 실행 |
|
|
61
|
+
| `/reap.push` | REAP 상태 검증 + git push |
|
|
62
|
+
| `/reap.merge {branch}` | merge generation 전체 lifecycle 실행 |
|
|
63
|
+
| `/reap.merge.start` | merge generation 생성 + detect |
|
|
64
|
+
| `/reap.merge.evolve` | merge 6단계 자율 실행 |
|
|
59
65
|
|
|
60
|
-
💡 `/reap.help {topic}` — workflow, genome, backlog, strict, agents, hooks, config, evolve, regression, author ...
|
|
66
|
+
💡 `/reap.help {topic}` — workflow, genome, backlog, strict, agents, hooks, config, evolve, regression, merge, pull, push, author ...
|
|
61
67
|
|
|
62
68
|
**Config**: Strict: {on/off} · Auto-Update: {on/off} · Language: {value}
|
|
63
69
|
|
|
@@ -82,5 +88,7 @@ For command-name topics: read `reap.{name}.md` from the same directory as this f
|
|
|
82
88
|
- **regression** — `/reap.back`: 이전 stage 회귀. timeline + artifact에 Regression 섹션 기록.
|
|
83
89
|
- **minor-fix** — 5분 이내, 설계 변경 없는 수정. stage 전환 없이 현재 artifact에 기록.
|
|
84
90
|
- **compression** — 10,000줄 + 5세대 이상 시 lineage 자동 압축. L1(40줄), L2(60줄).
|
|
91
|
+
- **merge** / **collaboration** — 분산 협업: genome-first merge 6단계 (detect→mate→merge→sync→validation→completion). `/reap.pull`로 fetch+merge, `/reap.push`로 검증+push. 상세: `domain/collaboration.md`, `domain/merge-lifecycle.md`.
|
|
85
92
|
- **author** — HyeonIL Choi. Email: hichoi@c-d.cc / Homepage: https://c-d.cc / LinkedIn: https://www.linkedin.com/in/hichoi-dev / GitHub: https://github.com/casamia918
|
|
86
93
|
- **start** / **objective** / **planning** / **implementation** / **validation** / **completion** / **next** / **back** / **sync** / **status** / **update** / **help** — Read `reap.{name}.md` from same directory, explain.
|
|
94
|
+
- **pull** / **push** / **merge.start** / **merge.detect** / **merge.mate** / **merge.merge** / **merge.sync** / **merge.validation** / **merge.completion** / **merge.evolve** — Read `reap.{name}.md` from same directory, explain.
|
|
@@ -34,6 +34,7 @@ If the target branch already includes all local work (fast-forward), skip the me
|
|
|
34
34
|
9. Check if the local latest generation is an ancestor of the remote latest generation:
|
|
35
35
|
- **If yes (fast-forward possible)**:
|
|
36
36
|
- Run `git merge --ff {branch}`
|
|
37
|
+
- Run `git submodule update --init` to sync submodules
|
|
37
38
|
- Report: "Fast-forwarded to {branch}. Local lineage now includes {remote-latest-id}. No merge generation needed."
|
|
38
39
|
- **STOP** — no merge lifecycle needed
|
|
39
40
|
- **If same generation**: "Already up to date." → **STOP**
|
|
@@ -44,7 +45,8 @@ If the target branch already includes all local work (fast-forward), skip the me
|
|
|
44
45
|
- This creates the merge generation and runs detect (01-detect.md)
|
|
45
46
|
11. Execute `/reap.merge.evolve` to run the full merge lifecycle:
|
|
46
47
|
- Detect → Mate → Merge → Sync → Validation → Completion
|
|
47
|
-
12.
|
|
48
|
+
12. Run `git submodule update --init` to sync submodules after merge
|
|
49
|
+
13. The merge generation is archived upon completion
|
|
48
50
|
|
|
49
51
|
## Completion
|
|
50
52
|
- Fast-forward: "Fast-forwarded to {branch}. No merge generation needed."
|
|
@@ -6,7 +6,7 @@ const gl = require('./genome-loader.cjs');
|
|
|
6
6
|
|
|
7
7
|
const startTime = Date.now();
|
|
8
8
|
let step = 0;
|
|
9
|
-
const totalSteps =
|
|
9
|
+
const totalSteps = 7;
|
|
10
10
|
|
|
11
11
|
function log(msg) {
|
|
12
12
|
step++;
|
|
@@ -28,6 +28,47 @@ if (!gl.dirExists(reapDir)) {
|
|
|
28
28
|
process.exit(0);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// Step 0: Install project-level command symlinks
|
|
32
|
+
const fs = require('fs');
|
|
33
|
+
const os = require('os');
|
|
34
|
+
const userReapCommands = path.join(os.homedir(), '.reap', 'commands');
|
|
35
|
+
const projectClaudeCommands = path.join(projectRoot, '.claude', 'commands');
|
|
36
|
+
|
|
37
|
+
if (gl.dirExists(userReapCommands)) {
|
|
38
|
+
try {
|
|
39
|
+
fs.mkdirSync(projectClaudeCommands, { recursive: true });
|
|
40
|
+
const cmdFiles = fs.readdirSync(userReapCommands).filter(f => f.startsWith('reap.') && f.endsWith('.md'));
|
|
41
|
+
for (const file of cmdFiles) {
|
|
42
|
+
const src = path.join(userReapCommands, file);
|
|
43
|
+
const dest = path.join(projectClaudeCommands, file);
|
|
44
|
+
try {
|
|
45
|
+
const stat = fs.lstatSync(dest);
|
|
46
|
+
if (stat.isSymbolicLink()) {
|
|
47
|
+
const target = fs.readlinkSync(dest);
|
|
48
|
+
if (target === src) continue; // already correct
|
|
49
|
+
fs.unlinkSync(dest); // stale symlink
|
|
50
|
+
} else {
|
|
51
|
+
// Regular file (old redirect or original) — replace with symlink
|
|
52
|
+
fs.unlinkSync(dest);
|
|
53
|
+
}
|
|
54
|
+
} catch { /* dest doesn't exist */ }
|
|
55
|
+
fs.symlinkSync(src, dest);
|
|
56
|
+
}
|
|
57
|
+
// Ensure .gitignore excludes these symlinks
|
|
58
|
+
const gitignorePath = path.join(projectRoot, '.gitignore');
|
|
59
|
+
const gitignoreEntry = '.claude/commands/reap.*';
|
|
60
|
+
try {
|
|
61
|
+
const gitignore = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, 'utf-8') : '';
|
|
62
|
+
if (!gitignore.includes(gitignoreEntry)) {
|
|
63
|
+
fs.appendFileSync(gitignorePath, `\n# REAP command symlinks (managed by session-start hook)\n${gitignoreEntry}\n`);
|
|
64
|
+
}
|
|
65
|
+
} catch { /* best effort */ }
|
|
66
|
+
process.stderr.write(`[REAP] Symlinked ${cmdFiles.length} commands to .claude/commands/\n`);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
process.stderr.write(`[REAP] Warning: failed to create command symlinks: ${err.message}\n`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
31
72
|
// Step 1: Version check + Auto-update
|
|
32
73
|
log('Checking for updates...');
|
|
33
74
|
let autoUpdateMessage = '';
|