worclaude 1.2.0 → 1.2.1
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 +12 -8
- package/package.json +1 -1
- package/src/commands/backup.js +3 -7
- package/src/commands/diff.js +14 -14
- package/src/commands/init.js +90 -72
- package/src/commands/restore.js +4 -5
- package/src/commands/status.js +24 -26
- package/src/commands/upgrade.js +27 -22
- package/src/core/merger.js +21 -18
- package/src/data/agents.js +143 -23
- package/src/index.js +1 -4
- package/src/prompts/agent-selection.js +3 -3
- package/src/prompts/claude-md-merge.js +1 -1
- package/src/prompts/project-type.js +6 -2
- package/src/utils/display.js +163 -18
package/README.md
CHANGED
|
@@ -20,6 +20,7 @@ Worclaude scaffolds a complete Claude Code workflow into any project in seconds.
|
|
|
20
20
|
`worclaude init` installs a production-ready Claude Code workflow:
|
|
21
21
|
|
|
22
22
|
**Agents (23 total)**
|
|
23
|
+
|
|
23
24
|
- 5 universal: plan-reviewer, code-simplifier, test-writer, build-validator, verify-app
|
|
24
25
|
- 18 optional across 6 categories: Backend, Frontend, DevOps, Quality, Documentation, Data/AI
|
|
25
26
|
|
|
@@ -27,15 +28,18 @@ Worclaude scaffolds a complete Claude Code workflow into any project in seconds.
|
|
|
27
28
|
`/start` `/end` `/commit-push-pr` `/review-plan` `/techdebt` `/verify` `/compact-safe` `/status` `/update-claude-md` `/setup`
|
|
28
29
|
|
|
29
30
|
**Skills (12)**
|
|
31
|
+
|
|
30
32
|
- 9 universal knowledge files (testing, git conventions, context management, and more)
|
|
31
33
|
- 3 project-specific templates filled in by `/setup`
|
|
32
34
|
|
|
33
35
|
**Hooks**
|
|
36
|
+
|
|
34
37
|
- PostToolUse formatter (auto-formats on every write)
|
|
35
38
|
- PostCompact re-injection (re-reads key files after compaction)
|
|
36
39
|
- Stop notifications (desktop alert when Claude finishes)
|
|
37
40
|
|
|
38
41
|
**Configuration**
|
|
42
|
+
|
|
39
43
|
- Pre-configured permissions per tech stack (Node.js, Python, Go, Rust, and more)
|
|
40
44
|
- CLAUDE.md template with progressive disclosure
|
|
41
45
|
- Sandbox, effort, and output defaults ready out of the box
|
|
@@ -58,14 +62,14 @@ For parallel tasks, run Claude with worktrees: `claude --worktree --tmux`
|
|
|
58
62
|
|
|
59
63
|
## Commands
|
|
60
64
|
|
|
61
|
-
| Command
|
|
62
|
-
|
|
63
|
-
| `worclaude init`
|
|
64
|
-
| `worclaude upgrade` | Update universal components to latest version
|
|
65
|
-
| `worclaude status`
|
|
66
|
-
| `worclaude backup`
|
|
67
|
-
| `worclaude restore` | Restore from a previous backup
|
|
68
|
-
| `worclaude diff`
|
|
65
|
+
| Command | Description |
|
|
66
|
+
| ------------------- | ---------------------------------------------- |
|
|
67
|
+
| `worclaude init` | Scaffold workflow into new or existing project |
|
|
68
|
+
| `worclaude upgrade` | Update universal components to latest version |
|
|
69
|
+
| `worclaude status` | Show current workflow state and version |
|
|
70
|
+
| `worclaude backup` | Create timestamped backup of workflow files |
|
|
71
|
+
| `worclaude restore` | Restore from a previous backup |
|
|
72
|
+
| `worclaude diff` | Compare current setup vs latest version |
|
|
69
73
|
|
|
70
74
|
The `init` command detects existing setups and merges intelligently — no data is overwritten without your confirmation. Use `upgrade` to pull in new features while preserving your customizations.
|
|
71
75
|
|
package/package.json
CHANGED
package/src/commands/backup.js
CHANGED
|
@@ -19,8 +19,8 @@ export async function backupCommand() {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
display.newline();
|
|
22
|
-
display.success(`
|
|
23
|
-
display.
|
|
22
|
+
display.success(`Backup created!`);
|
|
23
|
+
display.success(`${display.dimColor(path.basename(backupDir) + '/')}`);
|
|
24
24
|
|
|
25
25
|
// Summarize contents
|
|
26
26
|
const contents = [];
|
|
@@ -35,7 +35,6 @@ export async function backupCommand() {
|
|
|
35
35
|
const commands = await listFiles(path.join(claudeBackup, 'commands'));
|
|
36
36
|
const skills = await listFiles(path.join(claudeBackup, 'skills'));
|
|
37
37
|
const parts = [];
|
|
38
|
-
if (await fileExists(path.join(claudeBackup, 'settings.json'))) parts.push('settings.json');
|
|
39
38
|
if (agents.length > 0) parts.push(`${agents.length} agents`);
|
|
40
39
|
if (commands.length > 0) parts.push(`${commands.length} commands`);
|
|
41
40
|
if (skills.length > 0) parts.push(`${skills.length} skills`);
|
|
@@ -47,9 +46,6 @@ export async function backupCommand() {
|
|
|
47
46
|
}
|
|
48
47
|
|
|
49
48
|
if (contents.length > 0) {
|
|
50
|
-
display.
|
|
51
|
-
for (const item of contents) {
|
|
52
|
-
display.dim(` ${item}`);
|
|
53
|
-
}
|
|
49
|
+
display.dim(` ${contents.join(' · ')}`);
|
|
54
50
|
}
|
|
55
51
|
}
|
package/src/commands/diff.js
CHANGED
|
@@ -17,52 +17,52 @@ export async function diffCommand() {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const categories = await categorizeFiles(projectRoot, meta);
|
|
20
|
+
const cliVersion = await getPackageVersion();
|
|
20
21
|
|
|
21
|
-
display.
|
|
22
|
-
display.newline();
|
|
23
|
-
display.dim(` Comparing current setup to workflow v${meta.version}:`);
|
|
22
|
+
display.sectionHeader(`WORCLAUDE DIFF (v${meta.version} → v${cliVersion})`);
|
|
24
23
|
display.newline();
|
|
25
24
|
|
|
26
25
|
let hasChanges = false;
|
|
27
26
|
|
|
28
27
|
if (categories.modified.length > 0) {
|
|
29
28
|
hasChanges = true;
|
|
30
|
-
display.
|
|
29
|
+
display.barLine(`${display.yellow('~')} Modified (your changes):`);
|
|
31
30
|
for (const { key } of categories.modified) {
|
|
32
|
-
display.
|
|
31
|
+
display.barLine(` ${display.yellow(key)}`);
|
|
33
32
|
}
|
|
34
33
|
display.newline();
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
if (categories.deleted.length > 0) {
|
|
38
37
|
hasChanges = true;
|
|
39
|
-
display.
|
|
38
|
+
display.barLine(`${display.red('-')} Deleted (removed since install):`);
|
|
40
39
|
for (const { key } of categories.deleted) {
|
|
41
|
-
display.
|
|
40
|
+
display.barLine(` ${display.red(key)}`);
|
|
42
41
|
}
|
|
43
42
|
display.newline();
|
|
44
43
|
}
|
|
45
44
|
|
|
46
45
|
if (categories.userAdded.length > 0) {
|
|
47
46
|
hasChanges = true;
|
|
48
|
-
display.
|
|
47
|
+
display.barLine(`${display.green('+')} Extra (you added):`);
|
|
49
48
|
for (const { key } of categories.userAdded) {
|
|
50
|
-
display.
|
|
49
|
+
display.barLine(` ${display.green(key)}`);
|
|
51
50
|
}
|
|
52
51
|
display.newline();
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
if (categories.outdated.length > 0) {
|
|
56
55
|
hasChanges = true;
|
|
57
|
-
|
|
58
|
-
display.info(`Outdated (newer version available in CLI v${cliVersion}):`);
|
|
56
|
+
display.barLine(`${display.blue('↑')} Outdated (newer version available):`);
|
|
59
57
|
for (const { key } of categories.outdated) {
|
|
60
|
-
display.
|
|
58
|
+
display.barLine(` ${display.blue(key)}`);
|
|
61
59
|
}
|
|
62
60
|
display.newline();
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
display.
|
|
63
|
+
display.barLine(
|
|
64
|
+
`${display.dimColor('=')} Unchanged: ${display.dimColor(`${categories.unchanged.length} files`)}`
|
|
65
|
+
);
|
|
66
66
|
|
|
67
67
|
if (!hasChanges) {
|
|
68
68
|
display.newline();
|
|
@@ -71,6 +71,6 @@ export async function diffCommand() {
|
|
|
71
71
|
|
|
72
72
|
if (categories.outdated.length > 0) {
|
|
73
73
|
display.newline();
|
|
74
|
-
display.
|
|
74
|
+
display.barLine(`Run ${display.purple('worclaude upgrade')} to apply changes.`);
|
|
75
75
|
}
|
|
76
76
|
}
|
package/src/commands/init.js
CHANGED
|
@@ -204,18 +204,27 @@ async function showConfirmation(selections) {
|
|
|
204
204
|
stackLabels.push('Other / None');
|
|
205
205
|
}
|
|
206
206
|
if (selections.useDocker) stackLabels.push('Docker');
|
|
207
|
-
const stackText = stackLabels.join(', ') || 'None specified';
|
|
208
207
|
|
|
209
208
|
const universalCount = UNIVERSAL_AGENTS.length;
|
|
210
209
|
const optionalCount = selections.selectedAgents.length;
|
|
211
210
|
const totalCount = universalCount + optionalCount;
|
|
212
211
|
|
|
213
|
-
display.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
`
|
|
218
|
-
|
|
212
|
+
display.newline();
|
|
213
|
+
display.divider('REVIEW');
|
|
214
|
+
display.newline();
|
|
215
|
+
console.log(
|
|
216
|
+
` ${'Project'.padEnd(10)}${display.white(selections.projectName)}${selections.description ? display.dimColor(` — ${selections.description}`) : ''}`
|
|
217
|
+
);
|
|
218
|
+
console.log(
|
|
219
|
+
` ${'Type'.padEnd(10)}${display.renderBadgeList(selections.projectTypes, display.TYPE_BADGES)}`
|
|
220
|
+
);
|
|
221
|
+
console.log(
|
|
222
|
+
` ${'Stack'.padEnd(10)}${display.renderBadgeList(stackLabels, display.STACK_BADGES)}`
|
|
223
|
+
);
|
|
224
|
+
console.log(
|
|
225
|
+
` ${'Agents'.padEnd(10)}${display.white(`${universalCount} universal + ${optionalCount} optional`)} ${display.dimColor(`(${totalCount} total)`)}`
|
|
226
|
+
);
|
|
227
|
+
display.newline();
|
|
219
228
|
|
|
220
229
|
const { confirmation } = await inquirer.prompt([
|
|
221
230
|
{
|
|
@@ -318,15 +327,11 @@ function buildTemplateVariables(selections) {
|
|
|
318
327
|
techStackTableItems.push('Not specified');
|
|
319
328
|
}
|
|
320
329
|
const techStackTable = techStackTableItems.join(', ');
|
|
321
|
-
const dockerRow = useDocker
|
|
322
|
-
? '\n| Containers | Docker |'
|
|
323
|
-
: '';
|
|
330
|
+
const dockerRow = useDocker ? '\n| Containers | Docker |' : '';
|
|
324
331
|
|
|
325
332
|
const commandsText = buildCommandsBlock(languages, useDocker);
|
|
326
333
|
|
|
327
|
-
const skillsLines = TEMPLATE_SKILLS.map(
|
|
328
|
-
(s) => `- ${s}.md — Run /setup to fill automatically`
|
|
329
|
-
);
|
|
334
|
+
const skillsLines = TEMPLATE_SKILLS.map((s) => `- ${s}.md — Run /setup to fill automatically`);
|
|
330
335
|
const skillsText = skillsLines.join('\n');
|
|
331
336
|
|
|
332
337
|
return {
|
|
@@ -346,7 +351,10 @@ async function computeAndWriteWorkflowMeta(projectRoot, selections, version) {
|
|
|
346
351
|
const fileHashes = {};
|
|
347
352
|
const claudeFiles = await listFilesRecursive(path.join(projectRoot, '.claude'));
|
|
348
353
|
for (const filePath of claudeFiles) {
|
|
349
|
-
const relativePath = path
|
|
354
|
+
const relativePath = path
|
|
355
|
+
.relative(path.join(projectRoot, '.claude'), filePath)
|
|
356
|
+
.split(path.sep)
|
|
357
|
+
.join('/');
|
|
350
358
|
if (relativePath !== 'workflow-meta.json' && relativePath !== 'settings.json') {
|
|
351
359
|
fileHashes[relativePath] = await hashFile(filePath);
|
|
352
360
|
}
|
|
@@ -448,7 +456,12 @@ async function scaffoldFresh(projectRoot, selections, variables, settingsStr, ve
|
|
|
448
456
|
if (!(await fileExists(specPath))) {
|
|
449
457
|
const primaryType = projectTypes[0];
|
|
450
458
|
const specTemplate = SPEC_MD_TEMPLATE_MAP[primaryType] || 'spec-md.md';
|
|
451
|
-
await scaffoldFile(
|
|
459
|
+
await scaffoldFile(
|
|
460
|
+
specTemplate,
|
|
461
|
+
path.join('docs', 'spec', 'SPEC.md'),
|
|
462
|
+
variables,
|
|
463
|
+
projectRoot
|
|
464
|
+
);
|
|
452
465
|
} else {
|
|
453
466
|
skipped.specMd = true;
|
|
454
467
|
}
|
|
@@ -467,67 +480,66 @@ async function scaffoldFresh(projectRoot, selections, variables, settingsStr, ve
|
|
|
467
480
|
}
|
|
468
481
|
|
|
469
482
|
function displayFreshSuccess(selections, skipped) {
|
|
483
|
+
const totalAgents = UNIVERSAL_AGENTS.length + selections.selectedAgents.length;
|
|
484
|
+
const totalSkills = UNIVERSAL_SKILLS.length + TEMPLATE_SKILLS.length;
|
|
485
|
+
|
|
470
486
|
display.newline();
|
|
471
487
|
display.success('CLAUDE.md');
|
|
472
488
|
display.success('.claude/settings.json');
|
|
473
489
|
display.success('.claude/workflow-meta.json');
|
|
474
|
-
display.success(
|
|
475
|
-
|
|
476
|
-
);
|
|
477
|
-
display.success(`.claude/commands/ (${COMMAND_FILES.length})`);
|
|
478
|
-
display.success(
|
|
479
|
-
`.claude/skills/ (${UNIVERSAL_SKILLS.length} universal + ${TEMPLATE_SKILLS.length} templates)`
|
|
480
|
-
);
|
|
490
|
+
display.success(`.claude/agents/${display.dimColor(` ${totalAgents} agents`)}`);
|
|
491
|
+
display.success(`.claude/commands/${display.dimColor(` ${COMMAND_FILES.length} commands`)}`);
|
|
492
|
+
display.success(`.claude/skills/${display.dimColor(` ${totalSkills} skills`)}`);
|
|
481
493
|
display.success('.mcp.json');
|
|
482
494
|
if (skipped.progressMd) {
|
|
483
495
|
display.dim(' docs/spec/PROGRESS.md — already exists, skipped');
|
|
496
|
+
} else if (skipped.specMd) {
|
|
497
|
+
display.success(`docs/spec/${display.dimColor(' PROGRESS.md, SPEC.md')}`);
|
|
484
498
|
} else {
|
|
485
|
-
display.success(
|
|
486
|
-
}
|
|
487
|
-
if (skipped.specMd) {
|
|
488
|
-
display.dim(' docs/spec/SPEC.md — already exists, skipped');
|
|
489
|
-
} else {
|
|
490
|
-
display.success('docs/spec/SPEC.md');
|
|
499
|
+
display.success(`docs/spec/${display.dimColor(' PROGRESS.md, SPEC.md')}`);
|
|
491
500
|
}
|
|
501
|
+
|
|
492
502
|
display.newline();
|
|
493
|
-
display.
|
|
503
|
+
display.divider('NEXT');
|
|
494
504
|
display.newline();
|
|
495
|
-
display.
|
|
496
|
-
|
|
497
|
-
display.
|
|
498
|
-
|
|
499
|
-
|
|
505
|
+
console.log(` ${display.white('1.')} Start a Claude Code session in this project`);
|
|
506
|
+
console.log(
|
|
507
|
+
` ${display.white('2.')} Run ${display.purple('/setup')} — Claude will interview you about your project`
|
|
508
|
+
);
|
|
509
|
+
console.log(` and fill in all configuration files automatically`);
|
|
510
|
+
console.log(` ${display.white('3.')} Review CLAUDE.md and adjust if needed`);
|
|
511
|
+
console.log(` ${display.white('4.')} Start building!`);
|
|
500
512
|
display.newline();
|
|
501
|
-
|
|
502
|
-
display.
|
|
513
|
+
console.log(
|
|
514
|
+
` ${display.yellow('TIP')} ${display.dimColor(`${display.purple('/setup')} is the fastest way to configure. ~5 minutes.`)}`
|
|
515
|
+
);
|
|
503
516
|
display.newline();
|
|
504
517
|
}
|
|
505
518
|
|
|
506
519
|
// --- Scenario B: Detection report and merge report ---
|
|
507
520
|
|
|
508
521
|
function displayDetectionReport(scan) {
|
|
509
|
-
display.
|
|
510
|
-
display.newline();
|
|
522
|
+
display.sectionHeader('DETECTED SETUP');
|
|
511
523
|
|
|
512
524
|
const dot = (label, width = 26) => label + ' ' + '.'.repeat(width - label.length) + ' ';
|
|
513
525
|
|
|
514
|
-
display.
|
|
515
|
-
|
|
526
|
+
display.barLine(
|
|
527
|
+
`${display.dimColor(dot('CLAUDE.md'))}${scan.hasClaudeMd ? display.white(`exists (${scan.claudeMdLineCount} lines)`) : display.dimColor('not found')}`
|
|
516
528
|
);
|
|
517
|
-
display.
|
|
518
|
-
|
|
529
|
+
display.barLine(
|
|
530
|
+
`${display.dimColor(dot('.claude/settings.json'))}${scan.hasSettingsJson ? display.white('exists') : display.dimColor('not found')}`
|
|
519
531
|
);
|
|
520
|
-
display.
|
|
521
|
-
|
|
532
|
+
display.barLine(
|
|
533
|
+
`${display.dimColor(dot('.claude/skills/'))}${scan.existingSkills.length > 0 ? display.white(`${scan.existingSkills.length} files found`) : display.dimColor('not found')}`
|
|
522
534
|
);
|
|
523
|
-
display.
|
|
524
|
-
|
|
535
|
+
display.barLine(
|
|
536
|
+
`${display.dimColor(dot('.claude/agents/'))}${scan.existingAgents.length > 0 ? display.white(`${scan.existingAgents.length} files found`) : display.dimColor('not found')}`
|
|
525
537
|
);
|
|
526
|
-
display.
|
|
527
|
-
|
|
538
|
+
display.barLine(
|
|
539
|
+
`${display.dimColor(dot('.claude/commands/'))}${scan.existingCommands.length > 0 ? display.white(`${scan.existingCommands.length} files found`) : display.dimColor('not found')}`
|
|
528
540
|
);
|
|
529
|
-
display.
|
|
530
|
-
|
|
541
|
+
display.barLine(
|
|
542
|
+
`${display.dimColor(dot('.mcp.json'))}${scan.hasMcpJson ? display.white('exists') : display.dimColor('not found')}`
|
|
531
543
|
);
|
|
532
544
|
display.newline();
|
|
533
545
|
display.info('A backup will be created before any changes.');
|
|
@@ -543,23 +555,25 @@ function displayMergeReport(report, backupPath) {
|
|
|
543
555
|
report.added.commands.length > 0 ||
|
|
544
556
|
report.added.skills.length > 0
|
|
545
557
|
) {
|
|
546
|
-
display.
|
|
558
|
+
display.barLine(`${display.green('+')} Added automatically:`);
|
|
547
559
|
if (report.added.agents.length > 0) {
|
|
548
|
-
display.
|
|
560
|
+
display.barLine(` ${display.green('✓')} ${report.added.agents.length} agents added`);
|
|
549
561
|
}
|
|
550
562
|
if (report.added.commands.length > 0) {
|
|
551
|
-
display.
|
|
563
|
+
display.barLine(` ${display.green('✓')} ${report.added.commands.length} commands added`);
|
|
552
564
|
}
|
|
553
565
|
if (report.added.skills.length > 0) {
|
|
554
|
-
display.
|
|
555
|
-
|
|
566
|
+
display.barLine(
|
|
567
|
+
` ${display.green('✓')} ${report.added.skills.length} skills added${report.conflicts.skills.length > 0 ? ` (${report.conflicts.skills.length} conflicts saved as .workflow-ref.md)` : ''}`
|
|
556
568
|
);
|
|
557
569
|
}
|
|
558
570
|
if (report.added.permissions > 0) {
|
|
559
|
-
display.
|
|
571
|
+
display.barLine(
|
|
572
|
+
` ${display.green('✓')} ${report.added.permissions} permission rules appended to settings.json`
|
|
573
|
+
);
|
|
560
574
|
}
|
|
561
575
|
if (report.added.hooks > 0) {
|
|
562
|
-
display.
|
|
576
|
+
display.barLine(` ${display.green('✓')} ${report.added.hooks} hooks added to settings.json`);
|
|
563
577
|
}
|
|
564
578
|
display.newline();
|
|
565
579
|
}
|
|
@@ -571,19 +585,19 @@ function displayMergeReport(report, backupPath) {
|
|
|
571
585
|
...report.conflicts.commands,
|
|
572
586
|
];
|
|
573
587
|
if (allConflicts.length > 0) {
|
|
574
|
-
display.
|
|
588
|
+
display.barLine(`${display.yellow('~')} Conflicts (saved alongside for review):`);
|
|
575
589
|
for (const file of allConflicts) {
|
|
576
590
|
const refName = file.replace('.md', '.workflow-ref.md');
|
|
577
|
-
display.
|
|
591
|
+
display.barLine(` ${display.yellow('⚠')} ${file} → ${refName}`);
|
|
578
592
|
}
|
|
579
593
|
display.newline();
|
|
580
594
|
}
|
|
581
595
|
|
|
582
596
|
// Tier 3 — Hook conflicts
|
|
583
597
|
if (report.hookConflicts.length > 0) {
|
|
584
|
-
display.
|
|
598
|
+
display.barLine(`Hook conflicts resolved:`);
|
|
585
599
|
for (const desc of report.hookConflicts) {
|
|
586
|
-
display.
|
|
600
|
+
display.barLine(` ${display.dimColor(desc)}`);
|
|
587
601
|
}
|
|
588
602
|
display.newline();
|
|
589
603
|
}
|
|
@@ -610,17 +624,22 @@ function displayMergeReport(report, backupPath) {
|
|
|
610
624
|
if (backupPath) {
|
|
611
625
|
display.dim(` Backup: ${path.basename(backupPath)}/`);
|
|
612
626
|
}
|
|
627
|
+
|
|
613
628
|
display.newline();
|
|
614
|
-
display.
|
|
629
|
+
display.divider('NEXT');
|
|
615
630
|
display.newline();
|
|
616
631
|
if (allConflicts.length > 0) {
|
|
617
|
-
display.
|
|
632
|
+
console.log(` ${display.white('1.')} Review .workflow-ref.md files and merge what's useful`);
|
|
618
633
|
}
|
|
619
634
|
if (report.claudeMdHandling === 'suggestions-generated') {
|
|
620
|
-
display.
|
|
621
|
-
|
|
635
|
+
console.log(` ${display.white('2.')} Review CLAUDE.md.workflow-suggestions`);
|
|
636
|
+
console.log(
|
|
637
|
+
` ${display.white('3.')} Delete .workflow-ref.md and .workflow-suggestions files when done`
|
|
638
|
+
);
|
|
622
639
|
}
|
|
623
|
-
|
|
640
|
+
console.log(
|
|
641
|
+
` Run ${display.purple('/setup')} in Claude Code for project-specific configuration`
|
|
642
|
+
);
|
|
624
643
|
display.newline();
|
|
625
644
|
}
|
|
626
645
|
|
|
@@ -634,17 +653,14 @@ export async function initCommand() {
|
|
|
634
653
|
|
|
635
654
|
if (scenario === 'upgrade') {
|
|
636
655
|
const meta = await readWorkflowMeta(projectRoot);
|
|
637
|
-
display.info(
|
|
638
|
-
`This project was initialized with Worclaude v${meta?.version || 'unknown'}.`
|
|
639
|
-
);
|
|
656
|
+
display.info(`This project was initialized with Worclaude v${meta?.version || 'unknown'}.`);
|
|
640
657
|
display.info('Use `worclaude upgrade` to update.');
|
|
641
658
|
return;
|
|
642
659
|
}
|
|
643
660
|
|
|
644
661
|
// Step 2: Welcome
|
|
645
662
|
const version = await getPackageVersion();
|
|
646
|
-
display.
|
|
647
|
-
display.newline();
|
|
663
|
+
display.banner(version);
|
|
648
664
|
|
|
649
665
|
// Step 3: If existing project, show detection report and confirm
|
|
650
666
|
let existingScan = null;
|
|
@@ -692,7 +708,9 @@ export async function initCommand() {
|
|
|
692
708
|
// Scenario B: merge
|
|
693
709
|
const spinner = ora('Merging workflow...').start();
|
|
694
710
|
try {
|
|
695
|
-
const report = await performMerge(projectRoot, existingScan, selections, variables, {
|
|
711
|
+
const report = await performMerge(projectRoot, existingScan, selections, variables, {
|
|
712
|
+
spinner,
|
|
713
|
+
});
|
|
696
714
|
await computeAndWriteWorkflowMeta(projectRoot, selections, version);
|
|
697
715
|
spinner.succeed('Workflow merged successfully!');
|
|
698
716
|
displayMergeReport(report, backupPath);
|
package/src/commands/restore.js
CHANGED
|
@@ -15,7 +15,7 @@ export async function restoreCommand() {
|
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
display.
|
|
18
|
+
display.sectionHeader('AVAILABLE BACKUPS');
|
|
19
19
|
display.newline();
|
|
20
20
|
|
|
21
21
|
const choices = backups.map((b, i) => ({
|
|
@@ -77,7 +77,8 @@ export async function restoreCommand() {
|
|
|
77
77
|
// Show what was restored
|
|
78
78
|
const restored = [];
|
|
79
79
|
if (await fileExists(path.join(projectRoot, 'CLAUDE.md'))) restored.push('CLAUDE.md');
|
|
80
|
-
if (await dirExists(path.join(projectRoot, '.claude')))
|
|
80
|
+
if (await dirExists(path.join(projectRoot, '.claude')))
|
|
81
|
+
restored.push('.claude/ (full directory)');
|
|
81
82
|
if (await fileExists(path.join(projectRoot, '.mcp.json'))) restored.push('.mcp.json');
|
|
82
83
|
|
|
83
84
|
if (restored.length > 0) {
|
|
@@ -88,8 +89,6 @@ export async function restoreCommand() {
|
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
display.newline();
|
|
91
|
-
display.info(
|
|
92
|
-
'Note: workflow-meta.json has been restored to its backup state.'
|
|
93
|
-
);
|
|
92
|
+
display.info('Note: workflow-meta.json has been restored to its backup state.');
|
|
94
93
|
display.dim(' Run `worclaude upgrade` if you want to update to the latest version.');
|
|
95
94
|
}
|
package/src/commands/status.js
CHANGED
|
@@ -25,40 +25,41 @@ export async function statusCommand() {
|
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
display.
|
|
29
|
-
display.newline();
|
|
28
|
+
display.sectionHeader('WORCLAUDE STATUS');
|
|
30
29
|
|
|
31
|
-
// Version
|
|
32
|
-
display.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
display.newline();
|
|
30
|
+
// Version
|
|
31
|
+
display.barLine(
|
|
32
|
+
`${'Version'.padEnd(11)}${display.green(`v${meta.version}`)} ${display.dimColor('(up to date)')}`
|
|
33
|
+
);
|
|
36
34
|
|
|
37
35
|
// Project info
|
|
38
|
-
const projectTypes =
|
|
39
|
-
if (projectTypes
|
|
36
|
+
const projectTypes = meta.projectTypes || [];
|
|
37
|
+
if (projectTypes.length > 0) {
|
|
38
|
+
display.barLine(`${'Project'.padEnd(11)}${display.white(projectTypes.join(', '))}`);
|
|
39
|
+
display.barLine(
|
|
40
|
+
`${'Type'.padEnd(11)}${display.renderBadgeList(projectTypes, display.TYPE_BADGES)}`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
40
43
|
|
|
41
|
-
const techNames = (meta.techStack || [])
|
|
42
|
-
|
|
43
|
-
.
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
const techNames = (meta.techStack || []).map((t) => TECH_DISPLAY_NAMES[t] || t);
|
|
45
|
+
if (techNames.length > 0) {
|
|
46
|
+
display.barLine(
|
|
47
|
+
`${'Stack'.padEnd(11)}${display.renderBadgeList(techNames, display.STACK_BADGES)}`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
46
50
|
|
|
47
51
|
// Agents
|
|
48
52
|
const universalCount = (meta.universalAgents || []).length;
|
|
49
53
|
const optionalCount = (meta.optionalAgents || []).length;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
display.dim(` Optional: ${meta.optionalAgents.join(', ')}`);
|
|
54
|
-
}
|
|
55
|
-
display.newline();
|
|
54
|
+
display.barLine(
|
|
55
|
+
`${'Agents'.padEnd(11)}${display.white(`${universalCount} universal + ${optionalCount} optional`)}`
|
|
56
|
+
);
|
|
56
57
|
|
|
57
58
|
// Commands and skills counts
|
|
58
59
|
const commandCount = countByPrefix(meta.fileHashes || {}, 'commands/');
|
|
59
60
|
const skillCount = countByPrefix(meta.fileHashes || {}, 'skills/');
|
|
60
|
-
display.
|
|
61
|
-
display.
|
|
61
|
+
display.barLine(`${'Commands'.padEnd(11)}${display.white(String(commandCount))}`);
|
|
62
|
+
display.barLine(`${'Skills'.padEnd(11)}${display.white(String(skillCount))}`);
|
|
62
63
|
display.newline();
|
|
63
64
|
|
|
64
65
|
// Customized files
|
|
@@ -127,10 +128,7 @@ export async function statusCommand() {
|
|
|
127
128
|
const permCount = allow.filter((p) => !p.trim().startsWith('//')).length;
|
|
128
129
|
|
|
129
130
|
const hooks = settings.hooks || {};
|
|
130
|
-
const hookCount = Object.values(hooks).reduce(
|
|
131
|
-
(sum, entries) => sum + entries.length,
|
|
132
|
-
0
|
|
133
|
-
);
|
|
131
|
+
const hookCount = Object.values(hooks).reduce((sum, entries) => sum + entries.length, 0);
|
|
134
132
|
|
|
135
133
|
display.dim(` Hooks: ${hookCount} active`);
|
|
136
134
|
display.dim(` Permissions: ${permCount} rules`);
|
package/src/commands/upgrade.js
CHANGED
|
@@ -45,51 +45,52 @@ export async function upgradeCommand() {
|
|
|
45
45
|
const categories = await categorizeFiles(projectRoot, meta);
|
|
46
46
|
|
|
47
47
|
// 4. Preview
|
|
48
|
-
display.
|
|
49
|
-
display.newline();
|
|
50
|
-
display.dim(` Current version: ${installedVersion}`);
|
|
51
|
-
display.dim(` New version: ${currentVersion}`);
|
|
48
|
+
display.sectionHeader(`WORCLAUDE UPGRADE (v${installedVersion} → v${currentVersion})`);
|
|
52
49
|
display.newline();
|
|
53
50
|
|
|
54
|
-
display.
|
|
51
|
+
display.barLine('Changes:');
|
|
55
52
|
|
|
56
53
|
if (categories.autoUpdate.length > 0) {
|
|
57
|
-
display.
|
|
54
|
+
display.barLine(`${display.green('✓')} Auto-update (unchanged since install):`);
|
|
58
55
|
const showCount = Math.min(categories.autoUpdate.length, 3);
|
|
59
56
|
for (let i = 0; i < showCount; i++) {
|
|
60
|
-
display.
|
|
57
|
+
display.barLine(` ${display.green('✓')} ${categories.autoUpdate[i].key}`);
|
|
61
58
|
}
|
|
62
59
|
if (categories.autoUpdate.length > 3) {
|
|
63
|
-
display.
|
|
60
|
+
display.barLine(` ${display.green('✓')} ${categories.autoUpdate.length - 3} more files`);
|
|
64
61
|
}
|
|
65
62
|
display.newline();
|
|
66
63
|
}
|
|
67
64
|
|
|
68
65
|
if (categories.conflict.length > 0) {
|
|
69
|
-
display.
|
|
66
|
+
display.barLine(`${display.yellow('~')} Needs review (you've customized these):`);
|
|
70
67
|
for (const { key } of categories.conflict) {
|
|
71
|
-
display.
|
|
68
|
+
display.barLine(
|
|
69
|
+
` ${display.yellow('~')} ${key} ${display.dimColor('(modified since install)')}`
|
|
70
|
+
);
|
|
72
71
|
}
|
|
73
72
|
display.newline();
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
if (categories.newFiles.length > 0) {
|
|
77
|
-
display.
|
|
76
|
+
display.barLine(`${display.green('+')} New in this version:`);
|
|
78
77
|
for (const { key } of categories.newFiles) {
|
|
79
|
-
display.
|
|
78
|
+
display.barLine(` ${display.green('+')} ${key}`);
|
|
80
79
|
}
|
|
81
80
|
display.newline();
|
|
82
81
|
}
|
|
83
82
|
|
|
84
83
|
if (categories.unchanged.length > 0) {
|
|
85
|
-
display.
|
|
84
|
+
display.barLine(
|
|
85
|
+
`${display.dimColor('=')} Unchanged: ${display.dimColor(`${categories.unchanged.length} files`)}`
|
|
86
|
+
);
|
|
86
87
|
display.newline();
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
if (categories.modified.length > 0) {
|
|
90
|
-
display.
|
|
91
|
+
display.barLine(`${display.yellow('~')} Your customizations (no workflow updates available):`);
|
|
91
92
|
for (const { key } of categories.modified) {
|
|
92
|
-
display.
|
|
93
|
+
display.barLine(` ${display.yellow('~')} ${key}`);
|
|
93
94
|
}
|
|
94
95
|
display.newline();
|
|
95
96
|
}
|
|
@@ -182,24 +183,28 @@ export async function upgradeCommand() {
|
|
|
182
183
|
// 7. Display report
|
|
183
184
|
display.newline();
|
|
184
185
|
if (categories.autoUpdate.length > 0) {
|
|
185
|
-
display.
|
|
186
|
+
display.barLine(`Updated: ${categories.autoUpdate.length} files`);
|
|
186
187
|
}
|
|
187
188
|
if (categories.conflict.length > 0) {
|
|
188
|
-
display.
|
|
189
|
+
display.barLine(
|
|
190
|
+
`Conflicts: ${categories.conflict.length} files ${display.dimColor('(saved as .workflow-ref.md)')}`
|
|
191
|
+
);
|
|
189
192
|
}
|
|
190
193
|
if (categories.newFiles.length > 0) {
|
|
191
|
-
display.
|
|
194
|
+
display.barLine(`New: ${categories.newFiles.length} files added`);
|
|
192
195
|
}
|
|
193
|
-
display.
|
|
196
|
+
display.barLine(`Unchanged: ${categories.unchanged.length} files`);
|
|
194
197
|
if (categories.modified.length > 0) {
|
|
195
|
-
display.
|
|
198
|
+
display.barLine(
|
|
199
|
+
`Customized: ${categories.modified.length} files ${display.dimColor('(no updates needed)')}`
|
|
200
|
+
);
|
|
196
201
|
}
|
|
197
202
|
display.newline();
|
|
198
|
-
display.
|
|
203
|
+
display.barLine(display.dimColor(`Backup: ${path.basename(backupDir)}/`));
|
|
199
204
|
|
|
200
205
|
if (categories.conflict.length > 0) {
|
|
201
206
|
display.newline();
|
|
202
|
-
display.
|
|
207
|
+
display.barLine(`Review .workflow-ref.md files and merge what's useful.`);
|
|
203
208
|
}
|
|
204
209
|
} catch (err) {
|
|
205
210
|
spinner.fail('Upgrade failed.');
|
package/src/core/merger.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import { readFile, writeFile } from '../utils/file.js';
|
|
4
|
-
import {
|
|
5
|
-
readTemplate,
|
|
6
|
-
substituteVariables,
|
|
7
|
-
scaffoldFile,
|
|
8
|
-
mergeSettings,
|
|
9
|
-
} from './scaffolder.js';
|
|
4
|
+
import { readTemplate, substituteVariables, scaffoldFile, mergeSettings } from './scaffolder.js';
|
|
10
5
|
import { promptHookConflict } from '../prompts/conflict-resolution.js';
|
|
11
6
|
import {
|
|
12
7
|
detectMissingSections,
|
|
@@ -102,8 +97,16 @@ function parseUserJson(raw, filename) {
|
|
|
102
97
|
|
|
103
98
|
async function mergeSkills(projectRoot, existingScan, variables, report) {
|
|
104
99
|
const allSkills = [
|
|
105
|
-
...UNIVERSAL_SKILLS.map((s) => ({
|
|
106
|
-
|
|
100
|
+
...UNIVERSAL_SKILLS.map((s) => ({
|
|
101
|
+
name: s,
|
|
102
|
+
templatePath: `skills/universal/${s}.md`,
|
|
103
|
+
vars: {},
|
|
104
|
+
})),
|
|
105
|
+
...TEMPLATE_SKILLS.map((s) => ({
|
|
106
|
+
name: s,
|
|
107
|
+
templatePath: `skills/templates/${s}.md`,
|
|
108
|
+
vars: variables,
|
|
109
|
+
})),
|
|
107
110
|
];
|
|
108
111
|
|
|
109
112
|
for (const skill of allSkills) {
|
|
@@ -251,13 +254,9 @@ export async function mergeSettingsPermissionsAndHooks(projectRoot, workflowSett
|
|
|
251
254
|
},
|
|
252
255
|
],
|
|
253
256
|
};
|
|
254
|
-
report.hookConflicts.push(
|
|
255
|
-
`${category} "${workflowEntry.matcher}": chained both hooks`
|
|
256
|
-
);
|
|
257
|
+
report.hookConflicts.push(`${category} "${workflowEntry.matcher}": chained both hooks`);
|
|
257
258
|
} else {
|
|
258
|
-
report.hookConflicts.push(
|
|
259
|
-
`${category} "${workflowEntry.matcher}": kept existing hook`
|
|
260
|
-
);
|
|
259
|
+
report.hookConflicts.push(`${category} "${workflowEntry.matcher}": kept existing hook`);
|
|
261
260
|
}
|
|
262
261
|
} else {
|
|
263
262
|
// Tier 1: no conflict — append
|
|
@@ -291,9 +290,7 @@ async function mergeSettingsJson(projectRoot, existingScan, selections, report)
|
|
|
291
290
|
try {
|
|
292
291
|
await mergeSettingsPermissionsAndHooks(projectRoot, workflowSettings, report);
|
|
293
292
|
} catch {
|
|
294
|
-
display.warn(
|
|
295
|
-
'Existing settings.json contains invalid JSON — creating fresh settings instead.'
|
|
296
|
-
);
|
|
293
|
+
display.warn('Existing settings.json contains invalid JSON — creating fresh settings instead.');
|
|
297
294
|
await writeFile(path.join(projectRoot, '.claude', 'settings.json'), settingsStr);
|
|
298
295
|
report.added.permissions = workflowSettings.permissions?.allow?.length || 0;
|
|
299
296
|
report.added.hooks = countHooks(workflowSettings.hooks);
|
|
@@ -383,7 +380,13 @@ async function handleClaudeMd(projectRoot, existingScan, variables, report) {
|
|
|
383
380
|
|
|
384
381
|
// --- Main merge function ---
|
|
385
382
|
|
|
386
|
-
export async function performMerge(
|
|
383
|
+
export async function performMerge(
|
|
384
|
+
projectRoot,
|
|
385
|
+
existingScan,
|
|
386
|
+
selections,
|
|
387
|
+
variables,
|
|
388
|
+
{ spinner } = {}
|
|
389
|
+
) {
|
|
387
390
|
const report = {
|
|
388
391
|
added: { skills: [], agents: [], commands: [], permissions: 0, hooks: 0 },
|
|
389
392
|
conflicts: { skills: [], agents: [], commands: [] },
|
package/src/data/agents.js
CHANGED
|
@@ -7,34 +7,154 @@ export const UNIVERSAL_AGENTS = [
|
|
|
7
7
|
];
|
|
8
8
|
|
|
9
9
|
export const AGENT_CATALOG = {
|
|
10
|
-
'ui-reviewer': {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
'
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
'
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
10
|
+
'ui-reviewer': {
|
|
11
|
+
model: 'sonnet',
|
|
12
|
+
isolation: 'none',
|
|
13
|
+
category: 'frontend',
|
|
14
|
+
description: 'Reviews UI for consistency and accessibility',
|
|
15
|
+
},
|
|
16
|
+
'style-enforcer': {
|
|
17
|
+
model: 'haiku',
|
|
18
|
+
isolation: 'none',
|
|
19
|
+
category: 'frontend',
|
|
20
|
+
description: 'Ensures design system compliance',
|
|
21
|
+
},
|
|
22
|
+
'api-designer': {
|
|
23
|
+
model: 'opus',
|
|
24
|
+
isolation: 'none',
|
|
25
|
+
category: 'backend',
|
|
26
|
+
description: 'Reviews API design for RESTful conventions',
|
|
27
|
+
},
|
|
28
|
+
'database-analyst': {
|
|
29
|
+
model: 'sonnet',
|
|
30
|
+
isolation: 'none',
|
|
31
|
+
category: 'backend',
|
|
32
|
+
description: 'Reviews database schemas and queries',
|
|
33
|
+
},
|
|
34
|
+
'auth-auditor': {
|
|
35
|
+
model: 'opus',
|
|
36
|
+
isolation: 'none',
|
|
37
|
+
category: 'backend',
|
|
38
|
+
description: 'Audits authentication and authorization',
|
|
39
|
+
},
|
|
40
|
+
'security-reviewer': {
|
|
41
|
+
model: 'opus',
|
|
42
|
+
isolation: 'none',
|
|
43
|
+
category: 'quality',
|
|
44
|
+
description: 'Reviews code for security vulnerabilities',
|
|
45
|
+
},
|
|
46
|
+
'performance-auditor': {
|
|
47
|
+
model: 'sonnet',
|
|
48
|
+
isolation: 'none',
|
|
49
|
+
category: 'quality',
|
|
50
|
+
description: 'Analyzes code for performance issues',
|
|
51
|
+
},
|
|
52
|
+
'bug-fixer': {
|
|
53
|
+
model: 'sonnet',
|
|
54
|
+
isolation: 'worktree',
|
|
55
|
+
category: 'quality',
|
|
56
|
+
description: 'Diagnoses and fixes bugs',
|
|
57
|
+
},
|
|
58
|
+
refactorer: {
|
|
59
|
+
model: 'sonnet',
|
|
60
|
+
isolation: 'worktree',
|
|
61
|
+
category: 'quality',
|
|
62
|
+
description: 'Refactors code to improve maintainability',
|
|
63
|
+
},
|
|
64
|
+
'dependency-manager': {
|
|
65
|
+
model: 'haiku',
|
|
66
|
+
isolation: 'none',
|
|
67
|
+
category: 'devops',
|
|
68
|
+
description: 'Reviews dependency health and updates',
|
|
69
|
+
},
|
|
70
|
+
'ci-fixer': {
|
|
71
|
+
model: 'sonnet',
|
|
72
|
+
isolation: 'worktree',
|
|
73
|
+
category: 'devops',
|
|
74
|
+
description: 'Diagnoses and fixes CI/CD failures',
|
|
75
|
+
},
|
|
76
|
+
'docker-helper': {
|
|
77
|
+
model: 'sonnet',
|
|
78
|
+
isolation: 'none',
|
|
79
|
+
category: 'devops',
|
|
80
|
+
description: 'Reviews Docker configs for best practices',
|
|
81
|
+
},
|
|
82
|
+
'deploy-validator': {
|
|
83
|
+
model: 'sonnet',
|
|
84
|
+
isolation: 'none',
|
|
85
|
+
category: 'devops',
|
|
86
|
+
description: 'Validates deployment readiness',
|
|
87
|
+
},
|
|
88
|
+
'doc-writer': {
|
|
89
|
+
model: 'sonnet',
|
|
90
|
+
isolation: 'worktree',
|
|
91
|
+
category: 'docs',
|
|
92
|
+
description: 'Writes and updates documentation',
|
|
93
|
+
},
|
|
94
|
+
'changelog-generator': {
|
|
95
|
+
model: 'haiku',
|
|
96
|
+
isolation: 'none',
|
|
97
|
+
category: 'docs',
|
|
98
|
+
description: 'Generates changelog from commits',
|
|
99
|
+
},
|
|
100
|
+
'data-pipeline-reviewer': {
|
|
101
|
+
model: 'sonnet',
|
|
102
|
+
isolation: 'none',
|
|
103
|
+
category: 'data',
|
|
104
|
+
description: 'Reviews data pipeline correctness',
|
|
105
|
+
},
|
|
106
|
+
'ml-experiment-tracker': {
|
|
107
|
+
model: 'sonnet',
|
|
108
|
+
isolation: 'none',
|
|
109
|
+
category: 'data',
|
|
110
|
+
description: 'Reviews ML experiment reproducibility',
|
|
111
|
+
},
|
|
112
|
+
'prompt-engineer': {
|
|
113
|
+
model: 'opus',
|
|
114
|
+
isolation: 'none',
|
|
115
|
+
category: 'data',
|
|
116
|
+
description: 'Reviews and improves LLM prompts',
|
|
117
|
+
},
|
|
28
118
|
};
|
|
29
119
|
|
|
30
120
|
export const CATEGORY_RECOMMENDATIONS = {
|
|
31
|
-
'Full-stack web application': [
|
|
32
|
-
|
|
121
|
+
'Full-stack web application': [
|
|
122
|
+
'ui-reviewer',
|
|
123
|
+
'api-designer',
|
|
124
|
+
'database-analyst',
|
|
125
|
+
'security-reviewer',
|
|
126
|
+
'bug-fixer',
|
|
127
|
+
'doc-writer',
|
|
128
|
+
],
|
|
129
|
+
'Backend / API': [
|
|
130
|
+
'api-designer',
|
|
131
|
+
'database-analyst',
|
|
132
|
+
'security-reviewer',
|
|
133
|
+
'auth-auditor',
|
|
134
|
+
'bug-fixer',
|
|
135
|
+
'performance-auditor',
|
|
136
|
+
],
|
|
33
137
|
'Frontend / UI': ['ui-reviewer', 'style-enforcer', 'performance-auditor', 'bug-fixer'],
|
|
34
138
|
'CLI tool': ['bug-fixer', 'doc-writer', 'dependency-manager'],
|
|
35
|
-
'Data / ML / AI': [
|
|
36
|
-
|
|
37
|
-
|
|
139
|
+
'Data / ML / AI': [
|
|
140
|
+
'data-pipeline-reviewer',
|
|
141
|
+
'ml-experiment-tracker',
|
|
142
|
+
'prompt-engineer',
|
|
143
|
+
'database-analyst',
|
|
144
|
+
],
|
|
145
|
+
'Library / Package': [
|
|
146
|
+
'doc-writer',
|
|
147
|
+
'dependency-manager',
|
|
148
|
+
'performance-auditor',
|
|
149
|
+
'refactorer',
|
|
150
|
+
'changelog-generator',
|
|
151
|
+
],
|
|
152
|
+
'DevOps / Infrastructure': [
|
|
153
|
+
'ci-fixer',
|
|
154
|
+
'docker-helper',
|
|
155
|
+
'deploy-validator',
|
|
156
|
+
'dependency-manager',
|
|
157
|
+
],
|
|
38
158
|
};
|
|
39
159
|
|
|
40
160
|
export const COMMAND_FILES = [
|
package/src/index.js
CHANGED
|
@@ -38,10 +38,7 @@ program
|
|
|
38
38
|
.description('Create a backup of current Claude setup')
|
|
39
39
|
.action(backupCommand);
|
|
40
40
|
|
|
41
|
-
program
|
|
42
|
-
.command('restore')
|
|
43
|
-
.description('Restore Claude setup from a backup')
|
|
44
|
-
.action(restoreCommand);
|
|
41
|
+
program.command('restore').description('Restore Claude setup from a backup').action(restoreCommand);
|
|
45
42
|
|
|
46
43
|
program
|
|
47
44
|
.command('diff')
|
|
@@ -10,9 +10,9 @@ import * as display from '../utils/display.js';
|
|
|
10
10
|
export async function promptAgentSelection(projectTypes) {
|
|
11
11
|
// Show universal agents (informational)
|
|
12
12
|
display.newline();
|
|
13
|
-
display.
|
|
13
|
+
display.sectionHeader('UNIVERSAL AGENTS');
|
|
14
14
|
for (const agent of UNIVERSAL_AGENTS) {
|
|
15
|
-
display.
|
|
15
|
+
display.barLine(`${display.green('✓')} ${display.renderAgentWithBadges(agent)}`);
|
|
16
16
|
}
|
|
17
17
|
display.newline();
|
|
18
18
|
|
|
@@ -68,7 +68,7 @@ export async function promptAgentSelection(projectTypes) {
|
|
|
68
68
|
{
|
|
69
69
|
type: 'checkbox',
|
|
70
70
|
name: 'additionalCategories',
|
|
71
|
-
message:
|
|
71
|
+
message: "Any other agent categories you'd like to add? (space to toggle, enter to skip)",
|
|
72
72
|
choices: unselectedCategories.map((cat) => ({
|
|
73
73
|
name: `${cat} — ${AGENT_CATEGORIES[cat].description}`,
|
|
74
74
|
value: cat,
|
|
@@ -58,7 +58,7 @@ export function generateWorkflowSuggestions(existingContent, renderedTemplate) {
|
|
|
58
58
|
'# Worclaude — Suggested CLAUDE.md Additions',
|
|
59
59
|
'',
|
|
60
60
|
'The following sections are recommended based on the Claude Code',
|
|
61
|
-
|
|
61
|
+
"workflow system. Review and merge what's useful into your CLAUDE.md.",
|
|
62
62
|
'',
|
|
63
63
|
];
|
|
64
64
|
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import inquirer from 'inquirer';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
PROJECT_TYPES,
|
|
4
|
+
PROJECT_TYPE_DESCRIPTIONS,
|
|
5
|
+
CATEGORY_RECOMMENDATIONS,
|
|
6
|
+
} from '../data/agents.js';
|
|
3
7
|
import * as display from '../utils/display.js';
|
|
4
8
|
|
|
5
9
|
export async function promptProjectType() {
|
|
@@ -8,7 +12,7 @@ export async function promptProjectType() {
|
|
|
8
12
|
type: 'checkbox',
|
|
9
13
|
name: 'projectTypes',
|
|
10
14
|
message:
|
|
11
|
-
|
|
15
|
+
"What type of project is this? (space to toggle, enter to confirm)\n ℹ Not sure? Pick what's closest. You can add/remove agents later.",
|
|
12
16
|
choices: PROJECT_TYPES.map((t) => ({
|
|
13
17
|
name: `${t} — ${PROJECT_TYPE_DESCRIPTIONS[t]}`,
|
|
14
18
|
value: t,
|
package/src/utils/display.js
CHANGED
|
@@ -1,41 +1,186 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import { AGENT_CATALOG } from '../data/agents.js';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
// ── Color Palette ──────────────────────────────────────────────
|
|
5
|
+
|
|
6
|
+
// Brand colors
|
|
7
|
+
export const purple = chalk.hex('#c4b5fd');
|
|
8
|
+
// purpleDim covered by dimColor
|
|
9
|
+
|
|
10
|
+
// Semantic colors
|
|
11
|
+
export const green = chalk.hex('#6ee7b7');
|
|
12
|
+
export const yellow = chalk.hex('#fbbf24');
|
|
13
|
+
export const white = chalk.hex('#e2e0f0');
|
|
14
|
+
export const dimColor = chalk.hex('#6b6590');
|
|
15
|
+
export const blue = chalk.hex('#7dd3fc');
|
|
16
|
+
// teal and pink are used via badge styles below
|
|
17
|
+
export const red = chalk.hex('#fca5a5');
|
|
18
|
+
|
|
19
|
+
// ── Badge Styles ───────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
export const badges = {
|
|
22
|
+
// Models
|
|
23
|
+
opus: chalk.bgHex('#2d2455').hex('#c4b5fd'),
|
|
24
|
+
sonnet: chalk.bgHex('#1a2a3a').hex('#7dd3fc'),
|
|
25
|
+
haiku: chalk.bgHex('#2a2520').hex('#fbbf24'),
|
|
26
|
+
|
|
27
|
+
// Isolation
|
|
28
|
+
worktree: chalk.bgHex('#1a3a2a').hex('#6ee7b7'),
|
|
29
|
+
|
|
30
|
+
// Categories
|
|
31
|
+
backend: chalk.bgHex('#2d2455').hex('#c4b5fd'),
|
|
32
|
+
frontend: chalk.bgHex('#2a1a2a').hex('#f9a8d4'),
|
|
33
|
+
devops: chalk.bgHex('#1a2a2a').hex('#5eead4'),
|
|
34
|
+
quality: chalk.bgHex('#2a2520').hex('#fbbf24'),
|
|
35
|
+
docs: chalk.bgHex('#1a2520').hex('#6ee7b7'),
|
|
36
|
+
dataai: chalk.bgHex('#1a1a2a').hex('#818cf8'),
|
|
37
|
+
|
|
38
|
+
// Tech stacks
|
|
39
|
+
python: chalk.bgHex('#1a3a2a').hex('#6ee7b7'),
|
|
40
|
+
node: chalk.bgHex('#1a3a2a').hex('#6ee7b7'),
|
|
41
|
+
java: chalk.bgHex('#2a2520').hex('#fbbf24'),
|
|
42
|
+
csharp: chalk.bgHex('#2d2455').hex('#c4b5fd'),
|
|
43
|
+
cpp: chalk.bgHex('#1a2a3a').hex('#7dd3fc'),
|
|
44
|
+
go: chalk.bgHex('#1a2a2a').hex('#5eead4'),
|
|
45
|
+
rust: chalk.bgHex('#2a1a1a').hex('#fca5a5'),
|
|
46
|
+
php: chalk.bgHex('#1a1a2a').hex('#818cf8'),
|
|
47
|
+
docker: chalk.bgHex('#1a2a2a').hex('#5eead4'),
|
|
48
|
+
|
|
49
|
+
// Project types
|
|
50
|
+
backendApi: chalk.bgHex('#2d2455').hex('#c4b5fd'),
|
|
51
|
+
frontendUi: chalk.bgHex('#2a1a2a').hex('#f9a8d4'),
|
|
52
|
+
fullstack: chalk.bgHex('#1a2a3a').hex('#7dd3fc'),
|
|
53
|
+
library: chalk.bgHex('#1a3a2a').hex('#6ee7b7'),
|
|
54
|
+
cli: chalk.bgHex('#1a2a2a').hex('#5eead4'),
|
|
55
|
+
dataml: chalk.bgHex('#2a2520').hex('#fbbf24'),
|
|
56
|
+
devopsInfra: chalk.bgHex('#1a1a2a').hex('#818cf8'),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// ── Badge-to-Data Lookup Maps ──────────────────────────────────
|
|
60
|
+
|
|
61
|
+
export const MODEL_BADGES = {
|
|
62
|
+
opus: badges.opus,
|
|
63
|
+
sonnet: badges.sonnet,
|
|
64
|
+
haiku: badges.haiku,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const CATEGORY_BADGES = {
|
|
68
|
+
Backend: badges.backend,
|
|
69
|
+
Frontend: badges.frontend,
|
|
70
|
+
DevOps: badges.devops,
|
|
71
|
+
Quality: badges.quality,
|
|
72
|
+
Documentation: badges.docs,
|
|
73
|
+
'Data / AI': badges.dataai,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const STACK_BADGES = {
|
|
77
|
+
Python: badges.python,
|
|
78
|
+
'Node.js / TypeScript': badges.node,
|
|
79
|
+
Java: badges.java,
|
|
80
|
+
'C# / .NET': badges.csharp,
|
|
81
|
+
'C / C++': badges.cpp,
|
|
82
|
+
Go: badges.go,
|
|
83
|
+
Rust: badges.rust,
|
|
84
|
+
PHP: badges.php,
|
|
85
|
+
Docker: badges.docker,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const TYPE_BADGES = {
|
|
89
|
+
'Backend / API': badges.backendApi,
|
|
90
|
+
'Frontend / UI': badges.frontendUi,
|
|
91
|
+
'Full-stack web application': badges.fullstack,
|
|
92
|
+
'Library / Package': badges.library,
|
|
93
|
+
'CLI tool': badges.cli,
|
|
94
|
+
'Data / ML / AI': badges.dataml,
|
|
95
|
+
'DevOps / Infrastructure': badges.devopsInfra,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// ── Universal Agent Metadata ───────────────────────────────────
|
|
99
|
+
|
|
100
|
+
const UNIVERSAL_AGENT_META = {
|
|
101
|
+
'plan-reviewer': { model: 'opus', isolation: 'none' },
|
|
102
|
+
'code-simplifier': { model: 'sonnet', isolation: 'worktree' },
|
|
103
|
+
'test-writer': { model: 'sonnet', isolation: 'worktree' },
|
|
104
|
+
'build-validator': { model: 'haiku', isolation: 'none' },
|
|
105
|
+
'verify-app': { model: 'sonnet', isolation: 'worktree' },
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// ── Badge Rendering ────────────────────────────────────────────
|
|
109
|
+
|
|
110
|
+
function capitalize(s) {
|
|
111
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function badge(text, style) {
|
|
115
|
+
return style(` ${text} `);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function renderBadge(text, mapping) {
|
|
119
|
+
const style = mapping[text];
|
|
120
|
+
if (style) return badge(text, style);
|
|
121
|
+
return text;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function renderBadgeList(items, mapping) {
|
|
125
|
+
return items.map((item) => renderBadge(item, mapping)).join(' ');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function renderAgentWithBadges(name) {
|
|
129
|
+
const meta = UNIVERSAL_AGENT_META[name] || AGENT_CATALOG[name];
|
|
130
|
+
if (!meta) return name;
|
|
131
|
+
|
|
132
|
+
let line = name.padEnd(20);
|
|
133
|
+
line += badge(capitalize(meta.model), MODEL_BADGES[meta.model]);
|
|
134
|
+
if (meta.isolation === 'worktree') {
|
|
135
|
+
line += ' ' + badge('worktree', badges.worktree);
|
|
136
|
+
}
|
|
137
|
+
return line;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ── Structural Elements ────────────────────────────────────────
|
|
141
|
+
|
|
142
|
+
export const bar = dimColor('│');
|
|
143
|
+
|
|
144
|
+
export function banner(version) {
|
|
145
|
+
console.log();
|
|
146
|
+
console.log(` ${purple('▌')} ${white('WORCLAUDE')} ${dimColor(`v${version}`)}`);
|
|
4
147
|
console.log();
|
|
5
|
-
console.log(chalk.bold(text));
|
|
6
|
-
console.log(chalk.dim('─'.repeat(text.length)));
|
|
7
148
|
}
|
|
8
149
|
|
|
150
|
+
export function sectionHeader(title) {
|
|
151
|
+
console.log(` ${purple('▌')} ${white(title)}`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function divider(label) {
|
|
155
|
+
console.log(` ${dimColor(`─── ${label} ───`)}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function barLine(text) {
|
|
159
|
+
console.log(` ${bar} ${text}`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ── Display Functions (backward-compatible signatures) ─────────
|
|
163
|
+
|
|
9
164
|
export function success(text) {
|
|
10
|
-
console.log(
|
|
165
|
+
console.log(` ${green('✓')} ${text}`);
|
|
11
166
|
}
|
|
12
167
|
|
|
13
168
|
export function error(text) {
|
|
14
|
-
console.log(
|
|
169
|
+
console.log(` ${red('✗')} ${text}`);
|
|
15
170
|
}
|
|
16
171
|
|
|
17
172
|
export function info(text) {
|
|
18
|
-
console.log(
|
|
173
|
+
console.log(` ${blue('ℹ')} ${text}`);
|
|
19
174
|
}
|
|
20
175
|
|
|
21
176
|
export function warn(text) {
|
|
22
|
-
console.log(
|
|
177
|
+
console.log(` ${yellow('⚠')} ${text}`);
|
|
23
178
|
}
|
|
24
179
|
|
|
25
180
|
export function dim(text) {
|
|
26
|
-
console.log(
|
|
181
|
+
console.log(dimColor(' ' + text));
|
|
27
182
|
}
|
|
28
183
|
|
|
29
184
|
export function newline() {
|
|
30
185
|
console.log();
|
|
31
186
|
}
|
|
32
|
-
|
|
33
|
-
export function reviewBox(lines) {
|
|
34
|
-
console.log();
|
|
35
|
-
console.log(chalk.dim(' ─── Review Your Selections ───'));
|
|
36
|
-
console.log();
|
|
37
|
-
for (const line of lines) {
|
|
38
|
-
console.log(' ' + line);
|
|
39
|
-
}
|
|
40
|
-
console.log();
|
|
41
|
-
}
|