vibecodingmachine-cli 2026.2.20-438 → 2026.2.26-1739
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.
- package/bin/auth/auth-compliance.js +126 -0
- package/bin/cli-program.js +104 -0
- package/bin/cli-setup.js +52 -0
- package/bin/commands/agent-commands.js +310 -0
- package/bin/commands/auto-commands.js +70 -0
- package/bin/commands/command-aliases.js +118 -0
- package/bin/commands/repo-commands.js +39 -0
- package/bin/commands/rui-commands.js +152 -0
- package/bin/config/cli-config.js +394 -0
- package/bin/init/environment-setup.js +84 -0
- package/bin/update/update-checker.js +126 -0
- package/bin/vibecodingmachine-new.js +50 -0
- package/bin/vibecodingmachine.js +29 -663
- package/package.json +8 -2
- package/src/commands/agents/add.js +277 -0
- package/src/commands/agents/check.js +380 -0
- package/src/commands/agents/list.js +471 -0
- package/src/commands/agents/remove.js +351 -0
- package/src/commands/analyze-file-sizes.js +428 -0
- package/src/commands/auto-direct/code-processor.js +282 -0
- package/src/commands/auto-direct/file-scanner.js +266 -0
- package/src/commands/auto-direct/provider-config.js +178 -0
- package/src/commands/auto-direct/provider-manager.js +219 -0
- package/src/commands/auto-direct/requirement-manager.js +172 -0
- package/src/commands/auto-direct/status-display.js +91 -0
- package/src/commands/auto-direct/utils.js +106 -0
- package/src/commands/auto-direct.js +875 -488
- package/src/commands/auto-execution.js +342 -0
- package/src/commands/auto-provider-management.js +102 -0
- package/src/commands/auto-requirement-management.js +161 -0
- package/src/commands/auto-status-helpers.js +141 -0
- package/src/commands/auto.js +105 -5155
- package/src/commands/check-compliance.js +536 -0
- package/src/commands/continuous-scan.js +119 -0
- package/src/commands/ide.js +16 -4
- package/src/commands/refactor-file.js +486 -0
- package/src/commands/requirements.js +301 -2
- package/src/commands/timeout.js +290 -0
- package/src/trui/TruiInterface.js +108 -0
- package/src/trui/agents/AgentInterface.js +580 -0
- package/src/utils/antigravity-installer.js +60 -6
- package/src/utils/clarification-actions.js +290 -0
- package/src/utils/config.js +123 -2
- package/src/utils/first-run.js +5 -5
- package/src/utils/ide-handlers.js +212 -0
- package/src/utils/interactive/clarification-actions.js +348 -0
- package/src/utils/interactive/core-ui.js +265 -0
- package/src/utils/interactive/file-backup.js +237 -0
- package/src/utils/interactive/file-import-export.js +305 -0
- package/src/utils/interactive/file-operations.js +49 -0
- package/src/utils/interactive/file-validation.js +276 -0
- package/src/utils/interactive/interactive-prompts.js +480 -0
- package/src/utils/interactive/requirement-actions.js +127 -0
- package/src/utils/interactive/requirement-crud.js +356 -0
- package/src/utils/interactive/requirements-navigation.js +286 -0
- package/src/utils/interactive.js +390 -3459
- package/src/utils/provider-checker/agent-checker.js +250 -0
- package/src/utils/provider-checker/agent-runner.js +450 -0
- package/src/utils/provider-checker/cli-installer.js +123 -0
- package/src/utils/provider-checker/cli-utils.js +15 -0
- package/src/utils/provider-checker/format-utils.js +32 -0
- package/src/utils/provider-checker/ide-manager.js +72 -0
- package/src/utils/provider-checker/ide-utils.js +71 -0
- package/src/utils/provider-checker/node-detector.js +56 -0
- package/src/utils/provider-checker/node-utils.js +61 -0
- package/src/utils/provider-checker/process-spawn.js +22 -0
- package/src/utils/provider-checker/process-utils.js +37 -0
- package/src/utils/provider-checker/provider-validator.js +160 -0
- package/src/utils/provider-checker/quota-checker.js +54 -0
- package/src/utils/provider-checker/quota-detector.js +44 -0
- package/src/utils/provider-checker/requirements-manager.js +94 -0
- package/src/utils/provider-checker/test-requirements.js +95 -0
- package/src/utils/provider-checker/time-formatter.js +18 -0
- package/src/utils/provider-checker-new.js +14 -0
- package/src/utils/provider-checker.js +12 -407
- package/src/utils/provider-checkers/ide-manager.js +128 -0
- package/src/utils/provider-checkers/node-executable-finder.js +51 -0
- package/src/utils/provider-checkers/provider-checker-core.js +172 -0
- package/src/utils/provider-checkers/provider-checker-main.js +107 -0
- package/src/utils/provider-manager.js +60 -4
- package/src/utils/provider-registry.js +26 -3
- package/src/utils/provider-utils.js +173 -0
- package/src/utils/quota-detectors.js +212 -0
- package/src/utils/requirement-action-handlers.js +288 -0
- package/src/utils/requirement-actions/clarification-actions.js +229 -0
- package/src/utils/requirement-actions/confirmation-prompts.js +93 -0
- package/src/utils/requirement-actions/file-operations.js +92 -0
- package/src/utils/requirement-actions/helpers.js +40 -0
- package/src/utils/requirement-actions/requirement-operations.js +335 -0
- package/src/utils/requirement-actions.js +46 -856
- package/src/utils/requirement-file-operations.js +259 -0
- package/src/utils/requirement-helpers.js +128 -0
- package/src/utils/requirement-management.js +279 -0
- package/src/utils/requirement-navigation.js +146 -0
- package/src/utils/requirement-organization.js +271 -0
- package/src/utils/simple-trui.js +75 -1
- package/src/utils/trui-navigation.js +28 -2
- package/src/utils/trui-req-tree.js +196 -11
- package/src/utils/trui-specifications.js +31 -1
- package/src/utils/interactive-backup.js +0 -5664
- package/src/utils/trui-provider-manager.js +0 -182
|
@@ -2,13 +2,82 @@
|
|
|
2
2
|
* TRUI Requirements Tree Navigator
|
|
3
3
|
*
|
|
4
4
|
* Shows expandable sections using showQuickMenu with letter shortcuts.
|
|
5
|
-
* Sections: TODO SPECIFICATIONS,
|
|
5
|
+
* Sections: TODO SPECIFICATIONS, Verified, To Verify, TODO REQUIREMENTS
|
|
6
6
|
* Each section is collapsible; requirements shown as sub-items when expanded.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const chalk = require('chalk');
|
|
10
10
|
const fs = require('fs-extra');
|
|
11
11
|
const path = require('path');
|
|
12
|
+
const os = require('os');
|
|
13
|
+
|
|
14
|
+
// CLI state management functions
|
|
15
|
+
const getStateFilePath = () => path.join(os.homedir(), '.vibecodingmachine-cli-states.json');
|
|
16
|
+
|
|
17
|
+
const saveCliStates = async (expanded, expandedSpecs) => {
|
|
18
|
+
try {
|
|
19
|
+
const states = {
|
|
20
|
+
expanded: expanded,
|
|
21
|
+
expandedSpecs: Array.from(expandedSpecs)
|
|
22
|
+
};
|
|
23
|
+
await fs.writeFile(getStateFilePath(), JSON.stringify(states, null, 2));
|
|
24
|
+
console.log('💾 Saved CLI list states');
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error('❌ Error saving CLI states:', error.message);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const loadCliStates = async () => {
|
|
31
|
+
try {
|
|
32
|
+
const stateFile = getStateFilePath();
|
|
33
|
+
if (await fs.pathExists(stateFile)) {
|
|
34
|
+
const content = await fs.readFile(stateFile, 'utf8');
|
|
35
|
+
const states = JSON.parse(content);
|
|
36
|
+
console.log('📂 Loaded CLI list states');
|
|
37
|
+
return {
|
|
38
|
+
expanded: states.expanded || { specifications: false, verified: false, verify: false, todo: false, recycled: false },
|
|
39
|
+
expandedSpecs: new Set(states.expandedSpecs || [])
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
console.log('📂 No saved CLI states found, using defaults (all closed)');
|
|
43
|
+
return null;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error('❌ Error loading CLI states:', error.message);
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Create progress bar string with green/orange gradient based on completion percentage
|
|
54
|
+
* @param {number} percentage - Completion percentage (0-100)
|
|
55
|
+
* @param {number} done - Number of completed tasks
|
|
56
|
+
* @param {number} total - Total number of tasks
|
|
57
|
+
* @returns {string} Progress bar with colors
|
|
58
|
+
*/
|
|
59
|
+
function createProgressBar(percentage, done, total) {
|
|
60
|
+
if (total === 0) return chalk.gray(' TODO');
|
|
61
|
+
|
|
62
|
+
const isComplete = percentage === 100;
|
|
63
|
+
if (isComplete) {
|
|
64
|
+
return chalk.bgGreen.black(` ${percentage}%, ${done}/${total} tasks complete`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// For partial progress, split the text background based on actual percentage
|
|
68
|
+
const progressText = `${percentage}%, ${done}/${total} tasks complete`;
|
|
69
|
+
const textLength = progressText.length;
|
|
70
|
+
const splitPoint = Math.floor((percentage / 100) * textLength);
|
|
71
|
+
|
|
72
|
+
const firstHalf = progressText.substring(0, splitPoint);
|
|
73
|
+
const secondHalf = progressText.substring(splitPoint);
|
|
74
|
+
|
|
75
|
+
// Apply green background to percentage portion, orange to remaining
|
|
76
|
+
const greenHalf = chalk.bgGreen.black(firstHalf);
|
|
77
|
+
const orangeHalf = chalk.bgHex('#f59e0b').black(secondHalf);
|
|
78
|
+
|
|
79
|
+
return ` ${greenHalf}${orangeHalf}`;
|
|
80
|
+
}
|
|
12
81
|
|
|
13
82
|
// ─── Data loading (ported from old interactive.js) ───────────────────────────
|
|
14
83
|
|
|
@@ -84,9 +153,14 @@ async function buildTreeItems(sections, expanded, expandedSpecs, specUserStories
|
|
|
84
153
|
const count = reqs.length;
|
|
85
154
|
const isOpen = expanded[key];
|
|
86
155
|
const arrow = isOpen ? '▾' : '▸';
|
|
156
|
+
const percentage = total > 0 ? pct(count) : 0;
|
|
157
|
+
|
|
158
|
+
// Use createProgressBar for consistent colored progress bars
|
|
159
|
+
const progressStr = total > 0 ? ' ' + createProgressBar(percentage, count, total) : ` (${count})`;
|
|
160
|
+
|
|
87
161
|
items.push({
|
|
88
162
|
type: isOpen ? 'header' : 'action',
|
|
89
|
-
name: `${arrow} ${icon} ${label}
|
|
163
|
+
name: `${arrow} ${icon} ${label}${progressStr}`,
|
|
90
164
|
value: `section:${key}`,
|
|
91
165
|
});
|
|
92
166
|
if (expanded[key]) {
|
|
@@ -114,11 +188,27 @@ async function buildTreeItems(sections, expanded, expandedSpecs, specUserStories
|
|
|
114
188
|
const { getSpecsList } = require('./trui-specifications');
|
|
115
189
|
const specs = await getSpecsList();
|
|
116
190
|
const specsCount = specs.length;
|
|
191
|
+
|
|
192
|
+
// Calculate overall specs progress
|
|
193
|
+
let specsTotalTasks = 0;
|
|
194
|
+
let specsDoneTasks = 0;
|
|
195
|
+
specs.forEach(spec => {
|
|
196
|
+
if (spec.taskTotal > 0) {
|
|
197
|
+
specsTotalTasks += spec.taskTotal;
|
|
198
|
+
specsDoneTasks += spec.taskDone;
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
const specsPct = specsTotalTasks > 0 ? Math.round((specsDoneTasks / specsTotalTasks) * 100) : 0;
|
|
202
|
+
|
|
117
203
|
const specsOpen = expanded.specifications;
|
|
118
204
|
const specsArrow = specsOpen ? '▾' : '▸';
|
|
205
|
+
|
|
206
|
+
// Use createProgressBar for consistent colored progress bars
|
|
207
|
+
const specsProgressStr = specsTotalTasks > 0 ? ' ' + createProgressBar(specsPct, specsDoneTasks, specsTotalTasks) : '';
|
|
208
|
+
|
|
119
209
|
items.push({
|
|
120
210
|
type: specsOpen ? 'header' : 'action',
|
|
121
|
-
name: `${specsArrow} 📋 TODO
|
|
211
|
+
name: `${specsArrow} 📋 TODO Specifications${specsProgressStr}`,
|
|
122
212
|
value: 'section:specifications',
|
|
123
213
|
});
|
|
124
214
|
if (specsOpen) {
|
|
@@ -128,7 +218,7 @@ async function buildTreeItems(sections, expanded, expandedSpecs, specUserStories
|
|
|
128
218
|
specs.forEach((spec, idx) => {
|
|
129
219
|
let progressStr = '';
|
|
130
220
|
if (spec.taskTotal > 0) {
|
|
131
|
-
progressStr =
|
|
221
|
+
progressStr = ' ' + createProgressBar(spec.pct, spec.taskDone, spec.taskTotal);
|
|
132
222
|
}
|
|
133
223
|
const isSpecExpanded = expandedSpecs && expandedSpecs.has(idx);
|
|
134
224
|
const specArrow = isSpecExpanded ? '▾' : '▸';
|
|
@@ -150,7 +240,7 @@ async function buildTreeItems(sections, expanded, expandedSpecs, specUserStories
|
|
|
150
240
|
const phaseTitle = typeof phase === 'string' ? phase : phase.title;
|
|
151
241
|
let phaseProgress = '';
|
|
152
242
|
if (phase && typeof phase === 'object' && phase.total > 0) {
|
|
153
|
-
phaseProgress = chalk.gray(`
|
|
243
|
+
phaseProgress = chalk.gray(` ${phase.pct}%, ${phase.done}/${phase.total}`);
|
|
154
244
|
}
|
|
155
245
|
items.push({
|
|
156
246
|
type: 'info',
|
|
@@ -167,9 +257,30 @@ async function buildTreeItems(sections, expanded, expandedSpecs, specUserStories
|
|
|
167
257
|
items.push({ type: 'header', name: '▸ 📋 TODO SPECIFICATIONS', value: 'section:specifications' });
|
|
168
258
|
}
|
|
169
259
|
|
|
170
|
-
addSection('verified', '🎉', '
|
|
171
|
-
addSection('verify', '✅', '
|
|
172
|
-
|
|
260
|
+
addSection('verified', '🎉', 'Verified', sections.verified);
|
|
261
|
+
addSection('verify', '✅', 'To Verify', sections.verify);
|
|
262
|
+
|
|
263
|
+
// Calculate requirements progress
|
|
264
|
+
let reqsTotalTasks = 0;
|
|
265
|
+
let reqsDoneTasks = 0;
|
|
266
|
+
if (sections.todo && sections.todo.length > 0) {
|
|
267
|
+
sections.todo.forEach(req => {
|
|
268
|
+
if (req.total > 0) {
|
|
269
|
+
reqsTotalTasks += req.total;
|
|
270
|
+
reqsDoneTasks += req.done;
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
const reqsPct = reqsTotalTasks > 0 ? Math.round((reqsDoneTasks / reqsTotalTasks) * 100) : 0;
|
|
275
|
+
|
|
276
|
+
// Use createProgressBar for consistent colored progress bars
|
|
277
|
+
const reqsProgressStr = reqsTotalTasks > 0 ? ' ' + createProgressBar(reqsPct, reqsDoneTasks, reqsTotalTasks) : '';
|
|
278
|
+
|
|
279
|
+
const reqsTitle = reqsTotalTasks > 0
|
|
280
|
+
? `TODO Requirements${reqsProgressStr}`
|
|
281
|
+
: 'TODO Requirements';
|
|
282
|
+
|
|
283
|
+
addSection('todo', '⏳', reqsTitle, sections.todo);
|
|
173
284
|
|
|
174
285
|
if (sections.recycled && sections.recycled.length > 0) {
|
|
175
286
|
addSection('recycled', '♻️', 'RECYCLED', sections.recycled);
|
|
@@ -186,6 +297,15 @@ async function showRequirementsTree() {
|
|
|
186
297
|
const { getOrCreateRequirementsFilePath, getRequirementsPath } = require('vibecodingmachine-core');
|
|
187
298
|
const { getRepoPath } = require('./config');
|
|
188
299
|
|
|
300
|
+
// Toggle all items functionality
|
|
301
|
+
const extraKeys = (str, key, selectedIndex, context) => {
|
|
302
|
+
if (str === '*' || str === '8') {
|
|
303
|
+
context.resolveWith({ value: 'toggle-all', selectedIndex });
|
|
304
|
+
return true;
|
|
305
|
+
}
|
|
306
|
+
return false;
|
|
307
|
+
};
|
|
308
|
+
|
|
189
309
|
// Resolve requirements file path exactly like loadAllSections does (getRequirementsPath,
|
|
190
310
|
// NOT getOrCreate) so reads and writes always go to the same file regardless of
|
|
191
311
|
// whether it lives inside the repo or in a sibling directory.
|
|
@@ -202,12 +322,19 @@ async function showRequirementsTree() {
|
|
|
202
322
|
return getOrCreateRequirementsFilePath(effectiveRepoPath);
|
|
203
323
|
};
|
|
204
324
|
|
|
205
|
-
const expanded = { specifications: false, verified: false, verify: false, todo:
|
|
325
|
+
const expanded = { specifications: false, verified: false, verify: false, todo: false, recycled: false };
|
|
206
326
|
const expandedSpecs = new Set(); // indices of expanded spec items
|
|
207
327
|
const specPhases = new Map(); // specIdx -> string[]
|
|
208
328
|
let sections = await loadAllSections();
|
|
209
329
|
let lastIndex = 0;
|
|
210
330
|
|
|
331
|
+
// Load saved states from file
|
|
332
|
+
const savedStates = await loadCliStates();
|
|
333
|
+
if (savedStates) {
|
|
334
|
+
Object.assign(expanded, savedStates.expanded);
|
|
335
|
+
savedStates.expandedSpecs.forEach(idx => expandedSpecs.add(idx));
|
|
336
|
+
}
|
|
337
|
+
|
|
211
338
|
const printHeader = () => {
|
|
212
339
|
console.clear();
|
|
213
340
|
process.stdout.write(chalk.bold.cyan('📋 Requirements\n\n'));
|
|
@@ -371,6 +498,60 @@ async function showRequirementsTree() {
|
|
|
371
498
|
continue;
|
|
372
499
|
}
|
|
373
500
|
|
|
501
|
+
// Handle */8: toggle all items
|
|
502
|
+
if (value === 'toggle-all') {
|
|
503
|
+
try {
|
|
504
|
+
const reqPath = await getReqPath();
|
|
505
|
+
let content = await fs.readFile(reqPath, 'utf8');
|
|
506
|
+
let hasChanges = false;
|
|
507
|
+
|
|
508
|
+
// Toggle all requirements
|
|
509
|
+
if (sections.todo && sections.todo.length > 0) {
|
|
510
|
+
sections.todo.forEach(req => {
|
|
511
|
+
const title = req.title;
|
|
512
|
+
if (!title.startsWith('DISABLED: ')) {
|
|
513
|
+
// Disable all
|
|
514
|
+
const escaped = title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
515
|
+
content = content.replace(new RegExp(`^(###\\s*)${escaped}\\s*$`, 'm'), `$1DISABLED: ${title}`);
|
|
516
|
+
hasChanges = true;
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Toggle all specifications
|
|
522
|
+
const { getSpecsList } = require('./trui-specifications');
|
|
523
|
+
const specs = await getSpecsList();
|
|
524
|
+
for (const spec of specs) {
|
|
525
|
+
if (spec.taskTotal > 0) {
|
|
526
|
+
const specDir = spec.path || path.join(await getRepoPath(), 'specs', spec.directory);
|
|
527
|
+
const tasksMdPath = path.join(specDir, 'tasks.md');
|
|
528
|
+
if (await fs.pathExists(tasksMdPath)) {
|
|
529
|
+
let specContent = await fs.readFile(tasksMdPath, 'utf8');
|
|
530
|
+
const specTitle = spec.title || spec.directory;
|
|
531
|
+
if (!specContent.includes('DISABLED:')) {
|
|
532
|
+
// Disable spec
|
|
533
|
+
specContent = `DISABLED: ${specTitle}\n${specContent}`;
|
|
534
|
+
hasChanges = true;
|
|
535
|
+
} else {
|
|
536
|
+
// Enable spec
|
|
537
|
+
specContent = specContent.replace(/^DISABLED: .+\n/, '');
|
|
538
|
+
hasChanges = true;
|
|
539
|
+
}
|
|
540
|
+
if (hasChanges) {
|
|
541
|
+
await fs.writeFile(tasksMdPath, specContent, 'utf8');
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
if (hasChanges) {
|
|
548
|
+
sections = await loadAllSections();
|
|
549
|
+
}
|
|
550
|
+
} catch (_) {}
|
|
551
|
+
printHeader();
|
|
552
|
+
continue;
|
|
553
|
+
}
|
|
554
|
+
|
|
374
555
|
// Handle Space: toggle spec enabled/disabled (rename directory DISABLED- prefix)
|
|
375
556
|
if (value.startsWith('toggle-disabled-spec:')) {
|
|
376
557
|
const itemIdx = parseInt(value.split(':')[1], 10);
|
|
@@ -434,13 +615,13 @@ async function showRequirementsTree() {
|
|
|
434
615
|
if (value.startsWith('section:')) {
|
|
435
616
|
const key = value.slice('section:'.length);
|
|
436
617
|
expanded[key] = !expanded[key];
|
|
618
|
+
await saveCliStates(expanded, expandedSpecs);
|
|
437
619
|
if (!expanded[key]) {
|
|
438
|
-
// Closing: position cursor back on
|
|
620
|
+
// Closing: position cursor back on header
|
|
439
621
|
const newItems = await buildTreeItems(sections, expanded, expandedSpecs, specPhases);
|
|
440
622
|
const headerIdx = newItems.findIndex(item => item.value === `section:${key}`);
|
|
441
623
|
if (headerIdx !== -1) lastIndex = headerIdx;
|
|
442
624
|
}
|
|
443
|
-
// Opening: lastIndex stays pointing at header pos; showQuickMenu auto-advances past info
|
|
444
625
|
printHeader();
|
|
445
626
|
continue;
|
|
446
627
|
}
|
|
@@ -465,6 +646,7 @@ async function showRequirementsTree() {
|
|
|
465
646
|
if (value.startsWith('expand-section:')) {
|
|
466
647
|
const key = value.slice('expand-section:'.length);
|
|
467
648
|
expanded[key] = true;
|
|
649
|
+
await saveCliStates(expanded, expandedSpecs);
|
|
468
650
|
printHeader();
|
|
469
651
|
continue;
|
|
470
652
|
}
|
|
@@ -473,6 +655,7 @@ async function showRequirementsTree() {
|
|
|
473
655
|
if (value.startsWith('collapse-section:')) {
|
|
474
656
|
const key = value.slice('collapse-section:'.length);
|
|
475
657
|
expanded[key] = false;
|
|
658
|
+
await saveCliStates(expanded, expandedSpecs);
|
|
476
659
|
// Rebuild to find the now-selectable (action) section header position
|
|
477
660
|
const newItems = await buildTreeItems(sections, expanded, expandedSpecs, specPhases);
|
|
478
661
|
const headerIdx = newItems.findIndex(item => item.value === `section:${key}`);
|
|
@@ -485,6 +668,7 @@ async function showRequirementsTree() {
|
|
|
485
668
|
if (value.startsWith('expand-spec:')) {
|
|
486
669
|
const specIdx = parseInt(value.split(':')[1], 10);
|
|
487
670
|
expandedSpecs.add(specIdx);
|
|
671
|
+
await saveCliStates(expanded, expandedSpecs);
|
|
488
672
|
if (!specPhases.has(specIdx)) {
|
|
489
673
|
try {
|
|
490
674
|
const { getSpecsList, extractPhases } = require('./trui-specifications');
|
|
@@ -501,6 +685,7 @@ async function showRequirementsTree() {
|
|
|
501
685
|
if (value.startsWith('collapse-spec:')) {
|
|
502
686
|
const specIdx = parseInt(value.split(':')[1], 10);
|
|
503
687
|
expandedSpecs.delete(specIdx);
|
|
688
|
+
await saveCliStates(expanded, expandedSpecs);
|
|
504
689
|
// Rebuild to find the now-selectable spec item position
|
|
505
690
|
const newItems = await buildTreeItems(sections, expanded, expandedSpecs, specPhases);
|
|
506
691
|
const specItemIdx = newItems.findIndex(item => item.value === `spec:${specIdx}`);
|
|
@@ -8,6 +8,36 @@ const chalk = require('chalk');
|
|
|
8
8
|
const fs = require('fs');
|
|
9
9
|
const path = require('path');
|
|
10
10
|
const { showQuickMenu } = require('./trui-quick-menu');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Create progress bar string with green/orange gradient based on completion percentage
|
|
14
|
+
* @param {number} percentage - Completion percentage (0-100)
|
|
15
|
+
* @param {number} done - Number of completed tasks
|
|
16
|
+
* @param {number} total - Total number of tasks
|
|
17
|
+
* @returns {string} Progress bar with colors
|
|
18
|
+
*/
|
|
19
|
+
function createProgressBar(percentage, done, total) {
|
|
20
|
+
if (total === 0) return chalk.gray(' TODO');
|
|
21
|
+
|
|
22
|
+
const isComplete = percentage === 100;
|
|
23
|
+
if (isComplete) {
|
|
24
|
+
return chalk.bgGreen.black(` ${percentage}%, ${done}/${total} tasks complete`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// For partial progress, split the text background based on actual percentage
|
|
28
|
+
const progressText = `${percentage}%, ${done}/${total} tasks complete`;
|
|
29
|
+
const textLength = progressText.length;
|
|
30
|
+
const splitPoint = Math.floor((percentage / 100) * textLength);
|
|
31
|
+
|
|
32
|
+
const firstHalf = progressText.substring(0, splitPoint);
|
|
33
|
+
const secondHalf = progressText.substring(splitPoint);
|
|
34
|
+
|
|
35
|
+
// Apply green background to percentage portion, orange to remaining
|
|
36
|
+
const greenHalf = chalk.bgGreen.black(firstHalf);
|
|
37
|
+
const orangeHalf = chalk.bgHex('#f59e0b').black(secondHalf);
|
|
38
|
+
|
|
39
|
+
return ` ${greenHalf}${orangeHalf}`;
|
|
40
|
+
}
|
|
11
41
|
const { debugLogger } = require('./trui-debug');
|
|
12
42
|
|
|
13
43
|
/**
|
|
@@ -167,7 +197,7 @@ async function showSpecificationsList() {
|
|
|
167
197
|
specs.forEach((spec, index) => {
|
|
168
198
|
let progressStr = '';
|
|
169
199
|
if (spec.taskTotal > 0) {
|
|
170
|
-
progressStr =
|
|
200
|
+
progressStr = ' ' + createProgressBar(spec.pct, spec.taskDone, spec.taskTotal);
|
|
171
201
|
}
|
|
172
202
|
items.push({
|
|
173
203
|
type: 'action',
|