red-proto 0.11.0 → 0.12.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/README.md CHANGED
@@ -65,8 +65,18 @@ Der Installer fragt interaktiv:
65
65
  - **Global** (`~/.claude/`) → Commands in allen Projekten verfügbar
66
66
  - **Lokal** (`./.claude/`) → nur im aktuellen Verzeichnis
67
67
 
68
+ > **Hinweis:** Nicht global und lokal gleichzeitig installieren – Claude Code zeigt die Commands sonst doppelt an. Der Installer warnt dich, wenn eine andere Installation erkannt wird.
69
+
68
70
  > **Update:** Denselben Befehl erneut ausführen – der Installer erkennt bestehende Installationen.
69
71
 
72
+ **Deinstallieren:**
73
+
74
+ ```bash
75
+ npx red-proto --uninstall
76
+ ```
77
+
78
+ Entfernt alle Commands und Agents – deine Projektdateien (`features/`, `research/`, `prd.md` usw.) bleiben unangetastet.
79
+
70
80
  **Option B – Manuell via Git (falls kein npx):**
71
81
 
72
82
  ```bash
package/bin/install.js CHANGED
@@ -1,11 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { createInterface } from 'readline';
4
- import { cp, mkdir, access } from 'fs/promises';
4
+ import { cp, mkdir, rm, access } from 'fs/promises';
5
5
  import { join, dirname } from 'path';
6
6
  import { fileURLToPath } from 'url';
7
7
  import { homedir } from 'os';
8
- import { createReadStream } from 'fs';
9
8
 
10
9
  const __dirname = dirname(fileURLToPath(import.meta.url));
11
10
  const PACKAGE_ROOT = join(__dirname, '..');
@@ -21,6 +20,27 @@ const c = {
21
20
  dim: (s) => `\x1b[2m${s}\x1b[0m`,
22
21
  };
23
22
 
23
+ const COMMAND_FILES = [
24
+ 'red:proto.md',
25
+ 'red:proto-workflow.md',
26
+ 'red:proto-sparring.md',
27
+ 'red:proto-dev-setup.md',
28
+ 'red:proto-research.md',
29
+ 'red:proto-requirements.md',
30
+ 'red:proto-flows.md',
31
+ 'red:proto-ux.md',
32
+ 'red:proto-architect.md',
33
+ 'red:proto-dev.md',
34
+ 'red:proto-qa.md',
35
+ ];
36
+
37
+ const AGENT_FILES = [
38
+ 'frontend-developer.md',
39
+ 'backend-developer.md',
40
+ 'qa-engineer.md',
41
+ 'ux-reviewer.md',
42
+ ];
43
+
24
44
  async function exists(path) {
25
45
  try { await access(path); return true; }
26
46
  catch { return false; }
@@ -46,9 +66,98 @@ function printHeader(version) {
46
66
  console.log('');
47
67
  }
48
68
 
49
- // ─── Main ────────────────────────────────────────────────────────────────────
69
+ // ─── Uninstall ───────────────────────────────────────────────────────────────
70
+
71
+ async function runUninstall() {
72
+ const { version } = JSON.parse(
73
+ await import('fs').then(fs => fs.promises.readFile(join(PACKAGE_ROOT, 'package.json'), 'utf8'))
74
+ );
75
+
76
+ printHeader(version);
77
+
78
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
79
+
80
+ console.log(c.yellow(' Uninstall – where was red · proto installed?'));
81
+ console.log('');
82
+
83
+ const globalBase = join(homedir(), '.claude');
84
+ const localBase = join(process.cwd(), '.claude');
85
+
86
+ const globalExists = await exists(join(globalBase, 'commands', 'red:proto.md'));
87
+ const localExists = await exists(join(localBase, 'commands', 'red:proto.md'));
88
+
89
+ if (!globalExists && !localExists) {
90
+ console.log(c.dim(' red · proto is not installed in this location.'));
91
+ console.log('');
92
+ rl.close();
93
+ return;
94
+ }
95
+
96
+ const options = [];
97
+ if (globalExists) options.push({ label: `Global ${c.dim('(~/.claude)')}`, base: globalBase });
98
+ if (localExists) options.push({ label: `Local ${c.dim('(./.claude)')}`, base: localBase });
99
+
100
+ options.forEach((opt, i) => {
101
+ console.log(` ${i + 1}) ${c.bold(opt.label)}`);
102
+ });
103
+ if (options.length > 1) {
104
+ console.log(` ${options.length + 1}) ${c.bold('Both')}`);
105
+ }
106
+ console.log('');
107
+
108
+ const max = options.length > 1 ? options.length + 1 : options.length;
109
+ let choice = '';
110
+ while (!Array.from({ length: max }, (_, i) => String(i + 1)).includes(choice)) {
111
+ choice = (await ask(rl, c.dim(' Choice [1]: '))).trim() || '1';
112
+ }
113
+
114
+ const targets =
115
+ options.length > 1 && choice === String(options.length + 1)
116
+ ? options
117
+ : [options[parseInt(choice) - 1]];
118
+
119
+ console.log('');
120
+ console.log(c.yellow(' ⚠ This will remove all red:proto commands and agents.'));
121
+ console.log(c.dim(' Your project files (features/, research/, prd.md, …) are NOT touched.'));
122
+ console.log('');
123
+
124
+ const confirm = (await ask(rl, c.dim(' Type "yes" to confirm: '))).trim().toLowerCase();
125
+ rl.close();
126
+
127
+ if (confirm !== 'yes') {
128
+ console.log('');
129
+ console.log(c.dim(' Aborted. Nothing changed.'));
130
+ console.log('');
131
+ return;
132
+ }
133
+
134
+ let removed = 0;
135
+ for (const target of targets) {
136
+ for (const file of COMMAND_FILES) {
137
+ const path = join(target.base, 'commands', file);
138
+ if (await exists(path)) { await rm(path); removed++; }
139
+ }
140
+ for (const file of AGENT_FILES) {
141
+ const path = join(target.base, 'agents', file);
142
+ if (await exists(path)) { await rm(path); removed++; }
143
+ }
144
+ }
145
+
146
+ console.log('');
147
+ console.log(c.green(` ✓ ${removed} file(s) removed`));
148
+ console.log(c.dim(' red · proto has been uninstalled.'));
149
+ console.log('');
150
+ }
151
+
152
+ // ─── Install ─────────────────────────────────────────────────────────────────
50
153
 
51
154
  async function main() {
155
+ const args = process.argv.slice(2);
156
+
157
+ if (args.includes('--uninstall') || args.includes('-u')) {
158
+ return runUninstall();
159
+ }
160
+
52
161
  const { version } = JSON.parse(
53
162
  await import('fs').then(fs => fs.promises.readFile(join(PACKAGE_ROOT, 'package.json'), 'utf8'))
54
163
  );
@@ -76,6 +185,28 @@ async function main() {
76
185
  const claudeBase = isGlobal ? join(homedir(), '.claude') : join(process.cwd(), '.claude');
77
186
  const label = isGlobal ? `~/.claude` : `./.claude`;
78
187
 
188
+ // ── Duplicate detection ────────────────────────────────────────────────────
189
+ const globalBase = join(homedir(), '.claude');
190
+ const localBase = join(process.cwd(), '.claude');
191
+ const otherBase = isGlobal ? localBase : globalBase;
192
+ const otherLabel = isGlobal ? './.claude' : '~/.claude';
193
+
194
+ const otherInstalled = await exists(join(otherBase, 'commands', 'red:proto.md'));
195
+ if (otherInstalled) {
196
+ console.log('');
197
+ console.log(c.yellow(` ⚠ red · proto is already installed in ${otherLabel}`));
198
+ console.log(c.dim(` Installing in both locations will show every command twice in Claude Code.`));
199
+ console.log('');
200
+ const proceed = (await ask(rl, c.dim(' Continue anyway? [y/N]: '))).trim().toLowerCase();
201
+ if (proceed !== 'y') {
202
+ console.log('');
203
+ console.log(c.dim(' Aborted. Nothing changed.'));
204
+ console.log('');
205
+ rl.close();
206
+ return;
207
+ }
208
+ }
209
+
79
210
  console.log('');
80
211
 
81
212
  // ── Step 2: Confirm if already installed ──────────────────────────────────
@@ -144,53 +275,28 @@ async function installFiles(claudeBase, isGlobal, noClobber) {
144
275
  const agentsDir = join(claudeBase, 'agents');
145
276
  const projectRoot = process.cwd();
146
277
 
147
- // Create dirs
148
278
  await mkdir(commandsDir, { recursive: true });
149
279
  await mkdir(agentsDir, { recursive: true });
150
280
 
151
281
  const copyOpts = { recursive: true, force: !noClobber, errorOnExist: false };
152
282
 
153
- // Commands
154
283
  const srcCommands = join(PACKAGE_ROOT, 'commands');
155
- const files = [
156
- 'red:proto.md',
157
- 'red:proto-workflow.md',
158
- 'red:proto-sparring.md',
159
- 'red:proto-dev-setup.md',
160
- 'red:proto-research.md',
161
- 'red:proto-requirements.md',
162
- 'red:proto-flows.md',
163
- 'red:proto-ux.md',
164
- 'red:proto-architect.md',
165
- 'red:proto-dev.md',
166
- 'red:proto-qa.md',
167
- ];
168
-
169
284
  let copied = 0;
170
285
  let skipped = 0;
171
286
 
172
- for (const file of files) {
287
+ for (const file of COMMAND_FILES) {
173
288
  const dest = join(commandsDir, file);
174
289
  const alreadyExists = await exists(dest);
175
- if (noClobber && alreadyExists) {
176
- skipped++;
177
- continue;
178
- }
290
+ if (noClobber && alreadyExists) { skipped++; continue; }
179
291
  await cp(join(srcCommands, file), dest);
180
292
  copied++;
181
293
  }
182
294
 
183
- // Agents
184
295
  const srcAgents = join(PACKAGE_ROOT, 'agents');
185
- const agents = ['frontend-developer.md', 'backend-developer.md', 'qa-engineer.md', 'ux-reviewer.md'];
186
-
187
- for (const file of agents) {
296
+ for (const file of AGENT_FILES) {
188
297
  const dest = join(agentsDir, file);
189
298
  const alreadyExists = await exists(dest);
190
- if (noClobber && alreadyExists) {
191
- skipped++;
192
- continue;
193
- }
299
+ if (noClobber && alreadyExists) { skipped++; continue; }
194
300
  await cp(join(srcAgents, file), dest);
195
301
  copied++;
196
302
  }
@@ -161,8 +161,7 @@ echo "Ich committe jetzt:"
161
161
  echo " → features/FEAT-[X]-[name].md – Tech Design finalisiert"
162
162
  echo " → features/STATUS.md – Tech-Status aktualisiert"
163
163
  git add features/FEAT-[X]-*.md features/STATUS.md
164
- git commit -m "docs: FEAT-[X] tech design – [Feature Name]"
165
- git push
164
+ git commit -q -m "docs: FEAT-[X] tech design – [Feature Name]" && git push -q
166
165
  ```
167
166
 
168
167
  ## Routing nach Approval
@@ -428,7 +428,7 @@ Installiere nur was das PRD tatsächlich braucht – keine spekulativen Packages
428
428
  **Variante A – Nur Code versionieren:**
429
429
  ```bash
430
430
  cd [codedir]
431
- git init
431
+ git init -q -b main
432
432
  cat > .gitignore << 'EOF'
433
433
  node_modules/
434
434
  .env
@@ -445,14 +445,13 @@ target/
445
445
  bin/
446
446
  obj/
447
447
  EOF
448
- git add .
449
- git commit -m "chore: initial scaffold ([Stack])"
448
+ git add . && git commit -q -m "chore: initial scaffold ([Stack])"
450
449
  ```
451
450
 
452
451
  **Variante B – Alles versionieren (Code + Projektdokumentation):**
453
452
  ```bash
454
453
  # Im Projekt-Root:
455
- git init
454
+ git init -q -b main
456
455
  cat > .gitignore << 'EOF'
457
456
  node_modules/
458
457
  .env
@@ -469,8 +468,7 @@ target/
469
468
  bin/
470
469
  obj/
471
470
  EOF
472
- git add .
473
- git commit -m "chore: project setup – PRD + [Stack] scaffold"
471
+ git add . && git commit -q -m "chore: project setup – PRD + [Stack] scaffold"
474
472
  ```
475
473
 
476
474
  Danach in beiden Varianten: initialen Tag setzen:
@@ -495,8 +493,7 @@ gh repo create [repo-name] \
495
493
  --description "[Vision-Satz aus prd.md]"
496
494
 
497
495
  # Erst pushen, dann Tags:
498
- git push -u origin main
499
- git push origin --tags
496
+ git push -q -u origin main && git push -q origin --tags
500
497
  ```
501
498
 
502
499
  Zeige dem User die Repository-URL.
@@ -111,7 +111,7 @@ grep -r "[geänderte Funktion]" [Codeverzeichnis]/ --include="*.tsx" --include="
111
111
 
112
112
  Nach allen Fixes:
113
113
  ```bash
114
- git add . && git commit -m "fix: FEAT-[X] – [Zusammenfassung]" && git push
114
+ git add . && git commit -q -m "fix: FEAT-[X] – [Zusammenfassung]" && git push -q
115
115
  ```
116
116
 
117
117
  ## Phase 4.5: Selbstcheck vor Review
@@ -159,8 +159,7 @@ Status auf "Dev" setzen. STATUS.md aktualisieren.
159
159
 
160
160
  ```bash
161
161
  git add . features/STATUS.md
162
- git commit -m "feat: implement FEAT-[X] – [Feature Name]"
163
- git push
162
+ git commit -q -m "feat: implement FEAT-[X] – [Feature Name]" && git push -q
164
163
  ```
165
164
 
166
165
  ## Phase 7: Handoff schreiben
@@ -190,7 +189,7 @@ Schreibe `context/FEAT-[ID]-dev-handoff.md` (legt Kontext für `/red:proto-qa` i
190
189
  ```bash
191
190
  mkdir -p context
192
191
  git add context/FEAT-[ID]-dev-handoff.md
193
- git commit -m "docs: FEAT-[X] dev handoff" && git push
192
+ git commit -q -m "docs: FEAT-[X] dev handoff" && git push -q
194
193
  ```
195
194
 
196
195
  Sage: "Implementierung abgeschlossen. Handoff geschrieben. **Starte eine neue Session** und führe dort `/red:proto-qa FEAT-[ID]` aus. Nach einer Pause: `/red:proto-workflow` zeigt dir exakt wo du stehst."
@@ -247,8 +247,7 @@ Nach `weiter` oder Korrekturen im Chat:
247
247
  echo "Ich committe jetzt:"
248
248
  echo " → flows/product-flows.md – Screen-Inventar und Transitions finalisiert"
249
249
  git add flows/
250
- git commit -m "docs: product flows – screen inventory + transitions"
251
- git push
250
+ git commit -q -m "docs: product flows – screen inventory + transitions" && git push -q
252
251
  ```
253
252
 
254
253
  Sage dem User: "Flows dokumentiert. Nächster Schritt: `/red:proto-ux` für jedes Feature (einmal pro Feature) – die Transitions aus `flows/product-flows.md` sind die verbindliche Referenz.
@@ -146,8 +146,8 @@ STATUS.md: QA-Wert auf `✓`.
146
146
 
147
147
  ```bash
148
148
  git add . features/STATUS.md
149
- git commit -m "release: v[X.Y.Z] – FEAT-[X] [Feature Name]"
150
- git tag v[X.Y.Z] && git push && git push origin --tags
149
+ git commit -q -m "release: v[X.Y.Z] – FEAT-[X] [Feature Name]"
150
+ git tag v[X.Y.Z] && git push -q && git push -q origin --tags
151
151
  ```
152
152
 
153
153
  Sage: "v[X.Y.Z] getaggt. FEAT-[X] ist Production-Ready. Nächstes Feature: `/red:proto-requirements`. Nach Pause: `/red:proto-workflow`."
@@ -236,8 +236,7 @@ echo " → features/FEAT-[X]-[name].md – Spec finalisiert"
236
236
  echo " → features/STATUS.md – Feature eingetragen"
237
237
  echo " → project-config.md – Nächste ID aktualisiert"
238
238
  git add features/FEAT-[X]-*.md features/STATUS.md project-config.md
239
- git commit -m "docs: FEAT-[X] spec – [Feature Name]"
240
- git push
239
+ git commit -q -m "docs: FEAT-[X] spec – [Feature Name]" && git push -q
241
240
  ```
242
241
 
243
242
  Sage dem User:
@@ -429,8 +429,7 @@ echo " → research/research-questions.md – Forschungsfragen & Antworten"
429
429
  echo " → research/problem-statement.md – Problem Statement Map"
430
430
  echo " → research/personas.md – Personas"
431
431
  git add research/
432
- git commit -m "docs: add user research, personas and problem statement"
433
- git push
432
+ git commit -q -m "docs: add user research, personas and problem statement" && git push -q
434
433
  ```
435
434
 
436
435
  Prüfe den aktuellen Stand:
@@ -203,8 +203,7 @@ echo "Ich committe jetzt:"
203
203
  echo " → features/FEAT-[X]-[name].md – UX Entscheidungen finalisiert"
204
204
  echo " → features/STATUS.md – UX-Status aktualisiert"
205
205
  git add features/FEAT-[X]-*.md flows/product-flows.md features/STATUS.md 2>/dev/null
206
- git commit -m "docs: FEAT-[X] ux design – [Feature Name]"
207
- git push
206
+ git commit -q -m "docs: FEAT-[X] ux design – [Feature Name]" && git push -q
208
207
  ```
209
208
 
210
209
  ## Routing nach Approval
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "red-proto",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "AI-powered product development framework for Claude Code – from idea to tested prototype",
5
5
  "bin": {
6
6
  "red-proto": "./bin/install.js"