@neurcode-ai/cli 0.4.0 → 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.
Files changed (111) hide show
  1. package/dist/api-client.d.ts +105 -17
  2. package/dist/api-client.d.ts.map +1 -1
  3. package/dist/api-client.js +388 -85
  4. package/dist/api-client.js.map +1 -1
  5. package/dist/commands/allow.d.ts.map +1 -1
  6. package/dist/commands/allow.js +6 -33
  7. package/dist/commands/allow.js.map +1 -1
  8. package/dist/commands/check.d.ts.map +1 -1
  9. package/dist/commands/check.js +56 -13
  10. package/dist/commands/check.js.map +1 -1
  11. package/dist/commands/doctor.d.ts +7 -0
  12. package/dist/commands/doctor.d.ts.map +1 -0
  13. package/dist/commands/doctor.js +134 -0
  14. package/dist/commands/doctor.js.map +1 -0
  15. package/dist/commands/init.d.ts +13 -0
  16. package/dist/commands/init.d.ts.map +1 -0
  17. package/dist/commands/init.js +365 -0
  18. package/dist/commands/init.js.map +1 -0
  19. package/dist/commands/login.d.ts +8 -0
  20. package/dist/commands/login.d.ts.map +1 -0
  21. package/dist/commands/login.js +209 -0
  22. package/dist/commands/login.js.map +1 -0
  23. package/dist/commands/logout.d.ts +7 -0
  24. package/dist/commands/logout.d.ts.map +1 -0
  25. package/dist/commands/logout.js +70 -0
  26. package/dist/commands/logout.js.map +1 -0
  27. package/dist/commands/plan.d.ts +2 -0
  28. package/dist/commands/plan.d.ts.map +1 -1
  29. package/dist/commands/plan.js +210 -57
  30. package/dist/commands/plan.js.map +1 -1
  31. package/dist/commands/prompt.d.ts +6 -0
  32. package/dist/commands/prompt.d.ts.map +1 -0
  33. package/dist/commands/prompt.js +254 -0
  34. package/dist/commands/prompt.js.map +1 -0
  35. package/dist/commands/revert.d.ts.map +1 -1
  36. package/dist/commands/revert.js +10 -0
  37. package/dist/commands/revert.js.map +1 -1
  38. package/dist/commands/session.d.ts +29 -0
  39. package/dist/commands/session.d.ts.map +1 -0
  40. package/dist/commands/session.js +382 -0
  41. package/dist/commands/session.js.map +1 -0
  42. package/dist/commands/verify.d.ts.map +1 -1
  43. package/dist/commands/verify.js +127 -13
  44. package/dist/commands/verify.js.map +1 -1
  45. package/dist/commands/watch.d.ts +8 -0
  46. package/dist/commands/watch.d.ts.map +1 -0
  47. package/dist/commands/watch.js +78 -0
  48. package/dist/commands/watch.js.map +1 -0
  49. package/dist/config.d.ts +29 -4
  50. package/dist/config.d.ts.map +1 -1
  51. package/dist/config.js +186 -21
  52. package/dist/config.js.map +1 -1
  53. package/dist/index.js +120 -3
  54. package/dist/index.js.map +1 -1
  55. package/dist/services/integrations/TicketService.d.ts +68 -0
  56. package/dist/services/integrations/TicketService.d.ts.map +1 -0
  57. package/dist/services/integrations/TicketService.js +151 -0
  58. package/dist/services/integrations/TicketService.js.map +1 -0
  59. package/dist/services/security/SecurityGuard.d.ts +80 -0
  60. package/dist/services/security/SecurityGuard.d.ts.map +1 -0
  61. package/dist/services/security/SecurityGuard.js +410 -0
  62. package/dist/services/security/SecurityGuard.js.map +1 -0
  63. package/dist/services/watch/BlobStore.d.ts +33 -0
  64. package/dist/services/watch/BlobStore.d.ts.map +1 -0
  65. package/dist/services/watch/BlobStore.js +108 -0
  66. package/dist/services/watch/BlobStore.js.map +1 -0
  67. package/dist/services/watch/CommandPoller.d.ts +76 -0
  68. package/dist/services/watch/CommandPoller.d.ts.map +1 -0
  69. package/dist/services/watch/CommandPoller.js +298 -0
  70. package/dist/services/watch/CommandPoller.js.map +1 -0
  71. package/dist/services/watch/Journal.d.ts +58 -0
  72. package/dist/services/watch/Journal.d.ts.map +1 -0
  73. package/dist/services/watch/Journal.js +144 -0
  74. package/dist/services/watch/Journal.js.map +1 -0
  75. package/dist/services/watch/Sentinel.d.ts +49 -0
  76. package/dist/services/watch/Sentinel.d.ts.map +1 -0
  77. package/dist/services/watch/Sentinel.js +205 -0
  78. package/dist/services/watch/Sentinel.js.map +1 -0
  79. package/dist/services/watch/Syncer.d.ts +55 -0
  80. package/dist/services/watch/Syncer.d.ts.map +1 -0
  81. package/dist/services/watch/Syncer.js +231 -0
  82. package/dist/services/watch/Syncer.js.map +1 -0
  83. package/dist/utils/ROILogger.d.ts +16 -0
  84. package/dist/utils/ROILogger.d.ts.map +1 -0
  85. package/dist/utils/ROILogger.js +45 -0
  86. package/dist/utils/ROILogger.js.map +1 -0
  87. package/dist/utils/box.d.ts +16 -0
  88. package/dist/utils/box.d.ts.map +1 -0
  89. package/dist/utils/box.js +85 -0
  90. package/dist/utils/box.js.map +1 -0
  91. package/dist/utils/gitignore.d.ts +10 -0
  92. package/dist/utils/gitignore.d.ts.map +1 -0
  93. package/dist/utils/gitignore.js +34 -0
  94. package/dist/utils/gitignore.js.map +1 -0
  95. package/dist/utils/messages.d.ts +81 -0
  96. package/dist/utils/messages.d.ts.map +1 -0
  97. package/dist/utils/messages.js +306 -0
  98. package/dist/utils/messages.js.map +1 -0
  99. package/dist/utils/restore.d.ts +14 -0
  100. package/dist/utils/restore.d.ts.map +1 -0
  101. package/dist/utils/restore.js +89 -0
  102. package/dist/utils/restore.js.map +1 -0
  103. package/dist/utils/state.d.ts +69 -0
  104. package/dist/utils/state.d.ts.map +1 -0
  105. package/dist/utils/state.js +151 -0
  106. package/dist/utils/state.js.map +1 -0
  107. package/dist/utils/user-context.d.ts +28 -0
  108. package/dist/utils/user-context.d.ts.map +1 -0
  109. package/dist/utils/user-context.js +68 -0
  110. package/dist/utils/user-context.js.map +1 -0
  111. package/package.json +11 -4
@@ -0,0 +1,205 @@
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.Sentinel = void 0;
37
+ const chokidar = __importStar(require("chokidar"));
38
+ const path = __importStar(require("path"));
39
+ const fs_1 = require("fs");
40
+ const BlobStore_1 = require("./BlobStore");
41
+ const Journal_1 = require("./Journal");
42
+ const Syncer_1 = require("./Syncer");
43
+ /**
44
+ * Sentinel - File system watcher that records file changes
45
+ *
46
+ * Watches the project root for file changes, stores content in BlobStore,
47
+ * and records events in Journal. Uses debouncing to prevent high CPU usage.
48
+ */
49
+ class Sentinel {
50
+ watcher = null;
51
+ blobStore;
52
+ journal;
53
+ syncer;
54
+ sessionId;
55
+ projectRoot;
56
+ projectId;
57
+ debounceTimer = null;
58
+ pendingChanges = new Map();
59
+ debounceMs = 500;
60
+ constructor(projectRoot, projectId) {
61
+ this.projectRoot = projectRoot;
62
+ this.projectId = projectId;
63
+ this.blobStore = new BlobStore_1.BlobStore(projectRoot);
64
+ this.journal = new Journal_1.Journal(projectRoot);
65
+ this.syncer = new Syncer_1.Syncer(projectRoot, projectId);
66
+ this.sessionId = this.journal.createSession();
67
+ }
68
+ /**
69
+ * Initialize the watch service
70
+ */
71
+ async initialize() {
72
+ await this.blobStore.initialize();
73
+ }
74
+ /**
75
+ * Start watching the project root
76
+ */
77
+ async start() {
78
+ if (this.watcher) {
79
+ throw new Error('Sentinel is already watching');
80
+ }
81
+ // Ignore patterns for common directories and files
82
+ const ignored = [
83
+ '**/.git/**',
84
+ '**/node_modules/**',
85
+ '**/.neurcode/**',
86
+ '**/.next/**',
87
+ '**/dist/**',
88
+ '**/build/**',
89
+ '**/.DS_Store',
90
+ '**/Thumbs.db',
91
+ ];
92
+ this.watcher = chokidar.watch(this.projectRoot, {
93
+ ignored,
94
+ persistent: true,
95
+ ignoreInitial: true, // Don't process existing files on startup
96
+ awaitWriteFinish: {
97
+ stabilityThreshold: 200,
98
+ pollInterval: 100,
99
+ },
100
+ });
101
+ // Handle file changes
102
+ this.watcher.on('add', (filePath) => this.handleChange(filePath, 'add'));
103
+ this.watcher.on('change', (filePath) => this.handleChange(filePath, 'change'));
104
+ this.watcher.on('unlink', (filePath) => this.handleChange(filePath, 'unlink'));
105
+ this.watcher.on('error', (error) => {
106
+ console.error('❌ Watch error:', error);
107
+ });
108
+ console.log(`👁️ Watching: ${this.projectRoot}`);
109
+ console.log(`📝 Session ID: ${this.sessionId}`);
110
+ }
111
+ /**
112
+ * Handle a file change event (with debouncing)
113
+ */
114
+ handleChange(filePath, eventType) {
115
+ // Normalize path relative to project root
116
+ const relativePath = path.relative(this.projectRoot, filePath);
117
+ // Store the most recent event type for this file
118
+ this.pendingChanges.set(relativePath, eventType);
119
+ // Clear existing debounce timer
120
+ if (this.debounceTimer) {
121
+ clearTimeout(this.debounceTimer);
122
+ }
123
+ // Set new debounce timer
124
+ this.debounceTimer = setTimeout(() => {
125
+ this.processPendingChanges();
126
+ }, this.debounceMs);
127
+ }
128
+ /**
129
+ * Process all pending changes after debounce period
130
+ */
131
+ async processPendingChanges() {
132
+ const changes = Array.from(this.pendingChanges.entries());
133
+ this.pendingChanges.clear();
134
+ if (changes.length === 0) {
135
+ return;
136
+ }
137
+ for (const [filePath, eventType] of changes) {
138
+ try {
139
+ if (eventType === 'unlink') {
140
+ // File was deleted - we can't read it, but we can record the deletion
141
+ // For now, we'll skip recording deletions (or record with a special marker)
142
+ continue;
143
+ }
144
+ // Read file content
145
+ const fullPath = path.join(this.projectRoot, filePath);
146
+ const content = await fs_1.promises.readFile(fullPath, 'utf-8');
147
+ // Store content in blob store
148
+ const hash = await this.blobStore.store(content);
149
+ // Record event in journal (local JSON database)
150
+ this.journal.recordEvent(this.sessionId, filePath, hash);
151
+ // Queue event for cloud sync (non-blocking, fire-and-forget)
152
+ this.syncer.queueEvent({
153
+ sessionId: this.sessionId,
154
+ filePath,
155
+ hash,
156
+ timestamp: Date.now(),
157
+ });
158
+ console.log(`📝 Recorded: ${filePath} (${hash.substring(0, 8)}...)`);
159
+ }
160
+ catch (error) {
161
+ // Skip files that can't be read (permissions, binary files, etc.)
162
+ if (error instanceof Error) {
163
+ // Silently skip - this is expected for some files
164
+ }
165
+ }
166
+ }
167
+ }
168
+ /**
169
+ * Stop watching
170
+ */
171
+ async stop() {
172
+ if (this.debounceTimer) {
173
+ clearTimeout(this.debounceTimer);
174
+ this.debounceTimer = null;
175
+ }
176
+ if (this.watcher) {
177
+ await this.watcher.close();
178
+ this.watcher = null;
179
+ }
180
+ // Flush any pending syncs before closing
181
+ if (this.syncer.isConfigured()) {
182
+ console.log('☁️ Flushing pending cloud syncs...');
183
+ const result = await this.syncer.flush();
184
+ if (result.success && result.synced > 0) {
185
+ console.log(`✅ Synced ${result.synced} events to cloud`);
186
+ }
187
+ }
188
+ this.journal.close();
189
+ console.log('🛑 Watch stopped');
190
+ }
191
+ /**
192
+ * Get the current session ID
193
+ */
194
+ getSessionId() {
195
+ return this.sessionId;
196
+ }
197
+ /**
198
+ * Get the syncer instance (for checking sync status)
199
+ */
200
+ getSyncer() {
201
+ return this.syncer;
202
+ }
203
+ }
204
+ exports.Sentinel = Sentinel;
205
+ //# sourceMappingURL=Sentinel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sentinel.js","sourceRoot":"","sources":["../../../src/services/watch/Sentinel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Syncer - Cloud sync service for Time Machine events
3
+ *
4
+ * Pushes file change events to the cloud API in a fire-and-forget manner.
5
+ * If API key is not configured, operates in local-only mode (silent failure).
6
+ */
7
+ export interface SyncEvent {
8
+ sessionId: string;
9
+ filePath: string;
10
+ hash: string;
11
+ timestamp: number;
12
+ }
13
+ export interface SyncResult {
14
+ success: boolean;
15
+ synced: number;
16
+ skipped: number;
17
+ error?: string;
18
+ }
19
+ /**
20
+ * Syncer - Handles cloud sync of history events
21
+ */
22
+ export declare class Syncer {
23
+ private apiUrl;
24
+ private apiKey;
25
+ private projectRoot;
26
+ private projectId;
27
+ private syncQueue;
28
+ private syncTimer;
29
+ private readonly batchSize;
30
+ private readonly debounceMs;
31
+ constructor(projectRoot: string, projectId: string);
32
+ /**
33
+ * Queue an event for sync (non-blocking)
34
+ * @param event - The event to sync
35
+ */
36
+ queueEvent(event: SyncEvent): void;
37
+ /**
38
+ * Sync a batch of events to the cloud
39
+ * @returns Sync result
40
+ */
41
+ private syncBatch;
42
+ /**
43
+ * Force sync all pending events (useful for shutdown)
44
+ */
45
+ flush(): Promise<SyncResult>;
46
+ /**
47
+ * Check if syncer is configured (has API key)
48
+ */
49
+ isConfigured(): boolean;
50
+ /**
51
+ * Reload API key from config (useful if user logs in after watch starts)
52
+ */
53
+ reloadConfig(): void;
54
+ }
55
+ //# sourceMappingURL=Syncer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Syncer.d.ts","sourceRoot":"","sources":["../../../src/services/watch/Syncer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAM;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;gBAEvB,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAQlD;;;OAGG;IACH,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAuBlC;;;OAGG;YACW,SAAS;IA4GvB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC;IAyBlC;;OAEG;IACH,YAAY,IAAI,OAAO;IAIvB;;OAEG;IACH,YAAY,IAAI,IAAI;CAKrB"}
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ /**
3
+ * Syncer - Cloud sync service for Time Machine events
4
+ *
5
+ * Pushes file change events to the cloud API in a fire-and-forget manner.
6
+ * If API key is not configured, operates in local-only mode (silent failure).
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.Syncer = void 0;
43
+ const config_1 = require("../../config");
44
+ const fs_1 = require("fs");
45
+ const path = __importStar(require("path"));
46
+ /**
47
+ * Syncer - Handles cloud sync of history events
48
+ */
49
+ class Syncer {
50
+ apiUrl;
51
+ apiKey;
52
+ projectRoot;
53
+ projectId;
54
+ syncQueue = [];
55
+ syncTimer = null;
56
+ batchSize = 10; // Sync in batches
57
+ debounceMs = 2000; // Wait 2 seconds before syncing
58
+ constructor(projectRoot, projectId) {
59
+ this.projectRoot = projectRoot;
60
+ this.projectId = projectId;
61
+ const config = (0, config_1.loadConfig)();
62
+ this.apiUrl = config.apiUrl || config_1.DEFAULT_API_URL;
63
+ this.apiKey = (0, config_1.getApiKey)();
64
+ }
65
+ /**
66
+ * Queue an event for sync (non-blocking)
67
+ * @param event - The event to sync
68
+ */
69
+ queueEvent(event) {
70
+ // If no API key, skip silently (local-only mode)
71
+ if (!this.apiKey) {
72
+ return;
73
+ }
74
+ // Add to queue
75
+ this.syncQueue.push(event);
76
+ // Clear existing timer
77
+ if (this.syncTimer) {
78
+ clearTimeout(this.syncTimer);
79
+ }
80
+ // Set new timer to sync after debounce period
81
+ this.syncTimer = setTimeout(() => {
82
+ this.syncBatch().catch((error) => {
83
+ // Silently handle errors - don't block the watch service
84
+ console.error('⚠️ Sync error (non-fatal):', error.message);
85
+ });
86
+ }, this.debounceMs);
87
+ }
88
+ /**
89
+ * Sync a batch of events to the cloud
90
+ * @returns Sync result
91
+ */
92
+ async syncBatch() {
93
+ if (this.syncQueue.length === 0) {
94
+ return { success: true, synced: 0, skipped: 0 };
95
+ }
96
+ // If no API key, clear queue and return
97
+ if (!this.apiKey) {
98
+ const queuedCount = this.syncQueue.length;
99
+ this.syncQueue = [];
100
+ if (queuedCount > 0) {
101
+ console.warn(`⚠️ ${queuedCount} event(s) not synced: No API key configured. Run "neurcode config --key <your_api_key>"`);
102
+ }
103
+ return { success: false, synced: 0, skipped: 0, error: 'No API key configured' };
104
+ }
105
+ // Take a batch from the queue
106
+ const batch = this.syncQueue.splice(0, this.batchSize);
107
+ // Prepare events (metadata only - no content)
108
+ const events = batch.map(event => ({
109
+ sessionId: event.sessionId,
110
+ filePath: event.filePath,
111
+ hash: event.hash,
112
+ timestamp: event.timestamp,
113
+ }));
114
+ // Read blob content for all unique hashes in the batch
115
+ // Send blobs separately for server-side deduplication
116
+ const blobs = {};
117
+ const uniqueHashes = new Set(batch.map(e => e.hash));
118
+ for (const hash of uniqueHashes) {
119
+ try {
120
+ // Try to read the blob content
121
+ const blobPath = path.join(this.projectRoot, '.neurcode', 'blobs', hash);
122
+ const blobContent = await fs_1.promises.readFile(blobPath);
123
+ // Convert to base64 for transmission
124
+ // Server will handle deduplication - we send all blobs, server checks which are new
125
+ blobs[hash] = blobContent.toString('base64');
126
+ }
127
+ catch {
128
+ // If blob doesn't exist or can't be read, skip it
129
+ // The server can still store the event metadata with just the hash
130
+ // This allows events to be recorded even if blob read fails
131
+ }
132
+ }
133
+ try {
134
+ // Make API request with separated events and blobs
135
+ // Format: { events: [...], blobs: { [hash]: base64Content } }
136
+ const response = await fetch(`${this.apiUrl}/api/v1/history/sync`, {
137
+ method: 'POST',
138
+ headers: {
139
+ 'Content-Type': 'application/json',
140
+ 'Authorization': `Bearer ${this.apiKey}`,
141
+ },
142
+ body: JSON.stringify({
143
+ events,
144
+ blobs, // Separate blobs map for server-side deduplication
145
+ projectId: this.projectId, // Include projectId so events are associated with the correct project
146
+ }),
147
+ });
148
+ if (!response.ok) {
149
+ const errorText = await response.text();
150
+ throw new Error(`API error: ${response.status} ${errorText}`);
151
+ }
152
+ const result = await response.json();
153
+ // Log sync result for visibility
154
+ if (result.success) {
155
+ if (result.synced > 0) {
156
+ console.log(`✅ Synced ${result.synced} event(s) to cloud${result.skipped > 0 ? ` (${result.skipped} skipped)` : ''}`);
157
+ }
158
+ else if (result.skipped > 0) {
159
+ // All events were duplicates (already synced)
160
+ console.log(`ℹ️ All ${result.skipped} event(s) already synced`);
161
+ }
162
+ }
163
+ else {
164
+ console.error(`❌ Sync failed: ${result.error || 'Unknown error'}`);
165
+ }
166
+ // If there are more events in the queue, schedule another sync
167
+ if (this.syncQueue.length > 0) {
168
+ setTimeout(() => {
169
+ this.syncBatch().catch((error) => {
170
+ console.error('⚠️ Sync error (non-fatal):', error.message);
171
+ });
172
+ }, this.debounceMs);
173
+ }
174
+ return result;
175
+ }
176
+ catch (error) {
177
+ // Log error but don't throw - this is fire-and-forget
178
+ console.error(`❌ Failed to sync ${batch.length} event(s) to cloud: ${error.message}`);
179
+ // If it's an auth error, provide helpful message
180
+ if (error.message?.includes('401') || error.message?.includes('403')) {
181
+ console.error(' 💡 Tip: Check your API key with "neurcode config --key <your_api_key>"');
182
+ }
183
+ return {
184
+ success: false,
185
+ synced: 0,
186
+ skipped: batch.length,
187
+ error: error.message,
188
+ };
189
+ }
190
+ }
191
+ /**
192
+ * Force sync all pending events (useful for shutdown)
193
+ */
194
+ async flush() {
195
+ if (this.syncTimer) {
196
+ clearTimeout(this.syncTimer);
197
+ this.syncTimer = null;
198
+ }
199
+ // Sync all remaining events
200
+ const results = [];
201
+ while (this.syncQueue.length > 0) {
202
+ const result = await this.syncBatch();
203
+ results.push(result);
204
+ }
205
+ // Aggregate results
206
+ const totalSynced = results.reduce((sum, r) => sum + r.synced, 0);
207
+ const totalSkipped = results.reduce((sum, r) => sum + r.skipped, 0);
208
+ const allSuccess = results.every(r => r.success);
209
+ return {
210
+ success: allSuccess,
211
+ synced: totalSynced,
212
+ skipped: totalSkipped,
213
+ };
214
+ }
215
+ /**
216
+ * Check if syncer is configured (has API key)
217
+ */
218
+ isConfigured() {
219
+ return this.apiKey !== null;
220
+ }
221
+ /**
222
+ * Reload API key from config (useful if user logs in after watch starts)
223
+ */
224
+ reloadConfig() {
225
+ const config = (0, config_1.loadConfig)();
226
+ this.apiUrl = config.apiUrl || config_1.DEFAULT_API_URL;
227
+ this.apiKey = (0, config_1.getApiKey)();
228
+ }
229
+ }
230
+ exports.Syncer = Syncer;
231
+ //# sourceMappingURL=Syncer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Syncer.js","sourceRoot":"","sources":["../../../src/services/watch/Syncer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * ROI Logger
3
+ *
4
+ * Lightweight utility to send value events to the backend ROI service
5
+ * Tracks: reverts, verify passes, secret interceptions, hallucination blocks
6
+ */
7
+ export type ROIEventType = 'REVERT_SUCCESS' | 'VERIFY_PASS' | 'SECRET_INTERCEPTED' | 'HALLUCINATION_BLOCKED';
8
+ export interface ROIEventMetadata {
9
+ [key: string]: any;
10
+ }
11
+ /**
12
+ * Log a ROI event to the backend
13
+ * This is fire-and-forget - errors are silently ignored to avoid blocking user workflows
14
+ */
15
+ export declare function logROIEvent(eventType: ROIEventType, metadata?: ROIEventMetadata, projectId?: string | null): Promise<void>;
16
+ //# sourceMappingURL=ROILogger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ROILogger.d.ts","sourceRoot":"","sources":["../../src/utils/ROILogger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,MAAM,YAAY,GAAG,gBAAgB,GAAG,aAAa,GAAG,oBAAoB,GAAG,uBAAuB,CAAC;AAE7G,MAAM,WAAW,gBAAgB;IAC/B,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,YAAY,EACvB,QAAQ,GAAE,gBAAqB,EAC/B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB,OAAO,CAAC,IAAI,CAAC,CA8Bf"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ /**
3
+ * ROI Logger
4
+ *
5
+ * Lightweight utility to send value events to the backend ROI service
6
+ * Tracks: reverts, verify passes, secret interceptions, hallucination blocks
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.logROIEvent = logROIEvent;
10
+ const config_1 = require("../config");
11
+ /**
12
+ * Log a ROI event to the backend
13
+ * This is fire-and-forget - errors are silently ignored to avoid blocking user workflows
14
+ */
15
+ async function logROIEvent(eventType, metadata = {}, projectId) {
16
+ try {
17
+ const config = (0, config_1.loadConfig)();
18
+ if (!config.apiKey) {
19
+ // Silently fail if no API key (user not authenticated)
20
+ return;
21
+ }
22
+ // Use same API URL pattern as ApiClient
23
+ const apiUrl = config.apiUrl || process.env.NEURCODE_API_URL || 'https://api.neurcode.ai';
24
+ const url = `${apiUrl}/api/v1/roi/events`;
25
+ // Fire-and-forget fetch (don't await)
26
+ fetch(url, {
27
+ method: 'POST',
28
+ headers: {
29
+ 'Content-Type': 'application/json',
30
+ 'Authorization': `Bearer ${config.apiKey}`,
31
+ },
32
+ body: JSON.stringify({
33
+ eventType,
34
+ metadata,
35
+ projectId,
36
+ }),
37
+ }).catch(() => {
38
+ // Silently ignore errors - ROI tracking should never block user workflows
39
+ });
40
+ }
41
+ catch {
42
+ // Silently ignore all errors
43
+ }
44
+ }
45
+ //# sourceMappingURL=ROILogger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ROILogger.js","sourceRoot":"","sources":["../../src/utils/ROILogger.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAcH,kCAkCC;AA9CD,sCAAuC;AAQvC;;;GAGG;AACI,KAAK,UAAU,WAAW,CAC/B,SAAuB,EACvB,WAA6B,EAAE,EAC/B,SAAyB;IAEzB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAA,mBAAU,GAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACnB,uDAAuD;YACvD,OAAO;QACT,CAAC;QAED,wCAAwC;QACxC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,yBAAyB,CAAC;QAC1F,MAAM,GAAG,GAAG,GAAG,MAAM,oBAAoB,CAAC;QAE1C,sCAAsC;QACtC,KAAK,CAAC,GAAG,EAAE;YACT,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,eAAe,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE;aAC3C;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,SAAS;gBACT,QAAQ;gBACR,SAAS;aACV,CAAC;SACH,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YACZ,0EAA0E;QAC5E,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,6BAA6B;IAC/B,CAAC;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Box utility for creating terminal boxes
3
+ * Creates high-contrast, professional-looking boxes using chalk
4
+ */
5
+ export interface BoxOptions {
6
+ title?: string;
7
+ padding?: number;
8
+ borderColor?: 'green' | 'yellow' | 'red' | 'cyan' | 'white';
9
+ titleColor?: 'green' | 'yellow' | 'red' | 'cyan' | 'white';
10
+ align?: 'left' | 'center';
11
+ }
12
+ /**
13
+ * Create a boxed message for terminal output
14
+ */
15
+ export declare function createBox(content: string, options?: BoxOptions): string;
16
+ //# sourceMappingURL=box.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"box.d.ts","sourceRoot":"","sources":["../../src/utils/box.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiBH,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;IAC5D,UAAU,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;IAC3D,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,GAAG,MAAM,CAiF3E"}