vibecodingmachine-cli 2026.2.26-1752 → 2026.3.9-1621

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 (74) hide show
  1. package/bin/auth/auth-compliance.js +7 -1
  2. package/bin/commands/agent-commands.js +150 -228
  3. package/bin/commands/command-aliases.js +68 -0
  4. package/bin/vibecodingmachine.js +1 -2
  5. package/package.json +2 -2
  6. package/src/commands/agents/list.js +71 -115
  7. package/src/commands/agents-check.js +16 -4
  8. package/src/commands/analyze-file-sizes.js +1 -1
  9. package/src/commands/auto-direct/auto-provider-manager.js +290 -0
  10. package/src/commands/auto-direct/auto-status-display.js +331 -0
  11. package/src/commands/auto-direct/auto-utils.js +439 -0
  12. package/src/commands/auto-direct/file-operations.js +110 -0
  13. package/src/commands/auto-direct/provider-config.js +1 -1
  14. package/src/commands/auto-direct/provider-manager.js +1 -1
  15. package/src/commands/auto-direct/status-display.js +1 -1
  16. package/src/commands/auto-direct/utils.js +24 -18
  17. package/src/commands/auto-direct-refactored.js +413 -0
  18. package/src/commands/auto-direct.js +594 -188
  19. package/src/commands/requirements/commands.js +353 -0
  20. package/src/commands/requirements/default-handlers.js +272 -0
  21. package/src/commands/requirements/disable.js +97 -0
  22. package/src/commands/requirements/enable.js +97 -0
  23. package/src/commands/requirements/utils.js +194 -0
  24. package/src/commands/requirements-refactored.js +60 -0
  25. package/src/commands/requirements.js +38 -771
  26. package/src/commands/specs/disable.js +96 -0
  27. package/src/commands/specs/enable.js +96 -0
  28. package/src/trui/TruiInterface.js +5 -11
  29. package/src/trui/agents/AgentInterface.js +24 -396
  30. package/src/trui/agents/handlers/CommandHandler.js +93 -0
  31. package/src/trui/agents/handlers/ContextManager.js +117 -0
  32. package/src/trui/agents/handlers/DisplayHandler.js +243 -0
  33. package/src/trui/agents/handlers/HelpHandler.js +51 -0
  34. package/src/utils/auth.js +13 -111
  35. package/src/utils/config.js +4 -0
  36. package/src/utils/interactive/requirements-navigation.js +17 -15
  37. package/src/utils/interactive-broken.js +2 -2
  38. package/src/utils/provider-checker/agent-runner.js +15 -1
  39. package/src/utils/provider-checker/cli-installer.js +149 -7
  40. package/src/utils/provider-checker/opencode-checker.js +588 -0
  41. package/src/utils/provider-checker/provider-validator.js +88 -3
  42. package/src/utils/provider-checker/time-formatter.js +3 -2
  43. package/src/utils/provider-manager.js +28 -20
  44. package/src/utils/provider-registry.js +35 -3
  45. package/src/utils/requirements-navigator/index.js +94 -0
  46. package/src/utils/requirements-navigator/input-handler.js +217 -0
  47. package/src/utils/requirements-navigator/section-loader.js +188 -0
  48. package/src/utils/requirements-navigator/tree-builder.js +105 -0
  49. package/src/utils/requirements-navigator/tree-renderer.js +50 -0
  50. package/src/utils/requirements-navigator.js +2 -583
  51. package/src/utils/trui-clarifications.js +188 -0
  52. package/src/utils/trui-feedback.js +54 -1
  53. package/src/utils/trui-kiro-integration.js +398 -0
  54. package/src/utils/trui-main-handlers.js +194 -0
  55. package/src/utils/trui-main-menu.js +235 -0
  56. package/src/utils/trui-nav-agents.js +178 -25
  57. package/src/utils/trui-nav-requirements.js +203 -27
  58. package/src/utils/trui-nav-settings.js +114 -1
  59. package/src/utils/trui-nav-specifications.js +44 -3
  60. package/src/utils/trui-navigation-backup.js +603 -0
  61. package/src/utils/trui-navigation.js +70 -228
  62. package/src/utils/trui-provider-health.js +274 -0
  63. package/src/utils/trui-provider-manager.js +376 -0
  64. package/src/utils/trui-quick-menu.js +25 -1
  65. package/src/utils/trui-req-actions-backup.js +507 -0
  66. package/src/utils/trui-req-actions.js +148 -216
  67. package/src/utils/trui-req-editor.js +170 -0
  68. package/src/utils/trui-req-file-ops.js +278 -0
  69. package/src/utils/trui-req-tree-old.js +719 -0
  70. package/src/utils/trui-req-tree.js +348 -627
  71. package/src/utils/trui-specifications.js +25 -7
  72. package/src/utils/trui-windsurf.js +231 -10
  73. package/src/utils/welcome-screen-extracted.js +2 -2
  74. package/src/utils/welcome-screen.js +2 -2
@@ -1,793 +1,60 @@
1
- const path = require('path');
2
- const fs = require('fs-extra');
3
- const chalk = require('chalk');
4
- const chokidar = require('chokidar');
5
- const { getRepoPath, setRepoPath } = require('../utils/config');
6
- const { getRequirementsPath, DefaultRequirementManager, JSONStorage } = require('vibecodingmachine-core');
7
-
8
- async function getReqPathOrExit() {
9
- let repoPath = await getRepoPath();
10
-
11
- // Auto-detect and initialize if we're in a git repository
12
- if (!repoPath) {
13
- const cwd = process.cwd();
14
- const cwdResolved = path.resolve(cwd);
15
-
16
- // Find the git root by walking up the directory tree
17
- let currentDir = cwdResolved;
18
- let foundGitRoot = false;
19
- const maxDepth = 50; // Prevent infinite loops
20
- let depth = 0;
21
-
22
- // Walk up the directory tree looking for .git directory
23
- while (depth < maxDepth && currentDir !== path.dirname(currentDir)) {
24
- const gitPath = path.join(currentDir, '.git');
25
- try {
26
- if (await fs.pathExists(gitPath)) {
27
- repoPath = currentDir;
28
- foundGitRoot = true;
29
- break;
30
- }
31
- } catch (err) {
32
- // If we can't check, continue to parent
33
- }
34
- const parentDir = path.dirname(currentDir);
35
- if (parentDir === currentDir) {
36
- // Reached filesystem root
37
- break;
38
- }
39
- currentDir = parentDir;
40
- depth++;
41
- }
42
-
43
- // Fallback: if no .git found but .vibecodingmachine exists, use current dir
44
- if (!foundGitRoot) {
45
- try {
46
- const vibecodingmachineDir = path.join(cwdResolved, '.vibecodingmachine');
47
- if (await fs.pathExists(vibecodingmachineDir)) {
48
- repoPath = cwdResolved;
49
- foundGitRoot = true;
50
- }
51
- } catch (err) {
52
- // Ignore errors
53
- }
54
- }
55
-
56
- // Final fallback: use current directory if we have package.json
57
- if (!foundGitRoot) {
58
- try {
59
- const packageJsonPath = path.join(cwdResolved, 'package.json');
60
- if (await fs.pathExists(packageJsonPath)) {
61
- repoPath = cwdResolved;
62
- foundGitRoot = true;
63
- }
64
- } catch (err) {
65
- // Ignore errors
66
- }
67
- }
68
-
69
- // If we found a repo path, save it
70
- if (repoPath) {
71
- try {
72
- await setRepoPath(repoPath);
73
- } catch (err) {
74
- // If setting fails, we still have repoPath set, so continue
75
- }
76
- }
77
- }
78
-
79
- // Final validation - ensure we have a valid path
80
- // If we still don't have a repoPath, use current directory as absolute last resort
81
- if (!repoPath) {
82
- repoPath = path.resolve(process.cwd());
83
- try {
84
- await setRepoPath(repoPath);
85
- } catch (err) {
86
- // Even if we can't save it, we'll use it for this session
87
- }
88
- }
89
-
90
- // At this point, repoPath MUST be set (we've tried everything including current directory)
91
- if (!repoPath) {
92
- console.log(chalk.yellow('No repository path configured'));
93
- console.log(chalk.gray('Use'), chalk.cyan('vcm repo:init'), chalk.gray('or'), chalk.cyan('vcm repo:set <path>'));
94
- process.exit(1);
95
- }
96
-
97
- // Use getRequirementsPath which handles hostname-specific files
98
- const reqPath = await getRequirementsPath(repoPath);
99
- return { repoPath, reqPath };
100
- }
101
-
102
- async function list(options) {
103
- try {
104
- const { repoPath, reqPath } = await getReqPathOrExit();
105
-
106
- // Handle --all-computers flag
107
- if (options && options.allComputers) {
108
- const vibeDir = path.join(repoPath, '.vibecodingmachine');
109
- if (!await fs.pathExists(vibeDir)) {
110
- console.log(chalk.yellow('No .vibecodingmachine directory found.'));
111
- return;
112
- }
113
-
114
- // Find all REQUIREMENTS-*.md files
115
- const files = await fs.readdir(vibeDir);
116
- const reqFiles = files.filter(f => f.startsWith('REQUIREMENTS') && f.endsWith('.md'));
117
-
118
- if (reqFiles.length === 0) {
119
- console.log(chalk.yellow('No requirements files found.'));
120
- return;
121
- }
122
-
123
- // Extract computer info and requirements from each file
124
- for (const file of reqFiles) {
125
- const filePath = path.join(vibeDir, file);
126
- const content = await fs.readFile(filePath, 'utf8');
127
- const lines = content.split('\n');
128
-
129
- // Extract hostname from file
130
- let hostname = 'Unknown';
131
- const hostnameMatch = content.match(/- \*\*Hostname\*\*:\s*(.+)/);
132
- if (hostnameMatch) {
133
- hostname = hostnameMatch[1].trim();
134
- }
135
-
136
- // Extract focus area
137
- let focus = '';
138
- const focusMatch = content.match(/## 🎯 Focus\n\*\*(.+)\*\*/);
139
- if (focusMatch) {
140
- focus = focusMatch[1].trim();
141
- }
142
-
143
- // Filter by focus if specified
144
- if (options.focus && focus && !focus.toLowerCase().includes(options.focus.toLowerCase())) {
145
- continue;
146
- }
147
-
148
- console.log(chalk.blue.bold(`\n📍 ${hostname}`) + (focus ? chalk.gray(` (${focus})`) : ''));
149
-
150
- // List requirements from this file
151
- for (const line of lines) {
152
- if (line.startsWith('### ') || line.startsWith('## ')) {
153
- const statusFilter = options.status ? String(options.status).toLowerCase() : null;
154
- if (!statusFilter || line.toLowerCase().includes(statusFilter)) {
155
- console.log(' ' + line);
156
- }
157
- }
158
- }
159
- }
160
- return;
161
- }
162
-
163
- // Single computer mode (default or with --computer filter)
164
- let targetReqPath = reqPath;
165
-
166
- // If computer filter specified, find that computer's requirements file
167
- if (options && options.computer) {
168
- const vibeDir = path.join(repoPath, '.vibecodingmachine');
169
- const files = await fs.readdir(vibeDir);
170
- const computerFile = files.find(f =>
171
- f.startsWith('REQUIREMENTS') &&
172
- f.endsWith('.md') &&
173
- f.toLowerCase().includes(options.computer.toLowerCase())
174
- );
175
-
176
- if (!computerFile) {
177
- console.log(chalk.yellow(`No requirements file found for computer: ${options.computer}`));
178
- return;
179
- }
180
-
181
- targetReqPath = path.join(vibeDir, computerFile);
182
- }
183
-
184
- if (!await fs.pathExists(targetReqPath)) {
185
- console.log(chalk.yellow('No REQUIREMENTS.md found.'));
186
- return;
187
- }
188
-
189
- const content = await fs.readFile(targetReqPath, 'utf8');
190
- const lines = content.split('\n');
191
-
192
- // Extract focus area for focus filtering
193
- let fileFocus = '';
194
- const focusMatch = content.match(/## 🎯 Focus\n\*\*(.+)\*\*/);
195
- if (focusMatch) {
196
- fileFocus = focusMatch[1].trim();
197
- }
198
-
199
- // Check focus filter
200
- if (options && options.focus) {
201
- if (!fileFocus || !fileFocus.toLowerCase().includes(options.focus.toLowerCase())) {
202
- console.log(chalk.yellow(`No requirements match focus area: ${options.focus}`));
203
- return;
204
- }
205
- }
206
-
207
- const statusFilter = options && options.status ? String(options.status).toLowerCase() : null;
208
- for (const line of lines) {
209
- if (line.startsWith('### ') || line.startsWith('## ')) {
210
- if (!statusFilter || line.toLowerCase().includes(statusFilter)) {
211
- console.log(line);
212
- }
213
- }
214
- }
215
- } catch (error) {
216
- console.error(chalk.red('Error listing requirements:'), error.message);
217
- process.exit(1);
218
- }
219
- }
220
-
221
- async function add(name, pkg, description) {
222
- try {
223
- const { reqPath, repoPath } = await getReqPathOrExit();
224
- await fs.ensureFile(reqPath);
225
- let content = await fs.readFile(reqPath, 'utf8').catch(() => '');
226
-
227
- // Find the TODO section
228
- const todoSectionHeader = '## ⏳ Requirements not yet completed';
229
- if (!content.includes('Requirements not yet completed')) {
230
- content += '\n\n' + todoSectionHeader + '\n';
231
- }
232
-
233
- // Insert at the top of the TODO section (right after the header)
234
- const lines = content.split('\n');
235
- const newLines = [];
236
- let inserted = false;
237
-
238
- for (let i = 0; i < lines.length; i++) {
239
- newLines.push(lines[i]);
240
-
241
- // Insert right after the TODO section header
242
- if (!inserted && lines[i].startsWith('##') && lines[i].includes('Requirements not yet completed')) {
243
- // Add requirement header without number prefix (for backward compatibility)
244
- newLines.push(`### ${name}`);
245
-
246
- // Add package if provided (and not 'all')
247
- if (pkg && Array.isArray(pkg) && pkg.length > 0) {
248
- const packageValue = pkg.length === 1 ? pkg[0] : pkg.join(', ');
249
- if (packageValue !== 'all') {
250
- newLines.push(`PACKAGE: ${packageValue}`);
251
- }
252
- } else if (pkg && typeof pkg === 'string' && pkg !== 'all') {
253
- newLines.push(`PACKAGE: ${pkg}`);
254
- }
255
-
256
- // Add description if provided
257
- if (description && typeof description === 'string' && description.trim()) {
258
- const descLines = description.split('\n');
259
- descLines.forEach(line => {
260
- if (line.trim()) {
261
- newLines.push(line);
262
- }
263
- });
264
- } else if (description && Array.isArray(description)) {
265
- // Handle array of description lines
266
- description.forEach(line => {
267
- if (line && typeof line === 'string' && line.trim()) {
268
- newLines.push(line);
269
- }
270
- });
271
- }
272
-
273
- // Add blank line after requirement
274
- newLines.push('');
275
- inserted = true;
276
- }
277
- }
278
-
279
- content = newLines.join('\n');
280
- await fs.writeFile(reqPath, content);
281
- console.log(chalk.green('✓ Requirement added'));
282
- } catch (error) {
283
- console.error(chalk.red('Error adding requirement:'), error.message);
284
- process.exit(1);
285
- }
286
- }
287
-
288
- async function current() {
289
- try {
290
- const { reqPath } = await getReqPathOrExit();
291
- if (!await fs.pathExists(reqPath)) {
292
- console.log(chalk.yellow('No REQUIREMENTS.md found.'));
293
- return;
294
- }
295
- const content = await fs.readFile(reqPath, 'utf8');
296
- const match = content.match(/## \uD83D\uDEA6 Current Status\n([A-Z_]+)/);
297
- console.log(chalk.cyan(match ? match[1] : 'UNKNOWN'));
298
- } catch (error) {
299
- console.error(chalk.red('Error reading current status:'), error.message);
300
- process.exit(1);
301
- }
302
- }
303
-
304
- async function next() {
305
- try {
306
- const { reqPath } = await getReqPathOrExit();
307
- if (!await fs.pathExists(reqPath)) {
308
- console.log(chalk.yellow('No REQUIREMENTS.md found.'));
309
- return;
310
- }
311
- const content = await fs.readFile(reqPath, 'utf8');
312
- const order = ['PREPARE', 'ACT', 'CLEAN UP', 'VERIFY', 'DONE'];
313
- const currentMatch = content.match(/## \uD83D\uDEA6 Current Status\n([A-Z_ ]+)/);
314
- const current = currentMatch ? currentMatch[1] : 'PREPARE';
315
- const idx = Math.min(order.indexOf(current) + 1, order.length - 1);
316
- const nextStatus = order[idx];
317
- const updated = content.replace(/(## \uD83D\uDEA6 Current Status\n)([A-Z_ ]+)/, `$1${nextStatus}`);
318
- await fs.writeFile(reqPath, updated);
319
- console.log(chalk.green('✓ Moved to next status:'), chalk.cyan(nextStatus));
320
- } catch (error) {
321
- console.error(chalk.red('Error updating status:'), error.message);
322
- process.exit(1);
323
- }
324
- }
325
-
326
- async function edit() {
327
- try {
328
- const { reqPath } = await getReqPathOrExit();
329
- // Always use system default opener to avoid taking over the terminal
330
- const { execSync } = require('child_process');
331
- // Use 'open' for macOS (user's OS), could be expanded for others if needed
332
- execSync(`open ${JSON.stringify(reqPath)}`);
333
- } catch (error) {
334
- console.error(chalk.red('Error opening file:'), error.message);
335
- process.exit(1);
336
- }
337
- }
338
-
339
- async function watch() {
340
- try {
341
- const { reqPath } = await getReqPathOrExit();
342
- console.log(chalk.gray('Watching:'), chalk.cyan(reqPath));
343
- chokidar.watch(reqPath, { ignoreInitial: true })
344
- .on('change', () => console.log(chalk.green('✓ REQUIREMENTS.md changed')))
345
- .on('error', (err) => console.error(chalk.red('Watcher error:'), err.message));
346
- } catch (error) {
347
- console.error(chalk.red('Error watching requirements:'), error.message);
348
- process.exit(1);
349
- }
350
- }
351
-
352
- async function rename(oldTitle, newTitle, description) {
353
- try {
354
- const { reqPath } = await getReqPathOrExit();
355
- if (!await fs.pathExists(reqPath)) {
356
- console.log(chalk.yellow('No REQUIREMENTS.md found.'));
357
- return;
358
- }
359
-
360
- // Read the requirements file
361
- const content = await fs.readFile(reqPath, 'utf8');
362
- const lines = content.split('\n');
363
-
364
- // Find the requirement block
365
- let requirementStartIndex = -1;
366
- let requirementEndIndex = -1;
367
-
368
- for (let i = 0; i < lines.length; i++) {
369
- const line = lines[i].trim();
370
- if (line.startsWith('###')) {
371
- const title = line.replace(/^###\s*/, '').trim();
372
- if (title === oldTitle) {
373
- requirementStartIndex = i;
374
- // Find the end of this requirement (next ### or ## header)
375
- for (let j = i + 1; j < lines.length; j++) {
376
- const nextLine = lines[j].trim();
377
- if (nextLine.startsWith('###') || (nextLine.startsWith('##') && !nextLine.startsWith('###'))) {
378
- requirementEndIndex = j;
379
- break;
380
- }
381
- }
382
- if (requirementEndIndex === -1) {
383
- requirementEndIndex = lines.length;
384
- }
385
- break;
386
- }
387
- }
388
- }
389
-
390
- if (requirementStartIndex === -1) {
391
- console.log(chalk.yellow(`⚠️ Could not find requirement: "${oldTitle}"`));
392
- return;
393
- }
394
-
395
- // Build new requirement block
396
- const newBlock = [`### ${newTitle}`];
397
-
398
- // If description provided, use it
399
- if (description) {
400
- if (Array.isArray(description)) {
401
- description.forEach(line => {
402
- if (line && line.trim()) {
403
- newBlock.push(line);
404
- }
405
- });
406
- } else if (typeof description === 'string') {
407
- description.split('\n').forEach(line => {
408
- if (line.trim()) {
409
- newBlock.push(line);
410
- }
411
- });
412
- }
413
- } else {
414
- // Keep existing details (skip the ### header line)
415
- for (let i = requirementStartIndex + 1; i < requirementEndIndex; i++) {
416
- const line = lines[i];
417
- if (line.trim()) {
418
- newBlock.push(line);
419
- }
420
- }
421
- }
422
-
423
- newBlock.push(''); // Blank line after requirement
424
-
425
- // Replace the old block with the new one
426
- lines.splice(requirementStartIndex, requirementEndIndex - requirementStartIndex, ...newBlock);
427
-
428
- // Save
429
- await fs.writeFile(reqPath, lines.join('\n'));
430
- console.log(chalk.green('✓ Requirement renamed/updated'));
431
- } catch (error) {
432
- console.error(chalk.red('Error renaming requirement:'), error.message);
433
- process.exit(1);
434
- }
435
- }
436
-
437
- async function working() {
438
- try {
439
- const { reqPath } = await getReqPathOrExit();
440
- if (!await fs.pathExists(reqPath)) {
441
- console.log(chalk.yellow('No REQUIREMENTS.md found.'));
442
- return;
443
- }
444
- const { getCurrentRequirement } = require('vibecodingmachine-core');
445
- // Note: Core's getCurrentRequirement returns "Working on: X" or default text.
446
- // It assumes process.cwd() or similar.
447
- // But wait, Core's getCurrentRequirement takes 'repoPath'.
448
- // And imported from core index.cjs might need repoPath.
449
-
450
- // Let's manually implement it to be safe and use getReqPathOrExit's resolved path
451
- // OR use the core helper but pass the correct repo path.
452
- const { repoPath } = await getReqPathOrExit();
453
- const coreResult = await getCurrentRequirement(repoPath);
454
- console.log(chalk.cyan(coreResult));
455
-
456
- } catch (error) {
457
- console.error(chalk.red('Error getting working requirement:'), error.message);
458
- process.exit(1);
459
- }
460
- }
461
-
462
- async function numberAll() {
463
- try {
464
- const { reqPath, repoPath } = await getReqPathOrExit();
465
- if (!await fs.pathExists(reqPath)) {
466
- console.log(chalk.yellow('No REQUIREMENTS.md found.'));
467
- return;
468
- }
469
-
470
- console.log(chalk.cyan('Numbering all existing requirements...'));
471
- const { numberAllRequirements } = require('vibecodingmachine-core');
472
- const numbered = await numberAllRequirements(reqPath, repoPath);
473
-
474
- console.log(chalk.green(`✓ Numbered ${numbered} requirements`));
475
- } catch (error) {
476
- console.error(chalk.red('Error numbering requirements:'), error.message);
477
- process.exit(1);
478
- }
479
- }
480
-
481
- // Default Requirement Management Functions
482
-
483
1
  /**
484
- * Create a new default requirement
2
+ * Refactored Requirements Commands
3
+ *
4
+ * Splits monolithic requirements command into modular components
485
5
  */
486
- async function createDefault(title, options = {}) {
487
- const { description, maxIterations } = options;
488
- const repoPath = await getRepoPath();
489
-
490
- if (!repoPath) {
491
- console.log(chalk.red('✗ No repository configured'));
492
- return;
493
- }
494
-
495
- if (!title) {
496
- console.log(chalk.red('✗ Title is required'));
497
- console.log(chalk.gray('Usage: vcm req:default create "Title" --description "Description" --max-iterations 10'));
498
- return;
499
- }
500
6
 
501
- if (!description) {
502
- console.log(chalk.red('✗ Description is required'));
503
- console.log(chalk.gray('Usage: vcm req:default create "Title" --description "Description" --max-iterations 10'));
504
- return;
505
- }
506
-
507
- const iterations = maxIterations || 10;
508
-
509
- try {
510
- const storage = new JSONStorage();
511
- const manager = new DefaultRequirementManager(storage);
512
-
513
- const requirement = await manager.create({
514
- title: title.trim(),
515
- description: description.trim(),
516
- maxIterations: iterations
517
- });
518
-
519
- console.log(chalk.bold.green('✅ Default requirement created'));
520
- console.log(chalk.cyan(` Title: ${requirement.title}`));
521
- console.log(chalk.cyan(` Description: ${requirement.description}`));
522
- console.log(chalk.cyan(` Max Iterations: ${requirement.maxIterations}`));
523
- console.log(chalk.cyan(` Status: ${requirement.status}`));
524
- console.log();
525
- } catch (error) {
526
- console.log(chalk.red('✗ Failed to create default requirement:'), error.message);
527
- }
528
- }
529
-
530
- /**
531
- * Edit existing default requirement
532
- */
533
- async function editDefault(options = {}) {
534
- const { title, description, maxIterations } = options;
535
- const repoPath = await getRepoPath();
536
-
537
- if (!repoPath) {
538
- console.log(chalk.red('✗ No repository configured'));
539
- return;
540
- }
541
-
542
- if (!title && !description && !maxIterations) {
543
- console.log(chalk.red('✗ At least one field to update is required'));
544
- console.log(chalk.gray('Usage: vcm req:default edit --title "New Title" --description "New Description" --max-iterations 20'));
545
- return;
546
- }
547
-
548
- try {
549
- const storage = new JSONStorage();
550
- const manager = new DefaultRequirementManager(storage);
551
-
552
- const updates = {};
553
- if (title !== undefined) updates.title = title.trim();
554
- if (description !== undefined) updates.description = description.trim();
555
- if (maxIterations !== undefined) updates.maxIterations = maxIterations;
556
-
557
- const requirement = await manager.edit(updates);
558
-
559
- console.log(chalk.bold.green('✅ Default requirement updated'));
560
- console.log(chalk.cyan(` Title: ${requirement.title}`));
561
- console.log(chalk.cyan(` Description: ${requirement.description}`));
562
- console.log(chalk.cyan(` Max Iterations: ${requirement.maxIterations}`));
563
- console.log(chalk.cyan(` Status: ${requirement.status}`));
564
- if (requirement.updatedAt) {
565
- console.log(chalk.gray(` Updated: ${new Date(requirement.updatedAt).toLocaleString()}`));
566
- }
567
- console.log();
568
- } catch (error) {
569
- console.log(chalk.red('✗ Failed to edit default requirement:'), error.message);
570
- }
571
- }
572
-
573
- /**
574
- * Delete default requirement
575
- */
576
- async function deleteDefault() {
577
- const repoPath = await getRepoPath();
578
-
579
- if (!repoPath) {
580
- console.log(chalk.red('✗ No repository configured'));
581
- return;
582
- }
583
-
584
- try {
585
- const storage = new JSONStorage();
586
- const manager = new DefaultRequirementManager(storage);
587
-
588
- const status = await manager.getStatus();
589
- if (!status) {
590
- console.log(chalk.yellow('⚠️ No default requirement exists'));
591
- return;
592
- }
593
-
594
- console.log(chalk.bold.yellow(`Deleting default requirement: ${status.title}`));
595
-
596
- await manager.delete();
597
-
598
- console.log(chalk.bold.green('✅ Default requirement deleted'));
599
- console.log();
600
- } catch (error) {
601
- console.log(chalk.red('✗ Failed to delete default requirement:'), error.message);
602
- }
603
- }
604
-
605
- /**
606
- * Show current default requirement status
607
- */
608
- async function showDefault() {
609
- const repoPath = await getRepoPath();
610
-
611
- if (!repoPath) {
612
- console.log(chalk.red('✗ No repository configured'));
613
- return;
614
- }
615
-
616
- try {
617
- const storage = new JSONStorage();
618
- const manager = new DefaultRequirementManager(storage);
619
-
620
- const status = await manager.getStatus();
621
- if (!status) {
622
- console.log(chalk.yellow('⚠️ No default requirement exists'));
623
- console.log(chalk.gray('Create one with: vcm req:default create "Title" --description "Description" --max-iterations 10'));
624
- console.log();
625
- return;
626
- }
627
-
628
- const statistics = await manager.getStatistics();
629
-
630
- console.log(chalk.bold.cyan('📋 Default Requirement Status'));
631
- console.log(chalk.gray('─'.repeat(50)));
632
- console.log(chalk.cyan(`Title: ${status.title}`));
633
- console.log(chalk.cyan(`Description: ${status.description}`));
634
- console.log(chalk.cyan(`Status: ${status.status}`));
635
- console.log(chalk.cyan(`Iterations: ${status.iterationCount}/${status.maxIterations}`));
636
- console.log(chalk.cyan(`Consecutive Failures: ${status.consecutiveFailures}`));
637
-
638
- if (statistics) {
639
- console.log(chalk.cyan(`Completion: ${statistics.completionPercentage}%`));
640
- console.log(chalk.cyan(`Age: ${statistics.ageHours}h`));
641
- if (statistics.iterationsPerHour > 0) {
642
- console.log(chalk.cyan(`Rate: ${statistics.iterationsPerHour} iterations/hour`));
643
- }
644
- }
645
-
646
- if (status.createdAt) {
647
- console.log(chalk.gray(`Created: ${new Date(status.createdAt).toLocaleString()}`));
648
- }
649
- if (status.lastIterationAt) {
650
- console.log(chalk.gray(`Last iteration: ${new Date(status.lastIterationAt).toLocaleString()}`));
651
- }
652
- if (status.pausedAt) {
653
- console.log(chalk.yellow(`Paused: ${new Date(status.pausedAt).toLocaleString()}`));
654
- }
655
- if (status.resumedAt) {
656
- console.log(chalk.green(`Resumed: ${new Date(status.resumedAt).toLocaleString()}`));
657
- }
658
- if (status.completedAt) {
659
- console.log(chalk.green(`Completed: ${new Date(status.completedAt).toLocaleString()}`));
660
- console.log(chalk.green(`Reason: ${status.completionReason}`));
661
- }
662
-
663
- console.log();
664
- } catch (error) {
665
- console.log(chalk.red('✗ Failed to get default requirement status:'), error.message);
666
- }
667
- }
668
-
669
- /**
670
- * Pause default requirement
671
- */
672
- async function pauseDefault() {
673
- const repoPath = await getRepoPath();
674
-
675
- if (!repoPath) {
676
- console.log(chalk.red('✗ No repository configured'));
677
- return;
678
- }
679
-
680
- try {
681
- const storage = new JSONStorage();
682
- const manager = new DefaultRequirementManager(storage);
683
-
684
- const status = await manager.getStatus();
685
- if (!status) {
686
- console.log(chalk.yellow('⚠️ No default requirement exists'));
687
- return;
688
- }
689
-
690
- if (status.status === 'PAUSED') {
691
- console.log(chalk.yellow('⚠️ Default requirement is already paused'));
692
- return;
693
- }
694
-
695
- await manager.pause();
696
-
697
- console.log(chalk.bold.green('✅ Default requirement paused'));
698
- console.log(chalk.cyan(` Title: ${status.title}`));
699
- console.log();
700
- } catch (error) {
701
- console.log(chalk.red('✗ Failed to pause default requirement:'), error.message);
702
- }
703
- }
704
-
705
- /**
706
- * Resume default requirement
707
- */
708
- async function resumeDefault() {
709
- const repoPath = await getRepoPath();
710
-
711
- if (!repoPath) {
712
- console.log(chalk.red('✗ No repository configured'));
713
- return;
714
- }
715
-
716
- try {
717
- const storage = new JSONStorage();
718
- const manager = new DefaultRequirementManager(storage);
719
-
720
- const status = await manager.getStatus();
721
- if (!status) {
722
- console.log(chalk.yellow('⚠️ No default requirement exists'));
723
- return;
724
- }
725
-
726
- if (status.status === 'ACTIVE') {
727
- console.log(chalk.yellow('⚠️ Default requirement is already active'));
728
- return;
729
- }
730
-
731
- await manager.resume();
732
-
733
- console.log(chalk.bold.green('✅ Default requirement resumed'));
734
- console.log(chalk.cyan(` Title: ${status.title}`));
735
- console.log();
736
- } catch (error) {
737
- console.log(chalk.red('✗ Failed to resume default requirement:'), error.message);
738
- }
739
- }
740
-
741
- /**
742
- * Set max iterations for default requirement
743
- */
744
- async function setMaxIterations(maxIterations) {
745
- const repoPath = await getRepoPath();
746
-
747
- if (!repoPath) {
748
- console.log(chalk.red('✗ No repository configured'));
749
- return;
750
- }
751
-
752
- if (!maxIterations || maxIterations < 1 || maxIterations > 1000) {
753
- console.log(chalk.red('✗ Max iterations must be between 1 and 1000'));
754
- return;
755
- }
756
-
757
- try {
758
- const storage = new JSONStorage();
759
- const manager = new DefaultRequirementManager(storage);
760
-
761
- const requirement = await manager.edit({ maxIterations });
7
+ // Import command modules
8
+ const {
9
+ list,
10
+ add,
11
+ current,
12
+ next,
13
+ edit,
14
+ watch,
15
+ rename,
16
+ working,
17
+ numberAll
18
+ } = require('./requirements/commands');
762
19
 
763
- console.log(chalk.bold.green('✅ Max iterations updated'));
764
- console.log(chalk.cyan(` Max Iterations: ${requirement.maxIterations}`));
765
- console.log(chalk.cyan(` Current Iterations: ${requirement.iterationCount}`));
766
- console.log();
767
- } catch (error) {
768
- console.log(chalk.red('✗ Failed to set max iterations:'), error.message);
769
- }
770
- }
20
+ const {
21
+ createDefault,
22
+ editDefault,
23
+ deleteDefault,
24
+ showDefault,
25
+ pauseDefault,
26
+ resumeDefault,
27
+ setMaxIterations
28
+ } = require('./requirements/default-handlers');
771
29
 
30
+ // Export all commands for compatibility
772
31
  module.exports = {
32
+ // Basic requirement commands
773
33
  list,
774
34
  add,
775
35
  current,
776
- working,
777
36
  next,
778
37
  edit,
779
38
  watch,
780
39
  rename,
40
+ working,
781
41
  numberAll,
42
+
782
43
  // Default requirement commands
44
+ 'default:create': createDefault,
45
+ 'default:edit': editDefault,
46
+ 'default:delete': deleteDefault,
47
+ 'default:show': showDefault,
48
+ 'default:pause': pauseDefault,
49
+ 'default:resume': resumeDefault,
50
+ 'default:max-iterations': setMaxIterations,
51
+
52
+ // Aliases for backward compatibility
783
53
  createDefault,
784
54
  editDefault,
785
- delete: deleteDefault,
55
+ deleteDefault,
786
56
  showDefault,
787
57
  pauseDefault,
788
58
  resumeDefault,
789
59
  setMaxIterations
790
60
  };
791
-
792
-
793
-