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.
Files changed (101) hide show
  1. package/bin/auth/auth-compliance.js +126 -0
  2. package/bin/cli-program.js +104 -0
  3. package/bin/cli-setup.js +52 -0
  4. package/bin/commands/agent-commands.js +310 -0
  5. package/bin/commands/auto-commands.js +70 -0
  6. package/bin/commands/command-aliases.js +118 -0
  7. package/bin/commands/repo-commands.js +39 -0
  8. package/bin/commands/rui-commands.js +152 -0
  9. package/bin/config/cli-config.js +394 -0
  10. package/bin/init/environment-setup.js +84 -0
  11. package/bin/update/update-checker.js +126 -0
  12. package/bin/vibecodingmachine-new.js +50 -0
  13. package/bin/vibecodingmachine.js +29 -663
  14. package/package.json +8 -2
  15. package/src/commands/agents/add.js +277 -0
  16. package/src/commands/agents/check.js +380 -0
  17. package/src/commands/agents/list.js +471 -0
  18. package/src/commands/agents/remove.js +351 -0
  19. package/src/commands/analyze-file-sizes.js +428 -0
  20. package/src/commands/auto-direct/code-processor.js +282 -0
  21. package/src/commands/auto-direct/file-scanner.js +266 -0
  22. package/src/commands/auto-direct/provider-config.js +178 -0
  23. package/src/commands/auto-direct/provider-manager.js +219 -0
  24. package/src/commands/auto-direct/requirement-manager.js +172 -0
  25. package/src/commands/auto-direct/status-display.js +91 -0
  26. package/src/commands/auto-direct/utils.js +106 -0
  27. package/src/commands/auto-direct.js +875 -488
  28. package/src/commands/auto-execution.js +342 -0
  29. package/src/commands/auto-provider-management.js +102 -0
  30. package/src/commands/auto-requirement-management.js +161 -0
  31. package/src/commands/auto-status-helpers.js +141 -0
  32. package/src/commands/auto.js +105 -5155
  33. package/src/commands/check-compliance.js +536 -0
  34. package/src/commands/continuous-scan.js +119 -0
  35. package/src/commands/ide.js +16 -4
  36. package/src/commands/refactor-file.js +486 -0
  37. package/src/commands/requirements.js +301 -2
  38. package/src/commands/timeout.js +290 -0
  39. package/src/trui/TruiInterface.js +108 -0
  40. package/src/trui/agents/AgentInterface.js +580 -0
  41. package/src/utils/antigravity-installer.js +60 -6
  42. package/src/utils/clarification-actions.js +290 -0
  43. package/src/utils/config.js +123 -2
  44. package/src/utils/first-run.js +5 -5
  45. package/src/utils/ide-handlers.js +212 -0
  46. package/src/utils/interactive/clarification-actions.js +348 -0
  47. package/src/utils/interactive/core-ui.js +265 -0
  48. package/src/utils/interactive/file-backup.js +237 -0
  49. package/src/utils/interactive/file-import-export.js +305 -0
  50. package/src/utils/interactive/file-operations.js +49 -0
  51. package/src/utils/interactive/file-validation.js +276 -0
  52. package/src/utils/interactive/interactive-prompts.js +480 -0
  53. package/src/utils/interactive/requirement-actions.js +127 -0
  54. package/src/utils/interactive/requirement-crud.js +356 -0
  55. package/src/utils/interactive/requirements-navigation.js +286 -0
  56. package/src/utils/interactive.js +390 -3459
  57. package/src/utils/provider-checker/agent-checker.js +250 -0
  58. package/src/utils/provider-checker/agent-runner.js +450 -0
  59. package/src/utils/provider-checker/cli-installer.js +123 -0
  60. package/src/utils/provider-checker/cli-utils.js +15 -0
  61. package/src/utils/provider-checker/format-utils.js +32 -0
  62. package/src/utils/provider-checker/ide-manager.js +72 -0
  63. package/src/utils/provider-checker/ide-utils.js +71 -0
  64. package/src/utils/provider-checker/node-detector.js +56 -0
  65. package/src/utils/provider-checker/node-utils.js +61 -0
  66. package/src/utils/provider-checker/process-spawn.js +22 -0
  67. package/src/utils/provider-checker/process-utils.js +37 -0
  68. package/src/utils/provider-checker/provider-validator.js +160 -0
  69. package/src/utils/provider-checker/quota-checker.js +54 -0
  70. package/src/utils/provider-checker/quota-detector.js +44 -0
  71. package/src/utils/provider-checker/requirements-manager.js +94 -0
  72. package/src/utils/provider-checker/test-requirements.js +95 -0
  73. package/src/utils/provider-checker/time-formatter.js +18 -0
  74. package/src/utils/provider-checker-new.js +14 -0
  75. package/src/utils/provider-checker.js +12 -407
  76. package/src/utils/provider-checkers/ide-manager.js +128 -0
  77. package/src/utils/provider-checkers/node-executable-finder.js +51 -0
  78. package/src/utils/provider-checkers/provider-checker-core.js +172 -0
  79. package/src/utils/provider-checkers/provider-checker-main.js +107 -0
  80. package/src/utils/provider-manager.js +60 -4
  81. package/src/utils/provider-registry.js +26 -3
  82. package/src/utils/provider-utils.js +173 -0
  83. package/src/utils/quota-detectors.js +212 -0
  84. package/src/utils/requirement-action-handlers.js +288 -0
  85. package/src/utils/requirement-actions/clarification-actions.js +229 -0
  86. package/src/utils/requirement-actions/confirmation-prompts.js +93 -0
  87. package/src/utils/requirement-actions/file-operations.js +92 -0
  88. package/src/utils/requirement-actions/helpers.js +40 -0
  89. package/src/utils/requirement-actions/requirement-operations.js +335 -0
  90. package/src/utils/requirement-actions.js +46 -856
  91. package/src/utils/requirement-file-operations.js +259 -0
  92. package/src/utils/requirement-helpers.js +128 -0
  93. package/src/utils/requirement-management.js +279 -0
  94. package/src/utils/requirement-navigation.js +146 -0
  95. package/src/utils/requirement-organization.js +271 -0
  96. package/src/utils/simple-trui.js +75 -1
  97. package/src/utils/trui-navigation.js +28 -2
  98. package/src/utils/trui-req-tree.js +196 -11
  99. package/src/utils/trui-specifications.js +31 -1
  100. package/src/utils/interactive-backup.js +0 -5664
  101. 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, VERIFIED, TO VERIFY, TODO REQUIREMENTS
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} (${count}${total > 0 ? ' — ' + pct(count) + '%' : ''})`,
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 SPECIFICATIONS (${specsCount})`,
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 = chalk.gray(` [${spec.pct}%, ${spec.taskDone}/${spec.taskTotal} tasks complete]`);
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(` [${phase.pct}%, ${phase.done}/${phase.total}]`);
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', '🎉', 'VERIFIED', sections.verified);
171
- addSection('verify', '✅', 'TO VERIFY', sections.verify);
172
- addSection('todo', '⏳', 'TODO REQUIREMENTS', sections.todo);
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: true, recycled: false };
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 the header
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 = chalk.gray(` [${spec.pct}%, ${spec.taskDone}/${spec.taskTotal} tasks complete]`);
200
+ progressStr = ' ' + createProgressBar(spec.pct, spec.taskDone, spec.taskTotal);
171
201
  }
172
202
  items.push({
173
203
  type: 'action',