vibecodingmachine-cli 2025.12.1-534 → 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.
@@ -0,0 +1,178 @@
1
+ const fs = require('fs-extra');
2
+ const os = require('os');
3
+ const ora = require('ora');
4
+ const chalk = require('chalk');
5
+
6
+ // Placeholder check - this should ideally check for the actual application path
7
+ // On macOS, typically /Applications/AWS Kiro.app or similar
8
+ // For now, we'll check a simulated path or just return false to test the flow
9
+ function isKiroInstalled() {
10
+ const platform = os.platform();
11
+ if (platform === 'darwin') {
12
+ return fs.existsSync('/Applications/AWS Kiro.app') || fs.existsSync('/Applications/Kiro.app');
13
+ }
14
+ // Add Windows/Linux checks if needed
15
+ return false;
16
+ }
17
+
18
+ async function installKiro() {
19
+ console.log(chalk.cyan('\n🚀 Initiating AWS Kiro AI IDE Installation...'));
20
+
21
+ const spinner = ora('Checking system requirements...').start();
22
+ await new Promise(resolve => setTimeout(resolve, 1000));
23
+
24
+ // Detect architecture
25
+ const arch = process.arch;
26
+ const isArm = arch === 'arm64';
27
+
28
+ // Verified working URL for ARM64 (v202507161958)
29
+ // For x64, we don't have the exact timestamp/hash, so recent failures suggest we might need to fallback to manual
30
+ const downloadUrl = isArm
31
+ ? 'https://prod.download.desktop.kiro.dev/releases/202507161958-Kiro-dmg-darwin-arm64.dmg'
32
+ : 'https://kiro.dev/downloads/'; // Fallback to downloads page for x64 until we find the direct link
33
+
34
+ spinner.succeed(`System requirements met (${isArm ? 'Apple Silicon' : 'Intel'}).`);
35
+
36
+ // for x64, we can't automate yet
37
+ if (!isArm) {
38
+ console.log(chalk.yellow('\n⚠️ Automated installation is currently only available for Apple Silicon (M1/M2/M3).'));
39
+ console.log(chalk.cyan('Opening download page...'));
40
+ // open v11+ is ESM only
41
+ const open = (await import('open')).default;
42
+ await open(downloadUrl);
43
+ return false;
44
+ }
45
+
46
+ try {
47
+ const fs = require('fs-extra');
48
+ const path = require('path');
49
+ const os = require('os');
50
+ const { execSync } = require('child_process');
51
+
52
+ console.log(chalk.cyan(`\n⬇️ Downloading AWS Kiro for macOS (${arch})...`));
53
+ const cacheDir = path.join(os.homedir(), '.vibecodingmachine', 'cache');
54
+ await fs.ensureDir(cacheDir);
55
+ const cachedPath = path.join(cacheDir, 'Kiro.dmg');
56
+ const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'kiro-install-'));
57
+ const dmgPath = path.join(tempDir, 'Kiro.dmg');
58
+ const { downloadWithProgress } = require('./download-with-progress');
59
+
60
+ // Try to reuse cached DMG to avoid re-downloading
61
+ let usedCache = false;
62
+ try {
63
+ if (await fs.pathExists(cachedPath)) {
64
+ try {
65
+ const fetch = require('node-fetch');
66
+ const head = await fetch(downloadUrl, { method: 'HEAD' });
67
+ const total = Number(head.headers.get('content-length')) || 0;
68
+ const stat = await fs.stat(cachedPath);
69
+ if (total && stat.size === total) {
70
+ await fs.copy(cachedPath, dmgPath);
71
+ usedCache = true;
72
+ console.log(chalk.gray('Using cached Kiro DMG'));
73
+ }
74
+ } catch (e) {
75
+ await fs.copy(cachedPath, dmgPath);
76
+ usedCache = true;
77
+ console.log(chalk.gray('Using cached Kiro DMG (no HEAD)'));
78
+ }
79
+ }
80
+ } catch (e) {
81
+ usedCache = false;
82
+ }
83
+
84
+ if (!usedCache) {
85
+ await downloadWithProgress(downloadUrl, dmgPath, { label: 'Downloading AWS Kiro...' });
86
+ try { await fs.copy(dmgPath, cachedPath); } catch (e) { /* ignore */ }
87
+ }
88
+
89
+ const installSpinner = ora('Installing AWS Kiro...').start();
90
+
91
+ try {
92
+ // Mount DMG
93
+ installSpinner.text = 'Mounting disk image...';
94
+ // -nobrowse to prevent opening Finder window, -noverify to speed up
95
+ execSync(`hdiutil attach "${dmgPath}" -nobrowse -noverify -mountpoint "${tempDir}/mount"`);
96
+
97
+ // Copy App
98
+ installSpinner.text = 'Copying to Applications...';
99
+
100
+ // Look for .app file
101
+ const files = await fs.readdir(path.join(tempDir, 'mount'));
102
+ const appName = files.find(f => f.endsWith('.app'));
103
+
104
+ if (!appName) {
105
+ throw new Error('Could not find .app file in the downloaded DMG.');
106
+ }
107
+
108
+ const fullSourcePath = path.join(tempDir, 'mount', appName);
109
+ const destinationPath = path.join('/Applications', appName);
110
+
111
+ // Remove existing if any
112
+ if (await fs.pathExists(destinationPath)) {
113
+ installSpinner.text = 'Replacing existing installation...';
114
+ await fs.remove(destinationPath);
115
+ }
116
+ // Use robust copy with progress (rsync -> ditto -> node stream)
117
+ try {
118
+ const { copyAppWithProgress } = require('./copy-with-progress');
119
+ installSpinner.stop();
120
+ const ok = await copyAppWithProgress(fullSourcePath, destinationPath, { spinner: installSpinner });
121
+ if (!ok) {
122
+ console.log('Falling back to cp -R for installation...');
123
+ installSpinner.start();
124
+ try {
125
+ execSync(`cp -R "${fullSourcePath}" "/Applications/"`, { stdio: 'inherit' });
126
+ } catch (e) {
127
+ installSpinner.text = 'Copying (fs fallback) to /Applications...';
128
+ await fs.copy(fullSourcePath, destinationPath);
129
+ }
130
+ } else {
131
+ installSpinner.start();
132
+ }
133
+ } catch (e) {
134
+ installSpinner.text = 'Copying (cp/fs fallback) to /Applications...';
135
+ try {
136
+ execSync(`cp -R "${fullSourcePath}" "/Applications/"`, { stdio: 'inherit' });
137
+ } catch (err) {
138
+ await fs.copy(fullSourcePath, destinationPath);
139
+ }
140
+ }
141
+
142
+ // Unmount
143
+ installSpinner.text = 'Cleaning up...';
144
+ execSync(`hdiutil detach "${tempDir}/mount" -force`);
145
+ await fs.remove(tempDir);
146
+
147
+ installSpinner.succeed('AWS Kiro successfully installed!');
148
+ console.log(chalk.green(`\n✅ Installed to ${destinationPath}`));
149
+
150
+ return true;
151
+ } catch (installError) {
152
+ installSpinner.fail('Installation failed during file operations');
153
+ // Try to cleanup even if install failed
154
+ try {
155
+ if (fs.existsSync(path.join(tempDir, 'mount'))) {
156
+ execSync(`hdiutil detach "${tempDir}/mount" -force`);
157
+ }
158
+ await fs.remove(tempDir);
159
+ } catch (cleanupError) {
160
+ // Ignore cleanup errors
161
+ }
162
+ throw installError;
163
+ }
164
+
165
+ } catch (error) {
166
+ // If error was thrown, spinners should have been handled, but just in case
167
+ // The main catch block for installKiro should not call ora().fail()
168
+ // as specific spinners (downloadSpinner, installSpinner) would have already failed.
169
+ // We log the manual download link
170
+ console.log(chalk.red('\nYou may need to download manually from: https://kiro.dev'));
171
+ return false;
172
+ }
173
+ }
174
+
175
+ module.exports = {
176
+ isKiroInstalled,
177
+ installKiro
178
+ };
@@ -76,9 +76,7 @@ function formatAutoModeHeader(status) {
76
76
  step = 'PREPARE',
77
77
  chatCount = 0,
78
78
  maxChats = null,
79
- progress = 0,
80
- repoPath = '',
81
- hostname = ''
79
+ progress = 0
82
80
  } = status;
83
81
 
84
82
  const stepColors = {
@@ -1,5 +1,3 @@
1
- const path = require('path');
2
- const os = require('os');
3
1
  const { getAutoConfig, setAutoConfig } = require('./config');
4
2
 
5
3
  const PROVIDER_DEFINITIONS = [
@@ -9,6 +7,7 @@ const PROVIDER_DEFINITIONS = [
9
7
  type: 'direct',
10
8
  category: 'llm',
11
9
  defaultModel: 'llama-3.3-70b-versatile',
10
+ fallbackModels: ['llama-3.1-70b-versatile', 'llama-3.1-8b-instant', 'mixtral-8x7b-32768'],
12
11
  configKeys: { apiKey: 'groqApiKey', model: 'groqModel' },
13
12
  estimatedSpeed: 15000
14
13
  },
@@ -17,7 +16,8 @@ const PROVIDER_DEFINITIONS = [
17
16
  name: 'Anthropic (Claude Sonnet 4)',
18
17
  type: 'direct',
19
18
  category: 'llm',
20
- defaultModel: 'claude-sonnet-4-20250514',
19
+ defaultModel: 'claude-3-5-sonnet-20241022',
20
+ fallbackModels: ['claude-3-5-haiku-20241022', 'claude-3-opus-20240229'],
21
21
  configKeys: { apiKey: 'anthropicApiKey', model: 'anthropicModel' },
22
22
  estimatedSpeed: 25000
23
23
  },
@@ -26,7 +26,8 @@ const PROVIDER_DEFINITIONS = [
26
26
  name: 'AWS Bedrock (Claude)',
27
27
  type: 'direct',
28
28
  category: 'llm',
29
- defaultModel: 'anthropic.claude-sonnet-4-v1',
29
+ defaultModel: 'anthropic.claude-3-5-sonnet-20241022-v2:0',
30
+ fallbackModels: ['anthropic.claude-3-5-haiku-20241022-v1:0', 'anthropic.claude-3-sonnet-20240229-v1:0'],
30
31
  configKeys: { region: 'awsRegion', accessKeyId: 'awsAccessKeyId', secretAccessKey: 'awsSecretAccessKey' },
31
32
  estimatedSpeed: 40000
32
33
  },
@@ -62,6 +63,14 @@ const PROVIDER_DEFINITIONS = [
62
63
  ide: 'antigravity',
63
64
  estimatedSpeed: 90000
64
65
  },
66
+ {
67
+ id: 'kiro',
68
+ name: 'AWS Kiro AI IDE',
69
+ type: 'ide',
70
+ category: 'ide',
71
+ ide: 'kiro',
72
+ estimatedSpeed: 90000
73
+ },
65
74
  {
66
75
  id: 'ollama',
67
76
  name: 'Ollama (Local)',
@@ -64,7 +64,8 @@ function renderStatusCard(status) {
64
64
  borderStyle: 'round',
65
65
  borderColor: 'magenta',
66
66
  title: 'Auto Mode Status',
67
- titleAlignment: 'center'
67
+ titleAlignment: 'center',
68
+ width: 80
68
69
  });
69
70
  }
70
71
 
@@ -0,0 +1,300 @@
1
+ /**
2
+ * User Tracking Integration for CLI
3
+ *
4
+ * This module integrates the CLI with the enhanced user tracking system,
5
+ * automatically logging user activities and updating usage statistics.
6
+ */
7
+
8
+ const auth = require('./auth')
9
+
10
+ class CLIUserTracking {
11
+ constructor() {
12
+ this.sessionStartTime = Date.now()
13
+ this.activityBuffer = []
14
+ this.flushInterval = null
15
+
16
+ // Start periodic flush of activity data
17
+ this.startActivityFlush()
18
+ }
19
+
20
+ /**
21
+ * Track CLI command execution
22
+ */
23
+ async trackCommand(command, args = [], metadata = {}) {
24
+ try {
25
+ await auth.trackCLIActivity('command_executed', {
26
+ command,
27
+ args: args.filter(arg => !arg.includes('password') && !arg.includes('token')), // Filter sensitive data
28
+ duration: 0,
29
+ ...metadata
30
+ })
31
+ } catch (error) {
32
+ // Silently fail - don't disrupt user experience
33
+ console.debug('Failed to track command:', error.message)
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Track requirement operations
39
+ */
40
+ async trackRequirementActivity(action, requirementData = {}) {
41
+ try {
42
+ await auth.trackCLIActivity('requirement_activity', {
43
+ action, // 'created', 'updated', 'completed', 'verified', etc.
44
+ requirementId: requirementData.id,
45
+ package: requirementData.package,
46
+ duration: 0,
47
+ metadata: {
48
+ hasDescription: !!requirementData.description,
49
+ descriptionLength: requirementData.description?.length || 0,
50
+ timestamp: Date.now()
51
+ }
52
+ })
53
+ } catch (error) {
54
+ console.debug('Failed to track requirement activity:', error.message)
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Track auto mode sessions
60
+ */
61
+ async trackAutoModeSession(action, sessionData = {}) {
62
+ try {
63
+ await auth.trackCLIActivity('auto_mode', {
64
+ action, // 'started', 'stopped', 'iteration_completed'
65
+ duration: sessionData.duration || 0,
66
+ metadata: {
67
+ maxIterations: sessionData.maxIterations,
68
+ completedIterations: sessionData.completedIterations,
69
+ ide: sessionData.ide,
70
+ timestamp: Date.now()
71
+ }
72
+ })
73
+ } catch (error) {
74
+ console.debug('Failed to track auto mode session:', error.message)
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Track IDE interactions
80
+ */
81
+ async trackIDEInteraction(ide, action, metadata = {}) {
82
+ try {
83
+ await auth.trackCLIActivity('ide_interaction', {
84
+ action, // 'opened', 'sent_message', 'received_response'
85
+ ide,
86
+ duration: metadata.duration || 0,
87
+ metadata: {
88
+ messageLength: metadata.messageLength,
89
+ responseLength: metadata.responseLength,
90
+ success: metadata.success !== false,
91
+ timestamp: Date.now()
92
+ }
93
+ })
94
+ } catch (error) {
95
+ console.debug('Failed to track IDE interaction:', error.message)
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Track project operations
101
+ */
102
+ async trackProjectActivity(action, projectData = {}) {
103
+ try {
104
+ await auth.trackCLIActivity('project_activity', {
105
+ action, // 'created', 'opened', 'switched'
106
+ duration: 0,
107
+ metadata: {
108
+ projectPath: projectData.path,
109
+ hasDescription: !!projectData.description,
110
+ techStack: projectData.techStack || [],
111
+ timestamp: Date.now()
112
+ }
113
+ })
114
+ } catch (error) {
115
+ console.debug('Failed to track project activity:', error.message)
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Track sync operations
121
+ */
122
+ async trackSyncActivity(action, syncData = {}) {
123
+ try {
124
+ await auth.trackCLIActivity('sync_activity', {
125
+ action, // 'started', 'completed', 'failed'
126
+ duration: syncData.duration || 0,
127
+ metadata: {
128
+ itemsSync: syncData.itemsSync || 0,
129
+ conflicts: syncData.conflicts || 0,
130
+ success: syncData.success !== false,
131
+ timestamp: Date.now()
132
+ }
133
+ })
134
+ } catch (error) {
135
+ console.debug('Failed to track sync activity:', error.message)
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Track session duration and end session
141
+ */
142
+ async endSession() {
143
+ try {
144
+ const sessionDuration = Date.now() - this.sessionStartTime
145
+
146
+ await auth.trackCLIActivity('session_ended', {
147
+ duration: Math.round(sessionDuration / 1000), // Convert to seconds
148
+ metadata: {
149
+ sessionStartTime: this.sessionStartTime,
150
+ sessionEndTime: Date.now(),
151
+ totalCommands: this.activityBuffer.length,
152
+ timestamp: Date.now()
153
+ }
154
+ })
155
+
156
+ // Stop activity flushing
157
+ if (this.flushInterval) {
158
+ clearInterval(this.flushInterval)
159
+ }
160
+ } catch (error) {
161
+ console.debug('Failed to track session end:', error.message)
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Start periodic flushing of activity data
167
+ */
168
+ startActivityFlush() {
169
+ // Flush activity buffer every 5 minutes
170
+ this.flushInterval = setInterval(() => {
171
+ this.flushActivityBuffer()
172
+ }, 5 * 60 * 1000)
173
+ }
174
+
175
+ /**
176
+ * Flush buffered activity data
177
+ */
178
+ async flushActivityBuffer() {
179
+ if (this.activityBuffer.length === 0) return
180
+
181
+ try {
182
+ // Update user activity timestamp
183
+ const token = await auth.getToken()
184
+ if (token && token.id_token) {
185
+ await auth._updateUserActivity()
186
+ }
187
+
188
+ // Clear buffer after successful flush
189
+ this.activityBuffer = []
190
+ } catch (error) {
191
+ console.debug('Failed to flush activity buffer:', error.message)
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Register project with enhanced tracking
197
+ */
198
+ async registerProject(projectInfo) {
199
+ try {
200
+ const token = await auth.getToken()
201
+ if (!token || !token.id_token) return null
202
+
203
+ const payload = JSON.parse(Buffer.from(token.id_token.split('.')[1], 'base64').toString())
204
+
205
+ const UserDatabase = require('vibecodingmachine-core/src/database/user-schema')
206
+ const userDb = new UserDatabase()
207
+
208
+ const userId = userDb.generateUserId(payload.email)
209
+
210
+ const project = await userDb.registerProject(userId, {
211
+ name: projectInfo.name || 'Unnamed Project',
212
+ description: projectInfo.description || '',
213
+ path: projectInfo.path || process.cwd(),
214
+ techStack: projectInfo.techStack || [],
215
+ framework: projectInfo.framework || '',
216
+ language: projectInfo.language || '',
217
+ goals: projectInfo.goals || '',
218
+ category: projectInfo.category || 'general'
219
+ })
220
+
221
+ // Track project creation
222
+ await this.trackProjectActivity('created', {
223
+ path: project.path,
224
+ description: project.description,
225
+ techStack: project.techStack
226
+ })
227
+
228
+ return project
229
+ } catch (error) {
230
+ console.debug('Failed to register project:', error.message)
231
+ return null
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Check and prompt for compliance if needed
237
+ */
238
+ async checkCompliance() {
239
+ try {
240
+ const token = await auth.getToken()
241
+ if (!token || !token.id_token) return { compliant: false }
242
+
243
+ const payload = JSON.parse(Buffer.from(token.id_token.split('.')[1], 'base64').toString())
244
+
245
+ const ComplianceManager = require('vibecodingmachine-core/src/compliance/compliance-manager')
246
+ const compliance = new ComplianceManager()
247
+
248
+ const UserDatabase = require('vibecodingmachine-core/src/database/user-schema')
249
+ const userDb = new UserDatabase()
250
+ const userId = userDb.generateUserId(payload.email)
251
+
252
+ const status = await compliance.checkComplianceStatus(userId)
253
+
254
+ return {
255
+ compliant: !status.needsAcknowledgment,
256
+ termsAccepted: status.termsAccepted,
257
+ privacyAccepted: status.privacyAccepted,
258
+ requiredActions: status.requiredActions
259
+ }
260
+ } catch (error) {
261
+ console.debug('Failed to check compliance:', error.message)
262
+ return { compliant: true } // Default to compliant to not block users
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Record compliance acknowledgment
268
+ */
269
+ async recordCompliance(acknowledgments) {
270
+ try {
271
+ const token = await auth.getToken()
272
+ if (!token || !token.id_token) return false
273
+
274
+ const payload = JSON.parse(Buffer.from(token.id_token.split('.')[1], 'base64').toString())
275
+
276
+ const ComplianceManager = require('vibecodingmachine-core/src/compliance/compliance-manager')
277
+ const compliance = new ComplianceManager()
278
+
279
+ const UserDatabase = require('vibecodingmachine-core/src/database/user-schema')
280
+ const userDb = new UserDatabase()
281
+ const userId = userDb.generateUserId(payload.email)
282
+
283
+ await compliance.recordAcknowledgment(userId, acknowledgments)
284
+
285
+ // Track compliance activity
286
+ await this.trackCommand('compliance_acknowledged', [], {
287
+ termsAccepted: acknowledgments.terms,
288
+ privacyAccepted: acknowledgments.privacy
289
+ })
290
+
291
+ return true
292
+ } catch (error) {
293
+ console.debug('Failed to record compliance:', error.message)
294
+ return false
295
+ }
296
+ }
297
+ }
298
+
299
+ // Export singleton instance
300
+ module.exports = new CLIUserTracking()
@@ -0,0 +1,28 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ describe('Requirements Navigator regression: buildTree must be awaited', () => {
5
+ test('interactive.js does not call buildTree() without await', () => {
6
+ const interactivePath = path.join(__dirname, '../src/utils/interactive.js');
7
+ const content = fs.readFileSync(interactivePath, 'utf8');
8
+ const lines = content.split('\n');
9
+
10
+ const offending = [];
11
+
12
+ for (let i = 0; i < lines.length; i++) {
13
+ const line = lines[i];
14
+ if (!line.includes('buildTree();')) continue;
15
+
16
+ const trimmed = line.trim();
17
+
18
+ // Ignore the function definition line(s)
19
+ if (trimmed.startsWith('const buildTree') || trimmed.startsWith('function buildTree')) continue;
20
+
21
+ if (trimmed !== 'await buildTree();') {
22
+ offending.push({ lineNumber: i + 1, line: trimmed });
23
+ }
24
+ }
25
+
26
+ expect(offending).toEqual([]);
27
+ });
28
+ });