@c-d-cc/reap 0.16.5 → 0.16.6

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.md CHANGED
@@ -229,6 +229,7 @@ Pre-approve N generations for autonomous execution:
229
229
  | `/reap.init` | Initialize REAP in a project |
230
230
  | `/reap.run` | Execute a lifecycle command directly |
231
231
  | `/reap.config` | View/edit project configuration |
232
+ | `/reap.report` | Submit a bug report or feature request |
232
233
 
233
234
  ## Agent Integration
234
235
 
@@ -250,6 +251,31 @@ Switch clients by editing `.reap/config.yml`, then run `reap install-skills` fol
250
251
 
251
252
  `/reap.evolve` can delegate the entire generation to a subagent that runs autonomously through all stages, surfacing only when genuinely blocked.
252
253
 
254
+ ### Evaluator Agent (opt-in)
255
+
256
+ REAP ships a second subagent definition, `reap-evaluate`, that runs as an **independent reviewer** of the builder's work. It is read-only (Read/Glob/Grep/Bash only), produces qualitative assessments (no scores), and acts as an **advisor** — its concerns surface to you, but the builder owns the final lifecycle verdict.
257
+
258
+ Enable it by adding one line to `.reap/config.yml`:
259
+
260
+ ```yaml
261
+ evaluator: true # default: false
262
+ ```
263
+
264
+ When enabled, the validation stage instructs the builder to launch `reap-evaluate` as a subagent before declaring pass/partial/fail. The evaluator:
265
+
266
+ - runs typecheck, build, and the full test suite independently,
267
+ - cross-checks completion criteria from `02-planning.md` against the implementation,
268
+ - surfaces concerns about genome convention drift, sycophancy red flags, and regression risk,
269
+ - escalates per a confidence × impact matrix.
270
+
271
+ If the subagent invocation fails for any reason, the builder continues normal validation — the evaluator is opt-in advice, not a gate.
272
+
273
+ Agent definitions are installed automatically by `reap install-skills` **and** `reap update`:
274
+ - Claude Code → `~/.claude/agents/reap-*.md`
275
+ - OpenCode → `~/.config/opencode/agent/reap-*.md`
276
+
277
+ **Fitness phase + cruise mode** (gen-067): the evaluator also runs during the fitness phase. After receiving its reply, the builder persists the verdict on the generation state via `reap run validation --phase report-evaluator --severity <high|low|none> --summary "..."`. High-severity concerns recorded during validation **automatically abort cruise mode** when the next fitness phase runs — `cruiseCount` is cleared from `config.yml`, the cruise prompt is replaced with a supervised fallback, and the human reviews the concern before composing fitness feedback. Cruise can be resumed manually with `reap cruise <N>` once the concern is resolved. Low-severity concerns surface in the prompt's "Prior Evaluator Concerns" section without aborting cruise.
278
+
253
279
  ## Project Structure
254
280
 
255
281
  ```
@@ -290,6 +316,7 @@ strictEdit: false # Restrict code changes to REAP lifecycle
290
316
  strictMerge: false # Restrict direct git pull/push/merge
291
317
  agentClient: claude-code # AI agent client
292
318
  # cruiseCount: 1/5 # Present = cruise mode (current/total)
319
+ # evaluator: true # Opt-in: launch reap-evaluate during validation
293
320
  ```
294
321
 
295
322
  Key settings:
@@ -298,6 +325,7 @@ Key settings:
298
325
  - **`strictEdit`**: Restricts code changes to the implementation stage within the planned scope.
299
326
  - **`strictMerge`**: Restricts direct git pull/push/merge — use `/reap.pull`, `/reap.push`, `/reap.merge` instead.
300
327
  - **`agentClient`**: Determines which adapter is used for skill deployment.
328
+ - **`evaluator`**: Opt-in independent reviewer. When `true`, the validation stage launches the `reap-evaluate` subagent as an advisor (read-only, qualitative-only). Default `false` keeps validation byte-identical to pre-gen-066 behaviour. See [Evaluator Agent](#evaluator-agent-opt-in) above.
301
329
 
302
330
  ## Upgrading from v0.15 [↗](https://reap.cc/docs/migration-guide)
303
331
 
package/RELEASE_NOTICE.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Release Notices
2
2
 
3
+ ## v0.16.6
4
+ ### en
5
+ Evaluator Agent integration (opt-in `evaluator: true`): independent `reap-evaluate` subagent runs during validation and fitness phases as an advisor. High-severity concerns automatically abort cruise mode for human review.
6
+ ### ko
7
+ Evaluator Agent 통합 (opt-in `evaluator: true`): `reap-evaluate` 서브에이전트가 validation/fitness 단계에서 독립 검토자로 실행됨 (advisor 모델). high-severity concern 발생 시 cruise mode 자동 중단.
8
+
3
9
  ## v0.16.4
4
10
  ### en
5
11
  Restore missing npm metadata (license, author, repository, homepage, keywords). Fix GitHub Releases showing empty release notes.
package/dist/cli/index.js CHANGED
@@ -8984,6 +8984,116 @@ function buildBasePrompt(knowledge, paths, state, cruiseCount, clarityResult, co
8984
8984
  return lines.join(`
8985
8985
  `);
8986
8986
  }
8987
+ function buildEvaluatorPrompt(knowledge, paths, state, opts) {
8988
+ const lines = [];
8989
+ const isMerge = state?.type === "merge";
8990
+ lines.push(`## Evaluator Invocation — ${opts.stage} stage`);
8991
+ lines.push("");
8992
+ if (opts.stage === "validation") {
8993
+ lines.push("You are being invoked during the **validation** stage of a REAP generation. " + "The builder (reap-evolve) has completed implementation and run validation checks. " + "Your role is independent verification: confirm the build is sound, tests pass, " + "completion criteria from 02-planning.md are met, and the code changes follow " + "genome conventions. Surface any concern the builder may have missed.");
8994
+ } else {
8995
+ lines.push("You are being invoked during the **fitness** phase of completion. " + "Assess the generation against the 6 fitness dimensions in your agent definition " + "(goal achievement, code quality, regression safety, artifact quality, vision alignment, " + "cross-generation coherence). Cross-reference with vision goals and recent lineage.");
8996
+ }
8997
+ lines.push("");
8998
+ lines.push("## Current Generation");
8999
+ if (state) {
9000
+ lines.push(`- ID: ${state.id}`);
9001
+ lines.push(`- Type: ${state.type}`);
9002
+ lines.push(`- Goal: ${state.goal}`);
9003
+ lines.push(`- Stage: ${state.stage}`);
9004
+ if (isMerge) {
9005
+ lines.push(`- Parents: ${state.parents.join(", ")}`);
9006
+ if (state.commonAncestor)
9007
+ lines.push(`- Common Ancestor: ${state.commonAncestor}`);
9008
+ }
9009
+ } else {
9010
+ lines.push("- (no active generation — abort and report to the user)");
9011
+ }
9012
+ lines.push("");
9013
+ lines.push("## Artifacts to Read");
9014
+ lines.push("");
9015
+ if (isMerge) {
9016
+ lines.push(`- ${paths.artifact("01-detect.md")}`);
9017
+ lines.push(`- ${paths.artifact("02-mate.md")}`);
9018
+ lines.push(`- ${paths.artifact("03-merge.md")}`);
9019
+ lines.push(`- ${paths.artifact("04-reconcile.md")}`);
9020
+ lines.push(`- ${paths.artifact("05-validation.md")}`);
9021
+ } else {
9022
+ lines.push(`- ${paths.artifact("01-learning.md")}`);
9023
+ lines.push(`- ${paths.artifact("02-planning.md")}`);
9024
+ lines.push(`- ${paths.artifact("03-implementation.md")}`);
9025
+ lines.push(`- ${paths.artifact("04-validation.md")}`);
9026
+ }
9027
+ lines.push("");
9028
+ if (knowledge.visionGoals) {
9029
+ lines.push("## Vision Goals (current)");
9030
+ lines.push(knowledge.visionGoals);
9031
+ lines.push("");
9032
+ }
9033
+ if (knowledge.memoryShortterm || knowledge.memoryMidterm) {
9034
+ lines.push("## Memory");
9035
+ if (knowledge.memoryShortterm) {
9036
+ lines.push("### Shortterm (1-2 sessions)");
9037
+ lines.push(knowledge.memoryShortterm);
9038
+ lines.push("");
9039
+ }
9040
+ if (knowledge.memoryMidterm) {
9041
+ lines.push("### Midterm (multi-generation)");
9042
+ lines.push(knowledge.memoryMidterm);
9043
+ lines.push("");
9044
+ }
9045
+ }
9046
+ lines.push("## Verification Tasks");
9047
+ lines.push("");
9048
+ if (opts.stage === "validation") {
9049
+ lines.push("1. Run `npm run typecheck` (or the project's typecheck command) and record the result.");
9050
+ lines.push("2. Run `npm run build` (or the project's build command) and record the result.");
9051
+ lines.push("3. Run the full test suite (unit/e2e/scenario as defined by the project) and record each.");
9052
+ lines.push("4. Read 02-planning.md and verify each completion criterion against the implementation + validation artifacts.");
9053
+ lines.push("5. Read `git diff` against the parent commit and check for genome convention compliance.");
9054
+ lines.push('6. Check 04-validation.md for sycophancy red flags ("it will probably pass", "it passed before").');
9055
+ lines.push("");
9056
+ } else {
9057
+ lines.push("1. Read all completed artifacts and validate goal achievement.");
9058
+ lines.push("2. Cross-reference the implementation against genome conventions (application.md, evolution.md).");
9059
+ lines.push("3. Run the test suite and confirm no regression.");
9060
+ lines.push("4. Compare this generation's contribution against vision/goals.md and recent lineage.");
9061
+ lines.push("5. Assess each of the 6 fitness dimensions qualitatively (no scores).");
9062
+ lines.push("");
9063
+ }
9064
+ lines.push("## Output Format");
9065
+ lines.push("");
9066
+ lines.push("Apply the escalation matrix from your agent definition:");
9067
+ lines.push("");
9068
+ lines.push("| Confidence | Impact | Action |");
9069
+ lines.push("| --- | --- | --- |");
9070
+ lines.push("| High | Low | Direct judgment |");
9071
+ lines.push("| High | High | Escalate with judgment |");
9072
+ lines.push("| Low | Any | Escalate without judgment (facts only) |");
9073
+ lines.push("");
9074
+ lines.push("Structure your reply as:");
9075
+ lines.push("- **Summary** (1-2 sentences)");
9076
+ lines.push("- **Verification results** (typecheck / build / tests / criteria)");
9077
+ lines.push("- **Concerns** (if any — call out the severity)");
9078
+ lines.push("- **Recommendation** (per the matrix)");
9079
+ lines.push("");
9080
+ lines.push("## HARD-GATE — Evaluator Constraints");
9081
+ lines.push("");
9082
+ lines.push("- You MUST NOT write, edit, or create any source files. Use Read/Grep/Glob/Bash only.");
9083
+ lines.push("- You MUST NOT run git commands that modify state (`git commit`, `git push`, `git checkout`, `git reset`).");
9084
+ lines.push("- You MUST NOT run `reap run` commands — the lifecycle is the builder's responsibility.");
9085
+ lines.push("- You MUST NOT produce numerical scores, ratings, or percentages (Goodhart's Law).");
9086
+ lines.push("- Your verdict is an **advisor recommendation**, not a binding judgment. The builder owns the lifecycle verdict; the human owns final fitness.");
9087
+ lines.push("");
9088
+ lines.push("## If You Cannot Proceed");
9089
+ lines.push("");
9090
+ lines.push("If you cannot complete verification (missing tools, broken state, ambiguous artifacts), " + "report the obstacle in your reply with enough context for the human to act. Do not block " + "the builder's lifecycle — the builder will continue validation if you cannot.");
9091
+ lines.push("");
9092
+ lines.push("## Project");
9093
+ lines.push(`Path: ${paths.root}`);
9094
+ return lines.join(`
9095
+ `);
9096
+ }
8987
9097
 
8988
9098
  // src/core/dump-state-sync.ts
8989
9099
  var DUMP_COMMANDS = new Set([
@@ -10604,7 +10714,7 @@ async function execute6() {
10604
10714
  }
10605
10715
 
10606
10716
  // src/cli/commands/run/index.ts
10607
- var import_yaml17 = __toESM(require_dist(), 1);
10717
+ var import_yaml18 = __toESM(require_dist(), 1);
10608
10718
  init_fs();
10609
10719
  init_integrity();
10610
10720
 
@@ -11865,6 +11975,10 @@ async function execute10(paths, phase) {
11865
11975
  }
11866
11976
  }
11867
11977
 
11978
+ // src/cli/commands/run/validation.ts
11979
+ var import_yaml11 = __toESM(require_dist(), 1);
11980
+ init_fs();
11981
+
11868
11982
  // src/core/artifact-check.ts
11869
11983
  init_fs();
11870
11984
  var PRE_VALIDATION_NORMAL = {
@@ -11899,7 +12013,7 @@ function isUnfilled(content) {
11899
12013
  }
11900
12014
 
11901
12015
  // src/cli/commands/run/validation.ts
11902
- async function execute11(paths, phase) {
12016
+ async function execute11(paths, phase, extra) {
11903
12017
  const gm = new GenerationManager(paths);
11904
12018
  const state = await gm.current();
11905
12019
  if (!state)
@@ -11908,6 +12022,64 @@ async function execute11(paths, phase) {
11908
12022
  emitError("validation", `Current stage is '${state.stage}', not 'validation'.`);
11909
12023
  const isMerge = state.type === "merge";
11910
12024
  const s = state;
12025
+ if (phase === "report-evaluator") {
12026
+ let severity;
12027
+ let summary;
12028
+ if (extra) {
12029
+ try {
12030
+ const parsed = JSON.parse(extra);
12031
+ severity = parsed.severity;
12032
+ summary = parsed.summary;
12033
+ } catch {
12034
+ emitError("validation", "report-evaluator: failed to parse options. Expected --severity and --summary.");
12035
+ }
12036
+ }
12037
+ if (!severity) {
12038
+ emitError("validation", "report-evaluator requires --severity <high|low|none>.");
12039
+ }
12040
+ const sev = severity.toLowerCase();
12041
+ if (sev === "none") {
12042
+ emitOutput({
12043
+ status: "ok",
12044
+ command: "validation",
12045
+ phase: "report-evaluator",
12046
+ completed: ["gate", "noop"],
12047
+ context: { id: s.id, severity: "none" },
12048
+ message: "Evaluator reported no concern — state unchanged."
12049
+ });
12050
+ return;
12051
+ }
12052
+ if (sev !== "high" && sev !== "low") {
12053
+ emitError("validation", `report-evaluator: invalid severity '${severity}'. Use high, low, or none.`);
12054
+ }
12055
+ if (!summary || summary.trim().length === 0) {
12056
+ emitError("validation", 'report-evaluator requires --summary "<one-line description>".');
12057
+ }
12058
+ const concern = {
12059
+ stage: "validation",
12060
+ severity: sev,
12061
+ summary: summary.trim(),
12062
+ recordedAt: new Date().toISOString()
12063
+ };
12064
+ if (!s.evaluatorConcerns)
12065
+ s.evaluatorConcerns = [];
12066
+ s.evaluatorConcerns.push(concern);
12067
+ await gm.save(s);
12068
+ emitOutput({
12069
+ status: "ok",
12070
+ command: "validation",
12071
+ phase: "report-evaluator",
12072
+ completed: ["gate", "concern-recorded"],
12073
+ context: {
12074
+ id: s.id,
12075
+ severity: concern.severity,
12076
+ summary: concern.summary,
12077
+ total: s.evaluatorConcerns.length
12078
+ },
12079
+ message: `Evaluator concern recorded (severity=${concern.severity}). Total: ${s.evaluatorConcerns.length}.`
12080
+ });
12081
+ return;
12082
+ }
11911
12083
  if (!phase || phase === "work") {
11912
12084
  verifyTransition("validation", s, "validation:entry");
11913
12085
  await copyArtifactTemplate("validation", paths.artifact, isMerge);
@@ -11944,48 +12116,92 @@ async function execute11(paths, phase) {
11944
12116
  });
11945
12117
  return;
11946
12118
  }
12119
+ const basePromptLines = [
12120
+ "## Validation Stage",
12121
+ "",
12122
+ "### HARD-GATE:",
12123
+ "- Do NOT declare 'pass' without running the validation commands.",
12124
+ "- Do NOT reuse results from a previous run — execute them FRESH.",
12125
+ "- 'It will probably pass' is NOT validation.",
12126
+ "",
12127
+ "### Steps:",
12128
+ "1. **TypeCheck**: Run `npm run typecheck` (or project's typecheck command). Record result.",
12129
+ "2. **Build**: Run `npm run build` (or project's build command). Record result.",
12130
+ "3. **Tests**: Run ALL test commands the project has (e.g., e2e scripts). Record each result.",
12131
+ "4. **Completion Criteria**: Verify EACH criterion from 02-planning.md one by one.",
12132
+ "5. **Minor Fix** (trivial issues only, under 5 minutes): Fix and re-run the failed command.",
12133
+ "6. **Verdict**: Determine pass / partial / fail.",
12134
+ "",
12135
+ "### Red Flags (sycophancy prevention):",
12136
+ "- 'It will probably pass' → Run it.",
12137
+ "- 'It passed before' → Run it again.",
12138
+ "- 'It\\'s trivial, no need to test' → Test it anyway.",
12139
+ "",
12140
+ "### Verdict Criteria:",
12141
+ "- **pass**: All checks pass, all completion criteria met.",
12142
+ "- **partial**: Minor issues remain but core functionality works. Document what's incomplete.",
12143
+ "- **fail**: Critical failures. Must regress to implementation.",
12144
+ "",
12145
+ `### Artifact: Write \`.reap/life/${isMerge ? "05" : "04"}-validation.md\` progressively (after each command).`,
12146
+ "",
12147
+ "If pass/partial: reap run validation --phase complete",
12148
+ "If fail: reap run back to regress"
12149
+ ];
12150
+ const configContent = await readTextFile(paths.config);
12151
+ const config = configContent ? import_yaml11.default.parse(configContent) : null;
12152
+ const evaluatorEnabled = config?.evaluator === true;
12153
+ const context = {
12154
+ id: s.id,
12155
+ goal: s.goal,
12156
+ type: s.type,
12157
+ artifactPath: paths.artifact(isMerge ? "05-validation.md" : "04-validation.md"),
12158
+ evaluator: { enabled: evaluatorEnabled }
12159
+ };
12160
+ const promptLines = [...basePromptLines];
12161
+ if (evaluatorEnabled) {
12162
+ const knowledge = await loadReapKnowledge(paths);
12163
+ const evaluatorPrompt = buildEvaluatorPrompt(knowledge, paths, s, { stage: "validation" });
12164
+ context.evaluator.prompt = evaluatorPrompt;
12165
+ promptLines.push("");
12166
+ promptLines.push("### Evaluator Subagent Invocation (opt-in via `evaluator: true`)");
12167
+ promptLines.push("");
12168
+ promptLines.push("Before declaring your verdict, launch an independent reviewer using the Agent tool:");
12169
+ promptLines.push("");
12170
+ promptLines.push("- subagent_type: `reap-evaluate`");
12171
+ promptLines.push("- description: independent validation review");
12172
+ promptLines.push("- prompt: the `evaluator.prompt` value from the context above");
12173
+ promptLines.push("");
12174
+ promptLines.push("**Advisor model** — the evaluator's assessment is a recommendation, not a verdict:");
12175
+ promptLines.push("- You (the builder) decide the final pass/partial/fail verdict.");
12176
+ promptLines.push("- Surface every evaluator concern to the user in your validation report, even if you disagree.");
12177
+ promptLines.push("- If the evaluator escalates a high-impact concern, lean toward `partial` and document the concern in 04-validation.md.");
12178
+ promptLines.push("");
12179
+ promptLines.push("**Persist the verdict for the fitness phase (gen-067)**:");
12180
+ promptLines.push("");
12181
+ promptLines.push("After receiving the evaluator's reply, record the outcome on the generation state so the");
12182
+ promptLines.push("subsequent fitness phase can act on it (cruise mode auto-abort, evaluator concern surfacing):");
12183
+ promptLines.push("");
12184
+ promptLines.push("- High-impact escalation:");
12185
+ promptLines.push(' `reap run validation --phase report-evaluator --severity high --summary "<one-line description>"`');
12186
+ promptLines.push("- Low-impact concern (informational):");
12187
+ promptLines.push(' `reap run validation --phase report-evaluator --severity low --summary "<one-line description>"`');
12188
+ promptLines.push("- Clean review (no concern):");
12189
+ promptLines.push(' `reap run validation --phase report-evaluator --severity none --summary ""`');
12190
+ promptLines.push("");
12191
+ promptLines.push("This call does NOT advance the lifecycle — it only appends to `state.evaluatorConcerns`.");
12192
+ promptLines.push("");
12193
+ promptLines.push("**Fallback** — if the evaluator subagent fails (tool unavailable, model error, malformed reply):");
12194
+ promptLines.push("- Tell the user the evaluator could not run and why.");
12195
+ promptLines.push("- Continue normal validation. The evaluator is opt-in advice, not a gate.");
12196
+ promptLines.push("- Skip the `report-evaluator` CLI call (no concern was generated).");
12197
+ }
11947
12198
  emitOutput({
11948
12199
  status: "prompt",
11949
12200
  command: "validation",
11950
12201
  phase: "work",
11951
12202
  completed: ["gate", "artifact-check"],
11952
- context: {
11953
- id: s.id,
11954
- goal: s.goal,
11955
- type: s.type,
11956
- artifactPath: paths.artifact(isMerge ? "05-validation.md" : "04-validation.md")
11957
- },
11958
- prompt: [
11959
- "## Validation Stage",
11960
- "",
11961
- "### HARD-GATE:",
11962
- "- Do NOT declare 'pass' without running the validation commands.",
11963
- "- Do NOT reuse results from a previous run — execute them FRESH.",
11964
- "- 'It will probably pass' is NOT validation.",
11965
- "",
11966
- "### Steps:",
11967
- "1. **TypeCheck**: Run `npm run typecheck` (or project's typecheck command). Record result.",
11968
- "2. **Build**: Run `npm run build` (or project's build command). Record result.",
11969
- "3. **Tests**: Run ALL test commands the project has (e.g., e2e scripts). Record each result.",
11970
- "4. **Completion Criteria**: Verify EACH criterion from 02-planning.md one by one.",
11971
- "5. **Minor Fix** (trivial issues only, under 5 minutes): Fix and re-run the failed command.",
11972
- "6. **Verdict**: Determine pass / partial / fail.",
11973
- "",
11974
- "### Red Flags (sycophancy prevention):",
11975
- "- 'It will probably pass' → Run it.",
11976
- "- 'It passed before' → Run it again.",
11977
- "- 'It\\'s trivial, no need to test' → Test it anyway.",
11978
- "",
11979
- "### Verdict Criteria:",
11980
- "- **pass**: All checks pass, all completion criteria met.",
11981
- "- **partial**: Minor issues remain but core functionality works. Document what's incomplete.",
11982
- "- **fail**: Critical failures. Must regress to implementation.",
11983
- "",
11984
- `### Artifact: Write \`.reap/life/${isMerge ? "05" : "04"}-validation.md\` progressively (after each command).`,
11985
- "",
11986
- "If pass/partial: reap run validation --phase complete",
11987
- "If fail: reap run back to regress"
11988
- ].join(`
12203
+ context,
12204
+ prompt: promptLines.join(`
11989
12205
  `),
11990
12206
  nextCommand: "reap run validation --phase complete"
11991
12207
  });
@@ -12013,13 +12229,13 @@ init_fs();
12013
12229
 
12014
12230
  // src/core/archive.ts
12015
12231
  init_fs();
12016
- var import_yaml12 = __toESM(require_dist(), 1);
12232
+ var import_yaml13 = __toESM(require_dist(), 1);
12017
12233
  import { join as join16 } from "path";
12018
12234
  import { readdir as readdir13, rm as rm4, unlink } from "fs/promises";
12019
12235
 
12020
12236
  // src/core/compression.ts
12021
12237
  init_fs();
12022
- var import_yaml11 = __toESM(require_dist(), 1);
12238
+ var import_yaml12 = __toESM(require_dist(), 1);
12023
12239
  import { readdir as readdir12, rm as rm3 } from "fs/promises";
12024
12240
  import { join as join15 } from "path";
12025
12241
  var LEVEL1_THRESHOLD = 20;
@@ -12052,7 +12268,7 @@ async function compressLineage(lineageDir) {
12052
12268
  let meta = { id: dirName, type: "unknown", goal: "", parents: [] };
12053
12269
  if (metaContent) {
12054
12270
  try {
12055
- meta = import_yaml11.default.parse(metaContent);
12271
+ meta = import_yaml12.default.parse(metaContent);
12056
12272
  } catch {}
12057
12273
  }
12058
12274
  const completion = await readTextFile(join15(dirPath, "05-completion.md")) ?? "";
@@ -12107,7 +12323,7 @@ async function compressToEpoch(lineageDir) {
12107
12323
  let meta = { id: file.replace(".md", ""), type: "unknown", goal: "", parents: [] };
12108
12324
  if (fmMatch) {
12109
12325
  try {
12110
- const parsed = import_yaml11.default.parse(fmMatch[1]);
12326
+ const parsed = import_yaml12.default.parse(fmMatch[1]);
12111
12327
  meta = { ...meta, ...parsed };
12112
12328
  } catch {}
12113
12329
  }
@@ -12124,7 +12340,7 @@ async function compressToEpoch(lineageDir) {
12124
12340
  if (!metaContent)
12125
12341
  continue;
12126
12342
  try {
12127
- const m = import_yaml11.default.parse(metaContent);
12343
+ const m = import_yaml12.default.parse(metaContent);
12128
12344
  if (m.parents)
12129
12345
  m.parents.forEach((p) => dirParents.add(p));
12130
12346
  } catch {}
@@ -12137,7 +12353,7 @@ async function compressToEpoch(lineageDir) {
12137
12353
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
12138
12354
  if (fmMatch) {
12139
12355
  try {
12140
- const parsed = import_yaml11.default.parse(fmMatch[1]);
12356
+ const parsed = import_yaml12.default.parse(fmMatch[1]);
12141
12357
  const lastId = parsed.lastGeneration;
12142
12358
  if (lastId)
12143
12359
  dirParents.add(lastId);
@@ -12219,7 +12435,7 @@ async function writeArchive(paths, state, archiveDir, extraMeta) {
12219
12435
  timeline: state.timeline,
12220
12436
  ...extraMeta
12221
12437
  };
12222
- await writeTextFile(join16(archiveDir, "meta.yml"), import_yaml12.default.stringify(meta));
12438
+ await writeTextFile(join16(archiveDir, "meta.yml"), import_yaml13.default.stringify(meta));
12223
12439
  for (const entry of lifeEntries) {
12224
12440
  if (entry === "backlog")
12225
12441
  continue;
@@ -12544,7 +12760,7 @@ function tokenize(text) {
12544
12760
 
12545
12761
  // src/core/cruise.ts
12546
12762
  init_fs();
12547
- var import_yaml13 = __toESM(require_dist(), 1);
12763
+ var import_yaml14 = __toESM(require_dist(), 1);
12548
12764
  function parseCruiseCount(config) {
12549
12765
  if (!config.cruiseCount)
12550
12766
  return null;
@@ -12557,30 +12773,38 @@ async function advanceCruise(configPath) {
12557
12773
  const content = await readTextFile(configPath);
12558
12774
  if (!content)
12559
12775
  return false;
12560
- const config = import_yaml13.default.parse(content);
12776
+ const config = import_yaml14.default.parse(content);
12561
12777
  const cruise = parseCruiseCount(config);
12562
12778
  if (!cruise)
12563
12779
  return false;
12564
12780
  if (cruise.current >= cruise.total) {
12565
12781
  delete config.cruiseCount;
12566
- await writeTextFile(configPath, import_yaml13.default.stringify(config));
12782
+ await writeTextFile(configPath, import_yaml14.default.stringify(config));
12567
12783
  return false;
12568
12784
  }
12569
12785
  config.cruiseCount = `${cruise.current + 1}/${cruise.total}`;
12570
- await writeTextFile(configPath, import_yaml13.default.stringify(config));
12786
+ await writeTextFile(configPath, import_yaml14.default.stringify(config));
12571
12787
  return true;
12572
12788
  }
12789
+ async function clearCruise(configPath) {
12790
+ const content = await readTextFile(configPath);
12791
+ if (!content)
12792
+ return;
12793
+ const config = import_yaml14.default.parse(content);
12794
+ delete config.cruiseCount;
12795
+ await writeTextFile(configPath, import_yaml14.default.stringify(config));
12796
+ }
12573
12797
  async function setCruise(configPath, total) {
12574
12798
  const content = await readTextFile(configPath);
12575
12799
  if (!content)
12576
12800
  return;
12577
- const config = import_yaml13.default.parse(content);
12801
+ const config = import_yaml14.default.parse(content);
12578
12802
  config.cruiseCount = `1/${total}`;
12579
- await writeTextFile(configPath, import_yaml13.default.stringify(config));
12803
+ await writeTextFile(configPath, import_yaml14.default.stringify(config));
12580
12804
  }
12581
12805
 
12582
12806
  // src/cli/commands/run/completion.ts
12583
- var import_yaml14 = __toESM(require_dist(), 1);
12807
+ var import_yaml15 = __toESM(require_dist(), 1);
12584
12808
  async function execute12(paths, phase, feedback) {
12585
12809
  const gm = new GenerationManager(paths);
12586
12810
  const state = await gm.current();
@@ -12669,52 +12893,145 @@ async function execute12(paths, phase, feedback) {
12669
12893
  } else {
12670
12894
  verifyTransition("completion", s, "completion:fitness");
12671
12895
  const configContent = await readTextFile(paths.config);
12672
- const config = configContent ? import_yaml14.default.parse(configContent) : null;
12896
+ const config = configContent ? import_yaml15.default.parse(configContent) : null;
12673
12897
  const cruise = config ? parseCruiseCount(config) : null;
12898
+ const evaluatorEnabled = config?.evaluator === true;
12674
12899
  setTransitionNonces(s, "completion:fitness");
12675
12900
  await gm.save(s);
12901
+ const highConcerns = (s.evaluatorConcerns ?? []).filter((c) => c.severity === "high");
12902
+ let fitnessEvaluatorPrompt;
12903
+ if (evaluatorEnabled) {
12904
+ const knowledge = await loadReapKnowledge(paths);
12905
+ fitnessEvaluatorPrompt = buildEvaluatorPrompt(knowledge, paths, s, { stage: "fitness" });
12906
+ }
12907
+ const evaluatorSection = [];
12908
+ if (evaluatorEnabled) {
12909
+ evaluatorSection.push("");
12910
+ evaluatorSection.push("### Evaluator Subagent Invocation (opt-in via `evaluator: true`)");
12911
+ evaluatorSection.push("");
12912
+ evaluatorSection.push("Before composing the final fitness feedback, launch the independent reviewer using the Agent tool:");
12913
+ evaluatorSection.push("");
12914
+ evaluatorSection.push("- subagent_type: `reap-evaluate`");
12915
+ evaluatorSection.push("- description: independent fitness assessment");
12916
+ evaluatorSection.push("- prompt: the `evaluator.prompt` value from the context above");
12917
+ evaluatorSection.push("");
12918
+ evaluatorSection.push("The evaluator scores the generation along the 6 fitness dimensions (qualitative — no numeric scores).");
12919
+ evaluatorSection.push("Surface every concern to the user in your fitness summary; the human owns the final feedback.");
12920
+ evaluatorSection.push("");
12921
+ evaluatorSection.push("**Fallback** — if the evaluator subagent fails, document the failure and continue. Fitness phase is not gated on the evaluator.");
12922
+ }
12923
+ const priorConcernsSection = [];
12924
+ if ((s.evaluatorConcerns ?? []).length > 0) {
12925
+ priorConcernsSection.push("");
12926
+ priorConcernsSection.push("### Prior Evaluator Concerns (carried from earlier stages)");
12927
+ priorConcernsSection.push("");
12928
+ for (const c of s.evaluatorConcerns) {
12929
+ priorConcernsSection.push(`- [${c.severity}] (${c.stage}) ${c.summary}`);
12930
+ }
12931
+ priorConcernsSection.push("");
12932
+ priorConcernsSection.push("Surface each of the above to the user with your fitness summary.");
12933
+ }
12934
+ if (cruise && highConcerns.length > 0) {
12935
+ await clearCruise(paths.config);
12936
+ const fallbackPrompt = [
12937
+ "## Cruise Aborted by Evaluator Concern",
12938
+ "",
12939
+ "Cruise mode has been **disengaged** because the evaluator raised a high-impact concern:",
12940
+ ""
12941
+ ];
12942
+ for (const c of highConcerns) {
12943
+ fallbackPrompt.push(`- [${c.severity}] (${c.stage}) ${c.summary}`);
12944
+ }
12945
+ fallbackPrompt.push("");
12946
+ fallbackPrompt.push("The remaining cruise generations will NOT auto-start. This fitness phase now follows the supervised flow:");
12947
+ fallbackPrompt.push("");
12948
+ fallbackPrompt.push("1. Present the concern(s) above to the human together with a summary of this generation.");
12949
+ fallbackPrompt.push("2. Wait for the human's decision (continue, override, abort generation, etc.).");
12950
+ fallbackPrompt.push('3. Submit: `reap run completion --phase fitness --feedback "<human feedback>"`');
12951
+ fallbackPrompt.push("");
12952
+ fallbackPrompt.push("Cruise can be resumed manually with `reap cruise <N>` once the concern is resolved.");
12953
+ fallbackPrompt.push(...evaluatorSection);
12954
+ emitOutput({
12955
+ status: "prompt",
12956
+ command: "completion",
12957
+ phase: "fitness",
12958
+ completed: ["gate", "reflect", "cruise-aborted"],
12959
+ context: {
12960
+ id: s.id,
12961
+ goal: s.goal,
12962
+ cruiseMode: false,
12963
+ cruiseAborted: true,
12964
+ previousCruiseCount: config.cruiseCount,
12965
+ evaluatorConcerns: s.evaluatorConcerns,
12966
+ evaluator: evaluatorEnabled ? { enabled: true, prompt: fitnessEvaluatorPrompt } : { enabled: false }
12967
+ },
12968
+ prompt: fallbackPrompt.join(`
12969
+ `),
12970
+ nextCommand: "reap run completion --phase fitness"
12971
+ });
12972
+ return;
12973
+ }
12676
12974
  if (cruise) {
12975
+ const cruisePrompt = [
12976
+ "## Completion — Fitness Phase (Cruise Mode)",
12977
+ "",
12978
+ `Cruise: ${config.cruiseCount}`,
12979
+ "",
12980
+ "### Self-Assessment (not self-fitness, but metacognition):",
12981
+ "1. Did this generation proceed as expected?",
12982
+ "2. Are there uncertain areas or risks?",
12983
+ "3. Are there items that need human confirmation?",
12984
+ "",
12985
+ 'High confidence → auto-proceed: reap run completion --phase fitness --feedback "self-assessment: OK"',
12986
+ "Uncertain/risky → stop cruise and request human feedback"
12987
+ ];
12988
+ cruisePrompt.push(...priorConcernsSection);
12989
+ cruisePrompt.push(...evaluatorSection);
12677
12990
  emitOutput({
12678
12991
  status: "prompt",
12679
12992
  command: "completion",
12680
12993
  phase: "fitness",
12681
12994
  completed: ["gate", "reflect"],
12682
- context: { id: s.id, goal: s.goal, cruiseMode: true, cruiseCount: config.cruiseCount },
12683
- prompt: [
12684
- "## Completion — Fitness Phase (Cruise Mode)",
12685
- "",
12686
- `Cruise: ${config.cruiseCount}`,
12687
- "",
12688
- "### Self-Assessment (not self-fitness, but metacognition):",
12689
- "1. Did this generation proceed as expected?",
12690
- "2. Are there uncertain areas or risks?",
12691
- "3. Are there items that need human confirmation?",
12692
- "",
12693
- 'High confidence → auto-proceed: reap run completion --phase fitness --feedback "self-assessment: OK"',
12694
- "Uncertain/risky → stop cruise and request human feedback"
12695
- ].join(`
12995
+ context: {
12996
+ id: s.id,
12997
+ goal: s.goal,
12998
+ cruiseMode: true,
12999
+ cruiseCount: config.cruiseCount,
13000
+ evaluatorConcerns: s.evaluatorConcerns ?? [],
13001
+ evaluator: evaluatorEnabled ? { enabled: true, prompt: fitnessEvaluatorPrompt } : { enabled: false }
13002
+ },
13003
+ prompt: cruisePrompt.join(`
12696
13004
  `),
12697
13005
  nextCommand: "reap run completion --phase fitness"
12698
13006
  });
12699
13007
  } else {
13008
+ const supervisedPrompt = [
13009
+ "## Completion — Fitness Phase",
13010
+ "",
13011
+ "Collect feedback from the human.",
13012
+ "",
13013
+ "Present to the human:",
13014
+ "1. Summary of what was done in this generation",
13015
+ "2. What went well / areas for improvement",
13016
+ "3. Suggested next direction",
13017
+ "",
13018
+ 'Submit: reap run completion --phase fitness --feedback "human feedback here"'
13019
+ ];
13020
+ supervisedPrompt.push(...priorConcernsSection);
13021
+ supervisedPrompt.push(...evaluatorSection);
12700
13022
  emitOutput({
12701
13023
  status: "prompt",
12702
13024
  command: "completion",
12703
13025
  phase: "fitness",
12704
13026
  completed: ["gate", "reflect"],
12705
- context: { id: s.id, goal: s.goal, cruiseMode: false },
12706
- prompt: [
12707
- "## Completion — Fitness Phase",
12708
- "",
12709
- "Collect feedback from the human.",
12710
- "",
12711
- "Present to the human:",
12712
- "1. Summary of what was done in this generation",
12713
- "2. What went well / areas for improvement",
12714
- "3. Suggested next direction",
12715
- "",
12716
- 'Submit: reap run completion --phase fitness --feedback "human feedback here"'
12717
- ].join(`
13027
+ context: {
13028
+ id: s.id,
13029
+ goal: s.goal,
13030
+ cruiseMode: false,
13031
+ evaluatorConcerns: s.evaluatorConcerns ?? [],
13032
+ evaluator: evaluatorEnabled ? { enabled: true, prompt: fitnessEvaluatorPrompt } : { enabled: false }
13033
+ },
13034
+ prompt: supervisedPrompt.join(`
12718
13035
  `),
12719
13036
  nextCommand: "reap run completion --phase fitness"
12720
13037
  });
@@ -12726,7 +13043,7 @@ async function execute12(paths, phase, feedback) {
12726
13043
  const fitnessFeedback = s.fitnessFeedback;
12727
13044
  const visionGoals = await readTextFile(paths.visionGoals);
12728
13045
  const configContent = await readTextFile(paths.config);
12729
- const config = configContent ? import_yaml14.default.parse(configContent) : null;
13046
+ const config = configContent ? import_yaml15.default.parse(configContent) : null;
12730
13047
  const maturity = detectMaturity(s.type, config?.cruiseCount);
12731
13048
  const generationCount = await gm.countLineage();
12732
13049
  setTransitionNonces(s, "completion:adapt");
@@ -12859,7 +13176,7 @@ async function execute12(paths, phase, feedback) {
12859
13176
  }
12860
13177
 
12861
13178
  // src/cli/commands/run/evolve.ts
12862
- var import_yaml15 = __toESM(require_dist(), 1);
13179
+ var import_yaml16 = __toESM(require_dist(), 1);
12863
13180
  import { readdir as readdir14 } from "fs/promises";
12864
13181
  init_fs();
12865
13182
  async function collectClarityInput(paths, generationType) {
@@ -12896,7 +13213,7 @@ async function execute13(paths, _phase) {
12896
13213
  const gm = new GenerationManager(paths);
12897
13214
  const state = await gm.current();
12898
13215
  const configContent = await readTextFile(paths.config);
12899
- const config = configContent ? import_yaml15.default.parse(configContent) : null;
13216
+ const config = configContent ? import_yaml16.default.parse(configContent) : null;
12900
13217
  const autoSubagent = config?.autoSubagent ?? true;
12901
13218
  const cruise = config ? parseCruiseCount(config) : null;
12902
13219
  const generationType = state?.type ?? "normal";
@@ -13972,19 +14289,19 @@ async function execute24(paths, _phase, extra) {
13972
14289
 
13973
14290
  // src/cli/commands/run/report.ts
13974
14291
  init_fs();
13975
- var import_yaml16 = __toESM(require_dist(), 1);
14292
+ var import_yaml17 = __toESM(require_dist(), 1);
13976
14293
  async function execute25(paths, _phase) {
13977
14294
  let state = null;
13978
14295
  try {
13979
14296
  const raw = await readTextFile(paths.current);
13980
14297
  if (raw)
13981
- state = import_yaml16.default.parse(raw);
14298
+ state = import_yaml17.default.parse(raw);
13982
14299
  } catch {}
13983
14300
  let projectName = "unknown";
13984
14301
  try {
13985
14302
  const raw = await readTextFile(paths.config);
13986
14303
  if (raw) {
13987
- const config = import_yaml16.default.parse(raw);
14304
+ const config = import_yaml17.default.parse(raw);
13988
14305
  projectName = config.project ?? "unknown";
13989
14306
  }
13990
14307
  } catch {}
@@ -14081,13 +14398,16 @@ async function execute26(stage, options) {
14081
14398
  if (stage === "early-close") {
14082
14399
  extra = JSON.stringify({ reason: options.reason, sourceAction: options.sourceAction, deferTasks: options.deferTasks });
14083
14400
  }
14401
+ if (stage === "validation" && options.phase === "report-evaluator") {
14402
+ extra = JSON.stringify({ severity: options.severity, summary: options.summary });
14403
+ }
14084
14404
  try {
14085
14405
  await handler(paths, options.phase, extra);
14086
14406
  } catch (err) {
14087
14407
  try {
14088
14408
  const configContent = await readTextFile(paths.config);
14089
14409
  if (configContent) {
14090
- const config = import_yaml17.default.parse(configContent);
14410
+ const config = import_yaml18.default.parse(configContent);
14091
14411
  if (config.autoIssueReport !== false) {
14092
14412
  const cmd = `reap run ${stage}${options.phase ? ` --phase ${options.phase}` : ""}`;
14093
14413
  autoReport(cmd, err);
@@ -14230,7 +14550,7 @@ async function execute28(count) {
14230
14550
  }
14231
14551
 
14232
14552
  // src/cli/commands/install-skills.ts
14233
- var import_yaml18 = __toESM(require_dist(), 1);
14553
+ var import_yaml19 = __toESM(require_dist(), 1);
14234
14554
 
14235
14555
  // src/adapters/claude-code/install.ts
14236
14556
  init_fs();
@@ -14280,18 +14600,35 @@ async function installSkills(_projectRoot) {
14280
14600
  message: `Cleaned ${cleaned.length} stale skills, installed ${installed} skill files to ${targetDir}`
14281
14601
  });
14282
14602
  }
14283
- async function installAgents() {
14284
- const agentsDir = join20(homedir4(), ".claude", "agents");
14285
- await ensureDir(agentsDir);
14286
- const templateDir = __dirname2.includes("dist") ? join20(__dirname2, "..", "templates", "agents") : join20(__dirname2, "..", "..", "templates", "agents");
14603
+ var AGENT_PATTERN = /^reap-.+\.md$/;
14604
+ function agentsTemplateDir() {
14605
+ return __dirname2.includes("dist") ? join20(__dirname2, "..", "templates", "agents") : join20(__dirname2, "..", "..", "templates", "agents");
14606
+ }
14607
+ async function installAgents(home = homedir4()) {
14608
+ const targetDir = join20(home, ".claude", "agents");
14609
+ await ensureDir(targetDir);
14610
+ let cleaned = [];
14287
14611
  try {
14288
- const files = await readdir16(templateDir);
14289
- for (const file of files) {
14290
- if (file.endsWith(".md")) {
14291
- await cp2(join20(templateDir, file), join20(agentsDir, file));
14292
- }
14612
+ const existing = await readdir16(targetDir);
14613
+ cleaned = existing.filter((f) => AGENT_PATTERN.test(f));
14614
+ for (const file of cleaned) {
14615
+ await unlink2(join20(targetDir, file));
14616
+ }
14617
+ } catch {}
14618
+ let installed = 0;
14619
+ const files = [];
14620
+ const templateDir = agentsTemplateDir();
14621
+ try {
14622
+ const sources = await readdir16(templateDir);
14623
+ for (const file of sources) {
14624
+ if (!file.endsWith(".md"))
14625
+ continue;
14626
+ await cp2(join20(templateDir, file), join20(targetDir, file));
14627
+ files.push(file);
14628
+ installed++;
14293
14629
  }
14294
14630
  } catch {}
14631
+ return { cleaned, installed, files, targetDir };
14295
14632
  }
14296
14633
  async function installReapGuide() {
14297
14634
  const reapHome = join20(homedir4(), ".reap");
@@ -14354,6 +14691,7 @@ var claudeCodeAdapter = {
14354
14691
  },
14355
14692
  async registerSessionIntegration(_projectRoot) {
14356
14693
  await installSlashCommandsOnly();
14694
+ await installAgents();
14357
14695
  await registerSessionHooks();
14358
14696
  }
14359
14697
  };
@@ -14559,11 +14897,45 @@ async function installSlashCommands(home = homedir5()) {
14559
14897
  } catch {}
14560
14898
  return { cleaned, installed, targetDir };
14561
14899
  }
14900
+ var AGENT_PATTERN2 = /^reap-.+\.md$/;
14901
+ function agentsTemplateDir2() {
14902
+ return __dirname3.includes("dist") ? join21(__dirname3, "..", "templates", "agents") : join21(__dirname3, "..", "..", "templates", "agents");
14903
+ }
14904
+ function opencodeAgentsDir(home = homedir5()) {
14905
+ return join21(home, ".config", "opencode", "agent");
14906
+ }
14907
+ async function installAgents2(home = homedir5()) {
14908
+ const targetDir = opencodeAgentsDir(home);
14909
+ await ensureDir(targetDir);
14910
+ let cleaned = 0;
14911
+ try {
14912
+ const existing = await readdir17(targetDir);
14913
+ for (const file of existing) {
14914
+ if (AGENT_PATTERN2.test(file)) {
14915
+ await unlink3(join21(targetDir, file));
14916
+ cleaned++;
14917
+ }
14918
+ }
14919
+ } catch {}
14920
+ let installed = 0;
14921
+ const srcDir = agentsTemplateDir2();
14922
+ try {
14923
+ const sources = await readdir17(srcDir);
14924
+ for (const file of sources) {
14925
+ if (!file.endsWith(".md"))
14926
+ continue;
14927
+ await cp3(join21(srcDir, file), join21(targetDir, file));
14928
+ installed++;
14929
+ }
14930
+ } catch {}
14931
+ return { cleaned, installed, targetDir };
14932
+ }
14562
14933
  async function installSkills2(projectRoot) {
14563
14934
  await installPluginFile(projectRoot);
14564
14935
  const opencodeJsonAction = await ensureOpencodeJson(projectRoot);
14565
14936
  await installReapGuide2();
14566
14937
  const slashCommands = await installSlashCommands();
14938
+ const agents = await installAgents2();
14567
14939
  emitOutput({
14568
14940
  status: "ok",
14569
14941
  command: "install-skills",
@@ -14571,7 +14943,8 @@ async function installSkills2(projectRoot) {
14571
14943
  "install-plugin",
14572
14944
  "ensure-opencode-json",
14573
14945
  "install-reap-guide",
14574
- "install-slash-commands"
14946
+ "install-slash-commands",
14947
+ "install-agents"
14575
14948
  ],
14576
14949
  context: {
14577
14950
  agentClient: "opencode",
@@ -14581,15 +14954,21 @@ async function installSkills2(projectRoot) {
14581
14954
  cleaned: slashCommands.cleaned,
14582
14955
  installed: slashCommands.installed,
14583
14956
  targetDir: slashCommands.targetDir
14957
+ },
14958
+ agents: {
14959
+ cleaned: agents.cleaned,
14960
+ installed: agents.installed,
14961
+ targetDir: agents.targetDir
14584
14962
  }
14585
14963
  },
14586
- message: `OpenCode integration installed (opencode.json: ${opencodeJsonAction}, ` + `slash commands: ${slashCommands.installed} installed, ` + `${slashCommands.cleaned} cleaned).`
14964
+ message: `OpenCode integration installed (opencode.json: ${opencodeJsonAction}, ` + `slash commands: ${slashCommands.installed} installed, ` + `${slashCommands.cleaned} cleaned; ` + `agents: ${agents.installed} installed, ${agents.cleaned} cleaned).`
14587
14965
  });
14588
14966
  }
14589
14967
  async function registerSessionIntegration(projectRoot) {
14590
14968
  await installPluginFile(projectRoot);
14591
14969
  await ensureOpencodeJson(projectRoot);
14592
14970
  await installSlashCommands();
14971
+ await installAgents2();
14593
14972
  }
14594
14973
 
14595
14974
  // src/adapters/opencode/index.ts
@@ -14632,7 +15011,7 @@ async function execute29() {
14632
15011
  const raw = await readTextFile(paths.config);
14633
15012
  if (raw) {
14634
15013
  try {
14635
- const cfg = import_yaml18.default.parse(raw);
15014
+ const cfg = import_yaml19.default.parse(raw);
14636
15015
  agentClient = cfg.agentClient;
14637
15016
  } catch {}
14638
15017
  }
@@ -14642,7 +15021,7 @@ async function execute29() {
14642
15021
  }
14643
15022
 
14644
15023
  // src/cli/commands/fix.ts
14645
- var import_yaml19 = __toESM(require_dist(), 1);
15024
+ var import_yaml20 = __toESM(require_dist(), 1);
14646
15025
  import { mkdir as mkdir3, stat as stat4 } from "fs/promises";
14647
15026
  import { join as join22, dirname as dirname8 } from "path";
14648
15027
  import { fileURLToPath as fileURLToPath6 } from "url";
@@ -14694,7 +15073,7 @@ async function fixProject(projectRoot) {
14694
15073
  if (currentContent !== null) {
14695
15074
  if (currentContent.trim()) {
14696
15075
  try {
14697
- const state = import_yaml19.default.parse(currentContent);
15076
+ const state = import_yaml20.default.parse(currentContent);
14698
15077
  const allStages = [
14699
15078
  ...LIFECYCLE_STAGES,
14700
15079
  ...MERGE_STAGES
@@ -14761,7 +15140,7 @@ async function fixProject(projectRoot) {
14761
15140
  {
14762
15141
  const { ensureClaudeMd: ensureClaudeMd2 } = await Promise.resolve().then(() => (init_common(), exports_common));
14763
15142
  const configContent = await readTextFile(paths.config);
14764
- const projectName = configContent ? import_yaml19.default.parse(configContent)?.project ?? "my-project" : "my-project";
15143
+ const projectName = configContent ? import_yaml20.default.parse(configContent)?.project ?? "my-project" : "my-project";
14765
15144
  const action = await ensureClaudeMd2(paths.root, projectName);
14766
15145
  if (action !== "skipped") {
14767
15146
  fixed.push(`CLAUDE.md ${action} with REAP section`);
@@ -14810,7 +15189,7 @@ async function execute30(check) {
14810
15189
  }
14811
15190
 
14812
15191
  // src/cli/commands/destroy.ts
14813
- var import_yaml20 = __toESM(require_dist(), 1);
15192
+ var import_yaml21 = __toESM(require_dist(), 1);
14814
15193
  import { rm as rm6 } from "fs/promises";
14815
15194
  import { join as join23 } from "path";
14816
15195
  init_fs();
@@ -14821,7 +15200,7 @@ async function getProjectName(projectRoot) {
14821
15200
  const content = await readTextFile(paths.config);
14822
15201
  if (!content)
14823
15202
  return null;
14824
- const config = import_yaml20.default.parse(content);
15203
+ const config = import_yaml21.default.parse(content);
14825
15204
  return config.project ?? null;
14826
15205
  } catch {
14827
15206
  return null;
@@ -15069,7 +15448,7 @@ async function execute32(options) {
15069
15448
 
15070
15449
  // src/cli/commands/check-version.ts
15071
15450
  init_integrity();
15072
- var import_yaml21 = __toESM(require_dist(), 1);
15451
+ var import_yaml22 = __toESM(require_dist(), 1);
15073
15452
  import { execSync as execSync7 } from "child_process";
15074
15453
  import { readFileSync as readFileSync3 } from "fs";
15075
15454
  import { join as join26 } from "path";
@@ -15251,7 +15630,7 @@ async function execute33() {
15251
15630
  try {
15252
15631
  const configPath = join26(root, ".reap", "config.yml");
15253
15632
  const configContent = readFileSync3(configPath, "utf-8");
15254
- const config = import_yaml21.default.parse(configContent);
15633
+ const config = import_yaml22.default.parse(configContent);
15255
15634
  const language = config?.language ?? "english";
15256
15635
  const notice = fetchReleaseNotice(result.to, language);
15257
15636
  if (notice)
@@ -15261,7 +15640,7 @@ async function execute33() {
15261
15640
  }
15262
15641
 
15263
15642
  // src/cli/commands/config.ts
15264
- var import_yaml22 = __toESM(require_dist(), 1);
15643
+ var import_yaml23 = __toESM(require_dist(), 1);
15265
15644
  init_fs();
15266
15645
  init_integrity();
15267
15646
  async function execute34() {
@@ -15277,7 +15656,7 @@ async function execute34() {
15277
15656
  if (!configContent) {
15278
15657
  emitError("config", "Config file is empty.");
15279
15658
  }
15280
- const config = import_yaml22.default.parse(configContent);
15659
+ const config = import_yaml23.default.parse(configContent);
15281
15660
  emitOutput({
15282
15661
  status: "ok",
15283
15662
  command: "config",
@@ -15296,7 +15675,7 @@ async function execute34() {
15296
15675
  }
15297
15676
 
15298
15677
  // src/cli/commands/update.ts
15299
- var import_yaml23 = __toESM(require_dist(), 1);
15678
+ var import_yaml24 = __toESM(require_dist(), 1);
15300
15679
  import { readFileSync as readFileSync4 } from "fs";
15301
15680
  import { join as join27, dirname as dirname10 } from "path";
15302
15681
  import { fileURLToPath as fileURLToPath7 } from "url";
@@ -15355,7 +15734,7 @@ async function backfillConfig(paths) {
15355
15734
  return { added: [], removed: [] };
15356
15735
  let config;
15357
15736
  try {
15358
- config = import_yaml23.default.parse(content) ?? {};
15737
+ config = import_yaml24.default.parse(content) ?? {};
15359
15738
  } catch {
15360
15739
  return { added: [], removed: [] };
15361
15740
  }
@@ -15381,7 +15760,7 @@ async function backfillConfig(paths) {
15381
15760
  }
15382
15761
  }
15383
15762
  if (added.length > 0 || removed.length > 0) {
15384
- await writeTextFile(paths.config, import_yaml23.default.stringify(config));
15763
+ await writeTextFile(paths.config, import_yaml24.default.stringify(config));
15385
15764
  }
15386
15765
  return { added, removed };
15387
15766
  }
@@ -15432,7 +15811,7 @@ async function execute35(phase, postUpgrade) {
15432
15811
  let agentClient;
15433
15812
  if (configContent) {
15434
15813
  try {
15435
- const config = import_yaml23.default.parse(configContent);
15814
+ const config = import_yaml24.default.parse(configContent);
15436
15815
  projectName = config.project ?? "my-project";
15437
15816
  agentClient = config.agentClient;
15438
15817
  } catch {}
@@ -15449,7 +15828,7 @@ async function execute35(phase, postUpgrade) {
15449
15828
  const raw = configContent ?? "";
15450
15829
  if (raw) {
15451
15830
  try {
15452
- const cfg = import_yaml23.default.parse(raw);
15831
+ const cfg = import_yaml24.default.parse(raw);
15453
15832
  if (cfg?.language)
15454
15833
  language = cfg.language;
15455
15834
  } catch {}
@@ -15816,7 +16195,7 @@ ${lines.join(`
15816
16195
  }
15817
16196
 
15818
16197
  // src/cli/commands/load-context.ts
15819
- var import_yaml24 = __toESM(require_dist(), 1);
16198
+ var import_yaml25 = __toESM(require_dist(), 1);
15820
16199
  import { join as join29 } from "path";
15821
16200
  init_fs();
15822
16201
  async function buildKnowledgeContext(cwd) {
@@ -15832,13 +16211,13 @@ async function buildKnowledgeContext(cwd) {
15832
16211
  let config = null;
15833
16212
  if (configContent) {
15834
16213
  try {
15835
- config = import_yaml24.default.parse(configContent);
16214
+ config = import_yaml25.default.parse(configContent);
15836
16215
  } catch {}
15837
16216
  }
15838
16217
  let state = null;
15839
16218
  if (currentContent) {
15840
16219
  try {
15841
- state = import_yaml24.default.parse(currentContent);
16220
+ state = import_yaml25.default.parse(currentContent);
15842
16221
  } catch {}
15843
16222
  }
15844
16223
  const sections = [];
@@ -15951,7 +16330,7 @@ program2.command("init [project-name]").description("Initialize a new reap proje
15951
16330
  program2.command("status").description("Show current project status").action(async () => {
15952
16331
  await execute6();
15953
16332
  });
15954
- 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 (use --no-backlog to explicitly declare no relevant backlog)").option("--no-backlog", "Explicitly declare no backlog item is relevant to this generation (suppresses pending-backlog prompt). Negates --backlog.").option("--source-action <sourceAction>", "Source action for abort/early-close (rollback, stash, hold, none — rollback only for abort)").option("--save-backlog", "Save progress to backlog on abort").option("--defer-tasks <value>", "For early-close: auto-defer unchecked tasks to new backlog (true|false, default true)").action(async (stage, options) => {
16333
+ 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 (use --no-backlog to explicitly declare no relevant backlog)").option("--no-backlog", "Explicitly declare no backlog item is relevant to this generation (suppresses pending-backlog prompt). Negates --backlog.").option("--source-action <sourceAction>", "Source action for abort/early-close (rollback, stash, hold, none — rollback only for abort)").option("--save-backlog", "Save progress to backlog on abort").option("--defer-tasks <value>", "For early-close: auto-defer unchecked tasks to new backlog (true|false, default true)").option("--severity <severity>", "For validation --phase report-evaluator: evaluator concern severity (high|low|none — none is a no-op)").option("--summary <summary>", "For validation --phase report-evaluator: one-line evaluator concern summary").action(async (stage, options) => {
15955
16334
  await execute26(stage, options);
15956
16335
  });
15957
16336
  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) => {
@@ -317,6 +317,10 @@ Switching clients is a config edit: change `agentClient` in `.reap/config.yml`,
317
317
 
318
318
  For OpenCode users, see `AGENTS.md` (auto-generated by `reap update`) for the project-level entry-point. `~/.reap/reap-guide.md` (installed by `reap install-skills`) is referenced from `AGENTS.md` and remains the canonical REAP usage guide.
319
319
 
320
+ ### Evaluator agent (opt-in)
321
+
322
+ Both adapters install bundled agent definitions (`reap-evolve.md`, `reap-evaluate.md`) to the client's user-level agents directory (`~/.claude/agents/` for Claude Code, `~/.config/opencode/agent/` for OpenCode). The install runs on `reap install-skills` AND `reap update`, so user-level agents stay in sync with the bundled REAP version. Set `evaluator: true` in `.reap/config.yml` to launch `reap-evaluate` as an independent reviewer during the validation stage (advisor role — the builder owns the final verdict).
323
+
320
324
  ## Role Separation
321
325
 
322
326
  | Component | Role |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c-d-cc/reap",
3
- "version": "0.16.5",
3
+ "version": "0.16.6",
4
4
  "description": "Recursive Evolutionary Autonomous Pipeline — AI and humans evolve software across generations",
5
5
  "license": "MIT",
6
6
  "author": "HyeonIL Choi <hichoi@c-d.cc> (C to D)",