@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.
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 +132 -15
  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
@@ -1,4 +1,37 @@
1
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
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.ApiClient = void 0;
4
37
  const config_1 = require("./config");
@@ -6,12 +39,19 @@ class ApiClient {
6
39
  apiUrl;
7
40
  apiKey;
8
41
  requestTimeout = 300000; // 5 minutes (300,000ms)
42
+ isRetryingAuth = false; // Flag to prevent infinite retry loops
9
43
  constructor(config) {
10
44
  // API URL will always be set (defaults to production)
11
45
  // This check is no longer needed, but kept for safety
12
46
  this.apiUrl = (config.apiUrl || 'https://api.neurcode.com').replace(/\/$/, ''); // Remove trailing slash
13
47
  this.apiKey = config.apiKey;
14
48
  }
49
+ /**
50
+ * Update API key after re-login
51
+ */
52
+ updateApiKey(newApiKey) {
53
+ this.apiKey = newApiKey;
54
+ }
15
55
  /**
16
56
  * Get API key, requiring it if not set
17
57
  * Shows helpful error message if missing
@@ -46,17 +86,166 @@ class ApiClient {
46
86
  throw error;
47
87
  }
48
88
  }
89
+ /**
90
+ * Wrapper for fetch with debug logging on error
91
+ * Logs the exact URL attempted when fetch fails
92
+ */
93
+ async fetchWithDebug(url, options = {}) {
94
+ try {
95
+ return await this.fetchWithTimeout(url, options);
96
+ }
97
+ catch (error) {
98
+ // Debug logging: Show the exact URL that failed
99
+ console.error(`\n🔍 [DEBUG] Fetch failed for URL: ${url}`);
100
+ console.error(`🔍 [DEBUG] API Base URL: ${this.apiUrl}`);
101
+ console.error(`🔍 [DEBUG] Error: ${error instanceof Error ? error.message : String(error)}`);
102
+ if (error instanceof Error && 'code' in error) {
103
+ console.error(`🔍 [DEBUG] Error code: ${error.code}`);
104
+ }
105
+ throw error;
106
+ }
107
+ }
108
+ /**
109
+ * Central request handler with 401 recovery
110
+ * Handles authentication failures gracefully by prompting for re-login
111
+ */
112
+ async makeRequest(url, options, retryOnAuth = true) {
113
+ // Get API key for authorization
114
+ const apiKey = this.getApiKey();
115
+ const authHeader = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
116
+ // Ensure headers exist
117
+ if (!options.headers) {
118
+ options.headers = {};
119
+ }
120
+ const headers = options.headers;
121
+ headers['Authorization'] = authHeader;
122
+ try {
123
+ const response = await this.fetchWithDebug(url, options);
124
+ // Check for 401 Unauthorized
125
+ if (response.status === 401) {
126
+ const errorText = await response.text().catch(() => '');
127
+ let errorJson = null;
128
+ try {
129
+ errorJson = JSON.parse(errorText);
130
+ }
131
+ catch {
132
+ // Error body is not JSON, use default message
133
+ }
134
+ // If we're already retrying or this is a retry attempt, don't loop
135
+ if (this.isRetryingAuth || !retryOnAuth) {
136
+ const errorMessage = errorJson?.message || errorJson?.error || 'Authentication failed';
137
+ throw new Error(`Error: Authentication failed. Please run 'neurcode login'.`);
138
+ }
139
+ // Check if terminal is interactive
140
+ if (process.stdout.isTTY && !process.env.CI) {
141
+ // Import readline for interactive prompt
142
+ const { createInterface } = await Promise.resolve().then(() => __importStar(require('readline/promises')));
143
+ const { stdin, stdout } = await Promise.resolve().then(() => __importStar(require('process')));
144
+ const rl = createInterface({ input: stdin, output: stdout });
145
+ try {
146
+ const answer = await rl.question('❌ Session expired or invalid. Would you like to log in again? (Y/n) ');
147
+ rl.close();
148
+ const shouldRelogin = answer.trim().toLowerCase() !== 'n' && answer.trim().toLowerCase() !== 'no';
149
+ if (shouldRelogin) {
150
+ // Set flag to prevent infinite loops
151
+ this.isRetryingAuth = true;
152
+ try {
153
+ // Import and call login command
154
+ const { loginCommand } = await Promise.resolve().then(() => __importStar(require('./commands/login')));
155
+ await loginCommand();
156
+ // Reload config to get new API key
157
+ const { loadConfig } = await Promise.resolve().then(() => __importStar(require('./config')));
158
+ const newConfig = loadConfig();
159
+ if (newConfig.apiKey) {
160
+ this.updateApiKey(newConfig.apiKey);
161
+ // Retry the request once with new auth
162
+ // Create new options object with updated authorization header
163
+ const newAuthHeader = newConfig.apiKey.startsWith('Bearer ')
164
+ ? newConfig.apiKey
165
+ : `Bearer ${newConfig.apiKey}`;
166
+ const retryOptions = {
167
+ ...options,
168
+ headers: {
169
+ ...headers,
170
+ 'Authorization': newAuthHeader,
171
+ },
172
+ };
173
+ // Retry with retry flag set to false to prevent loops
174
+ const retryResponse = await this.fetchWithDebug(url, retryOptions);
175
+ if (retryResponse.status === 401) {
176
+ // Still 401 after login - something is wrong
177
+ throw new Error(`Error: Authentication failed. Please run 'neurcode login'.`);
178
+ }
179
+ if (!retryResponse.ok) {
180
+ const retryErrorText = await retryResponse.text();
181
+ throw new Error(`API request failed with status ${retryResponse.status}: ${retryErrorText}`);
182
+ }
183
+ return retryResponse.json();
184
+ }
185
+ else {
186
+ throw new Error(`Error: Authentication failed. Please run 'neurcode login'.`);
187
+ }
188
+ }
189
+ catch (loginError) {
190
+ // Login failed or was cancelled
191
+ if (loginError instanceof Error && loginError.message.includes('Authentication failed')) {
192
+ throw loginError;
193
+ }
194
+ throw new Error(`Error: Authentication failed. Please run 'neurcode login'.`);
195
+ }
196
+ finally {
197
+ // Reset flag
198
+ this.isRetryingAuth = false;
199
+ }
200
+ }
201
+ else {
202
+ // User declined to login
203
+ throw new Error(`Error: Authentication failed. Please run 'neurcode login'.`);
204
+ }
205
+ }
206
+ catch (promptError) {
207
+ rl.close();
208
+ throw promptError;
209
+ }
210
+ }
211
+ else {
212
+ // Non-interactive terminal (CI, scripts, etc.)
213
+ const errorMessage = errorJson?.message || errorJson?.error || 'Authentication failed';
214
+ throw new Error(`Error: Authentication failed. Please run 'neurcode login'.`);
215
+ }
216
+ }
217
+ if (!response.ok) {
218
+ const errorText = await response.text();
219
+ let errorMessage = `API request failed with status ${response.status}`;
220
+ try {
221
+ const errorJson = JSON.parse(errorText);
222
+ errorMessage = errorJson.error || errorMessage;
223
+ if (errorJson.message) {
224
+ errorMessage += `: ${errorJson.message}`;
225
+ }
226
+ }
227
+ catch {
228
+ errorMessage += `: ${errorText}`;
229
+ }
230
+ throw new Error(errorMessage);
231
+ }
232
+ return response.json();
233
+ }
234
+ catch (error) {
235
+ // Re-throw if it's already our formatted error
236
+ if (error instanceof Error && error.message.startsWith('Error: Authentication failed')) {
237
+ throw error;
238
+ }
239
+ // For other errors, wrap them appropriately
240
+ throw error;
241
+ }
242
+ }
49
243
  async analyzeDiff(diff, projectId) {
50
244
  const url = `${this.apiUrl}/api/v1/analyze-diff`;
51
245
  const headers = {
52
246
  'Content-Type': 'application/json'
53
247
  };
54
- // Get API key (will show helpful error if missing)
55
- const apiKey = this.getApiKey();
56
- // Support both "Bearer nk_live_..." and just "nk_live_..."
57
- const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
58
- headers['Authorization'] = key;
59
- const response = await fetch(url, {
248
+ return this.makeRequest(url, {
60
249
  method: 'POST',
61
250
  headers,
62
251
  body: JSON.stringify({
@@ -64,34 +253,13 @@ class ApiClient {
64
253
  projectId
65
254
  })
66
255
  });
67
- if (!response.ok) {
68
- const errorText = await response.text();
69
- let errorMessage = `API request failed with status ${response.status}`;
70
- try {
71
- const errorJson = JSON.parse(errorText);
72
- errorMessage = errorJson.error || errorMessage;
73
- if (errorJson.message) {
74
- errorMessage += `: ${errorJson.message}`;
75
- }
76
- }
77
- catch {
78
- errorMessage += `: ${errorText}`;
79
- }
80
- throw new Error(errorMessage);
81
- }
82
- return response.json();
83
256
  }
84
257
  async analyzeBloat(diff, intent, projectId, sessionId, fileContents) {
85
258
  const url = `${this.apiUrl}/api/v1/analyze-bloat`;
86
259
  const headers = {
87
260
  'Content-Type': 'application/json'
88
261
  };
89
- // Get API key (will show helpful error if missing)
90
- const apiKey = this.getApiKey();
91
- // Support both "Bearer nk_live_..." and just "nk_live_..."
92
- const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
93
- headers['Authorization'] = key;
94
- const response = await fetch(url, {
262
+ return this.makeRequest(url, {
95
263
  method: 'POST',
96
264
  headers,
97
265
  body: JSON.stringify({
@@ -102,22 +270,6 @@ class ApiClient {
102
270
  fileContents
103
271
  })
104
272
  });
105
- if (!response.ok) {
106
- const errorText = await response.text();
107
- let errorMessage = `API request failed with status ${response.status}`;
108
- try {
109
- const errorJson = JSON.parse(errorText);
110
- errorMessage = errorJson.error || errorMessage;
111
- if (errorJson.message) {
112
- errorMessage += `: ${errorJson.message}`;
113
- }
114
- }
115
- catch {
116
- errorMessage += `: ${errorText}`;
117
- }
118
- throw new Error(errorMessage);
119
- }
120
- return response.json();
121
273
  }
122
274
  async getFileVersions(filePath, projectId, limit = 50) {
123
275
  const url = `${this.apiUrl}/api/v1/revert/versions`;
@@ -132,7 +284,8 @@ class ApiClient {
132
284
  const apiKey = this.getApiKey();
133
285
  const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
134
286
  headers['Authorization'] = key;
135
- const response = await fetch(`${url}?${params.toString()}`, {
287
+ const fullUrl = `${url}?${params.toString()}`;
288
+ const response = await this.fetchWithDebug(fullUrl, {
136
289
  method: 'GET',
137
290
  headers,
138
291
  });
@@ -167,7 +320,8 @@ class ApiClient {
167
320
  const apiKey = this.getApiKey();
168
321
  const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
169
322
  headers['Authorization'] = key;
170
- const response = await fetch(`${url}?${params.toString()}`, {
323
+ const fullUrl = `${url}?${params.toString()}`;
324
+ const response = await this.fetchWithDebug(fullUrl, {
171
325
  method: 'GET',
172
326
  headers,
173
327
  });
@@ -199,7 +353,7 @@ class ApiClient {
199
353
  const apiKey = this.getApiKey();
200
354
  const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
201
355
  headers['Authorization'] = key;
202
- const response = await fetch(url, {
356
+ const response = await this.fetchWithDebug(url, {
203
357
  method: 'POST',
204
358
  headers,
205
359
  body: JSON.stringify({
@@ -237,7 +391,7 @@ class ApiClient {
237
391
  const apiKey = this.getApiKey();
238
392
  const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
239
393
  headers['Authorization'] = key;
240
- const response = await fetch(url, {
394
+ const response = await this.fetchWithDebug(url, {
241
395
  method: 'POST',
242
396
  headers,
243
397
  body: JSON.stringify({
@@ -272,7 +426,7 @@ class ApiClient {
272
426
  const apiKey = this.getApiKey();
273
427
  const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
274
428
  headers['Authorization'] = key;
275
- const response = await fetch(url, {
429
+ const response = await this.fetchWithDebug(url, {
276
430
  method: 'POST',
277
431
  headers,
278
432
  body: JSON.stringify({
@@ -308,7 +462,7 @@ class ApiClient {
308
462
  const apiKey = this.getApiKey();
309
463
  const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
310
464
  headers['Authorization'] = key;
311
- const response = await fetch(url, {
465
+ const response = await this.fetchWithDebug(url, {
312
466
  method: 'POST',
313
467
  headers,
314
468
  body: JSON.stringify({
@@ -336,6 +490,13 @@ class ApiClient {
336
490
  /**
337
491
  * Connect or ensure project exists
338
492
  * Automatically detects Git URL and creates/links project
493
+ *
494
+ * Note: organizationId is automatically extracted from the auth token by the backend,
495
+ * so it does not need to be passed in the request body.
496
+ *
497
+ * Backend Issue: The /api/v1/projects/connect endpoint currently requires a non-empty gitUrl.
498
+ * When creating name-only projects (without Git), this will fail with "gitUrl is required".
499
+ * The backend should be updated to allow empty gitUrl when name is provided.
339
500
  */
340
501
  async ensureProject(gitUrl, name) {
341
502
  const url = `${this.apiUrl}/api/v1/projects/connect`;
@@ -343,10 +504,11 @@ class ApiClient {
343
504
  'Content-Type': 'application/json',
344
505
  };
345
506
  // Get API key (will show helpful error if missing)
507
+ // Note: organizationId is extracted from the auth token by requireAuth middleware on the backend
346
508
  const apiKey = this.getApiKey();
347
509
  const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
348
510
  headers['Authorization'] = key;
349
- const response = await fetch(url, {
511
+ const response = await this.fetchWithDebug(url, {
350
512
  method: 'POST',
351
513
  headers,
352
514
  body: JSON.stringify({
@@ -357,53 +519,47 @@ class ApiClient {
357
519
  if (!response.ok) {
358
520
  const errorText = await response.text();
359
521
  let errorMessage = `HTTP ${response.status}`;
522
+ let fullErrorDetails = null;
360
523
  try {
361
524
  const errorJson = JSON.parse(errorText);
362
525
  errorMessage = errorJson.error || errorJson.message || errorMessage;
526
+ fullErrorDetails = errorJson;
363
527
  }
364
528
  catch {
365
529
  errorMessage = errorText || errorMessage;
530
+ fullErrorDetails = errorText;
531
+ }
532
+ // Enhanced error logging: Log full API error details for debugging
533
+ console.error('\n🔍 API Error Details:');
534
+ console.error(` Status: ${response.status}`);
535
+ console.error(` Error: ${errorMessage}`);
536
+ if (fullErrorDetails && typeof fullErrorDetails === 'object') {
537
+ console.error(` Full Response:`, JSON.stringify(fullErrorDetails, null, 2));
366
538
  }
539
+ else {
540
+ console.error(` Full Response: ${fullErrorDetails}`);
541
+ }
542
+ console.error('');
367
543
  throw new Error(`Failed to connect project: ${errorMessage}`);
368
544
  }
369
545
  const result = await response.json();
370
546
  return { id: result.id, name: result.name };
371
547
  }
372
- async generatePlan(intent, files, projectId) {
548
+ async generatePlan(intent, files, projectId, ticketMetadata) {
373
549
  const url = `${this.apiUrl}/api/v1/plan`;
374
550
  const headers = {
375
551
  'Content-Type': 'application/json'
376
552
  };
377
- // Get API key (will show helpful error if missing)
378
- const apiKey = this.getApiKey();
379
- // Support both "Bearer nk_live_..." and just "nk_live_..."
380
- const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
381
- headers['Authorization'] = key;
382
- const response = await this.fetchWithTimeout(url, {
553
+ return this.makeRequest(url, {
383
554
  method: 'POST',
384
555
  headers,
385
556
  body: JSON.stringify({
386
557
  intent,
387
558
  files,
388
559
  projectId,
560
+ ticketMetadata,
389
561
  })
390
562
  });
391
- if (!response.ok) {
392
- const errorText = await response.text();
393
- let errorMessage = `API request failed with status ${response.status}`;
394
- try {
395
- const errorJson = JSON.parse(errorText);
396
- errorMessage = errorJson.error || errorMessage;
397
- if (errorJson.message) {
398
- errorMessage += `: ${errorJson.message}`;
399
- }
400
- }
401
- catch {
402
- errorMessage += `: ${errorText}`;
403
- }
404
- throw new Error(errorMessage);
405
- }
406
- return response.json();
407
563
  }
408
564
  async applyPlan(planId, snapshots) {
409
565
  const url = `${this.apiUrl}/api/v1/apply`;
@@ -415,7 +571,7 @@ class ApiClient {
415
571
  // Support both "Bearer nk_live_..." and just "nk_live_..."
416
572
  const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
417
573
  headers['Authorization'] = key;
418
- const response = await fetch(url, {
574
+ const response = await this.fetchWithDebug(url, {
419
575
  method: 'POST',
420
576
  headers,
421
577
  body: JSON.stringify({
@@ -448,7 +604,7 @@ class ApiClient {
448
604
  const apiKey = this.getApiKey();
449
605
  const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
450
606
  headers['Authorization'] = key;
451
- const response = await fetch(url, {
607
+ const response = await this.fetchWithDebug(url, {
452
608
  method: 'POST',
453
609
  headers,
454
610
  body: JSON.stringify({
@@ -486,7 +642,7 @@ class ApiClient {
486
642
  const apiKey = this.getApiKey();
487
643
  const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
488
644
  headers['Authorization'] = key;
489
- const response = await fetch(url, {
645
+ const response = await this.fetchWithDebug(url, {
490
646
  method: 'POST',
491
647
  headers,
492
648
  body: JSON.stringify({ filePath }),
@@ -509,17 +665,17 @@ class ApiClient {
509
665
  return response.json();
510
666
  }
511
667
  /**
512
- * Get session by ID
668
+ * Get plan by ID
513
669
  */
514
- async getSession(sessionId) {
515
- const url = `${this.apiUrl}/api/v1/sessions/${sessionId}`;
670
+ async getPlan(planId) {
671
+ const url = `${this.apiUrl}/api/v1/plan/${planId}`;
516
672
  const headers = {
517
673
  'Content-Type': 'application/json'
518
674
  };
519
675
  const apiKey = this.getApiKey();
520
676
  const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
521
677
  headers['Authorization'] = key;
522
- const response = await fetch(url, {
678
+ const response = await this.fetchWithDebug(url, {
523
679
  method: 'GET',
524
680
  headers,
525
681
  });
@@ -541,17 +697,49 @@ class ApiClient {
541
697
  return response.json();
542
698
  }
543
699
  /**
544
- * Get plan by ID
700
+ * Get Cursor prompt for a plan
545
701
  */
546
- async getPlan(planId) {
547
- const url = `${this.apiUrl}/api/v1/plan/${planId}`;
702
+ async getPlanPrompt(planId) {
703
+ const url = `${this.apiUrl}/api/v1/architect/plan/${planId}/prompt`;
704
+ const headers = {
705
+ 'Content-Type': 'application/json'
706
+ };
707
+ const apiKey = this.getApiKey();
708
+ const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
709
+ headers['Authorization'] = key;
710
+ const response = await this.fetchWithTimeout(url, {
711
+ method: 'GET',
712
+ headers,
713
+ });
714
+ if (!response.ok) {
715
+ const errorText = await response.text();
716
+ let errorMessage = `API request failed with status ${response.status}`;
717
+ try {
718
+ const errorJson = JSON.parse(errorText);
719
+ errorMessage = errorJson.error || errorMessage;
720
+ if (errorJson.message) {
721
+ errorMessage += `: ${errorJson.message}`;
722
+ }
723
+ }
724
+ catch {
725
+ errorMessage += `: ${errorText}`;
726
+ }
727
+ throw new Error(errorMessage);
728
+ }
729
+ return response.json();
730
+ }
731
+ /**
732
+ * Get list of projects for the authenticated user
733
+ */
734
+ async getProjects() {
735
+ const url = `${this.apiUrl}/api/v1/projects`;
548
736
  const headers = {
549
737
  'Content-Type': 'application/json'
550
738
  };
551
739
  const apiKey = this.getApiKey();
552
740
  const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
553
741
  headers['Authorization'] = key;
554
- const response = await fetch(url, {
742
+ const response = await this.fetchWithDebug(url, {
555
743
  method: 'GET',
556
744
  headers,
557
745
  });
@@ -572,6 +760,121 @@ class ApiClient {
572
760
  }
573
761
  return response.json();
574
762
  }
763
+ /**
764
+ * Get project by name (for CLI auto-discovery)
765
+ */
766
+ async getProjectByName(name) {
767
+ const url = `${this.apiUrl}/api/v1/projects/by-name?name=${encodeURIComponent(name)}`;
768
+ const headers = {
769
+ 'Content-Type': 'application/json'
770
+ };
771
+ const apiKey = this.getApiKey();
772
+ const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
773
+ headers['Authorization'] = key;
774
+ const response = await this.fetchWithDebug(url, {
775
+ method: 'GET',
776
+ headers,
777
+ });
778
+ if (!response.ok) {
779
+ const errorText = await response.text();
780
+ let errorMessage = `API request failed with status ${response.status}`;
781
+ try {
782
+ const errorJson = JSON.parse(errorText);
783
+ errorMessage = errorJson.error || errorMessage;
784
+ if (errorJson.message) {
785
+ errorMessage += `: ${errorJson.message}`;
786
+ }
787
+ }
788
+ catch {
789
+ errorMessage += `: ${errorText}`;
790
+ }
791
+ throw new Error(errorMessage);
792
+ }
793
+ const result = await response.json();
794
+ return result;
795
+ }
796
+ /**
797
+ * Get current user information
798
+ * Works with both API keys and Clerk JWT tokens
799
+ */
800
+ async getCurrentUser() {
801
+ const url = `${this.apiUrl}/api/v1/users/me`;
802
+ const headers = {
803
+ 'Content-Type': 'application/json'
804
+ };
805
+ return this.makeRequest(url, {
806
+ method: 'GET',
807
+ headers,
808
+ }, false); // Don't retry on auth for getCurrentUser (used to check login status)
809
+ }
810
+ /**
811
+ * Get sessions for a project
812
+ */
813
+ async getSessions(projectId, limit = 5) {
814
+ const params = new URLSearchParams();
815
+ if (projectId)
816
+ params.set('projectId', projectId);
817
+ params.set('limit', limit.toString());
818
+ const url = `${this.apiUrl}/api/v1/sessions?${params.toString()}`;
819
+ const headers = {
820
+ 'Content-Type': 'application/json'
821
+ };
822
+ const apiKey = this.getApiKey();
823
+ const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
824
+ headers['Authorization'] = key;
825
+ const response = await this.fetchWithDebug(url, {
826
+ method: 'GET',
827
+ headers,
828
+ });
829
+ if (!response.ok) {
830
+ const errorText = await response.text();
831
+ throw new Error(`API request failed: ${errorText}`);
832
+ }
833
+ const sessions = await response.json();
834
+ return sessions;
835
+ }
836
+ /**
837
+ * End a session (mark as completed)
838
+ */
839
+ async endSession(sessionId) {
840
+ const url = `${this.apiUrl}/api/v1/sessions/${sessionId}/end`;
841
+ const headers = {
842
+ 'Content-Type': 'application/json'
843
+ };
844
+ const apiKey = this.getApiKey();
845
+ const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
846
+ headers['Authorization'] = key;
847
+ const response = await this.fetchWithDebug(url, {
848
+ method: 'POST',
849
+ headers,
850
+ });
851
+ if (!response.ok) {
852
+ const errorText = await response.text();
853
+ throw new Error(`API request failed: ${errorText}`);
854
+ }
855
+ return await response.json();
856
+ }
857
+ /**
858
+ * Get a specific session by ID
859
+ */
860
+ async getSession(sessionId) {
861
+ const url = `${this.apiUrl}/api/v1/sessions/${sessionId}`;
862
+ const headers = {
863
+ 'Content-Type': 'application/json'
864
+ };
865
+ const apiKey = this.getApiKey();
866
+ const key = apiKey.startsWith('Bearer ') ? apiKey : `Bearer ${apiKey}`;
867
+ headers['Authorization'] = key;
868
+ const response = await this.fetchWithDebug(url, {
869
+ method: 'GET',
870
+ headers,
871
+ });
872
+ if (!response.ok) {
873
+ const errorText = await response.text();
874
+ throw new Error(`API request failed: ${errorText}`);
875
+ }
876
+ return await response.json();
877
+ }
575
878
  }
576
879
  exports.ApiClient = ApiClient;
577
880
  //# sourceMappingURL=api-client.js.map