@paths.design/caws-cli 8.0.1 → 8.2.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.
Files changed (112) hide show
  1. package/README.md +5 -6
  2. package/dist/commands/archive.d.ts +1 -0
  3. package/dist/commands/archive.d.ts.map +1 -1
  4. package/dist/commands/archive.js +114 -6
  5. package/dist/commands/burnup.d.ts.map +1 -1
  6. package/dist/commands/burnup.js +109 -10
  7. package/dist/commands/diagnose.js +1 -1
  8. package/dist/commands/init.d.ts.map +1 -1
  9. package/dist/commands/init.js +185 -39
  10. package/dist/commands/mode.d.ts +2 -1
  11. package/dist/commands/mode.d.ts.map +1 -1
  12. package/dist/commands/mode.js +24 -14
  13. package/dist/commands/provenance.d.ts.map +1 -1
  14. package/dist/commands/provenance.js +216 -93
  15. package/dist/commands/quality-gates.d.ts.map +1 -1
  16. package/dist/commands/quality-gates.js +3 -1
  17. package/dist/commands/specs.d.ts.map +1 -1
  18. package/dist/commands/specs.js +184 -6
  19. package/dist/commands/status.d.ts.map +1 -1
  20. package/dist/commands/status.js +134 -10
  21. package/dist/commands/templates.js +2 -2
  22. package/dist/commands/worktree.d.ts +7 -0
  23. package/dist/commands/worktree.d.ts.map +1 -0
  24. package/dist/commands/worktree.js +136 -0
  25. package/dist/config/lite-scope.d.ts +33 -0
  26. package/dist/config/lite-scope.d.ts.map +1 -0
  27. package/dist/config/lite-scope.js +158 -0
  28. package/dist/config/modes.d.ts +90 -51
  29. package/dist/config/modes.d.ts.map +1 -1
  30. package/dist/config/modes.js +26 -0
  31. package/dist/error-handler.d.ts +3 -16
  32. package/dist/error-handler.d.ts.map +1 -1
  33. package/dist/error-handler.js +6 -98
  34. package/dist/generators/jest-config-generator.d.ts +32 -0
  35. package/dist/generators/jest-config-generator.d.ts.map +1 -0
  36. package/dist/generators/jest-config-generator.js +242 -0
  37. package/dist/index.js +40 -7
  38. package/dist/minimal-cli.js +3 -1
  39. package/dist/scaffold/claude-hooks.d.ts +28 -0
  40. package/dist/scaffold/claude-hooks.d.ts.map +1 -0
  41. package/dist/scaffold/claude-hooks.js +344 -0
  42. package/dist/scaffold/index.d.ts +2 -0
  43. package/dist/scaffold/index.d.ts.map +1 -1
  44. package/dist/scaffold/index.js +96 -76
  45. package/dist/templates/.caws/schemas/scope.schema.json +52 -0
  46. package/dist/templates/.caws/schemas/working-spec.schema.json +1 -1
  47. package/dist/templates/.caws/schemas/worktrees.schema.json +36 -0
  48. package/dist/templates/.claude/README.md +190 -0
  49. package/dist/templates/.claude/hooks/audit.sh +96 -0
  50. package/dist/templates/.claude/hooks/block-dangerous.sh +123 -0
  51. package/dist/templates/.claude/hooks/lite-sprawl-check.sh +117 -0
  52. package/dist/templates/.claude/hooks/naming-check.sh +97 -0
  53. package/dist/templates/.claude/hooks/quality-check.sh +68 -0
  54. package/dist/templates/.claude/hooks/scan-secrets.sh +85 -0
  55. package/dist/templates/.claude/hooks/scope-guard.sh +192 -0
  56. package/dist/templates/.claude/hooks/simplification-guard.sh +92 -0
  57. package/dist/templates/.claude/hooks/validate-spec.sh +76 -0
  58. package/dist/templates/.claude/settings.json +95 -0
  59. package/dist/templates/.cursor/README.md +0 -3
  60. package/dist/templates/.github/copilot-instructions.md +82 -0
  61. package/dist/templates/.junie/guidelines.md +73 -0
  62. package/dist/templates/.vscode/launch.json +0 -27
  63. package/dist/templates/.windsurf/rules/caws-quality-standards.md +54 -0
  64. package/dist/templates/CLAUDE.md +101 -0
  65. package/dist/templates/agents.md +73 -1016
  66. package/dist/templates/docs/README.md +5 -5
  67. package/dist/test-analysis.d.ts +50 -1
  68. package/dist/test-analysis.d.ts.map +1 -1
  69. package/dist/test-analysis.js +203 -10
  70. package/dist/utils/error-categories.d.ts +52 -0
  71. package/dist/utils/error-categories.d.ts.map +1 -0
  72. package/dist/utils/error-categories.js +210 -0
  73. package/dist/utils/gitignore-updater.d.ts +1 -1
  74. package/dist/utils/gitignore-updater.d.ts.map +1 -1
  75. package/dist/utils/gitignore-updater.js +4 -0
  76. package/dist/utils/ide-detection.js +133 -0
  77. package/dist/utils/quality-gates-utils.d.ts +49 -0
  78. package/dist/utils/quality-gates-utils.d.ts.map +1 -0
  79. package/dist/utils/quality-gates-utils.js +402 -0
  80. package/dist/utils/typescript-detector.d.ts +8 -5
  81. package/dist/utils/typescript-detector.d.ts.map +1 -1
  82. package/dist/utils/typescript-detector.js +36 -90
  83. package/dist/validation/spec-validation.d.ts.map +1 -1
  84. package/dist/validation/spec-validation.js +59 -6
  85. package/dist/worktree/worktree-manager.d.ts +54 -0
  86. package/dist/worktree/worktree-manager.d.ts.map +1 -0
  87. package/dist/worktree/worktree-manager.js +378 -0
  88. package/package.json +9 -3
  89. package/templates/.caws/schemas/scope.schema.json +52 -0
  90. package/templates/.caws/schemas/working-spec.schema.json +1 -1
  91. package/templates/.caws/schemas/worktrees.schema.json +36 -0
  92. package/templates/.claude/README.md +190 -0
  93. package/templates/.claude/hooks/audit.sh +96 -0
  94. package/templates/.claude/hooks/block-dangerous.sh +123 -0
  95. package/templates/.claude/hooks/lite-sprawl-check.sh +117 -0
  96. package/templates/.claude/hooks/naming-check.sh +97 -0
  97. package/templates/.claude/hooks/quality-check.sh +68 -0
  98. package/templates/.claude/hooks/scan-secrets.sh +85 -0
  99. package/templates/.claude/hooks/scope-guard.sh +192 -0
  100. package/templates/.claude/hooks/simplification-guard.sh +92 -0
  101. package/templates/.claude/hooks/validate-spec.sh +76 -0
  102. package/templates/.claude/settings.json +95 -0
  103. package/templates/.cursor/README.md +0 -3
  104. package/templates/.github/copilot-instructions.md +82 -0
  105. package/templates/.junie/guidelines.md +73 -0
  106. package/templates/.vscode/launch.json +0 -27
  107. package/templates/.windsurf/rules/caws-quality-standards.md +54 -0
  108. package/templates/AGENTS.md +104 -0
  109. package/templates/CLAUDE.md +101 -0
  110. package/templates/docs/README.md +5 -5
  111. package/templates/.github/copilot/instructions.md +0 -311
  112. package/templates/agents.md +0 -1047
@@ -0,0 +1,344 @@
1
+ /**
2
+ * @fileoverview Claude Code Hooks Scaffolding
3
+ * Functions for setting up Claude Code hooks for CAWS projects
4
+ * @author @darianrosebrook
5
+ */
6
+
7
+ const fs = require('fs-extra');
8
+ const path = require('path');
9
+ const chalk = require('chalk');
10
+
11
+ // Import detection utilities
12
+ const { detectCAWSSetup, findPackageRoot } = require('../utils/detection');
13
+
14
+ /**
15
+ * Scaffold Claude Code hooks for a CAWS project
16
+ * Creates .claude/settings.json with hooks and .claude/hooks/ directory with scripts
17
+ *
18
+ * @param {string} projectDir - Project directory path
19
+ * @param {string[]} levels - Hook levels to enable: 'safety', 'quality', 'scope', 'audit'
20
+ */
21
+ async function scaffoldClaudeHooks(projectDir, levels = ['safety', 'quality', 'scope', 'audit']) {
22
+ try {
23
+ const claudeDir = path.join(projectDir, '.claude');
24
+ const claudeHooksDir = path.join(claudeDir, 'hooks');
25
+
26
+ // Create .claude directory structure
27
+ await fs.ensureDir(claudeDir);
28
+ await fs.ensureDir(claudeHooksDir);
29
+
30
+ // Determine template directory - prefer bundled templates
31
+ const setup = detectCAWSSetup(projectDir);
32
+
33
+ // Find package root using shared utility
34
+ const packageRoot = findPackageRoot(__dirname);
35
+
36
+ // Try templates relative to package root first (works in both dev and global install)
37
+ const bundledTemplateDir = path.join(packageRoot, 'templates');
38
+ const fallbackTemplateDir = path.join(__dirname, '../../templates');
39
+ const templateDir = fs.existsSync(bundledTemplateDir)
40
+ ? bundledTemplateDir
41
+ : fs.existsSync(fallbackTemplateDir)
42
+ ? fallbackTemplateDir
43
+ : setup.templateDir || path.resolve(__dirname, '../templates');
44
+
45
+ const claudeTemplateDir = path.join(templateDir, '.claude');
46
+ const claudeHooksTemplateDir = path.join(claudeTemplateDir, 'hooks');
47
+
48
+ if (!fs.existsSync(claudeTemplateDir)) {
49
+ console.warn(chalk.yellow('⚠️ Claude Code hooks templates not found'));
50
+ console.warn(chalk.blue('💡 Skipping Claude Code hooks setup'));
51
+ return;
52
+ }
53
+
54
+ // Map levels to hook scripts
55
+ const hookMapping = {
56
+ safety: ['block-dangerous.sh', 'scan-secrets.sh'],
57
+ quality: ['quality-check.sh', 'validate-spec.sh'],
58
+ scope: ['scope-guard.sh', 'naming-check.sh'],
59
+ audit: ['audit.sh'],
60
+ lite: ['block-dangerous.sh', 'scope-guard.sh', 'lite-sprawl-check.sh', 'simplification-guard.sh'],
61
+ };
62
+
63
+ // Determine which hooks to enable
64
+ const enabledHooks = new Set();
65
+ levels.forEach((level) => {
66
+ const hooks = hookMapping[level] || [];
67
+ hooks.forEach((hook) => enabledHooks.add(hook));
68
+ });
69
+
70
+ // Always enable audit.sh if any hooks are enabled
71
+ if (enabledHooks.size > 0) {
72
+ enabledHooks.add('audit.sh');
73
+ }
74
+
75
+ // Copy enabled hook scripts
76
+ const allHookScripts = [
77
+ 'audit.sh',
78
+ 'validate-spec.sh',
79
+ 'quality-check.sh',
80
+ 'scan-secrets.sh',
81
+ 'block-dangerous.sh',
82
+ 'scope-guard.sh',
83
+ 'naming-check.sh',
84
+ 'lite-sprawl-check.sh',
85
+ 'simplification-guard.sh',
86
+ ];
87
+
88
+ for (const script of allHookScripts) {
89
+ if (enabledHooks.has(script)) {
90
+ const sourcePath = path.join(claudeHooksTemplateDir, script);
91
+ const destPath = path.join(claudeHooksDir, script);
92
+
93
+ if (fs.existsSync(sourcePath)) {
94
+ await fs.copy(sourcePath, destPath);
95
+ // Make executable
96
+ await fs.chmod(destPath, 0o755);
97
+ }
98
+ }
99
+ }
100
+
101
+ // Generate settings.json with hooks configuration
102
+ const settings = generateClaudeSettings(levels, enabledHooks);
103
+
104
+ // Check for existing settings and merge
105
+ const settingsPath = path.join(claudeDir, 'settings.json');
106
+ if (fs.existsSync(settingsPath)) {
107
+ try {
108
+ const existingSettings = await fs.readJSON(settingsPath);
109
+ // Merge hooks, preserving existing non-hook settings
110
+ settings.hooks = {
111
+ ...existingSettings.hooks,
112
+ ...settings.hooks,
113
+ };
114
+ // Preserve other settings
115
+ Object.keys(existingSettings).forEach((key) => {
116
+ if (key !== 'hooks' && !(key in settings)) {
117
+ settings[key] = existingSettings[key];
118
+ }
119
+ });
120
+ } catch (error) {
121
+ console.warn(chalk.yellow('⚠️ Could not merge existing settings:'), error.message);
122
+ }
123
+ }
124
+
125
+ // Write settings.json
126
+ await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2));
127
+
128
+ // Copy README if it exists
129
+ const readmePath = path.join(claudeTemplateDir, 'README.md');
130
+ if (fs.existsSync(readmePath)) {
131
+ await fs.copy(readmePath, path.join(claudeDir, 'README.md'));
132
+ }
133
+
134
+ console.log(chalk.green('✅ Claude Code hooks configured'));
135
+ console.log(chalk.gray(` Enabled: ${levels.join(', ')}`));
136
+ console.log(
137
+ chalk.gray(` Scripts: ${Array.from(enabledHooks).length} hook scripts installed`)
138
+ );
139
+ console.log(chalk.blue('💡 Hooks will activate on next Claude Code session'));
140
+ } catch (error) {
141
+ console.error(chalk.yellow('⚠️ Failed to setup Claude Code hooks:'), error.message);
142
+ console.log(chalk.blue('💡 You can manually copy .claude/ directory later'));
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Generate Claude Code settings with hooks configuration
148
+ * @param {string[]} levels - Enabled hook levels
149
+ * @param {Set<string>} enabledHooks - Set of enabled hook script names
150
+ * @returns {Object} Settings object for settings.json
151
+ */
152
+ function generateClaudeSettings(levels, _enabledHooks) {
153
+ const settings = {
154
+ hooks: {},
155
+ };
156
+
157
+ // Build hooks configuration based on enabled levels
158
+ // Claude Code uses different event names and matcher patterns
159
+
160
+ if (levels.includes('safety')) {
161
+ // Block dangerous bash commands
162
+ settings.hooks.PreToolUse = settings.hooks.PreToolUse || [];
163
+ settings.hooks.PreToolUse.push({
164
+ matcher: 'Bash',
165
+ hooks: [
166
+ {
167
+ type: 'command',
168
+ command: '"$CLAUDE_PROJECT_DIR"/.claude/hooks/block-dangerous.sh',
169
+ timeout: 10,
170
+ },
171
+ ],
172
+ });
173
+
174
+ // Scan for secrets on file read
175
+ settings.hooks.PreToolUse.push({
176
+ matcher: 'Read',
177
+ hooks: [
178
+ {
179
+ type: 'command',
180
+ command: '"$CLAUDE_PROJECT_DIR"/.claude/hooks/scan-secrets.sh',
181
+ timeout: 10,
182
+ },
183
+ ],
184
+ });
185
+ }
186
+
187
+ if (levels.includes('quality')) {
188
+ // Run quality checks after file edits
189
+ settings.hooks.PostToolUse = settings.hooks.PostToolUse || [];
190
+ settings.hooks.PostToolUse.push({
191
+ matcher: 'Write|Edit',
192
+ hooks: [
193
+ {
194
+ type: 'command',
195
+ command: '"$CLAUDE_PROJECT_DIR"/.claude/hooks/quality-check.sh',
196
+ timeout: 30,
197
+ },
198
+ {
199
+ type: 'command',
200
+ command: '"$CLAUDE_PROJECT_DIR"/.claude/hooks/validate-spec.sh',
201
+ timeout: 15,
202
+ },
203
+ ],
204
+ });
205
+ }
206
+
207
+ if (levels.includes('scope')) {
208
+ // Scope guard before file writes
209
+ settings.hooks.PreToolUse = settings.hooks.PreToolUse || [];
210
+ settings.hooks.PreToolUse.push({
211
+ matcher: 'Write|Edit',
212
+ hooks: [
213
+ {
214
+ type: 'command',
215
+ command: '"$CLAUDE_PROJECT_DIR"/.claude/hooks/scope-guard.sh',
216
+ timeout: 10,
217
+ },
218
+ ],
219
+ });
220
+
221
+ // Naming check after edits
222
+ settings.hooks.PostToolUse = settings.hooks.PostToolUse || [];
223
+ settings.hooks.PostToolUse.push({
224
+ matcher: 'Write|Edit',
225
+ hooks: [
226
+ {
227
+ type: 'command',
228
+ command: '"$CLAUDE_PROJECT_DIR"/.claude/hooks/naming-check.sh',
229
+ timeout: 10,
230
+ },
231
+ ],
232
+ });
233
+ }
234
+
235
+ if (levels.includes('lite')) {
236
+ // Lite mode: sprawl check on Write, simplification guard on Edit
237
+ settings.hooks.PreToolUse = settings.hooks.PreToolUse || [];
238
+ settings.hooks.PreToolUse.push({
239
+ matcher: 'Write',
240
+ hooks: [
241
+ {
242
+ type: 'command',
243
+ command: '"$CLAUDE_PROJECT_DIR"/.claude/hooks/lite-sprawl-check.sh',
244
+ timeout: 10,
245
+ },
246
+ ],
247
+ });
248
+ settings.hooks.PreToolUse.push({
249
+ matcher: 'Edit',
250
+ hooks: [
251
+ {
252
+ type: 'command',
253
+ command: '"$CLAUDE_PROJECT_DIR"/.claude/hooks/simplification-guard.sh',
254
+ timeout: 10,
255
+ },
256
+ ],
257
+ });
258
+ }
259
+
260
+ if (levels.includes('audit')) {
261
+ // Session audit logging
262
+ settings.hooks.SessionStart = settings.hooks.SessionStart || [];
263
+ settings.hooks.SessionStart.push({
264
+ hooks: [
265
+ {
266
+ type: 'command',
267
+ command: '"$CLAUDE_PROJECT_DIR"/.claude/hooks/audit.sh session-start',
268
+ timeout: 5,
269
+ },
270
+ ],
271
+ });
272
+
273
+ settings.hooks.Stop = settings.hooks.Stop || [];
274
+ settings.hooks.Stop.push({
275
+ hooks: [
276
+ {
277
+ type: 'command',
278
+ command: '"$CLAUDE_PROJECT_DIR"/.claude/hooks/audit.sh stop',
279
+ timeout: 5,
280
+ },
281
+ ],
282
+ });
283
+
284
+ // Audit tool usage
285
+ settings.hooks.PostToolUse = settings.hooks.PostToolUse || [];
286
+ settings.hooks.PostToolUse.push({
287
+ matcher: 'Write|Edit|Bash',
288
+ hooks: [
289
+ {
290
+ type: 'command',
291
+ command: '"$CLAUDE_PROJECT_DIR"/.claude/hooks/audit.sh tool-use',
292
+ timeout: 5,
293
+ },
294
+ ],
295
+ });
296
+ }
297
+
298
+ return settings;
299
+ }
300
+
301
+ /**
302
+ * Check if Claude Code hooks are already configured
303
+ * @param {string} projectDir - Project directory
304
+ * @returns {boolean} True if hooks are configured
305
+ */
306
+ function hasClaudeHooks(projectDir) {
307
+ const settingsPath = path.join(projectDir, '.claude', 'settings.json');
308
+ if (!fs.existsSync(settingsPath)) {
309
+ return false;
310
+ }
311
+
312
+ try {
313
+ const settings = fs.readJSONSync(settingsPath);
314
+ return settings.hooks && Object.keys(settings.hooks).length > 0;
315
+ } catch {
316
+ return false;
317
+ }
318
+ }
319
+
320
+ /**
321
+ * List configured Claude Code hooks
322
+ * @param {string} projectDir - Project directory
323
+ * @returns {Object} Hook configuration or null
324
+ */
325
+ function getClaudeHooksConfig(projectDir) {
326
+ const settingsPath = path.join(projectDir, '.claude', 'settings.json');
327
+ if (!fs.existsSync(settingsPath)) {
328
+ return null;
329
+ }
330
+
331
+ try {
332
+ const settings = fs.readJSONSync(settingsPath);
333
+ return settings.hooks || null;
334
+ } catch {
335
+ return null;
336
+ }
337
+ }
338
+
339
+ module.exports = {
340
+ scaffoldClaudeHooks,
341
+ generateClaudeSettings,
342
+ hasClaudeHooks,
343
+ getClaudeHooksConfig,
344
+ };
@@ -7,9 +7,11 @@ export function scaffoldIDEIntegrations(targetDir: any, options: any): Promise<{
7
7
  added: number;
8
8
  skipped: number;
9
9
  }>;
10
+ import { scaffoldClaudeHooks } from "./claude-hooks";
10
11
  /**
11
12
  * Set dependencies for scaffold module
12
13
  * @param {Object} deps - Dependencies object
13
14
  */
14
15
  export function setScaffoldDependencies(deps: any): void;
16
+ export { scaffoldClaudeHooks };
15
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scaffold/index.js"],"names":[],"mappings":"AA6LA;;;GAGG;AACH,6DA6jBC;AA3sBD;;;GA2HC;AAMD;;;GAGG;AACH,yDAGC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scaffold/index.js"],"names":[],"mappings":"AA8MA;;;GAGG;AACH,6DA6jBC;AAztBD;;;GAyIC;;AAMD;;;GAGG;AACH,yDAGC"}
@@ -16,6 +16,12 @@ const { detectsPublishing } = require('../utils/project-analysis');
16
16
  const { scaffoldGitHooks } = require('./git-hooks');
17
17
  const { updateGitignore } = require('../utils/gitignore-updater');
18
18
 
19
+ // Import Claude Code hooks scaffolding
20
+ const { scaffoldClaudeHooks } = require('./claude-hooks');
21
+
22
+ // Import IDE detection utilities
23
+ const { IDE_REGISTRY, parseIDESelection, getRecommendedIDEs } = require('../utils/ide-detection');
24
+
19
25
  // CLI version from package.json
20
26
  const CLI_VERSION = require('../../package.json').version;
21
27
 
@@ -52,12 +58,20 @@ function findTemplateDir() {
52
58
  async function scaffoldIDEIntegrations(targetDir, options) {
53
59
  const templateDir = findTemplateDir() || path.join(__dirname, '../../templates');
54
60
 
55
- console.log(chalk.cyan('🎨 Setting up IDE integrations...'));
61
+ // Determine which IDEs to install
62
+ const selectedIDEs = options.ides || [];
63
+ if (selectedIDEs.length === 0) {
64
+ console.log(chalk.gray('Skipping IDE setup (none selected)'));
65
+ return { added: 0, skipped: 0 };
66
+ }
67
+
68
+ const ideNames = selectedIDEs.map((id) => IDE_REGISTRY[id]?.name || id).join(', ');
69
+ console.log(chalk.cyan(`Setting up IDE integrations: ${ideNames}`));
56
70
 
57
71
  let addedCount = 0;
58
72
  let skippedCount = 0;
59
73
 
60
- // Setup git hooks with provenance integration
74
+ // Setup git hooks with provenance integration (always -- not IDE-specific)
61
75
  try {
62
76
  const gitHooksResult = await scaffoldGitHooks(targetDir, {
63
77
  provenance: true,
@@ -69,106 +83,107 @@ async function scaffoldIDEIntegrations(targetDir, options) {
69
83
  addedCount += gitHooksResult.added;
70
84
  skippedCount += gitHooksResult.skipped;
71
85
  } catch (error) {
72
- console.log(chalk.yellow(`⚠️ Git hooks setup failed: ${error.message}`));
86
+ console.log(chalk.yellow(`Warning: Git hooks setup failed: ${error.message}`));
73
87
  }
74
88
 
75
- // List of IDE integration templates to copy
76
- const ideTemplates = [
77
- // VS Code
78
- {
79
- src: '.vscode/settings.json',
80
- dest: '.vscode/settings.json',
81
- desc: 'VS Code workspace settings',
82
- },
83
- {
84
- src: '.vscode/launch.json',
85
- dest: '.vscode/launch.json',
86
- desc: 'VS Code debug configurations',
87
- },
88
-
89
- // IntelliJ IDEA
90
- {
91
- src: '.idea/runConfigurations/CAWS_Validate.xml',
92
- dest: '.idea/runConfigurations/CAWS_Validate.xml',
93
- desc: 'IntelliJ run configuration for CAWS validate',
94
- },
95
- {
96
- src: '.idea/runConfigurations/CAWS_Evaluate.xml',
97
- dest: '.idea/runConfigurations/CAWS_Evaluate.xml',
98
- desc: 'IntelliJ run configuration for CAWS evaluate',
99
- },
100
-
101
- // Windsurf
102
- {
103
- src: '.windsurf/workflows/caws-guided-development.md',
104
- dest: '.windsurf/workflows/caws-guided-development.md',
105
- desc: 'Windsurf workflow for CAWS-guided development',
106
- },
107
-
108
- // GitHub Copilot
109
- {
110
- src: '.github/copilot/instructions.md',
111
- dest: '.github/copilot/instructions.md',
112
- desc: 'GitHub Copilot CAWS integration instructions',
113
- },
114
-
115
- // Git hooks are handled separately by scaffoldGitHooks
116
-
117
- // Cursor hooks (already handled by scaffoldCursorHooks, but ensure README is copied)
118
- {
119
- src: '.cursor/README.md',
120
- dest: '.cursor/README.md',
121
- desc: 'Cursor integration documentation',
122
- },
123
- ];
89
+ // Build IDE templates list dynamically based on selection
90
+ const ideTemplates = [];
91
+
92
+ if (selectedIDEs.includes('vscode')) {
93
+ ideTemplates.push(
94
+ { src: '.vscode/settings.json', dest: '.vscode/settings.json', desc: 'VS Code workspace settings' },
95
+ { src: '.vscode/launch.json', dest: '.vscode/launch.json', desc: 'VS Code debug configurations' }
96
+ );
97
+ }
98
+
99
+ if (selectedIDEs.includes('intellij')) {
100
+ ideTemplates.push(
101
+ { src: '.idea/runConfigurations/CAWS_Validate.xml', dest: '.idea/runConfigurations/CAWS_Validate.xml', desc: 'IntelliJ run configuration for CAWS validate' },
102
+ { src: '.idea/runConfigurations/CAWS_Evaluate.xml', dest: '.idea/runConfigurations/CAWS_Evaluate.xml', desc: 'IntelliJ run configuration for CAWS evaluate' }
103
+ );
104
+ }
105
+
106
+ if (selectedIDEs.includes('junie')) {
107
+ ideTemplates.push(
108
+ { src: '.junie/guidelines.md', dest: '.junie/guidelines.md', desc: 'JetBrains Junie AI agent guidelines' }
109
+ );
110
+ }
111
+
112
+ if (selectedIDEs.includes('windsurf')) {
113
+ ideTemplates.push(
114
+ { src: '.windsurf/workflows/caws-guided-development.md', dest: '.windsurf/workflows/caws-guided-development.md', desc: 'Windsurf workflow for CAWS-guided development' },
115
+ { src: '.windsurf/rules/caws-quality-standards.md', dest: '.windsurf/rules/caws-quality-standards.md', desc: 'Windsurf CAWS quality rules' }
116
+ );
117
+ }
118
+
119
+ if (selectedIDEs.includes('copilot')) {
120
+ ideTemplates.push(
121
+ { src: '.github/copilot-instructions.md', dest: '.github/copilot-instructions.md', desc: 'GitHub Copilot CAWS integration instructions' }
122
+ );
123
+ }
124
+
125
+ if (selectedIDEs.includes('cursor')) {
126
+ ideTemplates.push(
127
+ { src: '.cursor/README.md', dest: '.cursor/README.md', desc: 'Cursor integration documentation' }
128
+ );
129
+ }
130
+
131
+ if (selectedIDEs.includes('claude')) {
132
+ ideTemplates.push(
133
+ { src: '.claude/README.md', dest: '.claude/README.md', desc: 'Claude Code integration documentation' },
134
+ { src: 'CLAUDE.md', dest: 'CLAUDE.md', desc: 'Claude Code project instructions' }
135
+ );
136
+
137
+ // Setup Claude Code hooks
138
+ try {
139
+ await scaffoldClaudeHooks(targetDir, ['safety', 'quality', 'scope', 'audit']);
140
+ } catch (error) {
141
+ console.log(chalk.yellow(`Warning: Claude Code hooks setup failed: ${error.message}`));
142
+ }
143
+ }
124
144
 
125
145
  for (const template of ideTemplates) {
126
146
  const srcPath = path.join(templateDir, template.src);
127
147
  const destPath = path.join(targetDir, template.dest);
128
148
 
129
149
  try {
130
- // Check if source exists
131
150
  if (!(await fs.pathExists(srcPath))) {
132
151
  if (!template.optional) {
133
- console.log(chalk.yellow(`⚠️ Template not found: ${template.src}`));
152
+ console.log(chalk.yellow(`Warning: Template not found: ${template.src}`));
134
153
  }
135
154
  continue;
136
155
  }
137
156
 
138
- // Check if destination already exists
139
157
  const destExists = await fs.pathExists(destPath);
140
158
 
141
159
  if (destExists && !options.force) {
142
- console.log(chalk.gray(`⏭️ Skipped ${template.desc} (already exists)`));
160
+ console.log(chalk.gray(`Skipped ${template.desc} (already exists)`));
143
161
  skippedCount++;
144
162
  continue;
145
163
  }
146
164
 
147
- // Ensure destination directory exists
148
165
  await fs.ensureDir(path.dirname(destPath));
149
-
150
- // Copy the file
151
166
  await fs.copy(srcPath, destPath);
152
167
 
153
- // Make scripts executable if they're in hooks or cursor directories
154
- if (destPath.includes('.git/hooks/') || destPath.includes('.cursor/hooks/')) {
168
+ if (destPath.includes('.git/hooks/') || destPath.includes('.cursor/hooks/') || destPath.includes('.claude/hooks/')) {
155
169
  try {
156
170
  await fs.chmod(destPath, '755');
157
- } catch (error) {
171
+ } catch (_) {
158
172
  // Ignore chmod errors on some systems
159
173
  }
160
174
  }
161
175
 
162
- console.log(chalk.green(`✅ Added ${template.desc}`));
176
+ console.log(chalk.green(`Added ${template.desc}`));
163
177
  addedCount++;
164
178
  } catch (error) {
165
- console.log(chalk.red(`❌ Failed to add ${template.desc}: ${error.message}`));
179
+ console.log(chalk.red(`Failed to add ${template.desc}: ${error.message}`));
166
180
  }
167
181
  }
168
182
 
169
183
  if (addedCount > 0) {
170
- console.log(chalk.green(`\n🎨 IDE integrations: ${addedCount} added, ${skippedCount} skipped`));
171
- console.log(chalk.blue('💡 Restart your IDE to activate the new integrations'));
184
+ console.log(chalk.green(`\nIDE integrations: ${addedCount} added, ${skippedCount} skipped`));
185
+ console.log(chalk.gray(` Installed: ${ideNames}`));
186
+ console.log(chalk.blue('Restart your IDE to activate the new integrations'));
172
187
  }
173
188
 
174
189
  return { added: addedCount, skipped: skippedCount };
@@ -353,15 +368,19 @@ async function scaffoldProject(options) {
353
368
  });
354
369
  }
355
370
 
356
- // Add IDE integrations for comprehensive development experience
357
- enhancements.push({
358
- name: 'ide-integrations',
359
- description: 'IDE integrations (VS Code, IntelliJ, Windsurf, Git hooks)',
360
- required: false,
361
- customHandler: async (targetDir, options) => {
362
- return await scaffoldIDEIntegrations(targetDir, options);
363
- },
364
- });
371
+ // Add IDE integrations for selected IDEs
372
+ const selectedIDEs = options.ide ? parseIDESelection(options.ide) : getRecommendedIDEs();
373
+ if (selectedIDEs.length > 0) {
374
+ const ideNames = selectedIDEs.map((id) => IDE_REGISTRY[id]?.name || id).join(', ');
375
+ enhancements.push({
376
+ name: 'ide-integrations',
377
+ description: `IDE integrations (${ideNames})`,
378
+ required: false,
379
+ customHandler: async (targetDir, opts) => {
380
+ return await scaffoldIDEIntegrations(targetDir, { ...opts, ides: selectedIDEs });
381
+ },
382
+ });
383
+ }
365
384
 
366
385
  // Add quality gates package and configuration if requested
367
386
  // Note: These are optional - git hooks fall back to CAWS CLI if package isn't installed
@@ -541,7 +560,7 @@ async function scaffoldProject(options) {
541
560
  !fs.existsSync(path.join(currentDir, 'caws.md'))
542
561
  ) {
543
562
  enhancements.push({
544
- name: 'agents.md',
563
+ name: 'AGENTS.md',
545
564
  description: 'CAWS agent workflow guide',
546
565
  required: false,
547
566
  });
@@ -769,5 +788,6 @@ async function scaffoldProject(options) {
769
788
  module.exports = {
770
789
  scaffoldProject,
771
790
  scaffoldIDEIntegrations,
791
+ scaffoldClaudeHooks,
772
792
  setScaffoldDependencies,
773
793
  };
@@ -0,0 +1,52 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "CAWS Lite Scope Configuration",
4
+ "description": "Scope configuration for CAWS lite mode — guardrails without YAML specs",
5
+ "type": "object",
6
+ "required": ["version", "allowedDirectories"],
7
+ "properties": {
8
+ "version": {
9
+ "type": "integer",
10
+ "const": 1,
11
+ "description": "Schema version"
12
+ },
13
+ "allowedDirectories": {
14
+ "type": "array",
15
+ "items": { "type": "string" },
16
+ "minItems": 1,
17
+ "description": "Directories the agent is allowed to modify (e.g., src/, tests/)"
18
+ },
19
+ "bannedPatterns": {
20
+ "type": "object",
21
+ "properties": {
22
+ "files": {
23
+ "type": "array",
24
+ "items": { "type": "string" },
25
+ "description": "Glob patterns for banned file names (e.g., *-enhanced.*, *-final.*)"
26
+ },
27
+ "directories": {
28
+ "type": "array",
29
+ "items": { "type": "string" },
30
+ "description": "Glob patterns for banned directory names (e.g., *venv*, .venv)"
31
+ },
32
+ "docs": {
33
+ "type": "array",
34
+ "items": { "type": "string" },
35
+ "description": "Glob patterns for banned doc file names (e.g., *-summary.md)"
36
+ }
37
+ },
38
+ "additionalProperties": false
39
+ },
40
+ "maxNewFilesPerCommit": {
41
+ "type": "integer",
42
+ "minimum": 1,
43
+ "maximum": 100,
44
+ "description": "Maximum number of new files allowed per commit (prevents file sprawl)"
45
+ },
46
+ "designatedVenvPath": {
47
+ "type": "string",
48
+ "description": "The only allowed virtual environment path (e.g., .venv)"
49
+ }
50
+ },
51
+ "additionalProperties": false
52
+ }
@@ -16,7 +16,7 @@
16
16
  "contracts"
17
17
  ],
18
18
  "properties": {
19
- "id": { "type": "string", "pattern": "^(PROJ|FEAT|FIX|ARCH)-\\d{4}$" },
19
+ "id": { "type": "string", "pattern": "^[A-Z]{2,6}-\\d{3,4}$" },
20
20
  "title": { "type": "string", "minLength": 10, "maxLength": 200 },
21
21
  "risk_tier": { "type": ["integer", "string"], "enum": [1, 2, 3, "1", "2", "3"] },
22
22
  "mode": { "type": "string", "enum": ["feature", "refactor", "fix", "doc", "chore"] },