@mehuljatiya/troupe 0.1.15
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 +84 -0
- package/bin/cli.js +20 -0
- package/bin/design.js +27 -0
- package/commands/document-component.md +505 -0
- package/commands/document.md +46 -0
- package/commands/figma.md +56 -0
- package/commands/handoff.md +92 -0
- package/commands/new-component.md +26 -0
- package/commands/qa.md +89 -0
- package/commands/review.md +49 -0
- package/commands/spec.md +77 -0
- package/commands/tokens.md +42 -0
- package/package.json +44 -0
- package/src/setup.js +397 -0
package/src/setup.js
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import { execSync, spawnSync } from 'child_process'
|
|
2
|
+
import { existsSync, mkdirSync, copyFileSync, readdirSync, appendFileSync } from 'fs'
|
|
3
|
+
import { join } from 'path'
|
|
4
|
+
import { homedir } from 'os'
|
|
5
|
+
import { fileURLToPath } from 'url'
|
|
6
|
+
import { dirname } from 'path'
|
|
7
|
+
import { confirm } from '@inquirer/prompts'
|
|
8
|
+
import chalk from 'chalk'
|
|
9
|
+
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
11
|
+
|
|
12
|
+
export async function runSetup() {
|
|
13
|
+
console.log()
|
|
14
|
+
console.log(chalk.bold('Troupe') + ' ✦')
|
|
15
|
+
console.log("Let's get you set up. This takes about 2 minutes.\n")
|
|
16
|
+
|
|
17
|
+
// ── Node version check ───────────────────────────────────────────────────
|
|
18
|
+
const nodeVersion = process.versions.node
|
|
19
|
+
const major = parseInt(nodeVersion.split('.')[0], 10)
|
|
20
|
+
if (major < 20) {
|
|
21
|
+
console.log(chalk.yellow(` Node.js v${nodeVersion} detected — version 20 or higher is required.\n`))
|
|
22
|
+
await upgradeNode()
|
|
23
|
+
// upgradeNode either re-execs (nvm path) or exits
|
|
24
|
+
process.exit(1)
|
|
25
|
+
}
|
|
26
|
+
console.log(chalk.green(` ✓ Node.js v${nodeVersion}\n`))
|
|
27
|
+
|
|
28
|
+
// ── Step 1: Claude Code ──────────────────────────────────────────────────
|
|
29
|
+
console.log(chalk.bold('Step 1/5') + ' — Claude Code')
|
|
30
|
+
|
|
31
|
+
const claudeInstalled = isClaudeInstalled()
|
|
32
|
+
|
|
33
|
+
if (claudeInstalled) {
|
|
34
|
+
console.log(chalk.green(' ✓ Claude Code is already installed\n'))
|
|
35
|
+
} else {
|
|
36
|
+
console.log(chalk.yellow(' Claude Code is not installed.'))
|
|
37
|
+
|
|
38
|
+
const shouldInstall = await confirm({
|
|
39
|
+
message: 'Install it now? (requires npm)',
|
|
40
|
+
default: true,
|
|
41
|
+
}).catch(() => false)
|
|
42
|
+
|
|
43
|
+
if (!shouldInstall) {
|
|
44
|
+
console.log()
|
|
45
|
+
console.log('No problem. Install it yourself when ready:')
|
|
46
|
+
console.log(' ' + chalk.cyan('npm install -g @anthropic-ai/claude-code'))
|
|
47
|
+
console.log('\nThen re-run: ' + chalk.cyan('npx @mehuljatiya/troupe setup'))
|
|
48
|
+
process.exit(0)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log(chalk.dim(' Installing...'))
|
|
52
|
+
try {
|
|
53
|
+
npmInstallGlobal('@anthropic-ai/claude-code')
|
|
54
|
+
console.log(chalk.green(' ✓ Claude Code installed\n'))
|
|
55
|
+
} catch {
|
|
56
|
+
console.log()
|
|
57
|
+
console.log(chalk.red(' Installation failed.'))
|
|
58
|
+
console.log(' Try running this manually:')
|
|
59
|
+
console.log(' ' + chalk.cyan('npm install -g @anthropic-ai/claude-code'))
|
|
60
|
+
process.exit(1)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ── Step 2: Slash commands ───────────────────────────────────────────────
|
|
65
|
+
console.log(chalk.bold('Step 2/5') + ' — Installing slash commands')
|
|
66
|
+
|
|
67
|
+
const { installed, skipped } = installSlashCommands()
|
|
68
|
+
|
|
69
|
+
if (skipped.length > 0) {
|
|
70
|
+
console.log(chalk.yellow(` ${skipped.length} workflow(s) already exist — skipping to avoid overwriting`))
|
|
71
|
+
console.log(chalk.dim(' (delete them from ~/.claude/commands/ and re-run to reset)'))
|
|
72
|
+
}
|
|
73
|
+
if (installed.length > 0) {
|
|
74
|
+
console.log(chalk.green(` ✓ Installed ${installed.length} design workflow(s)`))
|
|
75
|
+
}
|
|
76
|
+
console.log()
|
|
77
|
+
|
|
78
|
+
// ── Step 3: Figma MCP ────────────────────────────────────────────────────
|
|
79
|
+
console.log(chalk.bold('Step 3/5') + ' — Figma ' + chalk.dim('(optional)'))
|
|
80
|
+
console.log(chalk.dim(' Lets Claude read your Figma designs directly — no copy-pasting needed.\n'))
|
|
81
|
+
|
|
82
|
+
const wantsFigma = await confirm({
|
|
83
|
+
message: 'Connect Figma?',
|
|
84
|
+
default: true,
|
|
85
|
+
}).catch(() => false)
|
|
86
|
+
|
|
87
|
+
let figmaConnected = false
|
|
88
|
+
let figmaAuthNeeded = false
|
|
89
|
+
|
|
90
|
+
if (wantsFigma) {
|
|
91
|
+
const alreadyConfigured = isFigmaMcpConfigured()
|
|
92
|
+
|
|
93
|
+
if (alreadyConfigured) {
|
|
94
|
+
console.log(chalk.green(' ✓ Figma is already configured\n'))
|
|
95
|
+
figmaConnected = true
|
|
96
|
+
} else {
|
|
97
|
+
try {
|
|
98
|
+
execSync(
|
|
99
|
+
'claude mcp add --transport http figma https://mcp.figma.com/mcp --scope user',
|
|
100
|
+
{ stdio: 'pipe' }
|
|
101
|
+
)
|
|
102
|
+
console.log(chalk.green(' ✓ Figma MCP configured'))
|
|
103
|
+
figmaConnected = true
|
|
104
|
+
figmaAuthNeeded = true
|
|
105
|
+
} catch {
|
|
106
|
+
console.log(chalk.yellow(' Could not auto-configure Figma.'))
|
|
107
|
+
console.log(' Run this manually after setup:')
|
|
108
|
+
console.log(' ' + chalk.cyan('claude mcp add --transport http figma https://mcp.figma.com/mcp --scope user'))
|
|
109
|
+
console.log()
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (figmaConnected) {
|
|
113
|
+
console.log()
|
|
114
|
+
console.log(chalk.bold(' Authenticate Figma now') + ' — takes 30 seconds, saves you the step later.\n')
|
|
115
|
+
console.log(' Claude will open. Follow these 3 steps inside it:')
|
|
116
|
+
console.log(' 1. Type ' + chalk.cyan('/mcp') + ' and press Enter')
|
|
117
|
+
console.log(' 2. Select ' + chalk.cyan('figma') + ' → ' + chalk.cyan('Authenticate'))
|
|
118
|
+
console.log(' 3. Log in to Figma in the browser that opens, then come back here')
|
|
119
|
+
console.log(' 4. Type ' + chalk.cyan('/exit') + ' to return to setup\n')
|
|
120
|
+
|
|
121
|
+
const doAuth = await confirm({
|
|
122
|
+
message: 'Open Claude to authenticate Figma now?',
|
|
123
|
+
default: true,
|
|
124
|
+
}).catch(() => false)
|
|
125
|
+
|
|
126
|
+
if (doAuth) {
|
|
127
|
+
try {
|
|
128
|
+
execSync('claude', { stdio: 'inherit' })
|
|
129
|
+
console.log(chalk.green('\n ✓ Figma authentication complete\n'))
|
|
130
|
+
figmaAuthNeeded = false
|
|
131
|
+
} catch {
|
|
132
|
+
console.log(chalk.dim('\n (You can authenticate later — type /mcp inside Claude)\n'))
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
console.log(chalk.dim(' Skipped. To authenticate later, open Claude and type /mcp → figma → Authenticate\n'))
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
console.log(chalk.dim(' Skipped. You can always add it later:\n'))
|
|
141
|
+
console.log(chalk.dim(' claude mcp add --transport http figma https://mcp.figma.com/mcp --scope user\n'))
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ── Step 4: Browser & Figma plugins ─────────────────────────────────────
|
|
145
|
+
console.log(chalk.bold('Step 4/5') + ' — Browser tools')
|
|
146
|
+
console.log(chalk.dim(' Enables /document-component to open a browser preview and push docs into Figma.\n'))
|
|
147
|
+
|
|
148
|
+
installPlugin('chrome-devtools-mcp', 'chrome-devtools-plugins', 'Chrome DevTools')
|
|
149
|
+
installPlugin('figma-friend', 'figma-friend-marketplace', 'Figma Friend')
|
|
150
|
+
|
|
151
|
+
// ── Step 5: API key ──────────────────────────────────────────────────────
|
|
152
|
+
console.log(chalk.bold('Step 5/5') + ' — API key')
|
|
153
|
+
|
|
154
|
+
if (!claudeInstalled) {
|
|
155
|
+
console.log(' You\'ll need a free Anthropic API key.')
|
|
156
|
+
console.log(' Get one at: ' + chalk.cyan('https://console.anthropic.com'))
|
|
157
|
+
console.log(' Claude will ask for it when you first run ' + chalk.cyan('claude') + '.\n')
|
|
158
|
+
} else {
|
|
159
|
+
console.log(chalk.green(' ✓ Already configured\n'))
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ── Register design command globally ────────────────────────────────────
|
|
163
|
+
try {
|
|
164
|
+
npmInstallGlobal('@mehuljatiya/troupe')
|
|
165
|
+
} catch { /* non-critical — claude still works without design command */ }
|
|
166
|
+
|
|
167
|
+
// ── Done ─────────────────────────────────────────────────────────────────
|
|
168
|
+
showNextSteps(figmaConnected, figmaAuthNeeded)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function npmInstallGlobal(pkg) {
|
|
172
|
+
try {
|
|
173
|
+
// Pipe stderr so we can inspect it; stdout still streams to terminal
|
|
174
|
+
execSync(`npm install -g ${pkg}`, { stdio: ['inherit', 'inherit', 'pipe'] })
|
|
175
|
+
} catch (err) {
|
|
176
|
+
const stderr = err.stderr?.toString() || ''
|
|
177
|
+
if (!stderr.includes('EACCES') && !stderr.includes('permission denied')) throw err
|
|
178
|
+
|
|
179
|
+
// Permission denied — fix npm prefix to user home and retry
|
|
180
|
+
console.log(chalk.yellow('\n Permission denied. Fixing npm global directory...\n'))
|
|
181
|
+
const npmGlobal = join(homedir(), '.npm-global')
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
mkdirSync(join(npmGlobal, 'lib', 'node_modules'), { recursive: true })
|
|
185
|
+
mkdirSync(join(npmGlobal, 'bin'), { recursive: true })
|
|
186
|
+
execSync(`npm config set prefix '${npmGlobal}'`, { stdio: 'pipe' })
|
|
187
|
+
process.env.PATH = join(npmGlobal, 'bin') + ':' + (process.env.PATH || '')
|
|
188
|
+
} catch {
|
|
189
|
+
console.log(chalk.red(' Could not fix npm permissions automatically.'))
|
|
190
|
+
console.log(' Try: ' + chalk.cyan('sudo npm install -g ' + pkg))
|
|
191
|
+
throw new Error('permission-fix-failed')
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Persist to shell profile
|
|
195
|
+
const shell = process.env.SHELL || ''
|
|
196
|
+
const profileFile = shell.includes('zsh') ? '.zshrc' : '.bashrc'
|
|
197
|
+
const profilePath = join(homedir(), profileFile)
|
|
198
|
+
try {
|
|
199
|
+
appendFileSync(profilePath, `\nexport PATH="$HOME/.npm-global/bin:$PATH"\n`)
|
|
200
|
+
console.log(chalk.dim(` Added PATH export to ~/${profileFile}`))
|
|
201
|
+
} catch { /* non-critical */ }
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
// Pass --prefix directly so config file overrides can't interfere
|
|
205
|
+
execSync(`npm install -g ${pkg} --prefix="${npmGlobal}"`, {
|
|
206
|
+
stdio: 'inherit',
|
|
207
|
+
env: { ...process.env, npm_config_prefix: npmGlobal }
|
|
208
|
+
})
|
|
209
|
+
} catch {
|
|
210
|
+
console.log(chalk.red('\n Install still failed after fixing permissions.'))
|
|
211
|
+
console.log(' Try opening a new terminal tab and re-running:')
|
|
212
|
+
console.log(' ' + chalk.cyan('npx @mehuljatiya/troupe@latest setup'))
|
|
213
|
+
throw new Error('retry-failed')
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async function upgradeNode() {
|
|
219
|
+
const nvmScript = join(homedir(), '.nvm', 'nvm.sh')
|
|
220
|
+
const nvmDirEnv = process.env.NVM_DIR ? join(process.env.NVM_DIR, 'nvm.sh') : null
|
|
221
|
+
|
|
222
|
+
const nvmPath = nvmDirEnv && existsSync(nvmDirEnv) ? nvmDirEnv
|
|
223
|
+
: existsSync(nvmScript) ? nvmScript
|
|
224
|
+
: null
|
|
225
|
+
|
|
226
|
+
if (nvmPath) {
|
|
227
|
+
console.log(chalk.dim(' nvm detected.'))
|
|
228
|
+
const go = await confirm({ message: 'Install Node.js 20 via nvm and continue setup?', default: true }).catch(() => false)
|
|
229
|
+
if (go) {
|
|
230
|
+
console.log(chalk.dim('\n Installing Node.js 20 — this takes a minute...\n'))
|
|
231
|
+
try {
|
|
232
|
+
execSync(`. "${nvmPath}" && nvm install 20`, { shell: '/bin/bash', stdio: 'inherit' })
|
|
233
|
+
const newNode = execSync(`. "${nvmPath}" && nvm which 20`, { shell: '/bin/bash', encoding: 'utf8', stdio: 'pipe' }).trim()
|
|
234
|
+
console.log(chalk.green('\n ✓ Node.js 20 installed'))
|
|
235
|
+
console.log(chalk.dim(' Restarting setup with Node.js 20...\n'))
|
|
236
|
+
const result = spawnSync(newNode, process.argv.slice(1), { stdio: 'inherit' })
|
|
237
|
+
process.exit(result.status ?? 0)
|
|
238
|
+
} catch {
|
|
239
|
+
console.log(chalk.red('\n Node.js upgrade failed.'))
|
|
240
|
+
console.log(' Try manually: ' + chalk.cyan('nvm install 20') + ' then re-run setup.\n')
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
try {
|
|
247
|
+
execSync('which brew', { stdio: 'ignore' })
|
|
248
|
+
console.log(chalk.dim(' Homebrew detected.'))
|
|
249
|
+
|
|
250
|
+
// Check if node@20 is already installed but just not linked/active
|
|
251
|
+
let brewNodePath = null
|
|
252
|
+
try {
|
|
253
|
+
const prefix = execSync('brew --prefix node@20 2>/dev/null', { encoding: 'utf8', stdio: 'pipe' }).trim()
|
|
254
|
+
const candidate = join(prefix, 'bin', 'node')
|
|
255
|
+
if (existsSync(candidate)) brewNodePath = candidate
|
|
256
|
+
} catch { /* not installed yet */ }
|
|
257
|
+
|
|
258
|
+
if (brewNodePath) {
|
|
259
|
+
// Already installed — just re-exec with it directly
|
|
260
|
+
console.log(chalk.green(' ✓ Node.js 20 already installed via Homebrew'))
|
|
261
|
+
console.log(chalk.dim(' Restarting setup with Node.js 20...\n'))
|
|
262
|
+
const result = spawnSync(brewNodePath, process.argv.slice(1), { stdio: 'inherit' })
|
|
263
|
+
process.exit(result.status ?? 0)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const go = await confirm({ message: 'Install Node.js 20 via Homebrew?', default: true }).catch(() => false)
|
|
267
|
+
if (go) {
|
|
268
|
+
console.log(chalk.dim('\n Installing Node.js 20 — this takes a minute...\n'))
|
|
269
|
+
try {
|
|
270
|
+
execSync('brew install node@20', { shell: '/bin/bash', stdio: 'inherit' })
|
|
271
|
+
execSync('brew link --overwrite --force node@20', { shell: '/bin/bash', stdio: 'pipe' })
|
|
272
|
+
const prefix = execSync('brew --prefix node@20', { encoding: 'utf8', stdio: 'pipe' }).trim()
|
|
273
|
+
brewNodePath = join(prefix, 'bin', 'node')
|
|
274
|
+
console.log(chalk.green('\n ✓ Node.js 20 installed'))
|
|
275
|
+
console.log(chalk.dim(' Restarting setup with Node.js 20...\n'))
|
|
276
|
+
const result = spawnSync(brewNodePath, process.argv.slice(1), { stdio: 'inherit' })
|
|
277
|
+
process.exit(result.status ?? 0)
|
|
278
|
+
} catch {
|
|
279
|
+
console.log(chalk.red('\n Homebrew install failed.'))
|
|
280
|
+
console.log(' Try manually: ' + chalk.cyan('brew install node@20') + '\n')
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return
|
|
284
|
+
} catch { /* no brew */ }
|
|
285
|
+
|
|
286
|
+
console.log(' Download Node.js 20 LTS from: ' + chalk.cyan('https://nodejs.org'))
|
|
287
|
+
console.log(' Install it like any Mac app, then re-run this command.\n')
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function installPlugin(pluginName, marketplace, label) {
|
|
291
|
+
try {
|
|
292
|
+
const result = execSync('claude plugin list', { encoding: 'utf8', stdio: 'pipe' })
|
|
293
|
+
if (result.toLowerCase().includes(pluginName.toLowerCase())) {
|
|
294
|
+
console.log(chalk.green(` ✓ ${label} already installed`))
|
|
295
|
+
console.log()
|
|
296
|
+
return
|
|
297
|
+
}
|
|
298
|
+
} catch { /* continue */ }
|
|
299
|
+
|
|
300
|
+
try {
|
|
301
|
+
execSync(`claude plugin install ${pluginName}@${marketplace} --scope user`, { stdio: 'pipe' })
|
|
302
|
+
console.log(chalk.green(` ✓ ${label} installed`))
|
|
303
|
+
} catch {
|
|
304
|
+
console.log(chalk.yellow(` Could not install ${label} automatically.`))
|
|
305
|
+
console.log(' Run this manually:')
|
|
306
|
+
console.log(' ' + chalk.cyan(`claude plugin install ${pluginName}@${marketplace}`))
|
|
307
|
+
}
|
|
308
|
+
console.log()
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function isClaudeInstalled() {
|
|
312
|
+
try {
|
|
313
|
+
execSync('which claude', { stdio: 'ignore' })
|
|
314
|
+
return true
|
|
315
|
+
} catch {
|
|
316
|
+
return false
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function isFigmaMcpConfigured() {
|
|
321
|
+
try {
|
|
322
|
+
const result = execSync('claude mcp list', { encoding: 'utf8', stdio: 'pipe' })
|
|
323
|
+
return result.toLowerCase().includes('figma')
|
|
324
|
+
} catch {
|
|
325
|
+
return false
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function installSlashCommands() {
|
|
330
|
+
const commandsDir = join(homedir(), '.claude', 'commands')
|
|
331
|
+
try {
|
|
332
|
+
if (!existsSync(commandsDir)) {
|
|
333
|
+
mkdirSync(commandsDir, { recursive: true })
|
|
334
|
+
}
|
|
335
|
+
} catch {
|
|
336
|
+
console.log(chalk.red(' Could not create ~/.claude/commands/'))
|
|
337
|
+
console.log(chalk.dim(' Check permissions on your home directory.'))
|
|
338
|
+
return { installed: [], skipped: [] }
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const sourceDir = join(__dirname, '..', 'commands')
|
|
342
|
+
let files = []
|
|
343
|
+
try {
|
|
344
|
+
files = readdirSync(sourceDir).filter(f => f.endsWith('.md'))
|
|
345
|
+
} catch {
|
|
346
|
+
console.log(chalk.red(' Could not read commands from package — it may be corrupted.'))
|
|
347
|
+
console.log(chalk.dim(' Try re-running: npx @mehuljatiya/troupe@latest setup'))
|
|
348
|
+
return { installed: [], skipped: [] }
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const installed = []
|
|
352
|
+
const skipped = []
|
|
353
|
+
|
|
354
|
+
for (const file of files) {
|
|
355
|
+
const dest = join(commandsDir, file)
|
|
356
|
+
if (existsSync(dest)) {
|
|
357
|
+
skipped.push(file)
|
|
358
|
+
} else {
|
|
359
|
+
try {
|
|
360
|
+
copyFileSync(join(sourceDir, file), dest)
|
|
361
|
+
installed.push(file)
|
|
362
|
+
} catch {
|
|
363
|
+
console.log(chalk.yellow(` Could not copy ${file} — skipping`))
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return { installed, skipped }
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function showNextSteps(figmaConnected, figmaAuthNeeded) {
|
|
372
|
+
console.log('─'.repeat(50))
|
|
373
|
+
console.log(chalk.bold('\nYou\'re all set!\n'))
|
|
374
|
+
console.log(chalk.yellow(' Open a new terminal tab first') + ' so PATH updates take effect.\n')
|
|
375
|
+
console.log('To start:')
|
|
376
|
+
console.log(' 1. Open a new terminal tab in your project folder')
|
|
377
|
+
console.log(' 2. Type ' + chalk.cyan('claude') + ' (or ' + chalk.cyan('design') + ' for a command cheat sheet)')
|
|
378
|
+
|
|
379
|
+
if (figmaAuthNeeded) {
|
|
380
|
+
console.log(' 3. Inside Claude, type ' + chalk.cyan('/mcp') + ' → figma → Authenticate')
|
|
381
|
+
console.log(' (one-time step to connect your Figma account)\n')
|
|
382
|
+
} else {
|
|
383
|
+
console.log()
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
console.log('Available workflows (type inside Claude):')
|
|
387
|
+
console.log(' ' + chalk.cyan('/figma') + ' [url] Pull a Figma design and build it')
|
|
388
|
+
console.log(' ' + chalk.cyan('/document-component') + ' [url] Generate full component docs from Figma')
|
|
389
|
+
console.log(' ' + chalk.cyan('/spec') + ' [url] Ticket-ready spec with acceptance criteria')
|
|
390
|
+
console.log(' ' + chalk.cyan('/qa') + ' [url] Compare Figma to built component, flag gaps')
|
|
391
|
+
console.log(' ' + chalk.cyan('/new-component') + ' Start a new component from scratch')
|
|
392
|
+
console.log(' ' + chalk.cyan('/document') + ' Write docs for a component')
|
|
393
|
+
console.log(' ' + chalk.cyan('/review') + ' Design quality and consistency check')
|
|
394
|
+
console.log(' ' + chalk.cyan('/tokens') + ' Explain the design tokens in this project')
|
|
395
|
+
console.log(' ' + chalk.cyan('/handoff') + ' Generate a developer handoff doc')
|
|
396
|
+
console.log()
|
|
397
|
+
}
|