@vibescope/mcp-server 0.3.10 → 0.3.12
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/dist/api-client/findings.d.ts +97 -0
- package/dist/api-client/findings.js +55 -0
- package/dist/api-client/index.d.ts +86 -2
- package/dist/api-client/index.js +24 -0
- package/dist/api-client/milestones.d.ts +60 -0
- package/dist/api-client/milestones.js +43 -0
- package/dist/cli-init.js +44 -0
- package/dist/handlers/session.js +16 -0
- package/dist/handlers/tasks.js +7 -5
- package/dist/templates/agent-guidelines.d.ts +3 -1
- package/dist/templates/agent-guidelines.js +5 -1
- package/dist/templates/help-content.js +2 -2
- package/dist/tools/tasks.js +8 -0
- package/docs/TOOLS.md +34 -2
- package/package.json +16 -15
- package/src/api-client/findings.ts +154 -0
- package/src/api-client/index.ts +31 -3
- package/src/api-client/milestones.ts +103 -0
- package/src/cli-init.ts +44 -0
- package/src/handlers/session.ts +19 -0
- package/src/handlers/tasks.ts +7 -5
- package/src/templates/agent-guidelines.ts +6 -1
- package/src/templates/help-content.ts +2 -2
- package/src/tools/tasks.ts +8 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Findings API Methods
|
|
3
|
+
*
|
|
4
|
+
* Methods for audit findings and knowledge base management:
|
|
5
|
+
* - getFindings: List findings for a project
|
|
6
|
+
* - getFinding: Get a specific finding
|
|
7
|
+
* - addFinding: Create a new finding
|
|
8
|
+
* - updateFinding: Update an existing finding
|
|
9
|
+
* - deleteFinding: Delete a finding
|
|
10
|
+
* - getFindingsStats: Get findings statistics
|
|
11
|
+
* - queryKnowledgeBase: Search findings as knowledge base
|
|
12
|
+
*/
|
|
13
|
+
import type { ApiResponse, RequestFn } from './types.js';
|
|
14
|
+
export interface FindingsMethods {
|
|
15
|
+
getFindings(projectId: string, params?: {
|
|
16
|
+
category?: string;
|
|
17
|
+
severity?: string;
|
|
18
|
+
status?: string;
|
|
19
|
+
summary_only?: boolean;
|
|
20
|
+
limit?: number;
|
|
21
|
+
offset?: number;
|
|
22
|
+
}): Promise<ApiResponse<{
|
|
23
|
+
findings: Array<{
|
|
24
|
+
id: string;
|
|
25
|
+
title: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
category: string;
|
|
28
|
+
severity: string;
|
|
29
|
+
status: string;
|
|
30
|
+
created_at: string;
|
|
31
|
+
updated_at?: string;
|
|
32
|
+
related_task_id?: string;
|
|
33
|
+
}>;
|
|
34
|
+
total_count: number;
|
|
35
|
+
has_more: boolean;
|
|
36
|
+
}>>;
|
|
37
|
+
getFinding(findingId: string): Promise<ApiResponse<{
|
|
38
|
+
id: string;
|
|
39
|
+
title: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
category: string;
|
|
42
|
+
severity: string;
|
|
43
|
+
status: string;
|
|
44
|
+
created_at: string;
|
|
45
|
+
updated_at?: string;
|
|
46
|
+
related_task_id?: string;
|
|
47
|
+
}>>;
|
|
48
|
+
addFinding(params: {
|
|
49
|
+
project_id: string;
|
|
50
|
+
title: string;
|
|
51
|
+
description?: string;
|
|
52
|
+
category?: string;
|
|
53
|
+
severity?: string;
|
|
54
|
+
related_task_id?: string;
|
|
55
|
+
}): Promise<ApiResponse<{
|
|
56
|
+
success: boolean;
|
|
57
|
+
finding_id: string;
|
|
58
|
+
}>>;
|
|
59
|
+
updateFinding(findingId: string, params: {
|
|
60
|
+
title?: string;
|
|
61
|
+
description?: string;
|
|
62
|
+
category?: string;
|
|
63
|
+
severity?: string;
|
|
64
|
+
status?: string;
|
|
65
|
+
related_task_id?: string;
|
|
66
|
+
}): Promise<ApiResponse<{
|
|
67
|
+
success: boolean;
|
|
68
|
+
finding_id: string;
|
|
69
|
+
}>>;
|
|
70
|
+
deleteFinding(findingId: string): Promise<ApiResponse<{
|
|
71
|
+
success: boolean;
|
|
72
|
+
finding_id: string;
|
|
73
|
+
}>>;
|
|
74
|
+
getFindingsStats(projectId: string): Promise<ApiResponse<{
|
|
75
|
+
total: number;
|
|
76
|
+
by_severity: Record<string, number>;
|
|
77
|
+
by_category: Record<string, number>;
|
|
78
|
+
by_status: Record<string, number>;
|
|
79
|
+
}>>;
|
|
80
|
+
queryKnowledgeBase(projectId: string, params: {
|
|
81
|
+
query: string;
|
|
82
|
+
category?: string;
|
|
83
|
+
severity?: string;
|
|
84
|
+
limit?: number;
|
|
85
|
+
}): Promise<ApiResponse<{
|
|
86
|
+
findings: Array<{
|
|
87
|
+
id: string;
|
|
88
|
+
title: string;
|
|
89
|
+
description?: string;
|
|
90
|
+
category: string;
|
|
91
|
+
severity: string;
|
|
92
|
+
relevance_score?: number;
|
|
93
|
+
}>;
|
|
94
|
+
total_count: number;
|
|
95
|
+
}>>;
|
|
96
|
+
}
|
|
97
|
+
export declare function createFindingsMethods(request: RequestFn): FindingsMethods;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Findings API Methods
|
|
3
|
+
*
|
|
4
|
+
* Methods for audit findings and knowledge base management:
|
|
5
|
+
* - getFindings: List findings for a project
|
|
6
|
+
* - getFinding: Get a specific finding
|
|
7
|
+
* - addFinding: Create a new finding
|
|
8
|
+
* - updateFinding: Update an existing finding
|
|
9
|
+
* - deleteFinding: Delete a finding
|
|
10
|
+
* - getFindingsStats: Get findings statistics
|
|
11
|
+
* - queryKnowledgeBase: Search findings as knowledge base
|
|
12
|
+
*/
|
|
13
|
+
export function createFindingsMethods(request) {
|
|
14
|
+
return {
|
|
15
|
+
async getFindings(projectId, params) {
|
|
16
|
+
return request('/api/mcp/projects/{id}/findings', 'GET', {
|
|
17
|
+
path: { id: projectId },
|
|
18
|
+
query: params,
|
|
19
|
+
});
|
|
20
|
+
},
|
|
21
|
+
async getFinding(findingId) {
|
|
22
|
+
return request('/api/mcp/findings/{id}', 'GET', {
|
|
23
|
+
path: { id: findingId },
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
async addFinding(params) {
|
|
27
|
+
return request('/api/mcp/projects/{id}/findings', 'POST', {
|
|
28
|
+
path: { id: params.project_id },
|
|
29
|
+
body: params,
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
async updateFinding(findingId, params) {
|
|
33
|
+
return request('/api/mcp/findings/{id}', 'PATCH', {
|
|
34
|
+
path: { id: findingId },
|
|
35
|
+
body: params,
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
async deleteFinding(findingId) {
|
|
39
|
+
return request('/api/mcp/findings/{id}', 'DELETE', {
|
|
40
|
+
path: { id: findingId },
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
async getFindingsStats(projectId) {
|
|
44
|
+
return request('/api/mcp/projects/{id}/findings/stats', 'GET', {
|
|
45
|
+
path: { id: projectId },
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
async queryKnowledgeBase(projectId, params) {
|
|
49
|
+
return request('/api/mcp/projects/{id}/findings/query', 'POST', {
|
|
50
|
+
path: { id: projectId },
|
|
51
|
+
body: params,
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -16,6 +16,8 @@ import { type DiscoveryMethods } from './discovery.js';
|
|
|
16
16
|
import { type DecisionsMethods } from './decisions.js';
|
|
17
17
|
import { type IdeasMethods } from './ideas.js';
|
|
18
18
|
import { type TasksMethods } from './tasks.js';
|
|
19
|
+
import { type FindingsMethods } from './findings.js';
|
|
20
|
+
import { type MilestonesMethods } from './milestones.js';
|
|
19
21
|
export type { ApiClientConfig, ApiResponse, RetryConfig, RequestFn, ProxyFn } from './types.js';
|
|
20
22
|
export type { SessionMethods } from './session.js';
|
|
21
23
|
export type { ProjectMethods } from './project.js';
|
|
@@ -26,10 +28,12 @@ export type { DiscoveryMethods } from './discovery.js';
|
|
|
26
28
|
export type { DecisionsMethods } from './decisions.js';
|
|
27
29
|
export type { IdeasMethods } from './ideas.js';
|
|
28
30
|
export type { TasksMethods } from './tasks.js';
|
|
31
|
+
export type { FindingsMethods } from './findings.js';
|
|
32
|
+
export type { MilestonesMethods } from './milestones.js';
|
|
29
33
|
/**
|
|
30
34
|
* Combined interface for all API methods
|
|
31
35
|
*/
|
|
32
|
-
export interface VibescopeApiClientMethods extends SessionMethods, ProjectMethods, BlockersMethods, CostMethods, WorktreesMethods, DiscoveryMethods, DecisionsMethods, IdeasMethods, TasksMethods {
|
|
36
|
+
export interface VibescopeApiClientMethods extends SessionMethods, ProjectMethods, BlockersMethods, CostMethods, WorktreesMethods, DiscoveryMethods, DecisionsMethods, IdeasMethods, TasksMethods, Omit<FindingsMethods, 'queryKnowledgeBase'>, MilestonesMethods {
|
|
33
37
|
}
|
|
34
38
|
export declare class VibescopeApiClient implements VibescopeApiClientMethods {
|
|
35
39
|
private apiKey;
|
|
@@ -44,6 +48,8 @@ export declare class VibescopeApiClient implements VibescopeApiClientMethods {
|
|
|
44
48
|
private decisionsMethods;
|
|
45
49
|
private ideasMethods;
|
|
46
50
|
private tasksMethods;
|
|
51
|
+
private findingsMethods;
|
|
52
|
+
private milestonesMethods;
|
|
47
53
|
constructor(config: ApiClientConfig);
|
|
48
54
|
private request;
|
|
49
55
|
/**
|
|
@@ -568,7 +574,11 @@ export declare class VibescopeApiClient implements VibescopeApiClientMethods {
|
|
|
568
574
|
estimated_minutes?: number;
|
|
569
575
|
started_at?: string;
|
|
570
576
|
completed_at?: string;
|
|
571
|
-
git_branch
|
|
577
|
+
git_branch
|
|
578
|
+
/**
|
|
579
|
+
* Combined interface for all API methods
|
|
580
|
+
*/
|
|
581
|
+
?: string;
|
|
572
582
|
blocking?: boolean;
|
|
573
583
|
references?: Array<{
|
|
574
584
|
url: string;
|
|
@@ -744,6 +754,80 @@ export declare class VibescopeApiClient implements VibescopeApiClientMethods {
|
|
|
744
754
|
error?: string;
|
|
745
755
|
}>;
|
|
746
756
|
}>>;
|
|
757
|
+
getFindings: (projectId: string, params?: Parameters<FindingsMethods["getFindings"]>[1]) => Promise<ApiResponse<{
|
|
758
|
+
findings: Array<{
|
|
759
|
+
id: string;
|
|
760
|
+
title: string;
|
|
761
|
+
description?: string;
|
|
762
|
+
category: string;
|
|
763
|
+
severity: string;
|
|
764
|
+
status: string;
|
|
765
|
+
created_at: string;
|
|
766
|
+
updated_at?: string;
|
|
767
|
+
related_task_id?: string;
|
|
768
|
+
}>;
|
|
769
|
+
total_count: number;
|
|
770
|
+
has_more: boolean;
|
|
771
|
+
}>>;
|
|
772
|
+
getFinding: (findingId: string) => Promise<ApiResponse<{
|
|
773
|
+
id: string;
|
|
774
|
+
title: string;
|
|
775
|
+
description?: string;
|
|
776
|
+
category: string;
|
|
777
|
+
severity: string;
|
|
778
|
+
status: string;
|
|
779
|
+
created_at: string;
|
|
780
|
+
updated_at?: string;
|
|
781
|
+
related_task_id?: string;
|
|
782
|
+
}>>;
|
|
783
|
+
addFinding: (params: Parameters<FindingsMethods["addFinding"]>[0]) => Promise<ApiResponse<{
|
|
784
|
+
success: boolean;
|
|
785
|
+
finding_id: string;
|
|
786
|
+
}>>;
|
|
787
|
+
updateFinding: (findingId: string, params: Parameters<FindingsMethods["updateFinding"]>[1]) => Promise<ApiResponse<{
|
|
788
|
+
success: boolean;
|
|
789
|
+
finding_id: string;
|
|
790
|
+
}>>;
|
|
791
|
+
deleteFinding: (findingId: string) => Promise<ApiResponse<{
|
|
792
|
+
success: boolean;
|
|
793
|
+
finding_id: string;
|
|
794
|
+
}>>;
|
|
795
|
+
getFindingsStats: (projectId: string) => Promise<ApiResponse<{
|
|
796
|
+
total: number;
|
|
797
|
+
by_severity: Record<string, number>;
|
|
798
|
+
by_category: Record<string, number>;
|
|
799
|
+
by_status: Record<string, number>;
|
|
800
|
+
}>>;
|
|
801
|
+
getMilestones: (projectId: string, params?: Parameters<MilestonesMethods["getMilestones"]>[1]) => Promise<ApiResponse<{
|
|
802
|
+
milestones: Array<{
|
|
803
|
+
id: string;
|
|
804
|
+
title: string;
|
|
805
|
+
description?: string;
|
|
806
|
+
due_date?: string;
|
|
807
|
+
status: string;
|
|
808
|
+
created_at: string;
|
|
809
|
+
completed_at?: string;
|
|
810
|
+
}>;
|
|
811
|
+
total_count: number;
|
|
812
|
+
has_more: boolean;
|
|
813
|
+
}>>;
|
|
814
|
+
addMilestone: (params: Parameters<MilestonesMethods["addMilestone"]>[0]) => Promise<ApiResponse<{
|
|
815
|
+
success: boolean;
|
|
816
|
+
milestone_id: string;
|
|
817
|
+
}>>;
|
|
818
|
+
updateMilestone: (milestoneId: string, params: Parameters<MilestonesMethods["updateMilestone"]>[1]) => Promise<ApiResponse<{
|
|
819
|
+
success: boolean;
|
|
820
|
+
milestone_id: string;
|
|
821
|
+
}>>;
|
|
822
|
+
completeMilestone: (milestoneId: string, params?: Parameters<MilestonesMethods["completeMilestone"]>[1]) => Promise<ApiResponse<{
|
|
823
|
+
success: boolean;
|
|
824
|
+
milestone_id: string;
|
|
825
|
+
completed_at: string;
|
|
826
|
+
}>>;
|
|
827
|
+
deleteMilestone: (milestoneId: string) => Promise<ApiResponse<{
|
|
828
|
+
success: boolean;
|
|
829
|
+
milestone_id: string;
|
|
830
|
+
}>>;
|
|
747
831
|
}
|
|
748
832
|
export declare function getApiClient(): VibescopeApiClient;
|
|
749
833
|
export declare function initApiClient(config: ApiClientConfig): VibescopeApiClient;
|
package/dist/api-client/index.js
CHANGED
|
@@ -15,6 +15,8 @@ import { createDiscoveryMethods } from './discovery.js';
|
|
|
15
15
|
import { createDecisionsMethods } from './decisions.js';
|
|
16
16
|
import { createIdeasMethods } from './ideas.js';
|
|
17
17
|
import { createTasksMethods } from './tasks.js';
|
|
18
|
+
import { createFindingsMethods } from './findings.js';
|
|
19
|
+
import { createMilestonesMethods } from './milestones.js';
|
|
18
20
|
const DEFAULT_API_URL = 'https://vibescope.dev';
|
|
19
21
|
// Retry configuration defaults
|
|
20
22
|
const DEFAULT_RETRY_STATUS_CODES = [429, 503, 504];
|
|
@@ -52,6 +54,8 @@ export class VibescopeApiClient {
|
|
|
52
54
|
decisionsMethods;
|
|
53
55
|
ideasMethods;
|
|
54
56
|
tasksMethods;
|
|
57
|
+
findingsMethods;
|
|
58
|
+
milestonesMethods;
|
|
55
59
|
constructor(config) {
|
|
56
60
|
this.apiKey = config.apiKey;
|
|
57
61
|
this.baseUrl = config.baseUrl || process.env.VIBESCOPE_API_URL || DEFAULT_API_URL;
|
|
@@ -75,6 +79,8 @@ export class VibescopeApiClient {
|
|
|
75
79
|
this.decisionsMethods = createDecisionsMethods(proxy);
|
|
76
80
|
this.ideasMethods = createIdeasMethods(proxy);
|
|
77
81
|
this.tasksMethods = createTasksMethods(request, proxy);
|
|
82
|
+
this.findingsMethods = createFindingsMethods(request);
|
|
83
|
+
this.milestonesMethods = createMilestonesMethods(request);
|
|
78
84
|
}
|
|
79
85
|
async request(method, path, body) {
|
|
80
86
|
const url = `${this.baseUrl}${path}`;
|
|
@@ -242,6 +248,24 @@ export class VibescopeApiClient {
|
|
|
242
248
|
removeTaskReference = (taskId, url) => this.tasksMethods.removeTaskReference(taskId, url);
|
|
243
249
|
batchUpdateTasks = (updates) => this.tasksMethods.batchUpdateTasks(updates);
|
|
244
250
|
batchCompleteTasks = (completions) => this.tasksMethods.batchCompleteTasks(completions);
|
|
251
|
+
// ============================================================================
|
|
252
|
+
// Findings methods (delegated)
|
|
253
|
+
// ============================================================================
|
|
254
|
+
getFindings = (projectId, params) => this.findingsMethods.getFindings(projectId, params);
|
|
255
|
+
getFinding = (findingId) => this.findingsMethods.getFinding(findingId);
|
|
256
|
+
addFinding = (params) => this.findingsMethods.addFinding(params);
|
|
257
|
+
updateFinding = (findingId, params) => this.findingsMethods.updateFinding(findingId, params);
|
|
258
|
+
deleteFinding = (findingId) => this.findingsMethods.deleteFinding(findingId);
|
|
259
|
+
getFindingsStats = (projectId) => this.findingsMethods.getFindingsStats(projectId);
|
|
260
|
+
// queryKnowledgeBase from FindingsMethods removed - duplicates DiscoveryMethods.queryKnowledgeBase (delegated above)
|
|
261
|
+
// ============================================================================
|
|
262
|
+
// Milestones methods (delegated)
|
|
263
|
+
// ============================================================================
|
|
264
|
+
getMilestones = (projectId, params) => this.milestonesMethods.getMilestones(projectId, params);
|
|
265
|
+
addMilestone = (params) => this.milestonesMethods.addMilestone(params);
|
|
266
|
+
updateMilestone = (milestoneId, params) => this.milestonesMethods.updateMilestone(milestoneId, params);
|
|
267
|
+
completeMilestone = (milestoneId, params) => this.milestonesMethods.completeMilestone(milestoneId, params);
|
|
268
|
+
deleteMilestone = (milestoneId) => this.milestonesMethods.deleteMilestone(milestoneId);
|
|
245
269
|
}
|
|
246
270
|
// Singleton instance
|
|
247
271
|
let apiClient = null;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Milestones API Methods
|
|
3
|
+
*
|
|
4
|
+
* Methods for milestone management:
|
|
5
|
+
* - getMilestones: List milestones for a project
|
|
6
|
+
* - addMilestone: Create a new milestone
|
|
7
|
+
* - updateMilestone: Update an existing milestone
|
|
8
|
+
* - completeMilestone: Mark milestone as completed
|
|
9
|
+
* - deleteMilestone: Delete a milestone
|
|
10
|
+
*/
|
|
11
|
+
import type { ApiResponse, RequestFn } from './types.js';
|
|
12
|
+
export interface MilestonesMethods {
|
|
13
|
+
getMilestones(projectId: string, params?: {
|
|
14
|
+
status?: 'pending' | 'completed';
|
|
15
|
+
limit?: number;
|
|
16
|
+
offset?: number;
|
|
17
|
+
}): Promise<ApiResponse<{
|
|
18
|
+
milestones: Array<{
|
|
19
|
+
id: string;
|
|
20
|
+
title: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
due_date?: string;
|
|
23
|
+
status: string;
|
|
24
|
+
created_at: string;
|
|
25
|
+
completed_at?: string;
|
|
26
|
+
}>;
|
|
27
|
+
total_count: number;
|
|
28
|
+
has_more: boolean;
|
|
29
|
+
}>>;
|
|
30
|
+
addMilestone(params: {
|
|
31
|
+
project_id: string;
|
|
32
|
+
title: string;
|
|
33
|
+
description?: string;
|
|
34
|
+
due_date?: string;
|
|
35
|
+
}): Promise<ApiResponse<{
|
|
36
|
+
success: boolean;
|
|
37
|
+
milestone_id: string;
|
|
38
|
+
}>>;
|
|
39
|
+
updateMilestone(milestoneId: string, params: {
|
|
40
|
+
title?: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
due_date?: string;
|
|
43
|
+
status?: string;
|
|
44
|
+
}): Promise<ApiResponse<{
|
|
45
|
+
success: boolean;
|
|
46
|
+
milestone_id: string;
|
|
47
|
+
}>>;
|
|
48
|
+
completeMilestone(milestoneId: string, params?: {
|
|
49
|
+
completion_note?: string;
|
|
50
|
+
}): Promise<ApiResponse<{
|
|
51
|
+
success: boolean;
|
|
52
|
+
milestone_id: string;
|
|
53
|
+
completed_at: string;
|
|
54
|
+
}>>;
|
|
55
|
+
deleteMilestone(milestoneId: string): Promise<ApiResponse<{
|
|
56
|
+
success: boolean;
|
|
57
|
+
milestone_id: string;
|
|
58
|
+
}>>;
|
|
59
|
+
}
|
|
60
|
+
export declare function createMilestonesMethods(request: RequestFn): MilestonesMethods;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Milestones API Methods
|
|
3
|
+
*
|
|
4
|
+
* Methods for milestone management:
|
|
5
|
+
* - getMilestones: List milestones for a project
|
|
6
|
+
* - addMilestone: Create a new milestone
|
|
7
|
+
* - updateMilestone: Update an existing milestone
|
|
8
|
+
* - completeMilestone: Mark milestone as completed
|
|
9
|
+
* - deleteMilestone: Delete a milestone
|
|
10
|
+
*/
|
|
11
|
+
export function createMilestonesMethods(request) {
|
|
12
|
+
return {
|
|
13
|
+
async getMilestones(projectId, params) {
|
|
14
|
+
return request('/api/mcp/projects/{id}/milestones', 'GET', {
|
|
15
|
+
path: { id: projectId },
|
|
16
|
+
query: params,
|
|
17
|
+
});
|
|
18
|
+
},
|
|
19
|
+
async addMilestone(params) {
|
|
20
|
+
return request('/api/mcp/projects/{id}/milestones', 'POST', {
|
|
21
|
+
path: { id: params.project_id },
|
|
22
|
+
body: params,
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
async updateMilestone(milestoneId, params) {
|
|
26
|
+
return request('/api/mcp/milestones/{id}', 'PATCH', {
|
|
27
|
+
path: { id: milestoneId },
|
|
28
|
+
body: params,
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
async completeMilestone(milestoneId, params) {
|
|
32
|
+
return request('/api/mcp/milestones/{id}/complete', 'POST', {
|
|
33
|
+
path: { id: milestoneId },
|
|
34
|
+
body: params,
|
|
35
|
+
});
|
|
36
|
+
},
|
|
37
|
+
async deleteMilestone(milestoneId) {
|
|
38
|
+
return request('/api/mcp/milestones/{id}', 'DELETE', {
|
|
39
|
+
path: { id: milestoneId },
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
package/dist/cli-init.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* Detects installed AI agents, configures MCP, and stores credentials.
|
|
8
8
|
*/
|
|
9
9
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from 'node:fs';
|
|
10
|
+
import { getAgentGuidelinesTemplate, VIBESCOPE_SECTION_START, VIBESCOPE_SECTION_END } from './templates/agent-guidelines.js';
|
|
10
11
|
import { homedir, platform } from 'node:os';
|
|
11
12
|
import { join, dirname } from 'node:path';
|
|
12
13
|
import { exec, execSync } from 'node:child_process';
|
|
@@ -408,6 +409,49 @@ ${c.dim} AI project tracking for vibe coders${c.reset}
|
|
|
408
409
|
console.log(` ${icon.cross} Failed to configure ${agent.name}: ${err instanceof Error ? err.message : 'unknown error'}`);
|
|
409
410
|
}
|
|
410
411
|
}
|
|
412
|
+
// Step 5: Generate or update .claude/CLAUDE.md
|
|
413
|
+
const claudeMdPath = join(process.cwd(), '.claude', 'CLAUDE.md');
|
|
414
|
+
const claudeDir = join(process.cwd(), '.claude');
|
|
415
|
+
if (!existsSync(claudeDir)) {
|
|
416
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
417
|
+
}
|
|
418
|
+
const vibescopeGuidelines = getAgentGuidelinesTemplate();
|
|
419
|
+
if (existsSync(claudeMdPath)) {
|
|
420
|
+
const existing = readFileSync(claudeMdPath, 'utf-8');
|
|
421
|
+
const hasVibescopeSection = existing.includes(VIBESCOPE_SECTION_START);
|
|
422
|
+
if (hasVibescopeSection) {
|
|
423
|
+
// Replace existing Vibescope section
|
|
424
|
+
const update = await promptConfirm(`\n ${c.cyan}.claude/CLAUDE.md${c.reset} already has Vibescope guidelines. Update them?`, true);
|
|
425
|
+
if (update) {
|
|
426
|
+
const startIdx = existing.indexOf(VIBESCOPE_SECTION_START);
|
|
427
|
+
const endIdx = existing.indexOf(VIBESCOPE_SECTION_END);
|
|
428
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
429
|
+
const updated = existing.substring(0, startIdx) + vibescopeGuidelines + existing.substring(endIdx + VIBESCOPE_SECTION_END.length);
|
|
430
|
+
writeFileSync(claudeMdPath, updated);
|
|
431
|
+
console.log(` ${icon.check} Updated Vibescope section in ${c.cyan}.claude/CLAUDE.md${c.reset}`);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
console.log(` ${icon.dot} Skipped CLAUDE.md update`);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
// Append Vibescope guidelines to existing file
|
|
440
|
+
const append = await promptConfirm(`\n ${c.cyan}.claude/CLAUDE.md${c.reset} exists. Append Vibescope guidelines?`, true);
|
|
441
|
+
if (append) {
|
|
442
|
+
const separator = existing.endsWith('\n') ? '\n' : '\n\n';
|
|
443
|
+
writeFileSync(claudeMdPath, existing + separator + vibescopeGuidelines);
|
|
444
|
+
console.log(` ${icon.check} Appended Vibescope guidelines to ${c.cyan}.claude/CLAUDE.md${c.reset}`);
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
console.log(` ${icon.dot} Skipped CLAUDE.md`);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
writeFileSync(claudeMdPath, vibescopeGuidelines);
|
|
453
|
+
console.log(` ${icon.check} Created ${c.cyan}.claude/CLAUDE.md${c.reset} with agent guidelines`);
|
|
454
|
+
}
|
|
411
455
|
// Done!
|
|
412
456
|
console.log(`
|
|
413
457
|
${c.green}${c.bold}Setup complete!${c.reset}
|
package/dist/handlers/session.js
CHANGED
|
@@ -276,6 +276,22 @@ export const startWorkSession = async (args, ctx) => {
|
|
|
276
276
|
result.directive = `SETUP REQUIRED: This is your first time connecting as a ${data.agent_setup.agent_type} agent. Follow the agent_setup instructions before starting work.`;
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
|
+
// Build top-level AGENT_RULES - critical rules agents must follow
|
|
280
|
+
const agentRules = [];
|
|
281
|
+
const projectWorkflow = data.project?.git_workflow;
|
|
282
|
+
const isBranching = projectWorkflow === 'git-flow' || projectWorkflow === 'github-flow';
|
|
283
|
+
const ruleBaseBranch = projectWorkflow === 'git-flow'
|
|
284
|
+
? (data.project?.git_develop_branch || 'develop')
|
|
285
|
+
: (data.project?.git_main_branch || 'main');
|
|
286
|
+
if (isBranching) {
|
|
287
|
+
agentRules.push(`WORKTREE REQUIRED: Create a git worktree BEFORE making ANY file edits. Command: git worktree add ../PROJECT-PERSONA-task -b feature/TASKID-desc ${ruleBaseBranch}`);
|
|
288
|
+
}
|
|
289
|
+
if (projectWorkflow && projectWorkflow !== 'none') {
|
|
290
|
+
agentRules.push(`FOLLOW GIT WORKFLOW: This project uses ${projectWorkflow}. Branch from ${ruleBaseBranch}. Do NOT commit directly to main or develop.`);
|
|
291
|
+
}
|
|
292
|
+
agentRules.push('COMPLETE TASKS: Always call complete_task() after creating a PR. This is mandatory.');
|
|
293
|
+
agentRules.push('REVIEW REQUIRED: All tasks must be reviewed by another agent before merging.');
|
|
294
|
+
result.AGENT_RULES = agentRules;
|
|
279
295
|
// Add next action at end - pending requests take priority over validation, then regular tasks
|
|
280
296
|
if (hasUrgentQuestions) {
|
|
281
297
|
const firstQuestion = data.URGENT_QUESTIONS?.requests?.[0] || data.pending_requests?.[0];
|
package/dist/handlers/tasks.js
CHANGED
|
@@ -60,10 +60,12 @@ const updateTaskSchema = {
|
|
|
60
60
|
worktree_path: { type: 'string' },
|
|
61
61
|
task_type: { type: 'string', validate: createEnumValidator(VALID_TASK_TYPES) },
|
|
62
62
|
skip_worktree_requirement: { type: 'boolean', default: false },
|
|
63
|
+
session_id: { type: 'string' },
|
|
63
64
|
};
|
|
64
65
|
const completeTaskSchema = {
|
|
65
66
|
task_id: { type: 'string', required: true, validate: uuidValidator },
|
|
66
67
|
summary: { type: 'string' },
|
|
68
|
+
session_id: { type: 'string' },
|
|
67
69
|
};
|
|
68
70
|
const deleteTaskSchema = {
|
|
69
71
|
task_id: { type: 'string', required: true, validate: uuidValidator },
|
|
@@ -278,7 +280,7 @@ export const addTask = async (args, ctx) => {
|
|
|
278
280
|
return { result };
|
|
279
281
|
};
|
|
280
282
|
export const updateTask = async (args, ctx) => {
|
|
281
|
-
const { task_id, title, description, priority, status, progress_percentage, progress_note, estimated_minutes, git_branch, worktree_path, task_type, skip_worktree_requirement } = parseArgs(args, updateTaskSchema);
|
|
283
|
+
const { task_id, title, description, priority, status, progress_percentage, progress_note, estimated_minutes, git_branch, worktree_path, task_type, skip_worktree_requirement, session_id: explicit_session_id } = parseArgs(args, updateTaskSchema);
|
|
282
284
|
const updates = { title, description, priority, status, progress_percentage, estimated_minutes, git_branch, worktree_path, task_type };
|
|
283
285
|
// Enforce worktree creation: require git_branch when marking task as in_progress
|
|
284
286
|
// This ensures multi-agent collaboration works properly with isolated worktrees
|
|
@@ -300,7 +302,7 @@ export const updateTask = async (args, ctx) => {
|
|
|
300
302
|
const response = await api.updateTask(task_id, {
|
|
301
303
|
...updates,
|
|
302
304
|
progress_note,
|
|
303
|
-
session_id: ctx.session.currentSessionId || undefined,
|
|
305
|
+
session_id: explicit_session_id || ctx.session.currentSessionId || undefined,
|
|
304
306
|
});
|
|
305
307
|
if (!response.ok) {
|
|
306
308
|
// Check for specific error types
|
|
@@ -416,7 +418,7 @@ export const updateTask = async (args, ctx) => {
|
|
|
416
418
|
message: 'If investigation reveals the fix already exists but needs deployment:',
|
|
417
419
|
steps: [
|
|
418
420
|
'1. Add finding: add_finding(project_id, title: "Fix exists, awaits deployment", category: "other", severity: "info", description: "...", related_task_id: task_id)',
|
|
419
|
-
'2. Complete task: complete_task(task_id, summary: "Fix already exists in codebase (PR #
|
|
421
|
+
'2. Complete task: complete_task(task_id, summary: "Fix already exists in codebase (PR #{pr_number}). Needs deployment.")',
|
|
420
422
|
'3. Check deployment: check_deployment_status(project_id)',
|
|
421
423
|
'4. Request deployment if not pending: request_deployment(project_id, notes: "Includes fix for [issue]")',
|
|
422
424
|
],
|
|
@@ -426,11 +428,11 @@ export const updateTask = async (args, ctx) => {
|
|
|
426
428
|
return { result };
|
|
427
429
|
};
|
|
428
430
|
export const completeTask = async (args, ctx) => {
|
|
429
|
-
const { task_id, summary } = parseArgs(args, completeTaskSchema);
|
|
431
|
+
const { task_id, summary, session_id: explicit_session_id } = parseArgs(args, completeTaskSchema);
|
|
430
432
|
const api = getApiClient();
|
|
431
433
|
const response = await api.completeTask(task_id, {
|
|
432
434
|
summary,
|
|
433
|
-
session_id: ctx.session.currentSessionId || undefined,
|
|
435
|
+
session_id: explicit_session_id || ctx.session.currentSessionId || undefined,
|
|
434
436
|
});
|
|
435
437
|
if (!response.ok) {
|
|
436
438
|
return { result: { error: response.error || 'Failed to complete task' }, isError: true };
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
* in every project using Vibescope for agent tracking. These guidelines ensure
|
|
6
6
|
* agents follow proper workflows and maintain visibility.
|
|
7
7
|
*/
|
|
8
|
-
export declare const
|
|
8
|
+
export declare const VIBESCOPE_SECTION_START = "<!-- vibescope:start -->";
|
|
9
|
+
export declare const VIBESCOPE_SECTION_END = "<!-- vibescope:end -->";
|
|
10
|
+
export declare const AGENT_GUIDELINES_TEMPLATE = "<!-- vibescope:start -->\n# Vibescope Agent Guidelines\n\n## Quick Start\n\n```\nstart_work_session(git_url: \"https://github.com/YOUR/REPO\", model: \"opus\")\n```\n\n**IMPORTANT:** Always pass your model (opus/sonnet/haiku) to enable cost tracking. Check your system prompt for \"You are powered by the model named...\" to determine your model.\n\nThis returns your persona, project info, and `next_task`. Start working immediately.\n\n## CRITICAL: MCP Connection Required\n\n**If the Vibescope MCP server fails to connect, you MUST end your session immediately.**\n\n### Why This Is Non-Negotiable\n\nWorking without MCP connection causes:\n- **No progress visibility** - Humans can't see what you're doing\n- **Lost work tracking** - Tasks aren't tracked, time is wasted\n- **Workflow violations** - Other agents may conflict with your work\n- **Dashboard confusion** - Project state becomes inconsistent\n\n### Connection Failure Handling\n\n**If `start_work_session` fails or returns an error:**\n\n1. **Do NOT proceed with any work**\n2. **Inform the user** that MCP connection failed\n3. **End the session** - do not attempt workarounds\n4. **Provide troubleshooting steps:**\n - Check if MCP server is configured: `claude mcp list`\n - Verify API key is set: check `.mcp.json` or environment\n - Restart Claude Code after fixing configuration\n\n**Example error responses you might see:**\n```\nError: Failed to start session\nError: VIBESCOPE_API_KEY not set\nError: Network error connecting to Vibescope API\nError: MCP server 'vibescope' not found\n```\n\n### Recovery Steps\n\nIf MCP connection fails, tell the user:\n\n```\nMCP connection to Vibescope failed. I cannot proceed without task tracking.\n\nTo fix:\n1. Run: claude mcp list (verify vibescope is configured)\n2. Check API key: ensure VIBESCOPE_API_KEY is set\n3. Restart Claude Code\n4. Try again with: start_work_session(git_url: \"...\")\n\nI am ending this session to prevent untracked work.\n```\n\n**Never \"work around\" a broken MCP connection.** The whole point of Vibescope is visibility and coordination. Working without it defeats the purpose.\n\n## Core Workflow\n\n1. **Start session** \u2192 `start_work_session(git_url, model)` - Always include your model!\n2. **Mark task in progress** \u2192 `update_task(task_id, status: \"in_progress\")` - Returns git workflow instructions!\n3. **Set up worktree** \u2192 Create isolated worktree for this task (see Git Workflow below)\n4. **Update progress** \u2192 `update_task(task_id, progress_percentage: 50, progress_note: \"...\")`\n5. **Complete task** \u2192 `complete_task(task_id, summary: \"...\")` - **MANDATORY, see below!**\n6. **Clean up** \u2192 Remove worktree, then start next task immediately\n\n## CRITICAL: Always Call complete_task (MANDATORY)\n\n**You MUST call `complete_task()` when you finish a task.** This is not optional.\n\n### When to Call complete_task\n\nCall `complete_task()` immediately after:\n- \u2705 Creating and pushing a PR\n- \u2705 Merging changes (for trunk-based workflow)\n- \u2705 Finishing any unit of work, even if no code changes\n\n**Do NOT wait for:**\n- \u274C PR to be reviewed/merged (that's what validation is for)\n- \u274C User confirmation\n- \u274C \"Perfect\" summary - a brief summary is fine\n\n### The Rule\n\n```\nPR created + pushed \u2192 complete_task() \u2192 THEN worry about next steps\n```\n\n**If you create a PR and don't call `complete_task()`, you have failed the workflow.**\n\n## CRITICAL: Git Worktrees for Multi-Agent\n\nWhen multiple agents share a repository, you **MUST** use git worktrees to prevent conflicts.\n\n**Before starting ANY task:**\n```bash\n# For git-flow: ensure you're on develop first, then create worktree\ngit checkout develop\ngit pull origin develop\ngit worktree add ../worktree-<task-short-id> -b feature/<task-id>-<title>\ncd ../worktree-<task-short-id>\n```\n\n**After task is merged:**\n```bash\ngit worktree remove ../worktree-<task-short-id>\n```\n\n**Why?** Branch switching in shared repos causes file conflicts between agents. Worktrees provide isolated directories.\n\nRun `get_help(\"git\")` for full worktree documentation.\n\n## CRITICAL: Never Ask Permission\n\n**You must NEVER:**\n- Ask \"Should I continue to the next task?\" \u2192 Just continue\n- Ask \"Should I clear my context?\" \u2192 Just clear it\n- Ask \"What should I do next?\" \u2192 Check `next_task` or use fallback activities\n- Say \"All tasks are done, let me know what to do\" \u2192 Use `get_next_task` or start fallback activity\n- Wait for confirmation before clearing context \u2192 Just do it\n\n**You must ALWAYS:**\n- Call `complete_task()` immediately after creating/pushing a PR - this is non-negotiable\n- Immediately start the next task after completing one\n- Clear context and restart session automatically when needed\n- Keep working until there are genuinely no tasks and no fallback activities\n\n## Continuous Work\n\n**IMPORTANT: Never stop working!** When you complete a task:\n1. `complete_task` returns `next_task` \u2192 Start it immediately\n2. No `next_task`? \u2192 Call `get_next_task(project_id)`\n3. Still no tasks? \u2192 Start a `fallback_activity` (code_review, security_review, etc.)\n\n**When context grows large or responses slow down:**\n1. Run `/clear` to reset conversation\n2. Immediately call `start_work_session(git_url, model)` to reload context\n3. Continue with `next_task` from the response\n\n**Do NOT ask the user if you should clear context. Just do it.** The dashboard tracks all your progress, so nothing is lost when you clear.\n\n## Need Help?\n\nUse `get_help(topic)` for detailed guidance:\n\n| Topic | Description |\n|-------|-------------|\n| `getting_started` | Basic workflow overview |\n| `tasks` | Working on tasks, progress tracking |\n| `validation` | Cross-agent task validation |\n| `deployment` | Deployment coordination |\n| `git` | Git workflow configuration |\n| `blockers` | Handling blockers |\n| `milestones` | Breaking down complex tasks |\n| `fallback` | Background activities when idle |\n| `session` | Session management |\n| `topics` | List all available topics |\n\n## MCP Server Not Connected?\n\n### Quick Setup (Claude Code)\n\n```bash\nclaude mcp add vibescope npx @vibescope/mcp-server@latest \\\n --env VIBESCOPE_API_KEY=your_key\n```\n\n### Manual Setup\n\n1. Copy `.mcp.json.example` to `.mcp.json`\n2. Get `VIBESCOPE_API_KEY` from https://vibescope.dev/dashboard/settings\n3. Restart Claude Code\n<!-- vibescope:end -->\n";
|
|
9
11
|
/**
|
|
10
12
|
* Get the agent guidelines template
|
|
11
13
|
* @returns The full agent guidelines markdown template
|
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
* in every project using Vibescope for agent tracking. These guidelines ensure
|
|
6
6
|
* agents follow proper workflows and maintain visibility.
|
|
7
7
|
*/
|
|
8
|
-
export const
|
|
8
|
+
export const VIBESCOPE_SECTION_START = '<!-- vibescope:start -->';
|
|
9
|
+
export const VIBESCOPE_SECTION_END = '<!-- vibescope:end -->';
|
|
10
|
+
export const AGENT_GUIDELINES_TEMPLATE = `${VIBESCOPE_SECTION_START}
|
|
11
|
+
# Vibescope Agent Guidelines
|
|
9
12
|
|
|
10
13
|
## Quick Start
|
|
11
14
|
|
|
@@ -182,6 +185,7 @@ claude mcp add vibescope npx @vibescope/mcp-server@latest \\
|
|
|
182
185
|
1. Copy \`.mcp.json.example\` to \`.mcp.json\`
|
|
183
186
|
2. Get \`VIBESCOPE_API_KEY\` from https://vibescope.dev/dashboard/settings
|
|
184
187
|
3. Restart Claude Code
|
|
188
|
+
${VIBESCOPE_SECTION_END}
|
|
185
189
|
`;
|
|
186
190
|
/**
|
|
187
191
|
* Get the agent guidelines template
|
|
@@ -214,14 +214,14 @@ add_finding(
|
|
|
214
214
|
title: "Fix exists but awaits deployment",
|
|
215
215
|
category: "other",
|
|
216
216
|
severity: "info",
|
|
217
|
-
description: "The fix for [issue] was implemented in PR #
|
|
217
|
+
description: "The fix for [issue] was implemented in PR #{pr_number} but hasn't been deployed yet.",
|
|
218
218
|
related_task_id: task_id
|
|
219
219
|
)
|
|
220
220
|
\`\`\`
|
|
221
221
|
|
|
222
222
|
2. **Complete the task** (investigation is done):
|
|
223
223
|
\`\`\`
|
|
224
|
-
complete_task(task_id, summary: "Fix already exists in codebase (PR #
|
|
224
|
+
complete_task(task_id, summary: "Fix already exists in codebase (PR #{pr_number}). Needs deployment to production.")
|
|
225
225
|
\`\`\`
|
|
226
226
|
|
|
227
227
|
3. **Request deployment** if not already pending:
|
package/dist/tools/tasks.js
CHANGED
|
@@ -296,6 +296,10 @@ For projects without git branching (trunk-based or none), use skip_worktree_requ
|
|
|
296
296
|
type: 'boolean',
|
|
297
297
|
description: 'Skip git_branch requirement for projects without branching workflows (trunk-based or none). Default: false',
|
|
298
298
|
},
|
|
299
|
+
session_id: {
|
|
300
|
+
type: 'string',
|
|
301
|
+
description: 'Session ID from start_work_session. Required for cloud agents using mcporter (session context is not preserved between calls). Links the task to your agent on the dashboard.',
|
|
302
|
+
},
|
|
299
303
|
},
|
|
300
304
|
required: ['task_id'],
|
|
301
305
|
},
|
|
@@ -326,6 +330,10 @@ The auto_continue: true flag in the response means you are expected to continue
|
|
|
326
330
|
type: 'string',
|
|
327
331
|
description: 'Brief summary of what was done. This is stored on the task as completion_summary and displayed when reviewing completed tasks.',
|
|
328
332
|
},
|
|
333
|
+
session_id: {
|
|
334
|
+
type: 'string',
|
|
335
|
+
description: 'Session ID from start_work_session. Required for cloud agents using mcporter.',
|
|
336
|
+
},
|
|
329
337
|
},
|
|
330
338
|
required: ['task_id'],
|
|
331
339
|
},
|
package/docs/TOOLS.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
> Auto-generated from tool definitions. Do not edit manually.
|
|
4
4
|
>
|
|
5
|
-
> Generated: 2026-02-
|
|
5
|
+
> Generated: 2026-02-15
|
|
6
6
|
>
|
|
7
|
-
> Total tools:
|
|
7
|
+
> Total tools: 159
|
|
8
8
|
|
|
9
9
|
## Table of Contents
|
|
10
10
|
|
|
@@ -2513,3 +2513,35 @@ Update the Vibescope MCP server to the latest version. Runs npm install to fetch
|
|
|
2513
2513
|
| `global` | `boolean` | No | If true, update the global installation (npm install -g). If false, update locally. Default: true. |
|
|
2514
2514
|
|
|
2515
2515
|
---
|
|
2516
|
+
|
|
2517
|
+
## Uncategorized
|
|
2518
|
+
|
|
2519
|
+
*Tools not yet assigned to a category*
|
|
2520
|
+
|
|
2521
|
+
### update_agent_status
|
|
2522
|
+
|
|
2523
|
+
Report what you're currently doing. This updates the status message shown on the dashboard.
|
|
2524
|
+
|
|
2525
|
+
Call this at key milestones during boot and work:
|
|
2526
|
+
|
|
2527
|
+
- "Installing dependencies..."
|
|
2528
|
+
|
|
2529
|
+
- "Running start_work_session..."
|
|
2530
|
+
|
|
2531
|
+
- "Working on: <task title>"
|
|
2532
|
+
|
|
2533
|
+
- "Running tests..."
|
|
2534
|
+
|
|
2535
|
+
- "Committing changes..."
|
|
2536
|
+
|
|
2537
|
+
Keep messages short (under 80 chars). The dashboard shows this in real-time.
|
|
2538
|
+
|
|
2539
|
+
**Parameters:**
|
|
2540
|
+
|
|
2541
|
+
| Parameter | Type | Required | Description |
|
|
2542
|
+
|-----------|------|----------|-------------|
|
|
2543
|
+
| `status_message` | `string` | Yes | Short status message to display on dashboard (max 80 chars) |
|
|
2544
|
+
| `project_id` | `string` | No | Project UUID (optional if session has project context) |
|
|
2545
|
+
| `agent_name` | `string` | No | Agent name (used to find the spawned_agents record) |
|
|
2546
|
+
|
|
2547
|
+
---
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibescope/mcp-server",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.12",
|
|
4
4
|
"description": "MCP server for Vibescope - AI project tracking tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -19,6 +19,20 @@
|
|
|
19
19
|
"publishConfig": {
|
|
20
20
|
"access": "public"
|
|
21
21
|
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc",
|
|
24
|
+
"dev": "tsc --watch",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"test:watch": "vitest",
|
|
27
|
+
"docs:generate": "npx tsx scripts/generate-docs.ts --output=docs/TOOLS.md",
|
|
28
|
+
"docs:preview": "npx tsx scripts/generate-docs.ts",
|
|
29
|
+
"version:check": "npx tsx scripts/version-bump.ts --dry-run",
|
|
30
|
+
"version:bump": "npx tsx scripts/version-bump.ts",
|
|
31
|
+
"version:patch": "npx tsx scripts/version-bump.ts --patch",
|
|
32
|
+
"version:minor": "npx tsx scripts/version-bump.ts --minor",
|
|
33
|
+
"version:major": "npx tsx scripts/version-bump.ts --major",
|
|
34
|
+
"prepublishOnly": "npm run build"
|
|
35
|
+
},
|
|
22
36
|
"keywords": [
|
|
23
37
|
"mcp",
|
|
24
38
|
"model-context-protocol",
|
|
@@ -35,18 +49,5 @@
|
|
|
35
49
|
},
|
|
36
50
|
"dependencies": {
|
|
37
51
|
"@modelcontextprotocol/sdk": "^1.25.2"
|
|
38
|
-
},
|
|
39
|
-
"scripts": {
|
|
40
|
-
"build": "tsc",
|
|
41
|
-
"dev": "tsc --watch",
|
|
42
|
-
"test": "vitest run",
|
|
43
|
-
"test:watch": "vitest",
|
|
44
|
-
"docs:generate": "npx tsx scripts/generate-docs.ts --output=docs/TOOLS.md",
|
|
45
|
-
"docs:preview": "npx tsx scripts/generate-docs.ts",
|
|
46
|
-
"version:check": "npx tsx scripts/version-bump.ts --dry-run",
|
|
47
|
-
"version:bump": "npx tsx scripts/version-bump.ts",
|
|
48
|
-
"version:patch": "npx tsx scripts/version-bump.ts --patch",
|
|
49
|
-
"version:minor": "npx tsx scripts/version-bump.ts --minor",
|
|
50
|
-
"version:major": "npx tsx scripts/version-bump.ts --major"
|
|
51
52
|
}
|
|
52
|
-
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Findings API Methods
|
|
3
|
+
*
|
|
4
|
+
* Methods for audit findings and knowledge base management:
|
|
5
|
+
* - getFindings: List findings for a project
|
|
6
|
+
* - getFinding: Get a specific finding
|
|
7
|
+
* - addFinding: Create a new finding
|
|
8
|
+
* - updateFinding: Update an existing finding
|
|
9
|
+
* - deleteFinding: Delete a finding
|
|
10
|
+
* - getFindingsStats: Get findings statistics
|
|
11
|
+
* - queryKnowledgeBase: Search findings as knowledge base
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { ApiResponse, RequestFn } from './types.js';
|
|
15
|
+
|
|
16
|
+
export interface FindingsMethods {
|
|
17
|
+
getFindings(projectId: string, params?: {
|
|
18
|
+
category?: string;
|
|
19
|
+
severity?: string;
|
|
20
|
+
status?: string;
|
|
21
|
+
summary_only?: boolean;
|
|
22
|
+
limit?: number;
|
|
23
|
+
offset?: number;
|
|
24
|
+
}): Promise<ApiResponse<{
|
|
25
|
+
findings: Array<{
|
|
26
|
+
id: string;
|
|
27
|
+
title: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
category: string;
|
|
30
|
+
severity: string;
|
|
31
|
+
status: string;
|
|
32
|
+
created_at: string;
|
|
33
|
+
updated_at?: string;
|
|
34
|
+
related_task_id?: string;
|
|
35
|
+
}>;
|
|
36
|
+
total_count: number;
|
|
37
|
+
has_more: boolean;
|
|
38
|
+
}>>;
|
|
39
|
+
|
|
40
|
+
getFinding(findingId: string): Promise<ApiResponse<{
|
|
41
|
+
id: string;
|
|
42
|
+
title: string;
|
|
43
|
+
description?: string;
|
|
44
|
+
category: string;
|
|
45
|
+
severity: string;
|
|
46
|
+
status: string;
|
|
47
|
+
created_at: string;
|
|
48
|
+
updated_at?: string;
|
|
49
|
+
related_task_id?: string;
|
|
50
|
+
}>>;
|
|
51
|
+
|
|
52
|
+
addFinding(params: {
|
|
53
|
+
project_id: string;
|
|
54
|
+
title: string;
|
|
55
|
+
description?: string;
|
|
56
|
+
category?: string;
|
|
57
|
+
severity?: string;
|
|
58
|
+
related_task_id?: string;
|
|
59
|
+
}): Promise<ApiResponse<{
|
|
60
|
+
success: boolean;
|
|
61
|
+
finding_id: string;
|
|
62
|
+
}>>;
|
|
63
|
+
|
|
64
|
+
updateFinding(findingId: string, params: {
|
|
65
|
+
title?: string;
|
|
66
|
+
description?: string;
|
|
67
|
+
category?: string;
|
|
68
|
+
severity?: string;
|
|
69
|
+
status?: string;
|
|
70
|
+
related_task_id?: string;
|
|
71
|
+
}): Promise<ApiResponse<{
|
|
72
|
+
success: boolean;
|
|
73
|
+
finding_id: string;
|
|
74
|
+
}>>;
|
|
75
|
+
|
|
76
|
+
deleteFinding(findingId: string): Promise<ApiResponse<{
|
|
77
|
+
success: boolean;
|
|
78
|
+
finding_id: string;
|
|
79
|
+
}>>;
|
|
80
|
+
|
|
81
|
+
getFindingsStats(projectId: string): Promise<ApiResponse<{
|
|
82
|
+
total: number;
|
|
83
|
+
by_severity: Record<string, number>;
|
|
84
|
+
by_category: Record<string, number>;
|
|
85
|
+
by_status: Record<string, number>;
|
|
86
|
+
}>>;
|
|
87
|
+
|
|
88
|
+
queryKnowledgeBase(projectId: string, params: {
|
|
89
|
+
query: string;
|
|
90
|
+
category?: string;
|
|
91
|
+
severity?: string;
|
|
92
|
+
limit?: number;
|
|
93
|
+
}): Promise<ApiResponse<{
|
|
94
|
+
findings: Array<{
|
|
95
|
+
id: string;
|
|
96
|
+
title: string;
|
|
97
|
+
description?: string;
|
|
98
|
+
category: string;
|
|
99
|
+
severity: string;
|
|
100
|
+
relevance_score?: number;
|
|
101
|
+
}>;
|
|
102
|
+
total_count: number;
|
|
103
|
+
}>>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function createFindingsMethods(request: RequestFn): FindingsMethods {
|
|
107
|
+
return {
|
|
108
|
+
async getFindings(projectId, params) {
|
|
109
|
+
return request('/api/mcp/projects/{id}/findings', 'GET', {
|
|
110
|
+
path: { id: projectId },
|
|
111
|
+
query: params,
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
async getFinding(findingId) {
|
|
116
|
+
return request('/api/mcp/findings/{id}', 'GET', {
|
|
117
|
+
path: { id: findingId },
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
async addFinding(params) {
|
|
122
|
+
return request('/api/mcp/projects/{id}/findings', 'POST', {
|
|
123
|
+
path: { id: params.project_id },
|
|
124
|
+
body: params,
|
|
125
|
+
});
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
async updateFinding(findingId, params) {
|
|
129
|
+
return request('/api/mcp/findings/{id}', 'PATCH', {
|
|
130
|
+
path: { id: findingId },
|
|
131
|
+
body: params,
|
|
132
|
+
});
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
async deleteFinding(findingId) {
|
|
136
|
+
return request('/api/mcp/findings/{id}', 'DELETE', {
|
|
137
|
+
path: { id: findingId },
|
|
138
|
+
});
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
async getFindingsStats(projectId) {
|
|
142
|
+
return request('/api/mcp/projects/{id}/findings/stats', 'GET', {
|
|
143
|
+
path: { id: projectId },
|
|
144
|
+
});
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
async queryKnowledgeBase(projectId, params) {
|
|
148
|
+
return request('/api/mcp/projects/{id}/findings/query', 'POST', {
|
|
149
|
+
path: { id: projectId },
|
|
150
|
+
body: params,
|
|
151
|
+
});
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
package/src/api-client/index.ts
CHANGED
|
@@ -17,6 +17,8 @@ import { createDiscoveryMethods, type DiscoveryMethods } from './discovery.js';
|
|
|
17
17
|
import { createDecisionsMethods, type DecisionsMethods } from './decisions.js';
|
|
18
18
|
import { createIdeasMethods, type IdeasMethods } from './ideas.js';
|
|
19
19
|
import { createTasksMethods, type TasksMethods } from './tasks.js';
|
|
20
|
+
import { createFindingsMethods, type FindingsMethods } from './findings.js';
|
|
21
|
+
import { createMilestonesMethods, type MilestonesMethods } from './milestones.js';
|
|
20
22
|
|
|
21
23
|
// Re-export types
|
|
22
24
|
export type { ApiClientConfig, ApiResponse, RetryConfig, RequestFn, ProxyFn } from './types.js';
|
|
@@ -29,6 +31,8 @@ export type { DiscoveryMethods } from './discovery.js';
|
|
|
29
31
|
export type { DecisionsMethods } from './decisions.js';
|
|
30
32
|
export type { IdeasMethods } from './ideas.js';
|
|
31
33
|
export type { TasksMethods } from './tasks.js';
|
|
34
|
+
export type { FindingsMethods } from './findings.js';
|
|
35
|
+
export type { MilestonesMethods } from './milestones.js';
|
|
32
36
|
|
|
33
37
|
const DEFAULT_API_URL = 'https://vibescope.dev';
|
|
34
38
|
|
|
@@ -74,7 +78,9 @@ export interface VibescopeApiClientMethods
|
|
|
74
78
|
DiscoveryMethods,
|
|
75
79
|
DecisionsMethods,
|
|
76
80
|
IdeasMethods,
|
|
77
|
-
TasksMethods
|
|
81
|
+
TasksMethods,
|
|
82
|
+
Omit<FindingsMethods, 'queryKnowledgeBase'>,
|
|
83
|
+
MilestonesMethods {}
|
|
78
84
|
|
|
79
85
|
export class VibescopeApiClient implements VibescopeApiClientMethods {
|
|
80
86
|
private apiKey: string;
|
|
@@ -91,6 +97,8 @@ export class VibescopeApiClient implements VibescopeApiClientMethods {
|
|
|
91
97
|
private decisionsMethods: DecisionsMethods;
|
|
92
98
|
private ideasMethods: IdeasMethods;
|
|
93
99
|
private tasksMethods: TasksMethods;
|
|
100
|
+
private findingsMethods: FindingsMethods;
|
|
101
|
+
private milestonesMethods: MilestonesMethods;
|
|
94
102
|
|
|
95
103
|
constructor(config: ApiClientConfig) {
|
|
96
104
|
this.apiKey = config.apiKey;
|
|
@@ -117,6 +125,8 @@ export class VibescopeApiClient implements VibescopeApiClientMethods {
|
|
|
117
125
|
this.decisionsMethods = createDecisionsMethods(proxy);
|
|
118
126
|
this.ideasMethods = createIdeasMethods(proxy);
|
|
119
127
|
this.tasksMethods = createTasksMethods(request, proxy);
|
|
128
|
+
this.findingsMethods = createFindingsMethods(request);
|
|
129
|
+
this.milestonesMethods = createMilestonesMethods(request);
|
|
120
130
|
}
|
|
121
131
|
|
|
122
132
|
private async request<T>(method: string, path: string, body?: unknown): Promise<ApiResponse<T>> {
|
|
@@ -304,11 +314,29 @@ export class VibescopeApiClient implements VibescopeApiClientMethods {
|
|
|
304
314
|
batchUpdateTasks = (updates: Parameters<TasksMethods['batchUpdateTasks']>[0]) => this.tasksMethods.batchUpdateTasks(updates);
|
|
305
315
|
batchCompleteTasks = (completions: Parameters<TasksMethods['batchCompleteTasks']>[0]) => this.tasksMethods.batchCompleteTasks(completions);
|
|
306
316
|
|
|
317
|
+
// ============================================================================
|
|
318
|
+
// Findings methods (delegated)
|
|
319
|
+
// ============================================================================
|
|
320
|
+
getFindings = (projectId: string, params?: Parameters<FindingsMethods['getFindings']>[1]) => this.findingsMethods.getFindings(projectId, params);
|
|
321
|
+
getFinding = (findingId: string) => this.findingsMethods.getFinding(findingId);
|
|
322
|
+
addFinding = (params: Parameters<FindingsMethods['addFinding']>[0]) => this.findingsMethods.addFinding(params);
|
|
323
|
+
updateFinding = (findingId: string, params: Parameters<FindingsMethods['updateFinding']>[1]) => this.findingsMethods.updateFinding(findingId, params);
|
|
324
|
+
deleteFinding = (findingId: string) => this.findingsMethods.deleteFinding(findingId);
|
|
325
|
+
getFindingsStats = (projectId: string) => this.findingsMethods.getFindingsStats(projectId);
|
|
326
|
+
// queryKnowledgeBase from FindingsMethods removed - duplicates DiscoveryMethods.queryKnowledgeBase (delegated above)
|
|
327
|
+
|
|
328
|
+
// ============================================================================
|
|
329
|
+
// Milestones methods (delegated)
|
|
330
|
+
// ============================================================================
|
|
331
|
+
getMilestones = (projectId: string, params?: Parameters<MilestonesMethods['getMilestones']>[1]) => this.milestonesMethods.getMilestones(projectId, params);
|
|
332
|
+
addMilestone = (params: Parameters<MilestonesMethods['addMilestone']>[0]) => this.milestonesMethods.addMilestone(params);
|
|
333
|
+
updateMilestone = (milestoneId: string, params: Parameters<MilestonesMethods['updateMilestone']>[1]) => this.milestonesMethods.updateMilestone(milestoneId, params);
|
|
334
|
+
completeMilestone = (milestoneId: string, params?: Parameters<MilestonesMethods['completeMilestone']>[1]) => this.milestonesMethods.completeMilestone(milestoneId, params);
|
|
335
|
+
deleteMilestone = (milestoneId: string) => this.milestonesMethods.deleteMilestone(milestoneId);
|
|
336
|
+
|
|
307
337
|
// ============================================================================
|
|
308
338
|
// TODO: Additional methods to be migrated from original api-client.ts
|
|
309
339
|
// The following domains need to be split into separate files:
|
|
310
|
-
// - findings.ts (getFindings, addFinding, etc.)
|
|
311
|
-
// - milestones.ts (getMilestones, addMilestone, etc.)
|
|
312
340
|
// - requests.ts (getPendingRequests, answerQuestion, etc.)
|
|
313
341
|
// - validation.ts (getTasksAwaitingValidation, validateTask, etc.)
|
|
314
342
|
// - fallback.ts (startFallbackActivity, stopFallbackActivity)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Milestones API Methods
|
|
3
|
+
*
|
|
4
|
+
* Methods for milestone management:
|
|
5
|
+
* - getMilestones: List milestones for a project
|
|
6
|
+
* - addMilestone: Create a new milestone
|
|
7
|
+
* - updateMilestone: Update an existing milestone
|
|
8
|
+
* - completeMilestone: Mark milestone as completed
|
|
9
|
+
* - deleteMilestone: Delete a milestone
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { ApiResponse, RequestFn } from './types.js';
|
|
13
|
+
|
|
14
|
+
export interface MilestonesMethods {
|
|
15
|
+
getMilestones(projectId: string, params?: {
|
|
16
|
+
status?: 'pending' | 'completed';
|
|
17
|
+
limit?: number;
|
|
18
|
+
offset?: number;
|
|
19
|
+
}): Promise<ApiResponse<{
|
|
20
|
+
milestones: Array<{
|
|
21
|
+
id: string;
|
|
22
|
+
title: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
due_date?: string;
|
|
25
|
+
status: string;
|
|
26
|
+
created_at: string;
|
|
27
|
+
completed_at?: string;
|
|
28
|
+
}>;
|
|
29
|
+
total_count: number;
|
|
30
|
+
has_more: boolean;
|
|
31
|
+
}>>;
|
|
32
|
+
|
|
33
|
+
addMilestone(params: {
|
|
34
|
+
project_id: string;
|
|
35
|
+
title: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
due_date?: string;
|
|
38
|
+
}): Promise<ApiResponse<{
|
|
39
|
+
success: boolean;
|
|
40
|
+
milestone_id: string;
|
|
41
|
+
}>>;
|
|
42
|
+
|
|
43
|
+
updateMilestone(milestoneId: string, params: {
|
|
44
|
+
title?: string;
|
|
45
|
+
description?: string;
|
|
46
|
+
due_date?: string;
|
|
47
|
+
status?: string;
|
|
48
|
+
}): Promise<ApiResponse<{
|
|
49
|
+
success: boolean;
|
|
50
|
+
milestone_id: string;
|
|
51
|
+
}>>;
|
|
52
|
+
|
|
53
|
+
completeMilestone(milestoneId: string, params?: {
|
|
54
|
+
completion_note?: string;
|
|
55
|
+
}): Promise<ApiResponse<{
|
|
56
|
+
success: boolean;
|
|
57
|
+
milestone_id: string;
|
|
58
|
+
completed_at: string;
|
|
59
|
+
}>>;
|
|
60
|
+
|
|
61
|
+
deleteMilestone(milestoneId: string): Promise<ApiResponse<{
|
|
62
|
+
success: boolean;
|
|
63
|
+
milestone_id: string;
|
|
64
|
+
}>>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function createMilestonesMethods(request: RequestFn): MilestonesMethods {
|
|
68
|
+
return {
|
|
69
|
+
async getMilestones(projectId, params) {
|
|
70
|
+
return request('/api/mcp/projects/{id}/milestones', 'GET', {
|
|
71
|
+
path: { id: projectId },
|
|
72
|
+
query: params,
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
async addMilestone(params) {
|
|
77
|
+
return request('/api/mcp/projects/{id}/milestones', 'POST', {
|
|
78
|
+
path: { id: params.project_id },
|
|
79
|
+
body: params,
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
async updateMilestone(milestoneId, params) {
|
|
84
|
+
return request('/api/mcp/milestones/{id}', 'PATCH', {
|
|
85
|
+
path: { id: milestoneId },
|
|
86
|
+
body: params,
|
|
87
|
+
});
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
async completeMilestone(milestoneId, params) {
|
|
91
|
+
return request('/api/mcp/milestones/{id}/complete', 'POST', {
|
|
92
|
+
path: { id: milestoneId },
|
|
93
|
+
body: params,
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
async deleteMilestone(milestoneId) {
|
|
98
|
+
return request('/api/mcp/milestones/{id}', 'DELETE', {
|
|
99
|
+
path: { id: milestoneId },
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
package/src/cli-init.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from 'node:fs';
|
|
12
|
+
import { getAgentGuidelinesTemplate, VIBESCOPE_SECTION_START, VIBESCOPE_SECTION_END } from './templates/agent-guidelines.js';
|
|
12
13
|
import { homedir, platform } from 'node:os';
|
|
13
14
|
import { join, dirname } from 'node:path';
|
|
14
15
|
import { exec, execSync } from 'node:child_process';
|
|
@@ -466,6 +467,49 @@ ${c.dim} AI project tracking for vibe coders${c.reset}
|
|
|
466
467
|
}
|
|
467
468
|
}
|
|
468
469
|
|
|
470
|
+
// Step 5: Generate or update .claude/CLAUDE.md
|
|
471
|
+
const claudeMdPath = join(process.cwd(), '.claude', 'CLAUDE.md');
|
|
472
|
+
const claudeDir = join(process.cwd(), '.claude');
|
|
473
|
+
if (!existsSync(claudeDir)) {
|
|
474
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const vibescopeGuidelines = getAgentGuidelinesTemplate();
|
|
478
|
+
|
|
479
|
+
if (existsSync(claudeMdPath)) {
|
|
480
|
+
const existing = readFileSync(claudeMdPath, 'utf-8');
|
|
481
|
+
const hasVibescopeSection = existing.includes(VIBESCOPE_SECTION_START);
|
|
482
|
+
|
|
483
|
+
if (hasVibescopeSection) {
|
|
484
|
+
// Replace existing Vibescope section
|
|
485
|
+
const update = await promptConfirm(`\n ${c.cyan}.claude/CLAUDE.md${c.reset} already has Vibescope guidelines. Update them?`, true);
|
|
486
|
+
if (update) {
|
|
487
|
+
const startIdx = existing.indexOf(VIBESCOPE_SECTION_START);
|
|
488
|
+
const endIdx = existing.indexOf(VIBESCOPE_SECTION_END);
|
|
489
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
490
|
+
const updated = existing.substring(0, startIdx) + vibescopeGuidelines + existing.substring(endIdx + VIBESCOPE_SECTION_END.length);
|
|
491
|
+
writeFileSync(claudeMdPath, updated);
|
|
492
|
+
console.log(` ${icon.check} Updated Vibescope section in ${c.cyan}.claude/CLAUDE.md${c.reset}`);
|
|
493
|
+
}
|
|
494
|
+
} else {
|
|
495
|
+
console.log(` ${icon.dot} Skipped CLAUDE.md update`);
|
|
496
|
+
}
|
|
497
|
+
} else {
|
|
498
|
+
// Append Vibescope guidelines to existing file
|
|
499
|
+
const append = await promptConfirm(`\n ${c.cyan}.claude/CLAUDE.md${c.reset} exists. Append Vibescope guidelines?`, true);
|
|
500
|
+
if (append) {
|
|
501
|
+
const separator = existing.endsWith('\n') ? '\n' : '\n\n';
|
|
502
|
+
writeFileSync(claudeMdPath, existing + separator + vibescopeGuidelines);
|
|
503
|
+
console.log(` ${icon.check} Appended Vibescope guidelines to ${c.cyan}.claude/CLAUDE.md${c.reset}`);
|
|
504
|
+
} else {
|
|
505
|
+
console.log(` ${icon.dot} Skipped CLAUDE.md`);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
} else {
|
|
509
|
+
writeFileSync(claudeMdPath, vibescopeGuidelines);
|
|
510
|
+
console.log(` ${icon.check} Created ${c.cyan}.claude/CLAUDE.md${c.reset} with agent guidelines`);
|
|
511
|
+
}
|
|
512
|
+
|
|
469
513
|
// Done!
|
|
470
514
|
console.log(`
|
|
471
515
|
${c.green}${c.bold}Setup complete!${c.reset}
|
package/src/handlers/session.ts
CHANGED
|
@@ -320,6 +320,25 @@ export const startWorkSession: Handler = async (args, ctx) => {
|
|
|
320
320
|
}
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
+
// Build top-level AGENT_RULES - critical rules agents must follow
|
|
324
|
+
const agentRules: string[] = [];
|
|
325
|
+
const projectWorkflow = data.project?.git_workflow;
|
|
326
|
+
const isBranching = projectWorkflow === 'git-flow' || projectWorkflow === 'github-flow';
|
|
327
|
+
const ruleBaseBranch = projectWorkflow === 'git-flow'
|
|
328
|
+
? (data.project?.git_develop_branch || 'develop')
|
|
329
|
+
: (data.project?.git_main_branch || 'main');
|
|
330
|
+
|
|
331
|
+
if (isBranching) {
|
|
332
|
+
agentRules.push(`WORKTREE REQUIRED: Create a git worktree BEFORE making ANY file edits. Command: git worktree add ../PROJECT-PERSONA-task -b feature/TASKID-desc ${ruleBaseBranch}`);
|
|
333
|
+
}
|
|
334
|
+
if (projectWorkflow && projectWorkflow !== 'none') {
|
|
335
|
+
agentRules.push(`FOLLOW GIT WORKFLOW: This project uses ${projectWorkflow}. Branch from ${ruleBaseBranch}. Do NOT commit directly to main or develop.`);
|
|
336
|
+
}
|
|
337
|
+
agentRules.push('COMPLETE TASKS: Always call complete_task() after creating a PR. This is mandatory.');
|
|
338
|
+
agentRules.push('REVIEW REQUIRED: All tasks must be reviewed by another agent before merging.');
|
|
339
|
+
|
|
340
|
+
result.AGENT_RULES = agentRules;
|
|
341
|
+
|
|
323
342
|
// Add next action at end - pending requests take priority over validation, then regular tasks
|
|
324
343
|
if (hasUrgentQuestions) {
|
|
325
344
|
const firstQuestion = data.URGENT_QUESTIONS?.requests?.[0] || data.pending_requests?.[0];
|
package/src/handlers/tasks.ts
CHANGED
|
@@ -77,11 +77,13 @@ const updateTaskSchema = {
|
|
|
77
77
|
worktree_path: { type: 'string' as const },
|
|
78
78
|
task_type: { type: 'string' as const, validate: createEnumValidator(VALID_TASK_TYPES) },
|
|
79
79
|
skip_worktree_requirement: { type: 'boolean' as const, default: false },
|
|
80
|
+
session_id: { type: 'string' as const },
|
|
80
81
|
};
|
|
81
82
|
|
|
82
83
|
const completeTaskSchema = {
|
|
83
84
|
task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
84
85
|
summary: { type: 'string' as const },
|
|
86
|
+
session_id: { type: 'string' as const },
|
|
85
87
|
};
|
|
86
88
|
|
|
87
89
|
const deleteTaskSchema = {
|
|
@@ -367,7 +369,7 @@ export const addTask: Handler = async (args, ctx) => {
|
|
|
367
369
|
};
|
|
368
370
|
|
|
369
371
|
export const updateTask: Handler = async (args, ctx) => {
|
|
370
|
-
const { task_id, title, description, priority, status, progress_percentage, progress_note, estimated_minutes, git_branch, worktree_path, task_type, skip_worktree_requirement } = parseArgs(args, updateTaskSchema);
|
|
372
|
+
const { task_id, title, description, priority, status, progress_percentage, progress_note, estimated_minutes, git_branch, worktree_path, task_type, skip_worktree_requirement, session_id: explicit_session_id } = parseArgs(args, updateTaskSchema);
|
|
371
373
|
const updates = { title, description, priority, status, progress_percentage, estimated_minutes, git_branch, worktree_path, task_type };
|
|
372
374
|
|
|
373
375
|
// Enforce worktree creation: require git_branch when marking task as in_progress
|
|
@@ -391,7 +393,7 @@ export const updateTask: Handler = async (args, ctx) => {
|
|
|
391
393
|
const response = await api.updateTask(task_id, {
|
|
392
394
|
...updates,
|
|
393
395
|
progress_note,
|
|
394
|
-
session_id: ctx.session.currentSessionId || undefined,
|
|
396
|
+
session_id: explicit_session_id || ctx.session.currentSessionId || undefined,
|
|
395
397
|
});
|
|
396
398
|
|
|
397
399
|
if (!response.ok) {
|
|
@@ -514,7 +516,7 @@ export const updateTask: Handler = async (args, ctx) => {
|
|
|
514
516
|
message: 'If investigation reveals the fix already exists but needs deployment:',
|
|
515
517
|
steps: [
|
|
516
518
|
'1. Add finding: add_finding(project_id, title: "Fix exists, awaits deployment", category: "other", severity: "info", description: "...", related_task_id: task_id)',
|
|
517
|
-
'2. Complete task: complete_task(task_id, summary: "Fix already exists in codebase (PR #
|
|
519
|
+
'2. Complete task: complete_task(task_id, summary: "Fix already exists in codebase (PR #{pr_number}). Needs deployment.")',
|
|
518
520
|
'3. Check deployment: check_deployment_status(project_id)',
|
|
519
521
|
'4. Request deployment if not pending: request_deployment(project_id, notes: "Includes fix for [issue]")',
|
|
520
522
|
],
|
|
@@ -526,12 +528,12 @@ export const updateTask: Handler = async (args, ctx) => {
|
|
|
526
528
|
};
|
|
527
529
|
|
|
528
530
|
export const completeTask: Handler = async (args, ctx) => {
|
|
529
|
-
const { task_id, summary } = parseArgs(args, completeTaskSchema);
|
|
531
|
+
const { task_id, summary, session_id: explicit_session_id } = parseArgs(args, completeTaskSchema);
|
|
530
532
|
|
|
531
533
|
const api = getApiClient();
|
|
532
534
|
const response = await api.completeTask(task_id, {
|
|
533
535
|
summary,
|
|
534
|
-
session_id: ctx.session.currentSessionId || undefined,
|
|
536
|
+
session_id: explicit_session_id || ctx.session.currentSessionId || undefined,
|
|
535
537
|
});
|
|
536
538
|
|
|
537
539
|
if (!response.ok) {
|
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
* agents follow proper workflows and maintain visibility.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
export const
|
|
9
|
+
export const VIBESCOPE_SECTION_START = '<!-- vibescope:start -->';
|
|
10
|
+
export const VIBESCOPE_SECTION_END = '<!-- vibescope:end -->';
|
|
11
|
+
|
|
12
|
+
export const AGENT_GUIDELINES_TEMPLATE = `${VIBESCOPE_SECTION_START}
|
|
13
|
+
# Vibescope Agent Guidelines
|
|
10
14
|
|
|
11
15
|
## Quick Start
|
|
12
16
|
|
|
@@ -183,6 +187,7 @@ claude mcp add vibescope npx @vibescope/mcp-server@latest \\
|
|
|
183
187
|
1. Copy \`.mcp.json.example\` to \`.mcp.json\`
|
|
184
188
|
2. Get \`VIBESCOPE_API_KEY\` from https://vibescope.dev/dashboard/settings
|
|
185
189
|
3. Restart Claude Code
|
|
190
|
+
${VIBESCOPE_SECTION_END}
|
|
186
191
|
`;
|
|
187
192
|
|
|
188
193
|
/**
|
|
@@ -217,14 +217,14 @@ add_finding(
|
|
|
217
217
|
title: "Fix exists but awaits deployment",
|
|
218
218
|
category: "other",
|
|
219
219
|
severity: "info",
|
|
220
|
-
description: "The fix for [issue] was implemented in PR #
|
|
220
|
+
description: "The fix for [issue] was implemented in PR #{pr_number} but hasn't been deployed yet.",
|
|
221
221
|
related_task_id: task_id
|
|
222
222
|
)
|
|
223
223
|
\`\`\`
|
|
224
224
|
|
|
225
225
|
2. **Complete the task** (investigation is done):
|
|
226
226
|
\`\`\`
|
|
227
|
-
complete_task(task_id, summary: "Fix already exists in codebase (PR #
|
|
227
|
+
complete_task(task_id, summary: "Fix already exists in codebase (PR #{pr_number}). Needs deployment to production.")
|
|
228
228
|
\`\`\`
|
|
229
229
|
|
|
230
230
|
3. **Request deployment** if not already pending:
|
package/src/tools/tasks.ts
CHANGED
|
@@ -299,6 +299,10 @@ For projects without git branching (trunk-based or none), use skip_worktree_requ
|
|
|
299
299
|
type: 'boolean',
|
|
300
300
|
description: 'Skip git_branch requirement for projects without branching workflows (trunk-based or none). Default: false',
|
|
301
301
|
},
|
|
302
|
+
session_id: {
|
|
303
|
+
type: 'string',
|
|
304
|
+
description: 'Session ID from start_work_session. Required for cloud agents using mcporter (session context is not preserved between calls). Links the task to your agent on the dashboard.',
|
|
305
|
+
},
|
|
302
306
|
},
|
|
303
307
|
required: ['task_id'],
|
|
304
308
|
},
|
|
@@ -329,6 +333,10 @@ The auto_continue: true flag in the response means you are expected to continue
|
|
|
329
333
|
type: 'string',
|
|
330
334
|
description: 'Brief summary of what was done. This is stored on the task as completion_summary and displayed when reviewing completed tasks.',
|
|
331
335
|
},
|
|
336
|
+
session_id: {
|
|
337
|
+
type: 'string',
|
|
338
|
+
description: 'Session ID from start_work_session. Required for cloud agents using mcporter.',
|
|
339
|
+
},
|
|
332
340
|
},
|
|
333
341
|
required: ['task_id'],
|
|
334
342
|
},
|