@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.
@@ -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?: string;
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;
@@ -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}
@@ -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];
@@ -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 #XXX). Needs deployment.")',
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 AGENT_GUIDELINES_TEMPLATE = "# 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";
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 AGENT_GUIDELINES_TEMPLATE = `# Vibescope Agent Guidelines
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 #XXX but hasn't been deployed yet.",
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 #XXX). Needs deployment to production.")
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-15
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibescope/mcp-server",
3
- "version": "0.3.11",
3
+ "version": "0.3.13",
4
4
  "description": "MCP server for Vibescope - AI project tracking tools",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -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
+ }
@@ -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}
@@ -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];
@@ -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 #XXX). Needs deployment.")',
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 AGENT_GUIDELINES_TEMPLATE = `# Vibescope Agent Guidelines
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 #XXX but hasn't been deployed yet.",
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 #XXX). Needs deployment to production.")
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: