projecta-rrr 1.9.8 → 1.9.9

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/bin/install.js CHANGED
@@ -6,6 +6,14 @@ const os = require('os');
6
6
  const readline = require('readline');
7
7
  const { execSync } = require('child_process');
8
8
 
9
+ // Import install-roots utilities for duplicate detection and quarantine
10
+ const {
11
+ detectAndQuarantineDuplicates,
12
+ writeInstallInfo,
13
+ getCurrentVersion,
14
+ getCanonicalRoots
15
+ } = require('../rrr/lib/install-roots');
16
+
9
17
  /**
10
18
  * Detect if running on Windows
11
19
  */
@@ -670,13 +678,35 @@ function install(isGlobal) {
670
678
 
671
679
  console.log(` Installing to ${cyan}${locationLabel}${reset}\n`);
672
680
 
681
+ // GUARD: Prevent nested install paths
682
+ // If claudeDir is inside ~/.claude/rrr/, refuse to install to avoid nested ~/.claude/rrr/rrr/...
683
+ if (isGlobal && claudeDir.includes('/.claude/rrr/')) {
684
+ console.log(` ${orange}⚠${reset} Warning: Detected nested .claude path`);
685
+ console.log(` ${orange}⚠${reset} Refusing to install to avoid: ${claudeDir}`);
686
+ console.log(` ${orange}⚠${reset} This looks like a corrupted or nested installation.`);
687
+ console.log(`\n ${cyan}Fix:${reset} Run /rrr:doctor --fix to quarantine duplicates first.`);
688
+ console.log(` ${cyan}Or:${reset} Remove the nested directory manually:`);
689
+ console.log(` rm -rf ${claudeDir}`);
690
+ process.exit(1);
691
+ }
692
+
673
693
  // Create commands directory
674
694
  const commandsDir = path.join(claudeDir, 'commands');
675
695
  fs.mkdirSync(commandsDir, { recursive: true });
676
696
 
677
697
  // Copy commands/rrr with path replacement
698
+ // Dest must be: ~/.claude/commands/rrr (NOT ~/.claude/rrr/commands/rrr)
678
699
  const rrrSrc = path.join(src, 'commands', 'rrr');
679
700
  const rrrDest = path.join(commandsDir, 'rrr');
701
+
702
+ // Double-check we're not creating a nested structure
703
+ if (rrrDest.includes('/rrr/rrr/') || rrrDest.includes('\\rrr\\rrr\\')) {
704
+ console.log(` ${orange}⚠${reset} Refusing to create nested install path:`);
705
+ console.log(` ${rrrDest}`);
706
+ console.log(` This would cause duplicate command issues.`);
707
+ process.exit(1);
708
+ }
709
+
680
710
  copyWithPathReplacement(rrrSrc, rrrDest, pathPrefix);
681
711
  console.log(` ${green}✓${reset} Installed commands/rrr`);
682
712
 
@@ -737,6 +767,30 @@ function install(isGlobal) {
737
767
  fs.writeFileSync(versionDest, pkg.version);
738
768
  console.log(` ${green}✓${reset} Wrote VERSION (${pkg.version})`);
739
769
 
770
+ // Write INSTALL_INFO.json for idempotency tracking
771
+ const installSource = isGlobal ? 'npx projecta-rrr --global' : 'npx projecta-rrr --local';
772
+ writeInstallInfo({
773
+ version: pkg.version,
774
+ installRoot: claudeDir,
775
+ npmDistTag: 'latest', // Will be updated by /rrr:update if needed
776
+ installerSource: installSource
777
+ }, { configDir: explicitConfigDir || process.env.CLAUDE_CONFIG_DIR });
778
+ console.log(` ${green}✓${reset} Wrote INSTALL_INFO.json`);
779
+
780
+ // Quarantine any duplicate/legacy command roots BEFORE configuring hooks
781
+ // This ensures only one canonical root exists
782
+ if (isGlobal) {
783
+ console.log(` ${green}✓${reset} Checking for duplicate installs...`);
784
+ const quarantineResult = detectAndQuarantineDuplicates({
785
+ configDir: explicitConfigDir || process.env.CLAUDE_CONFIG_DIR,
786
+ dryRun: false,
787
+ quiet: true
788
+ });
789
+ if (quarantineResult.quarantined.length > 0) {
790
+ console.log(` ${green}✓${reset} Quarantined ${quarantineResult.quarantined.length} legacy/duplicate root(s)`);
791
+ }
792
+ }
793
+
740
794
  // Configure statusline and hooks in settings.json
741
795
  const settingsPath = path.join(claudeDir, 'settings.json');
742
796
  const settings = readSettings(settingsPath);
@@ -0,0 +1,202 @@
1
+ ---
2
+ name: rrr:doctor
3
+ description: Diagnose and fix duplicate RRR installs - non-destructive with rollback
4
+ argument-hint: [--report | --fix | --include-local]
5
+ allowed-tools: Read, Bash, Glob, Grep, Edit, Write
6
+ ---
7
+
8
+ <objective>
9
+ Diagnose RRR installation for duplicate command roots and optionally fix them safely.
10
+
11
+ **Safety first:**
12
+ - NEVER deletes anything - only moves to quarantine
13
+ - Always creates rollback script
14
+ - Safe mode: doesn't auto-fix if ambiguous
15
+ - Canonical override: always keeps healthy modern root
16
+
17
+ **Two modes:**
18
+ - `--report` (default): Show diagnostic report without making changes
19
+ - `--fix`: Quarantine duplicate roots safely, keeping one canonical root
20
+ - `--include-local`: Also scan/fix repo-local `.claude/commands/rrr`
21
+ </objective>
22
+
23
+ <windows_compatible>true</windows_compatible>
24
+
25
+ <process>
26
+
27
+ <step name="determine_script_path">
28
+ Resolve the doctor script path:
29
+
30
+ **If running from installed RRR:**
31
+ ```bash
32
+ node ~/.claude/rrr/scripts/doctor-rrr.js --report
33
+ ```
34
+
35
+ **If running from repo source (development):**
36
+ ```bash
37
+ node scripts/doctor-rrr.js --report
38
+ ```
39
+
40
+ Use whichever path exists.
41
+ </step>
42
+
43
+ <step name="run_report_mode">
44
+ Run in report mode (default):
45
+
46
+ ```bash
47
+ node <script-path> --report
48
+ ```
49
+
50
+ **Expected output format:**
51
+ ```
52
+ RRR Doctor Report
53
+ ════════════════════════════════════════════════════════════════
54
+
55
+ Found 3 command root(s):
56
+
57
+ # Score Ver Cmds Status Path
58
+ ────────────────────────────────────────────────────────────────
59
+ 1 1100 1.9.8 44 ✅ active ~/.claude/rrr/commands/rrr
60
+ 2 1005 1.9.7 44 ⚠ will q~ ~/.claude/commands/rrr
61
+ 3 180 - 1 📁 local ./claude/commands/rrr
62
+
63
+ Selected active root: ~/.claude/rrr/commands/rrr
64
+ Score: 1100 | Commands: 44 | Version: 1.9.8
65
+
66
+ Will quarantine:
67
+ • ~/.claude/commands/rrr
68
+
69
+ ════════════════════════════════════════════════════════════════
70
+ ```
71
+ </step>
72
+
73
+ <step name="interpret_report">
74
+ Interpret the scoring:
75
+
76
+ | Signal | Points |
77
+ |--------|--------|
78
+ | Canonical path (`~/.claude/rrr/commands/rrr`) | +1000 |
79
+ | Legacy path (`~/.claude/commands/rrr`) | +900 |
80
+ | Nested bad path (`~/.claude/rrr/rrr/...`) | +100 |
81
+ | 40+ commands | +50 |
82
+ | 30+ commands | +30 |
83
+ | 10+ commands | +10 |
84
+ | Required files (progress, update, verify-work, help) | +10 each |
85
+ | Has valid VERSION file | +50 |
86
+ | No VERSION but has commands | +20 |
87
+ | Newest commands | +5 |
88
+
89
+ **Canonical override:** If `~/.claude/rrr/commands/rrr` exists and is healthy (30+ commands, has progress.md + update.md), it is ALWAYS selected.
90
+
91
+ **Safe mode:** If top two candidates are within 20 points, doctor doesn't auto-fix.
92
+ </step>
93
+
94
+ <step name="run_fix_mode">
95
+ If `--fix` flag is present:
96
+
97
+ ```bash
98
+ node <script-path> --fix
99
+ ```
100
+
101
+ **What happens:**
102
+ 1. Duplicates are MOVED to `~/.claude/rrr/_quarantine/<timestamp>/`
103
+ 2. Rollback scripts are created (`.sh` and `.ps1`)
104
+ 3. Validation runs to confirm exactly one root remains
105
+
106
+ **Expected output:**
107
+ ```
108
+ RRR Doctor --fix Complete
109
+ ════════════════════════════════════════════════════════════════
110
+
111
+ ✓ Selected: ~/.claude/rrr/commands/rrr
112
+ Score: 1100 | Commands: 44
113
+
114
+ Quarantined 1 duplicate(s):
115
+ • ~/.claude/commands/rrr → quarantine
116
+
117
+ ───────────────────────────────────────────────────────────────
118
+ Rollback available:
119
+ macOS/Linux: bash "~/.claude/rrr/_quarantine/<ts>/rollback.sh"
120
+ Windows: powershell "...rollback.ps1"
121
+
122
+ Validation:
123
+ ✓ Exactly one active root: YES
124
+ ✓ Required files present: YES
125
+ ⚠ Skills registry: exists
126
+
127
+ Next step: Restart Claude Code to refresh commands.
128
+ ════════════════════════════════════════════════════════════════
129
+ ```
130
+ </step>
131
+
132
+ <step name="show_rollback_instructions">
133
+ After --fix, show rollback instructions:
134
+
135
+ **To rollback (undo the fix):**
136
+
137
+ macOS/Linux:
138
+ ```bash
139
+ bash ~/.claude/rrr/_quarantine/<timestamp>/rollback.sh
140
+ ```
141
+
142
+ Windows (PowerShell):
143
+ ```powershell
144
+ powershell "$env:USERPROFILE\.claude\rrr\_quarantine\<timestamp>\rollback.ps1"
145
+ ```
146
+
147
+ **Important:** Rollback restores the quarantined duplicates. After rollback, you'll see duplicate commands again until you re-run doctor or reinstall.
148
+ </step>
149
+
150
+ <step name="include_local_mode">
151
+ For repo-local installs, use `--include-local`:
152
+
153
+ ```bash
154
+ node <script-path> --report --include-local
155
+ node <script-path> --fix --include-local
156
+ ```
157
+
158
+ This also scans for `./.claude/commands/rrr` and quarantines it along with other duplicates.
159
+
160
+ **Default behavior:** Repo-local roots are reported but NOT quarantined unless `--include-local` is passed. This protects user-authored local overrides.
161
+ </step>
162
+
163
+ </process>
164
+
165
+ <success_criteria>
166
+ - [ ] Report mode shows all detected command roots with scores
167
+ - [ ] Report explains selection reason (canonical override or highest score)
168
+ - [ ] Safe mode triggers when candidates are ambiguous
169
+ - [ ] Fix mode quarantines duplicates (moves, never deletes)
170
+ - [ ] Rollback scripts are created for both Unix and Windows
171
+ - [ ] Validation confirms exactly one root remains
172
+ - [ ] Repo-local roots are protected by default
173
+ - [ ] Works on Windows (no bash constructs)
174
+ </success_criteria>
175
+
176
+ <notes>
177
+ **Quarantine location:**
178
+ - `~/.claude/rrr/_quarantine/<timestamp>-<original-name>/`
179
+ - Contains original directory structure
180
+ - Logged in `~/.claude/rrr/_quarantine/QUARANTINE_LOG.json`
181
+
182
+ **Rollback scripts:**
183
+ - macOS/Linux: `rollback.sh` (bash)
184
+ - Windows: `rollback.ps1` (PowerShell)
185
+ - Safe to delete quarantine folder if you don't need rollback
186
+
187
+ **Canonical root priority (highest wins):**
188
+ 1. `~/.claude/rrr/commands/rrr` (+1000) - MODERN CANONICAL
189
+ 2. `~/.claude/commands/rrr` (+900) - LEGACY VALID
190
+ 3. `~/.claude/rrr/rrr/commands/rrr` (+100) - BAD NESTED
191
+ 4. Others (+0)
192
+
193
+ **Safe mode triggers when:**
194
+ - Top two candidates score within 20 points
195
+ - AND canonical override doesn't apply
196
+ - Prevents guessing when installation state is unclear
197
+
198
+ **Symptoms of duplicates:**
199
+ - Seeing "two /rrr:progress" commands
200
+ - Commands appearing multiple times in help
201
+ - Update not taking effect
202
+ </notes>
@@ -68,18 +68,45 @@ Output ONLY the reference content below. Do NOT add:
68
68
 
69
69
  ## Staying Updated
70
70
 
71
- RRR evolves fast. Check for updates periodically:
71
+ RRR evolves fast. Check for updates and diagnose issues:
72
72
 
73
73
  ```
74
- /rrr:whats-new
74
+ /rrr:update
75
75
  ```
76
76
 
77
- Shows what changed since your installed version. Update with:
77
+ Updates RRR to latest version with idempotent install:
78
+ - Detects and quarantines duplicate/legacy install roots
79
+ - Installs exact version from npm (version-pinned via `@latest`)
80
+ - Verifies installation integrity
81
+ - Displays changelog for versions in range
82
+ - Safe to run multiple times - never creates duplicates
78
83
 
79
- ```bash
80
- npx projecta-rrr@latest
84
+ ```
85
+ /rrr:doctor
86
+ ```
87
+
88
+ Diagnoses and fixes duplicate RRR installs:
89
+ - Detects multiple command roots that cause duplicate commands
90
+ - Shows table of all found roots with status (preferred/duplicate)
91
+ - Lists duplicate command names (e.g., two rrr:progress)
92
+ - With `--fix`: quarantines duplicates safely to `~/.claude/rrr/_quarantine/`
93
+ - Keeps only one canonical root active
94
+
95
+ **If you see duplicate commands** (two /rrr:progress, etc.):
96
+ ```
97
+ /rrr:doctor # See what's wrong
98
+ /rrr:doctor --fix # Quarantine duplicates
99
+ ```
100
+ Then restart Claude Code.
101
+
102
+ ```
103
+ /rrr:whats-new
81
104
  ```
82
105
 
106
+ See what's changed since your installed version.
107
+
108
+ Shows installed vs latest version comparison and changelog entries for versions you've missed.
109
+
83
110
  ## Core Workflow
84
111
 
85
112
  ```
@@ -461,6 +488,29 @@ To include: add to PLAN frontmatter `skills: [projecta.shadcn-ui, projecta.mcp-s
461
488
  **`/rrr:help`**
462
489
  Show this command reference.
463
490
 
491
+ **`/rrr:doctor`**
492
+ Diagnose and fix duplicate RRR installs - non-destructive with rollback.
493
+
494
+ **If you see duplicate commands (two /rrr:progress), run this!**
495
+
496
+ Features:
497
+ - Detects all command roots (global + repo-local)
498
+ - Scores each root by completeness, version, freshness
499
+ - Canonical override: keeps healthy modern root (`~/.claude/rrr/commands/rrr`)
500
+ - Safe mode: doesn't auto-fix if scores are ambiguous
501
+ - `--fix`: Quarantines duplicates (moves, never deletes)
502
+ - `--include-local`: Also scan/fix repo-local `.claude/commands/rrr`
503
+ - Creates rollback scripts (`.sh` and `.ps1`)
504
+
505
+ Usage:
506
+ ```
507
+ /rrr:doctor # Report only
508
+ /rrr:doctor --fix # Quarantine duplicates safely
509
+ /rrr:doctor --fix --include-local # Include repo-local roots
510
+ ```
511
+
512
+ After `--fix`, restart Claude Code. To undo: run the rollback script shown.
513
+
464
514
  **`/rrr:check-version`**
465
515
  Check version consistency across package.json, CHANGELOG, and planning docs.
466
516
 
@@ -1,49 +1,61 @@
1
1
  ---
2
2
  name: rrr:update
3
- description: Update RRR to latest version with changelog display
3
+ description: Update RRR to latest version with idempotent install + duplicate prevention
4
4
  ---
5
5
 
6
6
  <objective>
7
- Check for RRR updates, install if available, and display what changed.
7
+ Update RRR to the latest version with guaranteed idempotency.
8
8
 
9
- Provides a better update experience than raw `npx projecta-rrr` by showing version diff and changelog entries.
9
+ This command:
10
+ 1. Checks npm for the latest version
11
+ 2. Installs using npx (not npm install -g, which can fail on macOS due to EACCES)
12
+ 3. Quarantines any duplicate/legacy install roots automatically
13
+ 4. Verifies installation integrity
14
+ 5. Recommends running /rrr:doctor if duplicates are detected
15
+
16
+ Safe to run multiple times - will never create duplicate command roots.
10
17
  </objective>
11
18
 
19
+ <windows_compatible>true</windows_compatible>
20
+
12
21
  <process>
13
22
 
14
- <step name="get_installed_version">
15
- Read installed version:
23
+ <step name="get_current_version">
24
+ Read current installed version from INSTALL_INFO.json (preferred) or VERSION file:
25
+
26
+ **Check INSTALL_INFO.json first:**
27
+ ```bash
28
+ cat ~/.claude/rrr/INSTALL_INFO.json 2>/dev/null | jq -r '.version'
29
+ ```
16
30
 
31
+ **Fallback to VERSION file:**
17
32
  ```bash
18
33
  cat ~/.claude/rrr/VERSION 2>/dev/null
19
34
  ```
20
35
 
21
- **If VERSION file missing:**
36
+ **If both missing:**
22
37
  ```
23
38
  ## RRR Update
24
39
 
25
- **Installed version:** Unknown
40
+ **Installed version:** Unknown (fresh install)
26
41
 
27
- Your installation doesn't include version tracking.
28
-
29
- Running fresh install...
42
+ Proceeding with fresh install...
30
43
  ```
31
-
32
- Proceed to install step (treat as version 0.0.0 for comparison).
44
+ Treat as version 0.0.0 for comparison.
33
45
  </step>
34
46
 
35
47
  <step name="check_latest_version">
36
- Check npm for latest version:
48
+ Get the latest version from npm:
37
49
 
38
50
  ```bash
39
- npm view projecta-rrr version 2>/dev/null
51
+ npm view projecta-rrr dist-tags.latest 2>/dev/null
40
52
  ```
41
53
 
42
54
  **If npm check fails:**
43
55
  ```
44
56
  Couldn't check for updates (offline or npm unavailable).
45
57
 
46
- To update manually: `npx projecta-rrr --global`
58
+ To update manually: npx --yes projecta-rrr@latest --global
47
59
  ```
48
60
 
49
61
  STOP here if npm unavailable.
@@ -60,6 +72,8 @@ Compare installed vs latest:
60
72
  **Latest:** X.Y.Z
61
73
 
62
74
  You're already on the latest version.
75
+
76
+ Run /rrr:doctor to verify installation integrity.
63
77
  ```
64
78
 
65
79
  STOP here if already up to date.
@@ -77,15 +91,33 @@ You're ahead of the latest release (development version?).
77
91
  STOP here if ahead.
78
92
  </step>
79
93
 
80
- <step name="run_update">
81
- Run the update:
94
+ <step name="run_idempotent_update">
95
+ Run the update with version pinning:
82
96
 
83
97
  ```bash
84
- npx projecta-rrr --global
98
+ npx --yes projecta-rrr@latest --global
85
99
  ```
86
100
 
87
- Capture output. If install fails, show error and STOP.
101
+ **Critical:**
102
+ - Uses `@latest` to pin to exact version at install time
103
+ - Uses `--yes` to skip interactive prompts
104
+ - Does NOT use `npm install -g` (avoids EACCES errors on macOS)
105
+
106
+ **On Windows (PowerShell):**
107
+ ```powershell
108
+ npx --yes projecta-rrr@latest --global
109
+ ```
88
110
 
111
+ **Capture output and verify:**
112
+ 1. Should complete without error
113
+ 2. Should show "Wrote INSTALL_INFO.json"
114
+ 3. Should show "Quarantined X legacy/duplicate root(s)" if any were found
115
+
116
+ **If install fails:**
117
+ Show error and STOP. Do not proceed.
118
+ </step>
119
+
120
+ <step name="clear_update_cache">
89
121
  Clear the update cache so statusline indicator disappears:
90
122
 
91
123
  ```bash
@@ -93,6 +125,30 @@ rm -f ~/.claude/cache/rrr-update-check.json
93
125
  ```
94
126
  </step>
95
127
 
128
+ <step name="verify_and_recommend_doctor">
129
+ Verify the installation and recommend doctor if needed:
130
+
131
+ ```bash
132
+ node ~/.claude/rrr/scripts/doctor-rrr.js --report
133
+ ```
134
+
135
+ **If duplicates were detected during install:**
136
+ ```
137
+ ## RRR Update
138
+
139
+ ⚠️ Duplicates were detected and quarantined during install.
140
+
141
+ Run /rrr:doctor --fix to complete cleanup.
142
+ ```
143
+
144
+ **If installation verified healthy:**
145
+ ```
146
+ ## RRR Update
147
+
148
+ ✓ Installation verified healthy (no duplicates)
149
+ ```
150
+ </step>
151
+
96
152
  <step name="fetch_changelog">
97
153
  Fetch changelog from GitHub:
98
154
 
@@ -116,13 +172,16 @@ Parse each `## [X.Y.Z]` section and collect all versions in the range.
116
172
  </step>
117
173
 
118
174
  <step name="display_result">
119
- Format beautiful output:
175
+ Format output:
120
176
 
121
177
  ```
122
178
  ╔═══════════════════════════════════════════════════════════╗
123
179
  ║ RRR Updated: v1.5.10 → v1.5.15 ║
124
180
  ╚═══════════════════════════════════════════════════════════╝
125
181
 
182
+ ✓ Installation verified (no duplicates)
183
+ ✓ quarantined 2 legacy install root(s)
184
+
126
185
  ✨ What's New
127
186
  ────────────────────────────────────────────────────────────
128
187
 
@@ -139,27 +198,47 @@ Format beautiful output:
139
198
 
140
199
  ────────────────────────────────────────────────────────────
141
200
 
142
- ⚠️ Restart Claude Code to pick up the new commands.
201
+ Restart Claude Code to pick up the new commands:
202
+
203
+ 1. Type: exit
204
+ 2. Run: claude
143
205
 
144
206
  [View full changelog](https://github.com/PA-Ai-Team/projecta-rrr/blob/main/CHANGELOG.md)
145
207
  ```
146
-
147
- **Key elements:**
148
- - Box header with version transition
149
- - All changelog entries in the range
150
- - **BREAKING:** changes surfaced prominently
151
- - Restart reminder (critical for picking up new commands)
152
- - Link to full changelog
153
208
  </step>
154
209
 
155
210
  </process>
156
211
 
157
212
  <success_criteria>
158
- - [ ] Installed version read correctly
213
+ - [ ] Current version read correctly (INSTALL_INFO.json preferred)
159
214
  - [ ] Latest version checked via npm
215
+ - [ ] Update uses npx (NOT npm install -g)
160
216
  - [ ] Update skipped if already current
161
- - [ ] Update executed successfully
217
+ - [ ] Update executed with version-pinned npx
218
+ - [ ] Duplicates quarantined automatically
219
+ - [ ] Installation verified after update
220
+ - [ ] Doctor recommended if issues found
162
221
  - [ ] Changelog fetched (remote or local fallback)
163
222
  - [ ] Changes between versions displayed
164
223
  - [ ] Restart reminder shown
165
224
  </success_criteria>
225
+
226
+ <notes>
227
+ **Why npx instead of npm install -g?**
228
+
229
+ - `npm install -g` often fails on macOS due to EACCES permission errors
230
+ - `npx` downloads and runs the package directly, avoiding global install issues
231
+ - Version-pinned `@latest` ensures deterministic installs
232
+
233
+ **Duplicate prevention:**
234
+ - Before install, any existing duplicate roots are quarantined
235
+ - After install, verification confirms only canonical root exists
236
+ - Quarantine location: `~/.claude/rrr/_quarantine/<timestamp>/`
237
+
238
+ **If you see duplicate commands:**
239
+ Run: `/rrr:doctor --fix`
240
+
241
+ **Windows compatibility:**
242
+ - Uses Node.js file operations (no bash constructs like `||`, `find`, `head`)
243
+ - Verification via `node doctor-rrr.js --report` works on all platforms
244
+ </notes>