@vibescope/mcp-server 0.3.11 → 0.3.13
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 +17 -0
- package/dist/handlers/tasks.js +1 -1
- 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/docs/TOOLS.md +3 -1
- package/package.json +1 -1
- 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 +20 -0
- package/src/handlers/tasks.ts +1 -1
- package/src/templates/agent-guidelines.ts +6 -1
- package/src/templates/help-content.ts +2 -2
|
@@ -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
|
@@ -148,6 +148,7 @@ export const startWorkSession = async (args, ctx) => {
|
|
|
148
148
|
result.auto_continue = true;
|
|
149
149
|
// Session info
|
|
150
150
|
result.session_id = data.session_id;
|
|
151
|
+
result.IMPORTANT_session_id_reminder = `Save this session_id ("${data.session_id}") and pass it on EVERY update_task and complete_task call. Without it, the dashboard shows "Agent" instead of your name.`;
|
|
151
152
|
result.persona = data.persona;
|
|
152
153
|
result.role = data.role;
|
|
153
154
|
result.project = data.project;
|
|
@@ -276,6 +277,22 @@ export const startWorkSession = async (args, ctx) => {
|
|
|
276
277
|
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
278
|
}
|
|
278
279
|
}
|
|
280
|
+
// Build top-level AGENT_RULES - critical rules agents must follow
|
|
281
|
+
const agentRules = [];
|
|
282
|
+
const projectWorkflow = data.project?.git_workflow;
|
|
283
|
+
const isBranching = projectWorkflow === 'git-flow' || projectWorkflow === 'github-flow';
|
|
284
|
+
const ruleBaseBranch = projectWorkflow === 'git-flow'
|
|
285
|
+
? (data.project?.git_develop_branch || 'develop')
|
|
286
|
+
: (data.project?.git_main_branch || 'main');
|
|
287
|
+
if (isBranching) {
|
|
288
|
+
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}`);
|
|
289
|
+
}
|
|
290
|
+
if (projectWorkflow && projectWorkflow !== 'none') {
|
|
291
|
+
agentRules.push(`FOLLOW GIT WORKFLOW: This project uses ${projectWorkflow}. Branch from ${ruleBaseBranch}. Do NOT commit directly to main or develop.`);
|
|
292
|
+
}
|
|
293
|
+
agentRules.push('COMPLETE TASKS: Always call complete_task() after creating a PR. This is mandatory.');
|
|
294
|
+
agentRules.push('REVIEW REQUIRED: All tasks must be reviewed by another agent before merging.');
|
|
295
|
+
result.AGENT_RULES = agentRules;
|
|
279
296
|
// Add next action at end - pending requests take priority over validation, then regular tasks
|
|
280
297
|
if (hasUrgentQuestions) {
|
|
281
298
|
const firstQuestion = data.URGENT_QUESTIONS?.requests?.[0] || data.pending_requests?.[0];
|
package/dist/handlers/tasks.js
CHANGED
|
@@ -418,7 +418,7 @@ export const updateTask = async (args, ctx) => {
|
|
|
418
418
|
message: 'If investigation reveals the fix already exists but needs deployment:',
|
|
419
419
|
steps: [
|
|
420
420
|
'1. Add finding: add_finding(project_id, title: "Fix exists, awaits deployment", category: "other", severity: "info", description: "...", related_task_id: task_id)',
|
|
421
|
-
'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.")',
|
|
422
422
|
'3. Check deployment: check_deployment_status(project_id)',
|
|
423
423
|
'4. Request deployment if not pending: request_deployment(project_id, notes: "Includes fix for [issue]")',
|
|
424
424
|
],
|
|
@@ -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/docs/TOOLS.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Auto-generated from tool definitions. Do not edit manually.
|
|
4
4
|
>
|
|
5
|
-
> Generated: 2026-02-
|
|
5
|
+
> Generated: 2026-02-18
|
|
6
6
|
>
|
|
7
7
|
> Total tools: 159
|
|
8
8
|
|
|
@@ -416,6 +416,7 @@ For projects without git branching (trunk-based or none), use skip_worktree_requ
|
|
|
416
416
|
| `worktree_hostname` | `string` | No | Machine hostname where worktree was created (os.hostname()). Required with worktree_path to enable machine-aware cleanup. |
|
|
417
417
|
| `model_capability` | `"haiku" | "sonnet" | "opus"` | No | Recommended model capability: haiku (simple tasks), sonnet (standard), opus (complex reasoning) |
|
|
418
418
|
| `skip_worktree_requirement` | `boolean` | No | Skip git_branch requirement for projects without branching workflows (trunk-based or none). Default: false |
|
|
419
|
+
| `session_id` | `string` | No | 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. |
|
|
419
420
|
|
|
420
421
|
---
|
|
421
422
|
|
|
@@ -447,6 +448,7 @@ The auto_continue: true flag in the response means you are expected to continue
|
|
|
447
448
|
|-----------|------|----------|-------------|
|
|
448
449
|
| `task_id` | `string` | Yes | Task UUID |
|
|
449
450
|
| `summary` | `string` | No | Brief summary of what was done. This is stored on the task as completion_summary and displayed when reviewing completed tasks. |
|
|
451
|
+
| `session_id` | `string` | No | Session ID from start_work_session. Required for cloud agents using mcporter. |
|
|
450
452
|
|
|
451
453
|
---
|
|
452
454
|
|
package/package.json
CHANGED
|
@@ -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
|
@@ -179,6 +179,7 @@ export const startWorkSession: Handler = async (args, ctx) => {
|
|
|
179
179
|
|
|
180
180
|
// Session info
|
|
181
181
|
result.session_id = data.session_id;
|
|
182
|
+
result.IMPORTANT_session_id_reminder = `Save this session_id ("${data.session_id}") and pass it on EVERY update_task and complete_task call. Without it, the dashboard shows "Agent" instead of your name.`;
|
|
182
183
|
result.persona = data.persona;
|
|
183
184
|
result.role = data.role;
|
|
184
185
|
result.project = data.project;
|
|
@@ -320,6 +321,25 @@ export const startWorkSession: Handler = async (args, ctx) => {
|
|
|
320
321
|
}
|
|
321
322
|
}
|
|
322
323
|
|
|
324
|
+
// Build top-level AGENT_RULES - critical rules agents must follow
|
|
325
|
+
const agentRules: string[] = [];
|
|
326
|
+
const projectWorkflow = data.project?.git_workflow;
|
|
327
|
+
const isBranching = projectWorkflow === 'git-flow' || projectWorkflow === 'github-flow';
|
|
328
|
+
const ruleBaseBranch = projectWorkflow === 'git-flow'
|
|
329
|
+
? (data.project?.git_develop_branch || 'develop')
|
|
330
|
+
: (data.project?.git_main_branch || 'main');
|
|
331
|
+
|
|
332
|
+
if (isBranching) {
|
|
333
|
+
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}`);
|
|
334
|
+
}
|
|
335
|
+
if (projectWorkflow && projectWorkflow !== 'none') {
|
|
336
|
+
agentRules.push(`FOLLOW GIT WORKFLOW: This project uses ${projectWorkflow}. Branch from ${ruleBaseBranch}. Do NOT commit directly to main or develop.`);
|
|
337
|
+
}
|
|
338
|
+
agentRules.push('COMPLETE TASKS: Always call complete_task() after creating a PR. This is mandatory.');
|
|
339
|
+
agentRules.push('REVIEW REQUIRED: All tasks must be reviewed by another agent before merging.');
|
|
340
|
+
|
|
341
|
+
result.AGENT_RULES = agentRules;
|
|
342
|
+
|
|
323
343
|
// Add next action at end - pending requests take priority over validation, then regular tasks
|
|
324
344
|
if (hasUrgentQuestions) {
|
|
325
345
|
const firstQuestion = data.URGENT_QUESTIONS?.requests?.[0] || data.pending_requests?.[0];
|
package/src/handlers/tasks.ts
CHANGED
|
@@ -516,7 +516,7 @@ export const updateTask: Handler = async (args, ctx) => {
|
|
|
516
516
|
message: 'If investigation reveals the fix already exists but needs deployment:',
|
|
517
517
|
steps: [
|
|
518
518
|
'1. Add finding: add_finding(project_id, title: "Fix exists, awaits deployment", category: "other", severity: "info", description: "...", related_task_id: task_id)',
|
|
519
|
-
'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.")',
|
|
520
520
|
'3. Check deployment: check_deployment_status(project_id)',
|
|
521
521
|
'4. Request deployment if not pending: request_deployment(project_id, notes: "Includes fix for [issue]")',
|
|
522
522
|
],
|
|
@@ -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:
|