@vibescope/mcp-server 0.2.4 → 0.2.5

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 (84) hide show
  1. package/CHANGELOG.md +84 -84
  2. package/README.md +194 -181
  3. package/dist/cli.d.ts +6 -3
  4. package/dist/cli.js +28 -10
  5. package/dist/handlers/tool-docs.js +828 -828
  6. package/dist/index.js +73 -73
  7. package/dist/knowledge.d.ts +6 -0
  8. package/dist/knowledge.js +218 -0
  9. package/dist/setup.d.ts +22 -0
  10. package/dist/setup.js +313 -0
  11. package/dist/templates/agent-guidelines.js +185 -185
  12. package/dist/tools.js +65 -65
  13. package/dist/utils.js +11 -11
  14. package/docs/TOOLS.md +2053 -2053
  15. package/package.json +1 -1
  16. package/scripts/generate-docs.ts +212 -212
  17. package/scripts/version-bump.ts +203 -203
  18. package/src/api-client.test.ts +723 -723
  19. package/src/api-client.ts +2499 -2499
  20. package/src/cli.ts +27 -10
  21. package/src/handlers/__test-setup__.ts +236 -236
  22. package/src/handlers/__test-utils__.ts +87 -87
  23. package/src/handlers/blockers.test.ts +468 -468
  24. package/src/handlers/blockers.ts +163 -163
  25. package/src/handlers/bodies-of-work.test.ts +704 -704
  26. package/src/handlers/bodies-of-work.ts +526 -526
  27. package/src/handlers/connectors.test.ts +834 -834
  28. package/src/handlers/connectors.ts +229 -229
  29. package/src/handlers/cost.test.ts +462 -462
  30. package/src/handlers/cost.ts +285 -285
  31. package/src/handlers/decisions.test.ts +382 -382
  32. package/src/handlers/decisions.ts +153 -153
  33. package/src/handlers/deployment.test.ts +551 -551
  34. package/src/handlers/deployment.ts +541 -541
  35. package/src/handlers/discovery.test.ts +206 -206
  36. package/src/handlers/discovery.ts +390 -390
  37. package/src/handlers/fallback.test.ts +537 -537
  38. package/src/handlers/fallback.ts +194 -194
  39. package/src/handlers/file-checkouts.test.ts +750 -750
  40. package/src/handlers/file-checkouts.ts +185 -185
  41. package/src/handlers/findings.test.ts +633 -633
  42. package/src/handlers/findings.ts +239 -239
  43. package/src/handlers/git-issues.test.ts +631 -631
  44. package/src/handlers/git-issues.ts +136 -136
  45. package/src/handlers/ideas.test.ts +644 -644
  46. package/src/handlers/ideas.ts +207 -207
  47. package/src/handlers/index.ts +84 -84
  48. package/src/handlers/milestones.test.ts +475 -475
  49. package/src/handlers/milestones.ts +180 -180
  50. package/src/handlers/organizations.test.ts +826 -826
  51. package/src/handlers/organizations.ts +315 -315
  52. package/src/handlers/progress.test.ts +269 -269
  53. package/src/handlers/progress.ts +77 -77
  54. package/src/handlers/project.test.ts +546 -546
  55. package/src/handlers/project.ts +239 -239
  56. package/src/handlers/requests.test.ts +303 -303
  57. package/src/handlers/requests.ts +99 -99
  58. package/src/handlers/roles.test.ts +303 -303
  59. package/src/handlers/roles.ts +226 -226
  60. package/src/handlers/session.test.ts +875 -875
  61. package/src/handlers/session.ts +738 -738
  62. package/src/handlers/sprints.test.ts +732 -732
  63. package/src/handlers/sprints.ts +537 -537
  64. package/src/handlers/tasks.test.ts +907 -907
  65. package/src/handlers/tasks.ts +945 -945
  66. package/src/handlers/tool-categories.test.ts +66 -66
  67. package/src/handlers/tool-docs.ts +1096 -1096
  68. package/src/handlers/types.test.ts +259 -259
  69. package/src/handlers/types.ts +175 -175
  70. package/src/handlers/validation.test.ts +582 -582
  71. package/src/handlers/validation.ts +97 -97
  72. package/src/index.ts +792 -792
  73. package/src/setup.test.ts +231 -0
  74. package/src/setup.ts +370 -0
  75. package/src/templates/agent-guidelines.ts +210 -210
  76. package/src/token-tracking.test.ts +453 -453
  77. package/src/token-tracking.ts +164 -164
  78. package/src/tools.ts +3562 -3562
  79. package/src/utils.test.ts +683 -683
  80. package/src/utils.ts +436 -436
  81. package/src/validators.test.ts +223 -223
  82. package/src/validators.ts +249 -249
  83. package/tsconfig.json +16 -16
  84. package/vitest.config.ts +14 -14
package/src/api-client.ts CHANGED
@@ -1,2499 +1,2499 @@
1
- /**
2
- * Vibescope API Client
3
- *
4
- * HTTP client for communicating with the Vibescope API.
5
- * All database operations are handled server-side through these endpoints.
6
- */
7
-
8
- const DEFAULT_API_URL = 'https://vibescope.dev';
9
-
10
- interface ApiClientConfig {
11
- apiKey: string;
12
- baseUrl?: string;
13
- }
14
-
15
- interface ApiResponse<T> {
16
- ok: boolean;
17
- status: number;
18
- data?: T;
19
- error?: string;
20
- }
21
-
22
- export class VibescopeApiClient {
23
- private apiKey: string;
24
- private baseUrl: string;
25
-
26
- constructor(config: ApiClientConfig) {
27
- this.apiKey = config.apiKey;
28
- this.baseUrl = config.baseUrl || process.env.VIBESCOPE_API_URL || DEFAULT_API_URL;
29
- }
30
-
31
- private async request<T>(method: string, path: string, body?: unknown): Promise<ApiResponse<T>> {
32
- const url = `${this.baseUrl}${path}`;
33
-
34
- try {
35
- const response = await fetch(url, {
36
- method,
37
- headers: {
38
- 'Content-Type': 'application/json',
39
- 'X-API-Key': this.apiKey
40
- },
41
- body: body ? JSON.stringify(body) : undefined
42
- });
43
-
44
- const data = await response.json();
45
-
46
- if (!response.ok) {
47
- return {
48
- ok: false,
49
- status: response.status,
50
- error: data.error || `HTTP ${response.status}`,
51
- data // Include full response data for additional error context
52
- };
53
- }
54
-
55
- return {
56
- ok: true,
57
- status: response.status,
58
- data
59
- };
60
- } catch (err) {
61
- return {
62
- ok: false,
63
- status: 0,
64
- error: err instanceof Error ? err.message : 'Network error'
65
- };
66
- }
67
- }
68
-
69
- // Auth endpoints
70
- async validateAuth(): Promise<ApiResponse<{
71
- valid: boolean;
72
- user_id: string;
73
- api_key_id: string;
74
- key_name: string;
75
- }>> {
76
- return this.request('POST', '/api/mcp/auth/validate', {
77
- api_key: this.apiKey
78
- });
79
- }
80
-
81
- // Session endpoints
82
- async startSession(params: {
83
- project_id?: string;
84
- git_url?: string;
85
- mode?: 'lite' | 'full';
86
- model?: 'opus' | 'sonnet' | 'haiku';
87
- role?: 'developer' | 'validator' | 'deployer' | 'reviewer' | 'maintainer';
88
- hostname?: string; // Machine hostname for worktree tracking
89
- agent_type?: 'claude' | 'gemini' | 'cursor' | 'windsurf' | 'other'; // Agent type for onboarding
90
- }): Promise<ApiResponse<{
91
- session_started: boolean;
92
- session_id?: string;
93
- persona?: string;
94
- role?: string;
95
- project?: {
96
- id: string;
97
- name: string;
98
- description?: string;
99
- goal?: string;
100
- status?: string;
101
- git_url?: string;
102
- agent_instructions?: string;
103
- tech_stack?: string[];
104
- git_workflow?: string;
105
- git_main_branch?: string;
106
- git_develop_branch?: string;
107
- git_auto_branch?: boolean;
108
- };
109
- active_tasks?: Array<{
110
- id: string;
111
- title: string;
112
- status: string;
113
- priority: number;
114
- progress_percentage?: number;
115
- estimated_minutes?: number;
116
- }>;
117
- blockers?: Array<{
118
- id: string;
119
- description: string;
120
- status: string;
121
- }>;
122
- next_task?: {
123
- id: string;
124
- title: string;
125
- priority: number;
126
- estimated_minutes?: number;
127
- } | null;
128
- pending_requests?: Array<{
129
- id: string;
130
- request_type: string;
131
- message: string;
132
- created_at: string;
133
- }>;
134
- pending_requests_count?: number;
135
- URGENT_QUESTIONS?: {
136
- count: number;
137
- oldest_waiting_minutes: number;
138
- action_required: string;
139
- requests: Array<{
140
- id: string;
141
- message: string;
142
- waiting_minutes: number;
143
- }>;
144
- };
145
- directive?: string;
146
- blockers_count?: number;
147
- validation_count?: number;
148
- project_not_found?: boolean;
149
- message?: string;
150
- suggestion?: {
151
- action: string;
152
- example: string;
153
- note: string;
154
- };
155
- // Agent onboarding - returned when a new agent type connects to an existing project
156
- agent_setup?: {
157
- agent_type: string;
158
- is_new_agent_type: boolean;
159
- setup_required: boolean;
160
- instructions: string;
161
- config_file: string; // e.g., '.gemini/GEMINI.md'
162
- template_url?: string;
163
- steps: string[];
164
- };
165
- // Stale worktrees that need cleanup
166
- stale_worktrees?: Array<{
167
- task_id: string;
168
- task_title: string;
169
- worktree_path: string;
170
- worktree_hostname?: string | null;
171
- }>;
172
- stale_worktrees_count?: number;
173
- cleanup_action?: string;
174
- // Validation info for validators
175
- awaiting_validation?: Array<{
176
- id: string;
177
- title?: string;
178
- }>;
179
- validation_priority?: boolean;
180
- next_action?: string;
181
- error?: string;
182
- }>> {
183
- return this.request('POST', '/api/mcp/sessions/start', params);
184
- }
185
-
186
- async heartbeat(sessionId: string, options?: {
187
- current_worktree_path?: string | null;
188
- hostname?: string; // Machine hostname for worktree tracking
189
- }): Promise<ApiResponse<{
190
- success: boolean;
191
- session_id: string;
192
- timestamp: string;
193
- }>> {
194
- return this.request('POST', '/api/mcp/sessions/heartbeat', {
195
- session_id: sessionId,
196
- ...options
197
- });
198
- }
199
-
200
- async endSession(sessionId: string): Promise<ApiResponse<{
201
- success: boolean;
202
- ended_session_id?: string;
203
- session_summary?: {
204
- agent_name: string;
205
- tasks_completed_this_session: number;
206
- tasks_awaiting_validation: number;
207
- tasks_released: number;
208
- };
209
- reminders?: string[];
210
- }>> {
211
- return this.request('POST', '/api/mcp/sessions/end', {
212
- session_id: sessionId
213
- });
214
- }
215
-
216
- // Project endpoints
217
- async listProjects(): Promise<ApiResponse<{
218
- projects: Array<{
219
- id: string;
220
- name: string;
221
- description?: string;
222
- status: string;
223
- git_url?: string;
224
- goal?: string;
225
- tech_stack?: string[];
226
- }>;
227
- }>> {
228
- return this.request('GET', '/api/mcp/projects');
229
- }
230
-
231
- async createProject(params: {
232
- name: string;
233
- description?: string;
234
- goal?: string;
235
- git_url?: string;
236
- tech_stack?: string[];
237
- }): Promise<ApiResponse<{
238
- success: boolean;
239
- project: {
240
- id: string;
241
- name: string;
242
- };
243
- }>> {
244
- return this.request('POST', '/api/mcp/projects', params);
245
- }
246
-
247
- async getProject(projectId: string, gitUrl?: string): Promise<ApiResponse<{
248
- found: boolean;
249
- project?: {
250
- id: string;
251
- name: string;
252
- description?: string;
253
- goal?: string;
254
- status: string;
255
- git_url?: string;
256
- agent_instructions?: string;
257
- tech_stack?: string[];
258
- git_workflow?: string;
259
- git_main_branch?: string;
260
- git_develop_branch?: string;
261
- git_auto_branch?: boolean;
262
- git_auto_tag?: boolean;
263
- deployment_instructions?: string;
264
- };
265
- active_tasks?: Array<{
266
- id: string;
267
- title: string;
268
- description?: string;
269
- priority: number;
270
- status: string;
271
- progress_percentage?: number;
272
- estimated_minutes?: number;
273
- }>;
274
- open_blockers?: Array<{
275
- id: string;
276
- description: string;
277
- }>;
278
- recent_decisions?: Array<{
279
- id: string;
280
- title: string;
281
- description?: string;
282
- }>;
283
- message?: string;
284
- }>> {
285
- const url = gitUrl
286
- ? `/api/mcp/projects/${projectId}?git_url=${encodeURIComponent(gitUrl)}`
287
- : `/api/mcp/projects/${projectId}`;
288
- return this.request('GET', url);
289
- }
290
-
291
- async updateProject(projectId: string, updates: {
292
- name?: string;
293
- description?: string;
294
- goal?: string;
295
- git_url?: string;
296
- tech_stack?: string[];
297
- status?: string;
298
- git_workflow?: string;
299
- git_main_branch?: string;
300
- git_develop_branch?: string;
301
- git_auto_branch?: boolean;
302
- git_auto_tag?: boolean;
303
- deployment_instructions?: string;
304
- agent_instructions?: string;
305
- // New project settings columns
306
- git_delete_branch_on_merge?: boolean;
307
- require_pr_for_validation?: boolean;
308
- auto_merge_on_approval?: boolean;
309
- validation_required?: boolean;
310
- default_task_priority?: number;
311
- require_time_estimates?: boolean;
312
- fallback_activities_enabled?: boolean;
313
- preferred_fallback_activities?: string[];
314
- }): Promise<ApiResponse<{
315
- success: boolean;
316
- project_id: string;
317
- }>> {
318
- return this.request('PATCH', `/api/mcp/projects/${projectId}`, updates);
319
- }
320
-
321
- // Task endpoints
322
- async getTasks(projectId: string, params?: {
323
- status?: string;
324
- limit?: number;
325
- offset?: number;
326
- include_subtasks?: boolean;
327
- search_query?: string;
328
- include_metadata?: boolean; // When true, returns all task fields; when false (default), only id/title/priority/status
329
- }): Promise<ApiResponse<{
330
- tasks: Array<{
331
- id: string;
332
- title: string;
333
- description?: string;
334
- priority: number;
335
- status: string;
336
- progress_percentage?: number;
337
- estimated_minutes?: number;
338
- started_at?: string;
339
- completed_at?: string;
340
- parent_task_id?: string;
341
- }>;
342
- total_count: number;
343
- has_more: boolean;
344
- }>> {
345
- const queryParams = new URLSearchParams();
346
- if (params?.status) queryParams.set('status', params.status);
347
- if (params?.limit) queryParams.set('limit', params.limit.toString());
348
- if (params?.offset) queryParams.set('offset', params.offset.toString());
349
- if (params?.include_subtasks) queryParams.set('include_subtasks', 'true');
350
- if (params?.search_query) queryParams.set('search_query', params.search_query);
351
- if (params?.include_metadata) queryParams.set('include_metadata', 'true');
352
-
353
- const query = queryParams.toString();
354
- const url = `/api/mcp/projects/${projectId}/tasks${query ? `?${query}` : ''}`;
355
- return this.request('GET', url);
356
- }
357
-
358
- async createTask(projectId: string, params: {
359
- title: string;
360
- description?: string;
361
- priority?: number;
362
- estimated_minutes?: number;
363
- blocking?: boolean;
364
- session_id?: string;
365
- task_type?: string;
366
- }): Promise<ApiResponse<{
367
- success: boolean;
368
- task_id: string;
369
- title: string;
370
- blocking?: boolean;
371
- message?: string;
372
- }>> {
373
- return this.request('POST', `/api/mcp/projects/${projectId}/tasks`, params);
374
- }
375
-
376
- async getNextTask(projectId: string, sessionId?: string): Promise<ApiResponse<{
377
- task?: {
378
- id: string;
379
- title: string;
380
- description?: string;
381
- priority: number;
382
- estimated_minutes?: number;
383
- blocking?: boolean;
384
- } | null;
385
- blocking_task?: boolean;
386
- deployment_blocks_tasks?: boolean;
387
- deployment?: {
388
- id: string;
389
- status: string;
390
- env: string;
391
- };
392
- awaiting_validation?: Array<{
393
- id: string;
394
- title: string;
395
- }>;
396
- validation_priority?: string;
397
- all_claimed?: boolean;
398
- is_subtask?: boolean;
399
- suggested_activity?: string;
400
- directive?: string;
401
- message?: string;
402
- action?: string;
403
- }>> {
404
- const url = sessionId
405
- ? `/api/mcp/projects/${projectId}/next-task?session_id=${sessionId}`
406
- : `/api/mcp/projects/${projectId}/next-task`;
407
- return this.request('GET', url);
408
- }
409
-
410
- async getTask(taskId: string): Promise<ApiResponse<{
411
- task: {
412
- id: string;
413
- title: string;
414
- description?: string;
415
- priority: number;
416
- status: string;
417
- progress_percentage?: number;
418
- estimated_minutes?: number;
419
- started_at?: string;
420
- completed_at?: string;
421
- git_branch?: string;
422
- blocking?: boolean;
423
- references?: Array<{ url: string; label?: string }>;
424
- parent_task_id?: string;
425
- working_agent_session_id?: string;
426
- };
427
- }>> {
428
- return this.request('GET', `/api/mcp/tasks/${taskId}`);
429
- }
430
-
431
- /**
432
- * Get a single task by ID with optional subtasks and milestones
433
- */
434
- async getTaskById(taskId: string, params?: {
435
- include_subtasks?: boolean;
436
- include_milestones?: boolean;
437
- }): Promise<ApiResponse<{
438
- task: {
439
- id: string;
440
- title: string;
441
- description?: string;
442
- priority: number;
443
- status: string;
444
- progress_percentage?: number;
445
- estimated_minutes?: number;
446
- started_at?: string;
447
- completed_at?: string;
448
- git_branch?: string;
449
- references?: Array<{ url: string; label?: string }>;
450
- };
451
- subtasks?: Array<{
452
- id: string;
453
- title: string;
454
- status: string;
455
- progress_percentage?: number;
456
- }>;
457
- milestones?: Array<{
458
- id: string;
459
- title: string;
460
- status: string;
461
- order_index: number;
462
- }>;
463
- }>> {
464
- return this.proxy('get_task', {
465
- task_id: taskId,
466
- include_subtasks: params?.include_subtasks,
467
- include_milestones: params?.include_milestones,
468
- });
469
- }
470
-
471
- /**
472
- * Search tasks by text query with pagination
473
- */
474
- async searchTasks(projectId: string, params: {
475
- query: string;
476
- status?: string[];
477
- limit?: number;
478
- offset?: number;
479
- }): Promise<ApiResponse<{
480
- tasks: Array<{
481
- id: string;
482
- title: string;
483
- status: string;
484
- priority: number;
485
- snippet?: string;
486
- }>;
487
- total_matches: number;
488
- hint?: string;
489
- }>> {
490
- return this.proxy('search_tasks', {
491
- project_id: projectId,
492
- query: params.query,
493
- status: params.status,
494
- limit: params.limit,
495
- offset: params.offset,
496
- });
497
- }
498
-
499
- /**
500
- * Get tasks filtered by priority with pagination
501
- */
502
- async getTasksByPriority(projectId: string, params?: {
503
- priority?: number;
504
- priority_max?: number;
505
- status?: string;
506
- limit?: number;
507
- offset?: number;
508
- }): Promise<ApiResponse<{
509
- tasks: Array<{
510
- id: string;
511
- title: string;
512
- priority: number;
513
- status: string;
514
- estimated_minutes?: number;
515
- }>;
516
- total_count: number;
517
- }>> {
518
- return this.proxy('get_tasks_by_priority', {
519
- project_id: projectId,
520
- priority: params?.priority,
521
- priority_max: params?.priority_max,
522
- status: params?.status,
523
- limit: params?.limit,
524
- offset: params?.offset,
525
- });
526
- }
527
-
528
- /**
529
- * Get recent tasks (newest or oldest) with pagination
530
- */
531
- async getRecentTasks(projectId: string, params?: {
532
- order?: 'newest' | 'oldest';
533
- status?: string;
534
- limit?: number;
535
- offset?: number;
536
- }): Promise<ApiResponse<{
537
- tasks: Array<{
538
- id: string;
539
- title: string;
540
- status: string;
541
- priority: number;
542
- created_at: string;
543
- age?: string;
544
- }>;
545
- total_count: number;
546
- }>> {
547
- return this.proxy('get_recent_tasks', {
548
- project_id: projectId,
549
- order: params?.order,
550
- status: params?.status,
551
- limit: params?.limit,
552
- offset: params?.offset,
553
- });
554
- }
555
-
556
- /**
557
- * Get task statistics for a project
558
- */
559
- async getTaskStats(projectId: string): Promise<ApiResponse<{
560
- total: number;
561
- by_status: {
562
- backlog: number;
563
- pending: number;
564
- in_progress: number;
565
- completed: number;
566
- cancelled: number;
567
- };
568
- by_priority: {
569
- 1: number;
570
- 2: number;
571
- 3: number;
572
- 4: number;
573
- 5: number;
574
- };
575
- awaiting_validation: number;
576
- oldest_pending_days: number | null;
577
- }>> {
578
- return this.proxy('get_task_stats', {
579
- project_id: projectId,
580
- });
581
- }
582
-
583
- async updateTask(taskId: string, updates: {
584
- title?: string;
585
- description?: string;
586
- priority?: number;
587
- status?: string;
588
- progress_percentage?: number;
589
- progress_note?: string;
590
- estimated_minutes?: number;
591
- git_branch?: string;
592
- worktree_path?: string;
593
- session_id?: string;
594
- }): Promise<ApiResponse<{
595
- success: boolean;
596
- task_id: string;
597
- git_workflow?: {
598
- workflow: string;
599
- base_branch: string;
600
- suggested_branch: string;
601
- worktree_required: boolean;
602
- };
603
- worktree_setup?: {
604
- message: string;
605
- commands: string[];
606
- worktree_path: string;
607
- branch_name: string;
608
- cleanup_command: string;
609
- };
610
- next_step?: string;
611
- }>> {
612
- return this.request('PATCH', `/api/mcp/tasks/${taskId}`, updates);
613
- }
614
-
615
- async completeTask(taskId: string, params: {
616
- summary?: string;
617
- session_id?: string;
618
- }): Promise<ApiResponse<{
619
- success: boolean;
620
- directive: string;
621
- auto_continue: boolean;
622
- completed_task_id: string;
623
- next_task?: {
624
- id: string;
625
- title: string;
626
- priority: number;
627
- estimated_minutes?: number;
628
- } | null;
629
- context?: {
630
- validation?: number;
631
- blockers?: number;
632
- deployment?: string;
633
- };
634
- next_action: string;
635
- warnings?: string[];
636
- }>> {
637
- // Use proxy endpoint for consistency - direct endpoint had routing issues on Vercel
638
- return this.proxy('complete_task', {
639
- task_id: taskId,
640
- summary: params.summary,
641
- }, params.session_id ? { session_id: params.session_id, persona: null, instance_id: '' } : undefined);
642
- }
643
-
644
- async deleteTask(taskId: string): Promise<ApiResponse<{
645
- success: boolean;
646
- deleted_id: string;
647
- }>> {
648
- return this.request('DELETE', `/api/mcp/tasks/${taskId}`);
649
- }
650
-
651
- // Progress endpoints
652
- async logProgress(projectId: string, params: {
653
- summary: string;
654
- details?: string;
655
- task_id?: string;
656
- session_id?: string;
657
- }): Promise<ApiResponse<{
658
- success: boolean;
659
- progress_id: string;
660
- }>> {
661
- return this.request('POST', `/api/mcp/projects/${projectId}/progress`, params);
662
- }
663
-
664
- // Git workflow endpoint
665
- async getGitWorkflow(projectId: string, taskId?: string): Promise<ApiResponse<{
666
- workflow: string;
667
- main_branch: string;
668
- develop_branch?: string | null;
669
- auto_branch?: boolean;
670
- auto_tag?: boolean;
671
- instructions: string[];
672
- task?: {
673
- id: string;
674
- title: string;
675
- current_branch?: string;
676
- suggested_branch?: string | null;
677
- };
678
- }>> {
679
- const url = taskId
680
- ? `/api/mcp/projects/${projectId}/git-workflow?task_id=${taskId}`
681
- : `/api/mcp/projects/${projectId}/git-workflow`;
682
- return this.request('GET', url);
683
- }
684
-
685
- // ============================================================================
686
- // Proxy endpoint - Generic method for all operations
687
- // ============================================================================
688
- async proxy<T>(operation: string, args: Record<string, unknown>, sessionContext?: {
689
- session_id: string | null;
690
- persona: string | null;
691
- instance_id: string;
692
- }): Promise<ApiResponse<T>> {
693
- return this.request('POST', '/api/mcp/proxy', {
694
- operation,
695
- args,
696
- session_context: sessionContext
697
- });
698
- }
699
-
700
- // ============================================================================
701
- // Blocker endpoints
702
- // ============================================================================
703
- async getBlockers(projectId: string, params?: {
704
- status?: string;
705
- limit?: number;
706
- offset?: number;
707
- search_query?: string;
708
- }): Promise<ApiResponse<{
709
- blockers: Array<{
710
- id: string;
711
- description: string;
712
- status: string;
713
- resolution_note?: string;
714
- created_at: string;
715
- resolved_at?: string;
716
- }>;
717
- total_count?: number;
718
- has_more?: boolean;
719
- }>> {
720
- return this.proxy('get_blockers', {
721
- project_id: projectId,
722
- ...params
723
- });
724
- }
725
-
726
- async addBlocker(projectId: string, description: string, sessionId?: string): Promise<ApiResponse<{
727
- success: boolean;
728
- blocker_id: string;
729
- }>> {
730
- return this.proxy('add_blocker', { project_id: projectId, description }, sessionId ? {
731
- session_id: sessionId,
732
- persona: null,
733
- instance_id: ''
734
- } : undefined);
735
- }
736
-
737
- async resolveBlocker(blockerId: string, resolutionNote?: string): Promise<ApiResponse<{
738
- success: boolean;
739
- blocker_id: string;
740
- }>> {
741
- return this.proxy('resolve_blocker', {
742
- blocker_id: blockerId,
743
- resolution_note: resolutionNote
744
- });
745
- }
746
-
747
- async deleteBlocker(blockerId: string): Promise<ApiResponse<{
748
- success: boolean;
749
- }>> {
750
- return this.proxy('delete_blocker', { blocker_id: blockerId });
751
- }
752
-
753
- async getBlockersStats(projectId: string): Promise<ApiResponse<{
754
- total: number;
755
- by_status: Record<string, number>;
756
- }>> {
757
- return this.proxy('get_blockers_stats', {
758
- project_id: projectId
759
- });
760
- }
761
-
762
- // ============================================================================
763
- // Decision endpoints
764
- // ============================================================================
765
- async getDecisions(projectId: string, options?: {
766
- limit?: number;
767
- offset?: number;
768
- search_query?: string;
769
- }): Promise<ApiResponse<{
770
- decisions: Array<{
771
- id: string;
772
- title: string;
773
- description: string;
774
- rationale?: string;
775
- alternatives_considered?: string[];
776
- created_at: string;
777
- }>;
778
- }>> {
779
- return this.proxy('get_decisions', { project_id: projectId, ...options });
780
- }
781
-
782
- async logDecision(projectId: string, params: {
783
- title: string;
784
- description: string;
785
- rationale?: string;
786
- alternatives_considered?: string[];
787
- }, sessionId?: string): Promise<ApiResponse<{
788
- success: boolean;
789
- decision_id: string;
790
- }>> {
791
- return this.proxy('log_decision', {
792
- project_id: projectId,
793
- ...params
794
- }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
795
- }
796
-
797
- async deleteDecision(decisionId: string): Promise<ApiResponse<{
798
- success: boolean;
799
- }>> {
800
- return this.proxy('delete_decision', { decision_id: decisionId });
801
- }
802
-
803
- async getDecisionsStats(projectId: string): Promise<ApiResponse<{
804
- total: number;
805
- }>> {
806
- return this.proxy('get_decisions_stats', {
807
- project_id: projectId
808
- });
809
- }
810
-
811
- // ============================================================================
812
- // Idea endpoints
813
- // ============================================================================
814
- async getIdeas(projectId: string, params?: {
815
- status?: string;
816
- limit?: number;
817
- offset?: number;
818
- search_query?: string;
819
- }): Promise<ApiResponse<{
820
- ideas: Array<{
821
- id: string;
822
- title: string;
823
- description?: string;
824
- status: string;
825
- doc_url?: string;
826
- created_at: string;
827
- }>;
828
- }>> {
829
- return this.proxy('get_ideas', {
830
- project_id: projectId,
831
- ...params
832
- });
833
- }
834
-
835
- async addIdea(projectId: string, params: {
836
- title: string;
837
- description?: string;
838
- status?: string;
839
- }, sessionId?: string): Promise<ApiResponse<{
840
- success: boolean;
841
- idea_id: string;
842
- }>> {
843
- return this.proxy('add_idea', {
844
- project_id: projectId,
845
- ...params
846
- }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
847
- }
848
-
849
- async updateIdea(ideaId: string, updates: {
850
- title?: string;
851
- description?: string;
852
- status?: string;
853
- doc_url?: string;
854
- }): Promise<ApiResponse<{
855
- success: boolean;
856
- idea_id: string;
857
- }>> {
858
- return this.proxy('update_idea', {
859
- idea_id: ideaId,
860
- ...updates
861
- });
862
- }
863
-
864
- async deleteIdea(ideaId: string): Promise<ApiResponse<{
865
- success: boolean;
866
- }>> {
867
- return this.proxy('delete_idea', { idea_id: ideaId });
868
- }
869
-
870
- async convertIdeaToTask(ideaId: string, params?: {
871
- priority?: number;
872
- estimated_minutes?: number;
873
- update_status?: boolean;
874
- }): Promise<ApiResponse<{
875
- success: boolean;
876
- task_id?: string;
877
- task_title?: string;
878
- idea_id?: string;
879
- idea_status?: string;
880
- message?: string;
881
- error?: string;
882
- existing_task_id?: string;
883
- }>> {
884
- return this.proxy('convert_idea_to_task', {
885
- idea_id: ideaId,
886
- ...params
887
- });
888
- }
889
-
890
- // ============================================================================
891
- // Finding endpoints
892
- // ============================================================================
893
- async getFindings(projectId: string, params?: {
894
- category?: string;
895
- severity?: string;
896
- status?: string;
897
- limit?: number;
898
- offset?: number;
899
- search_query?: string;
900
- summary_only?: boolean;
901
- }): Promise<ApiResponse<{
902
- findings: Array<{
903
- id: string;
904
- title: string;
905
- description?: string;
906
- category: string;
907
- severity: string;
908
- status: string;
909
- file_path?: string;
910
- line_number?: number;
911
- resolution_note?: string;
912
- created_at: string;
913
- }>;
914
- total_count?: number;
915
- has_more?: boolean;
916
- }>> {
917
- return this.proxy('get_findings', {
918
- project_id: projectId,
919
- ...params
920
- });
921
- }
922
-
923
- async getFindingsStats(projectId: string): Promise<ApiResponse<{
924
- total: number;
925
- by_status: Record<string, number>;
926
- by_severity: Record<string, number>;
927
- by_category: Record<string, number>;
928
- }>> {
929
- return this.proxy('get_findings_stats', {
930
- project_id: projectId
931
- });
932
- }
933
-
934
- async addFinding(projectId: string, params: {
935
- title: string;
936
- description?: string;
937
- category?: string;
938
- severity?: string;
939
- file_path?: string;
940
- line_number?: number;
941
- related_task_id?: string;
942
- }, sessionId?: string): Promise<ApiResponse<{
943
- success: boolean;
944
- finding_id: string;
945
- }>> {
946
- return this.proxy('add_finding', {
947
- project_id: projectId,
948
- ...params
949
- }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
950
- }
951
-
952
- async updateFinding(findingId: string, updates: {
953
- title?: string;
954
- description?: string;
955
- severity?: string;
956
- status?: string;
957
- resolution_note?: string;
958
- }): Promise<ApiResponse<{
959
- success: boolean;
960
- finding_id: string;
961
- }>> {
962
- return this.proxy('update_finding', {
963
- finding_id: findingId,
964
- ...updates
965
- });
966
- }
967
-
968
- async deleteFinding(findingId: string): Promise<ApiResponse<{
969
- success: boolean;
970
- }>> {
971
- return this.proxy('delete_finding', { finding_id: findingId });
972
- }
973
-
974
- // ============================================================================
975
- // Milestone endpoints
976
- // ============================================================================
977
- async getMilestones(taskId: string): Promise<ApiResponse<{
978
- milestones: Array<{
979
- id: string;
980
- title: string;
981
- description?: string;
982
- status: string;
983
- order_index: number;
984
- created_at: string;
985
- completed_at?: string;
986
- }>;
987
- stats: {
988
- total: number;
989
- completed: number;
990
- progress_percentage: number;
991
- };
992
- }>> {
993
- return this.proxy('get_milestones', { task_id: taskId });
994
- }
995
-
996
- async addMilestone(taskId: string, params: {
997
- title: string;
998
- description?: string;
999
- order_index?: number;
1000
- }, sessionId?: string): Promise<ApiResponse<{
1001
- success: boolean;
1002
- milestone_id: string;
1003
- }>> {
1004
- return this.proxy('add_milestone', {
1005
- task_id: taskId,
1006
- ...params
1007
- }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1008
- }
1009
-
1010
- async updateMilestone(milestoneId: string, updates: {
1011
- title?: string;
1012
- description?: string;
1013
- status?: string;
1014
- order_index?: number;
1015
- }): Promise<ApiResponse<{
1016
- success: boolean;
1017
- milestone: {
1018
- id: string;
1019
- title: string;
1020
- status: string;
1021
- };
1022
- }>> {
1023
- return this.proxy('update_milestone', {
1024
- milestone_id: milestoneId,
1025
- ...updates
1026
- });
1027
- }
1028
-
1029
- async completeMilestone(milestoneId: string): Promise<ApiResponse<{
1030
- success: boolean;
1031
- milestone: {
1032
- id: string;
1033
- title: string;
1034
- status: string;
1035
- };
1036
- }>> {
1037
- return this.proxy('complete_milestone', { milestone_id: milestoneId });
1038
- }
1039
-
1040
- async deleteMilestone(milestoneId: string): Promise<ApiResponse<{
1041
- success: boolean;
1042
- }>> {
1043
- return this.proxy('delete_milestone', { milestone_id: milestoneId });
1044
- }
1045
-
1046
- // ============================================================================
1047
- // Request endpoints
1048
- // ============================================================================
1049
- async getPendingRequests(projectId: string, sessionId?: string, limit?: number, offset?: number): Promise<ApiResponse<{
1050
- requests: Array<{
1051
- id: string;
1052
- request_type: string;
1053
- message: string;
1054
- created_at: string;
1055
- }>;
1056
- total_count: number;
1057
- has_more: boolean;
1058
- }>> {
1059
- return this.proxy('get_pending_requests', {
1060
- project_id: projectId,
1061
- ...(limit !== undefined && { limit }),
1062
- ...(offset !== undefined && { offset }),
1063
- }, sessionId ? {
1064
- session_id: sessionId,
1065
- persona: null,
1066
- instance_id: ''
1067
- } : undefined);
1068
- }
1069
-
1070
- async acknowledgeRequest(requestId: string, sessionId?: string): Promise<ApiResponse<{
1071
- success: boolean;
1072
- }>> {
1073
- return this.proxy('acknowledge_request', { request_id: requestId }, sessionId ? {
1074
- session_id: sessionId,
1075
- persona: null,
1076
- instance_id: ''
1077
- } : undefined);
1078
- }
1079
-
1080
- async answerQuestion(requestId: string, answer: string, sessionId?: string): Promise<ApiResponse<{
1081
- success: boolean;
1082
- }>> {
1083
- return this.proxy('answer_question', {
1084
- request_id: requestId,
1085
- answer
1086
- }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1087
- }
1088
-
1089
- // ============================================================================
1090
- // Validation endpoints
1091
- // ============================================================================
1092
- async getTasksAwaitingValidation(projectId: string): Promise<ApiResponse<{
1093
- tasks: Array<{
1094
- id: string;
1095
- title: string;
1096
- completed_at?: string;
1097
- completed_by_session_id?: string;
1098
- }>;
1099
- }>> {
1100
- return this.proxy('get_tasks_awaiting_validation', { project_id: projectId });
1101
- }
1102
-
1103
- async claimValidation(taskId: string, sessionId?: string): Promise<ApiResponse<{
1104
- success: boolean;
1105
- task_id: string;
1106
- }>> {
1107
- return this.proxy('claim_validation', { task_id: taskId }, sessionId ? {
1108
- session_id: sessionId,
1109
- persona: null,
1110
- instance_id: ''
1111
- } : undefined);
1112
- }
1113
-
1114
- async validateTask(taskId: string, params: {
1115
- approved: boolean;
1116
- validation_notes?: string;
1117
- skip_pr_check?: boolean;
1118
- }, sessionId?: string): Promise<ApiResponse<{
1119
- success: boolean;
1120
- approved: boolean;
1121
- task_id: string;
1122
- message?: string;
1123
- workflow?: string;
1124
- }>> {
1125
- return this.proxy('validate_task', {
1126
- task_id: taskId,
1127
- ...params
1128
- }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1129
- }
1130
-
1131
- // ============================================================================
1132
- // Fallback activity endpoints
1133
- // ============================================================================
1134
- async startFallbackActivity(projectId: string, activity: string, sessionId?: string): Promise<ApiResponse<{
1135
- success: boolean;
1136
- activity: string;
1137
- message: string;
1138
- git_workflow?: {
1139
- workflow: string;
1140
- base_branch: string;
1141
- worktree_recommended: boolean;
1142
- note: string;
1143
- };
1144
- worktree_setup?: {
1145
- message: string;
1146
- commands: string[];
1147
- worktree_path: string;
1148
- branch_name: string;
1149
- cleanup_command: string;
1150
- report_worktree: string;
1151
- };
1152
- next_step?: string;
1153
- }>> {
1154
- return this.proxy('start_fallback_activity', {
1155
- project_id: projectId,
1156
- activity
1157
- }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1158
- }
1159
-
1160
- async stopFallbackActivity(projectId: string, summary?: string, sessionId?: string): Promise<ApiResponse<{
1161
- success: boolean;
1162
- }>> {
1163
- return this.proxy('stop_fallback_activity', {
1164
- project_id: projectId,
1165
- summary
1166
- }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1167
- }
1168
-
1169
- async getActivityHistory(projectId: string, params?: {
1170
- activity_type?: string;
1171
- limit?: number;
1172
- }): Promise<ApiResponse<{
1173
- history: Array<{
1174
- id: string;
1175
- activity_type: string;
1176
- completed_at: string;
1177
- summary?: string;
1178
- }>;
1179
- latest_by_type: Record<string, unknown>;
1180
- count: number;
1181
- }>> {
1182
- return this.proxy('get_activity_history', {
1183
- project_id: projectId,
1184
- ...params
1185
- });
1186
- }
1187
-
1188
- async getActivitySchedules(projectId: string, params?: {
1189
- limit?: number;
1190
- offset?: number;
1191
- }): Promise<ApiResponse<{
1192
- schedules: Array<{
1193
- id: string;
1194
- activity_type: string;
1195
- schedule_type: string;
1196
- next_run_at?: string;
1197
- enabled: boolean;
1198
- }>;
1199
- total_count: number;
1200
- has_more: boolean;
1201
- }>> {
1202
- return this.proxy('get_activity_schedules', {
1203
- project_id: projectId,
1204
- ...params
1205
- });
1206
- }
1207
-
1208
- // ============================================================================
1209
- // Subtask endpoints
1210
- // ============================================================================
1211
- async addSubtask(parentTaskId: string, params: {
1212
- title: string;
1213
- description?: string;
1214
- priority?: number;
1215
- estimated_minutes?: number;
1216
- }, sessionId?: string): Promise<ApiResponse<{
1217
- success: boolean;
1218
- subtask_id: string;
1219
- parent_task_id: string;
1220
- }>> {
1221
- return this.proxy('add_subtask', {
1222
- parent_task_id: parentTaskId,
1223
- ...params
1224
- }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1225
- }
1226
-
1227
- async getSubtasks(parentTaskId: string, status?: string): Promise<ApiResponse<{
1228
- subtasks: Array<{
1229
- id: string;
1230
- title: string;
1231
- description?: string;
1232
- priority: number;
1233
- status: string;
1234
- progress_percentage?: number;
1235
- estimated_minutes?: number;
1236
- }>;
1237
- stats: {
1238
- total: number;
1239
- completed: number;
1240
- progress_percentage: number;
1241
- };
1242
- }>> {
1243
- return this.proxy('get_subtasks', {
1244
- parent_task_id: parentTaskId,
1245
- status
1246
- });
1247
- }
1248
-
1249
- // ============================================================================
1250
- // Activity feed endpoint
1251
- // ============================================================================
1252
- async getActivityFeed(projectId: string, params?: {
1253
- limit?: number;
1254
- since?: string;
1255
- types?: string[];
1256
- created_by?: string;
1257
- }): Promise<ApiResponse<{
1258
- activities: Array<{
1259
- type: string;
1260
- data: unknown;
1261
- timestamp: string;
1262
- }>;
1263
- }>> {
1264
- return this.proxy('get_activity_feed', {
1265
- project_id: projectId,
1266
- ...params
1267
- });
1268
- }
1269
-
1270
- // ============================================================================
1271
- // Deployment endpoints
1272
- // ============================================================================
1273
- async requestDeployment(projectId: string, params?: {
1274
- environment?: string;
1275
- version_bump?: string;
1276
- git_ref?: string;
1277
- notes?: string;
1278
- }, sessionId?: string): Promise<ApiResponse<{
1279
- success: boolean;
1280
- deployment_id: string;
1281
- status: string;
1282
- }>> {
1283
- return this.proxy('request_deployment', {
1284
- project_id: projectId,
1285
- ...params
1286
- }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1287
- }
1288
-
1289
- async checkDeploymentStatus(projectId: string): Promise<ApiResponse<{
1290
- active_deployment: boolean;
1291
- deployment?: {
1292
- id: string;
1293
- status: string;
1294
- environment: string;
1295
- git_ref?: string;
1296
- created_at: string;
1297
- };
1298
- }>> {
1299
- return this.proxy('check_deployment_status', { project_id: projectId });
1300
- }
1301
-
1302
- async claimDeploymentValidation(projectId: string, sessionId?: string): Promise<ApiResponse<{
1303
- success: boolean;
1304
- deployment_id: string;
1305
- message: string;
1306
- }>> {
1307
- return this.proxy('claim_deployment_validation', { project_id: projectId }, sessionId ? {
1308
- session_id: sessionId,
1309
- persona: null,
1310
- instance_id: ''
1311
- } : undefined);
1312
- }
1313
-
1314
- async reportValidation(projectId: string, params: {
1315
- build_passed: boolean;
1316
- tests_passed: boolean;
1317
- error_message?: string;
1318
- }): Promise<ApiResponse<{
1319
- success: boolean;
1320
- deployment_id: string;
1321
- status: string;
1322
- }>> {
1323
- return this.proxy('report_validation', {
1324
- project_id: projectId,
1325
- ...params
1326
- });
1327
- }
1328
-
1329
- async startDeployment(projectId: string, sessionId?: string): Promise<ApiResponse<{
1330
- success: boolean;
1331
- deployment_id: string;
1332
- instructions: string;
1333
- }>> {
1334
- return this.proxy('start_deployment', { project_id: projectId }, sessionId ? {
1335
- session_id: sessionId,
1336
- persona: null,
1337
- instance_id: ''
1338
- } : undefined);
1339
- }
1340
-
1341
- async completeDeployment(projectId: string, params: {
1342
- success: boolean;
1343
- summary?: string;
1344
- }): Promise<ApiResponse<{
1345
- success: boolean;
1346
- deployment_id: string;
1347
- status: string;
1348
- }>> {
1349
- return this.proxy('complete_deployment', {
1350
- project_id: projectId,
1351
- ...params
1352
- });
1353
- }
1354
-
1355
- async cancelDeployment(projectId: string, reason?: string): Promise<ApiResponse<{
1356
- success: boolean;
1357
- }>> {
1358
- return this.proxy('cancel_deployment', {
1359
- project_id: projectId,
1360
- reason
1361
- });
1362
- }
1363
-
1364
- // ============================================================================
1365
- // Task reference endpoints
1366
- // ============================================================================
1367
- async addTaskReference(taskId: string, url: string, label?: string): Promise<ApiResponse<{
1368
- success: boolean;
1369
- reference: { url: string; label?: string };
1370
- }>> {
1371
- return this.proxy('add_task_reference', {
1372
- task_id: taskId,
1373
- url,
1374
- label
1375
- });
1376
- }
1377
-
1378
- async removeTaskReference(taskId: string, url: string): Promise<ApiResponse<{
1379
- success: boolean;
1380
- }>> {
1381
- return this.proxy('remove_task_reference', {
1382
- task_id: taskId,
1383
- url
1384
- });
1385
- }
1386
-
1387
- // ============================================================================
1388
- // Knowledge base endpoint
1389
- // ============================================================================
1390
- async queryKnowledgeBase(projectId: string, params?: {
1391
- scope?: 'summary' | 'detailed';
1392
- categories?: string[];
1393
- limit?: number;
1394
- search_query?: string;
1395
- }): Promise<ApiResponse<{
1396
- findings?: Array<{ id: string; title: string; category: string; severity: string; description?: string }>;
1397
- decisions?: Array<{ id: string; title: string; description: string; rationale?: string }>;
1398
- completed_tasks?: Array<{ id: string; title: string; completed_at: string; summary?: string }>;
1399
- resolved_blockers?: Array<{ id: string; description: string; resolution_note?: string }>;
1400
- progress?: Array<{ id: string; summary: string; details?: string }>;
1401
- qa?: Array<{ id: string; question: string; answer: string }>;
1402
- }>> {
1403
- return this.proxy('query_knowledge_base', {
1404
- project_id: projectId,
1405
- ...params
1406
- });
1407
- }
1408
-
1409
- // ============================================================================
1410
- // Session sync endpoint
1411
- // ============================================================================
1412
- async syncSession(sessionId: string, params?: {
1413
- total_tokens?: number;
1414
- token_breakdown?: Record<string, unknown>;
1415
- model_usage?: Record<string, unknown>;
1416
- }): Promise<ApiResponse<{
1417
- success: boolean;
1418
- }>> {
1419
- return this.proxy('sync_session', {
1420
- session_id: sessionId,
1421
- ...params
1422
- });
1423
- }
1424
-
1425
- /**
1426
- * Report actual API token usage for accurate cost tracking.
1427
- * This records token usage to the session and attributes cost to the current task.
1428
- */
1429
- async reportTokenUsage(sessionId: string, params: {
1430
- input_tokens: number;
1431
- output_tokens: number;
1432
- model?: 'opus' | 'sonnet' | 'haiku';
1433
- }): Promise<ApiResponse<{
1434
- success: boolean;
1435
- reported: {
1436
- session_id: string;
1437
- model: string;
1438
- input_tokens: number;
1439
- output_tokens: number;
1440
- total_tokens: number;
1441
- estimated_cost_usd: number;
1442
- };
1443
- task_attributed: boolean;
1444
- task_id?: string;
1445
- }>> {
1446
- return this.proxy('report_token_usage', {
1447
- session_id: sessionId,
1448
- ...params
1449
- });
1450
- }
1451
-
1452
- // ============================================================================
1453
- // Organization endpoints
1454
- // ============================================================================
1455
- async listOrganizations(): Promise<ApiResponse<{
1456
- organizations: Array<{
1457
- id: string;
1458
- name: string;
1459
- slug: string;
1460
- description?: string;
1461
- role: string;
1462
- }>;
1463
- }>> {
1464
- return this.proxy('list_organizations', {});
1465
- }
1466
-
1467
- async createOrganization(params: {
1468
- name: string;
1469
- slug?: string;
1470
- description?: string;
1471
- }): Promise<ApiResponse<{
1472
- success: boolean;
1473
- organization: { id: string; name: string; slug: string };
1474
- }>> {
1475
- return this.proxy('create_organization', params);
1476
- }
1477
-
1478
- async updateOrganization(organizationId: string, updates: {
1479
- name?: string;
1480
- description?: string;
1481
- logo_url?: string;
1482
- }): Promise<ApiResponse<{
1483
- success: boolean;
1484
- organization_id: string;
1485
- }>> {
1486
- return this.proxy('update_organization', {
1487
- organization_id: organizationId,
1488
- ...updates
1489
- });
1490
- }
1491
-
1492
- async deleteOrganization(organizationId: string): Promise<ApiResponse<{
1493
- success: boolean;
1494
- }>> {
1495
- return this.proxy('delete_organization', { organization_id: organizationId });
1496
- }
1497
-
1498
- async listOrgMembers(organizationId: string): Promise<ApiResponse<{
1499
- members: Array<{
1500
- user_id: string;
1501
- email: string;
1502
- role: string;
1503
- joined_at: string;
1504
- }>;
1505
- }>> {
1506
- return this.proxy('list_org_members', { organization_id: organizationId });
1507
- }
1508
-
1509
- async inviteMember(organizationId: string, email: string, role?: string): Promise<ApiResponse<{
1510
- success: boolean;
1511
- invite_id: string;
1512
- }>> {
1513
- return this.proxy('invite_member', {
1514
- organization_id: organizationId,
1515
- email,
1516
- role
1517
- });
1518
- }
1519
-
1520
- async updateMemberRole(organizationId: string, userId: string, role: string): Promise<ApiResponse<{
1521
- success: boolean;
1522
- }>> {
1523
- return this.proxy('update_member_role', {
1524
- organization_id: organizationId,
1525
- user_id: userId,
1526
- role
1527
- });
1528
- }
1529
-
1530
- async removeMember(organizationId: string, userId: string): Promise<ApiResponse<{
1531
- success: boolean;
1532
- }>> {
1533
- return this.proxy('remove_member', {
1534
- organization_id: organizationId,
1535
- user_id: userId
1536
- });
1537
- }
1538
-
1539
- async shareProjectWithOrg(projectId: string, organizationId: string, permission?: string): Promise<ApiResponse<{
1540
- success: boolean;
1541
- }>> {
1542
- return this.proxy('share_project_with_org', {
1543
- project_id: projectId,
1544
- organization_id: organizationId,
1545
- permission
1546
- });
1547
- }
1548
-
1549
- async unshareProject(projectId: string, organizationId: string): Promise<ApiResponse<{
1550
- success: boolean;
1551
- }>> {
1552
- return this.proxy('unshare_project', {
1553
- project_id: projectId,
1554
- organization_id: organizationId
1555
- });
1556
- }
1557
-
1558
- async leaveOrganization(organizationId: string): Promise<ApiResponse<{
1559
- success: boolean;
1560
- message: string;
1561
- }>> {
1562
- return this.proxy('leave_organization', { organization_id: organizationId });
1563
- }
1564
-
1565
- async updateProjectShare(projectId: string, organizationId: string, permission: string): Promise<ApiResponse<{
1566
- success: boolean;
1567
- share: { permission: string };
1568
- }>> {
1569
- return this.proxy('update_project_share', {
1570
- project_id: projectId,
1571
- organization_id: organizationId,
1572
- permission
1573
- });
1574
- }
1575
-
1576
- async listProjectShares(projectId: string): Promise<ApiResponse<{
1577
- shares: Array<{
1578
- id: string;
1579
- permission: string;
1580
- shared_at: string;
1581
- organization: { id: string; name: string; slug: string };
1582
- }>;
1583
- count: number;
1584
- }>> {
1585
- return this.proxy('list_project_shares', { project_id: projectId });
1586
- }
1587
-
1588
- // ============================================================================
1589
- // Body of work endpoints
1590
- // ============================================================================
1591
- async createBodyOfWork(projectId: string, params: {
1592
- title: string;
1593
- description?: string;
1594
- auto_deploy_on_completion?: boolean;
1595
- deploy_environment?: string;
1596
- deploy_version_bump?: string;
1597
- deploy_trigger?: string;
1598
- }): Promise<ApiResponse<{
1599
- success: boolean;
1600
- body_of_work_id: string;
1601
- }>> {
1602
- return this.proxy('create_body_of_work', {
1603
- project_id: projectId,
1604
- ...params
1605
- });
1606
- }
1607
-
1608
- async getBodyOfWork(bodyOfWorkId: string): Promise<ApiResponse<{
1609
- body_of_work: {
1610
- id: string;
1611
- title: string;
1612
- description?: string;
1613
- status: string;
1614
- auto_deploy_on_completion: boolean;
1615
- };
1616
- tasks: {
1617
- pre: Array<{ id: string; title: string; status: string }>;
1618
- core: Array<{ id: string; title: string; status: string }>;
1619
- post: Array<{ id: string; title: string; status: string }>;
1620
- };
1621
- }>> {
1622
- return this.proxy('get_body_of_work', { body_of_work_id: bodyOfWorkId });
1623
- }
1624
-
1625
- async getBodiesOfWork(projectId: string, params?: {
1626
- status?: string;
1627
- limit?: number;
1628
- offset?: number;
1629
- search_query?: string;
1630
- }): Promise<ApiResponse<{
1631
- bodies_of_work: Array<{
1632
- id: string;
1633
- title: string;
1634
- description?: string;
1635
- status: string;
1636
- task_counts: { pre: number; core: number; post: number };
1637
- }>;
1638
- }>> {
1639
- return this.proxy('get_bodies_of_work', {
1640
- project_id: projectId,
1641
- ...params
1642
- });
1643
- }
1644
-
1645
- async updateBodyOfWork(bodyOfWorkId: string, updates: {
1646
- title?: string;
1647
- description?: string;
1648
- auto_deploy_on_completion?: boolean;
1649
- deploy_environment?: string;
1650
- deploy_version_bump?: string;
1651
- deploy_trigger?: string;
1652
- }): Promise<ApiResponse<{
1653
- success: boolean;
1654
- }>> {
1655
- return this.proxy('update_body_of_work', {
1656
- body_of_work_id: bodyOfWorkId,
1657
- ...updates
1658
- });
1659
- }
1660
-
1661
- async deleteBodyOfWork(bodyOfWorkId: string): Promise<ApiResponse<{
1662
- success: boolean;
1663
- }>> {
1664
- return this.proxy('delete_body_of_work', { body_of_work_id: bodyOfWorkId });
1665
- }
1666
-
1667
- async addTaskToBodyOfWork(bodyOfWorkId: string, taskId: string, phase?: string, orderIndex?: number): Promise<ApiResponse<{
1668
- success: boolean;
1669
- }>> {
1670
- return this.proxy('add_task_to_body_of_work', {
1671
- body_of_work_id: bodyOfWorkId,
1672
- task_id: taskId,
1673
- phase,
1674
- order_index: orderIndex
1675
- });
1676
- }
1677
-
1678
- async removeTaskFromBodyOfWork(taskId: string): Promise<ApiResponse<{
1679
- success: boolean;
1680
- }>> {
1681
- return this.proxy('remove_task_from_body_of_work', { task_id: taskId });
1682
- }
1683
-
1684
- async activateBodyOfWork(bodyOfWorkId: string): Promise<ApiResponse<{
1685
- success: boolean;
1686
- status: string;
1687
- }>> {
1688
- return this.proxy('activate_body_of_work', { body_of_work_id: bodyOfWorkId });
1689
- }
1690
-
1691
- async addTaskDependency(bodyOfWorkId: string, taskId: string, dependsOnTaskId: string): Promise<ApiResponse<{
1692
- success: boolean;
1693
- }>> {
1694
- return this.proxy('add_task_dependency', {
1695
- body_of_work_id: bodyOfWorkId,
1696
- task_id: taskId,
1697
- depends_on_task_id: dependsOnTaskId
1698
- });
1699
- }
1700
-
1701
- async removeTaskDependency(taskId: string, dependsOnTaskId: string): Promise<ApiResponse<{
1702
- success: boolean;
1703
- }>> {
1704
- return this.proxy('remove_task_dependency', {
1705
- task_id: taskId,
1706
- depends_on_task_id: dependsOnTaskId
1707
- });
1708
- }
1709
-
1710
- async getTaskDependencies(params: {
1711
- body_of_work_id?: string;
1712
- task_id?: string;
1713
- }): Promise<ApiResponse<{
1714
- dependencies: Array<{
1715
- id: string;
1716
- task_id: string;
1717
- depends_on_task_id: string;
1718
- created_at: string;
1719
- }>;
1720
- }>> {
1721
- return this.proxy('get_task_dependencies', params);
1722
- }
1723
-
1724
- async getNextBodyOfWorkTask(bodyOfWorkId: string): Promise<ApiResponse<{
1725
- task?: {
1726
- id: string;
1727
- title: string;
1728
- priority: number;
1729
- phase: string;
1730
- } | null;
1731
- message?: string;
1732
- }>> {
1733
- return this.proxy('get_next_body_of_work_task', { body_of_work_id: bodyOfWorkId });
1734
- }
1735
-
1736
- // ============================================================================
1737
- // Git issues endpoints
1738
- // ============================================================================
1739
- async addGitIssue(projectId: string, params: {
1740
- issue_type: string;
1741
- branch: string;
1742
- target_branch?: string;
1743
- pr_url?: string;
1744
- conflicting_files?: string[];
1745
- error_message?: string;
1746
- task_id?: string;
1747
- }, sessionId?: string): Promise<ApiResponse<{
1748
- success: boolean;
1749
- git_issue_id: string;
1750
- }>> {
1751
- return this.proxy('add_git_issue', {
1752
- project_id: projectId,
1753
- ...params
1754
- }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1755
- }
1756
-
1757
- async resolveGitIssue(gitIssueId: string, params?: {
1758
- resolution_note?: string;
1759
- auto_resolved?: boolean;
1760
- }, sessionId?: string): Promise<ApiResponse<{
1761
- success: boolean;
1762
- git_issue_id: string;
1763
- }>> {
1764
- return this.proxy('resolve_git_issue', {
1765
- git_issue_id: gitIssueId,
1766
- ...params
1767
- }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1768
- }
1769
-
1770
- async getGitIssues(projectId: string, params?: {
1771
- status?: string;
1772
- issue_type?: string;
1773
- branch?: string;
1774
- limit?: number;
1775
- offset?: number;
1776
- }): Promise<ApiResponse<{
1777
- git_issues: Array<{
1778
- id: string;
1779
- issue_type: string;
1780
- branch: string;
1781
- target_branch?: string;
1782
- pr_url?: string;
1783
- conflicting_files?: string[];
1784
- error_message?: string;
1785
- status: string;
1786
- created_at: string;
1787
- resolved_at?: string;
1788
- }>;
1789
- }>> {
1790
- return this.proxy('get_git_issues', {
1791
- project_id: projectId,
1792
- ...params
1793
- });
1794
- }
1795
-
1796
- async deleteGitIssue(gitIssueId: string): Promise<ApiResponse<{
1797
- success: boolean;
1798
- }>> {
1799
- return this.proxy('delete_git_issue', { git_issue_id: gitIssueId });
1800
- }
1801
-
1802
- // ============================================================================
1803
- // Cost tracking endpoints
1804
- // ============================================================================
1805
- async getCostSummary(projectId: string, params?: {
1806
- period?: 'daily' | 'weekly' | 'monthly';
1807
- limit?: number;
1808
- }): Promise<ApiResponse<{
1809
- summaries: Array<{
1810
- date: string;
1811
- total_cost: number;
1812
- input_tokens: number;
1813
- output_tokens: number;
1814
- }>;
1815
- }>> {
1816
- return this.proxy('get_cost_summary', {
1817
- project_id: projectId,
1818
- ...params
1819
- });
1820
- }
1821
-
1822
- async getCostAlerts(): Promise<ApiResponse<{
1823
- alerts: Array<{
1824
- id: string;
1825
- threshold_amount: number;
1826
- threshold_period: string;
1827
- alert_type: string;
1828
- enabled: boolean;
1829
- }>;
1830
- }>> {
1831
- return this.proxy('get_cost_alerts', {});
1832
- }
1833
-
1834
- async addCostAlert(params: {
1835
- threshold_amount: number;
1836
- threshold_period: 'daily' | 'weekly' | 'monthly';
1837
- alert_type?: 'warning' | 'critical';
1838
- project_id?: string;
1839
- }): Promise<ApiResponse<{
1840
- success: boolean;
1841
- alert_id: string;
1842
- }>> {
1843
- return this.proxy('add_cost_alert', params);
1844
- }
1845
-
1846
- async updateCostAlert(alertId: string, updates: {
1847
- threshold_amount?: number;
1848
- threshold_period?: string;
1849
- alert_type?: string;
1850
- enabled?: boolean;
1851
- }): Promise<ApiResponse<{
1852
- success: boolean;
1853
- }>> {
1854
- return this.proxy('update_cost_alert', {
1855
- alert_id: alertId,
1856
- ...updates
1857
- });
1858
- }
1859
-
1860
- async deleteCostAlert(alertId: string): Promise<ApiResponse<{
1861
- success: boolean;
1862
- }>> {
1863
- return this.proxy('delete_cost_alert', { alert_id: alertId });
1864
- }
1865
-
1866
- async getTaskCosts(projectId: string, limit?: number): Promise<ApiResponse<{
1867
- task_costs: Array<{
1868
- task_id: string;
1869
- title: string;
1870
- total_cost: number;
1871
- input_tokens: number;
1872
- output_tokens: number;
1873
- }>;
1874
- }>> {
1875
- return this.proxy('get_task_costs', {
1876
- project_id: projectId,
1877
- limit
1878
- });
1879
- }
1880
-
1881
- async getBodyOfWorkCosts(params: {
1882
- body_of_work_id?: string;
1883
- project_id?: string;
1884
- }): Promise<ApiResponse<{
1885
- bodies_of_work: Array<{
1886
- body_of_work_id: string;
1887
- title: string;
1888
- project_id: string;
1889
- status: string;
1890
- task_count: number;
1891
- total_cost_usd: number;
1892
- total_tokens: number;
1893
- pre_phase_cost_usd: number;
1894
- core_phase_cost_usd: number;
1895
- post_phase_cost_usd: number;
1896
- model_breakdown: Record<string, { input: number; output: number }>;
1897
- }>;
1898
- count: number;
1899
- totals: {
1900
- total_cost_usd: number;
1901
- total_tokens: number;
1902
- total_tasks: number;
1903
- };
1904
- }>> {
1905
- return this.proxy('get_body_of_work_costs', params);
1906
- }
1907
-
1908
- async getSprintCosts(params: {
1909
- sprint_id?: string;
1910
- project_id?: string;
1911
- }): Promise<ApiResponse<{
1912
- sprints: Array<{
1913
- sprint_id: string;
1914
- title: string;
1915
- project_id: string;
1916
- status: string;
1917
- sprint_number: number;
1918
- task_count: number;
1919
- total_cost_usd: number;
1920
- total_tokens: number;
1921
- cost_per_story_point: number | null;
1922
- committed_points: number;
1923
- velocity_points: number;
1924
- model_breakdown: Record<string, { input: number; output: number }>;
1925
- }>;
1926
- count: number;
1927
- totals: {
1928
- total_cost_usd: number;
1929
- total_tokens: number;
1930
- total_tasks: number;
1931
- total_velocity_points: number;
1932
- avg_cost_per_point: number | null;
1933
- };
1934
- }>> {
1935
- return this.proxy('get_sprint_costs', params);
1936
- }
1937
-
1938
- async getTokenUsage(): Promise<ApiResponse<{
1939
- session_tokens: number;
1940
- estimated_cost: number;
1941
- }>> {
1942
- return this.proxy('get_token_usage', {});
1943
- }
1944
-
1945
- // ============================================================================
1946
- // Batch operation endpoints
1947
- // ============================================================================
1948
- async batchUpdateTasks(updates: Array<{
1949
- task_id: string;
1950
- status?: string;
1951
- priority?: number;
1952
- progress_percentage?: number;
1953
- progress_note?: string;
1954
- }>): Promise<ApiResponse<{
1955
- success: boolean;
1956
- updated_count: number;
1957
- }>> {
1958
- return this.proxy('batch_update_tasks', { updates });
1959
- }
1960
-
1961
- async batchCompleteTasks(completions: Array<{
1962
- task_id: string;
1963
- summary?: string;
1964
- }>): Promise<ApiResponse<{
1965
- success: boolean;
1966
- completed_count: number;
1967
- next_task?: { id: string; title: string } | null;
1968
- }>> {
1969
- return this.proxy('batch_complete_tasks', { completions });
1970
- }
1971
-
1972
- // ============================================================================
1973
- // Deployment requirements and scheduling endpoints
1974
- // ============================================================================
1975
- async addDeploymentRequirement(projectId: string, params: {
1976
- type: string;
1977
- title: string;
1978
- description?: string;
1979
- file_path?: string;
1980
- stage?: string;
1981
- blocking?: boolean;
1982
- recurring?: boolean;
1983
- }): Promise<ApiResponse<{
1984
- success: boolean;
1985
- requirement_id: string;
1986
- }>> {
1987
- return this.proxy('add_deployment_requirement', {
1988
- project_id: projectId,
1989
- ...params
1990
- });
1991
- }
1992
-
1993
- async getDeploymentRequirements(projectId: string, params?: {
1994
- status?: string;
1995
- stage?: string;
1996
- limit?: number;
1997
- offset?: number;
1998
- }): Promise<ApiResponse<{
1999
- requirements: Array<{
2000
- id: string;
2001
- type: string;
2002
- title: string;
2003
- description?: string;
2004
- status: string;
2005
- stage: string;
2006
- }>;
2007
- total_count: number;
2008
- has_more: boolean;
2009
- }>> {
2010
- return this.proxy('get_deployment_requirements', {
2011
- project_id: projectId,
2012
- ...params
2013
- });
2014
- }
2015
-
2016
- async getDeploymentRequirementsStats(projectId: string): Promise<ApiResponse<{
2017
- total: number;
2018
- by_status: Record<string, number>;
2019
- by_stage: Record<string, number>;
2020
- by_type: Record<string, number>;
2021
- }>> {
2022
- return this.proxy('get_deployment_requirements_stats', {
2023
- project_id: projectId
2024
- });
2025
- }
2026
-
2027
- async completeDeploymentRequirement(requirementId: string): Promise<ApiResponse<{
2028
- success: boolean;
2029
- }>> {
2030
- return this.proxy('complete_deployment_requirement', { requirement_id: requirementId });
2031
- }
2032
-
2033
- async scheduleDeployment(projectId: string, params: {
2034
- scheduled_at: string;
2035
- schedule_type?: string;
2036
- environment?: string;
2037
- version_bump?: string;
2038
- auto_trigger?: boolean;
2039
- hours_interval?: number;
2040
- notes?: string;
2041
- git_ref?: string;
2042
- }): Promise<ApiResponse<{
2043
- success: boolean;
2044
- schedule_id: string;
2045
- }>> {
2046
- return this.proxy('schedule_deployment', {
2047
- project_id: projectId,
2048
- ...params
2049
- });
2050
- }
2051
-
2052
- async getScheduledDeployments(projectId: string, params?: {
2053
- includeDisabled?: boolean;
2054
- limit?: number;
2055
- offset?: number;
2056
- }): Promise<ApiResponse<{
2057
- schedules: Array<{
2058
- id: string;
2059
- scheduled_at: string;
2060
- schedule_type: string;
2061
- hours_interval: number;
2062
- environment: string;
2063
- version_bump: string;
2064
- auto_trigger: boolean;
2065
- enabled: boolean;
2066
- git_ref?: string;
2067
- notes?: string;
2068
- }>;
2069
- total_count: number;
2070
- has_more: boolean;
2071
- }>> {
2072
- return this.proxy('get_scheduled_deployments', {
2073
- project_id: projectId,
2074
- include_disabled: params?.includeDisabled,
2075
- limit: params?.limit,
2076
- offset: params?.offset
2077
- });
2078
- }
2079
-
2080
- async updateScheduledDeployment(scheduleId: string, updates: {
2081
- scheduled_at?: string;
2082
- schedule_type?: string;
2083
- hours_interval?: number;
2084
- environment?: string;
2085
- version_bump?: string;
2086
- auto_trigger?: boolean;
2087
- enabled?: boolean;
2088
- git_ref?: string;
2089
- notes?: string;
2090
- }): Promise<ApiResponse<{
2091
- success: boolean;
2092
- schedule_id: string;
2093
- }>> {
2094
- return this.proxy('update_scheduled_deployment', {
2095
- schedule_id: scheduleId,
2096
- ...updates
2097
- });
2098
- }
2099
-
2100
- async deleteScheduledDeployment(scheduleId: string): Promise<ApiResponse<{
2101
- success: boolean;
2102
- }>> {
2103
- return this.proxy('delete_scheduled_deployment', { schedule_id: scheduleId });
2104
- }
2105
-
2106
- async triggerScheduledDeployment(scheduleId: string, sessionId?: string): Promise<ApiResponse<{
2107
- success: boolean;
2108
- deployment_id?: string;
2109
- schedule_id: string;
2110
- schedule_type: string;
2111
- next_scheduled_at?: string;
2112
- message?: string;
2113
- }>> {
2114
- return this.proxy('trigger_scheduled_deployment', { schedule_id: scheduleId }, sessionId ? {
2115
- session_id: sessionId,
2116
- persona: null,
2117
- instance_id: ''
2118
- } : undefined);
2119
- }
2120
-
2121
- async checkDueDeployments(projectId: string): Promise<ApiResponse<{
2122
- due_schedules: Array<{
2123
- id: string;
2124
- scheduled_at: string;
2125
- environment: string;
2126
- version_bump: string;
2127
- schedule_type: string;
2128
- }>;
2129
- count: number;
2130
- }>> {
2131
- return this.proxy('check_due_deployments', { project_id: projectId });
2132
- }
2133
-
2134
- // ============================================================================
2135
- // Project README endpoint
2136
- // ============================================================================
2137
- async updateProjectReadme(projectId: string, readmeContent: string): Promise<ApiResponse<{
2138
- success: boolean;
2139
- project_id: string;
2140
- }>> {
2141
- return this.proxy('update_project_readme', {
2142
- project_id: projectId,
2143
- readme_content: readmeContent
2144
- });
2145
- }
2146
-
2147
- async getProjectSummary(projectId: string): Promise<ApiResponse<{
2148
- project: {
2149
- id: string;
2150
- name: string;
2151
- description?: string;
2152
- goal?: string;
2153
- status: string;
2154
- git_url?: string;
2155
- tech_stack?: string[];
2156
- git_workflow?: string;
2157
- };
2158
- tasks: {
2159
- total: number;
2160
- by_status: Record<string, number>;
2161
- };
2162
- blockers: {
2163
- total: number;
2164
- open: number;
2165
- resolved: number;
2166
- };
2167
- findings: {
2168
- total: number;
2169
- by_severity: Record<string, number>;
2170
- by_status: Record<string, number>;
2171
- };
2172
- agents: {
2173
- active_count: number;
2174
- total_tokens_this_session: number;
2175
- total_tool_calls: number;
2176
- };
2177
- activity: {
2178
- tasks_completed_today: number;
2179
- progress_entries_today: number;
2180
- };
2181
- deployment: {
2182
- active: boolean;
2183
- status: string | null;
2184
- last_deployment_at: string | null;
2185
- };
2186
- planning: {
2187
- active_sprints: number;
2188
- active_bodies_of_work: number;
2189
- pending_deployment_requirements: number;
2190
- };
2191
- }>> {
2192
- return this.proxy('get_project_summary', { project_id: projectId });
2193
- }
2194
-
2195
- // ============================================================================
2196
- // Help Topics (database-backed)
2197
- // ============================================================================
2198
- async getHelpTopic(slug: string): Promise<ApiResponse<{
2199
- slug: string;
2200
- title: string;
2201
- content: string;
2202
- } | null>> {
2203
- return this.proxy('get_help_topic', { slug });
2204
- }
2205
-
2206
- async getHelpTopics(): Promise<ApiResponse<Array<{
2207
- slug: string;
2208
- title: string;
2209
- }>>> {
2210
- return this.proxy('get_help_topics', {});
2211
- }
2212
-
2213
- // ============================================================================
2214
- // File Checkout endpoints (multi-agent coordination)
2215
- // ============================================================================
2216
- async checkoutFile(projectId: string, filePath: string, reason?: string, sessionId?: string): Promise<ApiResponse<{
2217
- success: boolean;
2218
- checkout_id: string;
2219
- file_path: string;
2220
- already_checked_out?: boolean;
2221
- message: string;
2222
- }>> {
2223
- return this.proxy('checkout_file', {
2224
- project_id: projectId,
2225
- file_path: filePath,
2226
- reason
2227
- }, sessionId ? {
2228
- session_id: sessionId,
2229
- persona: null,
2230
- instance_id: ''
2231
- } : undefined);
2232
- }
2233
-
2234
- async checkinFile(params: {
2235
- checkout_id?: string;
2236
- project_id?: string;
2237
- file_path?: string;
2238
- summary?: string;
2239
- }, sessionId?: string): Promise<ApiResponse<{
2240
- success: boolean;
2241
- checkout_id: string;
2242
- message: string;
2243
- }>> {
2244
- return this.proxy('checkin_file', params, sessionId ? {
2245
- session_id: sessionId,
2246
- persona: null,
2247
- instance_id: ''
2248
- } : undefined);
2249
- }
2250
-
2251
- async getFileCheckouts(projectId: string, options?: {
2252
- status?: string;
2253
- file_path?: string;
2254
- limit?: number;
2255
- offset?: number;
2256
- }): Promise<ApiResponse<{
2257
- checkouts: Array<{
2258
- id: string;
2259
- file_path: string;
2260
- status: string;
2261
- checked_out_at: string;
2262
- checkout_reason?: string;
2263
- checked_in_at?: string;
2264
- checkin_summary?: string;
2265
- checked_out_by?: string;
2266
- }>;
2267
- }>> {
2268
- return this.proxy('get_file_checkouts', {
2269
- project_id: projectId,
2270
- ...options
2271
- });
2272
- }
2273
-
2274
- async abandonCheckout(params: {
2275
- checkout_id?: string;
2276
- project_id?: string;
2277
- file_path?: string;
2278
- }): Promise<ApiResponse<{
2279
- success: boolean;
2280
- checkout_id: string;
2281
- message: string;
2282
- }>> {
2283
- return this.proxy('abandon_checkout', params);
2284
- }
2285
-
2286
- async getFileCheckoutsStats(projectId: string): Promise<ApiResponse<{
2287
- total: number;
2288
- by_status: Record<string, number>;
2289
- }>> {
2290
- return this.proxy('get_file_checkouts_stats', { project_id: projectId });
2291
- }
2292
-
2293
- // ============================================================================
2294
- // Worktree Management
2295
- // ============================================================================
2296
-
2297
- async getStaleWorktrees(projectId: string, params?: {
2298
- hostname?: string;
2299
- limit?: number;
2300
- offset?: number;
2301
- }): Promise<ApiResponse<{
2302
- project_id: string;
2303
- project_name: string;
2304
- hostname_filter: string | null;
2305
- stale_worktrees: Array<{
2306
- task_id: string;
2307
- task_title: string;
2308
- worktree_path: string;
2309
- worktree_hostname: string | null;
2310
- git_branch: string | null;
2311
- status: string;
2312
- completed_at: string | null;
2313
- updated_at: string;
2314
- pr_url: string | null;
2315
- stale_reason: 'task_finished' | 'potentially_abandoned';
2316
- can_cleanup_locally: boolean;
2317
- }>;
2318
- count: number;
2319
- local_count: number;
2320
- remote_count: number;
2321
- total_count: number;
2322
- has_more: boolean;
2323
- cleanup_instructions: string[] | null;
2324
- remote_worktree_note: string | null;
2325
- }>> {
2326
- const queryParams = new URLSearchParams({ project_id: projectId });
2327
- if (params?.hostname !== undefined) queryParams.set('hostname', params.hostname);
2328
- if (params?.limit !== undefined) queryParams.set('limit', String(params.limit));
2329
- if (params?.offset !== undefined) queryParams.set('offset', String(params.offset));
2330
- return this.request('GET', `/api/mcp/worktrees/stale?${queryParams.toString()}`);
2331
- }
2332
-
2333
- async clearWorktreePath(taskId: string): Promise<ApiResponse<{
2334
- success: boolean;
2335
- task_id: string;
2336
- }>> {
2337
- return this.request('PATCH', `/api/mcp/tasks/${taskId}`, { worktree_path: null });
2338
- }
2339
-
2340
- // ============================================================================
2341
- // Connector endpoints
2342
- // ============================================================================
2343
-
2344
- async getConnectors(projectId: string, params?: {
2345
- type?: string;
2346
- status?: string;
2347
- limit?: number;
2348
- offset?: number;
2349
- }): Promise<ApiResponse<{
2350
- connectors: Array<{
2351
- id: string;
2352
- name: string;
2353
- type: string;
2354
- description?: string;
2355
- status: string;
2356
- events: Record<string, boolean>;
2357
- events_sent: number;
2358
- last_triggered_at?: string;
2359
- last_error?: string;
2360
- last_error_at?: string;
2361
- created_at: string;
2362
- }>;
2363
- total_count: number;
2364
- has_more: boolean;
2365
- }>> {
2366
- return this.proxy('get_connectors', {
2367
- project_id: projectId,
2368
- ...params
2369
- });
2370
- }
2371
-
2372
- async getConnector(connectorId: string): Promise<ApiResponse<{
2373
- connector: {
2374
- id: string;
2375
- name: string;
2376
- type: string;
2377
- description?: string;
2378
- config: Record<string, unknown>;
2379
- events: Record<string, boolean>;
2380
- status: string;
2381
- events_sent: number;
2382
- last_triggered_at?: string;
2383
- last_error?: string;
2384
- last_error_at?: string;
2385
- created_at: string;
2386
- };
2387
- }>> {
2388
- return this.proxy('get_connector', { connector_id: connectorId });
2389
- }
2390
-
2391
- async addConnector(projectId: string, params: {
2392
- name: string;
2393
- type: string;
2394
- description?: string;
2395
- config?: Record<string, unknown>;
2396
- events?: Record<string, boolean>;
2397
- }): Promise<ApiResponse<{
2398
- success: boolean;
2399
- connector_id: string;
2400
- }>> {
2401
- return this.proxy('add_connector', {
2402
- project_id: projectId,
2403
- ...params
2404
- });
2405
- }
2406
-
2407
- async updateConnector(connectorId: string, updates: {
2408
- name?: string;
2409
- description?: string;
2410
- config?: Record<string, unknown>;
2411
- events?: Record<string, boolean>;
2412
- status?: string;
2413
- }): Promise<ApiResponse<{
2414
- success: boolean;
2415
- connector_id: string;
2416
- }>> {
2417
- return this.proxy('update_connector', {
2418
- connector_id: connectorId,
2419
- ...updates
2420
- });
2421
- }
2422
-
2423
- async deleteConnector(connectorId: string): Promise<ApiResponse<{
2424
- success: boolean;
2425
- }>> {
2426
- return this.proxy('delete_connector', { connector_id: connectorId });
2427
- }
2428
-
2429
- async testConnector(connectorId: string): Promise<ApiResponse<{
2430
- success: boolean;
2431
- event_id: string;
2432
- status?: number;
2433
- error?: string;
2434
- }>> {
2435
- return this.proxy('test_connector', { connector_id: connectorId });
2436
- }
2437
-
2438
- async getConnectorEvents(params: {
2439
- connector_id?: string;
2440
- project_id?: string;
2441
- status?: string;
2442
- limit?: number;
2443
- offset?: number;
2444
- }): Promise<ApiResponse<{
2445
- events: Array<{
2446
- id: string;
2447
- connector_id: string;
2448
- event_type: string;
2449
- status: string;
2450
- response_status?: number;
2451
- error_message?: string;
2452
- attempts: number;
2453
- created_at: string;
2454
- sent_at?: string;
2455
- }>;
2456
- total_count: number;
2457
- has_more: boolean;
2458
- }>> {
2459
- return this.proxy('get_connector_events', params);
2460
- }
2461
-
2462
- // ============================================================================
2463
- // Agent onboarding endpoints
2464
- // ============================================================================
2465
-
2466
- /**
2467
- * Confirm that agent setup is complete for a project.
2468
- * This marks the agent type as onboarded so future sessions don't receive setup instructions.
2469
- */
2470
- async confirmAgentSetup(projectId: string, agentType: 'claude' | 'gemini' | 'cursor' | 'windsurf' | 'other'): Promise<ApiResponse<{
2471
- success: boolean;
2472
- project_id: string;
2473
- agent_type: string;
2474
- }>> {
2475
- return this.proxy('confirm_agent_setup', {
2476
- project_id: projectId,
2477
- agent_type: agentType
2478
- });
2479
- }
2480
- }
2481
-
2482
- // Singleton instance
2483
- let apiClient: VibescopeApiClient | null = null;
2484
-
2485
- export function getApiClient(): VibescopeApiClient {
2486
- if (!apiClient) {
2487
- const apiKey = process.env.VIBESCOPE_API_KEY;
2488
- if (!apiKey) {
2489
- throw new Error('VIBESCOPE_API_KEY environment variable is required');
2490
- }
2491
- apiClient = new VibescopeApiClient({ apiKey });
2492
- }
2493
- return apiClient;
2494
- }
2495
-
2496
- export function initApiClient(config: ApiClientConfig): VibescopeApiClient {
2497
- apiClient = new VibescopeApiClient(config);
2498
- return apiClient;
2499
- }
1
+ /**
2
+ * Vibescope API Client
3
+ *
4
+ * HTTP client for communicating with the Vibescope API.
5
+ * All database operations are handled server-side through these endpoints.
6
+ */
7
+
8
+ const DEFAULT_API_URL = 'https://vibescope.dev';
9
+
10
+ interface ApiClientConfig {
11
+ apiKey: string;
12
+ baseUrl?: string;
13
+ }
14
+
15
+ interface ApiResponse<T> {
16
+ ok: boolean;
17
+ status: number;
18
+ data?: T;
19
+ error?: string;
20
+ }
21
+
22
+ export class VibescopeApiClient {
23
+ private apiKey: string;
24
+ private baseUrl: string;
25
+
26
+ constructor(config: ApiClientConfig) {
27
+ this.apiKey = config.apiKey;
28
+ this.baseUrl = config.baseUrl || process.env.VIBESCOPE_API_URL || DEFAULT_API_URL;
29
+ }
30
+
31
+ private async request<T>(method: string, path: string, body?: unknown): Promise<ApiResponse<T>> {
32
+ const url = `${this.baseUrl}${path}`;
33
+
34
+ try {
35
+ const response = await fetch(url, {
36
+ method,
37
+ headers: {
38
+ 'Content-Type': 'application/json',
39
+ 'X-API-Key': this.apiKey
40
+ },
41
+ body: body ? JSON.stringify(body) : undefined
42
+ });
43
+
44
+ const data = await response.json();
45
+
46
+ if (!response.ok) {
47
+ return {
48
+ ok: false,
49
+ status: response.status,
50
+ error: data.error || `HTTP ${response.status}`,
51
+ data // Include full response data for additional error context
52
+ };
53
+ }
54
+
55
+ return {
56
+ ok: true,
57
+ status: response.status,
58
+ data
59
+ };
60
+ } catch (err) {
61
+ return {
62
+ ok: false,
63
+ status: 0,
64
+ error: err instanceof Error ? err.message : 'Network error'
65
+ };
66
+ }
67
+ }
68
+
69
+ // Auth endpoints
70
+ async validateAuth(): Promise<ApiResponse<{
71
+ valid: boolean;
72
+ user_id: string;
73
+ api_key_id: string;
74
+ key_name: string;
75
+ }>> {
76
+ return this.request('POST', '/api/mcp/auth/validate', {
77
+ api_key: this.apiKey
78
+ });
79
+ }
80
+
81
+ // Session endpoints
82
+ async startSession(params: {
83
+ project_id?: string;
84
+ git_url?: string;
85
+ mode?: 'lite' | 'full';
86
+ model?: 'opus' | 'sonnet' | 'haiku';
87
+ role?: 'developer' | 'validator' | 'deployer' | 'reviewer' | 'maintainer';
88
+ hostname?: string; // Machine hostname for worktree tracking
89
+ agent_type?: 'claude' | 'gemini' | 'cursor' | 'windsurf' | 'other'; // Agent type for onboarding
90
+ }): Promise<ApiResponse<{
91
+ session_started: boolean;
92
+ session_id?: string;
93
+ persona?: string;
94
+ role?: string;
95
+ project?: {
96
+ id: string;
97
+ name: string;
98
+ description?: string;
99
+ goal?: string;
100
+ status?: string;
101
+ git_url?: string;
102
+ agent_instructions?: string;
103
+ tech_stack?: string[];
104
+ git_workflow?: string;
105
+ git_main_branch?: string;
106
+ git_develop_branch?: string;
107
+ git_auto_branch?: boolean;
108
+ };
109
+ active_tasks?: Array<{
110
+ id: string;
111
+ title: string;
112
+ status: string;
113
+ priority: number;
114
+ progress_percentage?: number;
115
+ estimated_minutes?: number;
116
+ }>;
117
+ blockers?: Array<{
118
+ id: string;
119
+ description: string;
120
+ status: string;
121
+ }>;
122
+ next_task?: {
123
+ id: string;
124
+ title: string;
125
+ priority: number;
126
+ estimated_minutes?: number;
127
+ } | null;
128
+ pending_requests?: Array<{
129
+ id: string;
130
+ request_type: string;
131
+ message: string;
132
+ created_at: string;
133
+ }>;
134
+ pending_requests_count?: number;
135
+ URGENT_QUESTIONS?: {
136
+ count: number;
137
+ oldest_waiting_minutes: number;
138
+ action_required: string;
139
+ requests: Array<{
140
+ id: string;
141
+ message: string;
142
+ waiting_minutes: number;
143
+ }>;
144
+ };
145
+ directive?: string;
146
+ blockers_count?: number;
147
+ validation_count?: number;
148
+ project_not_found?: boolean;
149
+ message?: string;
150
+ suggestion?: {
151
+ action: string;
152
+ example: string;
153
+ note: string;
154
+ };
155
+ // Agent onboarding - returned when a new agent type connects to an existing project
156
+ agent_setup?: {
157
+ agent_type: string;
158
+ is_new_agent_type: boolean;
159
+ setup_required: boolean;
160
+ instructions: string;
161
+ config_file: string; // e.g., '.gemini/GEMINI.md'
162
+ template_url?: string;
163
+ steps: string[];
164
+ };
165
+ // Stale worktrees that need cleanup
166
+ stale_worktrees?: Array<{
167
+ task_id: string;
168
+ task_title: string;
169
+ worktree_path: string;
170
+ worktree_hostname?: string | null;
171
+ }>;
172
+ stale_worktrees_count?: number;
173
+ cleanup_action?: string;
174
+ // Validation info for validators
175
+ awaiting_validation?: Array<{
176
+ id: string;
177
+ title?: string;
178
+ }>;
179
+ validation_priority?: boolean;
180
+ next_action?: string;
181
+ error?: string;
182
+ }>> {
183
+ return this.request('POST', '/api/mcp/sessions/start', params);
184
+ }
185
+
186
+ async heartbeat(sessionId: string, options?: {
187
+ current_worktree_path?: string | null;
188
+ hostname?: string; // Machine hostname for worktree tracking
189
+ }): Promise<ApiResponse<{
190
+ success: boolean;
191
+ session_id: string;
192
+ timestamp: string;
193
+ }>> {
194
+ return this.request('POST', '/api/mcp/sessions/heartbeat', {
195
+ session_id: sessionId,
196
+ ...options
197
+ });
198
+ }
199
+
200
+ async endSession(sessionId: string): Promise<ApiResponse<{
201
+ success: boolean;
202
+ ended_session_id?: string;
203
+ session_summary?: {
204
+ agent_name: string;
205
+ tasks_completed_this_session: number;
206
+ tasks_awaiting_validation: number;
207
+ tasks_released: number;
208
+ };
209
+ reminders?: string[];
210
+ }>> {
211
+ return this.request('POST', '/api/mcp/sessions/end', {
212
+ session_id: sessionId
213
+ });
214
+ }
215
+
216
+ // Project endpoints
217
+ async listProjects(): Promise<ApiResponse<{
218
+ projects: Array<{
219
+ id: string;
220
+ name: string;
221
+ description?: string;
222
+ status: string;
223
+ git_url?: string;
224
+ goal?: string;
225
+ tech_stack?: string[];
226
+ }>;
227
+ }>> {
228
+ return this.request('GET', '/api/mcp/projects');
229
+ }
230
+
231
+ async createProject(params: {
232
+ name: string;
233
+ description?: string;
234
+ goal?: string;
235
+ git_url?: string;
236
+ tech_stack?: string[];
237
+ }): Promise<ApiResponse<{
238
+ success: boolean;
239
+ project: {
240
+ id: string;
241
+ name: string;
242
+ };
243
+ }>> {
244
+ return this.request('POST', '/api/mcp/projects', params);
245
+ }
246
+
247
+ async getProject(projectId: string, gitUrl?: string): Promise<ApiResponse<{
248
+ found: boolean;
249
+ project?: {
250
+ id: string;
251
+ name: string;
252
+ description?: string;
253
+ goal?: string;
254
+ status: string;
255
+ git_url?: string;
256
+ agent_instructions?: string;
257
+ tech_stack?: string[];
258
+ git_workflow?: string;
259
+ git_main_branch?: string;
260
+ git_develop_branch?: string;
261
+ git_auto_branch?: boolean;
262
+ git_auto_tag?: boolean;
263
+ deployment_instructions?: string;
264
+ };
265
+ active_tasks?: Array<{
266
+ id: string;
267
+ title: string;
268
+ description?: string;
269
+ priority: number;
270
+ status: string;
271
+ progress_percentage?: number;
272
+ estimated_minutes?: number;
273
+ }>;
274
+ open_blockers?: Array<{
275
+ id: string;
276
+ description: string;
277
+ }>;
278
+ recent_decisions?: Array<{
279
+ id: string;
280
+ title: string;
281
+ description?: string;
282
+ }>;
283
+ message?: string;
284
+ }>> {
285
+ const url = gitUrl
286
+ ? `/api/mcp/projects/${projectId}?git_url=${encodeURIComponent(gitUrl)}`
287
+ : `/api/mcp/projects/${projectId}`;
288
+ return this.request('GET', url);
289
+ }
290
+
291
+ async updateProject(projectId: string, updates: {
292
+ name?: string;
293
+ description?: string;
294
+ goal?: string;
295
+ git_url?: string;
296
+ tech_stack?: string[];
297
+ status?: string;
298
+ git_workflow?: string;
299
+ git_main_branch?: string;
300
+ git_develop_branch?: string;
301
+ git_auto_branch?: boolean;
302
+ git_auto_tag?: boolean;
303
+ deployment_instructions?: string;
304
+ agent_instructions?: string;
305
+ // New project settings columns
306
+ git_delete_branch_on_merge?: boolean;
307
+ require_pr_for_validation?: boolean;
308
+ auto_merge_on_approval?: boolean;
309
+ validation_required?: boolean;
310
+ default_task_priority?: number;
311
+ require_time_estimates?: boolean;
312
+ fallback_activities_enabled?: boolean;
313
+ preferred_fallback_activities?: string[];
314
+ }): Promise<ApiResponse<{
315
+ success: boolean;
316
+ project_id: string;
317
+ }>> {
318
+ return this.request('PATCH', `/api/mcp/projects/${projectId}`, updates);
319
+ }
320
+
321
+ // Task endpoints
322
+ async getTasks(projectId: string, params?: {
323
+ status?: string;
324
+ limit?: number;
325
+ offset?: number;
326
+ include_subtasks?: boolean;
327
+ search_query?: string;
328
+ include_metadata?: boolean; // When true, returns all task fields; when false (default), only id/title/priority/status
329
+ }): Promise<ApiResponse<{
330
+ tasks: Array<{
331
+ id: string;
332
+ title: string;
333
+ description?: string;
334
+ priority: number;
335
+ status: string;
336
+ progress_percentage?: number;
337
+ estimated_minutes?: number;
338
+ started_at?: string;
339
+ completed_at?: string;
340
+ parent_task_id?: string;
341
+ }>;
342
+ total_count: number;
343
+ has_more: boolean;
344
+ }>> {
345
+ const queryParams = new URLSearchParams();
346
+ if (params?.status) queryParams.set('status', params.status);
347
+ if (params?.limit) queryParams.set('limit', params.limit.toString());
348
+ if (params?.offset) queryParams.set('offset', params.offset.toString());
349
+ if (params?.include_subtasks) queryParams.set('include_subtasks', 'true');
350
+ if (params?.search_query) queryParams.set('search_query', params.search_query);
351
+ if (params?.include_metadata) queryParams.set('include_metadata', 'true');
352
+
353
+ const query = queryParams.toString();
354
+ const url = `/api/mcp/projects/${projectId}/tasks${query ? `?${query}` : ''}`;
355
+ return this.request('GET', url);
356
+ }
357
+
358
+ async createTask(projectId: string, params: {
359
+ title: string;
360
+ description?: string;
361
+ priority?: number;
362
+ estimated_minutes?: number;
363
+ blocking?: boolean;
364
+ session_id?: string;
365
+ task_type?: string;
366
+ }): Promise<ApiResponse<{
367
+ success: boolean;
368
+ task_id: string;
369
+ title: string;
370
+ blocking?: boolean;
371
+ message?: string;
372
+ }>> {
373
+ return this.request('POST', `/api/mcp/projects/${projectId}/tasks`, params);
374
+ }
375
+
376
+ async getNextTask(projectId: string, sessionId?: string): Promise<ApiResponse<{
377
+ task?: {
378
+ id: string;
379
+ title: string;
380
+ description?: string;
381
+ priority: number;
382
+ estimated_minutes?: number;
383
+ blocking?: boolean;
384
+ } | null;
385
+ blocking_task?: boolean;
386
+ deployment_blocks_tasks?: boolean;
387
+ deployment?: {
388
+ id: string;
389
+ status: string;
390
+ env: string;
391
+ };
392
+ awaiting_validation?: Array<{
393
+ id: string;
394
+ title: string;
395
+ }>;
396
+ validation_priority?: string;
397
+ all_claimed?: boolean;
398
+ is_subtask?: boolean;
399
+ suggested_activity?: string;
400
+ directive?: string;
401
+ message?: string;
402
+ action?: string;
403
+ }>> {
404
+ const url = sessionId
405
+ ? `/api/mcp/projects/${projectId}/next-task?session_id=${sessionId}`
406
+ : `/api/mcp/projects/${projectId}/next-task`;
407
+ return this.request('GET', url);
408
+ }
409
+
410
+ async getTask(taskId: string): Promise<ApiResponse<{
411
+ task: {
412
+ id: string;
413
+ title: string;
414
+ description?: string;
415
+ priority: number;
416
+ status: string;
417
+ progress_percentage?: number;
418
+ estimated_minutes?: number;
419
+ started_at?: string;
420
+ completed_at?: string;
421
+ git_branch?: string;
422
+ blocking?: boolean;
423
+ references?: Array<{ url: string; label?: string }>;
424
+ parent_task_id?: string;
425
+ working_agent_session_id?: string;
426
+ };
427
+ }>> {
428
+ return this.request('GET', `/api/mcp/tasks/${taskId}`);
429
+ }
430
+
431
+ /**
432
+ * Get a single task by ID with optional subtasks and milestones
433
+ */
434
+ async getTaskById(taskId: string, params?: {
435
+ include_subtasks?: boolean;
436
+ include_milestones?: boolean;
437
+ }): Promise<ApiResponse<{
438
+ task: {
439
+ id: string;
440
+ title: string;
441
+ description?: string;
442
+ priority: number;
443
+ status: string;
444
+ progress_percentage?: number;
445
+ estimated_minutes?: number;
446
+ started_at?: string;
447
+ completed_at?: string;
448
+ git_branch?: string;
449
+ references?: Array<{ url: string; label?: string }>;
450
+ };
451
+ subtasks?: Array<{
452
+ id: string;
453
+ title: string;
454
+ status: string;
455
+ progress_percentage?: number;
456
+ }>;
457
+ milestones?: Array<{
458
+ id: string;
459
+ title: string;
460
+ status: string;
461
+ order_index: number;
462
+ }>;
463
+ }>> {
464
+ return this.proxy('get_task', {
465
+ task_id: taskId,
466
+ include_subtasks: params?.include_subtasks,
467
+ include_milestones: params?.include_milestones,
468
+ });
469
+ }
470
+
471
+ /**
472
+ * Search tasks by text query with pagination
473
+ */
474
+ async searchTasks(projectId: string, params: {
475
+ query: string;
476
+ status?: string[];
477
+ limit?: number;
478
+ offset?: number;
479
+ }): Promise<ApiResponse<{
480
+ tasks: Array<{
481
+ id: string;
482
+ title: string;
483
+ status: string;
484
+ priority: number;
485
+ snippet?: string;
486
+ }>;
487
+ total_matches: number;
488
+ hint?: string;
489
+ }>> {
490
+ return this.proxy('search_tasks', {
491
+ project_id: projectId,
492
+ query: params.query,
493
+ status: params.status,
494
+ limit: params.limit,
495
+ offset: params.offset,
496
+ });
497
+ }
498
+
499
+ /**
500
+ * Get tasks filtered by priority with pagination
501
+ */
502
+ async getTasksByPriority(projectId: string, params?: {
503
+ priority?: number;
504
+ priority_max?: number;
505
+ status?: string;
506
+ limit?: number;
507
+ offset?: number;
508
+ }): Promise<ApiResponse<{
509
+ tasks: Array<{
510
+ id: string;
511
+ title: string;
512
+ priority: number;
513
+ status: string;
514
+ estimated_minutes?: number;
515
+ }>;
516
+ total_count: number;
517
+ }>> {
518
+ return this.proxy('get_tasks_by_priority', {
519
+ project_id: projectId,
520
+ priority: params?.priority,
521
+ priority_max: params?.priority_max,
522
+ status: params?.status,
523
+ limit: params?.limit,
524
+ offset: params?.offset,
525
+ });
526
+ }
527
+
528
+ /**
529
+ * Get recent tasks (newest or oldest) with pagination
530
+ */
531
+ async getRecentTasks(projectId: string, params?: {
532
+ order?: 'newest' | 'oldest';
533
+ status?: string;
534
+ limit?: number;
535
+ offset?: number;
536
+ }): Promise<ApiResponse<{
537
+ tasks: Array<{
538
+ id: string;
539
+ title: string;
540
+ status: string;
541
+ priority: number;
542
+ created_at: string;
543
+ age?: string;
544
+ }>;
545
+ total_count: number;
546
+ }>> {
547
+ return this.proxy('get_recent_tasks', {
548
+ project_id: projectId,
549
+ order: params?.order,
550
+ status: params?.status,
551
+ limit: params?.limit,
552
+ offset: params?.offset,
553
+ });
554
+ }
555
+
556
+ /**
557
+ * Get task statistics for a project
558
+ */
559
+ async getTaskStats(projectId: string): Promise<ApiResponse<{
560
+ total: number;
561
+ by_status: {
562
+ backlog: number;
563
+ pending: number;
564
+ in_progress: number;
565
+ completed: number;
566
+ cancelled: number;
567
+ };
568
+ by_priority: {
569
+ 1: number;
570
+ 2: number;
571
+ 3: number;
572
+ 4: number;
573
+ 5: number;
574
+ };
575
+ awaiting_validation: number;
576
+ oldest_pending_days: number | null;
577
+ }>> {
578
+ return this.proxy('get_task_stats', {
579
+ project_id: projectId,
580
+ });
581
+ }
582
+
583
+ async updateTask(taskId: string, updates: {
584
+ title?: string;
585
+ description?: string;
586
+ priority?: number;
587
+ status?: string;
588
+ progress_percentage?: number;
589
+ progress_note?: string;
590
+ estimated_minutes?: number;
591
+ git_branch?: string;
592
+ worktree_path?: string;
593
+ session_id?: string;
594
+ }): Promise<ApiResponse<{
595
+ success: boolean;
596
+ task_id: string;
597
+ git_workflow?: {
598
+ workflow: string;
599
+ base_branch: string;
600
+ suggested_branch: string;
601
+ worktree_required: boolean;
602
+ };
603
+ worktree_setup?: {
604
+ message: string;
605
+ commands: string[];
606
+ worktree_path: string;
607
+ branch_name: string;
608
+ cleanup_command: string;
609
+ };
610
+ next_step?: string;
611
+ }>> {
612
+ return this.request('PATCH', `/api/mcp/tasks/${taskId}`, updates);
613
+ }
614
+
615
+ async completeTask(taskId: string, params: {
616
+ summary?: string;
617
+ session_id?: string;
618
+ }): Promise<ApiResponse<{
619
+ success: boolean;
620
+ directive: string;
621
+ auto_continue: boolean;
622
+ completed_task_id: string;
623
+ next_task?: {
624
+ id: string;
625
+ title: string;
626
+ priority: number;
627
+ estimated_minutes?: number;
628
+ } | null;
629
+ context?: {
630
+ validation?: number;
631
+ blockers?: number;
632
+ deployment?: string;
633
+ };
634
+ next_action: string;
635
+ warnings?: string[];
636
+ }>> {
637
+ // Use proxy endpoint for consistency - direct endpoint had routing issues on Vercel
638
+ return this.proxy('complete_task', {
639
+ task_id: taskId,
640
+ summary: params.summary,
641
+ }, params.session_id ? { session_id: params.session_id, persona: null, instance_id: '' } : undefined);
642
+ }
643
+
644
+ async deleteTask(taskId: string): Promise<ApiResponse<{
645
+ success: boolean;
646
+ deleted_id: string;
647
+ }>> {
648
+ return this.request('DELETE', `/api/mcp/tasks/${taskId}`);
649
+ }
650
+
651
+ // Progress endpoints
652
+ async logProgress(projectId: string, params: {
653
+ summary: string;
654
+ details?: string;
655
+ task_id?: string;
656
+ session_id?: string;
657
+ }): Promise<ApiResponse<{
658
+ success: boolean;
659
+ progress_id: string;
660
+ }>> {
661
+ return this.request('POST', `/api/mcp/projects/${projectId}/progress`, params);
662
+ }
663
+
664
+ // Git workflow endpoint
665
+ async getGitWorkflow(projectId: string, taskId?: string): Promise<ApiResponse<{
666
+ workflow: string;
667
+ main_branch: string;
668
+ develop_branch?: string | null;
669
+ auto_branch?: boolean;
670
+ auto_tag?: boolean;
671
+ instructions: string[];
672
+ task?: {
673
+ id: string;
674
+ title: string;
675
+ current_branch?: string;
676
+ suggested_branch?: string | null;
677
+ };
678
+ }>> {
679
+ const url = taskId
680
+ ? `/api/mcp/projects/${projectId}/git-workflow?task_id=${taskId}`
681
+ : `/api/mcp/projects/${projectId}/git-workflow`;
682
+ return this.request('GET', url);
683
+ }
684
+
685
+ // ============================================================================
686
+ // Proxy endpoint - Generic method for all operations
687
+ // ============================================================================
688
+ async proxy<T>(operation: string, args: Record<string, unknown>, sessionContext?: {
689
+ session_id: string | null;
690
+ persona: string | null;
691
+ instance_id: string;
692
+ }): Promise<ApiResponse<T>> {
693
+ return this.request('POST', '/api/mcp/proxy', {
694
+ operation,
695
+ args,
696
+ session_context: sessionContext
697
+ });
698
+ }
699
+
700
+ // ============================================================================
701
+ // Blocker endpoints
702
+ // ============================================================================
703
+ async getBlockers(projectId: string, params?: {
704
+ status?: string;
705
+ limit?: number;
706
+ offset?: number;
707
+ search_query?: string;
708
+ }): Promise<ApiResponse<{
709
+ blockers: Array<{
710
+ id: string;
711
+ description: string;
712
+ status: string;
713
+ resolution_note?: string;
714
+ created_at: string;
715
+ resolved_at?: string;
716
+ }>;
717
+ total_count?: number;
718
+ has_more?: boolean;
719
+ }>> {
720
+ return this.proxy('get_blockers', {
721
+ project_id: projectId,
722
+ ...params
723
+ });
724
+ }
725
+
726
+ async addBlocker(projectId: string, description: string, sessionId?: string): Promise<ApiResponse<{
727
+ success: boolean;
728
+ blocker_id: string;
729
+ }>> {
730
+ return this.proxy('add_blocker', { project_id: projectId, description }, sessionId ? {
731
+ session_id: sessionId,
732
+ persona: null,
733
+ instance_id: ''
734
+ } : undefined);
735
+ }
736
+
737
+ async resolveBlocker(blockerId: string, resolutionNote?: string): Promise<ApiResponse<{
738
+ success: boolean;
739
+ blocker_id: string;
740
+ }>> {
741
+ return this.proxy('resolve_blocker', {
742
+ blocker_id: blockerId,
743
+ resolution_note: resolutionNote
744
+ });
745
+ }
746
+
747
+ async deleteBlocker(blockerId: string): Promise<ApiResponse<{
748
+ success: boolean;
749
+ }>> {
750
+ return this.proxy('delete_blocker', { blocker_id: blockerId });
751
+ }
752
+
753
+ async getBlockersStats(projectId: string): Promise<ApiResponse<{
754
+ total: number;
755
+ by_status: Record<string, number>;
756
+ }>> {
757
+ return this.proxy('get_blockers_stats', {
758
+ project_id: projectId
759
+ });
760
+ }
761
+
762
+ // ============================================================================
763
+ // Decision endpoints
764
+ // ============================================================================
765
+ async getDecisions(projectId: string, options?: {
766
+ limit?: number;
767
+ offset?: number;
768
+ search_query?: string;
769
+ }): Promise<ApiResponse<{
770
+ decisions: Array<{
771
+ id: string;
772
+ title: string;
773
+ description: string;
774
+ rationale?: string;
775
+ alternatives_considered?: string[];
776
+ created_at: string;
777
+ }>;
778
+ }>> {
779
+ return this.proxy('get_decisions', { project_id: projectId, ...options });
780
+ }
781
+
782
+ async logDecision(projectId: string, params: {
783
+ title: string;
784
+ description: string;
785
+ rationale?: string;
786
+ alternatives_considered?: string[];
787
+ }, sessionId?: string): Promise<ApiResponse<{
788
+ success: boolean;
789
+ decision_id: string;
790
+ }>> {
791
+ return this.proxy('log_decision', {
792
+ project_id: projectId,
793
+ ...params
794
+ }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
795
+ }
796
+
797
+ async deleteDecision(decisionId: string): Promise<ApiResponse<{
798
+ success: boolean;
799
+ }>> {
800
+ return this.proxy('delete_decision', { decision_id: decisionId });
801
+ }
802
+
803
+ async getDecisionsStats(projectId: string): Promise<ApiResponse<{
804
+ total: number;
805
+ }>> {
806
+ return this.proxy('get_decisions_stats', {
807
+ project_id: projectId
808
+ });
809
+ }
810
+
811
+ // ============================================================================
812
+ // Idea endpoints
813
+ // ============================================================================
814
+ async getIdeas(projectId: string, params?: {
815
+ status?: string;
816
+ limit?: number;
817
+ offset?: number;
818
+ search_query?: string;
819
+ }): Promise<ApiResponse<{
820
+ ideas: Array<{
821
+ id: string;
822
+ title: string;
823
+ description?: string;
824
+ status: string;
825
+ doc_url?: string;
826
+ created_at: string;
827
+ }>;
828
+ }>> {
829
+ return this.proxy('get_ideas', {
830
+ project_id: projectId,
831
+ ...params
832
+ });
833
+ }
834
+
835
+ async addIdea(projectId: string, params: {
836
+ title: string;
837
+ description?: string;
838
+ status?: string;
839
+ }, sessionId?: string): Promise<ApiResponse<{
840
+ success: boolean;
841
+ idea_id: string;
842
+ }>> {
843
+ return this.proxy('add_idea', {
844
+ project_id: projectId,
845
+ ...params
846
+ }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
847
+ }
848
+
849
+ async updateIdea(ideaId: string, updates: {
850
+ title?: string;
851
+ description?: string;
852
+ status?: string;
853
+ doc_url?: string;
854
+ }): Promise<ApiResponse<{
855
+ success: boolean;
856
+ idea_id: string;
857
+ }>> {
858
+ return this.proxy('update_idea', {
859
+ idea_id: ideaId,
860
+ ...updates
861
+ });
862
+ }
863
+
864
+ async deleteIdea(ideaId: string): Promise<ApiResponse<{
865
+ success: boolean;
866
+ }>> {
867
+ return this.proxy('delete_idea', { idea_id: ideaId });
868
+ }
869
+
870
+ async convertIdeaToTask(ideaId: string, params?: {
871
+ priority?: number;
872
+ estimated_minutes?: number;
873
+ update_status?: boolean;
874
+ }): Promise<ApiResponse<{
875
+ success: boolean;
876
+ task_id?: string;
877
+ task_title?: string;
878
+ idea_id?: string;
879
+ idea_status?: string;
880
+ message?: string;
881
+ error?: string;
882
+ existing_task_id?: string;
883
+ }>> {
884
+ return this.proxy('convert_idea_to_task', {
885
+ idea_id: ideaId,
886
+ ...params
887
+ });
888
+ }
889
+
890
+ // ============================================================================
891
+ // Finding endpoints
892
+ // ============================================================================
893
+ async getFindings(projectId: string, params?: {
894
+ category?: string;
895
+ severity?: string;
896
+ status?: string;
897
+ limit?: number;
898
+ offset?: number;
899
+ search_query?: string;
900
+ summary_only?: boolean;
901
+ }): Promise<ApiResponse<{
902
+ findings: Array<{
903
+ id: string;
904
+ title: string;
905
+ description?: string;
906
+ category: string;
907
+ severity: string;
908
+ status: string;
909
+ file_path?: string;
910
+ line_number?: number;
911
+ resolution_note?: string;
912
+ created_at: string;
913
+ }>;
914
+ total_count?: number;
915
+ has_more?: boolean;
916
+ }>> {
917
+ return this.proxy('get_findings', {
918
+ project_id: projectId,
919
+ ...params
920
+ });
921
+ }
922
+
923
+ async getFindingsStats(projectId: string): Promise<ApiResponse<{
924
+ total: number;
925
+ by_status: Record<string, number>;
926
+ by_severity: Record<string, number>;
927
+ by_category: Record<string, number>;
928
+ }>> {
929
+ return this.proxy('get_findings_stats', {
930
+ project_id: projectId
931
+ });
932
+ }
933
+
934
+ async addFinding(projectId: string, params: {
935
+ title: string;
936
+ description?: string;
937
+ category?: string;
938
+ severity?: string;
939
+ file_path?: string;
940
+ line_number?: number;
941
+ related_task_id?: string;
942
+ }, sessionId?: string): Promise<ApiResponse<{
943
+ success: boolean;
944
+ finding_id: string;
945
+ }>> {
946
+ return this.proxy('add_finding', {
947
+ project_id: projectId,
948
+ ...params
949
+ }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
950
+ }
951
+
952
+ async updateFinding(findingId: string, updates: {
953
+ title?: string;
954
+ description?: string;
955
+ severity?: string;
956
+ status?: string;
957
+ resolution_note?: string;
958
+ }): Promise<ApiResponse<{
959
+ success: boolean;
960
+ finding_id: string;
961
+ }>> {
962
+ return this.proxy('update_finding', {
963
+ finding_id: findingId,
964
+ ...updates
965
+ });
966
+ }
967
+
968
+ async deleteFinding(findingId: string): Promise<ApiResponse<{
969
+ success: boolean;
970
+ }>> {
971
+ return this.proxy('delete_finding', { finding_id: findingId });
972
+ }
973
+
974
+ // ============================================================================
975
+ // Milestone endpoints
976
+ // ============================================================================
977
+ async getMilestones(taskId: string): Promise<ApiResponse<{
978
+ milestones: Array<{
979
+ id: string;
980
+ title: string;
981
+ description?: string;
982
+ status: string;
983
+ order_index: number;
984
+ created_at: string;
985
+ completed_at?: string;
986
+ }>;
987
+ stats: {
988
+ total: number;
989
+ completed: number;
990
+ progress_percentage: number;
991
+ };
992
+ }>> {
993
+ return this.proxy('get_milestones', { task_id: taskId });
994
+ }
995
+
996
+ async addMilestone(taskId: string, params: {
997
+ title: string;
998
+ description?: string;
999
+ order_index?: number;
1000
+ }, sessionId?: string): Promise<ApiResponse<{
1001
+ success: boolean;
1002
+ milestone_id: string;
1003
+ }>> {
1004
+ return this.proxy('add_milestone', {
1005
+ task_id: taskId,
1006
+ ...params
1007
+ }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1008
+ }
1009
+
1010
+ async updateMilestone(milestoneId: string, updates: {
1011
+ title?: string;
1012
+ description?: string;
1013
+ status?: string;
1014
+ order_index?: number;
1015
+ }): Promise<ApiResponse<{
1016
+ success: boolean;
1017
+ milestone: {
1018
+ id: string;
1019
+ title: string;
1020
+ status: string;
1021
+ };
1022
+ }>> {
1023
+ return this.proxy('update_milestone', {
1024
+ milestone_id: milestoneId,
1025
+ ...updates
1026
+ });
1027
+ }
1028
+
1029
+ async completeMilestone(milestoneId: string): Promise<ApiResponse<{
1030
+ success: boolean;
1031
+ milestone: {
1032
+ id: string;
1033
+ title: string;
1034
+ status: string;
1035
+ };
1036
+ }>> {
1037
+ return this.proxy('complete_milestone', { milestone_id: milestoneId });
1038
+ }
1039
+
1040
+ async deleteMilestone(milestoneId: string): Promise<ApiResponse<{
1041
+ success: boolean;
1042
+ }>> {
1043
+ return this.proxy('delete_milestone', { milestone_id: milestoneId });
1044
+ }
1045
+
1046
+ // ============================================================================
1047
+ // Request endpoints
1048
+ // ============================================================================
1049
+ async getPendingRequests(projectId: string, sessionId?: string, limit?: number, offset?: number): Promise<ApiResponse<{
1050
+ requests: Array<{
1051
+ id: string;
1052
+ request_type: string;
1053
+ message: string;
1054
+ created_at: string;
1055
+ }>;
1056
+ total_count: number;
1057
+ has_more: boolean;
1058
+ }>> {
1059
+ return this.proxy('get_pending_requests', {
1060
+ project_id: projectId,
1061
+ ...(limit !== undefined && { limit }),
1062
+ ...(offset !== undefined && { offset }),
1063
+ }, sessionId ? {
1064
+ session_id: sessionId,
1065
+ persona: null,
1066
+ instance_id: ''
1067
+ } : undefined);
1068
+ }
1069
+
1070
+ async acknowledgeRequest(requestId: string, sessionId?: string): Promise<ApiResponse<{
1071
+ success: boolean;
1072
+ }>> {
1073
+ return this.proxy('acknowledge_request', { request_id: requestId }, sessionId ? {
1074
+ session_id: sessionId,
1075
+ persona: null,
1076
+ instance_id: ''
1077
+ } : undefined);
1078
+ }
1079
+
1080
+ async answerQuestion(requestId: string, answer: string, sessionId?: string): Promise<ApiResponse<{
1081
+ success: boolean;
1082
+ }>> {
1083
+ return this.proxy('answer_question', {
1084
+ request_id: requestId,
1085
+ answer
1086
+ }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1087
+ }
1088
+
1089
+ // ============================================================================
1090
+ // Validation endpoints
1091
+ // ============================================================================
1092
+ async getTasksAwaitingValidation(projectId: string): Promise<ApiResponse<{
1093
+ tasks: Array<{
1094
+ id: string;
1095
+ title: string;
1096
+ completed_at?: string;
1097
+ completed_by_session_id?: string;
1098
+ }>;
1099
+ }>> {
1100
+ return this.proxy('get_tasks_awaiting_validation', { project_id: projectId });
1101
+ }
1102
+
1103
+ async claimValidation(taskId: string, sessionId?: string): Promise<ApiResponse<{
1104
+ success: boolean;
1105
+ task_id: string;
1106
+ }>> {
1107
+ return this.proxy('claim_validation', { task_id: taskId }, sessionId ? {
1108
+ session_id: sessionId,
1109
+ persona: null,
1110
+ instance_id: ''
1111
+ } : undefined);
1112
+ }
1113
+
1114
+ async validateTask(taskId: string, params: {
1115
+ approved: boolean;
1116
+ validation_notes?: string;
1117
+ skip_pr_check?: boolean;
1118
+ }, sessionId?: string): Promise<ApiResponse<{
1119
+ success: boolean;
1120
+ approved: boolean;
1121
+ task_id: string;
1122
+ message?: string;
1123
+ workflow?: string;
1124
+ }>> {
1125
+ return this.proxy('validate_task', {
1126
+ task_id: taskId,
1127
+ ...params
1128
+ }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1129
+ }
1130
+
1131
+ // ============================================================================
1132
+ // Fallback activity endpoints
1133
+ // ============================================================================
1134
+ async startFallbackActivity(projectId: string, activity: string, sessionId?: string): Promise<ApiResponse<{
1135
+ success: boolean;
1136
+ activity: string;
1137
+ message: string;
1138
+ git_workflow?: {
1139
+ workflow: string;
1140
+ base_branch: string;
1141
+ worktree_recommended: boolean;
1142
+ note: string;
1143
+ };
1144
+ worktree_setup?: {
1145
+ message: string;
1146
+ commands: string[];
1147
+ worktree_path: string;
1148
+ branch_name: string;
1149
+ cleanup_command: string;
1150
+ report_worktree: string;
1151
+ };
1152
+ next_step?: string;
1153
+ }>> {
1154
+ return this.proxy('start_fallback_activity', {
1155
+ project_id: projectId,
1156
+ activity
1157
+ }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1158
+ }
1159
+
1160
+ async stopFallbackActivity(projectId: string, summary?: string, sessionId?: string): Promise<ApiResponse<{
1161
+ success: boolean;
1162
+ }>> {
1163
+ return this.proxy('stop_fallback_activity', {
1164
+ project_id: projectId,
1165
+ summary
1166
+ }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1167
+ }
1168
+
1169
+ async getActivityHistory(projectId: string, params?: {
1170
+ activity_type?: string;
1171
+ limit?: number;
1172
+ }): Promise<ApiResponse<{
1173
+ history: Array<{
1174
+ id: string;
1175
+ activity_type: string;
1176
+ completed_at: string;
1177
+ summary?: string;
1178
+ }>;
1179
+ latest_by_type: Record<string, unknown>;
1180
+ count: number;
1181
+ }>> {
1182
+ return this.proxy('get_activity_history', {
1183
+ project_id: projectId,
1184
+ ...params
1185
+ });
1186
+ }
1187
+
1188
+ async getActivitySchedules(projectId: string, params?: {
1189
+ limit?: number;
1190
+ offset?: number;
1191
+ }): Promise<ApiResponse<{
1192
+ schedules: Array<{
1193
+ id: string;
1194
+ activity_type: string;
1195
+ schedule_type: string;
1196
+ next_run_at?: string;
1197
+ enabled: boolean;
1198
+ }>;
1199
+ total_count: number;
1200
+ has_more: boolean;
1201
+ }>> {
1202
+ return this.proxy('get_activity_schedules', {
1203
+ project_id: projectId,
1204
+ ...params
1205
+ });
1206
+ }
1207
+
1208
+ // ============================================================================
1209
+ // Subtask endpoints
1210
+ // ============================================================================
1211
+ async addSubtask(parentTaskId: string, params: {
1212
+ title: string;
1213
+ description?: string;
1214
+ priority?: number;
1215
+ estimated_minutes?: number;
1216
+ }, sessionId?: string): Promise<ApiResponse<{
1217
+ success: boolean;
1218
+ subtask_id: string;
1219
+ parent_task_id: string;
1220
+ }>> {
1221
+ return this.proxy('add_subtask', {
1222
+ parent_task_id: parentTaskId,
1223
+ ...params
1224
+ }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1225
+ }
1226
+
1227
+ async getSubtasks(parentTaskId: string, status?: string): Promise<ApiResponse<{
1228
+ subtasks: Array<{
1229
+ id: string;
1230
+ title: string;
1231
+ description?: string;
1232
+ priority: number;
1233
+ status: string;
1234
+ progress_percentage?: number;
1235
+ estimated_minutes?: number;
1236
+ }>;
1237
+ stats: {
1238
+ total: number;
1239
+ completed: number;
1240
+ progress_percentage: number;
1241
+ };
1242
+ }>> {
1243
+ return this.proxy('get_subtasks', {
1244
+ parent_task_id: parentTaskId,
1245
+ status
1246
+ });
1247
+ }
1248
+
1249
+ // ============================================================================
1250
+ // Activity feed endpoint
1251
+ // ============================================================================
1252
+ async getActivityFeed(projectId: string, params?: {
1253
+ limit?: number;
1254
+ since?: string;
1255
+ types?: string[];
1256
+ created_by?: string;
1257
+ }): Promise<ApiResponse<{
1258
+ activities: Array<{
1259
+ type: string;
1260
+ data: unknown;
1261
+ timestamp: string;
1262
+ }>;
1263
+ }>> {
1264
+ return this.proxy('get_activity_feed', {
1265
+ project_id: projectId,
1266
+ ...params
1267
+ });
1268
+ }
1269
+
1270
+ // ============================================================================
1271
+ // Deployment endpoints
1272
+ // ============================================================================
1273
+ async requestDeployment(projectId: string, params?: {
1274
+ environment?: string;
1275
+ version_bump?: string;
1276
+ git_ref?: string;
1277
+ notes?: string;
1278
+ }, sessionId?: string): Promise<ApiResponse<{
1279
+ success: boolean;
1280
+ deployment_id: string;
1281
+ status: string;
1282
+ }>> {
1283
+ return this.proxy('request_deployment', {
1284
+ project_id: projectId,
1285
+ ...params
1286
+ }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1287
+ }
1288
+
1289
+ async checkDeploymentStatus(projectId: string): Promise<ApiResponse<{
1290
+ active_deployment: boolean;
1291
+ deployment?: {
1292
+ id: string;
1293
+ status: string;
1294
+ environment: string;
1295
+ git_ref?: string;
1296
+ created_at: string;
1297
+ };
1298
+ }>> {
1299
+ return this.proxy('check_deployment_status', { project_id: projectId });
1300
+ }
1301
+
1302
+ async claimDeploymentValidation(projectId: string, sessionId?: string): Promise<ApiResponse<{
1303
+ success: boolean;
1304
+ deployment_id: string;
1305
+ message: string;
1306
+ }>> {
1307
+ return this.proxy('claim_deployment_validation', { project_id: projectId }, sessionId ? {
1308
+ session_id: sessionId,
1309
+ persona: null,
1310
+ instance_id: ''
1311
+ } : undefined);
1312
+ }
1313
+
1314
+ async reportValidation(projectId: string, params: {
1315
+ build_passed: boolean;
1316
+ tests_passed: boolean;
1317
+ error_message?: string;
1318
+ }): Promise<ApiResponse<{
1319
+ success: boolean;
1320
+ deployment_id: string;
1321
+ status: string;
1322
+ }>> {
1323
+ return this.proxy('report_validation', {
1324
+ project_id: projectId,
1325
+ ...params
1326
+ });
1327
+ }
1328
+
1329
+ async startDeployment(projectId: string, sessionId?: string): Promise<ApiResponse<{
1330
+ success: boolean;
1331
+ deployment_id: string;
1332
+ instructions: string;
1333
+ }>> {
1334
+ return this.proxy('start_deployment', { project_id: projectId }, sessionId ? {
1335
+ session_id: sessionId,
1336
+ persona: null,
1337
+ instance_id: ''
1338
+ } : undefined);
1339
+ }
1340
+
1341
+ async completeDeployment(projectId: string, params: {
1342
+ success: boolean;
1343
+ summary?: string;
1344
+ }): Promise<ApiResponse<{
1345
+ success: boolean;
1346
+ deployment_id: string;
1347
+ status: string;
1348
+ }>> {
1349
+ return this.proxy('complete_deployment', {
1350
+ project_id: projectId,
1351
+ ...params
1352
+ });
1353
+ }
1354
+
1355
+ async cancelDeployment(projectId: string, reason?: string): Promise<ApiResponse<{
1356
+ success: boolean;
1357
+ }>> {
1358
+ return this.proxy('cancel_deployment', {
1359
+ project_id: projectId,
1360
+ reason
1361
+ });
1362
+ }
1363
+
1364
+ // ============================================================================
1365
+ // Task reference endpoints
1366
+ // ============================================================================
1367
+ async addTaskReference(taskId: string, url: string, label?: string): Promise<ApiResponse<{
1368
+ success: boolean;
1369
+ reference: { url: string; label?: string };
1370
+ }>> {
1371
+ return this.proxy('add_task_reference', {
1372
+ task_id: taskId,
1373
+ url,
1374
+ label
1375
+ });
1376
+ }
1377
+
1378
+ async removeTaskReference(taskId: string, url: string): Promise<ApiResponse<{
1379
+ success: boolean;
1380
+ }>> {
1381
+ return this.proxy('remove_task_reference', {
1382
+ task_id: taskId,
1383
+ url
1384
+ });
1385
+ }
1386
+
1387
+ // ============================================================================
1388
+ // Knowledge base endpoint
1389
+ // ============================================================================
1390
+ async queryKnowledgeBase(projectId: string, params?: {
1391
+ scope?: 'summary' | 'detailed';
1392
+ categories?: string[];
1393
+ limit?: number;
1394
+ search_query?: string;
1395
+ }): Promise<ApiResponse<{
1396
+ findings?: Array<{ id: string; title: string; category: string; severity: string; description?: string }>;
1397
+ decisions?: Array<{ id: string; title: string; description: string; rationale?: string }>;
1398
+ completed_tasks?: Array<{ id: string; title: string; completed_at: string; summary?: string }>;
1399
+ resolved_blockers?: Array<{ id: string; description: string; resolution_note?: string }>;
1400
+ progress?: Array<{ id: string; summary: string; details?: string }>;
1401
+ qa?: Array<{ id: string; question: string; answer: string }>;
1402
+ }>> {
1403
+ return this.proxy('query_knowledge_base', {
1404
+ project_id: projectId,
1405
+ ...params
1406
+ });
1407
+ }
1408
+
1409
+ // ============================================================================
1410
+ // Session sync endpoint
1411
+ // ============================================================================
1412
+ async syncSession(sessionId: string, params?: {
1413
+ total_tokens?: number;
1414
+ token_breakdown?: Record<string, unknown>;
1415
+ model_usage?: Record<string, unknown>;
1416
+ }): Promise<ApiResponse<{
1417
+ success: boolean;
1418
+ }>> {
1419
+ return this.proxy('sync_session', {
1420
+ session_id: sessionId,
1421
+ ...params
1422
+ });
1423
+ }
1424
+
1425
+ /**
1426
+ * Report actual API token usage for accurate cost tracking.
1427
+ * This records token usage to the session and attributes cost to the current task.
1428
+ */
1429
+ async reportTokenUsage(sessionId: string, params: {
1430
+ input_tokens: number;
1431
+ output_tokens: number;
1432
+ model?: 'opus' | 'sonnet' | 'haiku';
1433
+ }): Promise<ApiResponse<{
1434
+ success: boolean;
1435
+ reported: {
1436
+ session_id: string;
1437
+ model: string;
1438
+ input_tokens: number;
1439
+ output_tokens: number;
1440
+ total_tokens: number;
1441
+ estimated_cost_usd: number;
1442
+ };
1443
+ task_attributed: boolean;
1444
+ task_id?: string;
1445
+ }>> {
1446
+ return this.proxy('report_token_usage', {
1447
+ session_id: sessionId,
1448
+ ...params
1449
+ });
1450
+ }
1451
+
1452
+ // ============================================================================
1453
+ // Organization endpoints
1454
+ // ============================================================================
1455
+ async listOrganizations(): Promise<ApiResponse<{
1456
+ organizations: Array<{
1457
+ id: string;
1458
+ name: string;
1459
+ slug: string;
1460
+ description?: string;
1461
+ role: string;
1462
+ }>;
1463
+ }>> {
1464
+ return this.proxy('list_organizations', {});
1465
+ }
1466
+
1467
+ async createOrganization(params: {
1468
+ name: string;
1469
+ slug?: string;
1470
+ description?: string;
1471
+ }): Promise<ApiResponse<{
1472
+ success: boolean;
1473
+ organization: { id: string; name: string; slug: string };
1474
+ }>> {
1475
+ return this.proxy('create_organization', params);
1476
+ }
1477
+
1478
+ async updateOrganization(organizationId: string, updates: {
1479
+ name?: string;
1480
+ description?: string;
1481
+ logo_url?: string;
1482
+ }): Promise<ApiResponse<{
1483
+ success: boolean;
1484
+ organization_id: string;
1485
+ }>> {
1486
+ return this.proxy('update_organization', {
1487
+ organization_id: organizationId,
1488
+ ...updates
1489
+ });
1490
+ }
1491
+
1492
+ async deleteOrganization(organizationId: string): Promise<ApiResponse<{
1493
+ success: boolean;
1494
+ }>> {
1495
+ return this.proxy('delete_organization', { organization_id: organizationId });
1496
+ }
1497
+
1498
+ async listOrgMembers(organizationId: string): Promise<ApiResponse<{
1499
+ members: Array<{
1500
+ user_id: string;
1501
+ email: string;
1502
+ role: string;
1503
+ joined_at: string;
1504
+ }>;
1505
+ }>> {
1506
+ return this.proxy('list_org_members', { organization_id: organizationId });
1507
+ }
1508
+
1509
+ async inviteMember(organizationId: string, email: string, role?: string): Promise<ApiResponse<{
1510
+ success: boolean;
1511
+ invite_id: string;
1512
+ }>> {
1513
+ return this.proxy('invite_member', {
1514
+ organization_id: organizationId,
1515
+ email,
1516
+ role
1517
+ });
1518
+ }
1519
+
1520
+ async updateMemberRole(organizationId: string, userId: string, role: string): Promise<ApiResponse<{
1521
+ success: boolean;
1522
+ }>> {
1523
+ return this.proxy('update_member_role', {
1524
+ organization_id: organizationId,
1525
+ user_id: userId,
1526
+ role
1527
+ });
1528
+ }
1529
+
1530
+ async removeMember(organizationId: string, userId: string): Promise<ApiResponse<{
1531
+ success: boolean;
1532
+ }>> {
1533
+ return this.proxy('remove_member', {
1534
+ organization_id: organizationId,
1535
+ user_id: userId
1536
+ });
1537
+ }
1538
+
1539
+ async shareProjectWithOrg(projectId: string, organizationId: string, permission?: string): Promise<ApiResponse<{
1540
+ success: boolean;
1541
+ }>> {
1542
+ return this.proxy('share_project_with_org', {
1543
+ project_id: projectId,
1544
+ organization_id: organizationId,
1545
+ permission
1546
+ });
1547
+ }
1548
+
1549
+ async unshareProject(projectId: string, organizationId: string): Promise<ApiResponse<{
1550
+ success: boolean;
1551
+ }>> {
1552
+ return this.proxy('unshare_project', {
1553
+ project_id: projectId,
1554
+ organization_id: organizationId
1555
+ });
1556
+ }
1557
+
1558
+ async leaveOrganization(organizationId: string): Promise<ApiResponse<{
1559
+ success: boolean;
1560
+ message: string;
1561
+ }>> {
1562
+ return this.proxy('leave_organization', { organization_id: organizationId });
1563
+ }
1564
+
1565
+ async updateProjectShare(projectId: string, organizationId: string, permission: string): Promise<ApiResponse<{
1566
+ success: boolean;
1567
+ share: { permission: string };
1568
+ }>> {
1569
+ return this.proxy('update_project_share', {
1570
+ project_id: projectId,
1571
+ organization_id: organizationId,
1572
+ permission
1573
+ });
1574
+ }
1575
+
1576
+ async listProjectShares(projectId: string): Promise<ApiResponse<{
1577
+ shares: Array<{
1578
+ id: string;
1579
+ permission: string;
1580
+ shared_at: string;
1581
+ organization: { id: string; name: string; slug: string };
1582
+ }>;
1583
+ count: number;
1584
+ }>> {
1585
+ return this.proxy('list_project_shares', { project_id: projectId });
1586
+ }
1587
+
1588
+ // ============================================================================
1589
+ // Body of work endpoints
1590
+ // ============================================================================
1591
+ async createBodyOfWork(projectId: string, params: {
1592
+ title: string;
1593
+ description?: string;
1594
+ auto_deploy_on_completion?: boolean;
1595
+ deploy_environment?: string;
1596
+ deploy_version_bump?: string;
1597
+ deploy_trigger?: string;
1598
+ }): Promise<ApiResponse<{
1599
+ success: boolean;
1600
+ body_of_work_id: string;
1601
+ }>> {
1602
+ return this.proxy('create_body_of_work', {
1603
+ project_id: projectId,
1604
+ ...params
1605
+ });
1606
+ }
1607
+
1608
+ async getBodyOfWork(bodyOfWorkId: string): Promise<ApiResponse<{
1609
+ body_of_work: {
1610
+ id: string;
1611
+ title: string;
1612
+ description?: string;
1613
+ status: string;
1614
+ auto_deploy_on_completion: boolean;
1615
+ };
1616
+ tasks: {
1617
+ pre: Array<{ id: string; title: string; status: string }>;
1618
+ core: Array<{ id: string; title: string; status: string }>;
1619
+ post: Array<{ id: string; title: string; status: string }>;
1620
+ };
1621
+ }>> {
1622
+ return this.proxy('get_body_of_work', { body_of_work_id: bodyOfWorkId });
1623
+ }
1624
+
1625
+ async getBodiesOfWork(projectId: string, params?: {
1626
+ status?: string;
1627
+ limit?: number;
1628
+ offset?: number;
1629
+ search_query?: string;
1630
+ }): Promise<ApiResponse<{
1631
+ bodies_of_work: Array<{
1632
+ id: string;
1633
+ title: string;
1634
+ description?: string;
1635
+ status: string;
1636
+ task_counts: { pre: number; core: number; post: number };
1637
+ }>;
1638
+ }>> {
1639
+ return this.proxy('get_bodies_of_work', {
1640
+ project_id: projectId,
1641
+ ...params
1642
+ });
1643
+ }
1644
+
1645
+ async updateBodyOfWork(bodyOfWorkId: string, updates: {
1646
+ title?: string;
1647
+ description?: string;
1648
+ auto_deploy_on_completion?: boolean;
1649
+ deploy_environment?: string;
1650
+ deploy_version_bump?: string;
1651
+ deploy_trigger?: string;
1652
+ }): Promise<ApiResponse<{
1653
+ success: boolean;
1654
+ }>> {
1655
+ return this.proxy('update_body_of_work', {
1656
+ body_of_work_id: bodyOfWorkId,
1657
+ ...updates
1658
+ });
1659
+ }
1660
+
1661
+ async deleteBodyOfWork(bodyOfWorkId: string): Promise<ApiResponse<{
1662
+ success: boolean;
1663
+ }>> {
1664
+ return this.proxy('delete_body_of_work', { body_of_work_id: bodyOfWorkId });
1665
+ }
1666
+
1667
+ async addTaskToBodyOfWork(bodyOfWorkId: string, taskId: string, phase?: string, orderIndex?: number): Promise<ApiResponse<{
1668
+ success: boolean;
1669
+ }>> {
1670
+ return this.proxy('add_task_to_body_of_work', {
1671
+ body_of_work_id: bodyOfWorkId,
1672
+ task_id: taskId,
1673
+ phase,
1674
+ order_index: orderIndex
1675
+ });
1676
+ }
1677
+
1678
+ async removeTaskFromBodyOfWork(taskId: string): Promise<ApiResponse<{
1679
+ success: boolean;
1680
+ }>> {
1681
+ return this.proxy('remove_task_from_body_of_work', { task_id: taskId });
1682
+ }
1683
+
1684
+ async activateBodyOfWork(bodyOfWorkId: string): Promise<ApiResponse<{
1685
+ success: boolean;
1686
+ status: string;
1687
+ }>> {
1688
+ return this.proxy('activate_body_of_work', { body_of_work_id: bodyOfWorkId });
1689
+ }
1690
+
1691
+ async addTaskDependency(bodyOfWorkId: string, taskId: string, dependsOnTaskId: string): Promise<ApiResponse<{
1692
+ success: boolean;
1693
+ }>> {
1694
+ return this.proxy('add_task_dependency', {
1695
+ body_of_work_id: bodyOfWorkId,
1696
+ task_id: taskId,
1697
+ depends_on_task_id: dependsOnTaskId
1698
+ });
1699
+ }
1700
+
1701
+ async removeTaskDependency(taskId: string, dependsOnTaskId: string): Promise<ApiResponse<{
1702
+ success: boolean;
1703
+ }>> {
1704
+ return this.proxy('remove_task_dependency', {
1705
+ task_id: taskId,
1706
+ depends_on_task_id: dependsOnTaskId
1707
+ });
1708
+ }
1709
+
1710
+ async getTaskDependencies(params: {
1711
+ body_of_work_id?: string;
1712
+ task_id?: string;
1713
+ }): Promise<ApiResponse<{
1714
+ dependencies: Array<{
1715
+ id: string;
1716
+ task_id: string;
1717
+ depends_on_task_id: string;
1718
+ created_at: string;
1719
+ }>;
1720
+ }>> {
1721
+ return this.proxy('get_task_dependencies', params);
1722
+ }
1723
+
1724
+ async getNextBodyOfWorkTask(bodyOfWorkId: string): Promise<ApiResponse<{
1725
+ task?: {
1726
+ id: string;
1727
+ title: string;
1728
+ priority: number;
1729
+ phase: string;
1730
+ } | null;
1731
+ message?: string;
1732
+ }>> {
1733
+ return this.proxy('get_next_body_of_work_task', { body_of_work_id: bodyOfWorkId });
1734
+ }
1735
+
1736
+ // ============================================================================
1737
+ // Git issues endpoints
1738
+ // ============================================================================
1739
+ async addGitIssue(projectId: string, params: {
1740
+ issue_type: string;
1741
+ branch: string;
1742
+ target_branch?: string;
1743
+ pr_url?: string;
1744
+ conflicting_files?: string[];
1745
+ error_message?: string;
1746
+ task_id?: string;
1747
+ }, sessionId?: string): Promise<ApiResponse<{
1748
+ success: boolean;
1749
+ git_issue_id: string;
1750
+ }>> {
1751
+ return this.proxy('add_git_issue', {
1752
+ project_id: projectId,
1753
+ ...params
1754
+ }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1755
+ }
1756
+
1757
+ async resolveGitIssue(gitIssueId: string, params?: {
1758
+ resolution_note?: string;
1759
+ auto_resolved?: boolean;
1760
+ }, sessionId?: string): Promise<ApiResponse<{
1761
+ success: boolean;
1762
+ git_issue_id: string;
1763
+ }>> {
1764
+ return this.proxy('resolve_git_issue', {
1765
+ git_issue_id: gitIssueId,
1766
+ ...params
1767
+ }, sessionId ? { session_id: sessionId, persona: null, instance_id: '' } : undefined);
1768
+ }
1769
+
1770
+ async getGitIssues(projectId: string, params?: {
1771
+ status?: string;
1772
+ issue_type?: string;
1773
+ branch?: string;
1774
+ limit?: number;
1775
+ offset?: number;
1776
+ }): Promise<ApiResponse<{
1777
+ git_issues: Array<{
1778
+ id: string;
1779
+ issue_type: string;
1780
+ branch: string;
1781
+ target_branch?: string;
1782
+ pr_url?: string;
1783
+ conflicting_files?: string[];
1784
+ error_message?: string;
1785
+ status: string;
1786
+ created_at: string;
1787
+ resolved_at?: string;
1788
+ }>;
1789
+ }>> {
1790
+ return this.proxy('get_git_issues', {
1791
+ project_id: projectId,
1792
+ ...params
1793
+ });
1794
+ }
1795
+
1796
+ async deleteGitIssue(gitIssueId: string): Promise<ApiResponse<{
1797
+ success: boolean;
1798
+ }>> {
1799
+ return this.proxy('delete_git_issue', { git_issue_id: gitIssueId });
1800
+ }
1801
+
1802
+ // ============================================================================
1803
+ // Cost tracking endpoints
1804
+ // ============================================================================
1805
+ async getCostSummary(projectId: string, params?: {
1806
+ period?: 'daily' | 'weekly' | 'monthly';
1807
+ limit?: number;
1808
+ }): Promise<ApiResponse<{
1809
+ summaries: Array<{
1810
+ date: string;
1811
+ total_cost: number;
1812
+ input_tokens: number;
1813
+ output_tokens: number;
1814
+ }>;
1815
+ }>> {
1816
+ return this.proxy('get_cost_summary', {
1817
+ project_id: projectId,
1818
+ ...params
1819
+ });
1820
+ }
1821
+
1822
+ async getCostAlerts(): Promise<ApiResponse<{
1823
+ alerts: Array<{
1824
+ id: string;
1825
+ threshold_amount: number;
1826
+ threshold_period: string;
1827
+ alert_type: string;
1828
+ enabled: boolean;
1829
+ }>;
1830
+ }>> {
1831
+ return this.proxy('get_cost_alerts', {});
1832
+ }
1833
+
1834
+ async addCostAlert(params: {
1835
+ threshold_amount: number;
1836
+ threshold_period: 'daily' | 'weekly' | 'monthly';
1837
+ alert_type?: 'warning' | 'critical';
1838
+ project_id?: string;
1839
+ }): Promise<ApiResponse<{
1840
+ success: boolean;
1841
+ alert_id: string;
1842
+ }>> {
1843
+ return this.proxy('add_cost_alert', params);
1844
+ }
1845
+
1846
+ async updateCostAlert(alertId: string, updates: {
1847
+ threshold_amount?: number;
1848
+ threshold_period?: string;
1849
+ alert_type?: string;
1850
+ enabled?: boolean;
1851
+ }): Promise<ApiResponse<{
1852
+ success: boolean;
1853
+ }>> {
1854
+ return this.proxy('update_cost_alert', {
1855
+ alert_id: alertId,
1856
+ ...updates
1857
+ });
1858
+ }
1859
+
1860
+ async deleteCostAlert(alertId: string): Promise<ApiResponse<{
1861
+ success: boolean;
1862
+ }>> {
1863
+ return this.proxy('delete_cost_alert', { alert_id: alertId });
1864
+ }
1865
+
1866
+ async getTaskCosts(projectId: string, limit?: number): Promise<ApiResponse<{
1867
+ task_costs: Array<{
1868
+ task_id: string;
1869
+ title: string;
1870
+ total_cost: number;
1871
+ input_tokens: number;
1872
+ output_tokens: number;
1873
+ }>;
1874
+ }>> {
1875
+ return this.proxy('get_task_costs', {
1876
+ project_id: projectId,
1877
+ limit
1878
+ });
1879
+ }
1880
+
1881
+ async getBodyOfWorkCosts(params: {
1882
+ body_of_work_id?: string;
1883
+ project_id?: string;
1884
+ }): Promise<ApiResponse<{
1885
+ bodies_of_work: Array<{
1886
+ body_of_work_id: string;
1887
+ title: string;
1888
+ project_id: string;
1889
+ status: string;
1890
+ task_count: number;
1891
+ total_cost_usd: number;
1892
+ total_tokens: number;
1893
+ pre_phase_cost_usd: number;
1894
+ core_phase_cost_usd: number;
1895
+ post_phase_cost_usd: number;
1896
+ model_breakdown: Record<string, { input: number; output: number }>;
1897
+ }>;
1898
+ count: number;
1899
+ totals: {
1900
+ total_cost_usd: number;
1901
+ total_tokens: number;
1902
+ total_tasks: number;
1903
+ };
1904
+ }>> {
1905
+ return this.proxy('get_body_of_work_costs', params);
1906
+ }
1907
+
1908
+ async getSprintCosts(params: {
1909
+ sprint_id?: string;
1910
+ project_id?: string;
1911
+ }): Promise<ApiResponse<{
1912
+ sprints: Array<{
1913
+ sprint_id: string;
1914
+ title: string;
1915
+ project_id: string;
1916
+ status: string;
1917
+ sprint_number: number;
1918
+ task_count: number;
1919
+ total_cost_usd: number;
1920
+ total_tokens: number;
1921
+ cost_per_story_point: number | null;
1922
+ committed_points: number;
1923
+ velocity_points: number;
1924
+ model_breakdown: Record<string, { input: number; output: number }>;
1925
+ }>;
1926
+ count: number;
1927
+ totals: {
1928
+ total_cost_usd: number;
1929
+ total_tokens: number;
1930
+ total_tasks: number;
1931
+ total_velocity_points: number;
1932
+ avg_cost_per_point: number | null;
1933
+ };
1934
+ }>> {
1935
+ return this.proxy('get_sprint_costs', params);
1936
+ }
1937
+
1938
+ async getTokenUsage(): Promise<ApiResponse<{
1939
+ session_tokens: number;
1940
+ estimated_cost: number;
1941
+ }>> {
1942
+ return this.proxy('get_token_usage', {});
1943
+ }
1944
+
1945
+ // ============================================================================
1946
+ // Batch operation endpoints
1947
+ // ============================================================================
1948
+ async batchUpdateTasks(updates: Array<{
1949
+ task_id: string;
1950
+ status?: string;
1951
+ priority?: number;
1952
+ progress_percentage?: number;
1953
+ progress_note?: string;
1954
+ }>): Promise<ApiResponse<{
1955
+ success: boolean;
1956
+ updated_count: number;
1957
+ }>> {
1958
+ return this.proxy('batch_update_tasks', { updates });
1959
+ }
1960
+
1961
+ async batchCompleteTasks(completions: Array<{
1962
+ task_id: string;
1963
+ summary?: string;
1964
+ }>): Promise<ApiResponse<{
1965
+ success: boolean;
1966
+ completed_count: number;
1967
+ next_task?: { id: string; title: string } | null;
1968
+ }>> {
1969
+ return this.proxy('batch_complete_tasks', { completions });
1970
+ }
1971
+
1972
+ // ============================================================================
1973
+ // Deployment requirements and scheduling endpoints
1974
+ // ============================================================================
1975
+ async addDeploymentRequirement(projectId: string, params: {
1976
+ type: string;
1977
+ title: string;
1978
+ description?: string;
1979
+ file_path?: string;
1980
+ stage?: string;
1981
+ blocking?: boolean;
1982
+ recurring?: boolean;
1983
+ }): Promise<ApiResponse<{
1984
+ success: boolean;
1985
+ requirement_id: string;
1986
+ }>> {
1987
+ return this.proxy('add_deployment_requirement', {
1988
+ project_id: projectId,
1989
+ ...params
1990
+ });
1991
+ }
1992
+
1993
+ async getDeploymentRequirements(projectId: string, params?: {
1994
+ status?: string;
1995
+ stage?: string;
1996
+ limit?: number;
1997
+ offset?: number;
1998
+ }): Promise<ApiResponse<{
1999
+ requirements: Array<{
2000
+ id: string;
2001
+ type: string;
2002
+ title: string;
2003
+ description?: string;
2004
+ status: string;
2005
+ stage: string;
2006
+ }>;
2007
+ total_count: number;
2008
+ has_more: boolean;
2009
+ }>> {
2010
+ return this.proxy('get_deployment_requirements', {
2011
+ project_id: projectId,
2012
+ ...params
2013
+ });
2014
+ }
2015
+
2016
+ async getDeploymentRequirementsStats(projectId: string): Promise<ApiResponse<{
2017
+ total: number;
2018
+ by_status: Record<string, number>;
2019
+ by_stage: Record<string, number>;
2020
+ by_type: Record<string, number>;
2021
+ }>> {
2022
+ return this.proxy('get_deployment_requirements_stats', {
2023
+ project_id: projectId
2024
+ });
2025
+ }
2026
+
2027
+ async completeDeploymentRequirement(requirementId: string): Promise<ApiResponse<{
2028
+ success: boolean;
2029
+ }>> {
2030
+ return this.proxy('complete_deployment_requirement', { requirement_id: requirementId });
2031
+ }
2032
+
2033
+ async scheduleDeployment(projectId: string, params: {
2034
+ scheduled_at: string;
2035
+ schedule_type?: string;
2036
+ environment?: string;
2037
+ version_bump?: string;
2038
+ auto_trigger?: boolean;
2039
+ hours_interval?: number;
2040
+ notes?: string;
2041
+ git_ref?: string;
2042
+ }): Promise<ApiResponse<{
2043
+ success: boolean;
2044
+ schedule_id: string;
2045
+ }>> {
2046
+ return this.proxy('schedule_deployment', {
2047
+ project_id: projectId,
2048
+ ...params
2049
+ });
2050
+ }
2051
+
2052
+ async getScheduledDeployments(projectId: string, params?: {
2053
+ includeDisabled?: boolean;
2054
+ limit?: number;
2055
+ offset?: number;
2056
+ }): Promise<ApiResponse<{
2057
+ schedules: Array<{
2058
+ id: string;
2059
+ scheduled_at: string;
2060
+ schedule_type: string;
2061
+ hours_interval: number;
2062
+ environment: string;
2063
+ version_bump: string;
2064
+ auto_trigger: boolean;
2065
+ enabled: boolean;
2066
+ git_ref?: string;
2067
+ notes?: string;
2068
+ }>;
2069
+ total_count: number;
2070
+ has_more: boolean;
2071
+ }>> {
2072
+ return this.proxy('get_scheduled_deployments', {
2073
+ project_id: projectId,
2074
+ include_disabled: params?.includeDisabled,
2075
+ limit: params?.limit,
2076
+ offset: params?.offset
2077
+ });
2078
+ }
2079
+
2080
+ async updateScheduledDeployment(scheduleId: string, updates: {
2081
+ scheduled_at?: string;
2082
+ schedule_type?: string;
2083
+ hours_interval?: number;
2084
+ environment?: string;
2085
+ version_bump?: string;
2086
+ auto_trigger?: boolean;
2087
+ enabled?: boolean;
2088
+ git_ref?: string;
2089
+ notes?: string;
2090
+ }): Promise<ApiResponse<{
2091
+ success: boolean;
2092
+ schedule_id: string;
2093
+ }>> {
2094
+ return this.proxy('update_scheduled_deployment', {
2095
+ schedule_id: scheduleId,
2096
+ ...updates
2097
+ });
2098
+ }
2099
+
2100
+ async deleteScheduledDeployment(scheduleId: string): Promise<ApiResponse<{
2101
+ success: boolean;
2102
+ }>> {
2103
+ return this.proxy('delete_scheduled_deployment', { schedule_id: scheduleId });
2104
+ }
2105
+
2106
+ async triggerScheduledDeployment(scheduleId: string, sessionId?: string): Promise<ApiResponse<{
2107
+ success: boolean;
2108
+ deployment_id?: string;
2109
+ schedule_id: string;
2110
+ schedule_type: string;
2111
+ next_scheduled_at?: string;
2112
+ message?: string;
2113
+ }>> {
2114
+ return this.proxy('trigger_scheduled_deployment', { schedule_id: scheduleId }, sessionId ? {
2115
+ session_id: sessionId,
2116
+ persona: null,
2117
+ instance_id: ''
2118
+ } : undefined);
2119
+ }
2120
+
2121
+ async checkDueDeployments(projectId: string): Promise<ApiResponse<{
2122
+ due_schedules: Array<{
2123
+ id: string;
2124
+ scheduled_at: string;
2125
+ environment: string;
2126
+ version_bump: string;
2127
+ schedule_type: string;
2128
+ }>;
2129
+ count: number;
2130
+ }>> {
2131
+ return this.proxy('check_due_deployments', { project_id: projectId });
2132
+ }
2133
+
2134
+ // ============================================================================
2135
+ // Project README endpoint
2136
+ // ============================================================================
2137
+ async updateProjectReadme(projectId: string, readmeContent: string): Promise<ApiResponse<{
2138
+ success: boolean;
2139
+ project_id: string;
2140
+ }>> {
2141
+ return this.proxy('update_project_readme', {
2142
+ project_id: projectId,
2143
+ readme_content: readmeContent
2144
+ });
2145
+ }
2146
+
2147
+ async getProjectSummary(projectId: string): Promise<ApiResponse<{
2148
+ project: {
2149
+ id: string;
2150
+ name: string;
2151
+ description?: string;
2152
+ goal?: string;
2153
+ status: string;
2154
+ git_url?: string;
2155
+ tech_stack?: string[];
2156
+ git_workflow?: string;
2157
+ };
2158
+ tasks: {
2159
+ total: number;
2160
+ by_status: Record<string, number>;
2161
+ };
2162
+ blockers: {
2163
+ total: number;
2164
+ open: number;
2165
+ resolved: number;
2166
+ };
2167
+ findings: {
2168
+ total: number;
2169
+ by_severity: Record<string, number>;
2170
+ by_status: Record<string, number>;
2171
+ };
2172
+ agents: {
2173
+ active_count: number;
2174
+ total_tokens_this_session: number;
2175
+ total_tool_calls: number;
2176
+ };
2177
+ activity: {
2178
+ tasks_completed_today: number;
2179
+ progress_entries_today: number;
2180
+ };
2181
+ deployment: {
2182
+ active: boolean;
2183
+ status: string | null;
2184
+ last_deployment_at: string | null;
2185
+ };
2186
+ planning: {
2187
+ active_sprints: number;
2188
+ active_bodies_of_work: number;
2189
+ pending_deployment_requirements: number;
2190
+ };
2191
+ }>> {
2192
+ return this.proxy('get_project_summary', { project_id: projectId });
2193
+ }
2194
+
2195
+ // ============================================================================
2196
+ // Help Topics (database-backed)
2197
+ // ============================================================================
2198
+ async getHelpTopic(slug: string): Promise<ApiResponse<{
2199
+ slug: string;
2200
+ title: string;
2201
+ content: string;
2202
+ } | null>> {
2203
+ return this.proxy('get_help_topic', { slug });
2204
+ }
2205
+
2206
+ async getHelpTopics(): Promise<ApiResponse<Array<{
2207
+ slug: string;
2208
+ title: string;
2209
+ }>>> {
2210
+ return this.proxy('get_help_topics', {});
2211
+ }
2212
+
2213
+ // ============================================================================
2214
+ // File Checkout endpoints (multi-agent coordination)
2215
+ // ============================================================================
2216
+ async checkoutFile(projectId: string, filePath: string, reason?: string, sessionId?: string): Promise<ApiResponse<{
2217
+ success: boolean;
2218
+ checkout_id: string;
2219
+ file_path: string;
2220
+ already_checked_out?: boolean;
2221
+ message: string;
2222
+ }>> {
2223
+ return this.proxy('checkout_file', {
2224
+ project_id: projectId,
2225
+ file_path: filePath,
2226
+ reason
2227
+ }, sessionId ? {
2228
+ session_id: sessionId,
2229
+ persona: null,
2230
+ instance_id: ''
2231
+ } : undefined);
2232
+ }
2233
+
2234
+ async checkinFile(params: {
2235
+ checkout_id?: string;
2236
+ project_id?: string;
2237
+ file_path?: string;
2238
+ summary?: string;
2239
+ }, sessionId?: string): Promise<ApiResponse<{
2240
+ success: boolean;
2241
+ checkout_id: string;
2242
+ message: string;
2243
+ }>> {
2244
+ return this.proxy('checkin_file', params, sessionId ? {
2245
+ session_id: sessionId,
2246
+ persona: null,
2247
+ instance_id: ''
2248
+ } : undefined);
2249
+ }
2250
+
2251
+ async getFileCheckouts(projectId: string, options?: {
2252
+ status?: string;
2253
+ file_path?: string;
2254
+ limit?: number;
2255
+ offset?: number;
2256
+ }): Promise<ApiResponse<{
2257
+ checkouts: Array<{
2258
+ id: string;
2259
+ file_path: string;
2260
+ status: string;
2261
+ checked_out_at: string;
2262
+ checkout_reason?: string;
2263
+ checked_in_at?: string;
2264
+ checkin_summary?: string;
2265
+ checked_out_by?: string;
2266
+ }>;
2267
+ }>> {
2268
+ return this.proxy('get_file_checkouts', {
2269
+ project_id: projectId,
2270
+ ...options
2271
+ });
2272
+ }
2273
+
2274
+ async abandonCheckout(params: {
2275
+ checkout_id?: string;
2276
+ project_id?: string;
2277
+ file_path?: string;
2278
+ }): Promise<ApiResponse<{
2279
+ success: boolean;
2280
+ checkout_id: string;
2281
+ message: string;
2282
+ }>> {
2283
+ return this.proxy('abandon_checkout', params);
2284
+ }
2285
+
2286
+ async getFileCheckoutsStats(projectId: string): Promise<ApiResponse<{
2287
+ total: number;
2288
+ by_status: Record<string, number>;
2289
+ }>> {
2290
+ return this.proxy('get_file_checkouts_stats', { project_id: projectId });
2291
+ }
2292
+
2293
+ // ============================================================================
2294
+ // Worktree Management
2295
+ // ============================================================================
2296
+
2297
+ async getStaleWorktrees(projectId: string, params?: {
2298
+ hostname?: string;
2299
+ limit?: number;
2300
+ offset?: number;
2301
+ }): Promise<ApiResponse<{
2302
+ project_id: string;
2303
+ project_name: string;
2304
+ hostname_filter: string | null;
2305
+ stale_worktrees: Array<{
2306
+ task_id: string;
2307
+ task_title: string;
2308
+ worktree_path: string;
2309
+ worktree_hostname: string | null;
2310
+ git_branch: string | null;
2311
+ status: string;
2312
+ completed_at: string | null;
2313
+ updated_at: string;
2314
+ pr_url: string | null;
2315
+ stale_reason: 'task_finished' | 'potentially_abandoned';
2316
+ can_cleanup_locally: boolean;
2317
+ }>;
2318
+ count: number;
2319
+ local_count: number;
2320
+ remote_count: number;
2321
+ total_count: number;
2322
+ has_more: boolean;
2323
+ cleanup_instructions: string[] | null;
2324
+ remote_worktree_note: string | null;
2325
+ }>> {
2326
+ const queryParams = new URLSearchParams({ project_id: projectId });
2327
+ if (params?.hostname !== undefined) queryParams.set('hostname', params.hostname);
2328
+ if (params?.limit !== undefined) queryParams.set('limit', String(params.limit));
2329
+ if (params?.offset !== undefined) queryParams.set('offset', String(params.offset));
2330
+ return this.request('GET', `/api/mcp/worktrees/stale?${queryParams.toString()}`);
2331
+ }
2332
+
2333
+ async clearWorktreePath(taskId: string): Promise<ApiResponse<{
2334
+ success: boolean;
2335
+ task_id: string;
2336
+ }>> {
2337
+ return this.request('PATCH', `/api/mcp/tasks/${taskId}`, { worktree_path: null });
2338
+ }
2339
+
2340
+ // ============================================================================
2341
+ // Connector endpoints
2342
+ // ============================================================================
2343
+
2344
+ async getConnectors(projectId: string, params?: {
2345
+ type?: string;
2346
+ status?: string;
2347
+ limit?: number;
2348
+ offset?: number;
2349
+ }): Promise<ApiResponse<{
2350
+ connectors: Array<{
2351
+ id: string;
2352
+ name: string;
2353
+ type: string;
2354
+ description?: string;
2355
+ status: string;
2356
+ events: Record<string, boolean>;
2357
+ events_sent: number;
2358
+ last_triggered_at?: string;
2359
+ last_error?: string;
2360
+ last_error_at?: string;
2361
+ created_at: string;
2362
+ }>;
2363
+ total_count: number;
2364
+ has_more: boolean;
2365
+ }>> {
2366
+ return this.proxy('get_connectors', {
2367
+ project_id: projectId,
2368
+ ...params
2369
+ });
2370
+ }
2371
+
2372
+ async getConnector(connectorId: string): Promise<ApiResponse<{
2373
+ connector: {
2374
+ id: string;
2375
+ name: string;
2376
+ type: string;
2377
+ description?: string;
2378
+ config: Record<string, unknown>;
2379
+ events: Record<string, boolean>;
2380
+ status: string;
2381
+ events_sent: number;
2382
+ last_triggered_at?: string;
2383
+ last_error?: string;
2384
+ last_error_at?: string;
2385
+ created_at: string;
2386
+ };
2387
+ }>> {
2388
+ return this.proxy('get_connector', { connector_id: connectorId });
2389
+ }
2390
+
2391
+ async addConnector(projectId: string, params: {
2392
+ name: string;
2393
+ type: string;
2394
+ description?: string;
2395
+ config?: Record<string, unknown>;
2396
+ events?: Record<string, boolean>;
2397
+ }): Promise<ApiResponse<{
2398
+ success: boolean;
2399
+ connector_id: string;
2400
+ }>> {
2401
+ return this.proxy('add_connector', {
2402
+ project_id: projectId,
2403
+ ...params
2404
+ });
2405
+ }
2406
+
2407
+ async updateConnector(connectorId: string, updates: {
2408
+ name?: string;
2409
+ description?: string;
2410
+ config?: Record<string, unknown>;
2411
+ events?: Record<string, boolean>;
2412
+ status?: string;
2413
+ }): Promise<ApiResponse<{
2414
+ success: boolean;
2415
+ connector_id: string;
2416
+ }>> {
2417
+ return this.proxy('update_connector', {
2418
+ connector_id: connectorId,
2419
+ ...updates
2420
+ });
2421
+ }
2422
+
2423
+ async deleteConnector(connectorId: string): Promise<ApiResponse<{
2424
+ success: boolean;
2425
+ }>> {
2426
+ return this.proxy('delete_connector', { connector_id: connectorId });
2427
+ }
2428
+
2429
+ async testConnector(connectorId: string): Promise<ApiResponse<{
2430
+ success: boolean;
2431
+ event_id: string;
2432
+ status?: number;
2433
+ error?: string;
2434
+ }>> {
2435
+ return this.proxy('test_connector', { connector_id: connectorId });
2436
+ }
2437
+
2438
+ async getConnectorEvents(params: {
2439
+ connector_id?: string;
2440
+ project_id?: string;
2441
+ status?: string;
2442
+ limit?: number;
2443
+ offset?: number;
2444
+ }): Promise<ApiResponse<{
2445
+ events: Array<{
2446
+ id: string;
2447
+ connector_id: string;
2448
+ event_type: string;
2449
+ status: string;
2450
+ response_status?: number;
2451
+ error_message?: string;
2452
+ attempts: number;
2453
+ created_at: string;
2454
+ sent_at?: string;
2455
+ }>;
2456
+ total_count: number;
2457
+ has_more: boolean;
2458
+ }>> {
2459
+ return this.proxy('get_connector_events', params);
2460
+ }
2461
+
2462
+ // ============================================================================
2463
+ // Agent onboarding endpoints
2464
+ // ============================================================================
2465
+
2466
+ /**
2467
+ * Confirm that agent setup is complete for a project.
2468
+ * This marks the agent type as onboarded so future sessions don't receive setup instructions.
2469
+ */
2470
+ async confirmAgentSetup(projectId: string, agentType: 'claude' | 'gemini' | 'cursor' | 'windsurf' | 'other'): Promise<ApiResponse<{
2471
+ success: boolean;
2472
+ project_id: string;
2473
+ agent_type: string;
2474
+ }>> {
2475
+ return this.proxy('confirm_agent_setup', {
2476
+ project_id: projectId,
2477
+ agent_type: agentType
2478
+ });
2479
+ }
2480
+ }
2481
+
2482
+ // Singleton instance
2483
+ let apiClient: VibescopeApiClient | null = null;
2484
+
2485
+ export function getApiClient(): VibescopeApiClient {
2486
+ if (!apiClient) {
2487
+ const apiKey = process.env.VIBESCOPE_API_KEY;
2488
+ if (!apiKey) {
2489
+ throw new Error('VIBESCOPE_API_KEY environment variable is required');
2490
+ }
2491
+ apiClient = new VibescopeApiClient({ apiKey });
2492
+ }
2493
+ return apiClient;
2494
+ }
2495
+
2496
+ export function initApiClient(config: ApiClientConfig): VibescopeApiClient {
2497
+ apiClient = new VibescopeApiClient(config);
2498
+ return apiClient;
2499
+ }