@ai-dev-methodologies/rlp-desk 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -11,6 +11,21 @@ For pre-v0.15.4 versions, refer to `git log` and individual GitHub release notes
11
11
  - Post-v0.15.6: remove `RLP_LIFECYCLE_METRICS` flag entirely (per plan v3 ADR follow-ups).
12
12
  - Phase D.1 (handoff documents) + Phase D.2 (per-stage agent role specialization) — both deferred per `docs/plans/v0.15.4-release-runbook.md` §7.6.
13
13
 
14
+ ## [0.17.0] — 2026-06-19
15
+
16
+ **BREAKING (ADR-001): `node run.mjs run <slug> --mode agent` (the deprecated Node-leader direct-CLI alpha) now hard-errors.** Per the schedule announced in 0.16.0, the `--mode agent` entry point exits 2 with a redirect, and the Node-CLI default mode flips from `agent` to `tmux` (the canonical production leader). The `src/node/**` engine modules are retained (they back the Native Agent() path and the test suite); only the direct-CLI `--mode agent` *dispatch entry* was removed. **Migration:** replace `node run.mjs run <slug> --mode agent` with `--mode tmux`. The slash command's `--mode native` default is unaffected.
17
+
18
+ ### Changed
19
+ - `node run.mjs run <slug>` (no `--mode`) now defaults to `--mode tmux` and delegates to the zsh leader, instead of the deprecated Node leader.
20
+
21
+ ### Fixed
22
+ - Four shipped files referenced `docs/multi-mission-orchestration.md`; corrected to the real shipped path `docs/rlp-desk/multi-mission-orchestration.md` (dead link on fresh installs). Added a docs-link-resolve test.
23
+ - `uninstall` now removes the `UNLOCK.md` marker (and unlocks 0o444 files before unlink), so the `ralph-desk/` directory is fully removed.
24
+ - The A4 fallback iteration-signal write now goes through the atomic `atomic_write` helper (temp+rename) instead of a raw redirect.
25
+
26
+ ### Changed (packaging)
27
+ - The shipped `examples/calculator` scaffold moved from the legacy `.claude/ralph-desk/` path to `.rlp-desk/` (v0.13.0+ convention) and no longer ships generated runtime state.
28
+
14
29
  ## [0.16.0] — 2026-06-18
15
30
 
16
31
  Leader consolidation (ADR-001): `--mode tmux` is now the canonical production leader, self-verification works on it, and the deprecated `--mode agent` Node-CLI path is on a dated removal schedule.
@@ -83,7 +83,7 @@ This creates the scaffold:
83
83
 
84
84
  ## Step 5: Customize the PRD
85
85
 
86
- Edit `.rlp-desk/plans/prd-loop-test.md` to define your user stories and acceptance criteria. See [`examples/calculator/`](../examples/calculator/.claude/ralph-desk/plans/prd-loop-test.md) for a complete example.
86
+ Edit `.rlp-desk/plans/prd-loop-test.md` to define your user stories and acceptance criteria. See [`examples/calculator/`](../examples/calculator/.rlp-desk/plans/prd-loop-test.md) for a complete example.
87
87
 
88
88
  Key sections:
89
89
  - **User Stories** with Given/When/Then acceptance criteria, Task Type, and Risk Level
@@ -649,5 +649,5 @@ an optional `next_mission_candidate` field:
649
649
 
650
650
  The leader propagates the field into `status.json`
651
651
  (`status.next_mission_candidate`). Wrappers poll either source. See
652
- `docs/multi-mission-orchestration.md` for the consumer-side polling
652
+ `docs/rlp-desk/multi-mission-orchestration.md` for the consumer-side polling
653
653
  pattern.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-dev-methodologies/rlp-desk",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "Fresh-context iterative loops for Claude Code — autonomous task completion with independent verification",
5
5
  "scripts": {
6
6
  "postinstall": "node scripts/postinstall.js",
@@ -23,10 +23,10 @@
23
23
  "scripts/",
24
24
  "docs/rlp-desk/*.md",
25
25
  "docs/rlp-desk/blueprints/",
26
- "examples/calculator/.claude/ralph-desk/context/",
27
- "examples/calculator/.claude/ralph-desk/memos/",
28
- "examples/calculator/.claude/ralph-desk/plans/",
29
- "examples/calculator/.claude/ralph-desk/prompts/",
26
+ "examples/calculator/.rlp-desk/context/",
27
+ "examples/calculator/.rlp-desk/memos/",
28
+ "examples/calculator/.rlp-desk/plans/",
29
+ "examples/calculator/.rlp-desk/prompts/",
30
30
  "install.sh",
31
31
  "README.md",
32
32
  "CHANGELOG.md",
@@ -25,10 +25,22 @@ const files = [
25
25
  path.join(deskDir, "init_ralph_desk.zsh"),
26
26
  path.join(deskDir, "run_ralph_desk.zsh"),
27
27
  path.join(deskDir, "lib_ralph_desk.zsh"),
28
+ // PKG-6: postinstall writes the UNLOCK.md escape-hatch doc into deskDir. If we
29
+ // skip it here, the empty-dir rmdir below always sees one leftover file and the
30
+ // ralph-desk/ directory is never removed.
31
+ path.join(deskDir, "UNLOCK.md"),
28
32
  ];
29
33
 
30
34
  for (const targetPath of files) {
31
35
  try {
36
+ // Installed files are write-locked (chmod 0o444) per postinstall v5.7 §4.10.
37
+ // Restore write permission before unlink so removal is robust across
38
+ // filesystems (mirrors postinstall's unlock-before-remove).
39
+ try {
40
+ fs.chmodSync(targetPath, 0o644);
41
+ } catch (_) {
42
+ // File may be missing or already writable.
43
+ }
32
44
  fs.rmSync(targetPath, { recursive: true, force: true });
33
45
  console.log(" - " + targetPath);
34
46
  } catch (_) {
@@ -374,7 +374,7 @@ This contract MUST be observed in every iteration of the leader loop below. Futu
374
374
 
375
375
  #### Direct Node CLI invocation (`node run.mjs run <slug> --mode agent` — deprecated alpha)
376
376
 
377
- Direct invocation of `node ~/.claude/ralph-desk/node/run.mjs run <slug> --mode agent` is **the deprecated Node-leader alpha path**. This is unrelated to the slash command's Native Agent() path above — different code, different leader, different lifecycle. The Node leader currently retains SV/flywheel implementations not yet ported to Native Agent(). For production tmux orchestration, use `--mode tmux` (the **canonical** leader). For Claude Code Native Agent() campaigns, use `/rlp-desk run <slug> --mode native` from a Claude Code session.
377
+ Direct invocation of `node ~/.claude/ralph-desk/node/run.mjs run <slug> --mode agent` **hard-errors (exit 2) as of this release** (per [ADR-001](../../docs/plans/adr-001-leader-consolidation.md) §3) — it was the deprecated Node-leader alpha path, and the dated breaking change has now landed. Direct CLI invocation redirects to `--mode tmux` (production) / `--mode native` (slash), and the **Node-CLI default mode is now `tmux`**. This is unrelated to the slash command's legacy `--mode agent` native redirect — different code, different leader, different lifecycle. The `src/node/**` engine modules (which still back the Native Agent() path and the test suite, and retain SV/flywheel implementations not yet ported to Native Agent()) are **retained** — only the direct-CLI `--mode agent` *entry point* hard-errors. For production tmux orchestration, use `--mode tmux` (the **canonical** leader). For Claude Code Native Agent() campaigns, use `/rlp-desk run <slug> --mode native` from a Claude Code session.
378
378
 
379
379
  **Deprecation schedule** (per [ADR-001](../../docs/plans/adr-001-leader-consolidation.md) §3 — applies to the Node-CLI `--mode agent` entry point ONLY; the `src/node/**` engine modules are retained throughout):
380
380
 
package/src/governance.md CHANGED
@@ -584,7 +584,7 @@ for iteration in 1..max_iter:
584
584
  ⑥½ Flywheel direction review (when --flywheel on-fail and consecutive_failures > 0)
585
585
  - Dispatch Flywheel agent (fresh context, --flywheel-model)
586
586
  - Read flywheel-signal.json for direction decision (hold/pivot/reduce/expand)
587
- - Optional `next_mission_candidate` field (string | null): when present, the leader propagates it to status.json so consumer wrappers can chain the next mission without code edits. See docs/multi-mission-orchestration.md.
587
+ - Optional `next_mission_candidate` field (string | null): when present, the leader propagates it to status.json so consumer wrappers can chain the next mission without code edits. See docs/rlp-desk/multi-mission-orchestration.md.
588
588
  - If --flywheel-guard on:
589
589
  - Dispatch Guard agent (fresh context, --flywheel-guard-model)
590
590
  - Read flywheel-guard-verdict.json:
package/src/node/run.mjs CHANGED
@@ -14,7 +14,11 @@ import {
14
14
  import { isClaudeEngine } from './cli/command-builder.mjs';
15
15
 
16
16
  const RUN_DEFAULTS = {
17
- mode: 'agent',
17
+ // ARCH Wave D (ADR-001 §3): the Node-CLI default mode flips from the deprecated
18
+ // 'agent' (Node-leader alpha) to 'tmux' (the canonical production leader) at the
19
+ // same step that makes --mode agent hard-error. A bare `run <slug>` now delegates
20
+ // to the zsh runner, not the deprecated Node leader.
21
+ mode: 'tmux',
18
22
  workerModel: 'haiku',
19
23
  verifierModel: 'sonnet',
20
24
  finalVerifierModel: 'opus',
@@ -49,14 +53,14 @@ function buildHelpText() {
49
53
  'Commands:',
50
54
  ' brainstorm <description> Plan before init (not implemented in the Node rewrite yet)',
51
55
  ' init <slug> [objective] Create project scaffold',
52
- ' run <slug> [options] Run loop (tmux=zsh leader [production], agent=Node leader [deprecated alpha], native=slash-only error)',
56
+ ' run <slug> [options] Run loop (tmux=zsh leader [production, default], agent=hard-errors per ADR-001, native=slash-only error)',
53
57
  ' status <slug> Show loop status',
54
58
  ' logs <slug> [N] Show iteration log (not implemented in the Node rewrite yet)',
55
59
  ' clean <slug> [--kill-session] Reset for re-run (removes sentinels + runtime/; preserves PRD/prompts/memory)',
56
60
  ' resume <slug> Resume loop (not implemented in the Node rewrite yet)',
57
61
  '',
58
62
  'Run Options:',
59
- ' --mode tmux|agent|native (CLI: tmux=production, agent=deprecated, native=errors with redirect to slash command)',
63
+ ' --mode tmux|agent|native (CLI: tmux=production [default], agent=hard-errors (ADR-001), native=errors with redirect to slash command)',
60
64
  ' --worker-model MODEL',
61
65
  ' --lock-worker-model',
62
66
  ' --verifier-model MODEL',
@@ -373,7 +377,7 @@ async function runTmuxViaZsh(slug, options, deps) {
373
377
  if (unsupported.length > 0) {
374
378
  write(
375
379
  deps.stderr,
376
- `WARNING: ${unsupported.join(', ')} not honored in --mode tmux (zsh runner). Flywheel is deprecated (ADR-001) use --mode agent if you still need it.`,
380
+ `WARNING: ${unsupported.join(', ')} not honored in --mode tmux (zsh runner). Flywheel is deprecated (ADR-001) and unimplemented in the canonical leader.`,
377
381
  );
378
382
  }
379
383
 
@@ -442,7 +446,7 @@ async function runRunCommand(args, deps) {
442
446
  );
443
447
  write(
444
448
  deps.stderr,
445
- 'If hang persists, switch to --worker-model gpt-5.5:high (codex) or --mode agent.',
449
+ 'If hang persists, switch to --worker-model gpt-5.5:high (codex).',
446
450
  );
447
451
  }
448
452
 
@@ -468,50 +472,38 @@ async function runRunCommand(args, deps) {
468
472
  );
469
473
  write(
470
474
  deps.stderr,
471
- 'or use `--mode tmux` (production) / `--mode agent` (deprecated alpha) for direct CLI invocation.',
475
+ 'or use `--mode tmux` (production) for direct CLI invocation. `--mode agent` hard-errors (ADR-001).',
472
476
  );
473
477
  return 2;
474
478
  }
475
479
 
476
- // P1.b: --mode agent (Node-leader alpha) is deprecated. The slash command's
477
- // Native Agent() path (`/rlp-desk run --mode native`) is unrelated different
478
- // code, different leader. We keep the Node-leader behavior unchanged for
479
- // backward compatibility but surface a strong deprecation banner so wrappers
480
- // can migrate before the next major release hard-errors this mode.
481
- if (
482
- options.mode === 'agent'
483
- && !process.env.RLP_DESK_QUIET_WARNINGS
484
- && process.env.NODE_ENV !== 'test'
485
- ) {
486
- write(
487
- deps.stderr,
488
- 'WARNING: --mode agent (Node-leader alpha) is deprecated.',
489
- );
480
+ // ARCH Wave D (ADR-001 §3): --mode agent (Node-leader direct-CLI alpha) HARD-ERRORS
481
+ // as of this release. It is the dated breaking change the deprecation banner
482
+ // announced direct CLI invocation now exits 2 with a redirect to the canonical
483
+ // production leader (--mode tmux) or the slash-command Native Agent() path
484
+ // (--mode native). This is UNRELATED to the slash command's legacy `--mode agent`
485
+ // → native redirect (different code, different leader). The `src/node/**` engine
486
+ // modules (run()/runCampaign) are RETAINED — they remain the engine the Native
487
+ // Agent() path and the test suite build on; only this direct-CLI dispatch entry
488
+ // hard-errors. Mirror the --mode native slash-only exit-2 pattern above.
489
+ if (options.mode === 'agent') {
490
490
  write(
491
491
  deps.stderr,
492
- 'This is the direct Node-CLI alpha path UNRELATED to the slash command Native Agent() path (`/rlp-desk run --mode native`).',
492
+ 'ERROR: --mode agent (Node-leader direct-CLI alpha) is no longer supported (ADR-001).',
493
493
  );
494
494
  write(
495
495
  deps.stderr,
496
- 'For production tmux orchestration, use `--mode tmux`.',
496
+ 'For production tmux orchestration, use `--mode tmux` (the canonical leader).',
497
497
  );
498
498
  write(
499
499
  deps.stderr,
500
- 'For Claude Code Native Agent() campaigns, use `/rlp-desk run --mode native` from a Claude Code session.',
500
+ 'For Claude Code Native Agent() campaigns, use `/rlp-desk run <slug> --mode native` from a Claude Code session.',
501
501
  );
502
- // 2026-05-07 (v0.15.2): rlp-desk is in active stabilization. Goal: reach
503
- // omc /team/ralph/ralplan level of reliability while preserving
504
- // rlp-desk's self-driving advantages (multi-engine consensus, multi-mission
505
- // queue, BLOCK_TAGS taxonomy, structured SV reports). omc is the BENCHMARK,
506
- // not a replacement. See docs/plans/v0.15-stabilization-plan.md.
507
502
  write(
508
503
  deps.stderr,
509
- 'SCHEDULED REMOVAL (ADR-001): --mode agent (Node CLI alpha) hard-errors in 0.17.0 (Node-CLI default flips to tmux) and the dispatch branch is removed in 0.18.0. Engine modules stay. Migrate to --mode tmux.',
510
- );
511
- write(
512
- deps.stderr,
513
- 'STABILIZATION IN PROGRESS: rlp-desk is hardening against the 10-bug regression pattern observed 2026-05-01..05-07. See docs/plans/v0.15-stabilization-plan.md.',
504
+ 'The src/node/** engine modules are retained; only the direct-CLI --mode agent entry point was removed.',
514
505
  );
506
+ return 2;
515
507
  }
516
508
 
517
509
  const result = await deps.runCampaign(slug, options);
@@ -1715,7 +1715,7 @@ async function _runCampaignBody(slug, options, paths, rootDir) {
1715
1715
  // P0-A multi-mission orchestration: optionally captured from flywheel signal.
1716
1716
  // null when the flywheel did not suggest a next mission. Consumer wrappers
1717
1717
  // poll status.next_mission_candidate to chain missions without code edits.
1718
- // See docs/multi-mission-orchestration.md.
1718
+ // See docs/rlp-desk/multi-mission-orchestration.md.
1719
1719
  state.next_mission_candidate = flywheelSignal.next_mission_candidate ?? null;
1720
1720
  // Bug #7 Fix-R cleanup: unlock before unlink so 0o444 doesn't block.
1721
1721
  await unlockSentinelFile(paths.flywheelSignalFile);
@@ -761,7 +761,7 @@ Based on your decision, update campaign memory:
761
761
  current direction. The wrapper polls this field for autonomous
762
762
  multi-mission orchestration (rlp-desk does not auto-launch missions —
763
763
  the consumer wrapper owns that policy). Field is OPTIONAL; absence is
764
- treated as null. See docs/multi-mission-orchestration.md for the
764
+ treated as null. See docs/rlp-desk/multi-mission-orchestration.md for the
765
765
  consumer-side polling pattern.
766
766
  FLYWHEEL_EOF
767
767
 
@@ -756,9 +756,18 @@ _lint_test_density() {
756
756
  us_list=$(grep -oE '^##[[:space:]]+US-[0-9]+' "$prd_file" 2>/dev/null | grep -oE 'US-[0-9]+' | sort -u)
757
757
  [[ -z "$us_list" ]] && return 0
758
758
 
759
- local audit_dir="${LOGS_DIR:-/tmp}"
760
- local audit_file="$audit_dir/test-density-audit.jsonl"
761
- [[ -d "$audit_dir" ]] || audit_file="/tmp/test-density-audit.jsonl"
759
+ # ZSH-8: prefer the campaign LOGS_DIR. When it is unavailable, avoid a fixed,
760
+ # predictable /tmp name (insecure-temp: symlink/collision risk) by creating a
761
+ # unique temp file via mktemp; fall back to a PID-scoped name only if mktemp
762
+ # is missing.
763
+ local audit_dir="${LOGS_DIR:-}"
764
+ local audit_file
765
+ if [[ -n "$audit_dir" && -d "$audit_dir" ]]; then
766
+ audit_file="$audit_dir/test-density-audit.jsonl"
767
+ else
768
+ audit_file=$(mktemp "${TMPDIR:-/tmp}/test-density-audit.XXXXXX" 2>/dev/null) \
769
+ || audit_file="${TMPDIR:-/tmp}/test-density-audit.$$.jsonl"
770
+ fi
762
771
 
763
772
  local us
764
773
  for us in ${(f)us_list}; do
@@ -2311,7 +2311,7 @@ poll_for_signal() {
2311
2311
  # done-claim and a fresh signal_file in that order.
2312
2312
  _kill_pane_process "$pane_id" "worker-a4"
2313
2313
  _lock_sentinel "$DONE_CLAIM_FILE"
2314
- echo '{"iteration":'"$ITERATION"',"status":"verify","us_id":"'"$dc_us_id"'","summary":"auto-generated by A4 fallback (done-claim + clean tree)","timestamp":"'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'"}' > "$signal_file"
2314
+ echo '{"iteration":'"$ITERATION"',"status":"verify","us_id":"'"$dc_us_id"'","summary":"auto-generated by A4 fallback (done-claim + clean tree)","timestamp":"'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'"}' | atomic_write "$signal_file"
2315
2315
  _emit_a4_fallback_audit "$dc_us_id" "$ITERATION" "inline_polling_a4_clean"
2316
2316
  return 0
2317
2317
  else
@@ -2885,7 +2885,13 @@ main() {
2885
2885
  log_error "Another instance is already running (PID $lock_pid). Kill $lock_pid or rm $lockfile"
2886
2886
  exit 1
2887
2887
  fi
2888
- # Stale lock — overwrite
2888
+ # Stale lock — overwrite.
2889
+ # NOTE (ZSH-4, deferred): a fully race-safe stale-lock recovery is a separate
2890
+ # distributed-lock redesign (codex review found subtle rm/create + mutex-leak
2891
+ # races in patch attempts). This finding is LOW: the outer RUNNER_LOCKDIR mkdir
2892
+ # lock (keyed on the same $ROOT) already serializes runners before this inner
2893
+ # path is reached, so the inner race is unreachable in practice. Left at the
2894
+ # tested baseline pending a dedicated redesign.
2889
2895
  log "Stale lock detected (PID ${lock_pid:-unknown} not running), recovering"
2890
2896
  echo $$ > "$lockfile"
2891
2897
  LOCKFILE_ACQUIRED=1