@neurcode-ai/cli 0.3.9 → 0.4.1
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/dist/api-client.d.ts +105 -17
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +388 -85
- package/dist/api-client.js.map +1 -1
- package/dist/commands/allow.d.ts.map +1 -1
- package/dist/commands/allow.js +6 -33
- package/dist/commands/allow.js.map +1 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +56 -13
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/doctor.d.ts +7 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +134 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +13 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +365 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/login.d.ts +8 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +209 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +7 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +70 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/plan.d.ts +2 -0
- package/dist/commands/plan.d.ts.map +1 -1
- package/dist/commands/plan.js +210 -57
- package/dist/commands/plan.js.map +1 -1
- package/dist/commands/prompt.d.ts +6 -0
- package/dist/commands/prompt.d.ts.map +1 -0
- package/dist/commands/prompt.js +254 -0
- package/dist/commands/prompt.js.map +1 -0
- package/dist/commands/revert.d.ts.map +1 -1
- package/dist/commands/revert.js +10 -0
- package/dist/commands/revert.js.map +1 -1
- package/dist/commands/session.d.ts +29 -0
- package/dist/commands/session.d.ts.map +1 -0
- package/dist/commands/session.js +382 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +132 -15
- package/dist/commands/verify.js.map +1 -1
- package/dist/commands/watch.d.ts +8 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +78 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/config.d.ts +29 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +186 -21
- package/dist/config.js.map +1 -1
- package/dist/index.js +120 -3
- package/dist/index.js.map +1 -1
- package/dist/services/integrations/TicketService.d.ts +68 -0
- package/dist/services/integrations/TicketService.d.ts.map +1 -0
- package/dist/services/integrations/TicketService.js +151 -0
- package/dist/services/integrations/TicketService.js.map +1 -0
- package/dist/services/security/SecurityGuard.d.ts +80 -0
- package/dist/services/security/SecurityGuard.d.ts.map +1 -0
- package/dist/services/security/SecurityGuard.js +410 -0
- package/dist/services/security/SecurityGuard.js.map +1 -0
- package/dist/services/watch/BlobStore.d.ts +33 -0
- package/dist/services/watch/BlobStore.d.ts.map +1 -0
- package/dist/services/watch/BlobStore.js +108 -0
- package/dist/services/watch/BlobStore.js.map +1 -0
- package/dist/services/watch/CommandPoller.d.ts +76 -0
- package/dist/services/watch/CommandPoller.d.ts.map +1 -0
- package/dist/services/watch/CommandPoller.js +298 -0
- package/dist/services/watch/CommandPoller.js.map +1 -0
- package/dist/services/watch/Journal.d.ts +58 -0
- package/dist/services/watch/Journal.d.ts.map +1 -0
- package/dist/services/watch/Journal.js +144 -0
- package/dist/services/watch/Journal.js.map +1 -0
- package/dist/services/watch/Sentinel.d.ts +49 -0
- package/dist/services/watch/Sentinel.d.ts.map +1 -0
- package/dist/services/watch/Sentinel.js +205 -0
- package/dist/services/watch/Sentinel.js.map +1 -0
- package/dist/services/watch/Syncer.d.ts +55 -0
- package/dist/services/watch/Syncer.d.ts.map +1 -0
- package/dist/services/watch/Syncer.js +231 -0
- package/dist/services/watch/Syncer.js.map +1 -0
- package/dist/utils/ROILogger.d.ts +16 -0
- package/dist/utils/ROILogger.d.ts.map +1 -0
- package/dist/utils/ROILogger.js +45 -0
- package/dist/utils/ROILogger.js.map +1 -0
- package/dist/utils/box.d.ts +16 -0
- package/dist/utils/box.d.ts.map +1 -0
- package/dist/utils/box.js +85 -0
- package/dist/utils/box.js.map +1 -0
- package/dist/utils/gitignore.d.ts +10 -0
- package/dist/utils/gitignore.d.ts.map +1 -0
- package/dist/utils/gitignore.js +34 -0
- package/dist/utils/gitignore.js.map +1 -0
- package/dist/utils/messages.d.ts +81 -0
- package/dist/utils/messages.d.ts.map +1 -0
- package/dist/utils/messages.js +306 -0
- package/dist/utils/messages.js.map +1 -0
- package/dist/utils/restore.d.ts +14 -0
- package/dist/utils/restore.d.ts.map +1 -0
- package/dist/utils/restore.js +89 -0
- package/dist/utils/restore.js.map +1 -0
- package/dist/utils/state.d.ts +69 -0
- package/dist/utils/state.d.ts.map +1 -0
- package/dist/utils/state.js +151 -0
- package/dist/utils/state.js.map +1 -0
- package/dist/utils/user-context.d.ts +28 -0
- package/dist/utils/user-context.d.ts.map +1 -0
- package/dist/utils/user-context.js +68 -0
- package/dist/utils/user-context.js.map +1 -0
- package/package.json +11 -4
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CommandPoller - Polls for remote commands and executes them locally
|
|
4
|
+
*
|
|
5
|
+
* Polls the cloud API every 3 seconds for pending commands (like file reverts).
|
|
6
|
+
* When a command is received, executes it locally and updates the status.
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.CommandPoller = void 0;
|
|
43
|
+
const config_1 = require("../../config");
|
|
44
|
+
const restore_1 = require("../../utils/restore");
|
|
45
|
+
const BlobStore_1 = require("./BlobStore");
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
const fs_1 = require("fs");
|
|
48
|
+
const crypto_1 = require("crypto");
|
|
49
|
+
/**
|
|
50
|
+
* CommandPoller - Handles polling and execution of remote commands
|
|
51
|
+
*/
|
|
52
|
+
class CommandPoller {
|
|
53
|
+
apiUrl;
|
|
54
|
+
apiKey;
|
|
55
|
+
projectRoot;
|
|
56
|
+
pollInterval = null;
|
|
57
|
+
pollIntervalMs = 3000; // Poll every 3 seconds
|
|
58
|
+
isRunning = false;
|
|
59
|
+
blobStore;
|
|
60
|
+
constructor(projectRoot) {
|
|
61
|
+
this.projectRoot = projectRoot;
|
|
62
|
+
const config = (0, config_1.loadConfig)();
|
|
63
|
+
this.apiUrl = config.apiUrl || config_1.DEFAULT_API_URL;
|
|
64
|
+
this.apiKey = (0, config_1.getApiKey)();
|
|
65
|
+
this.blobStore = new BlobStore_1.BlobStore(projectRoot);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Start polling for commands
|
|
69
|
+
*/
|
|
70
|
+
start() {
|
|
71
|
+
if (this.isRunning) {
|
|
72
|
+
console.warn('⚠️ CommandPoller is already running');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// If no API key, skip silently (local-only mode)
|
|
76
|
+
if (!this.apiKey) {
|
|
77
|
+
console.log('📦 Command polling: DISABLED (no API key configured)');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
this.isRunning = true;
|
|
81
|
+
console.log('🔄 Command polling: ENABLED (checking every 3s)');
|
|
82
|
+
// Start polling immediately, then every 3 seconds
|
|
83
|
+
this.poll();
|
|
84
|
+
this.pollInterval = setInterval(() => {
|
|
85
|
+
this.poll();
|
|
86
|
+
}, this.pollIntervalMs);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Stop polling for commands
|
|
90
|
+
*/
|
|
91
|
+
stop() {
|
|
92
|
+
if (this.pollInterval) {
|
|
93
|
+
clearInterval(this.pollInterval);
|
|
94
|
+
this.pollInterval = null;
|
|
95
|
+
}
|
|
96
|
+
this.isRunning = false;
|
|
97
|
+
console.log('🛑 Command polling stopped');
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Poll for pending commands and execute them
|
|
101
|
+
*/
|
|
102
|
+
async poll() {
|
|
103
|
+
if (!this.apiKey) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
// Poll for pending commands
|
|
108
|
+
const response = await fetch(`${this.apiUrl}/api/v1/commands/poll`, {
|
|
109
|
+
method: 'GET',
|
|
110
|
+
headers: {
|
|
111
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
if (!response.ok) {
|
|
115
|
+
if (response.status === 401 || response.status === 403) {
|
|
116
|
+
// API key invalid, stop polling
|
|
117
|
+
console.warn('⚠️ Command polling: API key invalid, stopping');
|
|
118
|
+
this.stop();
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
// For other errors, log but continue polling
|
|
122
|
+
console.warn(`⚠️ Command poll failed: ${response.status}`);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const data = await response.json();
|
|
126
|
+
if (!data.command) {
|
|
127
|
+
// No pending commands - log occasionally for debugging (every 20 polls = ~1 minute)
|
|
128
|
+
if (Math.random() < 0.05) {
|
|
129
|
+
console.log('🔄 Polling for commands... (no pending commands)');
|
|
130
|
+
}
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
// Execute the command
|
|
134
|
+
console.log(`📥 Found pending command: ${data.command.type} (${data.command.id.substring(0, 8)}...)`);
|
|
135
|
+
await this.executeCommand(data.command);
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
// Log error but continue polling (network issues, etc.)
|
|
139
|
+
console.warn(`⚠️ Command poll error: ${error.message}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Execute a command locally
|
|
144
|
+
*/
|
|
145
|
+
async executeCommand(command) {
|
|
146
|
+
console.log(`📥 Received command: ${command.type} (${command.id.substring(0, 8)}...)`);
|
|
147
|
+
try {
|
|
148
|
+
if (command.type === 'FILE_REVERT') {
|
|
149
|
+
await this.executeFileRevert(command);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
throw new Error(`Unknown command type: ${command.type}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
console.error(`❌ Command execution failed: ${error.message}`);
|
|
157
|
+
await this.updateCommandStatus(command.id, 'FAILED', error.message);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Compute the hash of the current file content
|
|
162
|
+
*/
|
|
163
|
+
async computeCurrentFileHash(filePath) {
|
|
164
|
+
const resolvedPath = path.resolve(this.projectRoot, filePath);
|
|
165
|
+
try {
|
|
166
|
+
// Check if file exists
|
|
167
|
+
await fs_1.promises.access(resolvedPath);
|
|
168
|
+
// Read file content
|
|
169
|
+
const content = await fs_1.promises.readFile(resolvedPath, 'utf-8');
|
|
170
|
+
// Compute SHA-256 hash (same as BlobStore)
|
|
171
|
+
const hash = (0, crypto_1.createHash)('sha256').update(content, 'utf8').digest('hex');
|
|
172
|
+
return hash;
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// File doesn't exist
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Execute a FILE_REVERT command
|
|
181
|
+
*/
|
|
182
|
+
async executeFileRevert(command) {
|
|
183
|
+
const { filePath, blobHash } = command.payload;
|
|
184
|
+
if (!filePath || !blobHash) {
|
|
185
|
+
throw new Error('Missing filePath or blobHash in command payload');
|
|
186
|
+
}
|
|
187
|
+
// Check if blob exists locally
|
|
188
|
+
const blobExists = await this.blobStore.exists(blobHash);
|
|
189
|
+
if (!blobExists) {
|
|
190
|
+
// Blob doesn't exist locally, fetch it from cloud
|
|
191
|
+
console.log(`📥 Blob not found locally, fetching from cloud: ${blobHash.substring(0, 12)}...`);
|
|
192
|
+
await this.fetchBlobFromCloud(blobHash);
|
|
193
|
+
}
|
|
194
|
+
// CRITICAL: Compare target hash with current file hash before reverting
|
|
195
|
+
const currentHash = await this.computeCurrentFileHash(filePath);
|
|
196
|
+
if (currentHash === blobHash) {
|
|
197
|
+
console.log(`⚠️ Skipped revert: Target hash (${blobHash.substring(0, 8)}...) is identical to current file`);
|
|
198
|
+
console.log(` File ${filePath} is already at the requested version`);
|
|
199
|
+
// Mark as completed (no-op, but successful)
|
|
200
|
+
await this.updateCommandStatus(command.id, 'COMPLETED');
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
// Restore the file using existing restoreFile utility
|
|
204
|
+
// Note: restoreFile expects hash and targetPath, and handles decompression
|
|
205
|
+
await (0, restore_1.restoreFile)(blobHash, filePath, this.projectRoot);
|
|
206
|
+
console.log(`✅ File reverted: ${filePath} (${blobHash.substring(0, 8)}...)`);
|
|
207
|
+
if (currentHash) {
|
|
208
|
+
console.log(` Previous: ${currentHash.substring(0, 8)}... → New: ${blobHash.substring(0, 8)}...`);
|
|
209
|
+
}
|
|
210
|
+
// Update command status to COMPLETED
|
|
211
|
+
await this.updateCommandStatus(command.id, 'COMPLETED');
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Fetch blob content from cloud API and store it locally
|
|
215
|
+
*/
|
|
216
|
+
async fetchBlobFromCloud(hash) {
|
|
217
|
+
if (!this.apiKey) {
|
|
218
|
+
throw new Error('API key not found. Please run "neurcode login" first.');
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
const response = await fetch(`${this.apiUrl}/api/v1/blobs/${hash}`, {
|
|
222
|
+
method: 'GET',
|
|
223
|
+
headers: {
|
|
224
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
225
|
+
'Content-Type': 'application/json',
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
if (!response.ok) {
|
|
229
|
+
if (response.status === 404) {
|
|
230
|
+
throw new Error(`Blob not found in cloud storage: ${hash.substring(0, 12)}...`);
|
|
231
|
+
}
|
|
232
|
+
if (response.status === 401 || response.status === 403) {
|
|
233
|
+
throw new Error('API key invalid. Please run "neurcode login" again.');
|
|
234
|
+
}
|
|
235
|
+
throw new Error(`Failed to fetch blob: ${response.status} ${response.statusText}`);
|
|
236
|
+
}
|
|
237
|
+
const data = await response.json();
|
|
238
|
+
// Decode base64 content to get GZIP compressed buffer
|
|
239
|
+
const compressedContent = Buffer.from(data.content, 'base64');
|
|
240
|
+
// Store the blob locally (BlobStore will handle the directory creation)
|
|
241
|
+
await this.blobStore.initialize();
|
|
242
|
+
const blobPath = this.blobStore.getBlobPath(hash);
|
|
243
|
+
await fs_1.promises.writeFile(blobPath, compressedContent);
|
|
244
|
+
console.log(`✅ Blob fetched and stored locally: ${hash.substring(0, 12)}...`);
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
throw new Error(`Failed to fetch blob from cloud: ${error.message}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Update command status on the server
|
|
252
|
+
*/
|
|
253
|
+
async updateCommandStatus(commandId, status, errorMessage) {
|
|
254
|
+
if (!this.apiKey) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
const response = await fetch(`${this.apiUrl}/api/v1/commands/${commandId}/status`, {
|
|
259
|
+
method: 'POST',
|
|
260
|
+
headers: {
|
|
261
|
+
'Content-Type': 'application/json',
|
|
262
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
263
|
+
},
|
|
264
|
+
body: JSON.stringify({
|
|
265
|
+
status,
|
|
266
|
+
errorMessage,
|
|
267
|
+
}),
|
|
268
|
+
});
|
|
269
|
+
if (!response.ok) {
|
|
270
|
+
const errorText = await response.text();
|
|
271
|
+
console.warn(`⚠️ Failed to update command status: ${response.status} ${errorText}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
console.warn(`⚠️ Failed to update command status: ${error.message}`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Check if poller is configured (has API key)
|
|
280
|
+
*/
|
|
281
|
+
isConfigured() {
|
|
282
|
+
return this.apiKey !== null;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Reload API key from config (useful if user logs in after watch starts)
|
|
286
|
+
*/
|
|
287
|
+
reloadConfig() {
|
|
288
|
+
const config = (0, config_1.loadConfig)();
|
|
289
|
+
this.apiUrl = config.apiUrl || config_1.DEFAULT_API_URL;
|
|
290
|
+
this.apiKey = (0, config_1.getApiKey)();
|
|
291
|
+
// Restart polling if we now have an API key and weren't running before
|
|
292
|
+
if (this.apiKey && !this.isRunning) {
|
|
293
|
+
this.start();
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
exports.CommandPoller = CommandPoller;
|
|
298
|
+
//# sourceMappingURL=CommandPoller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CommandPoller.js","sourceRoot":"","sources":["../../../src/services/watch/CommandPoller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export interface Session {
|
|
2
|
+
id: string;
|
|
3
|
+
startTime: number;
|
|
4
|
+
}
|
|
5
|
+
export interface Event {
|
|
6
|
+
id?: number;
|
|
7
|
+
sessionId: string;
|
|
8
|
+
filePath: string;
|
|
9
|
+
hash: string;
|
|
10
|
+
timestamp: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Journal - JSON database for tracking file change history
|
|
14
|
+
*
|
|
15
|
+
* Stores sessions and events in .neurcode/history.json
|
|
16
|
+
*/
|
|
17
|
+
export declare class Journal {
|
|
18
|
+
private db;
|
|
19
|
+
private readonly dbPath;
|
|
20
|
+
private nextEventId;
|
|
21
|
+
constructor(projectRoot: string);
|
|
22
|
+
/**
|
|
23
|
+
* Create a new session
|
|
24
|
+
* @returns The session ID
|
|
25
|
+
*/
|
|
26
|
+
createSession(): string;
|
|
27
|
+
/**
|
|
28
|
+
* Record a file change event
|
|
29
|
+
* @param sessionId - The session ID
|
|
30
|
+
* @param filePath - The path to the changed file
|
|
31
|
+
* @param hash - The SHA-256 hash of the file content
|
|
32
|
+
*/
|
|
33
|
+
recordEvent(sessionId: string, filePath: string, hash: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* Get all events for a session
|
|
36
|
+
* @param sessionId - The session ID
|
|
37
|
+
* @returns Array of events
|
|
38
|
+
*/
|
|
39
|
+
getSessionEvents(sessionId: string): Event[];
|
|
40
|
+
/**
|
|
41
|
+
* Get all events for a file
|
|
42
|
+
* @param filePath - The file path
|
|
43
|
+
* @returns Array of events
|
|
44
|
+
*/
|
|
45
|
+
getFileEvents(filePath: string): Event[];
|
|
46
|
+
/**
|
|
47
|
+
* Get the latest event for a file
|
|
48
|
+
* @param filePath - The file path
|
|
49
|
+
* @returns The latest event or null
|
|
50
|
+
*/
|
|
51
|
+
getLatestFileEvent(filePath: string): Event | null;
|
|
52
|
+
/**
|
|
53
|
+
* Close the database connection
|
|
54
|
+
* Note: lowdb doesn't require explicit closing, but we keep this for API compatibility
|
|
55
|
+
*/
|
|
56
|
+
close(): void;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=Journal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Journal.d.ts","sourceRoot":"","sources":["../../../src/services/watch/Journal.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,KAAK;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAOD;;;;GAIG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,EAAE,CAAM;IAChB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,WAAW,CAAa;gBAEpB,WAAW,EAAE,MAAM;IAoB/B;;;OAGG;IACH,aAAa,IAAI,MAAM;IAYvB;;;;;OAKG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAYpE;;;;OAIG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,KAAK,EAAE;IAO5C;;;;OAIG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,EAAE;IAOxC;;;;OAIG;IACH,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI;IAalD;;;OAGG;IACH,KAAK,IAAI,IAAI;CAId"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.Journal = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const fsExtra = __importStar(require("fs-extra"));
|
|
39
|
+
const uuid_1 = require("uuid");
|
|
40
|
+
// @ts-ignore - lowdb v1 doesn't have perfect TypeScript support
|
|
41
|
+
const lowdb = require('lowdb');
|
|
42
|
+
// @ts-ignore
|
|
43
|
+
const FileSync = require('lowdb/adapters/FileSync');
|
|
44
|
+
/**
|
|
45
|
+
* Journal - JSON database for tracking file change history
|
|
46
|
+
*
|
|
47
|
+
* Stores sessions and events in .neurcode/history.json
|
|
48
|
+
*/
|
|
49
|
+
class Journal {
|
|
50
|
+
db; // lowdb.LowdbSync<DatabaseSchema> - using any due to v1.x typing issues
|
|
51
|
+
dbPath;
|
|
52
|
+
nextEventId = 1;
|
|
53
|
+
constructor(projectRoot) {
|
|
54
|
+
this.dbPath = path.join(projectRoot, '.neurcode', 'history.json');
|
|
55
|
+
// Ensure .neurcode directory exists
|
|
56
|
+
fsExtra.ensureDirSync(path.dirname(this.dbPath));
|
|
57
|
+
// Initialize lowdb with JSON file adapter (v1.x API - synchronous)
|
|
58
|
+
const adapter = new FileSync(this.dbPath);
|
|
59
|
+
this.db = lowdb(adapter);
|
|
60
|
+
// Set default data if database is empty
|
|
61
|
+
this.db.defaults({ sessions: [], events: [] }).write();
|
|
62
|
+
// Find the highest event ID to continue auto-incrementing
|
|
63
|
+
if (this.db.get('events').value().length > 0) {
|
|
64
|
+
const maxId = Math.max(...this.db.get('events').value().map((e) => e.id || 0));
|
|
65
|
+
this.nextEventId = maxId + 1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Create a new session
|
|
70
|
+
* @returns The session ID
|
|
71
|
+
*/
|
|
72
|
+
createSession() {
|
|
73
|
+
const sessionId = (0, uuid_1.v4)();
|
|
74
|
+
const startTime = Date.now();
|
|
75
|
+
this.db.get('sessions').push({
|
|
76
|
+
id: sessionId,
|
|
77
|
+
startTime,
|
|
78
|
+
}).write();
|
|
79
|
+
return sessionId;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Record a file change event
|
|
83
|
+
* @param sessionId - The session ID
|
|
84
|
+
* @param filePath - The path to the changed file
|
|
85
|
+
* @param hash - The SHA-256 hash of the file content
|
|
86
|
+
*/
|
|
87
|
+
recordEvent(sessionId, filePath, hash) {
|
|
88
|
+
const timestamp = Date.now();
|
|
89
|
+
this.db.get('events').push({
|
|
90
|
+
id: this.nextEventId++,
|
|
91
|
+
sessionId,
|
|
92
|
+
filePath,
|
|
93
|
+
hash,
|
|
94
|
+
timestamp,
|
|
95
|
+
}).write();
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get all events for a session
|
|
99
|
+
* @param sessionId - The session ID
|
|
100
|
+
* @returns Array of events
|
|
101
|
+
*/
|
|
102
|
+
getSessionEvents(sessionId) {
|
|
103
|
+
return this.db.get('events')
|
|
104
|
+
.filter((event) => event.sessionId === sessionId)
|
|
105
|
+
.sortBy('timestamp')
|
|
106
|
+
.value();
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Get all events for a file
|
|
110
|
+
* @param filePath - The file path
|
|
111
|
+
* @returns Array of events
|
|
112
|
+
*/
|
|
113
|
+
getFileEvents(filePath) {
|
|
114
|
+
return this.db.get('events')
|
|
115
|
+
.filter((event) => event.filePath === filePath)
|
|
116
|
+
.sortBy((event) => -event.timestamp)
|
|
117
|
+
.value();
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get the latest event for a file
|
|
121
|
+
* @param filePath - The file path
|
|
122
|
+
* @returns The latest event or null
|
|
123
|
+
*/
|
|
124
|
+
getLatestFileEvent(filePath) {
|
|
125
|
+
const events = this.db.get('events')
|
|
126
|
+
.filter((event) => event.filePath === filePath)
|
|
127
|
+
.sortBy((event) => -event.timestamp)
|
|
128
|
+
.value();
|
|
129
|
+
if (events.length === 0) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
return events[0];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Close the database connection
|
|
136
|
+
* Note: lowdb doesn't require explicit closing, but we keep this for API compatibility
|
|
137
|
+
*/
|
|
138
|
+
close() {
|
|
139
|
+
// lowdb writes synchronously on write(), so no cleanup needed
|
|
140
|
+
// This method is kept for API compatibility with the previous implementation
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
exports.Journal = Journal;
|
|
144
|
+
//# sourceMappingURL=Journal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Journal.js","sourceRoot":"","sources":["../../../src/services/watch/Journal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Syncer } from './Syncer';
|
|
2
|
+
/**
|
|
3
|
+
* Sentinel - File system watcher that records file changes
|
|
4
|
+
*
|
|
5
|
+
* Watches the project root for file changes, stores content in BlobStore,
|
|
6
|
+
* and records events in Journal. Uses debouncing to prevent high CPU usage.
|
|
7
|
+
*/
|
|
8
|
+
export declare class Sentinel {
|
|
9
|
+
private watcher;
|
|
10
|
+
private blobStore;
|
|
11
|
+
private journal;
|
|
12
|
+
private syncer;
|
|
13
|
+
private sessionId;
|
|
14
|
+
private projectRoot;
|
|
15
|
+
private projectId;
|
|
16
|
+
private debounceTimer;
|
|
17
|
+
private pendingChanges;
|
|
18
|
+
private readonly debounceMs;
|
|
19
|
+
constructor(projectRoot: string, projectId: string);
|
|
20
|
+
/**
|
|
21
|
+
* Initialize the watch service
|
|
22
|
+
*/
|
|
23
|
+
initialize(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Start watching the project root
|
|
26
|
+
*/
|
|
27
|
+
start(): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Handle a file change event (with debouncing)
|
|
30
|
+
*/
|
|
31
|
+
private handleChange;
|
|
32
|
+
/**
|
|
33
|
+
* Process all pending changes after debounce period
|
|
34
|
+
*/
|
|
35
|
+
private processPendingChanges;
|
|
36
|
+
/**
|
|
37
|
+
* Stop watching
|
|
38
|
+
*/
|
|
39
|
+
stop(): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Get the current session ID
|
|
42
|
+
*/
|
|
43
|
+
getSessionId(): string;
|
|
44
|
+
/**
|
|
45
|
+
* Get the syncer instance (for checking sync status)
|
|
46
|
+
*/
|
|
47
|
+
getSyncer(): Syncer;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=Sentinel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Sentinel.d.ts","sourceRoot":"","sources":["../../../src/services/watch/Sentinel.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC;;;;;GAKG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,cAAc,CAAuD;IAC7E,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAO;gBAEtB,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IASlD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC5B;;OAEG;IACH,OAAO,CAAC,YAAY;IAkBpB;;OAEG;YACW,qBAAqB;IA4CnC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB3B;;OAEG;IACH,YAAY,IAAI,MAAM;IAItB;;OAEG;IACH,SAAS,IAAI,MAAM;CAGpB"}
|