@vibescope/mcp-server 0.1.0 → 0.2.0

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.
Files changed (39) hide show
  1. package/README.md +1 -1
  2. package/dist/api-client.d.ts +56 -1
  3. package/dist/api-client.js +17 -2
  4. package/dist/handlers/bodies-of-work.js +3 -2
  5. package/dist/handlers/deployment.js +3 -2
  6. package/dist/handlers/discovery.d.ts +3 -0
  7. package/dist/handlers/discovery.js +20 -652
  8. package/dist/handlers/fallback.js +18 -9
  9. package/dist/handlers/findings.d.ts +8 -1
  10. package/dist/handlers/findings.js +24 -3
  11. package/dist/handlers/session.js +23 -8
  12. package/dist/handlers/sprints.js +3 -2
  13. package/dist/handlers/tasks.js +22 -1
  14. package/dist/handlers/tool-docs.d.ts +4 -3
  15. package/dist/handlers/tool-docs.js +252 -5
  16. package/dist/handlers/validation.js +13 -1
  17. package/dist/index.js +25 -7
  18. package/dist/tools.js +30 -4
  19. package/package.json +1 -1
  20. package/src/api-client.ts +72 -2
  21. package/src/handlers/__test-setup__.ts +5 -0
  22. package/src/handlers/bodies-of-work.ts +27 -11
  23. package/src/handlers/deployment.ts +4 -2
  24. package/src/handlers/discovery.ts +23 -740
  25. package/src/handlers/fallback.test.ts +78 -0
  26. package/src/handlers/fallback.ts +20 -9
  27. package/src/handlers/findings.test.ts +129 -2
  28. package/src/handlers/findings.ts +32 -3
  29. package/src/handlers/session.test.ts +37 -2
  30. package/src/handlers/session.ts +29 -8
  31. package/src/handlers/sprints.ts +19 -6
  32. package/src/handlers/tasks.test.ts +61 -0
  33. package/src/handlers/tasks.ts +26 -1
  34. package/src/handlers/tool-docs.ts +1024 -0
  35. package/src/handlers/validation.test.ts +52 -0
  36. package/src/handlers/validation.ts +14 -1
  37. package/src/index.ts +25 -7
  38. package/src/tools.ts +30 -4
  39. package/src/knowledge.ts +0 -230
@@ -40,16 +40,25 @@ export const startFallbackActivity = async (args, ctx) => {
40
40
  }
41
41
  // Get the activity details for the response
42
42
  const activityInfo = FALLBACK_ACTIVITIES.find((a) => a.activity === activity);
43
- return {
44
- result: {
45
- success: true,
46
- activity,
47
- title: activityInfo?.title || activity,
48
- description: activityInfo?.description || '',
49
- prompt: activityInfo?.prompt || '',
50
- message: response.data?.message || `Started fallback activity: ${activityInfo?.title || activity}`,
51
- },
43
+ const result = {
44
+ success: true,
45
+ activity,
46
+ title: activityInfo?.title || activity,
47
+ description: activityInfo?.description || '',
48
+ prompt: activityInfo?.prompt || '',
49
+ message: response.data?.message || `Started fallback activity: ${activityInfo?.title || activity}`,
52
50
  };
51
+ // Pass through worktree guidance if provided
52
+ if (response.data?.git_workflow) {
53
+ result.git_workflow = response.data.git_workflow;
54
+ }
55
+ if (response.data?.worktree_setup) {
56
+ result.worktree_setup = response.data.worktree_setup;
57
+ }
58
+ if (response.data?.next_step) {
59
+ result.next_step = response.data.next_step;
60
+ }
61
+ return { result };
53
62
  };
54
63
  export const stopFallbackActivity = async (args, ctx) => {
55
64
  const { project_id, summary } = args;
@@ -3,13 +3,20 @@
3
3
  *
4
4
  * Handles audit findings and knowledge base:
5
5
  * - add_finding
6
- * - get_findings
6
+ * - get_findings (supports summary_only for reduced tokens)
7
+ * - get_findings_stats (aggregate counts for minimal tokens)
7
8
  * - update_finding
8
9
  * - delete_finding
9
10
  */
10
11
  import type { Handler, HandlerRegistry } from './types.js';
11
12
  export declare const addFinding: Handler;
12
13
  export declare const getFindings: Handler;
14
+ /**
15
+ * Get aggregate statistics about findings for a project.
16
+ * Returns counts by category, severity, and status without the actual finding data.
17
+ * This is much more token-efficient than get_findings for understanding the overall state.
18
+ */
19
+ export declare const getFindingsStats: Handler;
13
20
  export declare const updateFinding: Handler;
14
21
  export declare const deleteFinding: Handler;
15
22
  /**
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * Handles audit findings and knowledge base:
5
5
  * - add_finding
6
- * - get_findings
6
+ * - get_findings (supports summary_only for reduced tokens)
7
+ * - get_findings_stats (aggregate counts for minimal tokens)
7
8
  * - update_finding
8
9
  * - delete_finding
9
10
  */
@@ -32,7 +33,7 @@ export const addFinding = async (args, ctx) => {
32
33
  return { result: response.data };
33
34
  };
34
35
  export const getFindings = async (args, ctx) => {
35
- const { project_id, category, severity, status, limit = 50, offset = 0, search_query } = args;
36
+ const { project_id, category, severity, status, limit = 50, offset = 0, search_query, summary_only = false } = args;
36
37
  validateRequired(project_id, 'project_id');
37
38
  validateUUID(project_id, 'project_id');
38
39
  const apiClient = getApiClient();
@@ -40,13 +41,32 @@ export const getFindings = async (args, ctx) => {
40
41
  category,
41
42
  severity,
42
43
  status,
43
- limit
44
+ limit,
45
+ offset,
46
+ search_query,
47
+ summary_only
44
48
  });
45
49
  if (!response.ok) {
46
50
  throw new Error(response.error || 'Failed to get findings');
47
51
  }
48
52
  return { result: response.data };
49
53
  };
54
+ /**
55
+ * Get aggregate statistics about findings for a project.
56
+ * Returns counts by category, severity, and status without the actual finding data.
57
+ * This is much more token-efficient than get_findings for understanding the overall state.
58
+ */
59
+ export const getFindingsStats = async (args, ctx) => {
60
+ const { project_id } = args;
61
+ validateRequired(project_id, 'project_id');
62
+ validateUUID(project_id, 'project_id');
63
+ const apiClient = getApiClient();
64
+ const response = await apiClient.getFindingsStats(project_id);
65
+ if (!response.ok) {
66
+ throw new Error(response.error || 'Failed to get findings stats');
67
+ }
68
+ return { result: response.data };
69
+ };
50
70
  export const updateFinding = async (args, ctx) => {
51
71
  const { finding_id, status, resolution_note, title, description, severity } = args;
52
72
  validateRequired(finding_id, 'finding_id');
@@ -81,6 +101,7 @@ export const deleteFinding = async (args, ctx) => {
81
101
  export const findingHandlers = {
82
102
  add_finding: addFinding,
83
103
  get_findings: getFindings,
104
+ get_findings_stats: getFindingsStats,
84
105
  update_finding: updateFinding,
85
106
  delete_finding: deleteFinding,
86
107
  };
@@ -8,7 +8,6 @@
8
8
  * - get_help
9
9
  * - get_token_usage
10
10
  */
11
- import { KNOWLEDGE_BASE } from '../knowledge.js';
12
11
  import { getApiClient } from '../api-client.js';
13
12
  export const startWorkSession = async (args, ctx) => {
14
13
  const { project_id, git_url, mode = 'lite', model, role = 'developer' } = args;
@@ -114,7 +113,7 @@ export const startWorkSession = async (args, ctx) => {
114
113
  return { result };
115
114
  };
116
115
  export const heartbeat = async (args, ctx) => {
117
- const { session_id } = args;
116
+ const { session_id, current_worktree_path } = args;
118
117
  const { session } = ctx;
119
118
  const targetSession = session_id || session.currentSessionId;
120
119
  if (!targetSession) {
@@ -125,8 +124,10 @@ export const heartbeat = async (args, ctx) => {
125
124
  };
126
125
  }
127
126
  const apiClient = getApiClient();
128
- // Send heartbeat
129
- const heartbeatResponse = await apiClient.heartbeat(targetSession);
127
+ // Send heartbeat with optional worktree path
128
+ const heartbeatResponse = await apiClient.heartbeat(targetSession, {
129
+ current_worktree_path,
130
+ });
130
131
  if (!heartbeatResponse.ok) {
131
132
  return {
132
133
  result: {
@@ -205,16 +206,30 @@ export const endWorkSession = async (args, ctx) => {
205
206
  };
206
207
  export const getHelp = async (args, _ctx) => {
207
208
  const { topic } = args;
208
- const content = KNOWLEDGE_BASE[topic];
209
- if (!content) {
209
+ const apiClient = getApiClient();
210
+ const response = await apiClient.getHelpTopic(topic);
211
+ if (!response.ok) {
212
+ // If database fetch fails, return error
213
+ return {
214
+ result: {
215
+ error: response.error || `Failed to fetch help topic: ${topic}`,
216
+ },
217
+ };
218
+ }
219
+ if (!response.data) {
220
+ // Topic not found - fetch available topics
221
+ const topicsResponse = await apiClient.getHelpTopics();
222
+ const available = topicsResponse.ok && topicsResponse.data
223
+ ? topicsResponse.data.map(t => t.slug)
224
+ : ['getting_started', 'tasks', 'validation', 'deployment', 'git', 'blockers', 'milestones', 'fallback', 'session', 'tokens', 'sprints', 'topics'];
210
225
  return {
211
226
  result: {
212
227
  error: `Unknown topic: ${topic}`,
213
- available: Object.keys(KNOWLEDGE_BASE),
228
+ available,
214
229
  },
215
230
  };
216
231
  }
217
- return { result: { topic, content } };
232
+ return { result: { topic, content: response.data.content } };
218
233
  };
219
234
  // Model pricing rates (USD per 1M tokens)
220
235
  const MODEL_PRICING = {
@@ -117,11 +117,12 @@ export const updateSprint = async (args, ctx) => {
117
117
  return { result: { success: true, sprint_id } };
118
118
  };
119
119
  export const getSprint = async (args, ctx) => {
120
- const { sprint_id } = args;
120
+ const { sprint_id, summary_only = false } = args;
121
121
  validateRequired(sprint_id, 'sprint_id');
122
122
  validateUUID(sprint_id, 'sprint_id');
123
123
  const apiClient = getApiClient();
124
- const response = await apiClient.proxy('get_sprint', { sprint_id });
124
+ // Response type varies based on summary_only
125
+ const response = await apiClient.proxy('get_sprint', { sprint_id, summary_only });
125
126
  if (!response.ok) {
126
127
  throw new Error(`Failed to get sprint: ${response.error}`);
127
128
  }
@@ -210,7 +210,24 @@ export const updateTask = async (args, ctx) => {
210
210
  }
211
211
  throw new Error(`Failed to update task: ${response.error}`);
212
212
  }
213
- return { result: { success: true, task_id } };
213
+ // Build result - include git workflow info when transitioning to in_progress
214
+ const data = response.data;
215
+ const result = { success: true, task_id };
216
+ if (data?.git_workflow) {
217
+ result.git_workflow = data.git_workflow;
218
+ }
219
+ if (data?.worktree_setup) {
220
+ result.worktree_setup = data.worktree_setup;
221
+ }
222
+ if (data?.next_step) {
223
+ result.next_step = data.next_step;
224
+ }
225
+ // Warn if transitioning to in_progress without git_branch
226
+ if (updates.status === 'in_progress' && !updates.git_branch) {
227
+ result.warning = 'git_branch not set. For multi-agent collaboration, set git_branch when marking in_progress to track your worktree.';
228
+ result.hint = 'Call update_task again with git_branch parameter after creating your worktree.';
229
+ }
230
+ return { result };
214
231
  };
215
232
  export const completeTask = async (args, ctx) => {
216
233
  const { task_id, summary } = args;
@@ -239,6 +256,10 @@ export const completeTask = async (args, ctx) => {
239
256
  if (data.context) {
240
257
  result.context = data.context;
241
258
  }
259
+ // Pass through warnings (e.g., missing git_branch)
260
+ if (data.warnings) {
261
+ result.warnings = data.warnings;
262
+ }
242
263
  // Git workflow instructions are already in API response but we need to fetch
243
264
  // task details if we want to include them (API should return these)
244
265
  result.next_action = data.next_action;
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * Tool Documentation
3
3
  *
4
- * This file contains detailed documentation for all MCP tools.
5
- * It is loaded dynamically by get_tool_info to reduce memory footprint
6
- * when tool documentation is not needed.
4
+ * Externalized documentation for all MCP tools.
5
+ * This file is lazy-loaded by get_tool_info to save tokens.
6
+ *
7
+ * Token savings: ~8,000 tokens per schema load when this isn't bundled.
7
8
  */
8
9
  export declare const TOOL_INFO: Record<string, string>;
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * Tool Documentation
3
3
  *
4
- * This file contains detailed documentation for all MCP tools.
5
- * It is loaded dynamically by get_tool_info to reduce memory footprint
6
- * when tool documentation is not needed.
4
+ * Externalized documentation for all MCP tools.
5
+ * This file is lazy-loaded by get_tool_info to save tokens.
6
+ *
7
+ * Token savings: ~8,000 tokens per schema load when this isn't bundled.
7
8
  */
8
9
  export const TOOL_INFO = {
9
10
  start_work_session: `# start_work_session
@@ -32,7 +33,8 @@ Get token usage statistics for current session.
32
33
  Send heartbeat to maintain active status. Call every 30-60 seconds.
33
34
 
34
35
  **Parameters:**
35
- - session_id (optional): Uses current session if not provided`,
36
+ - session_id (optional): Uses current session if not provided
37
+ - current_worktree_path (optional): Report your current git worktree path (e.g., "../project-task-abc123")`,
36
38
  end_work_session: `# end_work_session
37
39
  End session and release claimed tasks.
38
40
 
@@ -629,7 +631,252 @@ Get cost breakdown by task for a project.
629
631
  - limit: Max tasks to return (default: 20)
630
632
 
631
633
  **Returns:** Tasks sorted by estimated cost with model breakdown`,
632
- // Knowledge base tools
634
+ // Subtasks
635
+ add_subtask: `# add_subtask
636
+ Add a subtask to break down a larger task.
637
+
638
+ **Parameters:**
639
+ - parent_task_id (required): UUID of the parent task
640
+ - title (required): Subtask title
641
+ - description (optional): Detailed description
642
+ - priority (optional): 1-5 (defaults to parent priority)
643
+ - estimated_minutes (optional): Time estimate
644
+
645
+ **Note:** Max depth is 1 (subtasks cannot have their own subtasks).`,
646
+ get_subtasks: `# get_subtasks
647
+ Get subtasks for a parent task.
648
+
649
+ **Parameters:**
650
+ - parent_task_id (required): UUID of the parent task
651
+ - status (optional): Filter by status
652
+
653
+ **Returns:** Subtasks with aggregate completion stats.`,
654
+ // Bodies of work
655
+ create_body_of_work: `# create_body_of_work
656
+ Create a new body of work to group tasks into phases.
657
+
658
+ **Parameters:**
659
+ - project_id (required): Project UUID
660
+ - title (required): Title for the body of work
661
+ - description (optional): Description
662
+ - auto_deploy_on_completion (optional): Auto-deploy when all tasks complete (default: false)
663
+ - deploy_environment (optional): Target environment (default: production)
664
+ - deploy_version_bump (optional): Version bump (default: minor)
665
+ - deploy_trigger (optional): When to trigger auto-deploy (default: all_completed_validated)`,
666
+ update_body_of_work: `# update_body_of_work
667
+ Update a body of work's settings.
668
+
669
+ **Parameters:**
670
+ - body_of_work_id (required): Body of work UUID
671
+ - title, description (optional)
672
+ - auto_deploy_on_completion, deploy_environment, deploy_version_bump, deploy_trigger (optional)`,
673
+ get_body_of_work: `# get_body_of_work
674
+ Get a body of work with all its tasks organized by phase.
675
+
676
+ **Parameters:**
677
+ - body_of_work_id (required): Body of work UUID
678
+
679
+ **Returns:** Body of work with tasks grouped by pre/core/post phases.`,
680
+ get_bodies_of_work: `# get_bodies_of_work
681
+ List bodies of work for a project.
682
+
683
+ **Parameters:**
684
+ - project_id (required): Project UUID
685
+ - status (optional): Filter by status (draft, active, completed, cancelled)
686
+ - limit (optional): Max items (default 50)`,
687
+ delete_body_of_work: `# delete_body_of_work
688
+ Delete a body of work. Tasks are preserved but no longer grouped.
689
+
690
+ **Parameters:**
691
+ - body_of_work_id (required): Body of work UUID`,
692
+ add_task_to_body_of_work: `# add_task_to_body_of_work
693
+ Add a task to a body of work in a specific phase.
694
+
695
+ **Parameters:**
696
+ - body_of_work_id (required): Body of work UUID
697
+ - task_id (required): Task UUID to add
698
+ - phase (optional): pre, core, or post (default: core)
699
+ - order_index (optional): Order within phase`,
700
+ remove_task_from_body_of_work: `# remove_task_from_body_of_work
701
+ Remove a task from its body of work.
702
+
703
+ **Parameters:**
704
+ - task_id (required): Task UUID to remove
705
+
706
+ **Note:** The task is preserved, just no longer grouped.`,
707
+ activate_body_of_work: `# activate_body_of_work
708
+ Activate a draft body of work to start execution.
709
+
710
+ **Parameters:**
711
+ - body_of_work_id (required): Body of work UUID
712
+
713
+ **Note:** Requires at least one task. Once active, tasks follow phase order.`,
714
+ add_task_dependency: `# add_task_dependency
715
+ Add a dependency between tasks in a body of work.
716
+
717
+ **Parameters:**
718
+ - body_of_work_id (required): Body of work UUID
719
+ - task_id (required): Task that depends on another
720
+ - depends_on_task_id (required): Task that must complete first
721
+
722
+ **Note:** Prevents circular dependencies.`,
723
+ remove_task_dependency: `# remove_task_dependency
724
+ Remove a dependency between tasks.
725
+
726
+ **Parameters:**
727
+ - task_id (required): Task UUID
728
+ - depends_on_task_id (required): Dependency task UUID`,
729
+ get_task_dependencies: `# get_task_dependencies
730
+ Get task dependencies for a body of work or specific task.
731
+
732
+ **Parameters:**
733
+ - body_of_work_id (optional): Body of work UUID
734
+ - task_id (optional): Specific task UUID`,
735
+ get_next_body_of_work_task: `# get_next_body_of_work_task
736
+ Get the next available task from a body of work.
737
+
738
+ **Parameters:**
739
+ - body_of_work_id (required): Body of work UUID
740
+
741
+ **Note:** Considers phase order (pre → core → post) and dependencies.`,
742
+ // Sprints
743
+ create_sprint: `# create_sprint
744
+ Create a new sprint with time bounds and velocity tracking.
745
+
746
+ **Parameters:**
747
+ - project_id (required): Project UUID
748
+ - title (required): Sprint title (e.g., "Sprint 5")
749
+ - start_date (required): Start date (YYYY-MM-DD)
750
+ - end_date (required): End date (YYYY-MM-DD)
751
+ - goal (optional): Sprint goal statement
752
+ - auto_deploy_on_completion, deploy_environment, deploy_version_bump (optional)`,
753
+ update_sprint: `# update_sprint
754
+ Update a sprint's details.
755
+
756
+ **Parameters:**
757
+ - sprint_id (required): Sprint UUID
758
+ - title, goal, start_date, end_date (optional)
759
+ - auto_deploy_on_completion, deploy_environment, deploy_version_bump (optional)`,
760
+ get_sprint: `# get_sprint
761
+ Get a sprint with all its tasks organized by phase.
762
+
763
+ **Parameters:**
764
+ - sprint_id (required): Sprint UUID
765
+
766
+ **Returns:** Sprint with progress percentage, velocity points, committed points.`,
767
+ get_sprints: `# get_sprints
768
+ List sprints for a project with velocity metrics.
769
+
770
+ **Parameters:**
771
+ - project_id (required): Project UUID
772
+ - status (optional): planning, active, in_review, retrospective, completed, cancelled
773
+ - limit (optional): Max sprints (default 20)`,
774
+ delete_sprint: `# delete_sprint
775
+ Delete a sprint. Tasks are preserved but no longer grouped.
776
+
777
+ **Parameters:**
778
+ - sprint_id (required): Sprint UUID`,
779
+ start_sprint: `# start_sprint
780
+ Start a sprint. Transitions from 'planning' to 'active'.
781
+
782
+ **Parameters:**
783
+ - sprint_id (required): Sprint UUID
784
+
785
+ **Note:** Locks committed_points at current total story points.`,
786
+ complete_sprint: `# complete_sprint
787
+ Complete a sprint. Handles retrospective phase and auto-deployment.
788
+
789
+ **Parameters:**
790
+ - sprint_id (required): Sprint UUID
791
+ - retrospective_notes (optional): Sprint retrospective notes
792
+ - skip_retrospective (optional): Skip retrospective phase (default: false)`,
793
+ add_task_to_sprint: `# add_task_to_sprint
794
+ Add a task to a sprint with optional story points.
795
+
796
+ **Parameters:**
797
+ - sprint_id (required): Sprint UUID
798
+ - task_id (required): Task UUID to add
799
+ - story_points (optional): Story point estimate
800
+ - phase (optional): pre, core, or post (default: core)`,
801
+ remove_task_from_sprint: `# remove_task_from_sprint
802
+ Remove a task from a sprint.
803
+
804
+ **Parameters:**
805
+ - sprint_id (required): Sprint UUID
806
+ - task_id (required): Task UUID to remove
807
+
808
+ **Note:** Task returns to backlog.`,
809
+ get_sprint_backlog: `# get_sprint_backlog
810
+ Get tasks that can be added to a sprint.
811
+
812
+ **Parameters:**
813
+ - project_id (required): Project UUID
814
+ - sprint_id (optional): Exclude tasks already in this sprint
815
+
816
+ **Returns:** Tasks not assigned to any body of work or sprint.`,
817
+ get_sprint_velocity: `# get_sprint_velocity
818
+ Get velocity metrics for completed sprints.
819
+
820
+ **Parameters:**
821
+ - project_id (required): Project UUID
822
+ - limit (optional): Number of sprints to analyze (default 10)
823
+
824
+ **Returns:** Committed vs completed points, average velocity.`,
825
+ // Git issues
826
+ add_git_issue: `# add_git_issue
827
+ Record a git-related issue (merge conflict, push failure, etc.).
828
+
829
+ **Parameters:**
830
+ - project_id (required): Project UUID
831
+ - issue_type (required): merge_conflict, push_failed, rebase_needed, branch_diverged, pr_not_mergeable
832
+ - branch (required): Branch where the issue occurred
833
+ - target_branch, conflicting_files, error_message, pr_url, task_id (optional)`,
834
+ resolve_git_issue: `# resolve_git_issue
835
+ Mark a git issue as resolved.
836
+
837
+ **Parameters:**
838
+ - git_issue_id (required): Git issue UUID
839
+ - resolution_note (optional): How the issue was resolved
840
+ - auto_resolved (optional): Whether auto-resolved`,
841
+ get_git_issues: `# get_git_issues
842
+ Get git issues for a project.
843
+
844
+ **Parameters:**
845
+ - project_id (required): Project UUID
846
+ - status (optional): open or resolved (default: open)
847
+ - issue_type (optional): Filter by issue type
848
+ - branch (optional): Filter by branch
849
+ - limit (optional): Max issues (default 50)`,
850
+ delete_git_issue: `# delete_git_issue
851
+ Delete a git issue.
852
+
853
+ **Parameters:**
854
+ - git_issue_id (required): Git issue UUID`,
855
+ // Deployment requirements
856
+ add_deployment_requirement: `# add_deployment_requirement
857
+ Add a pre-deployment requirement.
858
+
859
+ **Parameters:**
860
+ - project_id (required): Project UUID
861
+ - type (required): migration, env_var, config, manual, breaking_change, agent_task
862
+ - title (required): Brief description
863
+ - description (optional): Detailed instructions
864
+ - stage (optional): preparation, deployment, or verification (default: preparation)
865
+ - file_path (optional): File path reference
866
+ - blocking (optional): Whether converted task blocks other work`,
867
+ complete_deployment_requirement: `# complete_deployment_requirement
868
+ Mark a deployment requirement as completed.
869
+
870
+ **Parameters:**
871
+ - requirement_id (required): Requirement UUID`,
872
+ get_deployment_requirements: `# get_deployment_requirements
873
+ Get pending deployment requirements.
874
+
875
+ **Parameters:**
876
+ - project_id (required): Project UUID
877
+ - stage (optional): preparation, deployment, verification, or all
878
+ - status (optional): pending, completed, converted_to_task, or all (default: pending)`,
879
+ // Knowledge base
633
880
  query_knowledge_base: `# query_knowledge_base
634
881
  Query aggregated project knowledge in a single call. Reduces token usage by combining multiple data sources.
635
882
 
@@ -33,7 +33,7 @@ export const claimValidation = async (args, ctx) => {
33
33
  return { result: response.data };
34
34
  };
35
35
  export const validateTask = async (args, ctx) => {
36
- const { task_id, validation_notes, approved } = args;
36
+ const { task_id, validation_notes, approved, skip_pr_check } = args;
37
37
  validateRequired(task_id, 'task_id');
38
38
  validateUUID(task_id, 'task_id');
39
39
  if (approved === undefined) {
@@ -45,8 +45,20 @@ export const validateTask = async (args, ctx) => {
45
45
  const response = await apiClient.validateTask(task_id, {
46
46
  approved,
47
47
  validation_notes,
48
+ skip_pr_check,
48
49
  }, currentSessionId || undefined);
49
50
  if (!response.ok) {
51
+ // Handle PR required error specially
52
+ if (response.error === 'pr_required') {
53
+ return {
54
+ result: {
55
+ error: 'pr_required',
56
+ message: response.data?.message || 'A Pull Request is required before validation approval. Create a PR and add it via add_task_reference.',
57
+ workflow: response.data?.workflow,
58
+ action_required: 'Create a PR for this task and add it via add_task_reference(task_id, pr_url, label: "Pull Request")',
59
+ },
60
+ };
61
+ }
50
62
  throw new Error(response.error || 'Failed to validate task');
51
63
  }
52
64
  return { result: response.data };
package/dist/index.js CHANGED
@@ -606,8 +606,8 @@ Returns session info, persona, and next task. Use mode:'full' for complete conte
606
606
  },
607
607
  task_type: {
608
608
  type: 'string',
609
- enum: ['frontend', 'backend', 'database', 'mcp', 'testing', 'docs', 'infra', 'other'],
610
- description: 'Task category for visual grouping (frontend, backend, database, mcp, testing, docs, infra, other)',
609
+ enum: ['frontend', 'backend', 'database', 'feature', 'bugfix', 'design', 'mcp', 'testing', 'docs', 'infra', 'other'],
610
+ description: 'Task category (frontend, backend, database, feature, bugfix, design, mcp, testing, docs, infra, other)',
611
611
  },
612
612
  },
613
613
  required: ['project_id', 'title'],
@@ -655,8 +655,8 @@ Returns session info, persona, and next task. Use mode:'full' for complete conte
655
655
  },
656
656
  task_type: {
657
657
  type: 'string',
658
- enum: ['frontend', 'backend', 'database', 'mcp', 'testing', 'docs', 'infra', 'other'],
659
- description: 'Task category (frontend, backend, database, mcp, testing, docs, infra, other)',
658
+ enum: ['frontend', 'backend', 'database', 'feature', 'bugfix', 'design', 'mcp', 'testing', 'docs', 'infra', 'other'],
659
+ description: 'Task category (frontend, backend, database, feature, bugfix, design, mcp, testing, docs, infra, other)',
660
660
  },
661
661
  },
662
662
  required: ['task_id'],
@@ -1371,6 +1371,10 @@ Returns subtasks with aggregate completion stats.`,
1371
1371
  type: 'string',
1372
1372
  description: 'Session ID from start_work_session (optional, uses current session if not provided)',
1373
1373
  },
1374
+ current_worktree_path: {
1375
+ type: ['string', 'null'],
1376
+ description: 'Report your current git worktree path (e.g., "../project-task-abc123"). Set to null to clear.',
1377
+ },
1374
1378
  },
1375
1379
  },
1376
1380
  },
@@ -1420,7 +1424,7 @@ Returns subtasks with aggregate completion stats.`,
1420
1424
  },
1421
1425
  {
1422
1426
  name: 'validate_task',
1423
- description: 'Validate a completed task. Include test results in validation_notes.',
1427
+ description: 'Validate a completed task. Include test results in validation_notes. For github-flow/git-flow projects, a PR must exist before approval (add via add_task_reference).',
1424
1428
  inputSchema: {
1425
1429
  type: 'object',
1426
1430
  properties: {
@@ -1436,6 +1440,10 @@ Returns subtasks with aggregate completion stats.`,
1436
1440
  type: 'boolean',
1437
1441
  description: 'Whether the task passes validation (true = approved, false = needs more work)',
1438
1442
  },
1443
+ skip_pr_check: {
1444
+ type: 'boolean',
1445
+ description: 'Skip PR existence check (use only for tasks that legitimately do not need a PR)',
1446
+ },
1439
1447
  },
1440
1448
  required: ['task_id', 'approved'],
1441
1449
  },
@@ -2143,7 +2151,8 @@ Bodies of work allow organizing related tasks with optional auto-deployment on c
2143
2151
  },
2144
2152
  {
2145
2153
  name: 'get_body_of_work',
2146
- description: `Get a body of work with all its tasks organized by phase.`,
2154
+ description: `Get a body of work with all its tasks organized by phase.
2155
+ Use summary_only: true to get task counts and next task instead of full task arrays (saves tokens).`,
2147
2156
  inputSchema: {
2148
2157
  type: 'object',
2149
2158
  properties: {
@@ -2151,6 +2160,10 @@ Bodies of work allow organizing related tasks with optional auto-deployment on c
2151
2160
  type: 'string',
2152
2161
  description: 'Body of work UUID',
2153
2162
  },
2163
+ summary_only: {
2164
+ type: 'boolean',
2165
+ description: 'Return task counts and next task instead of full task arrays (default: false)',
2166
+ },
2154
2167
  },
2155
2168
  required: ['body_of_work_id'],
2156
2169
  },
@@ -2426,7 +2439,8 @@ Sprints start in 'planning' status where tasks can be added with story points.`,
2426
2439
  {
2427
2440
  name: 'get_sprint',
2428
2441
  description: `Get a sprint with all its tasks organized by phase (pre/core/post).
2429
- Includes progress percentage, velocity points, and committed points.`,
2442
+ Includes progress percentage, velocity points, and committed points.
2443
+ Use summary_only: true to get task counts and next task instead of full task arrays (saves tokens).`,
2430
2444
  inputSchema: {
2431
2445
  type: 'object',
2432
2446
  properties: {
@@ -2434,6 +2448,10 @@ Includes progress percentage, velocity points, and committed points.`,
2434
2448
  type: 'string',
2435
2449
  description: 'Sprint UUID',
2436
2450
  },
2451
+ summary_only: {
2452
+ type: 'boolean',
2453
+ description: 'Return task counts and next task instead of full task arrays (default: false)',
2454
+ },
2437
2455
  },
2438
2456
  required: ['sprint_id'],
2439
2457
  },