vibecodingmachine-core 1.0.0

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 (54) hide show
  1. package/.babelrc +13 -0
  2. package/README.md +28 -0
  3. package/__tests__/applescript-manager-claude-fix.test.js +286 -0
  4. package/__tests__/requirement-2-auto-start-looping.test.js +69 -0
  5. package/__tests__/requirement-3-auto-start-looping.test.js +69 -0
  6. package/__tests__/requirement-4-auto-start-looping.test.js +69 -0
  7. package/__tests__/requirement-6-auto-start-looping.test.js +73 -0
  8. package/__tests__/requirement-7-status-tracking.test.js +332 -0
  9. package/jest.config.js +18 -0
  10. package/jest.setup.js +12 -0
  11. package/package.json +46 -0
  12. package/src/auth/access-denied.html +119 -0
  13. package/src/auth/shared-auth-storage.js +230 -0
  14. package/src/autonomous-mode/feature-implementer.cjs +70 -0
  15. package/src/autonomous-mode/feature-implementer.js +425 -0
  16. package/src/chat-management/chat-manager.cjs +71 -0
  17. package/src/chat-management/chat-manager.js +342 -0
  18. package/src/ide-integration/__tests__/applescript-manager-thread-closure.test.js +227 -0
  19. package/src/ide-integration/aider-cli-manager.cjs +850 -0
  20. package/src/ide-integration/applescript-diagnostics.js +0 -0
  21. package/src/ide-integration/applescript-manager.cjs +1088 -0
  22. package/src/ide-integration/applescript-manager.js +2803 -0
  23. package/src/ide-integration/applescript-open-apps.js +0 -0
  24. package/src/ide-integration/applescript-read-response.js +0 -0
  25. package/src/ide-integration/applescript-send-text.js +0 -0
  26. package/src/ide-integration/applescript-thread-closure.js +0 -0
  27. package/src/ide-integration/applescript-utils.js +306 -0
  28. package/src/ide-integration/cdp-manager.cjs +221 -0
  29. package/src/ide-integration/cdp-manager.js +321 -0
  30. package/src/ide-integration/claude-code-cli-manager.cjs +301 -0
  31. package/src/ide-integration/cline-cli-manager.cjs +2252 -0
  32. package/src/ide-integration/continue-cli-manager.js +431 -0
  33. package/src/ide-integration/provider-manager.cjs +354 -0
  34. package/src/ide-integration/quota-detector.cjs +34 -0
  35. package/src/ide-integration/quota-detector.js +349 -0
  36. package/src/ide-integration/windows-automation-manager.js +262 -0
  37. package/src/index.cjs +43 -0
  38. package/src/index.js +17 -0
  39. package/src/llm/direct-llm-manager.cjs +609 -0
  40. package/src/ui/ButtonComponents.js +247 -0
  41. package/src/ui/ChatInterface.js +499 -0
  42. package/src/ui/StateManager.js +259 -0
  43. package/src/ui/StateManager.test.js +0 -0
  44. package/src/utils/audit-logger.cjs +116 -0
  45. package/src/utils/config-helpers.cjs +94 -0
  46. package/src/utils/config-helpers.js +94 -0
  47. package/src/utils/electron-update-checker.js +78 -0
  48. package/src/utils/gcloud-auth.cjs +394 -0
  49. package/src/utils/logger.cjs +193 -0
  50. package/src/utils/logger.js +191 -0
  51. package/src/utils/repo-helpers.cjs +120 -0
  52. package/src/utils/repo-helpers.js +120 -0
  53. package/src/utils/requirement-helpers.js +432 -0
  54. package/src/utils/update-checker.js +167 -0
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Shared State Manager
3
+ * Manages state synchronization between electron app and VSCode extension
4
+ */
5
+
6
+ class StateManager {
7
+ constructor() {
8
+ this.state = {
9
+ autonomousMode: false,
10
+ isPaused: false,
11
+ isStopped: false,
12
+ isCheckingQuota: false,
13
+ isOpeningIde: false,
14
+ currentIde: 'vscode', // Default IDE
15
+ featureProgress: 0,
16
+ currentFeature: null,
17
+ status: 'Ready to chat',
18
+ messages: [],
19
+ tabs: [],
20
+ activeTabId: null
21
+ };
22
+
23
+ this.listeners = new Set();
24
+ this.storageKey = 'allnightai-shared-state';
25
+ }
26
+
27
+ // Get current state
28
+ getState() {
29
+ return { ...this.state };
30
+ }
31
+
32
+ // Update state and notify listeners
33
+ setState(updates) {
34
+ const oldState = { ...this.state };
35
+ this.state = { ...this.state, ...updates };
36
+
37
+ // Save to localStorage for persistence
38
+ this.saveToStorage();
39
+
40
+ // Notify all listeners
41
+ this.listeners.forEach(listener => {
42
+ try {
43
+ listener(this.state, oldState);
44
+ } catch (error) {
45
+ console.error('State listener error:', error);
46
+ }
47
+ });
48
+ }
49
+
50
+ // Subscribe to state changes
51
+ subscribe(listener) {
52
+ this.listeners.add(listener);
53
+
54
+ // Return unsubscribe function
55
+ return () => {
56
+ this.listeners.delete(listener);
57
+ };
58
+ }
59
+
60
+ // Save state to localStorage
61
+ saveToStorage() {
62
+ try {
63
+ localStorage.setItem(this.storageKey, JSON.stringify(this.state));
64
+ } catch (error) {
65
+ console.error('Failed to save state to storage:', error);
66
+ }
67
+ }
68
+
69
+ // Load state from localStorage
70
+ loadFromStorage() {
71
+ try {
72
+ const saved = localStorage.getItem(this.storageKey);
73
+ if (saved) {
74
+ const parsed = JSON.parse(saved);
75
+ this.setState(parsed);
76
+ }
77
+ } catch (error) {
78
+ console.error('Failed to load state from storage:', error);
79
+ }
80
+ }
81
+
82
+ // Autonomous mode actions
83
+ startAutonomousMode(ide) {
84
+ this.setState({
85
+ autonomousMode: true,
86
+ isPaused: false,
87
+ isStopped: false,
88
+ currentIde: ide,
89
+ status: 'Starting autonomous mode...',
90
+ featureProgress: 0
91
+ });
92
+ }
93
+
94
+ stopAutonomousMode() {
95
+ this.setState({
96
+ autonomousMode: false,
97
+ isPaused: false,
98
+ isStopped: true,
99
+ status: 'Autonomous mode stopped',
100
+ featureProgress: 0,
101
+ currentFeature: null
102
+ });
103
+ }
104
+
105
+ pauseAutonomousMode() {
106
+ this.setState({
107
+ isPaused: true,
108
+ status: 'Autonomous mode paused'
109
+ });
110
+ }
111
+
112
+ resumeAutonomousMode() {
113
+ this.setState({
114
+ isPaused: false,
115
+ status: 'Autonomous mode resumed'
116
+ });
117
+ }
118
+
119
+ togglePause() {
120
+ if (this.state.isPaused) {
121
+ this.resumeAutonomousMode();
122
+ } else {
123
+ this.pauseAutonomousMode();
124
+ }
125
+ }
126
+
127
+ // Quota checking
128
+ startQuotaCheck() {
129
+ this.setState({
130
+ isCheckingQuota: true,
131
+ status: 'Checking quota...'
132
+ });
133
+ }
134
+
135
+ finishQuotaCheck(result) {
136
+ this.setState({
137
+ isCheckingQuota: false,
138
+ status: result.success ? 'Quota check completed' : 'Quota check failed'
139
+ });
140
+ }
141
+
142
+ // IDE opening
143
+ startOpeningIde() {
144
+ this.setState({
145
+ isOpeningIde: true,
146
+ status: 'Opening IDE...'
147
+ });
148
+ }
149
+
150
+ finishOpeningIde(result) {
151
+ this.setState({
152
+ isOpeningIde: false,
153
+ status: result.success ? 'IDE opened successfully' : 'Failed to open IDE'
154
+ });
155
+ }
156
+
157
+ // Feature progress
158
+ updateFeatureProgress(progress, feature = null) {
159
+ this.setState({
160
+ featureProgress: progress,
161
+ currentFeature: feature,
162
+ status: `Autonomous mode progress: ${progress}%`
163
+ });
164
+ }
165
+
166
+ // Message management
167
+ addMessage(role, text) {
168
+ const message = {
169
+ id: Date.now(),
170
+ role,
171
+ text,
172
+ timestamp: new Date().toISOString()
173
+ };
174
+
175
+ this.setState({
176
+ messages: [...this.state.messages, message]
177
+ });
178
+ }
179
+
180
+ clearMessages() {
181
+ this.setState({
182
+ messages: []
183
+ });
184
+ }
185
+
186
+ // Tab management
187
+ setTabs(tabs) {
188
+ this.setState({
189
+ tabs,
190
+ activeTabId: tabs.length > 0 ? tabs[0].id : null
191
+ });
192
+ }
193
+
194
+ setActiveTab(tabId) {
195
+ this.setState({
196
+ activeTabId: tabId
197
+ });
198
+ }
199
+
200
+ // Status updates
201
+ updateStatus(status) {
202
+ this.setState({
203
+ status
204
+ });
205
+ }
206
+
207
+ // Reset state
208
+ reset() {
209
+ this.setState({
210
+ autonomousMode: false,
211
+ isPaused: false,
212
+ isStopped: false,
213
+ isCheckingQuota: false,
214
+ isOpeningIde: false,
215
+ currentIde: 'vscode', // Default IDE
216
+ featureProgress: 0,
217
+ currentFeature: null,
218
+ status: 'Ready to chat',
219
+ messages: [],
220
+ tabs: [],
221
+ activeTabId: null
222
+ });
223
+ }
224
+
225
+ // Get specific state values
226
+ isAutonomousMode() {
227
+ return this.state.autonomousMode;
228
+ }
229
+
230
+ isPaused() {
231
+ return this.state.isPaused;
232
+ }
233
+
234
+ isStopped() {
235
+ return this.state.isStopped;
236
+ }
237
+
238
+ getCurrentIde() {
239
+ return this.state.currentIde;
240
+ }
241
+
242
+ getStatus() {
243
+ return this.state.status;
244
+ }
245
+
246
+ getProgress() {
247
+ return this.state.featureProgress;
248
+ }
249
+ }
250
+
251
+ // Create singleton instance
252
+ const stateManager = new StateManager();
253
+
254
+ // Load initial state from storage
255
+ if (typeof window !== 'undefined') {
256
+ stateManager.loadFromStorage();
257
+ }
258
+
259
+ export { StateManager, stateManager };
File without changes
@@ -0,0 +1,116 @@
1
+ // Shared audit logger for both Electron app and CLI
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ function getDateStr(d = new Date()) {
6
+ const y = d.getFullYear();
7
+ const m = String(d.getMonth() + 1).padStart(2, '0');
8
+ const day = String(d.getDate()).padStart(2, '0');
9
+ return `${y}-${m}-${day}`;
10
+ }
11
+
12
+ function getAuditLogDir() {
13
+ return path.join(process.cwd(), 'logs', 'audit');
14
+ }
15
+
16
+ function ensureAuditLogDir() {
17
+ const dir = getAuditLogDir();
18
+ try {
19
+ fs.mkdirSync(dir, { recursive: true });
20
+ } catch (_) {}
21
+ return dir;
22
+ }
23
+
24
+ function appendAuditLog(entry) {
25
+ try {
26
+ const dir = ensureAuditLogDir();
27
+ const when = entry && entry.timestamp ? new Date(entry.timestamp) : new Date();
28
+ const dateStr = getDateStr(when);
29
+ const filePath = path.join(dir, `${dateStr}.jsonl`);
30
+ const line = JSON.stringify(entry) + '\n';
31
+ fs.appendFileSync(filePath, line);
32
+ return { success: true };
33
+ } catch (e) {
34
+ return { success: false, error: e.message };
35
+ }
36
+ }
37
+
38
+ function listAuditLogDates() {
39
+ try {
40
+ const dir = getAuditLogDir();
41
+ if (!fs.existsSync(dir)) return [];
42
+ return fs.readdirSync(dir)
43
+ .filter(f => f.endsWith('.jsonl'))
44
+ .map(f => f.replace(/\.jsonl$/, ''))
45
+ .sort();
46
+ } catch (e) {
47
+ return [];
48
+ }
49
+ }
50
+
51
+ function readAuditLog(dateStr) {
52
+ try {
53
+ const dir = getAuditLogDir();
54
+ const filePath = path.join(dir, `${dateStr}.jsonl`);
55
+ if (!fs.existsSync(filePath)) return [];
56
+ const data = fs.readFileSync(filePath, 'utf8');
57
+ return data.split('\n').filter(Boolean).map(line => {
58
+ try {
59
+ return JSON.parse(line);
60
+ } catch {
61
+ return null;
62
+ }
63
+ }).filter(Boolean);
64
+ } catch (e) {
65
+ return [];
66
+ }
67
+ }
68
+
69
+ function logAutoModeStart(ide, maxChats) {
70
+ const entry = {
71
+ timestamp: new Date().toISOString(),
72
+ type: 'auto-mode-start',
73
+ ide,
74
+ maxChats,
75
+ message: `Auto Mode started with ${ide}, max chats: ${maxChats === 0 ? 'unlimited' : maxChats}`
76
+ };
77
+ appendAuditLog(entry);
78
+ return entry;
79
+ }
80
+
81
+ function logAutoModeStop(reason = 'manual') {
82
+ const entry = {
83
+ timestamp: new Date().toISOString(),
84
+ type: 'auto-mode-stop',
85
+ reason,
86
+ message: `Auto Mode stopped (${reason})`
87
+ };
88
+ appendAuditLog(entry);
89
+ return entry;
90
+ }
91
+
92
+ function logIDEMessage(ide, message, truncate = 100) {
93
+ const displayMessage = message.length > truncate
94
+ ? message.substring(0, truncate) + '...'
95
+ : message;
96
+
97
+ const entry = {
98
+ timestamp: new Date().toISOString(),
99
+ type: 'ide-message',
100
+ ide,
101
+ message: displayMessage,
102
+ fullMessage: message
103
+ };
104
+ appendAuditLog(entry);
105
+ return entry;
106
+ }
107
+
108
+ module.exports = {
109
+ appendAuditLog,
110
+ listAuditLogDates,
111
+ readAuditLog,
112
+ logAutoModeStart,
113
+ logAutoModeStop,
114
+ logIDEMessage,
115
+ getDateStr
116
+ };
@@ -0,0 +1,94 @@
1
+ const path = require('path');
2
+ const fs = require('fs-extra');
3
+ const os = require('os');
4
+
5
+ /**
6
+ * Get the config directory path
7
+ * Uses the same location as Electron's app.getPath('userData')
8
+ * @returns {string} The config directory path
9
+ */
10
+ function getConfigDir() {
11
+ const platform = process.platform;
12
+ const home = os.homedir();
13
+
14
+ let configDir;
15
+ if (platform === 'darwin') {
16
+ // macOS: ~/Library/Application Support/allnightai
17
+ configDir = path.join(home, 'Library', 'Application Support', 'allnightai');
18
+ } else if (platform === 'win32') {
19
+ // Windows: %APPDATA%\allnightai
20
+ configDir = path.join(process.env.APPDATA || path.join(home, 'AppData', 'Roaming'), 'allnightai');
21
+ } else {
22
+ // Linux: ~/.config/allnightai
23
+ configDir = path.join(home, '.config', 'allnightai');
24
+ }
25
+
26
+ return configDir;
27
+ }
28
+
29
+ /**
30
+ * Get the config file path
31
+ * @returns {string} The config file path
32
+ */
33
+ function getConfigPath() {
34
+ return path.join(getConfigDir(), 'allnightai-config.json');
35
+ }
36
+
37
+ /**
38
+ * Load the config from disk
39
+ * @returns {Promise<Object>} The config object
40
+ */
41
+ async function loadConfig() {
42
+ try {
43
+ const configPath = getConfigPath();
44
+ if (await fs.pathExists(configPath)) {
45
+ return await fs.readJson(configPath);
46
+ }
47
+ } catch (error) {
48
+ // Ignore errors, return empty config
49
+ }
50
+ return {};
51
+ }
52
+
53
+ /**
54
+ * Save the config to disk
55
+ * @param {Object} config - The config object to save
56
+ * @returns {Promise<void>}
57
+ */
58
+ async function saveConfig(config) {
59
+ const configPath = getConfigPath();
60
+ await fs.ensureDir(path.dirname(configPath));
61
+ await fs.writeJson(configPath, config, { spaces: 2 });
62
+ }
63
+
64
+ /**
65
+ * Get a config value
66
+ * @param {string} key - The config key
67
+ * @param {*} defaultValue - The default value if key doesn't exist
68
+ * @returns {Promise<*>} The config value
69
+ */
70
+ async function getConfigValue(key, defaultValue = null) {
71
+ const config = await loadConfig();
72
+ return config[key] !== undefined ? config[key] : defaultValue;
73
+ }
74
+
75
+ /**
76
+ * Set a config value
77
+ * @param {string} key - The config key
78
+ * @param {*} value - The value to set
79
+ * @returns {Promise<void>}
80
+ */
81
+ async function setConfigValue(key, value) {
82
+ const config = await loadConfig();
83
+ config[key] = value;
84
+ await saveConfig(config);
85
+ }
86
+
87
+ module.exports = {
88
+ getConfigDir,
89
+ getConfigPath,
90
+ loadConfig,
91
+ saveConfig,
92
+ getConfigValue,
93
+ setConfigValue
94
+ };
@@ -0,0 +1,94 @@
1
+ const path = require('path');
2
+ const fs = require('fs-extra');
3
+ const os = require('os');
4
+
5
+ /**
6
+ * Get the config directory path
7
+ * Uses the same location as Electron's app.getPath('userData')
8
+ * @returns {string} The config directory path
9
+ */
10
+ function getConfigDir() {
11
+ const platform = process.platform;
12
+ const home = os.homedir();
13
+
14
+ let configDir;
15
+ if (platform === 'darwin') {
16
+ // macOS: ~/Library/Application Support/allnightai
17
+ configDir = path.join(home, 'Library', 'Application Support', 'allnightai');
18
+ } else if (platform === 'win32') {
19
+ // Windows: %APPDATA%\allnightai
20
+ configDir = path.join(process.env.APPDATA || path.join(home, 'AppData', 'Roaming'), 'allnightai');
21
+ } else {
22
+ // Linux: ~/.config/allnightai
23
+ configDir = path.join(home, '.config', 'allnightai');
24
+ }
25
+
26
+ return configDir;
27
+ }
28
+
29
+ /**
30
+ * Get the config file path
31
+ * @returns {string} The config file path
32
+ */
33
+ function getConfigPath() {
34
+ return path.join(getConfigDir(), 'allnightai-config.json');
35
+ }
36
+
37
+ /**
38
+ * Load the config from disk
39
+ * @returns {Promise<Object>} The config object
40
+ */
41
+ async function loadConfig() {
42
+ try {
43
+ const configPath = getConfigPath();
44
+ if (await fs.pathExists(configPath)) {
45
+ return await fs.readJson(configPath);
46
+ }
47
+ } catch (error) {
48
+ // Ignore errors, return empty config
49
+ }
50
+ return {};
51
+ }
52
+
53
+ /**
54
+ * Save the config to disk
55
+ * @param {Object} config - The config object to save
56
+ * @returns {Promise<void>}
57
+ */
58
+ async function saveConfig(config) {
59
+ const configPath = getConfigPath();
60
+ await fs.ensureDir(path.dirname(configPath));
61
+ await fs.writeJson(configPath, config, { spaces: 2 });
62
+ }
63
+
64
+ /**
65
+ * Get a config value
66
+ * @param {string} key - The config key
67
+ * @param {*} defaultValue - The default value if key doesn't exist
68
+ * @returns {Promise<*>} The config value
69
+ */
70
+ async function getConfigValue(key, defaultValue = null) {
71
+ const config = await loadConfig();
72
+ return config[key] !== undefined ? config[key] : defaultValue;
73
+ }
74
+
75
+ /**
76
+ * Set a config value
77
+ * @param {string} key - The config key
78
+ * @param {*} value - The value to set
79
+ * @returns {Promise<void>}
80
+ */
81
+ async function setConfigValue(key, value) {
82
+ const config = await loadConfig();
83
+ config[key] = value;
84
+ await saveConfig(config);
85
+ }
86
+
87
+ module.exports = {
88
+ getConfigDir,
89
+ getConfigPath,
90
+ loadConfig,
91
+ saveConfig,
92
+ getConfigValue,
93
+ setConfigValue
94
+ };
@@ -0,0 +1,78 @@
1
+ const https = require('https');
2
+
3
+ /**
4
+ * Check for Electron app updates from S3 version manifest
5
+ * @param {string} currentVersion - Current version (e.g., '1.0.0')
6
+ * @returns {Promise<Object>} Update info or null if no update available
7
+ */
8
+ async function checkForElectronUpdates(currentVersion) {
9
+ return new Promise((resolve, reject) => {
10
+ const manifestUrl = 'https://vibecodingmachine-website.s3.amazonaws.com/version-manifest.json';
11
+
12
+ https.get(manifestUrl, (res) => {
13
+ let data = '';
14
+
15
+ res.on('data', (chunk) => {
16
+ data += chunk;
17
+ });
18
+
19
+ res.on('end', () => {
20
+ try {
21
+ const manifest = JSON.parse(data);
22
+ const latestVersion = manifest.version;
23
+
24
+ if (latestVersion !== currentVersion) {
25
+ const publishedDate = new Date(manifest.publishedDate);
26
+
27
+ // Detect architecture and choose appropriate download URL
28
+ // For auto-updates, use architecture-specific builds (faster, smaller)
29
+ const arch = process.arch; // 'arm64' or 'x64'
30
+ let downloadUrl = manifest.downloadUrl; // Fallback to universal
31
+
32
+ if (arch === 'arm64' && manifest.downloadUrlArm64) {
33
+ downloadUrl = manifest.downloadUrlArm64;
34
+ console.log('✅ Using Apple Silicon optimized update');
35
+ } else if (arch === 'x64' && manifest.downloadUrlX64) {
36
+ downloadUrl = manifest.downloadUrlX64;
37
+ console.log('✅ Using Intel optimized update');
38
+ } else {
39
+ console.log('ℹ️ Using universal build for update');
40
+ }
41
+
42
+ resolve({
43
+ hasUpdate: true,
44
+ currentVersion,
45
+ latestVersion,
46
+ publishedDate: publishedDate.toLocaleString('en-US', {
47
+ year: 'numeric',
48
+ month: '2-digit',
49
+ day: '2-digit',
50
+ hour: '2-digit',
51
+ minute: '2-digit',
52
+ timeZoneName: 'short'
53
+ }),
54
+ downloadUrl,
55
+ releaseNotes: manifest.releaseNotes || ''
56
+ });
57
+ } else {
58
+ resolve({
59
+ hasUpdate: false,
60
+ currentVersion,
61
+ latestVersion
62
+ });
63
+ }
64
+ } catch (error) {
65
+ console.error('Error parsing version manifest:', error);
66
+ resolve({ hasUpdate: false, currentVersion, error: error.message });
67
+ }
68
+ });
69
+ }).on('error', (error) => {
70
+ console.error('Error checking for Electron updates:', error);
71
+ resolve({ hasUpdate: false, currentVersion, error: error.message });
72
+ });
73
+ });
74
+ }
75
+
76
+ module.exports = {
77
+ checkForElectronUpdates
78
+ };