vibecodingmachine-cli 2025.12.6-1702 → 2025.12.22-2230
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/vibecodingmachine.js +209 -8
- package/package.json +2 -2
- package/reproduce_issue.js +160 -0
- package/src/commands/auth.js +0 -1
- package/src/commands/auto-direct.js +55 -40
- package/src/commands/auto.js +154 -57
- package/src/commands/computers.js +4 -4
- package/src/commands/repo.js +0 -1
- package/src/commands/requirements-remote.js +10 -6
- package/src/commands/requirements.js +29 -3
- package/src/commands/status.js +0 -1
- package/src/commands/sync.js +4 -4
- package/src/utils/agent-selector.js +50 -0
- package/src/utils/antigravity-installer.js +212 -0
- package/src/utils/antigravity-js-handler.js +60 -0
- package/src/utils/asset-cleanup.js +0 -1
- package/src/utils/auth.js +149 -2
- package/src/utils/auto-mode-ansi-ui.js +0 -1
- package/src/utils/auto-mode-simple-ui.js +1 -1
- package/src/utils/compliance-check.js +166 -0
- package/src/utils/config.js +27 -1
- package/src/utils/copy-with-progress.js +167 -0
- package/src/utils/download-with-progress.js +84 -0
- package/src/utils/first-run.js +185 -68
- package/src/utils/interactive.js +259 -263
- package/src/utils/kiro-installer.js +56 -24
- package/src/utils/persistent-header.js +1 -3
- package/src/utils/provider-registry.js +5 -4
- package/src/utils/user-tracking.js +300 -0
- package/tests/requirements-navigator-buildtree-await.test.js +28 -0
package/src/commands/auto.js
CHANGED
|
@@ -2,18 +2,18 @@ const chalk = require('chalk');
|
|
|
2
2
|
const ora = require('ora');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const os = require('os');
|
|
5
|
-
const {
|
|
6
|
-
const {
|
|
5
|
+
const { spawn } = require('child_process');
|
|
6
|
+
const { AppleScriptManager, ClineCLIManager, AiderCLIManager, ClaudeCodeCLIManager, logIDEMessage, runContinueCLIAutoMode } = require('vibecodingmachine-core');
|
|
7
|
+
const { getRepoPath, getAutoConfig, setAutoConfig, getStages } = require('../utils/config');
|
|
7
8
|
const { checkAutoModeStatus, startAutoMode, stopAutoMode, updateAutoModeStatus } = require('../utils/auto-mode');
|
|
8
9
|
const logger = require('../utils/logger');
|
|
9
10
|
const { createKeyboardHandler } = require('../utils/keyboard-handler');
|
|
10
11
|
const { getProviderDefinitions, getProviderPreferences } = require('../utils/provider-registry');
|
|
11
12
|
const PROVIDER_DEFINITIONS = getProviderDefinitions();
|
|
12
|
-
const DIRECT_AGENT_IDS = PROVIDER_DEFINITIONS.filter(def => def.type === 'direct').map(def => def.id);
|
|
13
13
|
const PROVIDER_DEFINITION_MAP = new Map(PROVIDER_DEFINITIONS.map(def => [def.id, def]));
|
|
14
14
|
const { handleAutoStart: handleDirectAutoStart } = require('./auto-direct');
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Get available LLM providers from config and environment variables
|
|
@@ -182,6 +182,7 @@ async function moveRequirementBackToTodo(repoPath, requirementText) {
|
|
|
182
182
|
|
|
183
183
|
for (let i = 0; i < lines.length; i++) {
|
|
184
184
|
const line = lines[i];
|
|
185
|
+
const trimmed = line.trim();
|
|
185
186
|
|
|
186
187
|
// Find verified section
|
|
187
188
|
if (line.includes('## ✅ Verified by AI screenshot')) {
|
|
@@ -199,7 +200,7 @@ async function moveRequirementBackToTodo(repoPath, requirementText) {
|
|
|
199
200
|
}
|
|
200
201
|
|
|
201
202
|
// Check if we're in verified section and this is the requirement to move
|
|
202
|
-
if (inVerifiedSection &&
|
|
203
|
+
if (inVerifiedSection && trimmed.startsWith('- ')) {
|
|
203
204
|
const lineRequirement = line.substring(2).trim();
|
|
204
205
|
// Remove date prefix if present (format: "2025-11-05: **requirement**")
|
|
205
206
|
const cleanRequirement = lineRequirement.replace(/^\d{4}-\d{2}-\d{2}:\s*\*\*/, '').replace(/\*\*$/, '').trim();
|
|
@@ -210,20 +211,21 @@ async function moveRequirementBackToTodo(repoPath, requirementText) {
|
|
|
210
211
|
requirementFound = true;
|
|
211
212
|
continue;
|
|
212
213
|
}
|
|
213
|
-
updatedLines.push(line);
|
|
214
|
-
continue;
|
|
215
214
|
}
|
|
216
215
|
|
|
217
216
|
// If we're in not yet completed section and haven't added the requirement yet, add it at the top
|
|
218
|
-
if (inNotYetCompleted && !requirementFound &&
|
|
217
|
+
if (inNotYetCompleted && !requirementFound && trimmed.startsWith('- ')) {
|
|
219
218
|
// Add the requirement before the first existing requirement
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
219
|
+
const newUpdatedLines = lines.slice(0, i);
|
|
220
|
+
newUpdatedLines.push(`- ${requirementText}`);
|
|
221
|
+
newUpdatedLines.push('');
|
|
222
|
+
newUpdatedLines.push(...lines.slice(i));
|
|
223
|
+
await fs.writeFile(reqPath, newUpdatedLines.join('\n'));
|
|
224
|
+
return { success: true };
|
|
223
225
|
}
|
|
224
226
|
|
|
225
227
|
// Reset section flags when hitting new sections
|
|
226
|
-
if (
|
|
228
|
+
if (trimmed.startsWith('##')) {
|
|
227
229
|
inVerifiedSection = false;
|
|
228
230
|
inNotYetCompleted = false;
|
|
229
231
|
}
|
|
@@ -234,6 +236,7 @@ async function moveRequirementBackToTodo(repoPath, requirementText) {
|
|
|
234
236
|
// If requirement wasn't found in verified section, try to add it to not yet completed anyway
|
|
235
237
|
if (!requirementFound) {
|
|
236
238
|
// Find the not yet completed section and add requirement at the top
|
|
239
|
+
const newUpdatedLines = lines.slice();
|
|
237
240
|
for (let i = 0; i < updatedLines.length; i++) {
|
|
238
241
|
if (updatedLines[i].includes('## ⏳ Requirements not yet completed')) {
|
|
239
242
|
// Find the first requirement line after this section
|
|
@@ -243,18 +246,13 @@ async function moveRequirementBackToTodo(repoPath, requirementText) {
|
|
|
243
246
|
insertIndex++;
|
|
244
247
|
}
|
|
245
248
|
updatedLines.splice(insertIndex, 0, `- ${requirementText}`, '');
|
|
246
|
-
|
|
247
|
-
|
|
249
|
+
await fs.writeFile(reqPath, updatedLines.join('\n'));
|
|
250
|
+
return { success: true };
|
|
248
251
|
}
|
|
249
252
|
}
|
|
250
253
|
}
|
|
251
254
|
|
|
252
|
-
|
|
253
|
-
await fs.writeFile(reqPath, updatedLines.join('\n'));
|
|
254
|
-
return { success: true };
|
|
255
|
-
} else {
|
|
256
|
-
return { success: false, error: 'Requirement not found in verified section' };
|
|
257
|
-
}
|
|
255
|
+
return { success: false, error: 'Requirement not found in verified section' };
|
|
258
256
|
} catch (error) {
|
|
259
257
|
return { success: false, error: error.message };
|
|
260
258
|
}
|
|
@@ -279,10 +277,8 @@ async function moveRequirementToFeedback(repoPath, requirementText, questions, f
|
|
|
279
277
|
|
|
280
278
|
const content = await fs.readFile(reqPath, 'utf8');
|
|
281
279
|
const lines = content.split('\n');
|
|
282
|
-
const updatedLines = [];
|
|
283
280
|
|
|
284
281
|
let inTodoSection = false;
|
|
285
|
-
let inFeedbackSection = false;
|
|
286
282
|
let requirementRemoved = false;
|
|
287
283
|
let feedbackAdded = false;
|
|
288
284
|
|
|
@@ -292,15 +288,13 @@ async function moveRequirementToFeedback(repoPath, requirementText, questions, f
|
|
|
292
288
|
// Find TODO section
|
|
293
289
|
if (trimmed.startsWith('##') && trimmed.includes('Requirements not yet completed')) {
|
|
294
290
|
inTodoSection = true;
|
|
295
|
-
inFeedbackSection = false;
|
|
296
|
-
updatedLines.push(line);
|
|
297
291
|
continue;
|
|
298
292
|
}
|
|
299
293
|
|
|
300
294
|
// Find "Requirements needing manual feedback" section
|
|
301
295
|
if (trimmed.startsWith('##') && (trimmed.includes('Requirements needing manual feedback') || trimmed.includes('❓ Requirements needing'))) {
|
|
302
296
|
inTodoSection = false;
|
|
303
|
-
|
|
297
|
+
const updatedLines = lines.slice(0, lines.indexOf(line));
|
|
304
298
|
updatedLines.push(line);
|
|
305
299
|
|
|
306
300
|
// Add blank line if not already present
|
|
@@ -328,13 +322,14 @@ async function moveRequirementToFeedback(repoPath, requirementText, questions, f
|
|
|
328
322
|
updatedLines.push('');
|
|
329
323
|
feedbackAdded = true;
|
|
330
324
|
}
|
|
331
|
-
|
|
325
|
+
updatedLines.push(...lines.slice(lines.indexOf(line) + 1));
|
|
326
|
+
await fs.writeFile(reqPath, updatedLines.join('\n'));
|
|
327
|
+
return { success: true };
|
|
332
328
|
}
|
|
333
329
|
|
|
334
330
|
// Stop sections at next header
|
|
335
331
|
if (trimmed.startsWith('##')) {
|
|
336
332
|
inTodoSection = false;
|
|
337
|
-
inFeedbackSection = false;
|
|
338
333
|
}
|
|
339
334
|
|
|
340
335
|
// Remove requirement from TODO section (match first occurrence)
|
|
@@ -694,8 +689,6 @@ async function start(options) {
|
|
|
694
689
|
if (global.pendingUpdate) {
|
|
695
690
|
const updateSpinner = ora('Installing update...').start();
|
|
696
691
|
try {
|
|
697
|
-
const { spawn } = require('child_process');
|
|
698
|
-
|
|
699
692
|
// Install update using npm
|
|
700
693
|
await new Promise((resolve, reject) => {
|
|
701
694
|
const npmInstall = spawn('npm', ['install', '-g', 'vibecodingmachine-cli'], {
|
|
@@ -708,7 +701,6 @@ async function start(options) {
|
|
|
708
701
|
console.log(chalk.green('\n✓ Restarting with new version...\n'));
|
|
709
702
|
|
|
710
703
|
// Restart CLI with same arguments
|
|
711
|
-
const { spawn } = require('child_process');
|
|
712
704
|
const args = process.argv.slice(2);
|
|
713
705
|
spawn(process.argv[0], [process.argv[1], ...args], {
|
|
714
706
|
stdio: 'inherit',
|
|
@@ -741,15 +733,32 @@ async function start(options) {
|
|
|
741
733
|
throw new Error('No repository configured');
|
|
742
734
|
}
|
|
743
735
|
|
|
744
|
-
//
|
|
736
|
+
// Get provider preferences and definitions
|
|
745
737
|
const savedConfig = await getAutoConfig();
|
|
746
738
|
const prefs = await getProviderPreferences();
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
const
|
|
750
|
-
const
|
|
751
|
-
|
|
752
|
-
|
|
739
|
+
|
|
740
|
+
// Get all available providers in the order specified in preferences
|
|
741
|
+
const availableProviders = [];
|
|
742
|
+
for (const id of prefs.order) {
|
|
743
|
+
if (prefs.enabled[id] !== false && PROVIDER_DEFINITION_MAP.has(id)) {
|
|
744
|
+
availableProviders.push(id);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// If no providers are available, use the first one from definitions as fallback
|
|
749
|
+
if (availableProviders.length === 0) {
|
|
750
|
+
availableProviders.push(PROVIDER_DEFINITIONS[0]?.id || 'claude-code');
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// Use the first available provider by default, unless overridden by options
|
|
754
|
+
let effectiveAgent = options.ide || availableProviders[0];
|
|
755
|
+
|
|
756
|
+
// If the requested agent isn't available, use the first available one
|
|
757
|
+
if (!availableProviders.includes(effectiveAgent)) {
|
|
758
|
+
effectiveAgent = availableProviders[0];
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
const providerDef = PROVIDER_DEFINITION_MAP.get(effectiveAgent);
|
|
753
762
|
|
|
754
763
|
const resolvedNeverStop = (() => {
|
|
755
764
|
if (options.neverStop !== undefined) return options.neverStop;
|
|
@@ -893,8 +902,15 @@ async function start(options) {
|
|
|
893
902
|
await startAutoMode(repoPath, config);
|
|
894
903
|
}
|
|
895
904
|
|
|
905
|
+
// Get configured stages
|
|
906
|
+
const stages = await getStages();
|
|
907
|
+
const stagesList = stages.join(' → ');
|
|
908
|
+
const defaultInstructionText = `Follow INSTRUCTIONS.md from .vibecodingmachine directory.
|
|
909
|
+
|
|
910
|
+
CRITICAL FOR IDE AGENTS: You MUST work through ALL configured stages (${stagesList}) without stopping. Update the "🚦 Current Status" section in the REQUIREMENTS file as you progress through each stage. DO NOT stop after acknowledging stages - you must COMPLETE the work and set status to DONE in the requirements file. The CLI is monitoring the file and waiting for you to finish.`;
|
|
911
|
+
|
|
896
912
|
// Send initial instruction to IDE or Continue/Cline CLI
|
|
897
|
-
const textToSend = options.text ||
|
|
913
|
+
const textToSend = options.text || defaultInstructionText;
|
|
898
914
|
|
|
899
915
|
if (config.ide === 'continue') {
|
|
900
916
|
// Use Continue CLI with command-line approach
|
|
@@ -1017,14 +1033,9 @@ async function start(options) {
|
|
|
1017
1033
|
'DONE': '⏳'
|
|
1018
1034
|
};
|
|
1019
1035
|
|
|
1020
|
-
|
|
1021
|
-
const stageMap = {
|
|
1022
|
-
|
|
1023
|
-
'ACT': 1,
|
|
1024
|
-
'CLEAN UP': 2,
|
|
1025
|
-
'VERIFY': 3,
|
|
1026
|
-
'DONE': 4
|
|
1027
|
-
};
|
|
1036
|
+
// Build stage map dynamically
|
|
1037
|
+
const stageMap = {};
|
|
1038
|
+
stages.forEach((s, i) => stageMap[s] = i);
|
|
1028
1039
|
|
|
1029
1040
|
const currentIndex = stageMap[currentStatus] || 0;
|
|
1030
1041
|
const workflowLine = stages.map((stage, idx) => {
|
|
@@ -1064,29 +1075,64 @@ async function start(options) {
|
|
|
1064
1075
|
let title = null;
|
|
1065
1076
|
let status = 'PREPARE';
|
|
1066
1077
|
let inTodoSection = false;
|
|
1078
|
+
let inCurrentSection = false;
|
|
1067
1079
|
|
|
1068
1080
|
for (let i = 0; i < lines.length; i++) {
|
|
1069
1081
|
const line = lines[i].trim();
|
|
1070
1082
|
|
|
1083
|
+
// Check if we're in the Current section
|
|
1084
|
+
if (line.includes('## 🔨 Current In Progress Requirement') ||
|
|
1085
|
+
line.includes('Current In Progress Requirement')) {
|
|
1086
|
+
inCurrentSection = true;
|
|
1087
|
+
inTodoSection = false;
|
|
1088
|
+
continue;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1071
1091
|
// Check if we're in the TODO section
|
|
1072
1092
|
if (line.includes('## ⏳ Requirements not yet completed') ||
|
|
1073
1093
|
(line.includes('Requirements not yet completed') && line.startsWith('##'))) {
|
|
1074
1094
|
inTodoSection = true;
|
|
1095
|
+
inCurrentSection = false;
|
|
1075
1096
|
continue;
|
|
1076
1097
|
}
|
|
1077
1098
|
|
|
1078
|
-
// If we hit another section header, stop looking
|
|
1079
|
-
if (inTodoSection && line.startsWith('##') && !line.startsWith('###')) {
|
|
1080
|
-
|
|
1099
|
+
// If we hit another section header, stop looking in current section/todo section logic
|
|
1100
|
+
if ((inTodoSection || inCurrentSection) && line.startsWith('##') && !line.startsWith('###')) {
|
|
1101
|
+
if (inCurrentSection) {
|
|
1102
|
+
// If we finished current section and found nothing, move to next sections (which might be TODO)
|
|
1103
|
+
inCurrentSection = false;
|
|
1104
|
+
continue;
|
|
1105
|
+
}
|
|
1106
|
+
if (inTodoSection) {
|
|
1107
|
+
break;
|
|
1108
|
+
}
|
|
1081
1109
|
}
|
|
1082
1110
|
|
|
1083
|
-
// If we're in
|
|
1084
|
-
if (
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
break;
|
|
1111
|
+
// If we're in Current section, look for bullet or header
|
|
1112
|
+
if (inCurrentSection) {
|
|
1113
|
+
if (line.startsWith('- ')) {
|
|
1114
|
+
title = line.substring(2).trim();
|
|
1115
|
+
// Remove bold if present
|
|
1116
|
+
title = title.replace(/\*\*/g, '');
|
|
1117
|
+
if (title) break;
|
|
1118
|
+
}
|
|
1119
|
+
if (line.startsWith('###')) {
|
|
1120
|
+
title = line.replace(/^###\s*/, '').trim();
|
|
1121
|
+
if (title) break;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
// If we're in TODO section and find a requirement header (###) or bullet
|
|
1126
|
+
if (inTodoSection) {
|
|
1127
|
+
if (line.startsWith('###')) {
|
|
1128
|
+
title = line.replace(/^###\s*/, '').trim();
|
|
1129
|
+
if (title) break;
|
|
1130
|
+
}
|
|
1131
|
+
// Also support bullet points in TODO if that's a format used
|
|
1132
|
+
if (line.startsWith('- ')) {
|
|
1133
|
+
title = line.substring(2).trim();
|
|
1134
|
+
title = title.replace(/\*\*/g, '');
|
|
1135
|
+
if (title) break;
|
|
1090
1136
|
}
|
|
1091
1137
|
}
|
|
1092
1138
|
}
|
|
@@ -4912,9 +4958,60 @@ async function config(options) {
|
|
|
4912
4958
|
}
|
|
4913
4959
|
}
|
|
4914
4960
|
|
|
4961
|
+
async function listAgents() {
|
|
4962
|
+
const ProviderManager = require('vibecodingmachine-core/src/ide-integration/provider-manager.cjs');
|
|
4963
|
+
const providerManager = new ProviderManager();
|
|
4964
|
+
|
|
4965
|
+
console.log(chalk.blue('\n📋 Available IDE Agents and Quota Status:\n'));
|
|
4966
|
+
|
|
4967
|
+
// Get all provider definitions
|
|
4968
|
+
const providers = getProviderDefinitions();
|
|
4969
|
+
|
|
4970
|
+
// Check each provider's quota status
|
|
4971
|
+
for (const provider of providers) {
|
|
4972
|
+
const rateLimitInfo = providerManager.getRateLimitInfo(provider.id);
|
|
4973
|
+
|
|
4974
|
+
let statusIcon = '✅';
|
|
4975
|
+
let statusText = chalk.green('Available');
|
|
4976
|
+
let quotaInfo = '';
|
|
4977
|
+
|
|
4978
|
+
if (rateLimitInfo.isRateLimited) {
|
|
4979
|
+
statusIcon = '⚠️';
|
|
4980
|
+
statusText = chalk.yellow('Quota Limit');
|
|
4981
|
+
|
|
4982
|
+
if (rateLimitInfo.resetTime) {
|
|
4983
|
+
const resetDate = new Date(rateLimitInfo.resetTime);
|
|
4984
|
+
const now = new Date();
|
|
4985
|
+
const minutesRemaining = Math.ceil((resetDate - now) / (1000 * 60));
|
|
4986
|
+
|
|
4987
|
+
if (minutesRemaining > 60) {
|
|
4988
|
+
const hoursRemaining = Math.ceil(minutesRemaining / 60);
|
|
4989
|
+
quotaInfo = chalk.gray(` (resets in ${hoursRemaining}h)`);
|
|
4990
|
+
} else if (minutesRemaining > 0) {
|
|
4991
|
+
quotaInfo = chalk.gray(` (resets in ${minutesRemaining}m)`);
|
|
4992
|
+
} else {
|
|
4993
|
+
quotaInfo = chalk.gray(' (resetting soon)');
|
|
4994
|
+
}
|
|
4995
|
+
}
|
|
4996
|
+
|
|
4997
|
+
if (rateLimitInfo.reason) {
|
|
4998
|
+
quotaInfo += chalk.gray(` - ${rateLimitInfo.reason}`);
|
|
4999
|
+
}
|
|
5000
|
+
}
|
|
5001
|
+
|
|
5002
|
+
console.log(`${statusIcon} ${chalk.cyan(provider.name)} ${statusText}${quotaInfo}`);
|
|
5003
|
+
if (provider.description) {
|
|
5004
|
+
console.log(` ${chalk.gray(provider.description)}`);
|
|
5005
|
+
}
|
|
5006
|
+
}
|
|
5007
|
+
|
|
5008
|
+
console.log(chalk.gray('\n💡 Tip: Auto mode will automatically skip quota-limited agents\n'));
|
|
5009
|
+
}
|
|
5010
|
+
|
|
4915
5011
|
module.exports = {
|
|
4916
5012
|
start,
|
|
4917
5013
|
stop,
|
|
4918
5014
|
status,
|
|
4919
|
-
config
|
|
5015
|
+
config,
|
|
5016
|
+
listAgents
|
|
4920
5017
|
};
|
|
@@ -93,7 +93,7 @@ async function listComputers(options = {}) {
|
|
|
93
93
|
/**
|
|
94
94
|
* Show detailed status of a specific computer
|
|
95
95
|
*/
|
|
96
|
-
async function showComputerStatus(computerId
|
|
96
|
+
async function showComputerStatus(computerId) {
|
|
97
97
|
const syncEngine = new SyncEngine();
|
|
98
98
|
|
|
99
99
|
try {
|
|
@@ -149,7 +149,7 @@ async function showComputerStatus(computerId, options = {}) {
|
|
|
149
149
|
/**
|
|
150
150
|
* Register current computer with focus area
|
|
151
151
|
*/
|
|
152
|
-
async function registerComputer(focusArea
|
|
152
|
+
async function registerComputer(focusArea) {
|
|
153
153
|
const syncEngine = new SyncEngine();
|
|
154
154
|
|
|
155
155
|
try {
|
|
@@ -185,7 +185,7 @@ async function registerComputer(focusArea, options = {}) {
|
|
|
185
185
|
/**
|
|
186
186
|
* Update focus area for current computer
|
|
187
187
|
*/
|
|
188
|
-
async function updateFocus(newFocusArea
|
|
188
|
+
async function updateFocus(newFocusArea) {
|
|
189
189
|
const syncEngine = new SyncEngine();
|
|
190
190
|
|
|
191
191
|
try {
|
|
@@ -195,7 +195,7 @@ async function updateFocus(newFocusArea, options = {}) {
|
|
|
195
195
|
|
|
196
196
|
if (!computer) {
|
|
197
197
|
console.log(chalk.yellow('\n⚠ Computer not registered. Registering now...\n'));
|
|
198
|
-
await registerComputer(newFocusArea
|
|
198
|
+
await registerComputer(newFocusArea);
|
|
199
199
|
return;
|
|
200
200
|
}
|
|
201
201
|
|
package/src/commands/repo.js
CHANGED
|
@@ -6,7 +6,7 @@ const inquirer = require('inquirer');
|
|
|
6
6
|
/**
|
|
7
7
|
* List requirements for a specific computer
|
|
8
8
|
*/
|
|
9
|
-
async function listRemoteRequirements(computerId
|
|
9
|
+
async function listRemoteRequirements(computerId) {
|
|
10
10
|
try {
|
|
11
11
|
const repoPath = process.cwd();
|
|
12
12
|
const reqFilename = `REQUIREMENTS-${computerId}.md`;
|
|
@@ -60,7 +60,7 @@ async function listRemoteRequirements(computerId, options = {}) {
|
|
|
60
60
|
/**
|
|
61
61
|
* Add a requirement to another computer's requirements file
|
|
62
62
|
*/
|
|
63
|
-
async function addRemoteRequirement(computerId, requirementText
|
|
63
|
+
async function addRemoteRequirement(computerId, requirementText) {
|
|
64
64
|
try {
|
|
65
65
|
const repoPath = process.cwd();
|
|
66
66
|
const reqFilename = `REQUIREMENTS-${computerId}.md`;
|
|
@@ -168,7 +168,7 @@ async function manageRemoteRequirements(computerId) {
|
|
|
168
168
|
]);
|
|
169
169
|
|
|
170
170
|
switch (action) {
|
|
171
|
-
case 'view':
|
|
171
|
+
case 'view': {
|
|
172
172
|
await listRemoteRequirements(computerId);
|
|
173
173
|
console.log(chalk.gray('Press Enter to continue...'));
|
|
174
174
|
await new Promise(resolve => {
|
|
@@ -184,8 +184,9 @@ async function manageRemoteRequirements(computerId) {
|
|
|
184
184
|
});
|
|
185
185
|
await manageRemoteRequirements(computerId);
|
|
186
186
|
break;
|
|
187
|
+
}
|
|
187
188
|
|
|
188
|
-
case 'add':
|
|
189
|
+
case 'add': {
|
|
189
190
|
const { requirement } = await inquirer.prompt([
|
|
190
191
|
{
|
|
191
192
|
type: 'input',
|
|
@@ -211,8 +212,9 @@ async function manageRemoteRequirements(computerId) {
|
|
|
211
212
|
}
|
|
212
213
|
await manageRemoteRequirements(computerId);
|
|
213
214
|
break;
|
|
215
|
+
}
|
|
214
216
|
|
|
215
|
-
case 'edit':
|
|
217
|
+
case 'edit': {
|
|
216
218
|
const repoPath = process.cwd();
|
|
217
219
|
const reqFilename = `REQUIREMENTS-${computerId}.md`;
|
|
218
220
|
const reqPath = path.join(repoPath, '.vibecodingmachine', reqFilename);
|
|
@@ -237,9 +239,11 @@ async function manageRemoteRequirements(computerId) {
|
|
|
237
239
|
}
|
|
238
240
|
await manageRemoteRequirements(computerId);
|
|
239
241
|
break;
|
|
242
|
+
}
|
|
240
243
|
|
|
241
|
-
case 'back':
|
|
244
|
+
case 'back': {
|
|
242
245
|
break;
|
|
246
|
+
}
|
|
243
247
|
}
|
|
244
248
|
}
|
|
245
249
|
|
|
@@ -130,7 +130,7 @@ async function add(name, pkg, description) {
|
|
|
130
130
|
|
|
131
131
|
// Find the TODO section
|
|
132
132
|
const todoSectionHeader = '## ⏳ Requirements not yet completed';
|
|
133
|
-
if (!content.includes(
|
|
133
|
+
if (!content.includes('Requirements not yet completed')) {
|
|
134
134
|
content += '\n\n' + todoSectionHeader + '\n';
|
|
135
135
|
}
|
|
136
136
|
|
|
@@ -142,8 +142,8 @@ async function add(name, pkg, description) {
|
|
|
142
142
|
for (let i = 0; i < lines.length; i++) {
|
|
143
143
|
newLines.push(lines[i]);
|
|
144
144
|
|
|
145
|
-
// Insert right after the TODO section header
|
|
146
|
-
if (!inserted && lines[i].includes(
|
|
145
|
+
// Insert right after the TODO section header
|
|
146
|
+
if (!inserted && lines[i].startsWith('##') && lines[i].includes('Requirements not yet completed')) {
|
|
147
147
|
// Add requirement header
|
|
148
148
|
newLines.push(`### ${name}`);
|
|
149
149
|
|
|
@@ -338,10 +338,36 @@ async function rename(oldTitle, newTitle, description) {
|
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
340
|
|
|
341
|
+
async function working() {
|
|
342
|
+
try {
|
|
343
|
+
const { reqPath } = await getReqPathOrExit();
|
|
344
|
+
if (!await fs.pathExists(reqPath)) {
|
|
345
|
+
console.log(chalk.yellow('No REQUIREMENTS.md found.'));
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
const { getCurrentRequirement } = require('vibecodingmachine-core');
|
|
349
|
+
// Note: Core's getCurrentRequirement returns "Working on: X" or default text.
|
|
350
|
+
// It assumes process.cwd() or similar.
|
|
351
|
+
// But wait, Core's getCurrentRequirement takes 'repoPath'.
|
|
352
|
+
// And imported from core index.cjs might need repoPath.
|
|
353
|
+
|
|
354
|
+
// Let's manually implement it to be safe and use getReqPathOrExit's resolved path
|
|
355
|
+
// OR use the core helper but pass the correct repo path.
|
|
356
|
+
const { repoPath } = await getReqPathOrExit();
|
|
357
|
+
const coreResult = await getCurrentRequirement(repoPath);
|
|
358
|
+
console.log(chalk.cyan(coreResult));
|
|
359
|
+
|
|
360
|
+
} catch (error) {
|
|
361
|
+
console.error(chalk.red('Error getting working requirement:'), error.message);
|
|
362
|
+
process.exit(1);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
341
366
|
module.exports = {
|
|
342
367
|
list,
|
|
343
368
|
add,
|
|
344
369
|
current,
|
|
370
|
+
working,
|
|
345
371
|
next,
|
|
346
372
|
edit,
|
|
347
373
|
watch,
|
package/src/commands/status.js
CHANGED
|
@@ -64,7 +64,6 @@ async function progress() {
|
|
|
64
64
|
|
|
65
65
|
async function logs(cmd) {
|
|
66
66
|
const lines = parseInt((cmd && cmd.lines) || '50', 10);
|
|
67
|
-
const repoPath = await getRepoPath();
|
|
68
67
|
const defaultLog = path.join(process.cwd(), 'logs', 'security', 'security-2025-10-29.log');
|
|
69
68
|
const logPath = await fs.pathExists(defaultLog) ? defaultLog : null;
|
|
70
69
|
console.log(chalk.bold('\nRecent Logs'));
|
package/src/commands/sync.js
CHANGED
|
@@ -5,7 +5,7 @@ const SyncEngine = require('vibecodingmachine-core/src/sync/sync-engine');
|
|
|
5
5
|
/**
|
|
6
6
|
* Trigger immediate sync
|
|
7
7
|
*/
|
|
8
|
-
async function syncNow(
|
|
8
|
+
async function syncNow() {
|
|
9
9
|
const syncEngine = new SyncEngine();
|
|
10
10
|
|
|
11
11
|
try {
|
|
@@ -52,7 +52,7 @@ async function syncNow(options = {}) {
|
|
|
52
52
|
/**
|
|
53
53
|
* Show sync status and statistics
|
|
54
54
|
*/
|
|
55
|
-
async function syncStatus(
|
|
55
|
+
async function syncStatus() {
|
|
56
56
|
const syncEngine = new SyncEngine();
|
|
57
57
|
|
|
58
58
|
try {
|
|
@@ -117,7 +117,7 @@ async function syncStatus(options = {}) {
|
|
|
117
117
|
/**
|
|
118
118
|
* View pending changes in offline queue
|
|
119
119
|
*/
|
|
120
|
-
async function viewQueue(
|
|
120
|
+
async function viewQueue() {
|
|
121
121
|
const syncEngine = new SyncEngine();
|
|
122
122
|
|
|
123
123
|
try {
|
|
@@ -172,7 +172,7 @@ async function viewQueue(options = {}) {
|
|
|
172
172
|
/**
|
|
173
173
|
* Force sync even if offline
|
|
174
174
|
*/
|
|
175
|
-
async function forceSync(
|
|
175
|
+
async function forceSync() {
|
|
176
176
|
const syncEngine = new SyncEngine();
|
|
177
177
|
|
|
178
178
|
try {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized agent selection logic
|
|
3
|
+
* Respects provider preferences order and ensures DRY principle
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { getProviderPreferences } = require('./provider-registry');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Get the effective agent based on provider preferences and options
|
|
10
|
+
* @param {Object} options - Command line options (may include ide)
|
|
11
|
+
* @param {Array} providerDefinitions - Array of provider definitions
|
|
12
|
+
* @param {Map} providerDefinitionMap - Map of provider definitions by ID
|
|
13
|
+
* @returns {Object} - { effectiveAgent: string, providerDef: Object }
|
|
14
|
+
*/
|
|
15
|
+
async function getEffectiveAgent(options = {}, providerDefinitions, providerDefinitionMap) {
|
|
16
|
+
const prefs = await getProviderPreferences();
|
|
17
|
+
|
|
18
|
+
// Get all available providers in the order specified in preferences
|
|
19
|
+
const availableProviders = [];
|
|
20
|
+
for (const id of prefs.order) {
|
|
21
|
+
if (prefs.enabled[id] !== false && providerDefinitionMap.has(id)) {
|
|
22
|
+
availableProviders.push(id);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// If no providers are available, use the first one from definitions as fallback
|
|
27
|
+
if (availableProviders.length === 0) {
|
|
28
|
+
availableProviders.push(providerDefinitions[0]?.id || 'claude-code');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Use the first available provider by default, unless overridden by options
|
|
32
|
+
let effectiveAgent = options.ide || availableProviders[0];
|
|
33
|
+
|
|
34
|
+
// If the requested agent isn't available, use the first available one
|
|
35
|
+
if (!availableProviders.includes(effectiveAgent)) {
|
|
36
|
+
effectiveAgent = availableProviders[0];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const providerDef = providerDefinitionMap.get(effectiveAgent);
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
effectiveAgent,
|
|
43
|
+
providerDef,
|
|
44
|
+
availableProviders
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
getEffectiveAgent
|
|
50
|
+
};
|