@paths.design/caws-cli 3.1.1 โ†’ 3.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.
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Scaffold git hooks for CAWS provenance tracking
3
+ * @param {string} projectDir - Project directory path
4
+ * @param {Object} options - Hook options
5
+ */
6
+ export function scaffoldGitHooks(projectDir: string, options?: any): Promise<{
7
+ added: number;
8
+ skipped: number;
9
+ }>;
10
+ /**
11
+ * Remove CAWS git hooks
12
+ * @param {string} projectDir - Project directory path
13
+ */
14
+ export function removeGitHooks(projectDir: string): Promise<void>;
15
+ /**
16
+ * Check git hooks status
17
+ * @param {string} projectDir - Project directory path
18
+ */
19
+ export function checkGitHooksStatus(projectDir: string): Promise<void>;
20
+ //# sourceMappingURL=git-hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-hooks.d.ts","sourceRoot":"","sources":["../../src/scaffold/git-hooks.js"],"names":[],"mappings":"AASA;;;;GAIG;AACH,6CAHW,MAAM;;;GAuGhB;AAgND;;;GAGG;AACH,2CAFW,MAAM,iBAkChB;AAED;;;GAGG;AACH,gDAFW,MAAM,iBAgDhB"}
@@ -0,0 +1,417 @@
1
+ /**
2
+ * @fileoverview Git Hooks Scaffolding for CAWS Provenance
3
+ * Functions for setting up git hooks that automatically update provenance
4
+ * @author @darianrosebrook
5
+ */
6
+
7
+ const fs = require('fs-extra');
8
+ const path = require('path');
9
+
10
+ /**
11
+ * Scaffold git hooks for CAWS provenance tracking
12
+ * @param {string} projectDir - Project directory path
13
+ * @param {Object} options - Hook options
14
+ */
15
+ async function scaffoldGitHooks(projectDir, options = {}) {
16
+ const { provenance = true, validation = true, qualityGates = true, force = false } = options;
17
+
18
+ console.log('๐Ÿ”— Setting up Git hooks for CAWS provenance...');
19
+
20
+ const gitDir = path.join(projectDir, '.git');
21
+ const hooksDir = path.join(gitDir, 'hooks');
22
+
23
+ // Check if this is a git repository
24
+ if (!(await fs.pathExists(gitDir))) {
25
+ console.log('โš ๏ธ Not a git repository - skipping git hooks setup');
26
+ console.log('๐Ÿ’ก Initialize git first: git init');
27
+ return { added: 0, skipped: 0 };
28
+ }
29
+
30
+ // Ensure hooks directory exists
31
+ await fs.ensureDir(hooksDir);
32
+
33
+ let addedCount = 0;
34
+ let skippedCount = 0;
35
+
36
+ // Define hook configurations
37
+ const hooks = [
38
+ {
39
+ name: 'pre-commit',
40
+ description: 'Pre-commit validation and quality checks',
41
+ enabled: validation || qualityGates,
42
+ content: generatePreCommitHook({ validation, qualityGates }),
43
+ },
44
+ {
45
+ name: 'post-commit',
46
+ description: 'Post-commit provenance tracking',
47
+ enabled: provenance,
48
+ content: generatePostCommitHook(),
49
+ },
50
+ {
51
+ name: 'pre-push',
52
+ description: 'Pre-push comprehensive validation',
53
+ enabled: qualityGates,
54
+ content: generatePrePushHook(),
55
+ },
56
+ {
57
+ name: 'commit-msg',
58
+ description: 'Commit message validation',
59
+ enabled: validation,
60
+ content: generateCommitMsgHook(),
61
+ },
62
+ ];
63
+
64
+ for (const hook of hooks) {
65
+ if (!hook.enabled) continue;
66
+
67
+ const hookPath = path.join(hooksDir, hook.name);
68
+
69
+ try {
70
+ // Check if hook already exists
71
+ const exists = await fs.pathExists(hookPath);
72
+
73
+ if (exists && !force) {
74
+ // Check if it's already a CAWS hook
75
+ const content = await fs.readFile(hookPath, 'utf8');
76
+ if (content.includes('# CAWS Hook')) {
77
+ console.log(`โญ๏ธ Skipped ${hook.description} (already configured)`);
78
+ skippedCount++;
79
+ continue;
80
+ } else {
81
+ console.log(`โš ๏ธ ${hook.description} exists but not CAWS-managed`);
82
+ if (!options.backup) {
83
+ console.log(`๐Ÿ’ก Use --force to replace, or --backup to preserve original`);
84
+ skippedCount++;
85
+ continue;
86
+ }
87
+ }
88
+ }
89
+
90
+ // Backup existing hook if requested
91
+ if (exists && options.backup) {
92
+ const backupPath = `${hookPath}.backup.${Date.now()}`;
93
+ await fs.copy(hookPath, backupPath);
94
+ console.log(`๐Ÿ’พ Backed up existing ${hook.name} to ${path.basename(backupPath)}`);
95
+ }
96
+
97
+ // Write the hook
98
+ await fs.writeFile(hookPath, hook.content);
99
+ await fs.chmod(hookPath, 0o755);
100
+
101
+ console.log(`โœ… Configured ${hook.description}`);
102
+ addedCount++;
103
+ } catch (error) {
104
+ console.log(`โŒ Failed to configure ${hook.description}: ${error.message}`);
105
+ }
106
+ }
107
+
108
+ if (addedCount > 0) {
109
+ console.log(`\n๐Ÿ”— Git hooks configured: ${addedCount} hooks active`);
110
+ console.log('๐Ÿ’ก Hooks will run automatically on git operations');
111
+ console.log('๐Ÿ’ก Use --no-verify to skip hooks: git commit --no-verify');
112
+ }
113
+
114
+ return { added: addedCount, skipped: skippedCount };
115
+ }
116
+
117
+ /**
118
+ * Generate pre-commit hook content
119
+ */
120
+ function generatePreCommitHook(options) {
121
+ const { qualityGates = true } = options;
122
+
123
+ return `#!/bin/bash
124
+ # CAWS Pre-commit Hook
125
+ # Runs validation and quality checks before commits
126
+
127
+ set -e
128
+
129
+ echo "๐Ÿ” CAWS Pre-commit Validation"
130
+ echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
131
+
132
+ # Check if CAWS is initialized
133
+ if [ ! -d ".caws" ]; then
134
+ echo "โš ๏ธ CAWS not initialized - skipping validation"
135
+ exit 0
136
+ fi
137
+
138
+ # Run CAWS validation if available
139
+ if command -v caws >/dev/null 2>&1; then
140
+ echo "๐Ÿ“‹ Running CAWS validation..."
141
+ if caws validate --quiet; then
142
+ echo "โœ… CAWS validation passed"
143
+ else
144
+ echo "โŒ CAWS validation failed"
145
+ echo "๐Ÿ’ก Fix issues or use: git commit --no-verify"
146
+ exit 1
147
+ fi
148
+ else
149
+ echo "โš ๏ธ CAWS CLI not found - install with: npm install -g @paths.design/caws-cli"
150
+ fi
151
+
152
+ # Run quality gates if enabled
153
+ ${
154
+ qualityGates
155
+ ? `
156
+ echo "๐ŸŽฏ Running quality gates..."
157
+ if [ -f "package.json" ]; then
158
+ # Run linting if available
159
+ if [ -f "node_modules/.bin/eslint" ] || command -v eslint >/dev/null 2>&1; then
160
+ echo "๐Ÿ” Running ESLint..."
161
+ if npx eslint . --quiet; then
162
+ echo "โœ… ESLint passed"
163
+ else
164
+ echo "โŒ ESLint failed - fix issues or use --no-verify"
165
+ exit 1
166
+ fi
167
+ fi
168
+
169
+ # Run tests if available
170
+ if [ -f "package.json" ] && grep -q '"test"' package.json; then
171
+ echo "๐Ÿงช Running tests..."
172
+ if npm test; then
173
+ echo "โœ… Tests passed"
174
+ else
175
+ echo "โŒ Tests failed - fix issues or use --no-verify"
176
+ exit 1
177
+ fi
178
+ fi
179
+ fi
180
+ `
181
+ : ''
182
+ }
183
+
184
+ echo "๐ŸŽ‰ Pre-commit checks passed!"
185
+ `;
186
+ }
187
+
188
+ /**
189
+ * Generate post-commit hook content
190
+ */
191
+ function generatePostCommitHook() {
192
+ return `#!/bin/bash
193
+ # CAWS Post-commit Hook
194
+ # Updates provenance tracking after successful commits
195
+
196
+ # Run in background to avoid blocking git operations
197
+ (
198
+ # Check if CAWS is initialized
199
+ if [ ! -d ".caws" ]; then
200
+ exit 0
201
+ fi
202
+
203
+ # Get the current commit hash
204
+ COMMIT_HASH=$(git rev-parse HEAD)
205
+
206
+ # Get commit details
207
+ COMMIT_MESSAGE=$(git log -1 --pretty=%B | head -1)
208
+ AUTHOR_NAME=$(git log -1 --pretty=%an)
209
+ AUTHOR_EMAIL=$(git log -1 --pretty=%ae)
210
+
211
+ # Update provenance if CAWS CLI is available
212
+ if command -v caws >/dev/null 2>&1; then
213
+ echo "๐Ÿ“œ Updating CAWS provenance for commit \${COMMIT_HASH:0:8}..."
214
+
215
+ # Run provenance update in background
216
+ (
217
+ caws provenance update \\
218
+ --commit "$COMMIT_HASH" \\
219
+ --message "$COMMIT_MESSAGE" \\
220
+ --author "$AUTHOR_NAME <$AUTHOR_EMAIL>" \\
221
+ --quiet
222
+ ) &
223
+ fi
224
+ ) >/dev/null 2>&1 &
225
+ `;
226
+ }
227
+
228
+ /**
229
+ * Generate pre-push hook content
230
+ */
231
+ function generatePrePushHook() {
232
+ return `#!/bin/bash
233
+ # CAWS Pre-push Hook
234
+ # Runs comprehensive checks before pushing
235
+
236
+ set -e
237
+
238
+ echo "๐Ÿš€ CAWS Pre-push Validation"
239
+ echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”"
240
+
241
+ # Check if CAWS is initialized
242
+ if [ ! -d ".caws" ]; then
243
+ echo "โš ๏ธ CAWS not initialized - skipping validation"
244
+ exit 0
245
+ fi
246
+
247
+ # Run full validation suite
248
+ if command -v caws >/dev/null 2>&1; then
249
+ echo "๐Ÿ“‹ Running comprehensive CAWS validation..."
250
+ if caws validate --quiet; then
251
+ echo "โœ… CAWS validation passed"
252
+ else
253
+ echo "โŒ CAWS validation failed"
254
+ echo "๐Ÿ’ก Fix issues or use: git push --no-verify"
255
+ exit 1
256
+ fi
257
+ fi
258
+
259
+ # Run security checks
260
+ echo "๐Ÿ”’ Running security checks..."
261
+ if [ -f "package.json" ]; then
262
+ # Check for vulnerabilities
263
+ if command -v npm >/dev/null 2>&1; then
264
+ echo "๐Ÿ” Checking for vulnerabilities..."
265
+ if npm audit --audit-level moderate >/dev/null 2>&1; then
266
+ echo "โœ… Security audit passed"
267
+ else
268
+ echo "โš ๏ธ Security vulnerabilities found"
269
+ echo "๐Ÿ’ก Review with: npm audit"
270
+ echo "๐Ÿ’ก Use --no-verify to push anyway"
271
+ # Don't fail on warnings, just warn
272
+ fi
273
+ fi
274
+ fi
275
+
276
+ echo "๐ŸŽ‰ Pre-push checks completed!"
277
+ `;
278
+ }
279
+
280
+ /**
281
+ * Generate commit-msg hook content
282
+ */
283
+ function generateCommitMsgHook() {
284
+ return `#!/bin/bash
285
+ # CAWS Commit Message Hook
286
+ # Validates commit message format
287
+
288
+ COMMIT_MSG_FILE=$1
289
+
290
+ # Read the commit message
291
+ COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
292
+
293
+ # Check if CAWS is initialized
294
+ if [ ! -d ".caws" ]; then
295
+ exit 0
296
+ fi
297
+
298
+ # Basic commit message validation
299
+ if [ \${#COMMIT_MSG} -lt 10 ]; then
300
+ echo "โŒ Commit message too short (minimum 10 characters)"
301
+ echo "๐Ÿ’ก Write descriptive commit messages"
302
+ exit 1
303
+ fi
304
+
305
+ # Check for conventional commit format (optional but encouraged)
306
+ if [[ $COMMIT_MSG =~ ^(feat|fix|docs|style|refactor|test|chore)(.+)? ]]; then
307
+ echo "โœ… Conventional commit format detected"
308
+ else
309
+ echo "๐Ÿ’ก Consider using conventional commit format:"
310
+ echo " feat: add new feature"
311
+ echo " fix: bug fix"
312
+ echo " docs: documentation"
313
+ echo " style: formatting"
314
+ echo " refactor: code restructuring"
315
+ echo " test: testing"
316
+ echo " chore: maintenance"
317
+ fi
318
+
319
+ echo "โœ… Commit message validation passed"
320
+ `;
321
+ }
322
+
323
+ /**
324
+ * Remove CAWS git hooks
325
+ * @param {string} projectDir - Project directory path
326
+ */
327
+ async function removeGitHooks(projectDir) {
328
+ console.log('๐Ÿงน Removing CAWS Git hooks...');
329
+
330
+ const hooksDir = path.join(projectDir, '.git', 'hooks');
331
+ const cawsHooks = ['pre-commit', 'post-commit', 'pre-push', 'commit-msg'];
332
+
333
+ let removedCount = 0;
334
+
335
+ for (const hookName of cawsHooks) {
336
+ const hookPath = path.join(hooksDir, hookName);
337
+
338
+ try {
339
+ if (await fs.pathExists(hookPath)) {
340
+ const content = await fs.readFile(hookPath, 'utf8');
341
+ if (content.includes('# CAWS Hook') || content.includes('# CAWS Pre-commit Hook')) {
342
+ await fs.remove(hookPath);
343
+ console.log(`โœ… Removed ${hookName} hook`);
344
+ removedCount++;
345
+ } else {
346
+ console.log(`โญ๏ธ Skipped ${hookName} (not CAWS-managed)`);
347
+ }
348
+ }
349
+ } catch (error) {
350
+ console.log(`โŒ Failed to remove ${hookName}: ${error.message}`);
351
+ }
352
+ }
353
+
354
+ if (removedCount > 0) {
355
+ console.log(`๐Ÿงน Removed ${removedCount} CAWS git hooks`);
356
+ } else {
357
+ console.log('โ„น๏ธ No CAWS git hooks found');
358
+ }
359
+ }
360
+
361
+ /**
362
+ * Check git hooks status
363
+ * @param {string} projectDir - Project directory path
364
+ */
365
+ async function checkGitHooksStatus(projectDir) {
366
+ const hooksDir = path.join(projectDir, '.git', 'hooks');
367
+ const cawsHooks = ['pre-commit', 'post-commit', 'pre-push', 'commit-msg'];
368
+
369
+ console.log('๐Ÿ” Git Hooks Status:');
370
+ console.log('โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”');
371
+
372
+ let activeCount = 0;
373
+ let totalCount = 0;
374
+
375
+ for (const hookName of cawsHooks) {
376
+ totalCount++;
377
+ const hookPath = path.join(hooksDir, hookName);
378
+
379
+ try {
380
+ if (await fs.pathExists(hookPath)) {
381
+ const content = await fs.readFile(hookPath, 'utf8');
382
+ const isExecutable = (await fs.stat(hookPath)).mode & 0o111;
383
+
384
+ if (content.includes('# CAWS') && isExecutable) {
385
+ console.log(`โœ… ${hookName}: Active`);
386
+ activeCount++;
387
+ } else if (content.includes('# CAWS')) {
388
+ console.log(`โš ๏ธ ${hookName}: Configured but not executable`);
389
+ } else {
390
+ console.log(`โŒ ${hookName}: Not CAWS-managed`);
391
+ }
392
+ } else {
393
+ console.log(`โŒ ${hookName}: Not installed`);
394
+ }
395
+ } catch (error) {
396
+ console.log(`โŒ ${hookName}: Error checking status`);
397
+ }
398
+ }
399
+
400
+ console.log('');
401
+ console.log(`๐Ÿ“Š Status: ${activeCount}/${totalCount} CAWS hooks active`);
402
+
403
+ if (activeCount < totalCount) {
404
+ console.log('');
405
+ console.log('๐Ÿ’ก To install missing hooks:');
406
+ console.log(' caws scaffold');
407
+ console.log('');
408
+ console.log('๐Ÿ’ก To check detailed status:');
409
+ console.log(' ls -la .git/hooks/');
410
+ }
411
+ }
412
+
413
+ module.exports = {
414
+ scaffoldGitHooks,
415
+ removeGitHooks,
416
+ checkGitHooksStatus,
417
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scaffold/index.js"],"names":[],"mappings":"AAkKA;;;GAGG;AACH,6DAyTC;AA/cD;;;;GAIG;AACH,mDAHW,MAAM;;;GAiIhB;AAMD;;;GAGG;AACH,yDAGC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scaffold/index.js"],"names":[],"mappings":"AAkKA;;;GAGG;AACH,6DAyTC;AA5cD;;;;GAIG;AACH,mDAHW,MAAM;;;GA8HhB;AAMD;;;GAGG;AACH,yDAGC"}
@@ -11,6 +11,9 @@ const chalk = require('chalk');
11
11
  // Import detection utilities
12
12
  const { detectCAWSSetup } = require('../utils/detection');
13
13
 
14
+ // Import git hooks scaffolding
15
+ const { scaffoldGitHooks } = require('./git-hooks');
16
+
14
17
  // CLI version from package.json
15
18
  const CLI_VERSION = require('../../package.json').version;
16
19
 
@@ -27,6 +30,21 @@ async function scaffoldIDEIntegrations(targetDir, options) {
27
30
  let addedCount = 0;
28
31
  let skippedCount = 0;
29
32
 
33
+ // Setup git hooks with provenance integration
34
+ try {
35
+ const gitHooksResult = await scaffoldGitHooks(targetDir, {
36
+ provenance: true,
37
+ validation: true,
38
+ qualityGates: true,
39
+ force: options.force,
40
+ backup: options.backup,
41
+ });
42
+ addedCount += gitHooksResult.added;
43
+ skippedCount += gitHooksResult.skipped;
44
+ } catch (error) {
45
+ console.log(chalk.yellow(`โš ๏ธ Git hooks setup failed: ${error.message}`));
46
+ }
47
+
30
48
  // List of IDE integration templates to copy
31
49
  const ideTemplates = [
32
50
  // VS Code
@@ -67,25 +85,7 @@ async function scaffoldIDEIntegrations(targetDir, options) {
67
85
  desc: 'GitHub Copilot CAWS integration instructions',
68
86
  },
69
87
 
70
- // Git hooks (only if not already present)
71
- {
72
- src: '.git/hooks/pre-commit',
73
- dest: '.git/hooks/pre-commit',
74
- desc: 'Git pre-commit hook for CAWS validation',
75
- optional: true,
76
- },
77
- {
78
- src: '.git/hooks/pre-push',
79
- dest: '.git/hooks/pre-push',
80
- desc: 'Git pre-push hook for comprehensive checks',
81
- optional: true,
82
- },
83
- {
84
- src: '.git/hooks/post-commit',
85
- dest: '.git/hooks/post-commit',
86
- desc: 'Git post-commit hook for provenance',
87
- optional: true,
88
- },
88
+ // Git hooks are handled separately by scaffoldGitHooks
89
89
 
90
90
  // Cursor hooks (already handled by scaffoldCursorHooks, but ensure README is copied)
91
91
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paths.design/caws-cli",
3
- "version": "3.1.1",
3
+ "version": "3.2.1",
4
4
  "description": "CAWS CLI - Coding Agent Workflow System command line tools",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
- import { generateWorkingSpec } from "./generators/working-spec";
3
- import { validateGeneratedSpec } from "./generators/working-spec";
4
- export { generateWorkingSpec, validateGeneratedSpec };
5
- //# sourceMappingURL=index-new.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-new.d.ts","sourceRoot":"","sources":["../src/index-new.js"],"names":[],"mappings":""}