vibecodingmachine-cli 2026.2.26-1739 → 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 +5 -1
  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
@@ -28,6 +28,12 @@ async function loadRequirementsData(navigation) {
28
28
  }
29
29
  }
30
30
 
31
+ // Track expanded requirement indices
32
+ const expandedRequirements = new Set();
33
+
34
+ // Track selected requirements for multi-select delete
35
+ const selectedRequirements = new Set();
36
+
31
37
  /**
32
38
  * Build inline accordion choice objects for the requirements section.
33
39
  * Requirements are grouped by status with Separator headers.
@@ -38,7 +44,10 @@ function buildRequirementChoices(data) {
38
44
  const requirements = (data && data.requirements) || [];
39
45
 
40
46
  if (!requirements.length) {
41
- return [{ name: chalk.gray(' (no requirements found)'), value: 'noop' }];
47
+ return [
48
+ { name: chalk.yellow(' No requirements found'), value: 'noop' },
49
+ { name: chalk.cyan(' [+ Add Requirement]'), value: 'add-requirement' }
50
+ ];
42
51
  }
43
52
 
44
53
  const sections = {
@@ -59,15 +68,44 @@ function buildRequirementChoices(data) {
59
68
  const isDisabled = req.title.startsWith('DISABLED:');
60
69
  const cleanTitle = isDisabled ? req.title.replace(/^DISABLED:\s*/, '') : req.title;
61
70
  const disabledIcon = isDisabled ? chalk.red('🚫') : '';
71
+ const isExpanded = expandedRequirements.has(idx);
72
+ const expandIcon = isExpanded ? '▼' : '▶';
73
+ const isSelected = selectedRequirements.has(idx);
74
+ const selectIcon = isSelected ? chalk.red('[✓]') : '[ ]';
75
+
62
76
  choices.push({
63
- name: ` ${disabledIcon}${icon} ${chalk.white(cleanTitle)}`,
77
+ name: ` ${selectIcon} ${disabledIcon}${icon} ${expandIcon} ${chalk.white(cleanTitle)}`,
64
78
  value: `req:${idx}`,
65
79
  });
80
+
81
+ // If expanded, add full details inline
82
+ if (isExpanded) {
83
+ const details = [];
84
+ if (req.description) {
85
+ details.push(chalk.gray(` Description: ${req.description}`));
86
+ }
87
+ if (req.acceptanceCriteria && req.acceptanceCriteria.length > 0) {
88
+ details.push(chalk.gray(` Acceptance Criteria:`));
89
+ req.acceptanceCriteria.forEach(ac => {
90
+ details.push(chalk.gray(` • ${ac}`));
91
+ });
92
+ }
93
+ if (req.dependencies && req.dependencies.length > 0) {
94
+ details.push(chalk.gray(` Dependencies: ${req.dependencies.join(', ')}`));
95
+ }
96
+ if (details.length > 0) {
97
+ details.forEach(detail => {
98
+ choices.push(new inquirer.Separator(detail));
99
+ });
100
+ } else {
101
+ choices.push(new inquirer.Separator(chalk.gray(' (no additional details)')));
102
+ }
103
+ }
66
104
  });
67
105
  };
68
106
 
69
107
  addSection('📌 CURRENT', sections.current, chalk.cyan('●'));
70
- addSection('⏳ TODO', sections.todo, chalk.yellow('○'));
108
+ addSection('⏳ TODO REQUIREMENTS', sections.todo, chalk.yellow('○'));
71
109
  addSection('🔍 TO VERIFY', sections.verify, chalk.blue('◎'));
72
110
  addSection('✅ VERIFIED', sections.verified, chalk.green('✓'));
73
111
  addSection('❓ NEED INFO', sections['need-information'], chalk.red('?'));
@@ -76,7 +114,7 @@ function buildRequirementChoices(data) {
76
114
  }
77
115
 
78
116
  /**
79
- * Handle selection of a requirement item — shows status-change sub-prompt
117
+ * Handle selection of a requirement item — toggles inline expand/collapse
80
118
  * @param {number} index - Index into data.requirements
81
119
  * @param {{requirements: Array}} data
82
120
  * @param {Object} navigation - TRUINavigation instance
@@ -87,6 +125,145 @@ async function handleRequirementSelection(index, data, navigation) {
87
125
 
88
126
  const req = data.requirements[index];
89
127
 
128
+ // Check if currently expanded - if so, collapse and return
129
+ if (expandedRequirements.has(index)) {
130
+ expandedRequirements.delete(index);
131
+ return true; // Refresh to show collapsed state
132
+ }
133
+
134
+ // First press expands inline
135
+ expandedRequirements.add(index);
136
+ return true; // Refresh to show expanded state
137
+ }
138
+
139
+ /**
140
+ * Handle moving a requirement up or down within its section
141
+ * @param {number} index - Index into data.requirements
142
+ * @param {{requirements: Array}} data
143
+ * @param {string} direction - 'up' or 'down'
144
+ * @returns {Promise<boolean>} true if requirements were changed
145
+ */
146
+ async function handleRequirementMove(index, data, direction) {
147
+ if (!data || !data.requirements || !data.requirements[index]) return false;
148
+
149
+ const req = data.requirements[index];
150
+
151
+ try {
152
+ const { moveRequirement, getOrCreateRequirementsFilePath } = require('vibecodingmachine-core');
153
+ const reqPath = await getOrCreateRequirementsFilePath();
154
+ const success = await moveRequirement(reqPath, req.title, direction);
155
+
156
+ if (success) {
157
+ console.log(chalk.green(`\n✓ Moved "${req.title}" ${direction}`));
158
+ }
159
+
160
+ return success;
161
+ } catch (err) {
162
+ console.log(chalk.red(`Error moving requirement: ${err.message}`));
163
+ return false;
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Handle multi-select toggle for a requirement
169
+ * @param {number} index - Index into data.requirements
170
+ * @returns {boolean} true to trigger refresh
171
+ */
172
+ function handleRequirementToggleSelect(index) {
173
+ if (selectedRequirements.has(index)) {
174
+ selectedRequirements.delete(index);
175
+ } else {
176
+ selectedRequirements.add(index);
177
+ }
178
+ return true;
179
+ }
180
+
181
+ /**
182
+ * Handle deleting selected requirements
183
+ * @param {{requirements: Array}} data
184
+ * @param {Object} navigation - TRUINavigation instance
185
+ * @returns {Promise<boolean>} true if requirements were changed
186
+ */
187
+ async function handleRequirementDelete(data, navigation) {
188
+ if (!data || !data.requirements) return false;
189
+
190
+ if (selectedRequirements.size === 0) {
191
+ console.log(chalk.yellow('\n⚠ No requirements selected for deletion'));
192
+ console.log(chalk.gray('Use Space key to select requirements, then press Delete/Backspace'));
193
+ await navigation.promptContinue();
194
+ return false;
195
+ }
196
+
197
+ const requirementsToDelete = Array.from(selectedRequirements)
198
+ .map(idx => data.requirements[idx])
199
+ .filter(Boolean);
200
+
201
+ if (requirementsToDelete.length === 0) return false;
202
+
203
+ console.log(chalk.bold.red(`\n⚠ Delete ${requirementsToDelete.length} requirement(s)?\n`));
204
+ requirementsToDelete.forEach(req => {
205
+ const cleanTitle = req.title.startsWith('DISABLED:')
206
+ ? req.title.replace(/^DISABLED:\s*/, '')
207
+ : req.title;
208
+ console.log(chalk.red(` • ${cleanTitle}`));
209
+ });
210
+ console.log('');
211
+
212
+ const { confirmDelete } = await inquirer.prompt([
213
+ {
214
+ type: 'confirm',
215
+ name: 'confirmDelete',
216
+ message: chalk.red('Are you sure you want to delete these requirements?'),
217
+ default: false,
218
+ },
219
+ ]);
220
+
221
+ if (!confirmDelete) {
222
+ console.log(chalk.gray('Deletion cancelled'));
223
+ await navigation.promptContinue();
224
+ return false;
225
+ }
226
+
227
+ try {
228
+ const { deleteRequirements, getOrCreateRequirementsFilePath } = require('vibecodingmachine-core');
229
+ const reqPath = await getOrCreateRequirementsFilePath();
230
+ const titles = requirementsToDelete.map(req => req.title);
231
+
232
+ const result = await deleteRequirements(reqPath, titles);
233
+
234
+ if (result.success) {
235
+ console.log(chalk.green(`\n✓ Deleted ${result.deleted} requirement(s)`));
236
+ if (result.errors.length > 0) {
237
+ result.errors.forEach(err => console.log(chalk.yellow(` ⚠ ${err}`)));
238
+ }
239
+ selectedRequirements.clear();
240
+ await navigation.promptContinue();
241
+ return true;
242
+ } else {
243
+ console.log(chalk.red(`\nError deleting requirements`));
244
+ result.errors.forEach(err => console.log(chalk.red(` • ${err}`)));
245
+ await navigation.promptContinue();
246
+ return false;
247
+ }
248
+ } catch (err) {
249
+ console.log(chalk.red(`Error deleting requirements: ${err.message}`));
250
+ await navigation.promptContinue();
251
+ return false;
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Handle action menu for a requirement (status changes, enable/disable)
257
+ * @param {number} index - Index into data.requirements
258
+ * @param {{requirements: Array}} data
259
+ * @param {Object} navigation - TRUINavigation instance
260
+ * @returns {Promise<boolean>} true if requirements were changed
261
+ */
262
+ async function handleRequirementAction(index, data, navigation) {
263
+ if (!data || !data.requirements || !data.requirements[index]) return false;
264
+
265
+ const req = data.requirements[index];
266
+
90
267
  const {
91
268
  promoteToVerified,
92
269
  demoteFromVerifiedToTodo,
@@ -97,7 +274,7 @@ async function handleRequirementSelection(index, data, navigation) {
97
274
 
98
275
  const statusLabel = {
99
276
  current: chalk.cyan('CURRENT'),
100
- todo: chalk.yellow('TODO'),
277
+ todo: chalk.yellow('TODO REQUIREMENTS'),
101
278
  verify: chalk.blue('TO VERIFY'),
102
279
  verified: chalk.green('VERIFIED'),
103
280
  'need-information': chalk.red('NEED INFO'),
@@ -123,7 +300,7 @@ async function handleRequirementSelection(index, data, navigation) {
123
300
 
124
301
  const { reqAction } = await inquirer.prompt([
125
302
  {
126
- type: 'list',
303
+ type: 'rawlist',
127
304
  name: 'reqAction',
128
305
  message: `${cleanTitle} [${statusLabel}]`,
129
306
  choices,
@@ -150,28 +327,22 @@ async function handleRequirementSelection(index, data, navigation) {
150
327
  } else if (reqAction === 'moveToVerified') {
151
328
  await promoteToVerified(reqPath, req.title);
152
329
  } else if (reqAction === 'enable' || reqAction === 'disable') {
153
- // Toggle disabled status
154
- const content = await fs.readFile(reqPath, 'utf8');
155
- const lines = content.split('\n');
156
-
157
- // Find the requirement line
158
- for (let i = 0; i < lines.length; i++) {
159
- if (lines[i].includes(req.title)) {
160
- if (reqAction === 'enable') {
161
- // Remove DISABLED: prefix
162
- lines[i] = lines[i].replace(/^###\s*DISABLED:\s*/, '### ');
163
- } else {
164
- // Add DISABLED: prefix
165
- lines[i] = lines[i].replace(/^###\s*/, '### DISABLED: ');
166
- }
167
- break;
168
- }
330
+ // Use the new enable/disable utility functions
331
+ const { enableRequirement, disableRequirement } = require('@vibecodingmachine/core/src/utils/requirement-enable-disable');
332
+
333
+ let result;
334
+ if (reqAction === 'enable') {
335
+ result = await enableRequirement(cleanTitle);
336
+ } else {
337
+ result = await disableRequirement(cleanTitle);
338
+ }
339
+
340
+ if (result.success) {
341
+ console.log(chalk.green(`\n✓ ${result.message}`));
342
+ console.log(chalk.gray(` Equivalent: app ${reqAction} requirement "${cleanTitle}"`));
343
+ } else {
344
+ console.log(chalk.red(`\n❌ ${result.message}`));
169
345
  }
170
-
171
- await fs.writeFile(reqPath, lines.join('\n'), 'utf8');
172
- const action = reqAction === 'enable' ? 'enabled' : 'disabled';
173
- console.log(chalk.green(`\n✓ Requirement "${cleanTitle}" ${action}`));
174
- console.log(chalk.gray(` Equivalent: app requirements ${cleanTitle} ${reqAction}`));
175
346
  await navigation.promptContinue();
176
347
  return true;
177
348
  }
@@ -264,5 +435,10 @@ module.exports = {
264
435
  loadRequirementsData,
265
436
  buildRequirementChoices,
266
437
  handleRequirementSelection,
438
+ handleRequirementAction,
439
+ handleRequirementMove,
440
+ handleRequirementToggleSelect,
441
+ handleRequirementDelete,
267
442
  addRequirementFlow,
443
+ selectedRequirements,
268
444
  };
@@ -6,6 +6,7 @@
6
6
 
7
7
  const inquirer = require('inquirer');
8
8
  const chalk = require('chalk');
9
+ const { getHostname, isComputerNameEnabled, enableComputerName, disableComputerName, setHostname } = require('vibecodingmachine-core');
9
10
 
10
11
  /**
11
12
  * Load settings data via the RUI command resolver
@@ -75,7 +76,7 @@ async function handleSettingSelection(key, data, navigation) {
75
76
  */
76
77
  async function showSettings() {
77
78
  const { showQuickMenu } = require('./trui-quick-menu');
78
- const { getAutoConfig, getRepoPath, getStages, setAutoConfig } = require('./config');
79
+ const { getAutoConfig, getRepoPath, getStages, setStages, setAutoConfig } = require('./config');
79
80
  const { getProviderPreferences } = require('./provider-registry');
80
81
  const inquirer = require('inquirer');
81
82
 
@@ -89,8 +90,13 @@ async function showSettings() {
89
90
  const repoPath = await getRepoPath();
90
91
  const autoConfig = await getAutoConfig();
91
92
  const prefs = await getProviderPreferences();
93
+ const stages = await getStages();
92
94
  // Find first enabled provider in order for display
93
95
  let activeIde = autoConfig.ide || autoConfig.agent || 'cline';
96
+
97
+ // Get hostname info
98
+ const currentHostname = getHostname();
99
+ const hostnameEnabled = isComputerNameEnabled();
94
100
 
95
101
  const items = [];
96
102
  items.push({ type: 'setting', name: `Repo: ${chalk.white(repoPath || '(not set)')}`, value: 'setting:repo' });
@@ -98,6 +104,8 @@ async function showSettings() {
98
104
  items.push({ type: 'setting', name: `Max Chats: ${chalk.white(autoConfig.maxChats || '(unlimited)')}`, value: 'setting:maxChats' });
99
105
  items.push({ type: 'setting', name: `Never Stop: ${chalk.white(autoConfig.neverStop ? 'true' : 'false')}`, value: 'setting:neverStop' });
100
106
  items.push({ type: 'setting', name: `Skip Disabled: ${chalk.white(autoConfig.skipDisabled ? 'true' : 'false')}`, value: 'setting:skipDisabled' });
107
+ items.push({ type: 'setting', name: `Hostname: ${chalk.white(currentHostname)} (${hostnameEnabled ? 'enabled' : 'disabled'})`, value: 'setting:hostname' });
108
+ items.push({ type: 'setting', name: `Stages: ${chalk.white(stages.join(', '))}`, value: 'setting:stages' });
101
109
  return items;
102
110
  };
103
111
 
@@ -143,6 +151,111 @@ async function showSettings() {
143
151
  } else if (value === 'setting:skipDisabled') {
144
152
  const autoConfig = await getAutoConfig();
145
153
  await setAutoConfig({ skipDisabled: !autoConfig.skipDisabled });
154
+ } else if (value === 'setting:hostname') {
155
+ const hostnameEnabled = isComputerNameEnabled();
156
+ const currentHostname = getHostname();
157
+
158
+ const { action } = await inquirer.prompt([{
159
+ type: 'list',
160
+ name: 'action',
161
+ message: 'Hostname settings:',
162
+ choices: [
163
+ { name: `Change hostname (current: ${currentHostname})`, value: 'change' },
164
+ { name: hostnameEnabled ? 'Disable hostname filtering' : 'Enable hostname filtering', value: 'toggle' },
165
+ { name: 'Back', value: 'back' }
166
+ ]
167
+ }]);
168
+
169
+ if (action === 'change') {
170
+ const { newHostname } = await inquirer.prompt([{
171
+ type: 'input',
172
+ name: 'newHostname',
173
+ message: 'Enter new hostname:',
174
+ default: currentHostname,
175
+ validate: input => {
176
+ if (!input.trim()) return 'Hostname cannot be empty';
177
+ if (!/^[a-zA-Z0-9-]+$/.test(input.trim())) {
178
+ return 'Hostname can only contain letters, numbers, and hyphens';
179
+ }
180
+ return true;
181
+ }
182
+ }]);
183
+
184
+ try {
185
+ await setHostname(newHostname.trim());
186
+ console.log(chalk.green(`✅ Hostname changed to: ${newHostname}`));
187
+ } catch (error) {
188
+ console.error(chalk.red('❌ Error changing hostname:'), error.message);
189
+ }
190
+ await inquirer.prompt([{ type: 'input', name: 'c', message: chalk.gray('Press Enter...') }]);
191
+ } else if (action === 'toggle') {
192
+ try {
193
+ if (hostnameEnabled) {
194
+ await disableComputerName();
195
+ console.log(chalk.green('✅ Hostname filtering disabled'));
196
+ } else {
197
+ await enableComputerName();
198
+ console.log(chalk.green('✅ Hostname filtering enabled'));
199
+ }
200
+ } catch (error) {
201
+ console.error(chalk.red('❌ Error toggling hostname filtering:'), error.message);
202
+ }
203
+ await inquirer.prompt([{ type: 'input', name: 'c', message: chalk.gray('Press Enter...') }]);
204
+ }
205
+ } else if (value === 'setting:stages') {
206
+ const stages = await getStages();
207
+
208
+ const { action } = await inquirer.prompt([{
209
+ type: 'list',
210
+ name: 'action',
211
+ message: 'Stage configuration:',
212
+ choices: [
213
+ { name: `Edit stages (current: ${stages.join(', ')})`, value: 'edit' },
214
+ { name: 'Reset to default stages', value: 'reset' },
215
+ { name: 'Back', value: 'back' }
216
+ ]
217
+ }]);
218
+
219
+ if (action === 'edit') {
220
+ const { newStages } = await inquirer.prompt([{
221
+ type: 'input',
222
+ name: 'newStages',
223
+ message: 'Enter stages (comma-separated):',
224
+ default: stages.join(', '),
225
+ validate: input => {
226
+ const stageList = input.split(',').map(s => s.trim()).filter(s => s);
227
+ if (stageList.length === 0) return 'At least one stage is required';
228
+
229
+ // Check for duplicate stages
230
+ const duplicates = stageList.filter((stage, index) => stageList.indexOf(stage) !== index);
231
+ if (duplicates.length > 0) return `Duplicate stages: ${duplicates.join(', ')}`;
232
+
233
+ // Check for valid stage names (alphanumeric with hyphens/underscores)
234
+ const invalidStages = stageList.filter(stage => !/^[a-zA-Z0-9_-]+$/.test(stage));
235
+ if (invalidStages.length > 0) return `Invalid stage names: ${invalidStages.join(', ')}`;
236
+
237
+ return true;
238
+ }
239
+ }]);
240
+
241
+ try {
242
+ const stageList = newStages.split(',').map(s => s.trim()).filter(s => s);
243
+ await setStages(stageList);
244
+ console.log(chalk.green(`✅ Stages updated to: ${stageList.join(', ')}`));
245
+ } catch (error) {
246
+ console.error(chalk.red('❌ Error updating stages:'), error.message);
247
+ }
248
+ await inquirer.prompt([{ type: 'input', name: 'c', message: chalk.gray('Press Enter...') }]);
249
+ } else if (action === 'reset') {
250
+ try {
251
+ const { DEFAULT_STAGES } = require('./config');
252
+ await setStages(DEFAULT_STAGES);
253
+ console.log(chalk.green(`✅ Stages reset to default: ${DEFAULT_STAGES.join(', ')}`));
254
+ } catch (error) {
255
+ console.error(chalk.red('❌ Error resetting stages:'), error.message);
256
+ }
257
+ await inquirer.prompt([{ type: 'input', name: 'c', message: chalk.gray('Press Enter...') }]);
258
+ }
146
259
  }
147
260
 
148
261
  printHeader();
@@ -43,7 +43,7 @@ function buildSpecificationChoices(specs) {
43
43
  }
44
44
 
45
45
  /**
46
- * Handle selection of a specification item — shows detail
46
+ * Handle selection of a specification item — shows detail with enable/disable options
47
47
  * @param {string} directory - Spec directory name
48
48
  * @param {Array} specs
49
49
  * @param {Object} navigation - TRUINavigation instance
@@ -57,13 +57,54 @@ async function handleSpecificationSelection(directory, specs, navigation) {
57
57
  return;
58
58
  }
59
59
 
60
+ const { enableSpec, disableSpec, isSpecDisabled } = require('@vibecodingmachine/core/src/utils/specification-enable-disable');
61
+ const isDisabled = await isSpecDisabled(directory);
62
+
60
63
  console.log(chalk.bold.cyan(`\n📐 ${spec.title || spec.directory}\n`));
61
64
  console.log(chalk.white(` Directory: ${spec.directory}`));
62
65
  console.log(chalk.white(` Path: ${spec.path}`));
66
+ console.log(chalk.white(` Status: ${isDisabled ? chalk.red('Disabled') : chalk.green('Enabled')}`));
63
67
  console.log(chalk.white(` Has Plan: ${spec.hasPlan ? chalk.green('Yes') : chalk.gray('No')}`));
64
68
  console.log(chalk.white(` Has Tasks: ${spec.hasTasks ? chalk.green('Yes') : chalk.yellow('No (TODO)')}`));
65
69
 
66
- await navigation.promptContinue();
70
+ // Show action options
71
+ console.log(chalk.bold.white('\nActions:'));
72
+ const choices = [
73
+ { name: 'Back to menu', value: 'back' }
74
+ ];
75
+
76
+ if (isDisabled) {
77
+ choices.unshift({ name: chalk.green('[e] Enable specification'), value: 'enable' });
78
+ } else {
79
+ choices.unshift({ name: chalk.red('[d] Disable specification'), value: 'disable' });
80
+ }
81
+
82
+ const { action } = await inquirer.prompt([
83
+ {
84
+ type: 'list',
85
+ name: 'action',
86
+ message: chalk.cyan('Choose action:'),
87
+ choices
88
+ }
89
+ ]);
90
+
91
+ if (action === 'enable') {
92
+ const result = await enableSpec(directory);
93
+ if (result.success) {
94
+ console.log(chalk.green(`\n✅ ${result.message}`));
95
+ } else {
96
+ console.log(chalk.red(`\n❌ ${result.message}`));
97
+ }
98
+ await navigation.promptContinue();
99
+ } else if (action === 'disable') {
100
+ const result = await disableSpec(directory);
101
+ if (result.success) {
102
+ console.log(chalk.green(`\n✅ ${result.message}`));
103
+ } else {
104
+ console.log(chalk.red(`\n❌ ${result.message}`));
105
+ }
106
+ await navigation.promptContinue();
107
+ }
67
108
  }
68
109
 
69
110
  /**
@@ -103,7 +144,7 @@ async function addSpecificationFlow(navigation) {
103
144
  }
104
145
  const specPrompt = promptLines.join('\n');
105
146
 
106
- console.log(chalk.gray('\nPlan prompt (optional). Enter blank line to skip.'));
147
+ console.log(chalk.gray('\nTechnical details leave blank to skip.'));
107
148
  const planLines = [];
108
149
  while (true) {
109
150
  const { line } = await inquirer.prompt([