@paths.design/caws-cli 3.2.4 → 3.3.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,317 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @fileoverview CAWS CLI - Scaffolding tool for Coding Agent Workflow System
5
+ * Provides commands to initialize new projects and scaffold existing ones with CAWS
6
+ * @author @darianrosebrook
7
+ */
8
+
9
+ const { Command } = require('commander');
10
+ const fs = require('fs-extra');
11
+ const path = require('path');
12
+ const yaml = require('js-yaml');
13
+ const chalk = require('chalk');
14
+
15
+ // Import configuration and utilities
16
+ const {
17
+ CLI_VERSION,
18
+ initializeGlobalSetup,
19
+ loadProvenanceTools,
20
+ initializeLanguageSupport,
21
+ } = require('./config');
22
+
23
+ // Import command handlers
24
+ const { initProject } = require('./commands/init');
25
+
26
+ // Import scaffold functionality
27
+ const { scaffoldProject, setScaffoldDependencies } = require('./scaffold');
28
+
29
+ // Import validation functionality
30
+ const { validateWorkingSpecWithSuggestions } = require('./validation/spec-validation');
31
+
32
+ // Import finalization utilities
33
+ const {
34
+ finalizeProject,
35
+ continueToSuccess,
36
+ setFinalizationDependencies,
37
+ } = require('./utils/finalization');
38
+
39
+ // Import generators
40
+ const { generateWorkingSpec, validateGeneratedSpec } = require('./generators/working-spec');
41
+
42
+ // Import tool system
43
+ const ToolLoader = require('./tool-loader');
44
+ const ToolValidator = require('./tool-validator');
45
+
46
+ // Initialize global configuration
47
+ const program = new Command();
48
+
49
+ // Initialize global state
50
+ const cawsSetup = initializeGlobalSetup();
51
+ const languageSupport = initializeLanguageSupport();
52
+
53
+ // Set up dependencies for modules that need them
54
+ setScaffoldDependencies({
55
+ cawsSetup,
56
+ loadProvenanceTools,
57
+ });
58
+
59
+ setFinalizationDependencies({
60
+ languageSupport,
61
+ loadProvenanceTools,
62
+ });
63
+
64
+ // Tool system state
65
+ let toolLoader = null;
66
+ let toolValidator = null;
67
+
68
+ /**
69
+ * Initialize tool system
70
+ */
71
+ async function initializeToolSystem() {
72
+ if (toolLoader) return toolLoader;
73
+
74
+ try {
75
+ toolLoader = new ToolLoader({
76
+ toolsDir: path.join(process.cwd(), 'apps/tools/caws'),
77
+ });
78
+
79
+ toolValidator = new ToolValidator();
80
+
81
+ // Set up event listeners for tool system
82
+ toolLoader.on('discovery:complete', ({ tools: _tools, count }) => {
83
+ if (count > 0) {
84
+ console.log(chalk.blue(`šŸ”§ Discovered ${count} tools`));
85
+ }
86
+ });
87
+
88
+ toolLoader.on('tool:loaded', ({ id, metadata }) => {
89
+ console.log(chalk.gray(` āœ“ Loaded tool: ${metadata.name} (${id})`));
90
+ });
91
+
92
+ toolLoader.on('tool:error', ({ id, error }) => {
93
+ console.warn(chalk.yellow(`āš ļø Failed to load tool ${id}: ${error}`));
94
+ });
95
+
96
+ // Auto-discover tools on initialization
97
+ await toolLoader.discoverTools();
98
+
99
+ return toolLoader;
100
+ } catch (error) {
101
+ console.warn(chalk.yellow('āš ļø Tool system initialization failed:'), error.message);
102
+ console.warn(chalk.blue('šŸ’” Continuing without dynamic tools'));
103
+ return null;
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Validate command handler
109
+ */
110
+ async function validateCommand(specFile, options) {
111
+ try {
112
+ let specPath = specFile || path.join('.caws', 'working-spec.yaml');
113
+
114
+ if (!fs.existsSync(specPath)) {
115
+ console.error(chalk.red(`āŒ Spec file not found: ${specPath}`));
116
+ console.error(chalk.blue('šŸ’” Run "caws init" first to create a working spec'));
117
+ process.exit(1);
118
+ }
119
+
120
+ const specContent = fs.readFileSync(specPath, 'utf8');
121
+ const spec = yaml.load(specContent);
122
+
123
+ console.log(chalk.cyan('šŸ” Validating CAWS working spec...'));
124
+
125
+ const result = validateWorkingSpecWithSuggestions(spec, {
126
+ autoFix: options.autoFix,
127
+ suggestions: !options.quiet,
128
+ });
129
+
130
+ if (result.valid) {
131
+ console.log(chalk.green('āœ… Working spec validation passed'));
132
+ if (!options.quiet) {
133
+ console.log(chalk.gray(` Risk tier: ${spec.risk_tier}`));
134
+ console.log(chalk.gray(` Mode: ${spec.mode}`));
135
+ if (spec.title) {
136
+ console.log(chalk.gray(` Title: ${spec.title}`));
137
+ }
138
+ }
139
+ } else {
140
+ console.log(chalk.red('āŒ Working spec validation failed'));
141
+
142
+ // Show errors
143
+ result.errors.forEach((error, index) => {
144
+ console.log(` ${index + 1}. ${chalk.red(error.message)}`);
145
+ if (error.suggestion) {
146
+ console.log(` ${chalk.blue('šŸ’” ' + error.suggestion)}`);
147
+ }
148
+ });
149
+
150
+ // Show warnings
151
+ if (result.warnings && result.warnings.length > 0) {
152
+ console.log(chalk.yellow('\nāš ļø Warnings:'));
153
+ result.warnings.forEach((warning, index) => {
154
+ console.log(` ${index + 1}. ${chalk.yellow(warning.message)}`);
155
+ });
156
+ }
157
+
158
+ process.exit(1);
159
+ }
160
+ } catch (error) {
161
+ console.error(chalk.red('āŒ Error during validation:'), error.message);
162
+ process.exit(1);
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Tool execution command handler
168
+ */
169
+ async function executeTool(toolId, options) {
170
+ try {
171
+ // Initialize tool system
172
+ const loader = await initializeToolSystem();
173
+
174
+ if (!loader) {
175
+ console.error(chalk.red('āŒ Tool system not available'));
176
+ process.exit(1);
177
+ }
178
+
179
+ // Load all tools first
180
+ await loader.loadAllTools();
181
+ const tool = loader.getTool(toolId);
182
+
183
+ if (!tool) {
184
+ console.error(chalk.red(`āŒ Tool '${toolId}' not found`));
185
+ console.log(chalk.blue('šŸ’” Available tools:'));
186
+ const tools = loader.getAllTools();
187
+ for (const [id, t] of tools) {
188
+ console.log(` - ${id}: ${t.metadata.name}`);
189
+ }
190
+ process.exit(1);
191
+ }
192
+
193
+ // Validate tool before execution
194
+ const validation = await toolValidator.validateTool(tool);
195
+ if (!validation.valid) {
196
+ console.error(chalk.red('āŒ Tool validation failed:'));
197
+ validation.errors.forEach((error) => {
198
+ console.error(` ${chalk.red('āœ—')} ${error}`);
199
+ });
200
+ process.exit(1);
201
+ }
202
+
203
+ // Parse parameters
204
+ let params = {};
205
+ if (options.params) {
206
+ try {
207
+ params = JSON.parse(options.params);
208
+ } catch (error) {
209
+ console.error(chalk.red('āŒ Invalid JSON parameters:'), error.message);
210
+ process.exit(1);
211
+ }
212
+ }
213
+
214
+ console.log(chalk.blue(`šŸš€ Executing tool: ${tool.metadata.name}`));
215
+
216
+ // Execute tool
217
+ const result = await tool.module.execute(params, {
218
+ workingDirectory: process.cwd(),
219
+ timeout: options.timeout,
220
+ });
221
+
222
+ // Display results
223
+ if (result.success) {
224
+ console.log(chalk.green('āœ… Tool execution successful'));
225
+ if (result.output && typeof result.output === 'object') {
226
+ console.log(chalk.gray('Output:'), JSON.stringify(result.output, null, 2));
227
+ }
228
+ } else {
229
+ console.error(chalk.red('āŒ Tool execution failed'));
230
+ result.errors.forEach((error) => {
231
+ console.error(` ${chalk.red('āœ—')} ${error}`);
232
+ });
233
+ process.exit(1);
234
+ }
235
+ } catch (error) {
236
+ console.error(chalk.red(`āŒ Error executing tool ${toolId}:`), error.message);
237
+ process.exit(1);
238
+ }
239
+ }
240
+
241
+ // Setup CLI program
242
+ program.name('caws').description('CAWS - Coding Agent Workflow System CLI').version(CLI_VERSION);
243
+
244
+ // Init command
245
+ program
246
+ .command('init')
247
+ .description('Initialize a new project with CAWS')
248
+ .argument('[project-name]', 'Name of the project to create (use "." for current directory)')
249
+ .option('-i, --interactive', 'Run interactive setup wizard', true)
250
+ .option('--non-interactive', 'Skip interactive prompts (use defaults)', false)
251
+ .option('--template <template>', 'Use specific project template')
252
+ .action(initProject);
253
+
254
+ // Scaffold command
255
+ program
256
+ .command('scaffold')
257
+ .description('Add CAWS components to existing project')
258
+ .option('-f, --force', 'Overwrite existing files', false)
259
+ .option('--minimal', 'Only essential components', false)
260
+ .option('--with-codemods', 'Include codemod scripts', false)
261
+ .option('--with-oidc', 'Include OIDC trusted publisher setup', false)
262
+ .action(scaffoldProject);
263
+
264
+ // Validate command
265
+ program
266
+ .command('validate')
267
+ .description('Validate CAWS working spec with suggestions')
268
+ .argument('[spec-file]', 'Path to working spec file (default: .caws/working-spec.yaml)')
269
+ .option('-q, --quiet', 'Suppress suggestions and warnings', false)
270
+ .option('--auto-fix', 'Automatically fix safe validation issues', false)
271
+ .action(validateCommand);
272
+
273
+ // Tool command
274
+ program
275
+ .command('tool')
276
+ .description('Execute CAWS tools programmatically')
277
+ .argument('<tool-id>', 'ID of the tool to execute')
278
+ .option('-p, --params <json>', 'Parameters as JSON string', '{}')
279
+ .option('-t, --timeout <ms>', 'Execution timeout in milliseconds', parseInt, 30000)
280
+ .action(executeTool);
281
+
282
+ // Error handling
283
+ program.exitOverride((err) => {
284
+ if (
285
+ err.code === 'commander.help' ||
286
+ err.code === 'commander.version' ||
287
+ err.message.includes('outputHelp')
288
+ ) {
289
+ process.exit(0);
290
+ }
291
+ console.error(chalk.red('āŒ Error:'), err.message);
292
+ process.exit(1);
293
+ });
294
+
295
+ // Parse and run
296
+ if (require.main === module) {
297
+ try {
298
+ program.parse();
299
+ } catch (error) {
300
+ if (
301
+ error.code === 'commander.help' ||
302
+ error.code === 'commander.version' ||
303
+ error.message.includes('outputHelp')
304
+ ) {
305
+ process.exit(0);
306
+ } else {
307
+ console.error(chalk.red('āŒ Error:'), error.message);
308
+ process.exit(1);
309
+ }
310
+ }
311
+ }
312
+
313
+ // Export functions for testing
314
+ module.exports = {
315
+ generateWorkingSpec,
316
+ validateGeneratedSpec,
317
+ };
package/dist/index.js CHANGED
@@ -23,6 +23,9 @@ const {
23
23
  initializeLanguageSupport,
24
24
  } = require('./config');
25
25
 
26
+ // Import error handling
27
+ const { handleCliError, findSimilarCommand } = require('./error-handler');
28
+
26
29
  // Import command handlers
27
30
  const { initProject } = require('./commands/init');
28
31
  const { validateCommand } = require('./commands/validate');
@@ -30,6 +33,9 @@ const { burnupCommand } = require('./commands/burnup');
30
33
  const { testAnalysisCommand } = require('./test-analysis');
31
34
  const { provenanceCommand } = require('./commands/provenance');
32
35
  const { executeTool } = require('./commands/tool');
36
+ const { statusCommand } = require('./commands/status');
37
+ const { templatesCommand } = require('./commands/templates');
38
+ const { diagnoseCommand } = require('./commands/diagnose');
33
39
 
34
40
  // Import scaffold functionality
35
41
  const { scaffoldProject, setScaffoldDependencies } = require('./scaffold');
@@ -72,7 +78,11 @@ setFinalizationDependencies({
72
78
  });
73
79
 
74
80
  // Setup CLI program
75
- program.name('caws').description('CAWS - Coding Agent Workflow System CLI').version(CLI_VERSION);
81
+ program
82
+ .name('caws')
83
+ .description('CAWS - Coding Agent Workflow System CLI')
84
+ .version(CLI_VERSION)
85
+ .showHelpAfterError(false); // We'll show better suggestions instead
76
86
 
77
87
  // Init command
78
88
  program
@@ -103,6 +113,27 @@ program
103
113
  .option('--auto-fix', 'Automatically fix safe validation issues', false)
104
114
  .action(validateCommand);
105
115
 
116
+ // Status command
117
+ program
118
+ .command('status')
119
+ .description('Show project health overview')
120
+ .option('-s, --spec <path>', 'Path to working spec file', '.caws/working-spec.yaml')
121
+ .action(statusCommand);
122
+
123
+ // Templates command
124
+ program
125
+ .command('templates [subcommand]')
126
+ .description('Discover and manage project templates')
127
+ .option('-n, --name <template>', 'Template name (for info subcommand)')
128
+ .action(templatesCommand);
129
+
130
+ // Diagnose command
131
+ program
132
+ .command('diagnose')
133
+ .description('Run health checks and suggest fixes')
134
+ .option('--fix', 'Apply automatic fixes', false)
135
+ .action(diagnoseCommand);
136
+
106
137
  // Tool command
107
138
  program
108
139
  .command('tool')
@@ -234,7 +265,14 @@ hooksCmd
234
265
  });
235
266
 
236
267
  // Error handling
268
+ // Custom error event handler for better messages
269
+ program.configureHelp({
270
+ // Override error display
271
+ showError: () => {}, // Suppress default error display
272
+ });
273
+
237
274
  program.exitOverride((err) => {
275
+ // Handle help and version requests gracefully
238
276
  if (
239
277
  err.code === 'commander.help' ||
240
278
  err.code === 'commander.version' ||
@@ -242,7 +280,74 @@ program.exitOverride((err) => {
242
280
  ) {
243
281
  process.exit(0);
244
282
  }
245
- console.error(chalk.red('āŒ Error:'), err.message);
283
+
284
+ const commandName = process.argv[2];
285
+
286
+ // Check for unknown command
287
+ if (err.code === 'commander.unknownCommand') {
288
+ const validCommands = [
289
+ 'init',
290
+ 'validate',
291
+ 'scaffold',
292
+ 'status',
293
+ 'templates',
294
+ 'provenance',
295
+ 'hooks',
296
+ 'burnup',
297
+ 'tool',
298
+ ];
299
+ const similar = findSimilarCommand(commandName, validCommands);
300
+
301
+ console.error(chalk.red(`\nāŒ Unknown command: ${commandName}`));
302
+
303
+ if (similar) {
304
+ console.error(chalk.yellow(`\nšŸ’” Did you mean: caws ${similar}?`));
305
+ }
306
+
307
+ console.error(
308
+ chalk.yellow('šŸ’” Available commands: init, validate, scaffold, provenance, hooks')
309
+ );
310
+ console.error(chalk.yellow('šŸ’” Try: caws --help for full command list'));
311
+ console.error(
312
+ chalk.blue(
313
+ '\nšŸ“š Documentation: https://github.com/Paths-Design/coding-agent-working-standard/blob/main/docs/api/cli.md'
314
+ )
315
+ );
316
+
317
+ process.exit(1);
318
+ }
319
+
320
+ // Check for unknown option
321
+ if (err.code === 'commander.unknownOption' || err.message.includes('unknown option')) {
322
+ const optionMatch = err.message.match(/unknown option ['"]([^'"]+)['"]/i);
323
+ const option = optionMatch ? optionMatch[1] : '';
324
+
325
+ console.error(chalk.red(`\nāŒ Unknown option: ${option}`));
326
+ console.error(chalk.yellow(`\nšŸ’” Try: caws ${commandName || ''} --help for available options`));
327
+
328
+ // Provide specific suggestions for common mistakes
329
+ if (option === '--suggestions' || option === '--suggest') {
330
+ console.error(chalk.yellow('šŸ’” Note: Validation includes suggestions by default'));
331
+ console.error(chalk.yellow(' Just run: caws validate'));
332
+ }
333
+
334
+ console.error(
335
+ chalk.blue(
336
+ '\nšŸ“š Documentation: https://github.com/Paths-Design/coding-agent-working-standard/blob/main/docs/api/cli.md'
337
+ )
338
+ );
339
+
340
+ process.exit(1);
341
+ }
342
+
343
+ // Generic Commander error
344
+ console.error(chalk.red('\nāŒ Error:'), err.message);
345
+ console.error(chalk.yellow('\nšŸ’” Try: caws --help for usage information'));
346
+ console.error(
347
+ chalk.blue(
348
+ '\nšŸ“š Documentation: https://github.com/Paths-Design/coding-agent-working-standard/blob/main/docs/agents/full-guide.md'
349
+ )
350
+ );
246
351
  process.exit(1);
247
352
  });
248
353
 
@@ -251,16 +356,81 @@ if (require.main === module) {
251
356
  try {
252
357
  program.parse();
253
358
  } catch (error) {
359
+ // Handle help and version requests gracefully
254
360
  if (
255
361
  error.code === 'commander.help' ||
256
362
  error.code === 'commander.version' ||
257
363
  error.message.includes('outputHelp')
258
364
  ) {
259
365
  process.exit(0);
260
- } else {
261
- console.error(chalk.red('āŒ Error:'), error.message);
366
+ }
367
+
368
+ // Enhanced error handling for Commander.js errors
369
+ const commandName = process.argv[2];
370
+ const context = {
371
+ command: commandName,
372
+ option: process.argv[3],
373
+ };
374
+
375
+ // Check for unknown command
376
+ if (error.code === 'commander.unknownCommand') {
377
+ const validCommands = [
378
+ 'init',
379
+ 'validate',
380
+ 'scaffold',
381
+ 'provenance',
382
+ 'hooks',
383
+ 'burnup',
384
+ 'tool',
385
+ ];
386
+ const similar = findSimilarCommand(commandName, validCommands);
387
+
388
+ console.error(chalk.red(`\nāŒ Unknown command: ${commandName}`));
389
+
390
+ if (similar) {
391
+ console.error(chalk.yellow(`\nšŸ’” Did you mean: caws ${similar}?`));
392
+ }
393
+
394
+ console.error(
395
+ chalk.yellow('šŸ’” Available commands: init, validate, scaffold, provenance, hooks')
396
+ );
397
+ console.error(chalk.yellow('šŸ’” Try: caws --help for full command list'));
398
+ console.error(
399
+ chalk.blue(
400
+ '\nšŸ“š Documentation: https://github.com/Paths-Design/coding-agent-working-standard/blob/main/docs/api/cli.md'
401
+ )
402
+ );
403
+
262
404
  process.exit(1);
263
405
  }
406
+
407
+ // Check for unknown option
408
+ if (error.code === 'commander.unknownOption' || error.message.includes('unknown option')) {
409
+ const optionMatch = error.message.match(/unknown option ['"]([^'"]+)['"]/i);
410
+ const option = optionMatch ? optionMatch[1] : '';
411
+
412
+ console.error(chalk.red(`\nāŒ Unknown option: ${option}`));
413
+ console.error(
414
+ chalk.yellow(`\nšŸ’” Try: caws ${commandName || ''} --help for available options`)
415
+ );
416
+
417
+ // Provide specific suggestions for common mistakes
418
+ if (option === '--suggestions' || option === '--suggest') {
419
+ console.error(chalk.yellow('šŸ’” Note: Validation includes suggestions by default'));
420
+ console.error(chalk.yellow(' Just run: caws validate'));
421
+ }
422
+
423
+ console.error(
424
+ chalk.blue(
425
+ '\nšŸ“š Documentation: https://github.com/Paths-Design/coding-agent-working-standard/blob/main/docs/api/cli.md'
426
+ )
427
+ );
428
+
429
+ process.exit(1);
430
+ }
431
+
432
+ // Generic error with enhanced handling
433
+ handleCliError(error, context, true);
264
434
  }
265
435
  }
266
436