claude-cli-advanced-starter-pack 1.1.0 → 1.8.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/OVERVIEW.md +5 -1
- package/README.md +241 -132
- package/bin/gtask.js +53 -0
- package/package.json +1 -1
- package/src/cli/menu.js +27 -0
- package/src/commands/explore-mcp/mcp-registry.js +99 -0
- package/src/commands/init.js +306 -77
- package/src/commands/install-panel-hook.js +108 -0
- package/src/commands/install-scripts.js +232 -0
- package/src/commands/install-skill.js +220 -0
- package/src/commands/panel.js +297 -0
- package/src/commands/setup-wizard.js +4 -3
- package/src/commands/test-setup.js +4 -5
- package/src/data/releases.json +164 -0
- package/src/panel/queue.js +188 -0
- package/templates/commands/ask-claude.template.md +118 -0
- package/templates/commands/ccasp-panel.template.md +72 -0
- package/templates/commands/ccasp-setup.template.md +470 -79
- package/templates/commands/create-smoke-test.template.md +186 -0
- package/templates/commands/project-impl.template.md +9 -113
- package/templates/commands/refactor-check.template.md +112 -0
- package/templates/commands/refactor-cleanup.template.md +144 -0
- package/templates/commands/refactor-prep.template.md +192 -0
- package/templates/docs/AI_ARCHITECTURE_CONSTITUTION.template.md +198 -0
- package/templates/docs/DETAILED_GOTCHAS.template.md +347 -0
- package/templates/docs/PHASE-DEV-CHECKLIST.template.md +241 -0
- package/templates/docs/PROGRESS_JSON_TEMPLATE.json +117 -0
- package/templates/docs/background-agent.template.md +264 -0
- package/templates/hooks/autonomous-decision-logger.template.js +207 -0
- package/templates/hooks/branch-merge-checker.template.js +272 -0
- package/templates/hooks/git-commit-tracker.template.js +267 -0
- package/templates/hooks/issue-completion-detector.template.js +205 -0
- package/templates/hooks/panel-queue-reader.template.js +83 -0
- package/templates/hooks/phase-validation-gates.template.js +307 -0
- package/templates/hooks/session-id-generator.template.js +236 -0
- package/templates/hooks/token-usage-monitor.template.js +193 -0
- package/templates/patterns/README.md +129 -0
- package/templates/patterns/l1-l2-orchestration.md +189 -0
- package/templates/patterns/multi-phase-orchestration.md +258 -0
- package/templates/patterns/two-tier-query-pipeline.md +192 -0
- package/templates/scripts/README.md +109 -0
- package/templates/scripts/analyze-delegation-log.js +299 -0
- package/templates/scripts/autonomous-decision-logger.js +277 -0
- package/templates/scripts/git-history-analyzer.py +269 -0
- package/templates/scripts/phase-validation-gates.js +307 -0
- package/templates/scripts/poll-deployment-status.js +260 -0
- package/templates/scripts/roadmap-scanner.js +263 -0
- package/templates/scripts/validate-deployment.js +293 -0
- package/templates/skills/agent-creator/skill.json +18 -0
- package/templates/skills/agent-creator/skill.md +335 -0
- package/templates/skills/hook-creator/skill.json +18 -0
- package/templates/skills/hook-creator/skill.md +318 -0
- package/templates/skills/panel/skill.json +18 -0
- package/templates/skills/panel/skill.md +90 -0
- package/templates/skills/rag-agent-creator/skill.json +18 -0
- package/templates/skills/rag-agent-creator/skill.md +307 -0
package/src/commands/init.js
CHANGED
|
@@ -93,6 +93,51 @@ const OPTIONAL_FEATURES = [
|
|
|
93
93
|
default: false,
|
|
94
94
|
requiresPostConfig: true,
|
|
95
95
|
},
|
|
96
|
+
{
|
|
97
|
+
name: 'advancedHooks',
|
|
98
|
+
label: 'Advanced Hook Suite',
|
|
99
|
+
description: 'Extended hook system with session management, git commit tracking, branch validation, issue detection, token monitoring, autonomous logging, and phase validation gates.',
|
|
100
|
+
commands: [],
|
|
101
|
+
hooks: [
|
|
102
|
+
'session-id-generator',
|
|
103
|
+
'git-commit-tracker',
|
|
104
|
+
'branch-merge-checker',
|
|
105
|
+
'issue-completion-detector',
|
|
106
|
+
'token-usage-monitor',
|
|
107
|
+
'autonomous-decision-logger',
|
|
108
|
+
'phase-validation-gates',
|
|
109
|
+
],
|
|
110
|
+
default: false,
|
|
111
|
+
requiresPostConfig: false,
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: 'skillTemplates',
|
|
115
|
+
label: 'Skill Creator Templates',
|
|
116
|
+
description: 'Pre-built skills for agent creation, hook creation, and RAG-enhanced agent building. Provides best-practice templates for extending Claude Code.',
|
|
117
|
+
commands: [],
|
|
118
|
+
hooks: [],
|
|
119
|
+
skills: ['agent-creator', 'hook-creator', 'rag-agent-creator', 'panel'],
|
|
120
|
+
default: true,
|
|
121
|
+
requiresPostConfig: false,
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: 'refactoring',
|
|
125
|
+
label: 'Refactoring Tools',
|
|
126
|
+
description: 'Code quality commands for linting, cleanup, and safe refactoring. Includes pre-commit checks, auto-fix, and safety checklists.',
|
|
127
|
+
commands: ['refactor-check', 'refactor-cleanup', 'refactor-prep'],
|
|
128
|
+
hooks: [],
|
|
129
|
+
default: false,
|
|
130
|
+
requiresPostConfig: false,
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: 'testing',
|
|
134
|
+
label: 'Advanced Testing',
|
|
135
|
+
description: 'Extended testing capabilities including smoke test generation and test coverage analysis.',
|
|
136
|
+
commands: ['create-smoke-test'],
|
|
137
|
+
hooks: [],
|
|
138
|
+
default: false,
|
|
139
|
+
requiresPostConfig: false,
|
|
140
|
+
},
|
|
96
141
|
];
|
|
97
142
|
|
|
98
143
|
/**
|
|
@@ -106,6 +151,12 @@ const AVAILABLE_COMMANDS = [
|
|
|
106
151
|
selected: true,
|
|
107
152
|
required: true,
|
|
108
153
|
},
|
|
154
|
+
{
|
|
155
|
+
name: 'ccasp-panel',
|
|
156
|
+
description: 'Launch control panel in new terminal (agents, skills, hooks, MCP)',
|
|
157
|
+
category: 'Navigation',
|
|
158
|
+
selected: true,
|
|
159
|
+
},
|
|
109
160
|
{
|
|
110
161
|
name: 'e2e-test',
|
|
111
162
|
description: 'Run E2E tests with Playwright (ralph loop, headed, watch modes)',
|
|
@@ -266,6 +317,41 @@ const AVAILABLE_COMMANDS = [
|
|
|
266
317
|
category: 'Maintenance',
|
|
267
318
|
selected: true,
|
|
268
319
|
},
|
|
320
|
+
// Refactoring commands (Phase 4)
|
|
321
|
+
{
|
|
322
|
+
name: 'refactor-check',
|
|
323
|
+
description: 'Fast pre-commit quality gate - lint, type-check, test affected files',
|
|
324
|
+
category: 'Refactoring',
|
|
325
|
+
selected: false,
|
|
326
|
+
feature: 'refactoring',
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
name: 'refactor-cleanup',
|
|
330
|
+
description: 'Daily maintenance automation - fix lint, remove unused imports, format',
|
|
331
|
+
category: 'Refactoring',
|
|
332
|
+
selected: false,
|
|
333
|
+
feature: 'refactoring',
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
name: 'refactor-prep',
|
|
337
|
+
description: 'Pre-refactoring safety checklist - ensure safe conditions',
|
|
338
|
+
category: 'Refactoring',
|
|
339
|
+
selected: false,
|
|
340
|
+
feature: 'refactoring',
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
name: 'ask-claude',
|
|
344
|
+
description: 'Natural language command discovery - find the right command for any task',
|
|
345
|
+
category: 'Discovery',
|
|
346
|
+
selected: true,
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
name: 'create-smoke-test',
|
|
350
|
+
description: 'Auto-generate Playwright smoke tests for critical user flows',
|
|
351
|
+
category: 'Testing',
|
|
352
|
+
selected: false,
|
|
353
|
+
feature: 'testing',
|
|
354
|
+
},
|
|
269
355
|
];
|
|
270
356
|
|
|
271
357
|
/**
|
|
@@ -337,10 +423,19 @@ description: Interactive project menu - Quick access to all commands, agents, sk
|
|
|
337
423
|
|
|
338
424
|
# ${projectName} - Project Menu
|
|
339
425
|
|
|
340
|
-
##
|
|
426
|
+
## CRITICAL FIRST STEP: Check for Updates
|
|
427
|
+
|
|
428
|
+
**BEFORE doing anything else**, you MUST read the update state file:
|
|
429
|
+
|
|
430
|
+
\`\`\`
|
|
431
|
+
Read file: .claude/config/ccasp-state.json
|
|
432
|
+
\`\`\`
|
|
433
|
+
|
|
434
|
+
Use the Read tool NOW to read \`.claude/config/ccasp-state.json\`. If it doesn't exist, that's fine - proceed without update banner.
|
|
341
435
|
|
|
342
|
-
|
|
436
|
+
If the file exists and contains \`"updateAvailable": true\`, you MUST display the update banner BEFORE the menu.
|
|
343
437
|
|
|
438
|
+
Example state file contents:
|
|
344
439
|
\`\`\`javascript
|
|
345
440
|
{
|
|
346
441
|
"currentVersion": "1.0.5",
|
|
@@ -412,6 +507,7 @@ On subsequent displays (when \`updateFirstDisplayed: true\`), show a compact ban
|
|
|
412
507
|
║ [T] Run Tests [G] GitHub Task [P] Phase Dev Plan ║
|
|
413
508
|
║ [A] Create Agent [H] Create Hook [S] Create Skill ║
|
|
414
509
|
║ [M] Explore MCP [C] Claude Audit [E] Explore Codebase ║
|
|
510
|
+
║ [⚡] Launch Panel Open control panel in new terminal window ║
|
|
415
511
|
║ ║
|
|
416
512
|
║ Project Resources: ║
|
|
417
513
|
║ ────────────────── ║
|
|
@@ -455,6 +551,7 @@ When the user invokes \`/menu\`:
|
|
|
455
551
|
| **M** | Explore MCP Servers | \`/explore-mcp\` |
|
|
456
552
|
| **C** | Claude Audit | \`/claude-audit\` |
|
|
457
553
|
| **E** | Explore Codebase | \`/codebase-explorer\` |
|
|
554
|
+
| **⚡** or **L** | Launch Panel | \`/ccasp-panel\` (opens in new terminal) |
|
|
458
555
|
| **1** | List project agents | Read \`.claude/agents/\` |
|
|
459
556
|
| **2** | List project skills | Read \`.claude/skills/\` |
|
|
460
557
|
| **3** | List active hooks | Read \`.claude/hooks/\` |
|
|
@@ -535,6 +632,7 @@ Ask: "What would you like to do? Enter a key:"
|
|
|
535
632
|
| **N** | **Update Now**: Run \`npm update -g claude-cli-advanced-starter-pack\` via Bash, then show: "Update complete! Restart Claude Code CLI to use new features." |
|
|
536
633
|
| **U** | Invoke \`/update-check\` for detailed update info and feature management |
|
|
537
634
|
| **I** | Invoke \`/project-impl\` for project implementation |
|
|
635
|
+
| **⚡** or **L** | **Launch Panel**: Run \`start powershell -NoExit -Command "ccasp panel"\` (Windows) or equivalent to open control panel in new terminal |
|
|
538
636
|
| **R** | Re-invoke \`/menu\` (refresh) |
|
|
539
637
|
| **Q** | End menu session |
|
|
540
638
|
| **1-6** | Read and display the corresponding resource |
|
|
@@ -1599,20 +1697,23 @@ export async function runInit(options = {}) {
|
|
|
1599
1697
|
console.log(chalk.dim(' Use --force flag to overwrite specific commands if needed.'));
|
|
1600
1698
|
console.log('');
|
|
1601
1699
|
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1700
|
+
// Skip prompt if called non-interactively (e.g., from wizard)
|
|
1701
|
+
if (!options.skipPrompts) {
|
|
1702
|
+
const { confirmProceed } = await inquirer.prompt([
|
|
1703
|
+
{
|
|
1704
|
+
type: 'confirm',
|
|
1705
|
+
name: 'confirmProceed',
|
|
1706
|
+
message: 'Continue with installation? (existing files are safe)',
|
|
1707
|
+
default: true,
|
|
1708
|
+
},
|
|
1709
|
+
]);
|
|
1610
1710
|
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1711
|
+
if (!confirmProceed) {
|
|
1712
|
+
console.log(chalk.dim('\nCancelled. No changes made.'));
|
|
1713
|
+
return;
|
|
1714
|
+
}
|
|
1715
|
+
console.log('');
|
|
1614
1716
|
}
|
|
1615
|
-
console.log('');
|
|
1616
1717
|
}
|
|
1617
1718
|
|
|
1618
1719
|
// Step 1: Check and create folder structure
|
|
@@ -1786,46 +1887,63 @@ export async function runInit(options = {}) {
|
|
|
1786
1887
|
console.log('');
|
|
1787
1888
|
|
|
1788
1889
|
// Step 4: Select optional features
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
if (feature.commands.length > 0) {
|
|
1800
|
-
console.log(chalk.dim(` Adds: ${feature.commands.map(c => '/' + c).join(', ')}`));
|
|
1890
|
+
let selectedFeatures;
|
|
1891
|
+
|
|
1892
|
+
if (options.skipPrompts && options.features) {
|
|
1893
|
+
// Use features passed from wizard
|
|
1894
|
+
selectedFeatures = options.features;
|
|
1895
|
+
console.log(chalk.bold('Step 4: Using pre-selected features\n'));
|
|
1896
|
+
if (selectedFeatures.length > 0) {
|
|
1897
|
+
console.log(chalk.dim(` Features: ${selectedFeatures.join(', ')}`));
|
|
1898
|
+
} else {
|
|
1899
|
+
console.log(chalk.dim(' Minimal mode - essential commands only'));
|
|
1801
1900
|
}
|
|
1802
1901
|
console.log('');
|
|
1803
|
-
}
|
|
1902
|
+
} else {
|
|
1903
|
+
console.log(chalk.bold('Step 4: Select optional features\n'));
|
|
1904
|
+
console.log(chalk.dim(' Each feature adds commands and hooks to your project.'));
|
|
1905
|
+
console.log(chalk.dim(' Features marked with (*) require additional configuration via /menu after installation.\n'));
|
|
1906
|
+
|
|
1907
|
+
// Display feature descriptions in a nice format
|
|
1908
|
+
for (const feature of OPTIONAL_FEATURES) {
|
|
1909
|
+
const marker = feature.default ? chalk.green('●') : chalk.dim('○');
|
|
1910
|
+
const postConfig = feature.requiresPostConfig ? chalk.yellow(' (*)') : '';
|
|
1911
|
+
console.log(` ${marker} ${chalk.bold(feature.label)}${postConfig}`);
|
|
1912
|
+
console.log(chalk.dim(` ${feature.description}`));
|
|
1913
|
+
if (feature.commands.length > 0) {
|
|
1914
|
+
console.log(chalk.dim(` Adds: ${feature.commands.map(c => '/' + c).join(', ')}`));
|
|
1915
|
+
}
|
|
1916
|
+
console.log('');
|
|
1917
|
+
}
|
|
1804
1918
|
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1919
|
+
const result = await inquirer.prompt([
|
|
1920
|
+
{
|
|
1921
|
+
type: 'checkbox',
|
|
1922
|
+
name: 'selectedFeatures',
|
|
1923
|
+
message: 'Select features to enable:',
|
|
1924
|
+
choices: OPTIONAL_FEATURES.map((feature) => ({
|
|
1925
|
+
name: `${feature.label}${feature.requiresPostConfig ? ' (*)' : ''} - ${feature.commands.length} commands, ${feature.hooks.length} hooks`,
|
|
1926
|
+
value: feature.name,
|
|
1927
|
+
checked: feature.default,
|
|
1928
|
+
})),
|
|
1929
|
+
pageSize: 10,
|
|
1930
|
+
},
|
|
1931
|
+
]);
|
|
1932
|
+
selectedFeatures = result.selectedFeatures;
|
|
1933
|
+
}
|
|
1818
1934
|
|
|
1819
1935
|
// Store selected features for later use
|
|
1820
1936
|
const enabledFeatures = OPTIONAL_FEATURES.filter((f) => selectedFeatures.includes(f.name));
|
|
1821
1937
|
const featuresRequiringConfig = enabledFeatures.filter((f) => f.requiresPostConfig);
|
|
1822
1938
|
|
|
1823
|
-
// Collect feature-specific commands and
|
|
1939
|
+
// Collect feature-specific commands, hooks, and skills to deploy
|
|
1824
1940
|
const featureCommands = [];
|
|
1825
1941
|
const featureHooks = [];
|
|
1942
|
+
const featureSkills = [];
|
|
1826
1943
|
for (const feature of enabledFeatures) {
|
|
1827
1944
|
featureCommands.push(...feature.commands);
|
|
1828
|
-
featureHooks.push(...feature.hooks);
|
|
1945
|
+
featureHooks.push(...(feature.hooks || []));
|
|
1946
|
+
featureSkills.push(...(feature.skills || []));
|
|
1829
1947
|
}
|
|
1830
1948
|
|
|
1831
1949
|
if (featureCommands.length > 0) {
|
|
@@ -1839,6 +1957,11 @@ export async function runInit(options = {}) {
|
|
|
1839
1957
|
console.log(chalk.dim(` ${featureHooks.join(', ')}`));
|
|
1840
1958
|
}
|
|
1841
1959
|
|
|
1960
|
+
if (featureSkills.length > 0) {
|
|
1961
|
+
console.log(chalk.green(` ✓ Selected features will add ${featureSkills.length} skill(s):`));
|
|
1962
|
+
console.log(chalk.dim(` ${featureSkills.join(', ')}`));
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1842
1965
|
if (featuresRequiringConfig.length > 0) {
|
|
1843
1966
|
console.log('');
|
|
1844
1967
|
console.log(chalk.yellow(' ℹ The following features require configuration after installation:'));
|
|
@@ -1850,7 +1973,7 @@ export async function runInit(options = {}) {
|
|
|
1850
1973
|
|
|
1851
1974
|
// Check for optional npm package installs from selected features
|
|
1852
1975
|
const featuresWithNpm = enabledFeatures.filter((f) => f.npmPackage);
|
|
1853
|
-
if (featuresWithNpm.length > 0) {
|
|
1976
|
+
if (featuresWithNpm.length > 0 && !options.skipPrompts) {
|
|
1854
1977
|
console.log('');
|
|
1855
1978
|
console.log(chalk.bold(' Optional Package Installation\n'));
|
|
1856
1979
|
|
|
@@ -1882,6 +2005,10 @@ export async function runInit(options = {}) {
|
|
|
1882
2005
|
console.log(chalk.dim(` Skipped. Install later with: npm install -g ${feature.npmPackage}`));
|
|
1883
2006
|
}
|
|
1884
2007
|
}
|
|
2008
|
+
} else if (featuresWithNpm.length > 0) {
|
|
2009
|
+
// In skipPrompts mode, just inform about optional packages
|
|
2010
|
+
console.log(chalk.dim(` ℹ Optional packages available: ${featuresWithNpm.map(f => f.npmPackage).join(', ')}`));
|
|
2011
|
+
console.log(chalk.dim(' Install manually if needed.'));
|
|
1885
2012
|
}
|
|
1886
2013
|
|
|
1887
2014
|
console.log('');
|
|
@@ -1895,45 +2022,54 @@ export async function runInit(options = {}) {
|
|
|
1895
2022
|
: [];
|
|
1896
2023
|
const existingCmdNames = existingCmdFiles.map(f => f.replace('.md', ''));
|
|
1897
2024
|
|
|
1898
|
-
if (existingCmdNames.length > 0) {
|
|
2025
|
+
if (existingCmdNames.length > 0 && !options.skipPrompts) {
|
|
1899
2026
|
console.log(chalk.blue(` ℹ Found ${existingCmdNames.length} existing command(s) in your project:`));
|
|
1900
2027
|
console.log(chalk.dim(` ${existingCmdNames.map(c => '/' + c).join(', ')}`));
|
|
1901
2028
|
console.log(chalk.dim(' These will be preserved unless you choose to overwrite.\n'));
|
|
1902
2029
|
}
|
|
1903
2030
|
|
|
1904
|
-
|
|
2031
|
+
let selectedCommands;
|
|
1905
2032
|
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
const required = cmd.required ? chalk.yellow(' (required)') : '';
|
|
1913
|
-
const existing = isExisting ? chalk.blue(' [exists]') : '';
|
|
1914
|
-
console.log(` ${marker} /${cmd.name}${required}${existing} - ${chalk.dim(cmd.description)}`);
|
|
1915
|
-
}
|
|
1916
|
-
console.log('');
|
|
1917
|
-
}
|
|
2033
|
+
if (options.skipPrompts) {
|
|
2034
|
+
// Use default selections when called non-interactively
|
|
2035
|
+
selectedCommands = AVAILABLE_COMMANDS.filter(c => c.selected).map(c => c.name);
|
|
2036
|
+
console.log(chalk.dim(` Auto-selecting ${selectedCommands.length} default command(s)`));
|
|
2037
|
+
} else {
|
|
2038
|
+
const categories = [...new Set(AVAILABLE_COMMANDS.map((c) => c.category))];
|
|
1918
2039
|
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
name: 'selectedCommands',
|
|
1924
|
-
message: 'Select commands to install (existing commands marked with [exists]):',
|
|
1925
|
-
choices: AVAILABLE_COMMANDS.map((cmd) => {
|
|
2040
|
+
for (const category of categories) {
|
|
2041
|
+
console.log(chalk.cyan(` ${category}:`));
|
|
2042
|
+
const cmds = AVAILABLE_COMMANDS.filter((c) => c.category === category);
|
|
2043
|
+
for (const cmd of cmds) {
|
|
1926
2044
|
const isExisting = existingCmdNames.includes(cmd.name);
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
2045
|
+
const marker = cmd.selected ? chalk.green('●') : chalk.dim('○');
|
|
2046
|
+
const required = cmd.required ? chalk.yellow(' (required)') : '';
|
|
2047
|
+
const existing = isExisting ? chalk.blue(' [exists]') : '';
|
|
2048
|
+
console.log(` ${marker} /${cmd.name}${required}${existing} - ${chalk.dim(cmd.description)}`);
|
|
2049
|
+
}
|
|
2050
|
+
console.log('');
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
// Ask which commands to install
|
|
2054
|
+
const result = await inquirer.prompt([
|
|
2055
|
+
{
|
|
2056
|
+
type: 'checkbox',
|
|
2057
|
+
name: 'selectedCommands',
|
|
2058
|
+
message: 'Select commands to install (existing commands marked with [exists]):',
|
|
2059
|
+
choices: AVAILABLE_COMMANDS.map((cmd) => {
|
|
2060
|
+
const isExisting = existingCmdNames.includes(cmd.name);
|
|
2061
|
+
return {
|
|
2062
|
+
name: `/${cmd.name}${isExisting ? ' [exists]' : ''} - ${cmd.description}`,
|
|
2063
|
+
value: cmd.name,
|
|
2064
|
+
checked: cmd.selected,
|
|
2065
|
+
disabled: cmd.required ? 'Required' : false,
|
|
2066
|
+
};
|
|
2067
|
+
}),
|
|
2068
|
+
pageSize: 15,
|
|
2069
|
+
},
|
|
2070
|
+
]);
|
|
2071
|
+
selectedCommands = result.selectedCommands;
|
|
2072
|
+
}
|
|
1937
2073
|
|
|
1938
2074
|
// Always include required commands AND feature-specific commands
|
|
1939
2075
|
const requiredCommands = AVAILABLE_COMMANDS.filter(c => c.required).map(c => c.name);
|
|
@@ -1960,6 +2096,17 @@ export async function runInit(options = {}) {
|
|
|
1960
2096
|
|
|
1961
2097
|
let overwrite = options.force || false;
|
|
1962
2098
|
if (commandsToOverwrite.length > 0 && !overwrite) {
|
|
2099
|
+
// In skipPrompts mode, preserve all existing commands (no overwrite)
|
|
2100
|
+
if (options.skipPrompts) {
|
|
2101
|
+
for (const cmd of commandsToOverwrite) {
|
|
2102
|
+
smartMergeDecisions[cmd] = 'skip';
|
|
2103
|
+
}
|
|
2104
|
+
// Filter out skipped commands
|
|
2105
|
+
const filtered = finalCommands.filter((c) => !commandsToOverwrite.includes(c) || requiredCommands.includes(c));
|
|
2106
|
+
finalCommands.length = 0;
|
|
2107
|
+
finalCommands.push(...filtered);
|
|
2108
|
+
console.log(chalk.dim(` Preserving ${commandsToOverwrite.length} existing command(s), installing ${finalCommands.length} new`));
|
|
2109
|
+
} else {
|
|
1963
2110
|
// Check for customized assets that have been used
|
|
1964
2111
|
const assetsNeedingMerge = getAssetsNeedingMerge(process.cwd());
|
|
1965
2112
|
const customizedCommands = commandsToOverwrite.filter(cmd =>
|
|
@@ -2152,6 +2299,7 @@ export async function runInit(options = {}) {
|
|
|
2152
2299
|
finalCommands.push(...filtered);
|
|
2153
2300
|
}
|
|
2154
2301
|
}
|
|
2302
|
+
} // end else (!options.skipPrompts)
|
|
2155
2303
|
}
|
|
2156
2304
|
|
|
2157
2305
|
// Track if we should create backups (set outside the if block for use later)
|
|
@@ -2254,9 +2402,10 @@ export async function runInit(options = {}) {
|
|
|
2254
2402
|
for (const hookName of featureHooks) {
|
|
2255
2403
|
try {
|
|
2256
2404
|
const hookPath = join(hooksDir, `${hookName}.js`);
|
|
2405
|
+
const hookExists = existsSync(hookPath);
|
|
2257
2406
|
|
|
2258
|
-
//
|
|
2259
|
-
if (
|
|
2407
|
+
// Respect overwrite setting for hooks (like commands)
|
|
2408
|
+
if (hookExists && !overwrite) {
|
|
2260
2409
|
console.log(chalk.blue(` ○ hooks/${hookName}.js exists (preserved)`));
|
|
2261
2410
|
continue;
|
|
2262
2411
|
}
|
|
@@ -2264,10 +2413,18 @@ export async function runInit(options = {}) {
|
|
|
2264
2413
|
// Try to load from templates/hooks/ folder
|
|
2265
2414
|
const templatePath = join(__dirname, '..', '..', 'templates', 'hooks', `${hookName}.template.js`);
|
|
2266
2415
|
if (existsSync(templatePath)) {
|
|
2416
|
+
// Create backup if overwriting existing hook
|
|
2417
|
+
if (hookExists && overwrite) {
|
|
2418
|
+
const backupPath = createBackup(hookPath);
|
|
2419
|
+
if (backupPath) {
|
|
2420
|
+
backedUpFiles.push({ original: hookPath, backup: backupPath });
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
2267
2423
|
const hookContent = readFileSync(templatePath, 'utf8');
|
|
2268
2424
|
writeFileSync(hookPath, hookContent, 'utf8');
|
|
2269
2425
|
deployedHooks.push(hookName);
|
|
2270
|
-
|
|
2426
|
+
const action = hookExists ? 'Updated' : 'Created';
|
|
2427
|
+
console.log(chalk.green(` ✓ ${action} hooks/${hookName}.js`));
|
|
2271
2428
|
} else {
|
|
2272
2429
|
failedHooks.push({ name: hookName, error: 'No template found' });
|
|
2273
2430
|
console.log(chalk.yellow(` ⚠ Skipped hooks/${hookName}.js (no template)`));
|
|
@@ -2283,6 +2440,56 @@ export async function runInit(options = {}) {
|
|
|
2283
2440
|
}
|
|
2284
2441
|
}
|
|
2285
2442
|
|
|
2443
|
+
// Step 6c: Deploy feature skills
|
|
2444
|
+
const deployedSkills = [];
|
|
2445
|
+
const failedSkills = [];
|
|
2446
|
+
|
|
2447
|
+
if (featureSkills.length > 0) {
|
|
2448
|
+
console.log(chalk.bold('\nStep 6c: Deploying feature skills\n'));
|
|
2449
|
+
|
|
2450
|
+
for (const skillName of featureSkills) {
|
|
2451
|
+
try {
|
|
2452
|
+
const skillPath = join(skillsDir, skillName);
|
|
2453
|
+
const skillExists = existsSync(skillPath);
|
|
2454
|
+
|
|
2455
|
+
// Respect overwrite setting for skills (like commands)
|
|
2456
|
+
if (skillExists && !overwrite) {
|
|
2457
|
+
console.log(chalk.blue(` ○ skills/${skillName}/ exists (preserved)`));
|
|
2458
|
+
continue;
|
|
2459
|
+
}
|
|
2460
|
+
|
|
2461
|
+
// Try to load from templates/skills/ folder
|
|
2462
|
+
const templatePath = join(__dirname, '..', '..', 'templates', 'skills', skillName);
|
|
2463
|
+
if (existsSync(templatePath)) {
|
|
2464
|
+
// Create backup if overwriting existing skill
|
|
2465
|
+
if (skillExists && overwrite) {
|
|
2466
|
+
const backupPath = createBackup(skillPath);
|
|
2467
|
+
if (backupPath) {
|
|
2468
|
+
backedUpFiles.push({ original: skillPath, backup: backupPath });
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
// Create skill directory and copy recursively
|
|
2472
|
+
mkdirSync(skillPath, { recursive: true });
|
|
2473
|
+
const { cpSync } = await import('fs');
|
|
2474
|
+
cpSync(templatePath, skillPath, { recursive: true });
|
|
2475
|
+
deployedSkills.push(skillName);
|
|
2476
|
+
const action = skillExists ? 'Updated' : 'Created';
|
|
2477
|
+
console.log(chalk.green(` ✓ ${action} skills/${skillName}/`));
|
|
2478
|
+
} else {
|
|
2479
|
+
failedSkills.push({ name: skillName, error: 'No template found' });
|
|
2480
|
+
console.log(chalk.yellow(` ⚠ Skipped skills/${skillName}/ (no template)`));
|
|
2481
|
+
}
|
|
2482
|
+
} catch (error) {
|
|
2483
|
+
failedSkills.push({ name: skillName, error: error.message });
|
|
2484
|
+
console.log(chalk.red(` ✗ Failed: skills/${skillName}/ - ${error.message}`));
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
if (deployedSkills.length > 0) {
|
|
2489
|
+
console.log(chalk.green(`\n ✓ Deployed ${deployedSkills.length} feature skill(s)`));
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
|
|
2286
2493
|
// Step 7: Generate INDEX.md
|
|
2287
2494
|
const indexPath = join(commandsDir, 'INDEX.md');
|
|
2288
2495
|
const indexContent = generateIndexFile(installed, projectName);
|
|
@@ -2416,6 +2623,8 @@ export async function runInit(options = {}) {
|
|
|
2416
2623
|
featureCommands: featureCommands.filter(c => installed.includes(c)),
|
|
2417
2624
|
hooks: deployedHooks,
|
|
2418
2625
|
featureHooks: featureHooks,
|
|
2626
|
+
skills: deployedSkills,
|
|
2627
|
+
featureSkills: featureSkills,
|
|
2419
2628
|
enabledFeatures: selectedFeatures,
|
|
2420
2629
|
timestamp: new Date().toISOString(),
|
|
2421
2630
|
},
|
|
@@ -2428,6 +2637,26 @@ export async function runInit(options = {}) {
|
|
|
2428
2637
|
console.log(chalk.blue(' ○ config/tech-stack.json exists (preserved)'));
|
|
2429
2638
|
}
|
|
2430
2639
|
|
|
2640
|
+
// Update ccasp-state.json with current version (fixes version display in /menu)
|
|
2641
|
+
const ccaspStatePath = join(configDir, 'ccasp-state.json');
|
|
2642
|
+
const currentVersion = getVersion();
|
|
2643
|
+
let ccaspState = { currentVersion, lastCheckTimestamp: 0, updateAvailable: false };
|
|
2644
|
+
|
|
2645
|
+
if (existsSync(ccaspStatePath)) {
|
|
2646
|
+
try {
|
|
2647
|
+
ccaspState = JSON.parse(readFileSync(ccaspStatePath, 'utf8'));
|
|
2648
|
+
} catch {
|
|
2649
|
+
// Use default state if parse fails
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
|
|
2653
|
+
// Always update the current version to match installed CCASP
|
|
2654
|
+
ccaspState.currentVersion = currentVersion;
|
|
2655
|
+
ccaspState.installedAt = new Date().toISOString();
|
|
2656
|
+
|
|
2657
|
+
writeFileSync(ccaspStatePath, JSON.stringify(ccaspState, null, 2), 'utf8');
|
|
2658
|
+
console.log(chalk.green(` ✓ Updated ccasp-state.json (v${currentVersion})`));
|
|
2659
|
+
|
|
2431
2660
|
// Show next steps
|
|
2432
2661
|
console.log(chalk.bold('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
2433
2662
|
console.log(chalk.bold('Next Steps:\n'));
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install Panel Hook Command
|
|
3
|
+
*
|
|
4
|
+
* Installs the panel queue reader hook to Claude Code's hooks directory.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from 'fs';
|
|
9
|
+
import { join, dirname } from 'path';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
import { homedir } from 'os';
|
|
12
|
+
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = dirname(__filename);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Install the panel queue reader hook
|
|
18
|
+
*/
|
|
19
|
+
export async function runInstallPanelHook(options = {}) {
|
|
20
|
+
console.log(chalk.cyan('\n Installing CCASP Panel Hook...\n'));
|
|
21
|
+
|
|
22
|
+
// Determine target directory
|
|
23
|
+
const targetDir = options.global
|
|
24
|
+
? join(homedir(), '.claude', 'hooks')
|
|
25
|
+
: join(process.cwd(), '.claude', 'hooks');
|
|
26
|
+
|
|
27
|
+
const hookPath = join(targetDir, 'panel-queue-reader.js');
|
|
28
|
+
const settingsPath = options.global
|
|
29
|
+
? join(homedir(), '.claude', 'settings.json')
|
|
30
|
+
: join(process.cwd(), '.claude', 'settings.json');
|
|
31
|
+
|
|
32
|
+
// Check if hook already exists
|
|
33
|
+
if (existsSync(hookPath) && !options.force) {
|
|
34
|
+
console.log(chalk.yellow(' Hook already installed.'));
|
|
35
|
+
console.log(chalk.dim(` Use --force to overwrite\n`));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Ensure hooks directory exists
|
|
40
|
+
if (!existsSync(targetDir)) {
|
|
41
|
+
mkdirSync(targetDir, { recursive: true });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Read template
|
|
45
|
+
const templatePath = join(__dirname, '..', '..', 'templates', 'hooks', 'panel-queue-reader.template.js');
|
|
46
|
+
|
|
47
|
+
if (!existsSync(templatePath)) {
|
|
48
|
+
console.log(chalk.red(' Template not found.'));
|
|
49
|
+
console.log(chalk.dim(` Expected: ${templatePath}\n`));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Copy template to hooks directory
|
|
54
|
+
const templateContent = readFileSync(templatePath, 'utf8');
|
|
55
|
+
writeFileSync(hookPath, templateContent, 'utf8');
|
|
56
|
+
|
|
57
|
+
console.log(chalk.green(` ✓ Hook installed: ${hookPath}`));
|
|
58
|
+
|
|
59
|
+
// Update settings.json to register the hook
|
|
60
|
+
let settings = {};
|
|
61
|
+
if (existsSync(settingsPath)) {
|
|
62
|
+
try {
|
|
63
|
+
settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
64
|
+
} catch {
|
|
65
|
+
settings = {};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Ensure hooks array exists
|
|
70
|
+
if (!settings.hooks) {
|
|
71
|
+
settings.hooks = [];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Check if hook already registered
|
|
75
|
+
const hookConfig = {
|
|
76
|
+
event: 'UserPromptSubmit',
|
|
77
|
+
command: `node ${hookPath}`
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const existingHook = settings.hooks.find(h =>
|
|
81
|
+
h.event === 'UserPromptSubmit' &&
|
|
82
|
+
h.command?.includes('panel-queue-reader')
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
if (!existingHook) {
|
|
86
|
+
settings.hooks.push(hookConfig);
|
|
87
|
+
|
|
88
|
+
// Ensure settings directory exists
|
|
89
|
+
const settingsDir = dirname(settingsPath);
|
|
90
|
+
if (!existsSync(settingsDir)) {
|
|
91
|
+
mkdirSync(settingsDir, { recursive: true });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
|
95
|
+
console.log(chalk.green(` ✓ Hook registered in settings.json`));
|
|
96
|
+
} else {
|
|
97
|
+
console.log(chalk.dim(' Hook already registered in settings.json'));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.log('');
|
|
101
|
+
console.log(chalk.white.bold(' Setup complete!'));
|
|
102
|
+
console.log('');
|
|
103
|
+
console.log(chalk.dim(' How to use:'));
|
|
104
|
+
console.log(chalk.dim(' 1. Open a new terminal and run: ccasp panel'));
|
|
105
|
+
console.log(chalk.dim(' 2. Select commands from the panel'));
|
|
106
|
+
console.log(chalk.dim(' 3. In Claude Code, press Enter to execute'));
|
|
107
|
+
console.log('');
|
|
108
|
+
}
|