design-protocol 1.0.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/LICENSE +21 -0
- package/README.md +225 -0
- package/agents/dp-researcher.md +239 -0
- package/agents/dp-verifier.md +207 -0
- package/bin/install.js +464 -0
- package/commands/dp-back.md +221 -0
- package/commands/dp-discuss.md +257 -0
- package/commands/dp-execute.md +513 -0
- package/commands/dp-journey.md +85 -0
- package/commands/dp-progress.md +178 -0
- package/commands/dp-roadmap.md +83 -0
- package/commands/dp-skip.md +186 -0
- package/commands/dp-start.md +510 -0
- package/commands/dp-storytell.md +94 -0
- package/commands/dp-verify.md +207 -0
- package/package.json +59 -0
- package/skills/dp-color/SKILL.md +214 -0
- package/skills/dp-color/export_tokens.py +297 -0
- package/skills/dp-color/references/apca-contrast.md +87 -0
- package/skills/dp-color/references/hue-emotions.md +109 -0
- package/skills/dp-color/references/oklch-gamut.md +79 -0
- package/skills/dp-color/references/pitfalls.md +171 -0
- package/skills/dp-color/references/scale-patterns.md +206 -0
- package/skills/dp-color/references/tool-workflows.md +200 -0
- package/skills/dp-discovery/SKILL.md +480 -0
- package/skills/dp-eng_review/SKILL.md +471 -0
- package/skills/dp-eng_review/references/code-review-checklist.md +385 -0
- package/skills/dp-eng_review/references/react-patterns.md +512 -0
- package/skills/dp-eng_review/references/shadcn-patterns.md +510 -0
- package/skills/dp-eng_review/references/tailwind-conventions.md +351 -0
- package/skills/dp-journey/SKILL.md +682 -0
- package/skills/dp-journey/references/journey-types.md +97 -0
- package/skills/dp-journey/references/map-structures.md +177 -0
- package/skills/dp-journey/references/omnichannel-patterns.md +208 -0
- package/skills/dp-journey/references/research-methods.md +125 -0
- package/skills/dp-prd/SKILL.md +201 -0
- package/skills/dp-prd/references/claude-code-spec.md +107 -0
- package/skills/dp-prd/references/interview-questions.md +158 -0
- package/skills/dp-prd/references/section-templates.md +231 -0
- package/skills/dp-research/SKILL.md +540 -0
- package/skills/dp-research/references/facilitation-guide.md +291 -0
- package/skills/dp-research/references/interview-guide-template.md +190 -0
- package/skills/dp-research/references/method-selection.md +195 -0
- package/skills/dp-research/references/question-writing.md +244 -0
- package/skills/dp-research/references/research-report-template.md +363 -0
- package/skills/dp-research/references/synthesis-methods.md +289 -0
- package/skills/dp-research/references/usability-test-template.md +260 -0
- package/skills/dp-roadmap/SKILL.md +648 -0
- package/skills/dp-roadmap/references/prioritization-frameworks.md +312 -0
- package/skills/dp-roadmap/references/roadmap-structures.md +179 -0
- package/skills/dp-roadmap/references/roadmap-workshops.md +264 -0
- package/skills/dp-roadmap/references/theme-development.md +168 -0
- package/skills/dp-storytell/SKILL.md +645 -0
- package/skills/dp-storytell/references/audience-playbooks.md +260 -0
- package/skills/dp-storytell/references/content-type-templates.md +310 -0
- package/skills/dp-storytell/references/delivery-tactics.md +228 -0
- package/skills/dp-storytell/references/narrative-frameworks.md +259 -0
- package/skills/dp-ui/SKILL.md +503 -0
- package/skills/dp-ui/references/b2b-enterprise-patterns.md +319 -0
- package/skills/dp-ui/references/data-visualization.md +304 -0
- package/skills/dp-ui/references/visual-design-principles.md +237 -0
- package/skills/dp-ux/SKILL.md +414 -0
- package/skills/dp-ux/references/accessibility-checklist.md +128 -0
- package/skills/dp-ux/references/product-excellence.md +149 -0
- package/skills/dp-ux/references/usability-principles.md +140 -0
- package/skills/dp-ux/references/ux-patterns.md +221 -0
- package/templates/config.json +55 -0
- package/templates/context.md +96 -0
- package/templates/project.md +83 -0
- package/templates/requirements.md +137 -0
- package/templates/roadmap.md +168 -0
- package/templates/state.md +107 -0
package/bin/install.js
ADDED
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const readline = require('readline');
|
|
6
|
+
const { execSync } = require('child_process');
|
|
7
|
+
|
|
8
|
+
const VERSION = '1.0.0';
|
|
9
|
+
const PACKAGE_NAME = 'design-protocol';
|
|
10
|
+
const PACKAGE_DIR = path.join(__dirname, '..');
|
|
11
|
+
let VERBOSE = false;
|
|
12
|
+
|
|
13
|
+
// ANSI colors
|
|
14
|
+
const c = {
|
|
15
|
+
reset: '\x1b[0m',
|
|
16
|
+
bright: '\x1b[1m',
|
|
17
|
+
dim: '\x1b[2m',
|
|
18
|
+
green: '\x1b[32m',
|
|
19
|
+
yellow: '\x1b[33m',
|
|
20
|
+
blue: '\x1b[34m',
|
|
21
|
+
magenta: '\x1b[35m',
|
|
22
|
+
cyan: '\x1b[36m',
|
|
23
|
+
red: '\x1b[31m'
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function log(msg, color = 'reset') {
|
|
27
|
+
console.log(`${c[color]}${msg}${c.reset}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function logStep(step, total, msg) {
|
|
31
|
+
console.log(`${c.cyan}[${step}/${total}]${c.reset} ${msg}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function logSuccess(msg) {
|
|
35
|
+
console.log(` ${c.green}✓${c.reset} ${msg}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function logSkip(msg) {
|
|
39
|
+
console.log(` ${c.yellow}○${c.reset} ${msg}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function logError(msg) {
|
|
43
|
+
console.log(` ${c.red}✗${c.reset} ${msg}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function logVerbose(msg) {
|
|
47
|
+
if (VERBOSE) console.log(` ${c.dim} → ${msg}${c.reset}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function printBanner() {
|
|
51
|
+
console.log(`\n${c.magenta}${c.bright} DP ${c.reset}${c.cyan}Design Protocol${c.reset} ${c.dim}v${VERSION}${c.reset}`);
|
|
52
|
+
console.log(`${c.dim} Complete design workflow for Claude Code${c.reset}\n`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getClaudeDir(location) {
|
|
56
|
+
if (location === 'global') {
|
|
57
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
58
|
+
return process.env.CLAUDE_CONFIG_DIR || path.join(homeDir, '.claude');
|
|
59
|
+
}
|
|
60
|
+
return path.join(process.cwd(), '.claude');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function ensureDir(dir) {
|
|
64
|
+
if (!fs.existsSync(dir)) {
|
|
65
|
+
logVerbose(`mkdir ${dir}`);
|
|
66
|
+
try {
|
|
67
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
68
|
+
} catch (err) {
|
|
69
|
+
if (err.code === 'EACCES') {
|
|
70
|
+
throw new Error(`Permission denied creating directory: ${dir}\n Try running with sudo or check folder permissions.`);
|
|
71
|
+
}
|
|
72
|
+
throw new Error(`Failed to create directory: ${dir}\n ${err.message}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const MAX_COPY_DEPTH = 10;
|
|
78
|
+
const SKIP_ENTRIES = new Set(['.git', '.DS_Store', '.env', 'node_modules', '.next']);
|
|
79
|
+
|
|
80
|
+
function copyRecursive(src, dest, depth = 0) {
|
|
81
|
+
if (!fs.existsSync(src)) return 0;
|
|
82
|
+
if (depth > MAX_COPY_DEPTH) {
|
|
83
|
+
logError(`Skipping deeply nested path (>${MAX_COPY_DEPTH} levels): ${src}`);
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Skip symlinks — only copy real files
|
|
88
|
+
const lstats = fs.lstatSync(src);
|
|
89
|
+
if (lstats.isSymbolicLink()) return 0;
|
|
90
|
+
|
|
91
|
+
let count = 0;
|
|
92
|
+
|
|
93
|
+
if (lstats.isDirectory()) {
|
|
94
|
+
ensureDir(dest);
|
|
95
|
+
const files = fs.readdirSync(src);
|
|
96
|
+
for (const file of files) {
|
|
97
|
+
if (SKIP_ENTRIES.has(file)) continue;
|
|
98
|
+
count += copyRecursive(
|
|
99
|
+
path.join(src, file),
|
|
100
|
+
path.join(dest, file),
|
|
101
|
+
depth + 1
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
try {
|
|
106
|
+
fs.copyFileSync(src, dest);
|
|
107
|
+
logVerbose(`${path.basename(src)}`);
|
|
108
|
+
} catch (err) {
|
|
109
|
+
if (err.code === 'EACCES') {
|
|
110
|
+
throw new Error(`Permission denied writing file: ${dest}`);
|
|
111
|
+
}
|
|
112
|
+
throw new Error(`Failed to copy ${path.basename(src)} → ${dest}\n ${err.message}`);
|
|
113
|
+
}
|
|
114
|
+
count = 1;
|
|
115
|
+
}
|
|
116
|
+
return count;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function countFiles(dir) {
|
|
120
|
+
if (!fs.existsSync(dir)) return 0;
|
|
121
|
+
let count = 0;
|
|
122
|
+
const items = fs.readdirSync(dir);
|
|
123
|
+
for (const item of items) {
|
|
124
|
+
const itemPath = path.join(dir, item);
|
|
125
|
+
const stats = fs.statSync(itemPath);
|
|
126
|
+
if (stats.isDirectory()) {
|
|
127
|
+
count += countFiles(itemPath);
|
|
128
|
+
} else {
|
|
129
|
+
count++;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return count;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function prompt(question) {
|
|
136
|
+
const rl = readline.createInterface({
|
|
137
|
+
input: process.stdin,
|
|
138
|
+
output: process.stdout
|
|
139
|
+
});
|
|
140
|
+
return new Promise((resolve) => {
|
|
141
|
+
rl.question(question, (answer) => {
|
|
142
|
+
rl.close();
|
|
143
|
+
resolve(answer.trim().toLowerCase());
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function getLatestVersion() {
|
|
149
|
+
try {
|
|
150
|
+
const result = execSync(`npm view ${PACKAGE_NAME} version`, { encoding: 'utf8' });
|
|
151
|
+
return result.trim();
|
|
152
|
+
} catch (err) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function compareVersions(v1, v2) {
|
|
158
|
+
const parts1 = v1.split('.').map(Number);
|
|
159
|
+
const parts2 = v2.split('.').map(Number);
|
|
160
|
+
|
|
161
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
162
|
+
const p1 = parts1[i] || 0;
|
|
163
|
+
const p2 = parts2[i] || 0;
|
|
164
|
+
if (p1 > p2) return 1;
|
|
165
|
+
if (p1 < p2) return -1;
|
|
166
|
+
}
|
|
167
|
+
return 0;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function checkForUpdate() {
|
|
171
|
+
log('\nChecking for updates...', 'dim');
|
|
172
|
+
|
|
173
|
+
const latest = getLatestVersion();
|
|
174
|
+
if (!latest) {
|
|
175
|
+
logError('Could not check for updates. Are you online?');
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const comparison = compareVersions(latest, VERSION);
|
|
180
|
+
|
|
181
|
+
if (comparison > 0) {
|
|
182
|
+
log(`\n${c.yellow}Update available!${c.reset} ${VERSION} → ${c.green}${latest}${c.reset}\n`);
|
|
183
|
+
return latest;
|
|
184
|
+
} else if (comparison === 0) {
|
|
185
|
+
log(`\n${c.green}✓${c.reset} You have the latest version (${VERSION})\n`);
|
|
186
|
+
return false;
|
|
187
|
+
} else {
|
|
188
|
+
log(`\n${c.green}✓${c.reset} You have a newer version (${VERSION}) than npm (${latest})\n`);
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async function performUpdate(location) {
|
|
194
|
+
log(`\nUpdating DP...`, 'bright');
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
// Run npx with latest version
|
|
198
|
+
log('Downloading latest version...', 'dim');
|
|
199
|
+
execSync(`npx ${PACKAGE_NAME}@latest --${location} --auto`, {
|
|
200
|
+
stdio: 'inherit',
|
|
201
|
+
encoding: 'utf8'
|
|
202
|
+
});
|
|
203
|
+
return true;
|
|
204
|
+
} catch (err) {
|
|
205
|
+
logError(`Update failed: ${err.message}`);
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async function main() {
|
|
211
|
+
const args = process.argv.slice(2);
|
|
212
|
+
|
|
213
|
+
// Parse arguments
|
|
214
|
+
const isGlobal = args.includes('--global') || args.includes('-g');
|
|
215
|
+
const isLocal = args.includes('--local') || args.includes('-l');
|
|
216
|
+
const isAuto = args.includes('--auto');
|
|
217
|
+
const isUninstall = args.includes('--uninstall') || args.includes('-u');
|
|
218
|
+
const isUpdate = args.includes('--update') || args.includes('--upgrade');
|
|
219
|
+
const isCheckUpdate = args.includes('--check-update');
|
|
220
|
+
const isHelp = args.includes('--help') || args.includes('-h');
|
|
221
|
+
const showVersion = args.includes('--version') || args.includes('-v');
|
|
222
|
+
VERBOSE = args.includes('--verbose');
|
|
223
|
+
|
|
224
|
+
if (showVersion) {
|
|
225
|
+
console.log(`dp v${VERSION}`);
|
|
226
|
+
process.exit(0);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (isHelp) {
|
|
230
|
+
console.log(`
|
|
231
|
+
${c.bright}DP - Design Protocol v${VERSION}${c.reset}
|
|
232
|
+
|
|
233
|
+
Usage: npx design-protocol [options]
|
|
234
|
+
|
|
235
|
+
Options:
|
|
236
|
+
--global, -g Install to ~/.claude/ (all projects)
|
|
237
|
+
--local, -l Install to ./.claude/ (current project only)
|
|
238
|
+
--auto Non-interactive install (default: global)
|
|
239
|
+
--update Update to the latest version
|
|
240
|
+
--check-update Check if updates are available
|
|
241
|
+
--uninstall, -u Remove DP from specified location
|
|
242
|
+
--verbose Show detailed output for troubleshooting
|
|
243
|
+
--version, -v Show version number
|
|
244
|
+
--help, -h Show this help message
|
|
245
|
+
|
|
246
|
+
Examples:
|
|
247
|
+
npx design-protocol # Interactive installation
|
|
248
|
+
npx design-protocol --global # Install globally
|
|
249
|
+
npx design-protocol --local # Install to current project
|
|
250
|
+
npx design-protocol --update # Update to latest version
|
|
251
|
+
npx design-protocol -g -u # Uninstall from global
|
|
252
|
+
|
|
253
|
+
${c.bright}What Gets Installed:${c.reset}
|
|
254
|
+
~/.claude/skills/ 10 design skills (dp-discovery, dp-prd, dp-journey, dp-roadmap, dp-ux, dp-color, dp-ui, dp-eng_review, dp-research, dp-storytell)
|
|
255
|
+
~/.claude/commands/ 7 workflow commands (dp:start, dp:execute, etc.)
|
|
256
|
+
~/.claude/agents/ 2 specialized agents
|
|
257
|
+
|
|
258
|
+
${c.bright}Workflow:${c.reset}
|
|
259
|
+
/dp:start → /dp:discovery → /dp:ux → /dp:execute → /dp:ui → /dp:execute → /dp:eng_review → /dp:verify
|
|
260
|
+
`);
|
|
261
|
+
process.exit(0);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Check for updates only
|
|
265
|
+
if (isCheckUpdate) {
|
|
266
|
+
printBanner();
|
|
267
|
+
await checkForUpdate();
|
|
268
|
+
process.exit(0);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Update mode
|
|
272
|
+
if (isUpdate) {
|
|
273
|
+
printBanner();
|
|
274
|
+
const latest = await checkForUpdate();
|
|
275
|
+
if (latest) {
|
|
276
|
+
const location = isLocal ? 'local' : 'global';
|
|
277
|
+
const answer = await prompt(`Update to v${latest}? [Y/n]: `);
|
|
278
|
+
if (answer !== 'n' && answer !== 'no') {
|
|
279
|
+
await performUpdate(location);
|
|
280
|
+
} else {
|
|
281
|
+
log('Update cancelled.', 'yellow');
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
process.exit(0);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
printBanner();
|
|
288
|
+
|
|
289
|
+
// Determine installation location
|
|
290
|
+
let location;
|
|
291
|
+
if (isGlobal || isAuto) {
|
|
292
|
+
location = 'global';
|
|
293
|
+
} else if (isLocal) {
|
|
294
|
+
location = 'local';
|
|
295
|
+
} else {
|
|
296
|
+
log('\nWhere would you like to install DP?\n', 'bright');
|
|
297
|
+
console.log(' 1. Global (~/.claude/) - Available in all projects');
|
|
298
|
+
console.log(' 2. Local (./.claude/) - Current project only\n');
|
|
299
|
+
const answer = await prompt('Choose [1/2] (default: 1): ');
|
|
300
|
+
location = answer === '2' ? 'local' : 'global';
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const claudeDir = getClaudeDir(location);
|
|
304
|
+
const skillsDir = path.join(claudeDir, 'skills');
|
|
305
|
+
const commandsDir = path.join(claudeDir, 'commands');
|
|
306
|
+
const agentsDir = path.join(claudeDir, 'agents');
|
|
307
|
+
|
|
308
|
+
if (VERBOSE) {
|
|
309
|
+
log('', 'dim');
|
|
310
|
+
log(' Resolved paths:', 'dim');
|
|
311
|
+
log(` PACKAGE_DIR: ${PACKAGE_DIR}`, 'dim');
|
|
312
|
+
log(` claudeDir: ${claudeDir}`, 'dim');
|
|
313
|
+
log(` CLAUDE_CONFIG_DIR: ${process.env.CLAUDE_CONFIG_DIR || '(not set)'}`, 'dim');
|
|
314
|
+
log(` HOME: ${process.env.HOME || process.env.USERPROFILE}`, 'dim');
|
|
315
|
+
log('', 'dim');
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (isUninstall) {
|
|
319
|
+
await runUninstall(location, { skillsDir, commandsDir, agentsDir, claudeDir });
|
|
320
|
+
} else {
|
|
321
|
+
await runInstall(location, { skillsDir, commandsDir, agentsDir, claudeDir }, isAuto);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// ─── Uninstall ────────────────────────────────────────────────────────────────
|
|
326
|
+
|
|
327
|
+
async function runUninstall(location, dirs) {
|
|
328
|
+
log(`\nUninstalling from ${location} location...`, 'yellow');
|
|
329
|
+
log(`Target: ${dirs.claudeDir}`, 'dim');
|
|
330
|
+
|
|
331
|
+
let removed = 0;
|
|
332
|
+
|
|
333
|
+
const skillNames = ['dp-discovery', 'dp-prd', 'dp-journey', 'dp-roadmap', 'dp-ux', 'dp-color', 'dp-ui', 'dp-eng_review', 'dp-research', 'dp-storytell'];
|
|
334
|
+
for (const name of skillNames) {
|
|
335
|
+
const skillPath = path.join(dirs.skillsDir, name);
|
|
336
|
+
if (fs.existsSync(skillPath)) {
|
|
337
|
+
fs.rmSync(skillPath, { recursive: true, force: true });
|
|
338
|
+
logSuccess(`Removed skill: ${name}`);
|
|
339
|
+
removed++;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const commandFiles = fs.readdirSync(path.join(PACKAGE_DIR, 'commands')).filter(f => f.endsWith('.md'));
|
|
344
|
+
for (const file of commandFiles) {
|
|
345
|
+
const cmdPath = path.join(dirs.commandsDir, file);
|
|
346
|
+
if (fs.existsSync(cmdPath)) {
|
|
347
|
+
fs.unlinkSync(cmdPath);
|
|
348
|
+
logSuccess(`Removed command: ${file}`);
|
|
349
|
+
removed++;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const agentFiles = fs.readdirSync(path.join(PACKAGE_DIR, 'agents')).filter(f => f.endsWith('.md'));
|
|
354
|
+
for (const file of agentFiles) {
|
|
355
|
+
const agentPath = path.join(dirs.agentsDir, file);
|
|
356
|
+
if (fs.existsSync(agentPath)) {
|
|
357
|
+
fs.unlinkSync(agentPath);
|
|
358
|
+
logSuccess(`Removed agent: ${file}`);
|
|
359
|
+
removed++;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (removed > 0) {
|
|
364
|
+
log(`\n${c.green}DP uninstalled successfully!${c.reset}\n`);
|
|
365
|
+
} else {
|
|
366
|
+
log(`\n${c.yellow}No DP installation found at ${dirs.claudeDir}${c.reset}\n`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// ─── Install ──────────────────────────────────────────────────────────────────
|
|
371
|
+
|
|
372
|
+
async function runInstall(location, dirs, isAuto) {
|
|
373
|
+
const totalSteps = 4;
|
|
374
|
+
log(`\nInstalling to ${location} location...`, 'bright');
|
|
375
|
+
log(`Target: ${dirs.claudeDir}\n`, 'dim');
|
|
376
|
+
|
|
377
|
+
// Step 1: Skills
|
|
378
|
+
logStep(1, totalSteps, 'Installing skills...');
|
|
379
|
+
const srcSkills = path.join(PACKAGE_DIR, 'skills');
|
|
380
|
+
const skillDirs = fs.readdirSync(srcSkills).filter(f =>
|
|
381
|
+
fs.statSync(path.join(srcSkills, f)).isDirectory()
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
for (const skill of skillDirs) {
|
|
385
|
+
const src = path.join(srcSkills, skill);
|
|
386
|
+
const dest = path.join(dirs.skillsDir, skill);
|
|
387
|
+
|
|
388
|
+
if (fs.existsSync(dest) && !isAuto) {
|
|
389
|
+
const answer = await prompt(` Overwrite ${skill}? [y/N]: `);
|
|
390
|
+
if (answer !== 'y' && answer !== 'yes') {
|
|
391
|
+
logSkip(skill);
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
fs.rmSync(dest, { recursive: true, force: true });
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const count = copyRecursive(src, dest);
|
|
398
|
+
logSuccess(`${skill} (${count} files)`);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Step 2: Commands
|
|
402
|
+
logStep(2, totalSteps, 'Installing commands...');
|
|
403
|
+
ensureDir(dirs.commandsDir);
|
|
404
|
+
const srcCommands = path.join(PACKAGE_DIR, 'commands');
|
|
405
|
+
const commandFiles = fs.readdirSync(srcCommands).filter(f => f.endsWith('.md'));
|
|
406
|
+
|
|
407
|
+
for (const file of commandFiles) {
|
|
408
|
+
fs.copyFileSync(path.join(srcCommands, file), path.join(dirs.commandsDir, file));
|
|
409
|
+
logSuccess(file.replace('.md', ''));
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Step 3: Agents
|
|
413
|
+
logStep(3, totalSteps, 'Installing agents...');
|
|
414
|
+
ensureDir(dirs.agentsDir);
|
|
415
|
+
const srcAgents = path.join(PACKAGE_DIR, 'agents');
|
|
416
|
+
const agentFiles = fs.readdirSync(srcAgents).filter(f => f.endsWith('.md'));
|
|
417
|
+
|
|
418
|
+
for (const file of agentFiles) {
|
|
419
|
+
fs.copyFileSync(path.join(srcAgents, file), path.join(dirs.agentsDir, file));
|
|
420
|
+
logSuccess(file.replace('.md', ''));
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Step 4: Summary
|
|
424
|
+
logStep(4, totalSteps, 'Installation complete!');
|
|
425
|
+
printSummary(
|
|
426
|
+
{ skills: skillDirs.length, commands: commandFiles.length, agents: agentFiles.length },
|
|
427
|
+
dirs
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// ─── Summary ──────────────────────────────────────────────────────────────────
|
|
432
|
+
|
|
433
|
+
function printSummary(counts, dirs) {
|
|
434
|
+
console.log(`
|
|
435
|
+
${c.green}${c.bright}DP ${VERSION} installed successfully!${c.reset}
|
|
436
|
+
|
|
437
|
+
${c.bright}Installed:${c.reset}
|
|
438
|
+
${c.cyan}${counts.skills}${c.reset} skills → ${dirs.skillsDir}
|
|
439
|
+
${c.cyan}${counts.commands}${c.reset} commands → ${dirs.commandsDir}
|
|
440
|
+
${c.cyan}${counts.agents}${c.reset} agents → ${dirs.agentsDir}
|
|
441
|
+
|
|
442
|
+
${c.bright}Quick Start:${c.reset}
|
|
443
|
+
${c.cyan}/dp:start${c.reset} Start a new design workflow
|
|
444
|
+
${c.cyan}/dp:progress${c.reset} Check workflow status
|
|
445
|
+
${c.cyan}/dp:execute${c.reset} Generate implementation
|
|
446
|
+
|
|
447
|
+
${c.bright}Design Skills:${c.reset}
|
|
448
|
+
${c.cyan}/dp:discovery${c.reset} Discovery & requirements
|
|
449
|
+
${c.cyan}/dp:ux${c.reset} UX principles & states
|
|
450
|
+
${c.cyan}/dp:ui${c.reset} Visual design & tokens
|
|
451
|
+
${c.cyan}/dp:eng_review${c.reset} Code review & a11y
|
|
452
|
+
|
|
453
|
+
${c.bright}Workflow:${c.reset}
|
|
454
|
+
Discovery → UX → ${c.yellow}Execute(wireframe)${c.reset} → UI → ${c.yellow}Execute(polished)${c.reset} → Review
|
|
455
|
+
|
|
456
|
+
${c.dim}Restart Claude Code to load DP.${c.reset}
|
|
457
|
+
`);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
main().catch((err) => {
|
|
461
|
+
logError(`Installation failed: ${err.message}`);
|
|
462
|
+
console.error(err);
|
|
463
|
+
process.exit(1);
|
|
464
|
+
});
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dp-back
|
|
3
|
+
description: Go back to a previous DP workflow phase. Use to revisit decisions, update context, or re-run a phase with new information.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /dp:back — Return to Previous Phase
|
|
7
|
+
|
|
8
|
+
You are navigating back in the DP workflow. This allows revisiting earlier phases to update or refine design work.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
- New information invalidates earlier decisions
|
|
13
|
+
- Need to update discovery based on research findings
|
|
14
|
+
- Want to refine UX decisions after UI work revealed issues
|
|
15
|
+
- Stakeholder feedback requires earlier phase changes
|
|
16
|
+
- Review found issues that need design-level fixes
|
|
17
|
+
|
|
18
|
+
## Workflow
|
|
19
|
+
|
|
20
|
+
### Step 1: Check Workflow Exists
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
ls .design/config.json 2>/dev/null
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Step 2: Get Current Position
|
|
27
|
+
|
|
28
|
+
Read `.design/STATE.md` and `.design/config.json` to determine:
|
|
29
|
+
- Current phase number
|
|
30
|
+
- Completed phases
|
|
31
|
+
- Available phases to return to
|
|
32
|
+
|
|
33
|
+
### Step 3: Present Options
|
|
34
|
+
|
|
35
|
+
**If current phase > 1:**
|
|
36
|
+
```
|
|
37
|
+
CURRENT POSITION: Phase [N] — [Phase Name]
|
|
38
|
+
|
|
39
|
+
Go back to:
|
|
40
|
+
1. Discovery — Update problem/users/requirements
|
|
41
|
+
2. UX — Revise user flows and states
|
|
42
|
+
[3. UI — Adjust visual specs]
|
|
43
|
+
|
|
44
|
+
Or enter phase number (1-[N-1])
|
|
45
|
+
|
|
46
|
+
Which phase? (1-[N-1] or cancel)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**If on first phase:**
|
|
50
|
+
```
|
|
51
|
+
You're on Phase 1 (Discovery) — can't go back further.
|
|
52
|
+
|
|
53
|
+
Options:
|
|
54
|
+
• Run /dp:discovery to start/redo discovery
|
|
55
|
+
• Run /dp:progress to see status
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Step 4: Handle Navigation
|
|
59
|
+
|
|
60
|
+
**When user selects a phase:**
|
|
61
|
+
|
|
62
|
+
1. Confirm the action:
|
|
63
|
+
```
|
|
64
|
+
Going back to: Phase [X] — [Phase Name]
|
|
65
|
+
|
|
66
|
+
This will:
|
|
67
|
+
✓ Set Phase [X] as current
|
|
68
|
+
✓ Keep existing [Phase X] output for reference
|
|
69
|
+
○ Later phases remain but may need updates
|
|
70
|
+
|
|
71
|
+
Continue? (y/n)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
2. Update `.design/STATE.md`:
|
|
75
|
+
- Set current phase to selected phase
|
|
76
|
+
- Add navigation to activity log
|
|
77
|
+
- Note any context about why going back
|
|
78
|
+
|
|
79
|
+
3. Update `.design/config.json`:
|
|
80
|
+
- Set `current_phase` to selected phase number
|
|
81
|
+
- Don't remove later phases from `phases_completed` (they exist but may be stale)
|
|
82
|
+
|
|
83
|
+
4. Rename existing phase file (if exists):
|
|
84
|
+
- `.design/phases/DISCOVERY.md` → `.design/phases/DISCOVERY.v1.md`
|
|
85
|
+
- Allows fresh start while preserving history
|
|
86
|
+
|
|
87
|
+
**Output:**
|
|
88
|
+
```
|
|
89
|
+
✓ Returned to: Phase [X] — [Phase Name]
|
|
90
|
+
|
|
91
|
+
Previous output preserved as: [PHASE_NAME].v1.md
|
|
92
|
+
|
|
93
|
+
Current Position:
|
|
94
|
+
Phase: [X] of 4 ([Phase Name])
|
|
95
|
+
Status: Ready
|
|
96
|
+
Progress: [██░░░░░░░░] [X]%
|
|
97
|
+
|
|
98
|
+
Note: Phases [X+1] through [N] may need updates after you modify this phase.
|
|
99
|
+
|
|
100
|
+
Next: Run /[skill] to redo this phase
|
|
101
|
+
Or /dp:discuss to capture new context first
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Step 5: Provide Context
|
|
105
|
+
|
|
106
|
+
When going back, remind user of relevant context:
|
|
107
|
+
|
|
108
|
+
**Going back to Discovery:**
|
|
109
|
+
```
|
|
110
|
+
CONTEXT FOR DISCOVERY REDO
|
|
111
|
+
────────────────────────────────────────────────────────────────────────────────
|
|
112
|
+
What triggered going back:
|
|
113
|
+
• [from user or inferred]
|
|
114
|
+
|
|
115
|
+
Existing outputs that may be affected:
|
|
116
|
+
• UX-DECISIONS.md — May need updates
|
|
117
|
+
• UI-SPEC.md — May need updates
|
|
118
|
+
|
|
119
|
+
Key questions to reconsider:
|
|
120
|
+
• Is the problem statement still accurate?
|
|
121
|
+
• Has our understanding of users changed?
|
|
122
|
+
• Do requirements need reprioritization?
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Going back to UX:**
|
|
126
|
+
```
|
|
127
|
+
CONTEXT FOR UX REDO
|
|
128
|
+
────────────────────────────────────────────────────────────────────────────────
|
|
129
|
+
From Discovery (unchanged):
|
|
130
|
+
• Problem: [problem statement]
|
|
131
|
+
• User: [primary user]
|
|
132
|
+
|
|
133
|
+
What may need updating:
|
|
134
|
+
• User flows
|
|
135
|
+
• State definitions
|
|
136
|
+
• Accessibility requirements
|
|
137
|
+
|
|
138
|
+
Existing UI spec may need realignment after UX changes.
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Step 6: Edge Cases
|
|
142
|
+
|
|
143
|
+
**Going back with uncommitted changes:**
|
|
144
|
+
```
|
|
145
|
+
Note: You have changes in progress for Phase [N].
|
|
146
|
+
|
|
147
|
+
Options:
|
|
148
|
+
1. Go back anyway (current progress will be marked incomplete)
|
|
149
|
+
2. Complete current phase first, then go back
|
|
150
|
+
3. Cancel
|
|
151
|
+
|
|
152
|
+
Choice?
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Going back to a skipped phase:**
|
|
156
|
+
```
|
|
157
|
+
Phase [X] was previously skipped.
|
|
158
|
+
|
|
159
|
+
Going back will:
|
|
160
|
+
• Set Phase [X] as current
|
|
161
|
+
• Allow you to complete it properly
|
|
162
|
+
|
|
163
|
+
This is a good way to fill in a skipped phase.
|
|
164
|
+
|
|
165
|
+
Continue? (y/n)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Multiple iterations:**
|
|
169
|
+
|
|
170
|
+
Track version history in STATE.md:
|
|
171
|
+
```markdown
|
|
172
|
+
## Iteration History
|
|
173
|
+
|
|
174
|
+
| Phase | Version | Date | Reason |
|
|
175
|
+
|-------|---------|------|--------|
|
|
176
|
+
| Discovery | v1 | 2024-01-15 | Initial |
|
|
177
|
+
| Discovery | v2 | 2024-01-18 | Updated after research |
|
|
178
|
+
| UX | v1 | 2024-01-16 | Initial |
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Version Management
|
|
182
|
+
|
|
183
|
+
When going back, preserve history:
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
.design/phases/
|
|
187
|
+
├── DISCOVERY.md # Current version (v2)
|
|
188
|
+
├── DISCOVERY.v1.md # Previous version
|
|
189
|
+
├── UX-DECISIONS.md # Current (may be stale)
|
|
190
|
+
└── UI-SPEC.md # Current (may be stale)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Maximum versions to keep: 3 (oldest auto-deleted)
|
|
194
|
+
|
|
195
|
+
## State Updates
|
|
196
|
+
|
|
197
|
+
**STATE.md activity log:**
|
|
198
|
+
```markdown
|
|
199
|
+
### Last Activity
|
|
200
|
+
- **Date:** [TIMESTAMP]
|
|
201
|
+
- **Action:** Returned to Discovery phase (was on UI)
|
|
202
|
+
- **Reason:** Research findings changed user understanding
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Integration Notes
|
|
206
|
+
|
|
207
|
+
- Skills should check STATE.md to see if they're running as a redo
|
|
208
|
+
- If redoing, skill can offer to show diff from previous version
|
|
209
|
+
- Later phases should be flagged as "may need update" in progress view
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Workflow Navigation
|
|
214
|
+
|
|
215
|
+
| | |
|
|
216
|
+
|---|---|
|
|
217
|
+
| **This command** | `/dp:back` — Return to previous phase |
|
|
218
|
+
| **Use when** | New information invalidates earlier decisions |
|
|
219
|
+
| **Returns to** | The previous phase (or a specific phase if specified) |
|
|
220
|
+
| **Then run** | The phase skill for that phase to redo it |
|
|
221
|
+
| **Related** | `/dp:skip` — Skip forward if redo isn't needed after all |
|