@vibescope/mcp-server 0.3.10 → 0.3.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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}
@@ -276,6 +276,22 @@ export const startWorkSession = async (args, ctx) => {
276
276
  result.directive = `SETUP REQUIRED: This is your first time connecting as a ${data.agent_setup.agent_type} agent. Follow the agent_setup instructions before starting work.`;
277
277
  }
278
278
  }
279
+ // Build top-level AGENT_RULES - critical rules agents must follow
280
+ const agentRules = [];
281
+ const projectWorkflow = data.project?.git_workflow;
282
+ const isBranching = projectWorkflow === 'git-flow' || projectWorkflow === 'github-flow';
283
+ const ruleBaseBranch = projectWorkflow === 'git-flow'
284
+ ? (data.project?.git_develop_branch || 'develop')
285
+ : (data.project?.git_main_branch || 'main');
286
+ if (isBranching) {
287
+ agentRules.push(`WORKTREE REQUIRED: Create a git worktree BEFORE making ANY file edits. Command: git worktree add ../PROJECT-PERSONA-task -b feature/TASKID-desc ${ruleBaseBranch}`);
288
+ }
289
+ if (projectWorkflow && projectWorkflow !== 'none') {
290
+ agentRules.push(`FOLLOW GIT WORKFLOW: This project uses ${projectWorkflow}. Branch from ${ruleBaseBranch}. Do NOT commit directly to main or develop.`);
291
+ }
292
+ agentRules.push('COMPLETE TASKS: Always call complete_task() after creating a PR. This is mandatory.');
293
+ agentRules.push('REVIEW REQUIRED: All tasks must be reviewed by another agent before merging.');
294
+ result.AGENT_RULES = agentRules;
279
295
  // Add next action at end - pending requests take priority over validation, then regular tasks
280
296
  if (hasUrgentQuestions) {
281
297
  const firstQuestion = data.URGENT_QUESTIONS?.requests?.[0] || data.pending_requests?.[0];
@@ -60,10 +60,12 @@ const updateTaskSchema = {
60
60
  worktree_path: { type: 'string' },
61
61
  task_type: { type: 'string', validate: createEnumValidator(VALID_TASK_TYPES) },
62
62
  skip_worktree_requirement: { type: 'boolean', default: false },
63
+ session_id: { type: 'string' },
63
64
  };
64
65
  const completeTaskSchema = {
65
66
  task_id: { type: 'string', required: true, validate: uuidValidator },
66
67
  summary: { type: 'string' },
68
+ session_id: { type: 'string' },
67
69
  };
68
70
  const deleteTaskSchema = {
69
71
  task_id: { type: 'string', required: true, validate: uuidValidator },
@@ -278,7 +280,7 @@ export const addTask = async (args, ctx) => {
278
280
  return { result };
279
281
  };
280
282
  export const updateTask = async (args, ctx) => {
281
- const { task_id, title, description, priority, status, progress_percentage, progress_note, estimated_minutes, git_branch, worktree_path, task_type, skip_worktree_requirement } = parseArgs(args, updateTaskSchema);
283
+ const { task_id, title, description, priority, status, progress_percentage, progress_note, estimated_minutes, git_branch, worktree_path, task_type, skip_worktree_requirement, session_id: explicit_session_id } = parseArgs(args, updateTaskSchema);
282
284
  const updates = { title, description, priority, status, progress_percentage, estimated_minutes, git_branch, worktree_path, task_type };
283
285
  // Enforce worktree creation: require git_branch when marking task as in_progress
284
286
  // This ensures multi-agent collaboration works properly with isolated worktrees
@@ -300,7 +302,7 @@ export const updateTask = async (args, ctx) => {
300
302
  const response = await api.updateTask(task_id, {
301
303
  ...updates,
302
304
  progress_note,
303
- session_id: ctx.session.currentSessionId || undefined,
305
+ session_id: explicit_session_id || ctx.session.currentSessionId || undefined,
304
306
  });
305
307
  if (!response.ok) {
306
308
  // Check for specific error types
@@ -416,7 +418,7 @@ export const updateTask = async (args, ctx) => {
416
418
  message: 'If investigation reveals the fix already exists but needs deployment:',
417
419
  steps: [
418
420
  '1. Add finding: add_finding(project_id, title: "Fix exists, awaits deployment", category: "other", severity: "info", description: "...", related_task_id: task_id)',
419
- '2. Complete task: complete_task(task_id, summary: "Fix already exists in codebase (PR #XXX). Needs deployment.")',
421
+ '2. Complete task: complete_task(task_id, summary: "Fix already exists in codebase (PR #{pr_number}). Needs deployment.")',
420
422
  '3. Check deployment: check_deployment_status(project_id)',
421
423
  '4. Request deployment if not pending: request_deployment(project_id, notes: "Includes fix for [issue]")',
422
424
  ],
@@ -426,11 +428,11 @@ export const updateTask = async (args, ctx) => {
426
428
  return { result };
427
429
  };
428
430
  export const completeTask = async (args, ctx) => {
429
- const { task_id, summary } = parseArgs(args, completeTaskSchema);
431
+ const { task_id, summary, session_id: explicit_session_id } = parseArgs(args, completeTaskSchema);
430
432
  const api = getApiClient();
431
433
  const response = await api.completeTask(task_id, {
432
434
  summary,
433
- session_id: ctx.session.currentSessionId || undefined,
435
+ session_id: explicit_session_id || ctx.session.currentSessionId || undefined,
434
436
  });
435
437
  if (!response.ok) {
436
438
  return { result: { error: response.error || 'Failed to complete task' }, isError: true };
@@ -5,7 +5,9 @@
5
5
  * in every project using Vibescope for agent tracking. These guidelines ensure
6
6
  * agents follow proper workflows and maintain visibility.
7
7
  */
8
- export declare const 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:
@@ -296,6 +296,10 @@ For projects without git branching (trunk-based or none), use skip_worktree_requ
296
296
  type: 'boolean',
297
297
  description: 'Skip git_branch requirement for projects without branching workflows (trunk-based or none). Default: false',
298
298
  },
299
+ session_id: {
300
+ type: 'string',
301
+ description: 'Session ID from start_work_session. Required for cloud agents using mcporter (session context is not preserved between calls). Links the task to your agent on the dashboard.',
302
+ },
299
303
  },
300
304
  required: ['task_id'],
301
305
  },
@@ -326,6 +330,10 @@ The auto_continue: true flag in the response means you are expected to continue
326
330
  type: 'string',
327
331
  description: 'Brief summary of what was done. This is stored on the task as completion_summary and displayed when reviewing completed tasks.',
328
332
  },
333
+ session_id: {
334
+ type: 'string',
335
+ description: 'Session ID from start_work_session. Required for cloud agents using mcporter.',
336
+ },
329
337
  },
330
338
  required: ['task_id'],
331
339
  },
package/docs/TOOLS.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  > Auto-generated from tool definitions. Do not edit manually.
4
4
  >
5
- > Generated: 2026-02-13
5
+ > Generated: 2026-02-15
6
6
  >
7
- > Total tools: 158
7
+ > Total tools: 159
8
8
 
9
9
  ## Table of Contents
10
10
 
@@ -2513,3 +2513,35 @@ Update the Vibescope MCP server to the latest version. Runs npm install to fetch
2513
2513
  | `global` | `boolean` | No | If true, update the global installation (npm install -g). If false, update locally. Default: true. |
2514
2514
 
2515
2515
  ---
2516
+
2517
+ ## Uncategorized
2518
+
2519
+ *Tools not yet assigned to a category*
2520
+
2521
+ ### update_agent_status
2522
+
2523
+ Report what you're currently doing. This updates the status message shown on the dashboard.
2524
+
2525
+ Call this at key milestones during boot and work:
2526
+
2527
+ - "Installing dependencies..."
2528
+
2529
+ - "Running start_work_session..."
2530
+
2531
+ - "Working on: <task title>"
2532
+
2533
+ - "Running tests..."
2534
+
2535
+ - "Committing changes..."
2536
+
2537
+ Keep messages short (under 80 chars). The dashboard shows this in real-time.
2538
+
2539
+ **Parameters:**
2540
+
2541
+ | Parameter | Type | Required | Description |
2542
+ |-----------|------|----------|-------------|
2543
+ | `status_message` | `string` | Yes | Short status message to display on dashboard (max 80 chars) |
2544
+ | `project_id` | `string` | No | Project UUID (optional if session has project context) |
2545
+ | `agent_name` | `string` | No | Agent name (used to find the spawned_agents record) |
2546
+
2547
+ ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibescope/mcp-server",
3
- "version": "0.3.10",
3
+ "version": "0.3.12",
4
4
  "description": "MCP server for Vibescope - AI project tracking tools",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -19,6 +19,20 @@
19
19
  "publishConfig": {
20
20
  "access": "public"
21
21
  },
22
+ "scripts": {
23
+ "build": "tsc",
24
+ "dev": "tsc --watch",
25
+ "test": "vitest run",
26
+ "test:watch": "vitest",
27
+ "docs:generate": "npx tsx scripts/generate-docs.ts --output=docs/TOOLS.md",
28
+ "docs:preview": "npx tsx scripts/generate-docs.ts",
29
+ "version:check": "npx tsx scripts/version-bump.ts --dry-run",
30
+ "version:bump": "npx tsx scripts/version-bump.ts",
31
+ "version:patch": "npx tsx scripts/version-bump.ts --patch",
32
+ "version:minor": "npx tsx scripts/version-bump.ts --minor",
33
+ "version:major": "npx tsx scripts/version-bump.ts --major",
34
+ "prepublishOnly": "npm run build"
35
+ },
22
36
  "keywords": [
23
37
  "mcp",
24
38
  "model-context-protocol",
@@ -35,18 +49,5 @@
35
49
  },
36
50
  "dependencies": {
37
51
  "@modelcontextprotocol/sdk": "^1.25.2"
38
- },
39
- "scripts": {
40
- "build": "tsc",
41
- "dev": "tsc --watch",
42
- "test": "vitest run",
43
- "test:watch": "vitest",
44
- "docs:generate": "npx tsx scripts/generate-docs.ts --output=docs/TOOLS.md",
45
- "docs:preview": "npx tsx scripts/generate-docs.ts",
46
- "version:check": "npx tsx scripts/version-bump.ts --dry-run",
47
- "version:bump": "npx tsx scripts/version-bump.ts",
48
- "version:patch": "npx tsx scripts/version-bump.ts --patch",
49
- "version:minor": "npx tsx scripts/version-bump.ts --minor",
50
- "version:major": "npx tsx scripts/version-bump.ts --major"
51
52
  }
52
- }
53
+ }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Findings API Methods
3
+ *
4
+ * Methods for audit findings and knowledge base management:
5
+ * - getFindings: List findings for a project
6
+ * - getFinding: Get a specific finding
7
+ * - addFinding: Create a new finding
8
+ * - updateFinding: Update an existing finding
9
+ * - deleteFinding: Delete a finding
10
+ * - getFindingsStats: Get findings statistics
11
+ * - queryKnowledgeBase: Search findings as knowledge base
12
+ */
13
+
14
+ import type { ApiResponse, RequestFn } from './types.js';
15
+
16
+ export interface FindingsMethods {
17
+ getFindings(projectId: string, params?: {
18
+ category?: string;
19
+ severity?: string;
20
+ status?: string;
21
+ summary_only?: boolean;
22
+ limit?: number;
23
+ offset?: number;
24
+ }): Promise<ApiResponse<{
25
+ findings: Array<{
26
+ id: string;
27
+ title: string;
28
+ description?: string;
29
+ category: string;
30
+ severity: string;
31
+ status: string;
32
+ created_at: string;
33
+ updated_at?: string;
34
+ related_task_id?: string;
35
+ }>;
36
+ total_count: number;
37
+ has_more: boolean;
38
+ }>>;
39
+
40
+ getFinding(findingId: string): Promise<ApiResponse<{
41
+ id: string;
42
+ title: string;
43
+ description?: string;
44
+ category: string;
45
+ severity: string;
46
+ status: string;
47
+ created_at: string;
48
+ updated_at?: string;
49
+ related_task_id?: string;
50
+ }>>;
51
+
52
+ addFinding(params: {
53
+ project_id: string;
54
+ title: string;
55
+ description?: string;
56
+ category?: string;
57
+ severity?: string;
58
+ related_task_id?: string;
59
+ }): Promise<ApiResponse<{
60
+ success: boolean;
61
+ finding_id: string;
62
+ }>>;
63
+
64
+ updateFinding(findingId: string, params: {
65
+ title?: string;
66
+ description?: string;
67
+ category?: string;
68
+ severity?: string;
69
+ status?: string;
70
+ related_task_id?: string;
71
+ }): Promise<ApiResponse<{
72
+ success: boolean;
73
+ finding_id: string;
74
+ }>>;
75
+
76
+ deleteFinding(findingId: string): Promise<ApiResponse<{
77
+ success: boolean;
78
+ finding_id: string;
79
+ }>>;
80
+
81
+ getFindingsStats(projectId: string): Promise<ApiResponse<{
82
+ total: number;
83
+ by_severity: Record<string, number>;
84
+ by_category: Record<string, number>;
85
+ by_status: Record<string, number>;
86
+ }>>;
87
+
88
+ queryKnowledgeBase(projectId: string, params: {
89
+ query: string;
90
+ category?: string;
91
+ severity?: string;
92
+ limit?: number;
93
+ }): Promise<ApiResponse<{
94
+ findings: Array<{
95
+ id: string;
96
+ title: string;
97
+ description?: string;
98
+ category: string;
99
+ severity: string;
100
+ relevance_score?: number;
101
+ }>;
102
+ total_count: number;
103
+ }>>;
104
+ }
105
+
106
+ export function createFindingsMethods(request: RequestFn): FindingsMethods {
107
+ return {
108
+ async getFindings(projectId, params) {
109
+ return request('/api/mcp/projects/{id}/findings', 'GET', {
110
+ path: { id: projectId },
111
+ query: params,
112
+ });
113
+ },
114
+
115
+ async getFinding(findingId) {
116
+ return request('/api/mcp/findings/{id}', 'GET', {
117
+ path: { id: findingId },
118
+ });
119
+ },
120
+
121
+ async addFinding(params) {
122
+ return request('/api/mcp/projects/{id}/findings', 'POST', {
123
+ path: { id: params.project_id },
124
+ body: params,
125
+ });
126
+ },
127
+
128
+ async updateFinding(findingId, params) {
129
+ return request('/api/mcp/findings/{id}', 'PATCH', {
130
+ path: { id: findingId },
131
+ body: params,
132
+ });
133
+ },
134
+
135
+ async deleteFinding(findingId) {
136
+ return request('/api/mcp/findings/{id}', 'DELETE', {
137
+ path: { id: findingId },
138
+ });
139
+ },
140
+
141
+ async getFindingsStats(projectId) {
142
+ return request('/api/mcp/projects/{id}/findings/stats', 'GET', {
143
+ path: { id: projectId },
144
+ });
145
+ },
146
+
147
+ async queryKnowledgeBase(projectId, params) {
148
+ return request('/api/mcp/projects/{id}/findings/query', 'POST', {
149
+ path: { id: projectId },
150
+ body: params,
151
+ });
152
+ },
153
+ };
154
+ }
@@ -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}
@@ -320,6 +320,25 @@ export const startWorkSession: Handler = async (args, ctx) => {
320
320
  }
321
321
  }
322
322
 
323
+ // Build top-level AGENT_RULES - critical rules agents must follow
324
+ const agentRules: string[] = [];
325
+ const projectWorkflow = data.project?.git_workflow;
326
+ const isBranching = projectWorkflow === 'git-flow' || projectWorkflow === 'github-flow';
327
+ const ruleBaseBranch = projectWorkflow === 'git-flow'
328
+ ? (data.project?.git_develop_branch || 'develop')
329
+ : (data.project?.git_main_branch || 'main');
330
+
331
+ if (isBranching) {
332
+ agentRules.push(`WORKTREE REQUIRED: Create a git worktree BEFORE making ANY file edits. Command: git worktree add ../PROJECT-PERSONA-task -b feature/TASKID-desc ${ruleBaseBranch}`);
333
+ }
334
+ if (projectWorkflow && projectWorkflow !== 'none') {
335
+ agentRules.push(`FOLLOW GIT WORKFLOW: This project uses ${projectWorkflow}. Branch from ${ruleBaseBranch}. Do NOT commit directly to main or develop.`);
336
+ }
337
+ agentRules.push('COMPLETE TASKS: Always call complete_task() after creating a PR. This is mandatory.');
338
+ agentRules.push('REVIEW REQUIRED: All tasks must be reviewed by another agent before merging.');
339
+
340
+ result.AGENT_RULES = agentRules;
341
+
323
342
  // Add next action at end - pending requests take priority over validation, then regular tasks
324
343
  if (hasUrgentQuestions) {
325
344
  const firstQuestion = data.URGENT_QUESTIONS?.requests?.[0] || data.pending_requests?.[0];
@@ -77,11 +77,13 @@ const updateTaskSchema = {
77
77
  worktree_path: { type: 'string' as const },
78
78
  task_type: { type: 'string' as const, validate: createEnumValidator(VALID_TASK_TYPES) },
79
79
  skip_worktree_requirement: { type: 'boolean' as const, default: false },
80
+ session_id: { type: 'string' as const },
80
81
  };
81
82
 
82
83
  const completeTaskSchema = {
83
84
  task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
84
85
  summary: { type: 'string' as const },
86
+ session_id: { type: 'string' as const },
85
87
  };
86
88
 
87
89
  const deleteTaskSchema = {
@@ -367,7 +369,7 @@ export const addTask: Handler = async (args, ctx) => {
367
369
  };
368
370
 
369
371
  export const updateTask: Handler = async (args, ctx) => {
370
- const { task_id, title, description, priority, status, progress_percentage, progress_note, estimated_minutes, git_branch, worktree_path, task_type, skip_worktree_requirement } = parseArgs(args, updateTaskSchema);
372
+ const { task_id, title, description, priority, status, progress_percentage, progress_note, estimated_minutes, git_branch, worktree_path, task_type, skip_worktree_requirement, session_id: explicit_session_id } = parseArgs(args, updateTaskSchema);
371
373
  const updates = { title, description, priority, status, progress_percentage, estimated_minutes, git_branch, worktree_path, task_type };
372
374
 
373
375
  // Enforce worktree creation: require git_branch when marking task as in_progress
@@ -391,7 +393,7 @@ export const updateTask: Handler = async (args, ctx) => {
391
393
  const response = await api.updateTask(task_id, {
392
394
  ...updates,
393
395
  progress_note,
394
- session_id: ctx.session.currentSessionId || undefined,
396
+ session_id: explicit_session_id || ctx.session.currentSessionId || undefined,
395
397
  });
396
398
 
397
399
  if (!response.ok) {
@@ -514,7 +516,7 @@ export const updateTask: Handler = async (args, ctx) => {
514
516
  message: 'If investigation reveals the fix already exists but needs deployment:',
515
517
  steps: [
516
518
  '1. Add finding: add_finding(project_id, title: "Fix exists, awaits deployment", category: "other", severity: "info", description: "...", related_task_id: task_id)',
517
- '2. Complete task: complete_task(task_id, summary: "Fix already exists in codebase (PR #XXX). Needs deployment.")',
519
+ '2. Complete task: complete_task(task_id, summary: "Fix already exists in codebase (PR #{pr_number}). Needs deployment.")',
518
520
  '3. Check deployment: check_deployment_status(project_id)',
519
521
  '4. Request deployment if not pending: request_deployment(project_id, notes: "Includes fix for [issue]")',
520
522
  ],
@@ -526,12 +528,12 @@ export const updateTask: Handler = async (args, ctx) => {
526
528
  };
527
529
 
528
530
  export const completeTask: Handler = async (args, ctx) => {
529
- const { task_id, summary } = parseArgs(args, completeTaskSchema);
531
+ const { task_id, summary, session_id: explicit_session_id } = parseArgs(args, completeTaskSchema);
530
532
 
531
533
  const api = getApiClient();
532
534
  const response = await api.completeTask(task_id, {
533
535
  summary,
534
- session_id: ctx.session.currentSessionId || undefined,
536
+ session_id: explicit_session_id || ctx.session.currentSessionId || undefined,
535
537
  });
536
538
 
537
539
  if (!response.ok) {
@@ -6,7 +6,11 @@
6
6
  * agents follow proper workflows and maintain visibility.
7
7
  */
8
8
 
9
- export const 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:
@@ -299,6 +299,10 @@ For projects without git branching (trunk-based or none), use skip_worktree_requ
299
299
  type: 'boolean',
300
300
  description: 'Skip git_branch requirement for projects without branching workflows (trunk-based or none). Default: false',
301
301
  },
302
+ session_id: {
303
+ type: 'string',
304
+ description: 'Session ID from start_work_session. Required for cloud agents using mcporter (session context is not preserved between calls). Links the task to your agent on the dashboard.',
305
+ },
302
306
  },
303
307
  required: ['task_id'],
304
308
  },
@@ -329,6 +333,10 @@ The auto_continue: true flag in the response means you are expected to continue
329
333
  type: 'string',
330
334
  description: 'Brief summary of what was done. This is stored on the task as completion_summary and displayed when reviewing completed tasks.',
331
335
  },
336
+ session_id: {
337
+ type: 'string',
338
+ description: 'Session ID from start_work_session. Required for cloud agents using mcporter.',
339
+ },
332
340
  },
333
341
  required: ['task_id'],
334
342
  },