@paths.design/caws-cli 3.1.0 → 3.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 (94) hide show
  1. package/README.md +295 -150
  2. package/dist/budget-derivation.d.ts +35 -0
  3. package/dist/budget-derivation.d.ts.map +1 -0
  4. package/dist/budget-derivation.js +204 -0
  5. package/dist/cicd-optimizer.d.ts +142 -0
  6. package/dist/cicd-optimizer.d.ts.map +1 -0
  7. package/dist/cicd-optimizer.js +504 -0
  8. package/dist/commands/burnup.d.ts +6 -0
  9. package/dist/commands/burnup.d.ts.map +1 -0
  10. package/dist/commands/burnup.js +90 -0
  11. package/dist/commands/init.d.ts +5 -0
  12. package/dist/commands/init.d.ts.map +1 -0
  13. package/dist/commands/init.js +514 -0
  14. package/dist/commands/provenance.d.ts +32 -0
  15. package/dist/commands/provenance.d.ts.map +1 -0
  16. package/dist/commands/provenance.js +979 -0
  17. package/dist/commands/tool.d.ts +13 -0
  18. package/dist/commands/tool.d.ts.map +1 -0
  19. package/dist/commands/tool.js +138 -0
  20. package/dist/commands/validate.d.ts +7 -0
  21. package/dist/commands/validate.d.ts.map +1 -0
  22. package/dist/commands/validate.js +80 -0
  23. package/dist/config/index.d.ts +29 -0
  24. package/dist/config/index.d.ts.map +1 -0
  25. package/dist/config/index.js +132 -0
  26. package/dist/error-handler.d.ts +50 -0
  27. package/dist/error-handler.d.ts.map +1 -0
  28. package/dist/error-handler.js +253 -0
  29. package/dist/generators/working-spec.d.ts +13 -0
  30. package/dist/generators/working-spec.d.ts.map +1 -0
  31. package/dist/generators/working-spec.js +204 -0
  32. package/dist/index.d.ts +3 -12
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +193 -2983
  35. package/dist/scaffold/cursor-hooks.d.ts +7 -0
  36. package/dist/scaffold/cursor-hooks.d.ts.map +1 -0
  37. package/dist/scaffold/cursor-hooks.js +152 -0
  38. package/dist/scaffold/git-hooks.d.ts +20 -0
  39. package/dist/scaffold/git-hooks.d.ts.map +1 -0
  40. package/dist/scaffold/git-hooks.js +417 -0
  41. package/dist/scaffold/index.d.ts +20 -0
  42. package/dist/scaffold/index.d.ts.map +1 -0
  43. package/dist/scaffold/index.js +486 -0
  44. package/dist/test-analysis.d.ts +182 -0
  45. package/dist/test-analysis.d.ts.map +1 -0
  46. package/dist/test-analysis.js +580 -0
  47. package/dist/tool-interface.d.ts +236 -0
  48. package/dist/tool-interface.d.ts.map +1 -0
  49. package/dist/tool-interface.js +314 -0
  50. package/dist/tool-loader.d.ts +77 -0
  51. package/dist/tool-loader.d.ts.map +1 -0
  52. package/dist/tool-loader.js +298 -0
  53. package/dist/tool-validator.d.ts +72 -0
  54. package/dist/tool-validator.d.ts.map +1 -0
  55. package/dist/tool-validator.js +387 -0
  56. package/dist/utils/detection.d.ts +7 -0
  57. package/dist/utils/detection.d.ts.map +1 -0
  58. package/dist/utils/detection.js +174 -0
  59. package/dist/utils/finalization.d.ts +17 -0
  60. package/dist/utils/finalization.d.ts.map +1 -0
  61. package/dist/utils/finalization.js +229 -0
  62. package/dist/utils/project-analysis.d.ts +14 -0
  63. package/dist/utils/project-analysis.d.ts.map +1 -0
  64. package/dist/utils/project-analysis.js +105 -0
  65. package/dist/validation/spec-validation.d.ts +29 -0
  66. package/dist/validation/spec-validation.d.ts.map +1 -0
  67. package/dist/validation/spec-validation.js +376 -0
  68. package/dist/waivers-manager.d.ts +167 -0
  69. package/dist/waivers-manager.d.ts.map +1 -0
  70. package/dist/waivers-manager.js +549 -0
  71. package/package.json +10 -12
  72. package/templates/.cursor/README.md +311 -0
  73. package/templates/.cursor/hooks/audit.sh +55 -0
  74. package/templates/.cursor/hooks/block-dangerous.sh +77 -0
  75. package/templates/.cursor/hooks/caws-quality-check.sh +52 -0
  76. package/templates/.cursor/hooks/caws-scope-guard.sh +74 -0
  77. package/templates/.cursor/hooks/caws-tool-validation.sh +121 -0
  78. package/templates/.cursor/hooks/format.sh +38 -0
  79. package/templates/.cursor/hooks/naming-check.sh +64 -0
  80. package/templates/.cursor/hooks/scan-secrets.sh +46 -0
  81. package/templates/.cursor/hooks/scope-guard.sh +52 -0
  82. package/templates/.cursor/hooks/validate-spec.sh +38 -0
  83. package/templates/.cursor/hooks.json +59 -0
  84. package/templates/.github/copilot/instructions.md +311 -0
  85. package/templates/.idea/runConfigurations/CAWS_Evaluate.xml +5 -0
  86. package/templates/.idea/runConfigurations/CAWS_Validate.xml +5 -0
  87. package/templates/.vscode/launch.json +56 -0
  88. package/templates/.vscode/settings.json +93 -0
  89. package/templates/.windsurf/workflows/caws-guided-development.md +92 -0
  90. package/templates/apps/tools/caws/README.md +1 -1
  91. package/templates/apps/tools/caws/schemas/working-spec.schema.json +21 -3
  92. package/templates/codemod/test.js +93 -1
  93. package/templates/apps/tools/caws/prompt-lint.js.backup +0 -274
  94. package/templates/apps/tools/caws/provenance.js.backup +0 -73
@@ -0,0 +1,549 @@
1
+ /**
2
+ * CAWS Waivers Manager
3
+ *
4
+ * Provides fast-lane escape hatches for exceptional circumstances.
5
+ * Waivers are temporary bypasses of quality gates with full audit trails.
6
+ *
7
+ * @author @darianrosebrook
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const yaml = require('js-yaml');
13
+
14
+ /**
15
+ * Waiver Manager Class
16
+ * Handles waiver creation, validation, expiration, and audit logging
17
+ */
18
+ class WaiversManager {
19
+ constructor(options = {}) {
20
+ this.projectRoot = options.projectRoot || process.cwd();
21
+ this.waiversDir = path.join(this.projectRoot, '.caws', 'waivers');
22
+ this.waiversFile = path.join(this.waiversDir, 'active-waivers.yaml');
23
+ this.auditLogFile = path.join(this.waiversDir, 'waiver-audit.log');
24
+
25
+ // Ensure waivers directory exists
26
+ if (!fs.existsSync(this.waiversDir)) {
27
+ fs.mkdirSync(this.waiversDir, { recursive: true });
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Waiver Schema Definition
33
+ */
34
+ getWaiverSchema() {
35
+ return {
36
+ type: 'object',
37
+ required: ['id', 'title', 'reason', 'gates', 'expires_at', 'approved_by', 'created_at'],
38
+ properties: {
39
+ id: {
40
+ type: 'string',
41
+ pattern: '^WV-\\d{4}$',
42
+ description: 'Waiver ID in format WV-XXXX',
43
+ },
44
+ title: {
45
+ type: 'string',
46
+ minLength: 10,
47
+ maxLength: 200,
48
+ description: 'Clear, descriptive title explaining the waiver',
49
+ },
50
+ reason: {
51
+ type: 'string',
52
+ enum: [
53
+ 'emergency_hotfix',
54
+ 'legacy_integration',
55
+ 'experimental_feature',
56
+ 'third_party_constraint',
57
+ 'performance_critical',
58
+ 'security_patch',
59
+ 'infrastructure_limitation',
60
+ 'other',
61
+ ],
62
+ description: 'Categorization of waiver reason',
63
+ },
64
+ description: {
65
+ type: 'string',
66
+ minLength: 50,
67
+ maxLength: 1000,
68
+ description: 'Detailed explanation of why waiver is needed',
69
+ },
70
+ gates: {
71
+ type: 'array',
72
+ items: {
73
+ type: 'string',
74
+ enum: [
75
+ 'spec_completeness',
76
+ 'contract_compliance',
77
+ 'coverage_threshold',
78
+ 'mutation_threshold',
79
+ 'security_scan',
80
+ 'accessibility_check',
81
+ 'performance_budget',
82
+ 'scope_boundary',
83
+ 'budget_limit',
84
+ ],
85
+ },
86
+ minItems: 1,
87
+ description: 'Quality gates to waive',
88
+ },
89
+ risk_assessment: {
90
+ type: 'object',
91
+ properties: {
92
+ impact_level: {
93
+ type: 'string',
94
+ enum: ['low', 'medium', 'high', 'critical'],
95
+ },
96
+ mitigation_plan: {
97
+ type: 'string',
98
+ minLength: 50,
99
+ },
100
+ review_required: {
101
+ type: 'boolean',
102
+ },
103
+ },
104
+ required: ['impact_level', 'mitigation_plan'],
105
+ },
106
+ expires_at: {
107
+ type: 'string',
108
+ format: 'date-time',
109
+ description: 'ISO 8601 datetime when waiver expires',
110
+ },
111
+ approved_by: {
112
+ type: 'string',
113
+ description: 'Person/entity approving the waiver',
114
+ },
115
+ created_at: {
116
+ type: 'string',
117
+ format: 'date-time',
118
+ description: 'ISO 8601 datetime when waiver was created',
119
+ },
120
+ metadata: {
121
+ type: 'object',
122
+ properties: {
123
+ related_pr: { type: 'string' },
124
+ related_issue: { type: 'string' },
125
+ environment: { type: 'string', enum: ['development', 'staging', 'production'] },
126
+ urgency: { type: 'string', enum: ['low', 'normal', 'high', 'critical'] },
127
+ },
128
+ },
129
+ },
130
+ };
131
+ }
132
+
133
+ /**
134
+ * Create a new waiver
135
+ */
136
+ async createWaiver(waiverData) {
137
+ // Generate waiver ID
138
+ const waiverId = await this.generateWaiverId();
139
+
140
+ // Set creation timestamp
141
+ const now = new Date().toISOString();
142
+
143
+ // Construct full waiver object
144
+ const waiver = {
145
+ id: waiverId,
146
+ title: waiverData.title,
147
+ reason: waiverData.reason,
148
+ description: waiverData.description,
149
+ gates: waiverData.gates,
150
+ risk_assessment: waiverData.risk_assessment,
151
+ expires_at: waiverData.expires_at,
152
+ approved_by: waiverData.approved_by,
153
+ created_at: now,
154
+ metadata: waiverData.metadata || {},
155
+ };
156
+
157
+ // Validate waiver against schema
158
+ const validation = this.validateWaiver(waiver);
159
+ if (!validation.valid) {
160
+ throw new Error(`Waiver validation failed: ${validation.errors.join(', ')}`);
161
+ }
162
+
163
+ // Check for conflicts with existing waivers
164
+ const conflicts = await this.checkWaiverConflicts(waiver);
165
+ if (conflicts.length > 0) {
166
+ throw new Error(`Waiver conflicts with existing waivers: ${conflicts.join(', ')}`);
167
+ }
168
+
169
+ // Load existing waivers
170
+ const waivers = await this.loadActiveWaivers();
171
+
172
+ // Add new waiver
173
+ waivers.push(waiver);
174
+
175
+ // Save waivers
176
+ await this.saveActiveWaivers(waivers);
177
+
178
+ // Log waiver creation
179
+ await this.auditLog('CREATE', waiverId, {
180
+ title: waiver.title,
181
+ reason: waiver.reason,
182
+ gates: waiver.gates,
183
+ expires_at: waiver.expires_at,
184
+ approved_by: waiver.approved_by,
185
+ });
186
+
187
+ // Flag high-risk waivers for review
188
+ if (
189
+ waiver.risk_assessment.impact_level === 'critical' ||
190
+ waiver.risk_assessment.review_required
191
+ ) {
192
+ await this.flagForReview(waiver);
193
+ }
194
+
195
+ return waiver;
196
+ }
197
+
198
+ /**
199
+ * Check if waiver applies to specific gates
200
+ */
201
+ async checkWaiverCoverage(gatesToCheck, context = {}) {
202
+ const activeWaivers = await this.getActiveWaivers();
203
+ const coveredGates = new Set();
204
+ const waiverDetails = [];
205
+
206
+ for (const waiver of activeWaivers) {
207
+ // Check if waiver applies to current context
208
+ if (!this.waiverAppliesToContext(waiver, context)) {
209
+ continue;
210
+ }
211
+
212
+ // Check which gates this waiver covers
213
+ for (const gate of gatesToCheck) {
214
+ if (waiver.gates.includes(gate)) {
215
+ coveredGates.add(gate);
216
+ waiverDetails.push({
217
+ gate,
218
+ waiver_id: waiver.id,
219
+ reason: waiver.reason,
220
+ expires_at: waiver.expires_at,
221
+ approved_by: waiver.approved_by,
222
+ });
223
+ }
224
+ }
225
+ }
226
+
227
+ return {
228
+ coveredGates: Array.from(coveredGates),
229
+ waiverDetails,
230
+ allCovered: coveredGates.size === gatesToCheck.length,
231
+ };
232
+ }
233
+
234
+ /**
235
+ * Get all active waivers
236
+ */
237
+ async getActiveWaivers() {
238
+ const waivers = await this.loadActiveWaivers();
239
+ const now = new Date();
240
+
241
+ // Filter out expired waivers and clean up
242
+ const activeWaivers = waivers.filter((waiver) => {
243
+ const expiresAt = new Date(waiver.expires_at);
244
+ return expiresAt > now;
245
+ });
246
+
247
+ // Auto-cleanup expired waivers
248
+ if (activeWaivers.length !== waivers.length) {
249
+ await this.saveActiveWaivers(activeWaivers);
250
+ }
251
+
252
+ return activeWaivers;
253
+ }
254
+
255
+ /**
256
+ * Revoke a waiver
257
+ */
258
+ async revokeWaiver(waiverId, reason = 'Manual revocation') {
259
+ const waivers = await this.loadActiveWaivers();
260
+ const index = waivers.findIndex((w) => w.id === waiverId);
261
+
262
+ if (index === -1) {
263
+ throw new Error(`Waiver ${waiverId} not found`);
264
+ }
265
+
266
+ const waiver = waivers[index];
267
+ waivers.splice(index, 1);
268
+
269
+ await this.saveActiveWaivers(waivers);
270
+ await this.auditLog('REVOKE', waiverId, { reason, original_waiver: waiver });
271
+
272
+ return waiver;
273
+ }
274
+
275
+ /**
276
+ * Extend waiver expiration
277
+ */
278
+ async extendWaiver(waiverId, newExpiryDate, approvedBy) {
279
+ const waivers = await this.loadActiveWaivers();
280
+ const waiver = waivers.find((w) => w.id === waiverId);
281
+
282
+ if (!waiver) {
283
+ throw new Error(`Waiver ${waiverId} not found`);
284
+ }
285
+
286
+ const oldExpiry = waiver.expires_at;
287
+ waiver.expires_at = new Date(newExpiryDate).toISOString();
288
+ waiver.metadata = waiver.metadata || {};
289
+ waiver.metadata.extended_by = approvedBy;
290
+ waiver.metadata.extended_at = new Date().toISOString();
291
+ waiver.metadata.previous_expiry = oldExpiry;
292
+
293
+ await this.saveActiveWaivers(waivers);
294
+ await this.auditLog('EXTEND', waiverId, {
295
+ new_expiry: waiver.expires_at,
296
+ approved_by: approvedBy,
297
+ old_expiry: oldExpiry,
298
+ });
299
+
300
+ return waiver;
301
+ }
302
+
303
+ /**
304
+ * Get waiver statistics and health metrics
305
+ */
306
+ async getWaiverStats() {
307
+ const waivers = await this.getActiveWaivers();
308
+ const now = new Date();
309
+
310
+ const stats = {
311
+ total_active: waivers.length,
312
+ by_reason: {},
313
+ by_risk_level: {},
314
+ expiring_soon: [], // Next 7 days
315
+ high_risk: [],
316
+ total_gates_waived: 0,
317
+ average_lifespan_days: 0,
318
+ };
319
+
320
+ const sevenDaysFromNow = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
321
+
322
+ for (const waiver of waivers) {
323
+ // Count by reason
324
+ stats.by_reason[waiver.reason] = (stats.by_reason[waiver.reason] || 0) + 1;
325
+
326
+ // Count by risk level
327
+ const riskLevel = waiver.risk_assessment.impact_level;
328
+ stats.by_risk_level[riskLevel] = (stats.by_risk_level[riskLevel] || 0) + 1;
329
+
330
+ // Check expiring soon
331
+ const expiresAt = new Date(waiver.expires_at);
332
+ if (expiresAt <= sevenDaysFromNow) {
333
+ stats.expiring_soon.push({
334
+ id: waiver.id,
335
+ title: waiver.title,
336
+ expires_at: waiver.expires_at,
337
+ days_remaining: Math.ceil((expiresAt - now) / (24 * 60 * 60 * 1000)),
338
+ });
339
+ }
340
+
341
+ // Track high-risk waivers
342
+ if (riskLevel === 'high' || riskLevel === 'critical') {
343
+ stats.high_risk.push({
344
+ id: waiver.id,
345
+ title: waiver.title,
346
+ risk_level: riskLevel,
347
+ reason: waiver.reason,
348
+ });
349
+ }
350
+
351
+ // Count gates waived
352
+ stats.total_gates_waived += waiver.gates.length;
353
+
354
+ // Calculate lifespan
355
+ const createdAt = new Date(waiver.created_at);
356
+ const lifespanDays = (expiresAt - createdAt) / (24 * 60 * 60 * 1000);
357
+ stats.average_lifespan_days += lifespanDays;
358
+ }
359
+
360
+ if (waivers.length > 0) {
361
+ stats.average_lifespan_days /= waivers.length;
362
+ }
363
+
364
+ return stats;
365
+ }
366
+
367
+ // Private helper methods
368
+
369
+ async generateWaiverId() {
370
+ const existingWaivers = await this.loadActiveWaivers();
371
+ const usedIds = new Set(existingWaivers.map((w) => parseInt(w.id.split('-')[1])));
372
+
373
+ let counter = 1;
374
+ while (usedIds.has(counter)) {
375
+ counter++;
376
+ }
377
+
378
+ return `WV-${counter.toString().padStart(4, '0')}`;
379
+ }
380
+
381
+ validateWaiver(waiver) {
382
+ // Basic validation - in production, use a full JSON schema validator
383
+ const errors = [];
384
+
385
+ if (!waiver.id || !waiver.id.match(/^WV-\d{4}$/)) {
386
+ errors.push('Invalid waiver ID format');
387
+ }
388
+
389
+ if (!waiver.title || waiver.title.length < 10) {
390
+ errors.push('Title too short (minimum 10 characters)');
391
+ }
392
+
393
+ if (
394
+ !waiver.reason ||
395
+ ![
396
+ 'emergency_hotfix',
397
+ 'legacy_integration',
398
+ 'experimental_feature',
399
+ 'third_party_constraint',
400
+ 'performance_critical',
401
+ 'security_patch',
402
+ 'infrastructure_limitation',
403
+ 'other',
404
+ ].includes(waiver.reason)
405
+ ) {
406
+ errors.push('Invalid waiver reason');
407
+ }
408
+
409
+ if (!waiver.gates || !Array.isArray(waiver.gates) || waiver.gates.length === 0) {
410
+ errors.push('At least one gate must be specified');
411
+ }
412
+
413
+ if (!waiver.expires_at) {
414
+ errors.push('Expiration date required');
415
+ } else {
416
+ const expiresAt = new Date(waiver.expires_at);
417
+ const now = new Date();
418
+ if (expiresAt <= now) {
419
+ errors.push('Expiration date must be in the future');
420
+ }
421
+ }
422
+
423
+ if (!waiver.approved_by) {
424
+ errors.push('Approval information required');
425
+ }
426
+
427
+ return {
428
+ valid: errors.length === 0,
429
+ errors,
430
+ };
431
+ }
432
+
433
+ async checkWaiverConflicts(newWaiver) {
434
+ const activeWaivers = await this.getActiveWaivers();
435
+ const conflicts = [];
436
+
437
+ for (const existingWaiver of activeWaivers) {
438
+ // Check for overlapping gates
439
+ const overlappingGates = newWaiver.gates.filter((gate) =>
440
+ existingWaiver.gates.includes(gate)
441
+ );
442
+
443
+ if (overlappingGates.length > 0) {
444
+ conflicts.push(
445
+ `Waiver ${existingWaiver.id} already covers gates: ${overlappingGates.join(', ')}`
446
+ );
447
+ }
448
+ }
449
+
450
+ return conflicts;
451
+ }
452
+
453
+ waiverAppliesToContext(waiver, context) {
454
+ // Check environment restrictions
455
+ if (waiver.metadata?.environment && context.environment) {
456
+ if (waiver.metadata.environment !== context.environment) {
457
+ return false;
458
+ }
459
+ }
460
+
461
+ // Add more context checks as needed (branch, user, etc.)
462
+ return true;
463
+ }
464
+
465
+ async loadActiveWaivers() {
466
+ try {
467
+ if (!fs.existsSync(this.waiversFile)) {
468
+ return [];
469
+ }
470
+
471
+ const content = fs.readFileSync(this.waiversFile, 'utf8');
472
+ return yaml.load(content) || [];
473
+ } catch (error) {
474
+ console.warn(`Warning: Could not load waivers file: ${error.message}`);
475
+ return [];
476
+ }
477
+ }
478
+
479
+ async saveActiveWaivers(waivers) {
480
+ const content = yaml.dump(waivers, {
481
+ indent: 2,
482
+ sortKeys: true,
483
+ });
484
+
485
+ fs.writeFileSync(this.waiversFile, content, 'utf8');
486
+ }
487
+
488
+ async auditLog(action, waiverId, details) {
489
+ const logEntry = {
490
+ timestamp: new Date().toISOString(),
491
+ action,
492
+ waiver_id: waiverId,
493
+ details,
494
+ user: process.env.USER || process.env.USERNAME || 'unknown',
495
+ cwd: process.cwd(),
496
+ };
497
+
498
+ const logLine = JSON.stringify(logEntry) + '\n';
499
+
500
+ fs.appendFileSync(this.auditLogFile, logLine);
501
+ }
502
+
503
+ async flagForReview(waiver) {
504
+ // Create a flag file for code owners to review
505
+ const flagFile = path.join(this.waiversDir, `review-${waiver.id}.md`);
506
+
507
+ const flagContent = `# Waiver Review Required: ${waiver.id}
508
+
509
+ ## Waiver Details
510
+ - **ID**: ${waiver.id}
511
+ - **Title**: ${waiver.title}
512
+ - **Reason**: ${waiver.reason}
513
+ - **Risk Level**: ${waiver.risk_assessment.impact_level}
514
+ - **Approved By**: ${waiver.approved_by}
515
+ - **Expires**: ${waiver.expires_at}
516
+
517
+ ## Description
518
+ ${waiver.description}
519
+
520
+ ## Gates Waived
521
+ ${waiver.gates.map((gate) => `- ${gate}`).join('\n')}
522
+
523
+ ## Risk Assessment
524
+ **Impact Level**: ${waiver.risk_assessment.impact_level}
525
+ **Mitigation Plan**: ${waiver.risk_assessment.mitigation_plan}
526
+
527
+ ## Review Checklist
528
+ - [ ] Risk assessment is adequate
529
+ - [ ] Mitigation plan is sufficient
530
+ - [ ] Waiver duration is appropriate
531
+ - [ ] No alternative solutions available
532
+ - [ ] Code owners approve waiver usage
533
+
534
+ ---
535
+ *This waiver requires manual review. Please check the waiver details and mitigation plan before approving continued use.*
536
+ `;
537
+
538
+ fs.writeFileSync(flagFile, flagContent);
539
+
540
+ // Also log this flagging action
541
+ await this.auditLog('FLAG_REVIEW', waiver.id, {
542
+ flag_file: flagFile,
543
+ risk_level: waiver.risk_assessment.impact_level,
544
+ review_required: waiver.risk_assessment.review_required,
545
+ });
546
+ }
547
+ }
548
+
549
+ module.exports = WaiversManager;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paths.design/caws-cli",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "CAWS CLI - Coding Agent Workflow System command line tools",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -13,8 +13,8 @@
13
13
  "templates"
14
14
  ],
15
15
  "scripts": {
16
- "build": "mkdir -p dist && cp src/*.js dist/ && npm run typecheck",
17
- "dev": "mkdir -p dist && cp src/*.js dist/ && node dist/index.js",
16
+ "build": "mkdir -p dist && cp -r src/* dist/ && npm run typecheck",
17
+ "dev": "mkdir -p dist && cp -r src/* dist/ && node dist/index.js",
18
18
  "typecheck": "tsc --emitDeclarationOnly --outDir dist",
19
19
  "start": "node dist/index.js",
20
20
  "test": "npm run build && jest && npm run test:cleanup",
@@ -27,9 +27,9 @@
27
27
  "perf:budgets": "npm run build && jest --testPathPatterns=perf && npm run test:cleanup",
28
28
  "test:watch": "npm run build && jest --watch",
29
29
  "test:cleanup": "node scripts/cleanup-tests.js",
30
- "lint": "eslint src/**/*.js tests/**/*.js",
31
- "lint:fix": "eslint src/**/*.js tests/**/*.js --fix",
32
- "lint:staged": "eslint src/**/*.js tests/**/*.js",
30
+ "lint": "npx eslint src/**/*.js tests/**/*.js",
31
+ "lint:fix": "npx eslint src/**/*.js tests/**/*.js --fix",
32
+ "lint:staged": "npx eslint src/**/*.js tests/**/*.js",
33
33
  "format": "prettier --write src/**/*.js tests/**/*.js",
34
34
  "validate": "echo 'CLI package validation not required'",
35
35
  "caws:validate": "node ../../.caws/validate.js ../../.caws/working-spec.yaml",
@@ -54,22 +54,20 @@
54
54
  "ajv": "^8.12.0",
55
55
  "commander": "^11.0.0",
56
56
  "fs-extra": "^11.0.0",
57
- "inquirer": "^9.0.0"
57
+ "inquirer": "8.2.7"
58
58
  },
59
59
  "devDependencies": {
60
+ "@eslint/js": "^9.0.0",
60
61
  "@semantic-release/changelog": "6.0.3",
61
62
  "@semantic-release/exec": "7.1.0",
62
63
  "@semantic-release/git": "10.0.1",
63
64
  "@semantic-release/npm": "12.0.2",
64
65
  "@types/fs-extra": "^11.0.0",
65
- "@types/inquirer": "^9.0.0",
66
+ "@types/inquirer": "^8.2.6",
66
67
  "@types/js-yaml": "^4.0.0",
67
68
  "@types/node": "^20.0.0",
68
69
  "chalk": "4.1.2",
69
- "eslint": "9.36.0",
70
- "eslint-config-prettier": "10.1.8",
71
- "eslint-plugin-n": "17.23.1",
72
- "eslint-plugin-node": "^11.1.0",
70
+ "eslint": "^9.0.0",
73
71
  "jest": "30.1.3",
74
72
  "js-yaml": "4.1.0",
75
73
  "lint-staged": "15.5.2",