@c-d-cc/reap 0.7.0 → 0.7.2
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 +440 -125
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -31,6 +31,20 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
31
31
|
return to;
|
|
32
32
|
};
|
|
33
33
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
34
|
+
var __returnValue = (v) => v;
|
|
35
|
+
function __exportSetter(name, newValue) {
|
|
36
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
37
|
+
}
|
|
38
|
+
var __export = (target, all) => {
|
|
39
|
+
for (var name in all)
|
|
40
|
+
__defProp(target, name, {
|
|
41
|
+
get: all[name],
|
|
42
|
+
enumerable: true,
|
|
43
|
+
configurable: true,
|
|
44
|
+
set: __exportSetter.bind(all, name)
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
34
48
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
35
49
|
|
|
36
50
|
// node_modules/commander/lib/error.js
|
|
@@ -8823,6 +8837,311 @@ var require_dist = __commonJS((exports) => {
|
|
|
8823
8837
|
exports.visitAsync = visit.visitAsync;
|
|
8824
8838
|
});
|
|
8825
8839
|
|
|
8840
|
+
// src/core/fs.ts
|
|
8841
|
+
var exports_fs = {};
|
|
8842
|
+
__export(exports_fs, {
|
|
8843
|
+
writeTextFile: () => writeTextFile,
|
|
8844
|
+
readTextFileOrThrow: () => readTextFileOrThrow,
|
|
8845
|
+
readTextFile: () => readTextFile,
|
|
8846
|
+
fileExists: () => fileExists
|
|
8847
|
+
});
|
|
8848
|
+
import { readFile, writeFile, access } from "fs/promises";
|
|
8849
|
+
async function readTextFile(path) {
|
|
8850
|
+
try {
|
|
8851
|
+
return await readFile(path, "utf-8");
|
|
8852
|
+
} catch {
|
|
8853
|
+
return null;
|
|
8854
|
+
}
|
|
8855
|
+
}
|
|
8856
|
+
async function readTextFileOrThrow(path) {
|
|
8857
|
+
return await readFile(path, "utf-8");
|
|
8858
|
+
}
|
|
8859
|
+
async function writeTextFile(path, content) {
|
|
8860
|
+
await writeFile(path, content, "utf-8");
|
|
8861
|
+
}
|
|
8862
|
+
async function fileExists(path) {
|
|
8863
|
+
try {
|
|
8864
|
+
await access(path);
|
|
8865
|
+
return true;
|
|
8866
|
+
} catch {
|
|
8867
|
+
return false;
|
|
8868
|
+
}
|
|
8869
|
+
}
|
|
8870
|
+
var init_fs = () => {};
|
|
8871
|
+
|
|
8872
|
+
// src/core/genome-sync.ts
|
|
8873
|
+
var exports_genome_sync = {};
|
|
8874
|
+
__export(exports_genome_sync, {
|
|
8875
|
+
syncGenomeFromProject: () => syncGenomeFromProject
|
|
8876
|
+
});
|
|
8877
|
+
import { join as join4 } from "path";
|
|
8878
|
+
import { readdir as readdir3, stat as stat2 } from "fs/promises";
|
|
8879
|
+
async function scanProject(projectRoot) {
|
|
8880
|
+
const scan = {
|
|
8881
|
+
language: "Unknown",
|
|
8882
|
+
runtime: "Unknown",
|
|
8883
|
+
framework: "None",
|
|
8884
|
+
packageManager: "Unknown",
|
|
8885
|
+
testFramework: "None",
|
|
8886
|
+
linter: "None",
|
|
8887
|
+
formatter: "None",
|
|
8888
|
+
buildTool: "None",
|
|
8889
|
+
scripts: {},
|
|
8890
|
+
dependencies: [],
|
|
8891
|
+
devDependencies: [],
|
|
8892
|
+
hasTypeScript: false,
|
|
8893
|
+
hasDocker: false,
|
|
8894
|
+
directories: [],
|
|
8895
|
+
existingDocs: []
|
|
8896
|
+
};
|
|
8897
|
+
const pkgContent = await readTextFile(join4(projectRoot, "package.json"));
|
|
8898
|
+
if (pkgContent) {
|
|
8899
|
+
try {
|
|
8900
|
+
const pkg = JSON.parse(pkgContent);
|
|
8901
|
+
scan.dependencies = Object.keys(pkg.dependencies ?? {});
|
|
8902
|
+
scan.devDependencies = Object.keys(pkg.devDependencies ?? {});
|
|
8903
|
+
scan.scripts = pkg.scripts ?? {};
|
|
8904
|
+
scan.packageManager = pkg.packageManager?.startsWith("bun") ? "Bun" : pkg.packageManager?.startsWith("pnpm") ? "pnpm" : pkg.packageManager?.startsWith("yarn") ? "Yarn" : "npm";
|
|
8905
|
+
scan.language = "JavaScript";
|
|
8906
|
+
scan.runtime = "Node.js";
|
|
8907
|
+
const allDeps = [...scan.dependencies, ...scan.devDependencies];
|
|
8908
|
+
if (allDeps.includes("next"))
|
|
8909
|
+
scan.framework = "Next.js";
|
|
8910
|
+
else if (allDeps.includes("nuxt"))
|
|
8911
|
+
scan.framework = "Nuxt";
|
|
8912
|
+
else if (allDeps.includes("react"))
|
|
8913
|
+
scan.framework = "React";
|
|
8914
|
+
else if (allDeps.includes("vue"))
|
|
8915
|
+
scan.framework = "Vue";
|
|
8916
|
+
else if (allDeps.includes("svelte") || allDeps.includes("@sveltejs/kit"))
|
|
8917
|
+
scan.framework = "Svelte/SvelteKit";
|
|
8918
|
+
else if (allDeps.includes("express"))
|
|
8919
|
+
scan.framework = "Express";
|
|
8920
|
+
else if (allDeps.includes("hono"))
|
|
8921
|
+
scan.framework = "Hono";
|
|
8922
|
+
else if (allDeps.includes("fastify"))
|
|
8923
|
+
scan.framework = "Fastify";
|
|
8924
|
+
else if (allDeps.includes("nestjs") || allDeps.includes("@nestjs/core"))
|
|
8925
|
+
scan.framework = "NestJS";
|
|
8926
|
+
else if (allDeps.includes("astro"))
|
|
8927
|
+
scan.framework = "Astro";
|
|
8928
|
+
if (allDeps.includes("vitest"))
|
|
8929
|
+
scan.testFramework = "Vitest";
|
|
8930
|
+
else if (allDeps.includes("jest"))
|
|
8931
|
+
scan.testFramework = "Jest";
|
|
8932
|
+
else if (allDeps.includes("mocha"))
|
|
8933
|
+
scan.testFramework = "Mocha";
|
|
8934
|
+
else if (scan.scripts.test?.includes("bun test"))
|
|
8935
|
+
scan.testFramework = "Bun Test";
|
|
8936
|
+
if (allDeps.includes("eslint"))
|
|
8937
|
+
scan.linter = "ESLint";
|
|
8938
|
+
else if (allDeps.includes("biome") || allDeps.includes("@biomejs/biome"))
|
|
8939
|
+
scan.linter = "Biome";
|
|
8940
|
+
if (allDeps.includes("prettier"))
|
|
8941
|
+
scan.formatter = "Prettier";
|
|
8942
|
+
else if (allDeps.includes("biome") || allDeps.includes("@biomejs/biome"))
|
|
8943
|
+
scan.formatter = "Biome";
|
|
8944
|
+
if (allDeps.includes("vite"))
|
|
8945
|
+
scan.buildTool = "Vite";
|
|
8946
|
+
else if (allDeps.includes("webpack"))
|
|
8947
|
+
scan.buildTool = "Webpack";
|
|
8948
|
+
else if (allDeps.includes("esbuild"))
|
|
8949
|
+
scan.buildTool = "esbuild";
|
|
8950
|
+
else if (allDeps.includes("rollup"))
|
|
8951
|
+
scan.buildTool = "Rollup";
|
|
8952
|
+
else if (allDeps.includes("turbo") || allDeps.includes("turbopack"))
|
|
8953
|
+
scan.buildTool = "Turbopack";
|
|
8954
|
+
} catch {}
|
|
8955
|
+
}
|
|
8956
|
+
if (await fileExists(join4(projectRoot, "go.mod"))) {
|
|
8957
|
+
scan.language = "Go";
|
|
8958
|
+
scan.runtime = "Go";
|
|
8959
|
+
scan.packageManager = "Go Modules";
|
|
8960
|
+
}
|
|
8961
|
+
if (await fileExists(join4(projectRoot, "pyproject.toml")) || await fileExists(join4(projectRoot, "requirements.txt"))) {
|
|
8962
|
+
scan.language = "Python";
|
|
8963
|
+
scan.runtime = "Python";
|
|
8964
|
+
if (await fileExists(join4(projectRoot, "pyproject.toml"))) {
|
|
8965
|
+
const pyproject = await readTextFile(join4(projectRoot, "pyproject.toml"));
|
|
8966
|
+
if (pyproject?.includes("[tool.poetry]"))
|
|
8967
|
+
scan.packageManager = "Poetry";
|
|
8968
|
+
else if (pyproject?.includes("[tool.uv]") || pyproject?.includes("[project]"))
|
|
8969
|
+
scan.packageManager = "uv/pip";
|
|
8970
|
+
if (pyproject?.includes("pytest"))
|
|
8971
|
+
scan.testFramework = "pytest";
|
|
8972
|
+
if (pyproject?.includes("django"))
|
|
8973
|
+
scan.framework = "Django";
|
|
8974
|
+
else if (pyproject?.includes("fastapi"))
|
|
8975
|
+
scan.framework = "FastAPI";
|
|
8976
|
+
else if (pyproject?.includes("flask"))
|
|
8977
|
+
scan.framework = "Flask";
|
|
8978
|
+
}
|
|
8979
|
+
}
|
|
8980
|
+
if (await fileExists(join4(projectRoot, "Cargo.toml"))) {
|
|
8981
|
+
scan.language = "Rust";
|
|
8982
|
+
scan.runtime = "Rust";
|
|
8983
|
+
scan.packageManager = "Cargo";
|
|
8984
|
+
}
|
|
8985
|
+
if (await fileExists(join4(projectRoot, "tsconfig.json"))) {
|
|
8986
|
+
scan.hasTypeScript = true;
|
|
8987
|
+
scan.language = "TypeScript";
|
|
8988
|
+
}
|
|
8989
|
+
scan.hasDocker = await fileExists(join4(projectRoot, "Dockerfile")) || await fileExists(join4(projectRoot, "docker-compose.yml"));
|
|
8990
|
+
try {
|
|
8991
|
+
const entries = await readdir3(projectRoot);
|
|
8992
|
+
for (const entry of entries) {
|
|
8993
|
+
if (entry.startsWith(".") || entry === "node_modules")
|
|
8994
|
+
continue;
|
|
8995
|
+
try {
|
|
8996
|
+
const s = await stat2(join4(projectRoot, entry));
|
|
8997
|
+
if (s.isDirectory())
|
|
8998
|
+
scan.directories.push(entry);
|
|
8999
|
+
} catch {}
|
|
9000
|
+
}
|
|
9001
|
+
} catch {}
|
|
9002
|
+
const docFiles = ["README.md", "CLAUDE.md", "AGENTS.md", "CONTRIBUTING.md", "ARCHITECTURE.md"];
|
|
9003
|
+
for (const file of docFiles) {
|
|
9004
|
+
const content = await readTextFile(join4(projectRoot, file));
|
|
9005
|
+
if (content) {
|
|
9006
|
+
scan.existingDocs.push({ file, content: content.substring(0, 2000) });
|
|
9007
|
+
}
|
|
9008
|
+
}
|
|
9009
|
+
return scan;
|
|
9010
|
+
}
|
|
9011
|
+
function generateConstraints(scan) {
|
|
9012
|
+
const lines = [
|
|
9013
|
+
"# Technical Constraints",
|
|
9014
|
+
"",
|
|
9015
|
+
"> Auto-generated by `reap init` from project scan. Refine during the first Generation's Objective stage.",
|
|
9016
|
+
"",
|
|
9017
|
+
"## Tech Stack",
|
|
9018
|
+
"",
|
|
9019
|
+
`- **Language**: ${scan.language}${scan.hasTypeScript ? " (TypeScript)" : ""}`,
|
|
9020
|
+
`- **Runtime**: ${scan.runtime}`
|
|
9021
|
+
];
|
|
9022
|
+
if (scan.framework !== "None")
|
|
9023
|
+
lines.push(`- **Framework**: ${scan.framework}`);
|
|
9024
|
+
if (scan.packageManager !== "Unknown")
|
|
9025
|
+
lines.push(`- **Package Manager**: ${scan.packageManager}`);
|
|
9026
|
+
if (scan.buildTool !== "None")
|
|
9027
|
+
lines.push(`- **Build Tool**: ${scan.buildTool}`);
|
|
9028
|
+
lines.push("", "## Constraints", "");
|
|
9029
|
+
if (scan.hasDocker)
|
|
9030
|
+
lines.push("- Docker containerized deployment");
|
|
9031
|
+
if (scan.hasTypeScript)
|
|
9032
|
+
lines.push("- TypeScript strict mode (check tsconfig.json for details)");
|
|
9033
|
+
lines.push("", "## Validation Commands", "", "| Purpose | Command | Description |", "|---------|---------|-------------|");
|
|
9034
|
+
if (scan.testFramework !== "None") {
|
|
9035
|
+
const testCmd = scan.scripts.test ?? `${scan.testFramework.toLowerCase()} test`;
|
|
9036
|
+
lines.push(`| Test | \`${testCmd}\` | Run tests |`);
|
|
9037
|
+
}
|
|
9038
|
+
if (scan.scripts.lint)
|
|
9039
|
+
lines.push(`| Lint | \`${scan.scripts.lint.includes("npm") ? "npm run lint" : scan.scripts.lint}\` | Lint check |`);
|
|
9040
|
+
else if (scan.scripts.lint)
|
|
9041
|
+
lines.push(`| Lint | \`npm run lint\` | Lint check |`);
|
|
9042
|
+
if (scan.scripts.build)
|
|
9043
|
+
lines.push(`| Build | \`npm run build\` | Build project |`);
|
|
9044
|
+
if (scan.hasTypeScript)
|
|
9045
|
+
lines.push("| Type check | `npx tsc --noEmit` | TypeScript compile check |");
|
|
9046
|
+
lines.push("", "## External Dependencies", "", "- (review and fill in during first generation)");
|
|
9047
|
+
return lines.join(`
|
|
9048
|
+
`) + `
|
|
9049
|
+
`;
|
|
9050
|
+
}
|
|
9051
|
+
function generateConventions(scan) {
|
|
9052
|
+
const lines = [
|
|
9053
|
+
"# Development Conventions",
|
|
9054
|
+
"",
|
|
9055
|
+
"> Auto-generated by `reap init` from project scan. Refine during the first Generation's Objective stage.",
|
|
9056
|
+
"",
|
|
9057
|
+
"## Code Style",
|
|
9058
|
+
""
|
|
9059
|
+
];
|
|
9060
|
+
if (scan.linter !== "None")
|
|
9061
|
+
lines.push(`- Linter: ${scan.linter}`);
|
|
9062
|
+
if (scan.formatter !== "None")
|
|
9063
|
+
lines.push(`- Formatter: ${scan.formatter}`);
|
|
9064
|
+
if (scan.hasTypeScript)
|
|
9065
|
+
lines.push("- TypeScript strict mode");
|
|
9066
|
+
lines.push("", "## Naming Conventions", "", "- (review and fill in during first generation)");
|
|
9067
|
+
lines.push("", "## Git Conventions", "", "- (review and fill in during first generation)");
|
|
9068
|
+
if (scan.testFramework !== "None") {
|
|
9069
|
+
lines.push("", "## Testing", "", `- Test framework: ${scan.testFramework}`);
|
|
9070
|
+
}
|
|
9071
|
+
lines.push("", "## Enforced Rules", "", "| Rule | Tool | Command |", "|------|------|---------|");
|
|
9072
|
+
if (scan.scripts.test)
|
|
9073
|
+
lines.push(`| Tests pass | ${scan.testFramework} | \`npm test\` |`);
|
|
9074
|
+
if (scan.scripts.lint)
|
|
9075
|
+
lines.push(`| Lint clean | ${scan.linter} | \`npm run lint\` |`);
|
|
9076
|
+
if (scan.scripts.build)
|
|
9077
|
+
lines.push("| Build succeeds | Build | `npm run build` |");
|
|
9078
|
+
if (scan.hasTypeScript)
|
|
9079
|
+
lines.push("| TypeScript compiles | tsc | `npx tsc --noEmit` |");
|
|
9080
|
+
return lines.join(`
|
|
9081
|
+
`) + `
|
|
9082
|
+
`;
|
|
9083
|
+
}
|
|
9084
|
+
function generatePrinciples(scan) {
|
|
9085
|
+
const lines = [
|
|
9086
|
+
"# Architecture Principles",
|
|
9087
|
+
"",
|
|
9088
|
+
"> Auto-generated by `reap init` from project scan. Refine during the first Generation's Objective stage.",
|
|
9089
|
+
"",
|
|
9090
|
+
"## Core Beliefs",
|
|
9091
|
+
"",
|
|
9092
|
+
"- (define your project's core architectural beliefs during the first generation)",
|
|
9093
|
+
"",
|
|
9094
|
+
"## Architecture Decisions",
|
|
9095
|
+
"",
|
|
9096
|
+
"| ID | Decision | Rationale | Date |",
|
|
9097
|
+
"|----|----------|-----------|------|"
|
|
9098
|
+
];
|
|
9099
|
+
if (scan.framework !== "None")
|
|
9100
|
+
lines.push(`| ADR-001 | ${scan.framework} | Detected from project dependencies | Auto |`);
|
|
9101
|
+
if (scan.hasTypeScript)
|
|
9102
|
+
lines.push(`| ADR-002 | TypeScript | Type safety | Auto |`);
|
|
9103
|
+
lines.push("", "## Source Map", "", "→ `genome/source-map.md`");
|
|
9104
|
+
return lines.join(`
|
|
9105
|
+
`) + `
|
|
9106
|
+
`;
|
|
9107
|
+
}
|
|
9108
|
+
function generateSourceMap(scan) {
|
|
9109
|
+
const lines = [
|
|
9110
|
+
"# Source Map",
|
|
9111
|
+
"",
|
|
9112
|
+
"> Auto-generated by `reap init` from project scan. Refine during the first Generation's Objective stage.",
|
|
9113
|
+
"",
|
|
9114
|
+
"## Project Structure",
|
|
9115
|
+
"",
|
|
9116
|
+
"```"
|
|
9117
|
+
];
|
|
9118
|
+
for (const dir of scan.directories.sort()) {
|
|
9119
|
+
lines.push(`${dir}/`);
|
|
9120
|
+
}
|
|
9121
|
+
lines.push("```");
|
|
9122
|
+
return lines.join(`
|
|
9123
|
+
`) + `
|
|
9124
|
+
`;
|
|
9125
|
+
}
|
|
9126
|
+
async function syncGenomeFromProject(projectRoot, genomePath, onProgress) {
|
|
9127
|
+
const log = onProgress ?? (() => {});
|
|
9128
|
+
log("Scanning project structure...");
|
|
9129
|
+
const scan = await scanProject(projectRoot);
|
|
9130
|
+
log(`Detected: ${scan.language}, ${scan.framework !== "None" ? scan.framework : "no framework"}, ${scan.packageManager}`);
|
|
9131
|
+
const { writeTextFile: writeTextFile2 } = await Promise.resolve().then(() => (init_fs(), exports_fs));
|
|
9132
|
+
log("Generating constraints.md...");
|
|
9133
|
+
await writeTextFile2(join4(genomePath, "constraints.md"), generateConstraints(scan));
|
|
9134
|
+
log("Generating conventions.md...");
|
|
9135
|
+
await writeTextFile2(join4(genomePath, "conventions.md"), generateConventions(scan));
|
|
9136
|
+
log("Generating principles.md...");
|
|
9137
|
+
await writeTextFile2(join4(genomePath, "principles.md"), generatePrinciples(scan));
|
|
9138
|
+
log("Generating source-map.md...");
|
|
9139
|
+
await writeTextFile2(join4(genomePath, "source-map.md"), generateSourceMap(scan));
|
|
9140
|
+
}
|
|
9141
|
+
var init_genome_sync = __esm(() => {
|
|
9142
|
+
init_fs();
|
|
9143
|
+
});
|
|
9144
|
+
|
|
8826
9145
|
// node_modules/commander/esm.mjs
|
|
8827
9146
|
var import__ = __toESM(require_commander(), 1);
|
|
8828
9147
|
var {
|
|
@@ -8840,8 +9159,8 @@ var {
|
|
|
8840
9159
|
} = import__.default;
|
|
8841
9160
|
|
|
8842
9161
|
// src/cli/commands/init.ts
|
|
8843
|
-
import { mkdir as mkdir3, readdir as
|
|
8844
|
-
import { join as
|
|
9162
|
+
import { mkdir as mkdir3, readdir as readdir4, chmod } from "fs/promises";
|
|
9163
|
+
import { join as join5 } from "path";
|
|
8845
9164
|
|
|
8846
9165
|
// src/core/paths.ts
|
|
8847
9166
|
import { join, dirname } from "path";
|
|
@@ -8966,33 +9285,9 @@ class ReapPaths {
|
|
|
8966
9285
|
}
|
|
8967
9286
|
|
|
8968
9287
|
// src/core/config.ts
|
|
9288
|
+
init_fs();
|
|
8969
9289
|
var import_yaml = __toESM(require_dist(), 1);
|
|
8970
9290
|
|
|
8971
|
-
// src/core/fs.ts
|
|
8972
|
-
import { readFile, writeFile, access } from "fs/promises";
|
|
8973
|
-
async function readTextFile(path) {
|
|
8974
|
-
try {
|
|
8975
|
-
return await readFile(path, "utf-8");
|
|
8976
|
-
} catch {
|
|
8977
|
-
return null;
|
|
8978
|
-
}
|
|
8979
|
-
}
|
|
8980
|
-
async function readTextFileOrThrow(path) {
|
|
8981
|
-
return await readFile(path, "utf-8");
|
|
8982
|
-
}
|
|
8983
|
-
async function writeTextFile(path, content) {
|
|
8984
|
-
await writeFile(path, content, "utf-8");
|
|
8985
|
-
}
|
|
8986
|
-
async function fileExists(path) {
|
|
8987
|
-
try {
|
|
8988
|
-
await access(path);
|
|
8989
|
-
return true;
|
|
8990
|
-
} catch {
|
|
8991
|
-
return false;
|
|
8992
|
-
}
|
|
8993
|
-
}
|
|
8994
|
-
|
|
8995
|
-
// src/core/config.ts
|
|
8996
9291
|
class ConfigManager {
|
|
8997
9292
|
static async read(paths) {
|
|
8998
9293
|
const content = await readTextFileOrThrow(paths.config);
|
|
@@ -9017,6 +9312,7 @@ class ConfigManager {
|
|
|
9017
9312
|
}
|
|
9018
9313
|
|
|
9019
9314
|
// src/core/agents/claude-code.ts
|
|
9315
|
+
init_fs();
|
|
9020
9316
|
import { join as join2 } from "path";
|
|
9021
9317
|
import { homedir as homedir2 } from "os";
|
|
9022
9318
|
import { mkdir, readdir, unlink } from "fs/promises";
|
|
@@ -9242,6 +9538,7 @@ Read \`~/.reap/commands/${cmd}.md\` and follow the instructions there.
|
|
|
9242
9538
|
}
|
|
9243
9539
|
|
|
9244
9540
|
// src/core/agents/opencode.ts
|
|
9541
|
+
init_fs();
|
|
9245
9542
|
import { join as join3 } from "path";
|
|
9246
9543
|
import { homedir as homedir3 } from "os";
|
|
9247
9544
|
import { mkdir as mkdir2, readdir as readdir2, unlink as unlink2 } from "fs/promises";
|
|
@@ -9441,6 +9738,7 @@ class AgentRegistry {
|
|
|
9441
9738
|
}
|
|
9442
9739
|
|
|
9443
9740
|
// src/cli/commands/init.ts
|
|
9741
|
+
init_fs();
|
|
9444
9742
|
var COMMAND_NAMES = [
|
|
9445
9743
|
"reap.objective",
|
|
9446
9744
|
"reap.planning",
|
|
@@ -9474,8 +9772,8 @@ async function initProject(projectRoot, projectName, entryMode, preset, onProgre
|
|
|
9474
9772
|
throw new Error(".reap/ already exists. This is already a REAP project.");
|
|
9475
9773
|
}
|
|
9476
9774
|
if (preset) {
|
|
9477
|
-
const presetDir =
|
|
9478
|
-
const presetExists = await fileExists(
|
|
9775
|
+
const presetDir = join5(ReapPaths.packageTemplatesDir, "presets", preset);
|
|
9776
|
+
const presetExists = await fileExists(join5(presetDir, "principles.md"));
|
|
9479
9777
|
if (!presetExists) {
|
|
9480
9778
|
throw new Error(`Unknown preset: "${preset}". Available presets: bun-hono-react`);
|
|
9481
9779
|
}
|
|
@@ -9492,59 +9790,65 @@ async function initProject(projectRoot, projectName, entryMode, preset, onProgre
|
|
|
9492
9790
|
version: "0.1.0",
|
|
9493
9791
|
project: projectName,
|
|
9494
9792
|
entryMode,
|
|
9793
|
+
autoUpdate: true,
|
|
9495
9794
|
...preset && { preset }
|
|
9496
9795
|
};
|
|
9497
9796
|
await ConfigManager.write(paths, config);
|
|
9498
9797
|
log("Setting up Genome templates...");
|
|
9499
9798
|
const genomeTemplates = ["principles.md", "conventions.md", "constraints.md", "source-map.md"];
|
|
9500
|
-
const genomeSourceDir = preset ?
|
|
9799
|
+
const genomeSourceDir = preset ? join5(ReapPaths.packageTemplatesDir, "presets", preset) : ReapPaths.packageGenomeDir;
|
|
9501
9800
|
for (const file of genomeTemplates) {
|
|
9502
|
-
const src =
|
|
9503
|
-
const dest =
|
|
9801
|
+
const src = join5(genomeSourceDir, file);
|
|
9802
|
+
const dest = join5(paths.genome, file);
|
|
9504
9803
|
await writeTextFile(dest, await readTextFileOrThrow(src));
|
|
9505
9804
|
}
|
|
9805
|
+
if ((entryMode === "adoption" || entryMode === "migration") && !preset) {
|
|
9806
|
+
log("Scanning project for genome auto-sync...");
|
|
9807
|
+
const { syncGenomeFromProject: syncGenomeFromProject2 } = await Promise.resolve().then(() => (init_genome_sync(), exports_genome_sync));
|
|
9808
|
+
await syncGenomeFromProject2(projectRoot, paths.genome, log);
|
|
9809
|
+
}
|
|
9506
9810
|
log("Installing artifact templates...");
|
|
9507
9811
|
await mkdir3(ReapPaths.userReapTemplates, { recursive: true });
|
|
9508
9812
|
const artifactFiles = ["01-objective.md", "02-planning.md", "03-implementation.md", "04-validation.md", "05-completion.md"];
|
|
9509
9813
|
for (const file of artifactFiles) {
|
|
9510
|
-
const src =
|
|
9511
|
-
const dest =
|
|
9814
|
+
const src = join5(ReapPaths.packageArtifactsDir, file);
|
|
9815
|
+
const dest = join5(ReapPaths.userReapTemplates, file);
|
|
9512
9816
|
await writeTextFile(dest, await readTextFileOrThrow(src));
|
|
9513
9817
|
}
|
|
9514
|
-
const domainGuideSrc =
|
|
9515
|
-
const domainGuideDest =
|
|
9818
|
+
const domainGuideSrc = join5(ReapPaths.packageGenomeDir, "domain/README.md");
|
|
9819
|
+
const domainGuideDest = join5(ReapPaths.userReapTemplates, "domain-guide.md");
|
|
9516
9820
|
await writeTextFile(domainGuideDest, await readTextFileOrThrow(domainGuideSrc));
|
|
9517
|
-
const mergeTemplatesDir =
|
|
9821
|
+
const mergeTemplatesDir = join5(ReapPaths.userReapTemplates, "merge");
|
|
9518
9822
|
await mkdir3(mergeTemplatesDir, { recursive: true });
|
|
9519
9823
|
const mergeArtifactFiles = ["01-detect.md", "02-mate.md", "03-merge.md", "04-sync.md", "05-validation.md", "06-completion.md"];
|
|
9520
|
-
const mergeSourceDir =
|
|
9824
|
+
const mergeSourceDir = join5(ReapPaths.packageArtifactsDir, "merge");
|
|
9521
9825
|
for (const file of mergeArtifactFiles) {
|
|
9522
|
-
const src =
|
|
9523
|
-
const dest =
|
|
9826
|
+
const src = join5(mergeSourceDir, file);
|
|
9827
|
+
const dest = join5(mergeTemplatesDir, file);
|
|
9524
9828
|
await writeTextFile(dest, await readTextFileOrThrow(src));
|
|
9525
9829
|
}
|
|
9526
9830
|
log("Installing brainstorm server...");
|
|
9527
|
-
const brainstormSourceDir =
|
|
9528
|
-
const brainstormDestDir =
|
|
9831
|
+
const brainstormSourceDir = join5(ReapPaths.packageTemplatesDir, "brainstorm");
|
|
9832
|
+
const brainstormDestDir = join5(paths.root, "brainstorm");
|
|
9529
9833
|
await mkdir3(brainstormDestDir, { recursive: true });
|
|
9530
9834
|
const brainstormFiles = ["server.cjs", "frame.html", "start-server.sh"];
|
|
9531
9835
|
for (const file of brainstormFiles) {
|
|
9532
|
-
const src =
|
|
9533
|
-
const dest =
|
|
9836
|
+
const src = join5(brainstormSourceDir, file);
|
|
9837
|
+
const dest = join5(brainstormDestDir, file);
|
|
9534
9838
|
await writeTextFile(dest, await readTextFileOrThrow(src));
|
|
9535
9839
|
if (file.endsWith(".sh"))
|
|
9536
9840
|
await chmod(dest, 493);
|
|
9537
9841
|
}
|
|
9538
9842
|
log("Installing hook conditions...");
|
|
9539
|
-
const conditionsSourceDir =
|
|
9540
|
-
const conditionsDestDir =
|
|
9843
|
+
const conditionsSourceDir = join5(ReapPaths.packageTemplatesDir, "conditions");
|
|
9844
|
+
const conditionsDestDir = join5(paths.hooks, "conditions");
|
|
9541
9845
|
await mkdir3(conditionsDestDir, { recursive: true });
|
|
9542
|
-
const conditionFiles = await
|
|
9846
|
+
const conditionFiles = await readdir4(conditionsSourceDir);
|
|
9543
9847
|
for (const file of conditionFiles) {
|
|
9544
9848
|
if (!file.endsWith(".sh"))
|
|
9545
9849
|
continue;
|
|
9546
|
-
const src =
|
|
9547
|
-
const dest =
|
|
9850
|
+
const src = join5(conditionsSourceDir, file);
|
|
9851
|
+
const dest = join5(conditionsDestDir, file);
|
|
9548
9852
|
await writeTextFile(dest, await readTextFileOrThrow(src));
|
|
9549
9853
|
await chmod(dest, 493);
|
|
9550
9854
|
}
|
|
@@ -9564,8 +9868,8 @@ async function initProject(projectRoot, projectName, entryMode, preset, onProgre
|
|
|
9564
9868
|
}
|
|
9565
9869
|
|
|
9566
9870
|
// src/cli/commands/update.ts
|
|
9567
|
-
import { readdir as
|
|
9568
|
-
import { join as
|
|
9871
|
+
import { readdir as readdir9, unlink as unlink3, rm as rm2, mkdir as mkdir6, chmod as chmod2 } from "fs/promises";
|
|
9872
|
+
import { join as join10 } from "path";
|
|
9569
9873
|
|
|
9570
9874
|
// src/core/hooks.ts
|
|
9571
9875
|
async function migrateHooks(dryRun = false) {
|
|
@@ -9580,17 +9884,21 @@ async function migrateHooks(dryRun = false) {
|
|
|
9580
9884
|
return { results };
|
|
9581
9885
|
}
|
|
9582
9886
|
|
|
9887
|
+
// src/cli/commands/update.ts
|
|
9888
|
+
init_fs();
|
|
9889
|
+
|
|
9583
9890
|
// src/core/migration.ts
|
|
9891
|
+
init_fs();
|
|
9584
9892
|
var import_yaml5 = __toESM(require_dist(), 1);
|
|
9585
|
-
import { readdir as
|
|
9586
|
-
import { join as
|
|
9893
|
+
import { readdir as readdir8, rename as rename2 } from "fs/promises";
|
|
9894
|
+
import { join as join9 } from "path";
|
|
9587
9895
|
|
|
9588
9896
|
// src/core/generation.ts
|
|
9589
9897
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
9590
9898
|
import { createHash } from "crypto";
|
|
9591
9899
|
import { hostname } from "os";
|
|
9592
|
-
import { readdir as
|
|
9593
|
-
import { join as
|
|
9900
|
+
import { readdir as readdir7, mkdir as mkdir4, rename } from "fs/promises";
|
|
9901
|
+
import { join as join8 } from "path";
|
|
9594
9902
|
|
|
9595
9903
|
// src/types/index.ts
|
|
9596
9904
|
var LIFECYCLE_ORDER = [
|
|
@@ -9644,9 +9952,10 @@ class LifeCycle {
|
|
|
9644
9952
|
}
|
|
9645
9953
|
|
|
9646
9954
|
// src/core/compression.ts
|
|
9955
|
+
init_fs();
|
|
9647
9956
|
var import_yaml2 = __toESM(require_dist(), 1);
|
|
9648
|
-
import { readdir as
|
|
9649
|
-
import { join as
|
|
9957
|
+
import { readdir as readdir5, rm } from "fs/promises";
|
|
9958
|
+
import { join as join6 } from "path";
|
|
9650
9959
|
var LINEAGE_MAX_LINES = 5000;
|
|
9651
9960
|
var MIN_GENERATIONS_FOR_COMPRESSION = 5;
|
|
9652
9961
|
var LEVEL1_MAX_LINES = 40;
|
|
@@ -9683,9 +9992,9 @@ async function countLines(filePath) {
|
|
|
9683
9992
|
async function countDirLines(dirPath) {
|
|
9684
9993
|
let total = 0;
|
|
9685
9994
|
try {
|
|
9686
|
-
const entries = await
|
|
9995
|
+
const entries = await readdir5(dirPath, { withFileTypes: true });
|
|
9687
9996
|
for (const entry of entries) {
|
|
9688
|
-
const fullPath =
|
|
9997
|
+
const fullPath = join6(dirPath, entry.name);
|
|
9689
9998
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
9690
9999
|
total += await countLines(fullPath);
|
|
9691
10000
|
} else if (entry.isDirectory()) {
|
|
@@ -9696,7 +10005,7 @@ async function countDirLines(dirPath) {
|
|
|
9696
10005
|
return total;
|
|
9697
10006
|
}
|
|
9698
10007
|
async function readDirMeta(dirPath) {
|
|
9699
|
-
const content = await readTextFile(
|
|
10008
|
+
const content = await readTextFile(join6(dirPath, "meta.yml"));
|
|
9700
10009
|
if (content === null)
|
|
9701
10010
|
return null;
|
|
9702
10011
|
try {
|
|
@@ -9714,9 +10023,9 @@ async function readFileMeta(filePath) {
|
|
|
9714
10023
|
async function scanLineage(paths) {
|
|
9715
10024
|
const entries = [];
|
|
9716
10025
|
try {
|
|
9717
|
-
const items = await
|
|
10026
|
+
const items = await readdir5(paths.lineage, { withFileTypes: true });
|
|
9718
10027
|
for (const item of items) {
|
|
9719
|
-
const fullPath =
|
|
10028
|
+
const fullPath = join6(paths.lineage, item.name);
|
|
9720
10029
|
if (item.isDirectory() && item.name.startsWith("gen-")) {
|
|
9721
10030
|
const genNum = extractGenNum(item.name);
|
|
9722
10031
|
const lines = await countDirLines(fullPath);
|
|
@@ -9770,7 +10079,7 @@ async function findLeafNodes(paths, entries) {
|
|
|
9770
10079
|
if (entry.type === "level2")
|
|
9771
10080
|
continue;
|
|
9772
10081
|
let meta = null;
|
|
9773
|
-
const fullPath =
|
|
10082
|
+
const fullPath = join6(paths.lineage, entry.name);
|
|
9774
10083
|
if (entry.type === "dir") {
|
|
9775
10084
|
meta = await readDirMeta(fullPath);
|
|
9776
10085
|
} else {
|
|
@@ -9801,7 +10110,7 @@ async function compressLevel1(genDir, genName) {
|
|
|
9801
10110
|
}
|
|
9802
10111
|
let goal = "", completionConditions = "";
|
|
9803
10112
|
{
|
|
9804
|
-
const objective = await readTextFile(
|
|
10113
|
+
const objective = await readTextFile(join6(genDir, "01-objective.md"));
|
|
9805
10114
|
if (objective) {
|
|
9806
10115
|
const goalMatch = objective.match(/## Goal\n([\s\S]*?)(?=\n##)/);
|
|
9807
10116
|
if (goalMatch)
|
|
@@ -9813,7 +10122,7 @@ async function compressLevel1(genDir, genName) {
|
|
|
9813
10122
|
}
|
|
9814
10123
|
let lessons = "", genomeChanges = "", nextBacklog = "";
|
|
9815
10124
|
{
|
|
9816
|
-
const completion = await readTextFile(
|
|
10125
|
+
const completion = await readTextFile(join6(genDir, "05-completion.md"));
|
|
9817
10126
|
if (completion) {
|
|
9818
10127
|
const lessonsMatch = completion.match(/### Lessons Learned\n([\s\S]*?)(?=\n###)/);
|
|
9819
10128
|
if (lessonsMatch)
|
|
@@ -9828,7 +10137,7 @@ async function compressLevel1(genDir, genName) {
|
|
|
9828
10137
|
}
|
|
9829
10138
|
let summaryText = "";
|
|
9830
10139
|
{
|
|
9831
|
-
const completion = await readTextFile(
|
|
10140
|
+
const completion = await readTextFile(join6(genDir, "05-completion.md"));
|
|
9832
10141
|
if (completion) {
|
|
9833
10142
|
const summaryMatch = completion.match(/## Summary\n([\s\S]*?)(?=\n##)/);
|
|
9834
10143
|
if (summaryMatch)
|
|
@@ -9837,7 +10146,7 @@ async function compressLevel1(genDir, genName) {
|
|
|
9837
10146
|
}
|
|
9838
10147
|
let validationResult = "";
|
|
9839
10148
|
{
|
|
9840
|
-
const validation = await readTextFile(
|
|
10149
|
+
const validation = await readTextFile(join6(genDir, "04-validation.md"));
|
|
9841
10150
|
if (validation) {
|
|
9842
10151
|
const resultMatch = validation.match(/## Result: (.+)/);
|
|
9843
10152
|
if (resultMatch)
|
|
@@ -9846,7 +10155,7 @@ async function compressLevel1(genDir, genName) {
|
|
|
9846
10155
|
}
|
|
9847
10156
|
let deferred = "";
|
|
9848
10157
|
{
|
|
9849
|
-
const impl = await readTextFile(
|
|
10158
|
+
const impl = await readTextFile(join6(genDir, "03-implementation.md"));
|
|
9850
10159
|
if (impl) {
|
|
9851
10160
|
const deferredMatch = impl.match(/## Deferred Tasks\n([\s\S]*?)(?=\n##)/);
|
|
9852
10161
|
if (deferredMatch) {
|
|
@@ -9970,10 +10279,10 @@ async function compressLineageIfNeeded(paths) {
|
|
|
9970
10279
|
const currentTotal = await countDirLines(paths.lineage);
|
|
9971
10280
|
if (currentTotal <= LINEAGE_MAX_LINES)
|
|
9972
10281
|
break;
|
|
9973
|
-
const dirPath =
|
|
10282
|
+
const dirPath = join6(paths.lineage, dir.name);
|
|
9974
10283
|
const compressed = await compressLevel1(dirPath, dir.name);
|
|
9975
10284
|
const genId = dir.name.match(/^gen-\d{3}(?:-[a-f0-9]{6})?/)?.[0] ?? dir.name;
|
|
9976
|
-
const outPath =
|
|
10285
|
+
const outPath = join6(paths.lineage, `${genId}.md`);
|
|
9977
10286
|
await writeTextFile(outPath, compressed);
|
|
9978
10287
|
await rm(dirPath, { recursive: true });
|
|
9979
10288
|
result.level1.push(genId);
|
|
@@ -9987,10 +10296,10 @@ async function compressLineageIfNeeded(paths) {
|
|
|
9987
10296
|
const batch = level1s.slice(i * LEVEL2_BATCH_SIZE, (i + 1) * LEVEL2_BATCH_SIZE);
|
|
9988
10297
|
const files = batch.map((e) => ({
|
|
9989
10298
|
name: e.name,
|
|
9990
|
-
path:
|
|
10299
|
+
path: join6(paths.lineage, e.name)
|
|
9991
10300
|
}));
|
|
9992
10301
|
const compressed = await compressLevel2(files, epochNum);
|
|
9993
|
-
const outPath =
|
|
10302
|
+
const outPath = join6(paths.lineage, `epoch-${String(epochNum).padStart(3, "0")}.md`);
|
|
9994
10303
|
await writeTextFile(outPath, compressed);
|
|
9995
10304
|
for (const file of files) {
|
|
9996
10305
|
await rm(file.path);
|
|
@@ -10002,20 +10311,24 @@ async function compressLineageIfNeeded(paths) {
|
|
|
10002
10311
|
return result;
|
|
10003
10312
|
}
|
|
10004
10313
|
|
|
10314
|
+
// src/core/generation.ts
|
|
10315
|
+
init_fs();
|
|
10316
|
+
|
|
10005
10317
|
// src/core/lineage.ts
|
|
10318
|
+
init_fs();
|
|
10006
10319
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
10007
|
-
import { readdir as
|
|
10008
|
-
import { join as
|
|
10320
|
+
import { readdir as readdir6 } from "fs/promises";
|
|
10321
|
+
import { join as join7 } from "path";
|
|
10009
10322
|
async function listCompleted(paths) {
|
|
10010
10323
|
try {
|
|
10011
|
-
const entries = await
|
|
10324
|
+
const entries = await readdir6(paths.lineage);
|
|
10012
10325
|
return entries.filter((e) => e.startsWith("gen-")).sort();
|
|
10013
10326
|
} catch {
|
|
10014
10327
|
return [];
|
|
10015
10328
|
}
|
|
10016
10329
|
}
|
|
10017
10330
|
async function readMeta(paths, lineageDirName) {
|
|
10018
|
-
const metaPath =
|
|
10331
|
+
const metaPath = join7(paths.lineage, lineageDirName, "meta.yml");
|
|
10019
10332
|
const content = await readTextFile(metaPath);
|
|
10020
10333
|
if (content === null)
|
|
10021
10334
|
return null;
|
|
@@ -10024,14 +10337,14 @@ async function readMeta(paths, lineageDirName) {
|
|
|
10024
10337
|
async function listMeta(paths) {
|
|
10025
10338
|
const metas = [];
|
|
10026
10339
|
try {
|
|
10027
|
-
const entries = await
|
|
10340
|
+
const entries = await readdir6(paths.lineage, { withFileTypes: true });
|
|
10028
10341
|
for (const entry of entries) {
|
|
10029
10342
|
if (entry.isDirectory() && entry.name.startsWith("gen-")) {
|
|
10030
10343
|
const meta = await readMeta(paths, entry.name);
|
|
10031
10344
|
if (meta)
|
|
10032
10345
|
metas.push(meta);
|
|
10033
10346
|
} else if (entry.isFile() && entry.name.startsWith("gen-") && entry.name.endsWith(".md")) {
|
|
10034
|
-
const content = await readTextFile(
|
|
10347
|
+
const content = await readTextFile(join7(paths.lineage, entry.name));
|
|
10035
10348
|
if (content) {
|
|
10036
10349
|
const meta = parseFrontmatter(content);
|
|
10037
10350
|
if (meta)
|
|
@@ -10085,13 +10398,13 @@ function getMachineId() {
|
|
|
10085
10398
|
async function computeGenomeHash(genomePath) {
|
|
10086
10399
|
const hash = createHash("sha256");
|
|
10087
10400
|
try {
|
|
10088
|
-
const entries = (await
|
|
10089
|
-
const pathA =
|
|
10090
|
-
const pathB =
|
|
10401
|
+
const entries = (await readdir7(genomePath, { recursive: true, withFileTypes: true })).filter((e) => e.isFile()).sort((a, b) => {
|
|
10402
|
+
const pathA = join8(e2path(a), a.name);
|
|
10403
|
+
const pathB = join8(e2path(b), b.name);
|
|
10091
10404
|
return pathA.localeCompare(pathB);
|
|
10092
10405
|
});
|
|
10093
10406
|
for (const entry of entries) {
|
|
10094
|
-
const filePath =
|
|
10407
|
+
const filePath = join8(e2path(entry), entry.name);
|
|
10095
10408
|
const content = await readTextFile(filePath);
|
|
10096
10409
|
if (content !== null) {
|
|
10097
10410
|
hash.update(filePath.replace(genomePath, ""));
|
|
@@ -10188,28 +10501,28 @@ class GenerationManager {
|
|
|
10188
10501
|
startedAt: state.startedAt,
|
|
10189
10502
|
completedAt: now
|
|
10190
10503
|
};
|
|
10191
|
-
await writeTextFile(
|
|
10192
|
-
const lifeEntries = await
|
|
10504
|
+
await writeTextFile(join8(genDir, "meta.yml"), import_yaml4.default.stringify(meta));
|
|
10505
|
+
const lifeEntries = await readdir7(this.paths.life);
|
|
10193
10506
|
for (const entry of lifeEntries) {
|
|
10194
10507
|
if (/^\d{2}-[a-z]+(?:-[a-z]+)*\.md$/.test(entry)) {
|
|
10195
|
-
await rename(
|
|
10508
|
+
await rename(join8(this.paths.life, entry), join8(genDir, entry));
|
|
10196
10509
|
}
|
|
10197
10510
|
}
|
|
10198
|
-
const backlogDir =
|
|
10511
|
+
const backlogDir = join8(genDir, "backlog");
|
|
10199
10512
|
await mkdir4(backlogDir, { recursive: true });
|
|
10200
10513
|
try {
|
|
10201
|
-
const backlogEntries = await
|
|
10514
|
+
const backlogEntries = await readdir7(this.paths.backlog);
|
|
10202
10515
|
for (const entry of backlogEntries) {
|
|
10203
|
-
await rename(
|
|
10516
|
+
await rename(join8(this.paths.backlog, entry), join8(backlogDir, entry));
|
|
10204
10517
|
}
|
|
10205
10518
|
} catch {}
|
|
10206
10519
|
try {
|
|
10207
|
-
const mutEntries = await
|
|
10520
|
+
const mutEntries = await readdir7(this.paths.mutations);
|
|
10208
10521
|
if (mutEntries.length > 0) {
|
|
10209
|
-
const mutDir =
|
|
10522
|
+
const mutDir = join8(genDir, "mutations");
|
|
10210
10523
|
await mkdir4(mutDir, { recursive: true });
|
|
10211
10524
|
for (const entry of mutEntries) {
|
|
10212
|
-
await rename(
|
|
10525
|
+
await rename(join8(this.paths.mutations, entry), join8(mutDir, entry));
|
|
10213
10526
|
}
|
|
10214
10527
|
}
|
|
10215
10528
|
} catch {}
|
|
@@ -10245,11 +10558,11 @@ class GenerationManager {
|
|
|
10245
10558
|
// src/core/migration.ts
|
|
10246
10559
|
async function needsMigration(paths) {
|
|
10247
10560
|
try {
|
|
10248
|
-
const entries = await
|
|
10561
|
+
const entries = await readdir8(paths.lineage, { withFileTypes: true });
|
|
10249
10562
|
for (const entry of entries) {
|
|
10250
10563
|
if (!entry.isDirectory() || !entry.name.startsWith("gen-"))
|
|
10251
10564
|
continue;
|
|
10252
|
-
const metaPath =
|
|
10565
|
+
const metaPath = join9(paths.lineage, entry.name, "meta.yml");
|
|
10253
10566
|
const content = await readTextFile(metaPath);
|
|
10254
10567
|
if (content === null)
|
|
10255
10568
|
return true;
|
|
@@ -10263,18 +10576,18 @@ async function migrateLineage(paths) {
|
|
|
10263
10576
|
const result = { migrated: [], skipped: [], errors: [] };
|
|
10264
10577
|
let entries;
|
|
10265
10578
|
try {
|
|
10266
|
-
const dirEntries = await
|
|
10579
|
+
const dirEntries = await readdir8(paths.lineage, { withFileTypes: true });
|
|
10267
10580
|
entries = dirEntries.filter((e) => e.isDirectory() && e.name.startsWith("gen-")).map((e) => e.name).sort();
|
|
10268
10581
|
} catch {
|
|
10269
10582
|
return result;
|
|
10270
10583
|
}
|
|
10271
10584
|
const plan = [];
|
|
10272
10585
|
for (const dirName of entries) {
|
|
10273
|
-
const metaPath =
|
|
10586
|
+
const metaPath = join9(paths.lineage, dirName, "meta.yml");
|
|
10274
10587
|
const metaContent = await readTextFile(metaPath);
|
|
10275
10588
|
const seq = parseGenSeq(dirName);
|
|
10276
10589
|
let goal = "";
|
|
10277
|
-
const objContent = await readTextFile(
|
|
10590
|
+
const objContent = await readTextFile(join9(paths.lineage, dirName, "01-objective.md"));
|
|
10278
10591
|
if (objContent) {
|
|
10279
10592
|
const goalMatch = objContent.match(/## Goal\n+([\s\S]*?)(?=\n##)/);
|
|
10280
10593
|
if (goalMatch)
|
|
@@ -10289,7 +10602,7 @@ async function migrateLineage(paths) {
|
|
|
10289
10602
|
let prevId = null;
|
|
10290
10603
|
for (const entry of plan) {
|
|
10291
10604
|
if (entry.hasMeta) {
|
|
10292
|
-
const metaContent = await readTextFile(
|
|
10605
|
+
const metaContent = await readTextFile(join9(paths.lineage, entry.dirName, "meta.yml"));
|
|
10293
10606
|
if (metaContent) {
|
|
10294
10607
|
const meta = import_yaml5.default.parse(metaContent);
|
|
10295
10608
|
prevId = meta.id;
|
|
@@ -10310,11 +10623,11 @@ async function migrateLineage(paths) {
|
|
|
10310
10623
|
startedAt: `legacy-${entry.seq}`,
|
|
10311
10624
|
completedAt: `legacy-${entry.seq}`
|
|
10312
10625
|
};
|
|
10313
|
-
await writeTextFile(
|
|
10626
|
+
await writeTextFile(join9(paths.lineage, entry.dirName, "meta.yml"), import_yaml5.default.stringify(meta));
|
|
10314
10627
|
const oldSlug = entry.dirName.replace(/^gen-\d{3}/, "");
|
|
10315
10628
|
const newDirName = `${newId}${oldSlug}`;
|
|
10316
10629
|
if (newDirName !== entry.dirName) {
|
|
10317
|
-
await rename2(
|
|
10630
|
+
await rename2(join9(paths.lineage, entry.dirName), join9(paths.lineage, newDirName));
|
|
10318
10631
|
}
|
|
10319
10632
|
prevId = newId;
|
|
10320
10633
|
result.migrated.push(`${entry.dirName} → ${newDirName}`);
|
|
@@ -10352,13 +10665,13 @@ async function updateProject(projectRoot, dryRun = false) {
|
|
|
10352
10665
|
const config = await ConfigManager.read(paths);
|
|
10353
10666
|
const adapters = await AgentRegistry.getActiveAdapters(config ?? undefined);
|
|
10354
10667
|
const commandsDir = ReapPaths.packageCommandsDir;
|
|
10355
|
-
const commandFiles = await
|
|
10668
|
+
const commandFiles = await readdir9(commandsDir);
|
|
10356
10669
|
await mkdir6(ReapPaths.userReapCommands, { recursive: true });
|
|
10357
10670
|
for (const file of commandFiles) {
|
|
10358
10671
|
if (!file.endsWith(".md"))
|
|
10359
10672
|
continue;
|
|
10360
|
-
const src = await readTextFileOrThrow(
|
|
10361
|
-
const dest =
|
|
10673
|
+
const src = await readTextFileOrThrow(join10(commandsDir, file));
|
|
10674
|
+
const dest = join10(ReapPaths.userReapCommands, file);
|
|
10362
10675
|
const existing = await readTextFile(dest);
|
|
10363
10676
|
if (existing !== null && existing === src) {
|
|
10364
10677
|
result.skipped.push(`~/.reap/commands/${file}`);
|
|
@@ -10380,7 +10693,7 @@ description: "REAP — redirected to ~/.reap/commands/"
|
|
|
10380
10693
|
---
|
|
10381
10694
|
Read \`~/.reap/commands/${cmdName}.md\` and follow the instructions there.
|
|
10382
10695
|
`;
|
|
10383
|
-
const dest =
|
|
10696
|
+
const dest = join10(agentCmdDir, file);
|
|
10384
10697
|
const existingContent = await readTextFile(dest);
|
|
10385
10698
|
if (existingContent !== null && existingContent === redirectContent) {
|
|
10386
10699
|
result.skipped.push(`[${label}] commands/${file}`);
|
|
@@ -10400,8 +10713,8 @@ Read \`~/.reap/commands/${cmdName}.md\` and follow the instructions there.
|
|
|
10400
10713
|
await mkdir6(ReapPaths.userReapTemplates, { recursive: true });
|
|
10401
10714
|
const artifactFiles = ["01-objective.md", "02-planning.md", "03-implementation.md", "04-validation.md", "05-completion.md"];
|
|
10402
10715
|
for (const file of artifactFiles) {
|
|
10403
|
-
const src = await readTextFileOrThrow(
|
|
10404
|
-
const dest =
|
|
10716
|
+
const src = await readTextFileOrThrow(join10(ReapPaths.packageArtifactsDir, file));
|
|
10717
|
+
const dest = join10(ReapPaths.userReapTemplates, file);
|
|
10405
10718
|
const existingContent = await readTextFile(dest);
|
|
10406
10719
|
if (existingContent !== null && existingContent === src) {
|
|
10407
10720
|
result.skipped.push(`~/.reap/templates/${file}`);
|
|
@@ -10411,8 +10724,8 @@ Read \`~/.reap/commands/${cmdName}.md\` and follow the instructions there.
|
|
|
10411
10724
|
result.updated.push(`~/.reap/templates/${file}`);
|
|
10412
10725
|
}
|
|
10413
10726
|
}
|
|
10414
|
-
const domainGuideSrc = await readTextFileOrThrow(
|
|
10415
|
-
const domainGuideDest =
|
|
10727
|
+
const domainGuideSrc = await readTextFileOrThrow(join10(ReapPaths.packageGenomeDir, "domain/README.md"));
|
|
10728
|
+
const domainGuideDest = join10(ReapPaths.userReapTemplates, "domain-guide.md");
|
|
10416
10729
|
const domainExistingContent = await readTextFile(domainGuideDest);
|
|
10417
10730
|
if (domainExistingContent !== null && domainExistingContent === domainGuideSrc) {
|
|
10418
10731
|
result.skipped.push(`~/.reap/templates/domain-guide.md`);
|
|
@@ -10421,13 +10734,13 @@ Read \`~/.reap/commands/${cmdName}.md\` and follow the instructions there.
|
|
|
10421
10734
|
await writeTextFile(domainGuideDest, domainGuideSrc);
|
|
10422
10735
|
result.updated.push(`~/.reap/templates/domain-guide.md`);
|
|
10423
10736
|
}
|
|
10424
|
-
const mergeTemplatesDir =
|
|
10737
|
+
const mergeTemplatesDir = join10(ReapPaths.userReapTemplates, "merge");
|
|
10425
10738
|
await mkdir6(mergeTemplatesDir, { recursive: true });
|
|
10426
10739
|
const mergeArtifactFiles = ["01-detect.md", "02-mate.md", "03-merge.md", "04-sync.md", "05-validation.md", "06-completion.md"];
|
|
10427
|
-
const mergeSourceDir =
|
|
10740
|
+
const mergeSourceDir = join10(ReapPaths.packageArtifactsDir, "merge");
|
|
10428
10741
|
for (const file of mergeArtifactFiles) {
|
|
10429
|
-
const src = await readTextFileOrThrow(
|
|
10430
|
-
const dest =
|
|
10742
|
+
const src = await readTextFileOrThrow(join10(mergeSourceDir, file));
|
|
10743
|
+
const dest = join10(mergeTemplatesDir, file);
|
|
10431
10744
|
const existing = await readTextFile(dest);
|
|
10432
10745
|
if (existing !== null && existing === src) {
|
|
10433
10746
|
result.skipped.push(`~/.reap/templates/merge/${file}`);
|
|
@@ -10437,13 +10750,13 @@ Read \`~/.reap/commands/${cmdName}.md\` and follow the instructions there.
|
|
|
10437
10750
|
result.updated.push(`~/.reap/templates/merge/${file}`);
|
|
10438
10751
|
}
|
|
10439
10752
|
}
|
|
10440
|
-
const brainstormSourceDir =
|
|
10441
|
-
const brainstormDestDir =
|
|
10753
|
+
const brainstormSourceDir = join10(ReapPaths.packageTemplatesDir, "brainstorm");
|
|
10754
|
+
const brainstormDestDir = join10(paths.root, "brainstorm");
|
|
10442
10755
|
await mkdir6(brainstormDestDir, { recursive: true });
|
|
10443
10756
|
const brainstormFiles = ["server.cjs", "frame.html", "start-server.sh"];
|
|
10444
10757
|
for (const file of brainstormFiles) {
|
|
10445
|
-
const src = await readTextFileOrThrow(
|
|
10446
|
-
const dest =
|
|
10758
|
+
const src = await readTextFileOrThrow(join10(brainstormSourceDir, file));
|
|
10759
|
+
const dest = join10(brainstormDestDir, file);
|
|
10447
10760
|
const existing = await readTextFile(dest);
|
|
10448
10761
|
if (existing !== null && existing === src) {
|
|
10449
10762
|
result.skipped.push(`.reap/brainstorm/${file}`);
|
|
@@ -10492,11 +10805,11 @@ async function migrateLegacyFiles(paths, dryRun, result) {
|
|
|
10492
10805
|
await removeDirIfExists(paths.legacyTemplates, ".reap/templates/", dryRun, result);
|
|
10493
10806
|
try {
|
|
10494
10807
|
const claudeCmdDir = paths.legacyClaudeCommands;
|
|
10495
|
-
const files = await
|
|
10808
|
+
const files = await readdir9(claudeCmdDir);
|
|
10496
10809
|
for (const file of files) {
|
|
10497
10810
|
if (file.startsWith("reap.") && file.endsWith(".md")) {
|
|
10498
10811
|
if (!dryRun)
|
|
10499
|
-
await unlink3(
|
|
10812
|
+
await unlink3(join10(claudeCmdDir, file));
|
|
10500
10813
|
result.removed.push(`.claude/commands/${file}`);
|
|
10501
10814
|
}
|
|
10502
10815
|
}
|
|
@@ -10540,7 +10853,7 @@ async function migrateLegacyFiles(paths, dryRun, result) {
|
|
|
10540
10853
|
}
|
|
10541
10854
|
async function removeDirIfExists(dirPath, label, dryRun, result) {
|
|
10542
10855
|
try {
|
|
10543
|
-
const entries = await
|
|
10856
|
+
const entries = await readdir9(dirPath);
|
|
10544
10857
|
if (entries.length > 0 || true) {
|
|
10545
10858
|
if (!dryRun)
|
|
10546
10859
|
await rm2(dirPath, { recursive: true });
|
|
@@ -10575,10 +10888,11 @@ async function getStatus(projectRoot) {
|
|
|
10575
10888
|
|
|
10576
10889
|
// src/cli/commands/fix.ts
|
|
10577
10890
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
10578
|
-
import { mkdir as mkdir7, stat as
|
|
10891
|
+
import { mkdir as mkdir7, stat as stat3 } from "fs/promises";
|
|
10892
|
+
init_fs();
|
|
10579
10893
|
async function dirExists(path) {
|
|
10580
10894
|
try {
|
|
10581
|
-
const s = await
|
|
10895
|
+
const s = await stat3(path);
|
|
10582
10896
|
return s.isDirectory();
|
|
10583
10897
|
} catch {
|
|
10584
10898
|
return false;
|
|
@@ -10631,8 +10945,9 @@ async function fixProject(projectRoot) {
|
|
|
10631
10945
|
}
|
|
10632
10946
|
|
|
10633
10947
|
// src/cli/index.ts
|
|
10634
|
-
|
|
10635
|
-
|
|
10948
|
+
init_fs();
|
|
10949
|
+
import { join as join11 } from "path";
|
|
10950
|
+
program.name("reap").description("REAP — Recursive Evolutionary Autonomous Pipeline").version("0.7.2");
|
|
10636
10951
|
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) => {
|
|
10637
10952
|
try {
|
|
10638
10953
|
const cwd = process.cwd();
|
|
@@ -10754,10 +11069,10 @@ program.command("help").description("Show REAP commands, slash commands, and wor
|
|
|
10754
11069
|
if (l === "korean" || l === "ko")
|
|
10755
11070
|
lang = "ko";
|
|
10756
11071
|
}
|
|
10757
|
-
const helpDir =
|
|
10758
|
-
let helpText = await readTextFile(
|
|
11072
|
+
const helpDir = join11(ReapPaths.packageTemplatesDir, "help");
|
|
11073
|
+
let helpText = await readTextFile(join11(helpDir, `${lang}.txt`));
|
|
10759
11074
|
if (!helpText)
|
|
10760
|
-
helpText = await readTextFile(
|
|
11075
|
+
helpText = await readTextFile(join11(helpDir, "en.txt"));
|
|
10761
11076
|
if (!helpText) {
|
|
10762
11077
|
console.log("Help file not found. Run 'reap update' to install templates.");
|
|
10763
11078
|
return;
|