@codebakers/cli 3.3.12 → 3.3.14

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/src/lib/api.ts CHANGED
@@ -260,3 +260,258 @@ export async function reportCliError(
260
260
  // Never fail on error reporting
261
261
  }
262
262
  }
263
+
264
+ // ============================================================================
265
+ // PROJECT TRACKING API
266
+ // ============================================================================
267
+
268
+ export interface ProjectSyncData {
269
+ // Project updates
270
+ project?: {
271
+ status?: 'discovery' | 'planning' | 'building' | 'testing' | 'completed' | 'paused' | 'failed';
272
+ overallProgress?: number;
273
+ prdContent?: string;
274
+ discoveryAnswers?: Record<string, unknown>;
275
+ patternsUsed?: string[];
276
+ detectedStack?: Record<string, string>;
277
+ };
278
+
279
+ // Phases to sync
280
+ phases?: Array<{
281
+ id?: string;
282
+ phaseNumber: number;
283
+ phaseName: string;
284
+ phaseDescription?: string;
285
+ status?: 'pending' | 'in_progress' | 'completed' | 'skipped' | 'failed';
286
+ progress?: number;
287
+ requiredPatterns?: string[];
288
+ aiConfidence?: number;
289
+ aiNotes?: string;
290
+ alternativesConsidered?: string[];
291
+ requiresApproval?: boolean;
292
+ }>;
293
+
294
+ // Events to record
295
+ events?: Array<{
296
+ eventType: string;
297
+ eventTitle: string;
298
+ eventDescription?: string;
299
+ eventData?: Record<string, unknown>;
300
+ phaseId?: string;
301
+ featureId?: string;
302
+ filePath?: string;
303
+ fileAction?: string;
304
+ linesChanged?: number;
305
+ aiConfidence?: number;
306
+ riskLevel?: 'low' | 'medium' | 'high' | 'critical';
307
+ riskReason?: string;
308
+ }>;
309
+
310
+ // Test runs to record
311
+ testRuns?: Array<{
312
+ testType: string;
313
+ testCommand?: string;
314
+ passed: boolean;
315
+ totalTests: number;
316
+ passedTests: number;
317
+ failedTests: number;
318
+ skippedTests: number;
319
+ durationMs?: number;
320
+ phaseId?: string;
321
+ featureId?: string;
322
+ }>;
323
+
324
+ // Files to track
325
+ files?: Array<{
326
+ filePath: string;
327
+ fileName: string;
328
+ fileType?: string;
329
+ lineCount?: number;
330
+ complexity?: number;
331
+ parentPath?: string;
332
+ depth?: number;
333
+ status?: 'active' | 'deleted' | 'renamed';
334
+ featureId?: string;
335
+ }>;
336
+
337
+ // Dependencies to track
338
+ dependencies?: Array<{
339
+ sourceFile: string;
340
+ sourceType?: string;
341
+ targetFile: string;
342
+ targetType?: string;
343
+ dependencyType?: string;
344
+ importName?: string;
345
+ featureId?: string;
346
+ }>;
347
+
348
+ // Risk flags to create
349
+ riskFlags?: Array<{
350
+ riskLevel: 'low' | 'medium' | 'high' | 'critical';
351
+ riskCategory: string;
352
+ riskTitle: string;
353
+ riskDescription?: string;
354
+ triggerFile?: string;
355
+ triggerCode?: string;
356
+ triggerReason?: string;
357
+ aiRecommendation?: string;
358
+ phaseId?: string;
359
+ featureId?: string;
360
+ }>;
361
+
362
+ // Resource usage to track
363
+ resources?: Array<{
364
+ resourceType: string;
365
+ apiEndpoint?: string;
366
+ apiMethod?: string;
367
+ inputTokens?: number;
368
+ outputTokens?: number;
369
+ totalTokens?: number;
370
+ durationMs?: number;
371
+ estimatedCostMillicents?: number;
372
+ phaseId?: string;
373
+ featureId?: string;
374
+ }>;
375
+
376
+ // Create snapshot
377
+ createSnapshot?: {
378
+ snapshotName: string;
379
+ snapshotDescription?: string;
380
+ isAutomatic?: boolean;
381
+ gitCommitHash?: string;
382
+ gitBranch?: string;
383
+ projectState?: Record<string, unknown>;
384
+ fileTree?: Array<Record<string, unknown>>;
385
+ phaseId?: string;
386
+ };
387
+ }
388
+
389
+ export interface ProjectSyncResult {
390
+ projectId: string;
391
+ synced: {
392
+ project: boolean;
393
+ phases: number;
394
+ events: number;
395
+ testRuns: number;
396
+ files: number;
397
+ dependencies: number;
398
+ riskFlags: number;
399
+ resources: number;
400
+ snapshot: boolean;
401
+ };
402
+ }
403
+
404
+ /**
405
+ * Get or create a project on the server
406
+ */
407
+ export async function getOrCreateProject(
408
+ projectHash: string,
409
+ projectName: string,
410
+ projectDescription?: string,
411
+ detectedStack?: Record<string, string>,
412
+ authHeaders?: Record<string, string>
413
+ ): Promise<{ projectId: string; isNew: boolean }> {
414
+ const apiUrl = getApiUrl();
415
+
416
+ const response = await fetch(`${apiUrl}/api/projects`, {
417
+ method: 'POST',
418
+ headers: {
419
+ 'Content-Type': 'application/json',
420
+ ...authHeaders,
421
+ },
422
+ body: JSON.stringify({
423
+ projectHash,
424
+ projectName,
425
+ projectDescription,
426
+ detectedStack,
427
+ }),
428
+ });
429
+
430
+ if (!response.ok) {
431
+ const error = await response.json().catch(() => ({ error: 'Unknown error' }));
432
+ throw createApiError(
433
+ error.error || 'Failed to create/get project',
434
+ 'PROJECT_ERROR',
435
+ ['Check your internet connection', 'Verify your API key is valid']
436
+ );
437
+ }
438
+
439
+ const result = await response.json();
440
+ return {
441
+ projectId: result.data?.id || result.id,
442
+ isNew: result.data?.isNew || result.isNew || false,
443
+ };
444
+ }
445
+
446
+ /**
447
+ * Sync project data to the server
448
+ * This is the main endpoint for keeping the server updated with local state
449
+ */
450
+ export async function syncProjectData(
451
+ projectId: string,
452
+ data: ProjectSyncData,
453
+ authHeaders?: Record<string, string>
454
+ ): Promise<ProjectSyncResult> {
455
+ const apiUrl = getApiUrl();
456
+
457
+ const response = await fetch(`${apiUrl}/api/projects/${projectId}/sync`, {
458
+ method: 'POST',
459
+ headers: {
460
+ 'Content-Type': 'application/json',
461
+ ...authHeaders,
462
+ },
463
+ body: JSON.stringify(data),
464
+ });
465
+
466
+ if (!response.ok) {
467
+ const error = await response.json().catch(() => ({ error: 'Unknown error' }));
468
+ throw createApiError(
469
+ error.error || 'Failed to sync project data',
470
+ 'SYNC_ERROR',
471
+ ['Check your internet connection', 'Try again in a few moments']
472
+ );
473
+ }
474
+
475
+ const result = await response.json();
476
+ return result.data || result;
477
+ }
478
+
479
+ /**
480
+ * Get project dashboard data from the server
481
+ */
482
+ export async function getProjectDashboard(
483
+ projectId: string,
484
+ authHeaders?: Record<string, string>
485
+ ): Promise<Record<string, unknown>> {
486
+ const apiUrl = getApiUrl();
487
+
488
+ const response = await fetch(`${apiUrl}/api/projects/${projectId}`, {
489
+ method: 'GET',
490
+ headers: {
491
+ 'Accept': 'application/json',
492
+ ...authHeaders,
493
+ },
494
+ });
495
+
496
+ if (!response.ok) {
497
+ const error = await response.json().catch(() => ({ error: 'Unknown error' }));
498
+ throw createApiError(
499
+ error.error || 'Failed to get project dashboard',
500
+ 'PROJECT_ERROR',
501
+ ['Check your internet connection', 'Verify the project exists']
502
+ );
503
+ }
504
+
505
+ const result = await response.json();
506
+ return result.data || result;
507
+ }
508
+
509
+ /**
510
+ * Create a project hash from the project directory
511
+ * Uses a combination of directory path and package.json name for uniqueness
512
+ */
513
+ export function createProjectHash(projectDir: string, packageName?: string): string {
514
+ const crypto = require('crypto');
515
+ const hashInput = packageName ? `${projectDir}:${packageName}` : projectDir;
516
+ return crypto.createHash('sha256').update(hashInput).digest('hex').substring(0, 16);
517
+ }