@vibescope/mcp-server 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +84 -0
- package/README.md +35 -20
- package/dist/api-client.d.ts +276 -8
- package/dist/api-client.js +128 -9
- package/dist/handlers/blockers.d.ts +11 -0
- package/dist/handlers/blockers.js +37 -2
- package/dist/handlers/bodies-of-work.d.ts +2 -0
- package/dist/handlers/bodies-of-work.js +30 -1
- package/dist/handlers/connectors.js +2 -2
- package/dist/handlers/decisions.d.ts +11 -0
- package/dist/handlers/decisions.js +37 -2
- package/dist/handlers/deployment.d.ts +6 -0
- package/dist/handlers/deployment.js +33 -5
- package/dist/handlers/discovery.js +27 -11
- package/dist/handlers/fallback.js +12 -6
- package/dist/handlers/file-checkouts.d.ts +1 -0
- package/dist/handlers/file-checkouts.js +17 -2
- package/dist/handlers/findings.d.ts +5 -0
- package/dist/handlers/findings.js +19 -2
- package/dist/handlers/git-issues.js +4 -2
- package/dist/handlers/ideas.d.ts +5 -0
- package/dist/handlers/ideas.js +19 -2
- package/dist/handlers/progress.js +2 -2
- package/dist/handlers/project.d.ts +1 -0
- package/dist/handlers/project.js +35 -2
- package/dist/handlers/requests.js +6 -3
- package/dist/handlers/roles.js +13 -2
- package/dist/handlers/session.d.ts +12 -0
- package/dist/handlers/session.js +288 -25
- package/dist/handlers/sprints.d.ts +2 -0
- package/dist/handlers/sprints.js +30 -1
- package/dist/handlers/tasks.d.ts +25 -2
- package/dist/handlers/tasks.js +228 -35
- package/dist/handlers/tool-docs.js +72 -5
- package/dist/templates/agent-guidelines.d.ts +18 -0
- package/dist/templates/agent-guidelines.js +207 -0
- package/dist/tools.js +478 -125
- package/dist/utils.d.ts +5 -2
- package/dist/utils.js +90 -51
- package/package.json +51 -46
- package/scripts/version-bump.ts +203 -0
- package/src/api-client.test.ts +8 -3
- package/src/api-client.ts +376 -13
- package/src/handlers/__test-setup__.ts +5 -0
- package/src/handlers/blockers.test.ts +76 -0
- package/src/handlers/blockers.ts +56 -2
- package/src/handlers/bodies-of-work.ts +59 -1
- package/src/handlers/connectors.ts +2 -2
- package/src/handlers/decisions.test.ts +71 -2
- package/src/handlers/decisions.ts +56 -2
- package/src/handlers/deployment.test.ts +81 -0
- package/src/handlers/deployment.ts +38 -5
- package/src/handlers/discovery.ts +27 -11
- package/src/handlers/fallback.test.ts +11 -10
- package/src/handlers/fallback.ts +14 -8
- package/src/handlers/file-checkouts.test.ts +83 -3
- package/src/handlers/file-checkouts.ts +22 -2
- package/src/handlers/findings.test.ts +2 -2
- package/src/handlers/findings.ts +38 -2
- package/src/handlers/git-issues.test.ts +2 -2
- package/src/handlers/git-issues.ts +4 -2
- package/src/handlers/ideas.test.ts +1 -1
- package/src/handlers/ideas.ts +34 -2
- package/src/handlers/progress.ts +2 -2
- package/src/handlers/project.ts +47 -2
- package/src/handlers/requests.test.ts +38 -7
- package/src/handlers/requests.ts +6 -3
- package/src/handlers/roles.test.ts +1 -1
- package/src/handlers/roles.ts +20 -2
- package/src/handlers/session.test.ts +303 -4
- package/src/handlers/session.ts +335 -28
- package/src/handlers/sprints.ts +61 -1
- package/src/handlers/tasks.test.ts +0 -73
- package/src/handlers/tasks.ts +269 -40
- package/src/handlers/tool-docs.ts +77 -5
- package/src/handlers/types.test.ts +259 -0
- package/src/templates/agent-guidelines.ts +210 -0
- package/src/tools.ts +479 -125
- package/src/utils.test.ts +7 -5
- package/src/utils.ts +95 -51
package/src/api-client.ts
CHANGED
|
@@ -85,6 +85,8 @@ export class VibescopeApiClient {
|
|
|
85
85
|
mode?: 'lite' | 'full';
|
|
86
86
|
model?: 'opus' | 'sonnet' | 'haiku';
|
|
87
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
|
|
88
90
|
}): Promise<ApiResponse<{
|
|
89
91
|
session_started: boolean;
|
|
90
92
|
session_id?: string;
|
|
@@ -150,6 +152,32 @@ export class VibescopeApiClient {
|
|
|
150
152
|
example: string;
|
|
151
153
|
note: string;
|
|
152
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;
|
|
153
181
|
error?: string;
|
|
154
182
|
}>> {
|
|
155
183
|
return this.request('POST', '/api/mcp/sessions/start', params);
|
|
@@ -157,6 +185,7 @@ export class VibescopeApiClient {
|
|
|
157
185
|
|
|
158
186
|
async heartbeat(sessionId: string, options?: {
|
|
159
187
|
current_worktree_path?: string | null;
|
|
188
|
+
hostname?: string; // Machine hostname for worktree tracking
|
|
160
189
|
}): Promise<ApiResponse<{
|
|
161
190
|
success: boolean;
|
|
162
191
|
session_id: string;
|
|
@@ -273,6 +302,15 @@ export class VibescopeApiClient {
|
|
|
273
302
|
git_auto_tag?: boolean;
|
|
274
303
|
deployment_instructions?: string;
|
|
275
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[];
|
|
276
314
|
}): Promise<ApiResponse<{
|
|
277
315
|
success: boolean;
|
|
278
316
|
project_id: string;
|
|
@@ -390,6 +428,158 @@ export class VibescopeApiClient {
|
|
|
390
428
|
return this.request('GET', `/api/mcp/tasks/${taskId}`);
|
|
391
429
|
}
|
|
392
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
|
+
|
|
393
583
|
async updateTask(taskId: string, updates: {
|
|
394
584
|
title?: string;
|
|
395
585
|
description?: string;
|
|
@@ -444,7 +634,11 @@ export class VibescopeApiClient {
|
|
|
444
634
|
next_action: string;
|
|
445
635
|
warnings?: string[];
|
|
446
636
|
}>> {
|
|
447
|
-
|
|
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);
|
|
448
642
|
}
|
|
449
643
|
|
|
450
644
|
async deleteTask(taskId: string): Promise<ApiResponse<{
|
|
@@ -556,6 +750,15 @@ export class VibescopeApiClient {
|
|
|
556
750
|
return this.proxy('delete_blocker', { blocker_id: blockerId });
|
|
557
751
|
}
|
|
558
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
|
+
|
|
559
762
|
// ============================================================================
|
|
560
763
|
// Decision endpoints
|
|
561
764
|
// ============================================================================
|
|
@@ -597,6 +800,14 @@ export class VibescopeApiClient {
|
|
|
597
800
|
return this.proxy('delete_decision', { decision_id: decisionId });
|
|
598
801
|
}
|
|
599
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
|
+
|
|
600
811
|
// ============================================================================
|
|
601
812
|
// Idea endpoints
|
|
602
813
|
// ============================================================================
|
|
@@ -835,15 +1046,21 @@ export class VibescopeApiClient {
|
|
|
835
1046
|
// ============================================================================
|
|
836
1047
|
// Request endpoints
|
|
837
1048
|
// ============================================================================
|
|
838
|
-
async getPendingRequests(projectId: string, sessionId?: string): Promise<ApiResponse<{
|
|
1049
|
+
async getPendingRequests(projectId: string, sessionId?: string, limit?: number, offset?: number): Promise<ApiResponse<{
|
|
839
1050
|
requests: Array<{
|
|
840
1051
|
id: string;
|
|
841
1052
|
request_type: string;
|
|
842
1053
|
message: string;
|
|
843
1054
|
created_at: string;
|
|
844
1055
|
}>;
|
|
1056
|
+
total_count: number;
|
|
1057
|
+
has_more: boolean;
|
|
845
1058
|
}>> {
|
|
846
|
-
return this.proxy('get_pending_requests', {
|
|
1059
|
+
return this.proxy('get_pending_requests', {
|
|
1060
|
+
project_id: projectId,
|
|
1061
|
+
...(limit !== undefined && { limit }),
|
|
1062
|
+
...(offset !== undefined && { offset }),
|
|
1063
|
+
}, sessionId ? {
|
|
847
1064
|
session_id: sessionId,
|
|
848
1065
|
persona: null,
|
|
849
1066
|
instance_id: ''
|
|
@@ -968,7 +1185,10 @@ export class VibescopeApiClient {
|
|
|
968
1185
|
});
|
|
969
1186
|
}
|
|
970
1187
|
|
|
971
|
-
async getActivitySchedules(projectId: string
|
|
1188
|
+
async getActivitySchedules(projectId: string, params?: {
|
|
1189
|
+
limit?: number;
|
|
1190
|
+
offset?: number;
|
|
1191
|
+
}): Promise<ApiResponse<{
|
|
972
1192
|
schedules: Array<{
|
|
973
1193
|
id: string;
|
|
974
1194
|
activity_type: string;
|
|
@@ -976,10 +1196,13 @@ export class VibescopeApiClient {
|
|
|
976
1196
|
next_run_at?: string;
|
|
977
1197
|
enabled: boolean;
|
|
978
1198
|
}>;
|
|
979
|
-
|
|
980
|
-
|
|
1199
|
+
total_count: number;
|
|
1200
|
+
has_more: boolean;
|
|
981
1201
|
}>> {
|
|
982
|
-
return this.proxy('get_activity_schedules', {
|
|
1202
|
+
return this.proxy('get_activity_schedules', {
|
|
1203
|
+
project_id: projectId,
|
|
1204
|
+
...params
|
|
1205
|
+
});
|
|
983
1206
|
}
|
|
984
1207
|
|
|
985
1208
|
// ============================================================================
|
|
@@ -1199,6 +1422,33 @@ export class VibescopeApiClient {
|
|
|
1199
1422
|
});
|
|
1200
1423
|
}
|
|
1201
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
|
+
|
|
1202
1452
|
// ============================================================================
|
|
1203
1453
|
// Organization endpoints
|
|
1204
1454
|
// ============================================================================
|
|
@@ -1522,6 +1772,7 @@ export class VibescopeApiClient {
|
|
|
1522
1772
|
issue_type?: string;
|
|
1523
1773
|
branch?: string;
|
|
1524
1774
|
limit?: number;
|
|
1775
|
+
offset?: number;
|
|
1525
1776
|
}): Promise<ApiResponse<{
|
|
1526
1777
|
git_issues: Array<{
|
|
1527
1778
|
id: string;
|
|
@@ -1742,6 +1993,8 @@ export class VibescopeApiClient {
|
|
|
1742
1993
|
async getDeploymentRequirements(projectId: string, params?: {
|
|
1743
1994
|
status?: string;
|
|
1744
1995
|
stage?: string;
|
|
1996
|
+
limit?: number;
|
|
1997
|
+
offset?: number;
|
|
1745
1998
|
}): Promise<ApiResponse<{
|
|
1746
1999
|
requirements: Array<{
|
|
1747
2000
|
id: string;
|
|
@@ -1751,6 +2004,8 @@ export class VibescopeApiClient {
|
|
|
1751
2004
|
status: string;
|
|
1752
2005
|
stage: string;
|
|
1753
2006
|
}>;
|
|
2007
|
+
total_count: number;
|
|
2008
|
+
has_more: boolean;
|
|
1754
2009
|
}>> {
|
|
1755
2010
|
return this.proxy('get_deployment_requirements', {
|
|
1756
2011
|
project_id: projectId,
|
|
@@ -1758,6 +2013,17 @@ export class VibescopeApiClient {
|
|
|
1758
2013
|
});
|
|
1759
2014
|
}
|
|
1760
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
|
+
|
|
1761
2027
|
async completeDeploymentRequirement(requirementId: string): Promise<ApiResponse<{
|
|
1762
2028
|
success: boolean;
|
|
1763
2029
|
}>> {
|
|
@@ -1783,7 +2049,11 @@ export class VibescopeApiClient {
|
|
|
1783
2049
|
});
|
|
1784
2050
|
}
|
|
1785
2051
|
|
|
1786
|
-
async getScheduledDeployments(projectId: string,
|
|
2052
|
+
async getScheduledDeployments(projectId: string, params?: {
|
|
2053
|
+
includeDisabled?: boolean;
|
|
2054
|
+
limit?: number;
|
|
2055
|
+
offset?: number;
|
|
2056
|
+
}): Promise<ApiResponse<{
|
|
1787
2057
|
schedules: Array<{
|
|
1788
2058
|
id: string;
|
|
1789
2059
|
scheduled_at: string;
|
|
@@ -1796,12 +2066,14 @@ export class VibescopeApiClient {
|
|
|
1796
2066
|
git_ref?: string;
|
|
1797
2067
|
notes?: string;
|
|
1798
2068
|
}>;
|
|
1799
|
-
|
|
1800
|
-
|
|
2069
|
+
total_count: number;
|
|
2070
|
+
has_more: boolean;
|
|
1801
2071
|
}>> {
|
|
1802
2072
|
return this.proxy('get_scheduled_deployments', {
|
|
1803
2073
|
project_id: projectId,
|
|
1804
|
-
include_disabled: includeDisabled
|
|
2074
|
+
include_disabled: params?.includeDisabled,
|
|
2075
|
+
limit: params?.limit,
|
|
2076
|
+
offset: params?.offset
|
|
1805
2077
|
});
|
|
1806
2078
|
}
|
|
1807
2079
|
|
|
@@ -1872,6 +2144,54 @@ export class VibescopeApiClient {
|
|
|
1872
2144
|
});
|
|
1873
2145
|
}
|
|
1874
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
|
+
|
|
1875
2195
|
// ============================================================================
|
|
1876
2196
|
// Help Topics (database-backed)
|
|
1877
2197
|
// ============================================================================
|
|
@@ -1932,6 +2252,7 @@ export class VibescopeApiClient {
|
|
|
1932
2252
|
status?: string;
|
|
1933
2253
|
file_path?: string;
|
|
1934
2254
|
limit?: number;
|
|
2255
|
+
offset?: number;
|
|
1935
2256
|
}): Promise<ApiResponse<{
|
|
1936
2257
|
checkouts: Array<{
|
|
1937
2258
|
id: string;
|
|
@@ -1962,28 +2283,51 @@ export class VibescopeApiClient {
|
|
|
1962
2283
|
return this.proxy('abandon_checkout', params);
|
|
1963
2284
|
}
|
|
1964
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
|
+
|
|
1965
2293
|
// ============================================================================
|
|
1966
2294
|
// Worktree Management
|
|
1967
2295
|
// ============================================================================
|
|
1968
2296
|
|
|
1969
|
-
async getStaleWorktrees(projectId: string
|
|
2297
|
+
async getStaleWorktrees(projectId: string, params?: {
|
|
2298
|
+
hostname?: string;
|
|
2299
|
+
limit?: number;
|
|
2300
|
+
offset?: number;
|
|
2301
|
+
}): Promise<ApiResponse<{
|
|
1970
2302
|
project_id: string;
|
|
1971
2303
|
project_name: string;
|
|
2304
|
+
hostname_filter: string | null;
|
|
1972
2305
|
stale_worktrees: Array<{
|
|
1973
2306
|
task_id: string;
|
|
1974
2307
|
task_title: string;
|
|
1975
2308
|
worktree_path: string;
|
|
2309
|
+
worktree_hostname: string | null;
|
|
1976
2310
|
git_branch: string | null;
|
|
1977
2311
|
status: string;
|
|
1978
2312
|
completed_at: string | null;
|
|
1979
2313
|
updated_at: string;
|
|
1980
2314
|
pr_url: string | null;
|
|
1981
2315
|
stale_reason: 'task_finished' | 'potentially_abandoned';
|
|
2316
|
+
can_cleanup_locally: boolean;
|
|
1982
2317
|
}>;
|
|
1983
2318
|
count: number;
|
|
2319
|
+
local_count: number;
|
|
2320
|
+
remote_count: number;
|
|
2321
|
+
total_count: number;
|
|
2322
|
+
has_more: boolean;
|
|
1984
2323
|
cleanup_instructions: string[] | null;
|
|
2324
|
+
remote_worktree_note: string | null;
|
|
1985
2325
|
}>> {
|
|
1986
|
-
|
|
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()}`);
|
|
1987
2331
|
}
|
|
1988
2332
|
|
|
1989
2333
|
async clearWorktreePath(taskId: string): Promise<ApiResponse<{
|
|
@@ -2114,6 +2458,25 @@ export class VibescopeApiClient {
|
|
|
2114
2458
|
}>> {
|
|
2115
2459
|
return this.proxy('get_connector_events', params);
|
|
2116
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
|
+
}
|
|
2117
2480
|
}
|
|
2118
2481
|
|
|
2119
2482
|
// Singleton instance
|
|
@@ -26,6 +26,7 @@ export const mockApiClient = {
|
|
|
26
26
|
heartbeat: vi.fn(),
|
|
27
27
|
syncSession: vi.fn(),
|
|
28
28
|
endSession: vi.fn(),
|
|
29
|
+
reportTokenUsage: vi.fn(),
|
|
29
30
|
|
|
30
31
|
// Project
|
|
31
32
|
listProjects: vi.fn(),
|
|
@@ -60,11 +61,13 @@ export const mockApiClient = {
|
|
|
60
61
|
addBlocker: vi.fn(),
|
|
61
62
|
resolveBlocker: vi.fn(),
|
|
62
63
|
getBlockers: vi.fn(),
|
|
64
|
+
getBlockersStats: vi.fn(),
|
|
63
65
|
deleteBlocker: vi.fn(),
|
|
64
66
|
|
|
65
67
|
// Decisions
|
|
66
68
|
logDecision: vi.fn(),
|
|
67
69
|
getDecisions: vi.fn(),
|
|
70
|
+
getDecisionsStats: vi.fn(),
|
|
68
71
|
deleteDecision: vi.fn(),
|
|
69
72
|
|
|
70
73
|
// Ideas
|
|
@@ -154,6 +157,7 @@ export const mockApiClient = {
|
|
|
154
157
|
addDeploymentRequirement: vi.fn(),
|
|
155
158
|
completeDeploymentRequirement: vi.fn(),
|
|
156
159
|
getDeploymentRequirements: vi.fn(),
|
|
160
|
+
getDeploymentRequirementsStats: vi.fn(),
|
|
157
161
|
scheduleDeployment: vi.fn(),
|
|
158
162
|
getScheduledDeployments: vi.fn(),
|
|
159
163
|
updateScheduledDeployment: vi.fn(),
|
|
@@ -174,6 +178,7 @@ export const mockApiClient = {
|
|
|
174
178
|
checkoutFile: vi.fn(),
|
|
175
179
|
checkinFile: vi.fn(),
|
|
176
180
|
getFileCheckouts: vi.fn(),
|
|
181
|
+
getFileCheckoutsStats: vi.fn(),
|
|
177
182
|
abandonCheckout: vi.fn(),
|
|
178
183
|
|
|
179
184
|
// Connectors
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
addBlocker,
|
|
4
4
|
resolveBlocker,
|
|
5
5
|
getBlockers,
|
|
6
|
+
getBlockersStats,
|
|
6
7
|
deleteBlocker,
|
|
7
8
|
} from './blockers.js';
|
|
8
9
|
import { ValidationError } from '../validators.js';
|
|
@@ -390,3 +391,78 @@ describe('deleteBlocker', () => {
|
|
|
390
391
|
});
|
|
391
392
|
});
|
|
392
393
|
});
|
|
394
|
+
|
|
395
|
+
// ============================================================================
|
|
396
|
+
// getBlockersStats Tests
|
|
397
|
+
// ============================================================================
|
|
398
|
+
|
|
399
|
+
describe('getBlockersStats', () => {
|
|
400
|
+
beforeEach(() => vi.clearAllMocks());
|
|
401
|
+
|
|
402
|
+
it('should throw error for missing project_id', async () => {
|
|
403
|
+
const ctx = createMockContext();
|
|
404
|
+
|
|
405
|
+
await expect(getBlockersStats({}, ctx)).rejects.toThrow(ValidationError);
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it('should throw error for invalid project_id UUID', async () => {
|
|
409
|
+
const ctx = createMockContext();
|
|
410
|
+
|
|
411
|
+
await expect(
|
|
412
|
+
getBlockersStats({ project_id: 'invalid' }, ctx)
|
|
413
|
+
).rejects.toThrow(ValidationError);
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
it('should return blockers stats', async () => {
|
|
417
|
+
mockApiClient.getBlockersStats.mockResolvedValue({
|
|
418
|
+
ok: true,
|
|
419
|
+
data: {
|
|
420
|
+
total: 5,
|
|
421
|
+
by_status: { open: 3, resolved: 2 },
|
|
422
|
+
},
|
|
423
|
+
});
|
|
424
|
+
const ctx = createMockContext();
|
|
425
|
+
|
|
426
|
+
const result = await getBlockersStats(
|
|
427
|
+
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
428
|
+
ctx
|
|
429
|
+
);
|
|
430
|
+
|
|
431
|
+
expect(result.result).toMatchObject({
|
|
432
|
+
total: 5,
|
|
433
|
+
by_status: { open: 3, resolved: 2 },
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
it('should call API client getBlockersStats', async () => {
|
|
438
|
+
mockApiClient.getBlockersStats.mockResolvedValue({
|
|
439
|
+
ok: true,
|
|
440
|
+
data: { total: 0, by_status: {} },
|
|
441
|
+
});
|
|
442
|
+
const ctx = createMockContext();
|
|
443
|
+
|
|
444
|
+
await getBlockersStats(
|
|
445
|
+
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
446
|
+
ctx
|
|
447
|
+
);
|
|
448
|
+
|
|
449
|
+
expect(mockApiClient.getBlockersStats).toHaveBeenCalledWith(
|
|
450
|
+
'123e4567-e89b-12d3-a456-426614174000'
|
|
451
|
+
);
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
it('should return error when API call fails', async () => {
|
|
455
|
+
mockApiClient.getBlockersStats.mockResolvedValue({
|
|
456
|
+
ok: false,
|
|
457
|
+
error: 'Query failed',
|
|
458
|
+
});
|
|
459
|
+
const ctx = createMockContext();
|
|
460
|
+
|
|
461
|
+
const result = await getBlockersStats({ project_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx);
|
|
462
|
+
|
|
463
|
+
expect(result.isError).toBe(true);
|
|
464
|
+
expect(result.result).toMatchObject({
|
|
465
|
+
error: 'Query failed',
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
});
|