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 +10 -0
- package/bin/install.js +138 -32
- package/commands/red:proto-architect.md +1 -2
- package/commands/red:proto-dev-setup.md +5 -8
- package/commands/red:proto-dev.md +3 -4
- package/commands/red:proto-flows.md +1 -2
- package/commands/red:proto-qa.md +2 -2
- package/commands/red:proto-requirements.md +1 -2
- package/commands/red:proto-research.md +1 -2
- package/commands/red:proto-ux.md +1 -2
- package/package.json +1 -1
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
|
-
// ───
|
|
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
|
|
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
|
|
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.
|
package/commands/red:proto-qa.md
CHANGED
|
@@ -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:
|
package/commands/red:proto-ux.md
CHANGED
|
@@ -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
|