@vibescope/mcp-server 0.2.1 → 0.2.3

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 (93) hide show
  1. package/README.md +63 -38
  2. package/dist/api-client.d.ts +187 -0
  3. package/dist/api-client.js +53 -1
  4. package/dist/handlers/blockers.js +9 -8
  5. package/dist/handlers/bodies-of-work.js +14 -14
  6. package/dist/handlers/connectors.d.ts +45 -0
  7. package/dist/handlers/connectors.js +183 -0
  8. package/dist/handlers/cost.d.ts +10 -0
  9. package/dist/handlers/cost.js +54 -0
  10. package/dist/handlers/decisions.js +3 -3
  11. package/dist/handlers/deployment.js +35 -19
  12. package/dist/handlers/discovery.d.ts +7 -0
  13. package/dist/handlers/discovery.js +61 -2
  14. package/dist/handlers/fallback.js +5 -4
  15. package/dist/handlers/file-checkouts.d.ts +2 -0
  16. package/dist/handlers/file-checkouts.js +38 -6
  17. package/dist/handlers/findings.js +13 -12
  18. package/dist/handlers/git-issues.js +4 -4
  19. package/dist/handlers/ideas.js +5 -5
  20. package/dist/handlers/index.d.ts +1 -0
  21. package/dist/handlers/index.js +3 -0
  22. package/dist/handlers/milestones.js +5 -5
  23. package/dist/handlers/organizations.js +13 -13
  24. package/dist/handlers/progress.js +2 -2
  25. package/dist/handlers/project.js +6 -6
  26. package/dist/handlers/requests.js +3 -3
  27. package/dist/handlers/session.js +28 -9
  28. package/dist/handlers/sprints.js +17 -17
  29. package/dist/handlers/tasks.d.ts +2 -0
  30. package/dist/handlers/tasks.js +78 -20
  31. package/dist/handlers/types.d.ts +64 -2
  32. package/dist/handlers/types.js +48 -1
  33. package/dist/handlers/validation.js +3 -3
  34. package/dist/index.js +7 -2716
  35. package/dist/token-tracking.d.ts +74 -0
  36. package/dist/token-tracking.js +122 -0
  37. package/dist/tools.js +298 -9
  38. package/dist/utils.d.ts +5 -0
  39. package/dist/utils.js +17 -0
  40. package/docs/TOOLS.md +2053 -0
  41. package/package.json +4 -1
  42. package/scripts/generate-docs.ts +212 -0
  43. package/src/api-client.test.ts +723 -0
  44. package/src/api-client.ts +236 -1
  45. package/src/handlers/__test-setup__.ts +9 -0
  46. package/src/handlers/blockers.test.ts +31 -19
  47. package/src/handlers/blockers.ts +9 -8
  48. package/src/handlers/bodies-of-work.test.ts +55 -32
  49. package/src/handlers/bodies-of-work.ts +14 -14
  50. package/src/handlers/connectors.test.ts +834 -0
  51. package/src/handlers/connectors.ts +229 -0
  52. package/src/handlers/cost.ts +66 -0
  53. package/src/handlers/decisions.test.ts +34 -25
  54. package/src/handlers/decisions.ts +3 -3
  55. package/src/handlers/deployment.ts +39 -19
  56. package/src/handlers/discovery.ts +61 -2
  57. package/src/handlers/fallback.test.ts +26 -22
  58. package/src/handlers/fallback.ts +5 -4
  59. package/src/handlers/file-checkouts.test.ts +242 -49
  60. package/src/handlers/file-checkouts.ts +44 -6
  61. package/src/handlers/findings.test.ts +38 -24
  62. package/src/handlers/findings.ts +13 -12
  63. package/src/handlers/git-issues.test.ts +51 -43
  64. package/src/handlers/git-issues.ts +4 -4
  65. package/src/handlers/ideas.test.ts +28 -23
  66. package/src/handlers/ideas.ts +5 -5
  67. package/src/handlers/index.ts +3 -0
  68. package/src/handlers/milestones.test.ts +33 -28
  69. package/src/handlers/milestones.ts +5 -5
  70. package/src/handlers/organizations.test.ts +104 -83
  71. package/src/handlers/organizations.ts +13 -13
  72. package/src/handlers/progress.test.ts +20 -14
  73. package/src/handlers/progress.ts +2 -2
  74. package/src/handlers/project.test.ts +34 -27
  75. package/src/handlers/project.ts +6 -6
  76. package/src/handlers/requests.test.ts +27 -18
  77. package/src/handlers/requests.ts +3 -3
  78. package/src/handlers/session.test.ts +47 -0
  79. package/src/handlers/session.ts +26 -9
  80. package/src/handlers/sprints.test.ts +71 -50
  81. package/src/handlers/sprints.ts +17 -17
  82. package/src/handlers/tasks.test.ts +77 -15
  83. package/src/handlers/tasks.ts +90 -21
  84. package/src/handlers/tool-categories.test.ts +66 -0
  85. package/src/handlers/types.ts +81 -2
  86. package/src/handlers/validation.test.ts +78 -45
  87. package/src/handlers/validation.ts +3 -3
  88. package/src/index.ts +12 -2732
  89. package/src/token-tracking.test.ts +453 -0
  90. package/src/token-tracking.ts +164 -0
  91. package/src/tools.ts +298 -9
  92. package/src/utils.test.ts +2 -2
  93. package/src/utils.ts +17 -0
package/README.md CHANGED
@@ -13,7 +13,7 @@ Use directly in your MCP config without installing:
13
13
  "mcpServers": {
14
14
  "vibescope": {
15
15
  "command": "npx",
16
- "args": ["-y", "-p", "@vibescope/mcp-server", "vibescope-mcp"],
16
+ "args": ["-y", "-p", "@vibescope/mcp-server@latest", "vibescope-mcp"],
17
17
  "env": {
18
18
  "VIBESCOPE_API_KEY": "your-api-key"
19
19
  }
@@ -25,7 +25,7 @@ Use directly in your MCP config without installing:
25
25
  ### Option 2: Global Install
26
26
 
27
27
  ```bash
28
- npm install -g @vibescope/mcp-server
28
+ npm install -g @vibescope/mcp-server@latest
29
29
  ```
30
30
 
31
31
  Then configure:
@@ -43,40 +43,12 @@ Then configure:
43
43
  }
44
44
  ```
45
45
 
46
- ### Option 3: From Source (Development)
47
-
48
- ```bash
49
- # Clone the repo
50
- git clone https://github.com/Nonatomic/Vibescope.git
51
- cd Vibescope
52
-
53
- # Install dependencies and build
54
- pnpm install
55
- pnpm build
56
-
57
- # Point your MCP config to the built file
58
- ```
59
-
60
- ```json
61
- {
62
- "mcpServers": {
63
- "vibescope": {
64
- "command": "node",
65
- "args": ["/path/to/Vibescope/packages/mcp-server/dist/index.js"],
66
- "env": {
67
- "VIBESCOPE_API_KEY": "your-api-key"
68
- }
69
- }
70
- }
71
- }
72
- ```
73
-
74
46
  ## Quick Start with Claude Code
75
47
 
76
48
  The easiest way to get started:
77
49
 
78
50
  ```bash
79
- claude mcp add vibescope npx @vibescope/mcp-server \
51
+ claude mcp add vibescope npx @vibescope/mcp-server@latest \
80
52
  --env VIBESCOPE_API_KEY=your_key
81
53
  ```
82
54
 
@@ -88,24 +60,77 @@ claude mcp add vibescope npx @vibescope/mcp-server \
88
60
 
89
61
  ## Available Tools
90
62
 
91
- The MCP server provides these tools for AI agents:
63
+ The MCP server provides **140+ tools** for AI agents. Here are the key tools by category:
64
+
65
+ ### Session
66
+ | Tool | Description |
67
+ |------|-------------|
68
+ | `start_work_session` | Initialize session, get persona, role, and next task |
69
+ | `end_work_session` | End session and release claimed tasks |
70
+ | `heartbeat` | Keep session active (call every 30-60s) |
71
+ | `get_help` | Get guidance on workflows |
72
+ | `discover_tools` | List tools by category |
73
+ | `get_tool_info` | Get detailed tool documentation |
74
+
75
+ ### Projects
76
+ | Tool | Description |
77
+ |------|-------------|
78
+ | `create_project` | Create a new project |
79
+ | `update_project` | Update project details and git workflow |
80
+ | `get_project_context` | Get full project context |
81
+ | `get_git_workflow` | Get git branching instructions |
82
+ | `query_knowledge_base` | Query aggregated project knowledge |
92
83
 
84
+ ### Tasks
93
85
  | Tool | Description |
94
86
  |------|-------------|
95
- | `start_work_session` | Initialize a work session for a project |
96
- | `get_project_context` | Get full project context including tasks, blockers, and user updates |
97
87
  | `get_tasks` | List tasks, optionally filtered by status |
98
- | `get_next_task` | Get the highest priority pending task |
88
+ | `get_next_task` | Get highest priority pending task |
99
89
  | `add_task` | Create a new task |
100
90
  | `update_task` | Update task status, progress, or details |
101
91
  | `complete_task` | Mark a task as completed |
92
+ | `add_subtask` | Break down tasks into subtasks |
93
+ | `add_task_reference` | Add reference URL (docs, PRs) |
94
+ | `batch_update_tasks` | Update multiple tasks at once |
95
+
96
+ ### Progress & Context
97
+ | Tool | Description |
98
+ |------|-------------|
102
99
  | `log_progress` | Log a progress update |
103
100
  | `add_blocker` | Flag a blocker needing human input |
104
101
  | `resolve_blocker` | Mark a blocker as resolved |
105
- | `log_decision` | Record an architectural or technical decision |
102
+ | `log_decision` | Record an architectural decision |
106
103
  | `add_idea` | Record an improvement idea |
107
- | `create_project` | Create a new project |
108
- | `update_project` | Update project details |
104
+ | `add_finding` | Record an audit finding |
105
+
106
+ ### Validation & Deployment
107
+ | Tool | Description |
108
+ |------|-------------|
109
+ | `get_tasks_awaiting_validation` | Get tasks needing review |
110
+ | `claim_validation` | Claim a task for review |
111
+ | `validate_task` | Approve or reject work |
112
+ | `request_deployment` | Request a deployment |
113
+ | `check_deployment_status` | Check deployment state |
114
+ | `complete_deployment` | Mark deployment done |
115
+
116
+ ### Collaboration
117
+ | Tool | Description |
118
+ |------|-------------|
119
+ | `add_milestone` | Track progress on complex tasks |
120
+ | `create_body_of_work` | Group tasks into phases |
121
+ | `create_sprint` | Create time-bounded sprints |
122
+ | `checkout_file` | Prevent file conflicts |
123
+ | `get_pending_requests` | Get human requests |
124
+ | `answer_question` | Answer user questions |
125
+
126
+ ### Additional Categories
127
+ - **Organizations**: Create, manage, and share projects with teams
128
+ - **Cost Tracking**: Monitor spending with alerts and summaries
129
+ - **Git Issues**: Track merge conflicts and push failures
130
+ - **Role Management**: Configure agent roles (developer, validator, deployer)
131
+ - **Scheduled Deployments**: Schedule recurring deployments
132
+
133
+ Use `discover_tools` to explore all categories and `get_tool_info` for detailed documentation
109
134
 
110
135
  ## Rate Limits
111
136
 
@@ -69,6 +69,23 @@ export declare class VibescopeApiClient {
69
69
  priority: number;
70
70
  estimated_minutes?: number;
71
71
  } | null;
72
+ pending_requests?: Array<{
73
+ id: string;
74
+ request_type: string;
75
+ message: string;
76
+ created_at: string;
77
+ }>;
78
+ pending_requests_count?: number;
79
+ URGENT_QUESTIONS?: {
80
+ count: number;
81
+ oldest_waiting_minutes: number;
82
+ action_required: string;
83
+ requests: Array<{
84
+ id: string;
85
+ message: string;
86
+ waiting_minutes: number;
87
+ }>;
88
+ };
72
89
  directive?: string;
73
90
  blockers_count?: number;
74
91
  validation_count?: number;
@@ -275,6 +292,7 @@ export declare class VibescopeApiClient {
275
292
  progress_note?: string;
276
293
  estimated_minutes?: number;
277
294
  git_branch?: string;
295
+ worktree_path?: string;
278
296
  session_id?: string;
279
297
  }): Promise<ApiResponse<{
280
298
  success: boolean;
@@ -1057,6 +1075,63 @@ export declare class VibescopeApiClient {
1057
1075
  output_tokens: number;
1058
1076
  }>;
1059
1077
  }>>;
1078
+ getBodyOfWorkCosts(params: {
1079
+ body_of_work_id?: string;
1080
+ project_id?: string;
1081
+ }): Promise<ApiResponse<{
1082
+ bodies_of_work: Array<{
1083
+ body_of_work_id: string;
1084
+ title: string;
1085
+ project_id: string;
1086
+ status: string;
1087
+ task_count: number;
1088
+ total_cost_usd: number;
1089
+ total_tokens: number;
1090
+ pre_phase_cost_usd: number;
1091
+ core_phase_cost_usd: number;
1092
+ post_phase_cost_usd: number;
1093
+ model_breakdown: Record<string, {
1094
+ input: number;
1095
+ output: number;
1096
+ }>;
1097
+ }>;
1098
+ count: number;
1099
+ totals: {
1100
+ total_cost_usd: number;
1101
+ total_tokens: number;
1102
+ total_tasks: number;
1103
+ };
1104
+ }>>;
1105
+ getSprintCosts(params: {
1106
+ sprint_id?: string;
1107
+ project_id?: string;
1108
+ }): Promise<ApiResponse<{
1109
+ sprints: Array<{
1110
+ sprint_id: string;
1111
+ title: string;
1112
+ project_id: string;
1113
+ status: string;
1114
+ sprint_number: number;
1115
+ task_count: number;
1116
+ total_cost_usd: number;
1117
+ total_tokens: number;
1118
+ cost_per_story_point: number | null;
1119
+ committed_points: number;
1120
+ velocity_points: number;
1121
+ model_breakdown: Record<string, {
1122
+ input: number;
1123
+ output: number;
1124
+ }>;
1125
+ }>;
1126
+ count: number;
1127
+ totals: {
1128
+ total_cost_usd: number;
1129
+ total_tokens: number;
1130
+ total_tasks: number;
1131
+ total_velocity_points: number;
1132
+ avg_cost_per_point: number | null;
1133
+ };
1134
+ }>>;
1060
1135
  getTokenUsage(): Promise<ApiResponse<{
1061
1136
  session_tokens: number;
1062
1137
  estimated_cost: number;
@@ -1116,6 +1191,7 @@ export declare class VibescopeApiClient {
1116
1191
  environment?: string;
1117
1192
  version_bump?: string;
1118
1193
  auto_trigger?: boolean;
1194
+ hours_interval?: number;
1119
1195
  notes?: string;
1120
1196
  git_ref?: string;
1121
1197
  }): Promise<ApiResponse<{
@@ -1127,6 +1203,7 @@ export declare class VibescopeApiClient {
1127
1203
  id: string;
1128
1204
  scheduled_at: string;
1129
1205
  schedule_type: string;
1206
+ hours_interval: number;
1130
1207
  environment: string;
1131
1208
  version_bump: string;
1132
1209
  auto_trigger: boolean;
@@ -1140,6 +1217,7 @@ export declare class VibescopeApiClient {
1140
1217
  updateScheduledDeployment(scheduleId: string, updates: {
1141
1218
  scheduled_at?: string;
1142
1219
  schedule_type?: string;
1220
+ hours_interval?: number;
1143
1221
  environment?: string;
1144
1222
  version_bump?: string;
1145
1223
  auto_trigger?: boolean;
@@ -1226,6 +1304,115 @@ export declare class VibescopeApiClient {
1226
1304
  checkout_id: string;
1227
1305
  message: string;
1228
1306
  }>>;
1307
+ getStaleWorktrees(projectId: string): Promise<ApiResponse<{
1308
+ project_id: string;
1309
+ project_name: string;
1310
+ stale_worktrees: Array<{
1311
+ task_id: string;
1312
+ task_title: string;
1313
+ worktree_path: string;
1314
+ git_branch: string | null;
1315
+ status: string;
1316
+ completed_at: string | null;
1317
+ updated_at: string;
1318
+ pr_url: string | null;
1319
+ stale_reason: 'task_finished' | 'potentially_abandoned';
1320
+ }>;
1321
+ count: number;
1322
+ cleanup_instructions: string[] | null;
1323
+ }>>;
1324
+ clearWorktreePath(taskId: string): Promise<ApiResponse<{
1325
+ success: boolean;
1326
+ task_id: string;
1327
+ }>>;
1328
+ getConnectors(projectId: string, params?: {
1329
+ type?: string;
1330
+ status?: string;
1331
+ limit?: number;
1332
+ offset?: number;
1333
+ }): Promise<ApiResponse<{
1334
+ connectors: Array<{
1335
+ id: string;
1336
+ name: string;
1337
+ type: string;
1338
+ description?: string;
1339
+ status: string;
1340
+ events: Record<string, boolean>;
1341
+ events_sent: number;
1342
+ last_triggered_at?: string;
1343
+ last_error?: string;
1344
+ last_error_at?: string;
1345
+ created_at: string;
1346
+ }>;
1347
+ total_count: number;
1348
+ has_more: boolean;
1349
+ }>>;
1350
+ getConnector(connectorId: string): Promise<ApiResponse<{
1351
+ connector: {
1352
+ id: string;
1353
+ name: string;
1354
+ type: string;
1355
+ description?: string;
1356
+ config: Record<string, unknown>;
1357
+ events: Record<string, boolean>;
1358
+ status: string;
1359
+ events_sent: number;
1360
+ last_triggered_at?: string;
1361
+ last_error?: string;
1362
+ last_error_at?: string;
1363
+ created_at: string;
1364
+ };
1365
+ }>>;
1366
+ addConnector(projectId: string, params: {
1367
+ name: string;
1368
+ type: string;
1369
+ description?: string;
1370
+ config?: Record<string, unknown>;
1371
+ events?: Record<string, boolean>;
1372
+ }): Promise<ApiResponse<{
1373
+ success: boolean;
1374
+ connector_id: string;
1375
+ }>>;
1376
+ updateConnector(connectorId: string, updates: {
1377
+ name?: string;
1378
+ description?: string;
1379
+ config?: Record<string, unknown>;
1380
+ events?: Record<string, boolean>;
1381
+ status?: string;
1382
+ }): Promise<ApiResponse<{
1383
+ success: boolean;
1384
+ connector_id: string;
1385
+ }>>;
1386
+ deleteConnector(connectorId: string): Promise<ApiResponse<{
1387
+ success: boolean;
1388
+ }>>;
1389
+ testConnector(connectorId: string): Promise<ApiResponse<{
1390
+ success: boolean;
1391
+ event_id: string;
1392
+ status?: number;
1393
+ error?: string;
1394
+ }>>;
1395
+ getConnectorEvents(params: {
1396
+ connector_id?: string;
1397
+ project_id?: string;
1398
+ status?: string;
1399
+ limit?: number;
1400
+ offset?: number;
1401
+ }): Promise<ApiResponse<{
1402
+ events: Array<{
1403
+ id: string;
1404
+ connector_id: string;
1405
+ event_type: string;
1406
+ status: string;
1407
+ response_status?: number;
1408
+ error_message?: string;
1409
+ attempts: number;
1410
+ created_at: string;
1411
+ sent_at?: string;
1412
+ }>;
1413
+ total_count: number;
1414
+ has_more: boolean;
1415
+ }>>;
1229
1416
  }
1230
1417
  export declare function getApiClient(): VibescopeApiClient;
1231
1418
  export declare function initApiClient(config: ApiClientConfig): VibescopeApiClient;
@@ -118,7 +118,11 @@ export class VibescopeApiClient {
118
118
  return this.request('PATCH', `/api/mcp/tasks/${taskId}`, updates);
119
119
  }
120
120
  async completeTask(taskId, params) {
121
- return this.request('POST', `/api/mcp/tasks/${taskId}/complete`, params);
121
+ // Use proxy endpoint for consistency - direct endpoint had routing issues on Vercel
122
+ return this.proxy('complete_task', {
123
+ task_id: taskId,
124
+ summary: params.summary,
125
+ }, params.session_id ? { session_id: params.session_id, persona: null, instance_id: '' } : undefined);
122
126
  }
123
127
  async deleteTask(taskId) {
124
128
  return this.request('DELETE', `/api/mcp/tasks/${taskId}`);
@@ -616,6 +620,12 @@ export class VibescopeApiClient {
616
620
  limit
617
621
  });
618
622
  }
623
+ async getBodyOfWorkCosts(params) {
624
+ return this.proxy('get_body_of_work_costs', params);
625
+ }
626
+ async getSprintCosts(params) {
627
+ return this.proxy('get_sprint_costs', params);
628
+ }
619
629
  async getTokenUsage() {
620
630
  return this.proxy('get_token_usage', {});
621
631
  }
@@ -725,6 +735,48 @@ export class VibescopeApiClient {
725
735
  async abandonCheckout(params) {
726
736
  return this.proxy('abandon_checkout', params);
727
737
  }
738
+ // ============================================================================
739
+ // Worktree Management
740
+ // ============================================================================
741
+ async getStaleWorktrees(projectId) {
742
+ return this.request('GET', `/api/mcp/worktrees/stale?project_id=${projectId}`);
743
+ }
744
+ async clearWorktreePath(taskId) {
745
+ return this.request('PATCH', `/api/mcp/tasks/${taskId}`, { worktree_path: null });
746
+ }
747
+ // ============================================================================
748
+ // Connector endpoints
749
+ // ============================================================================
750
+ async getConnectors(projectId, params) {
751
+ return this.proxy('get_connectors', {
752
+ project_id: projectId,
753
+ ...params
754
+ });
755
+ }
756
+ async getConnector(connectorId) {
757
+ return this.proxy('get_connector', { connector_id: connectorId });
758
+ }
759
+ async addConnector(projectId, params) {
760
+ return this.proxy('add_connector', {
761
+ project_id: projectId,
762
+ ...params
763
+ });
764
+ }
765
+ async updateConnector(connectorId, updates) {
766
+ return this.proxy('update_connector', {
767
+ connector_id: connectorId,
768
+ ...updates
769
+ });
770
+ }
771
+ async deleteConnector(connectorId) {
772
+ return this.proxy('delete_connector', { connector_id: connectorId });
773
+ }
774
+ async testConnector(connectorId) {
775
+ return this.proxy('test_connector', { connector_id: connectorId });
776
+ }
777
+ async getConnectorEvents(params) {
778
+ return this.proxy('get_connector_events', params);
779
+ }
728
780
  }
729
781
  // Singleton instance
730
782
  let apiClient = null;
@@ -7,6 +7,7 @@
7
7
  * - get_blockers
8
8
  * - delete_blocker
9
9
  */
10
+ import { success, error } from './types.js';
10
11
  import { parseArgs, uuidValidator, createEnumValidator, VALID_BLOCKER_STATUSES, } from '../validators.js';
11
12
  import { getApiClient } from '../api-client.js';
12
13
  // Argument schemas for type-safe parsing
@@ -33,18 +34,18 @@ export const addBlocker = async (args, ctx) => {
33
34
  const apiClient = getApiClient();
34
35
  const response = await apiClient.addBlocker(project_id, description, ctx.session.currentSessionId || undefined);
35
36
  if (!response.ok) {
36
- throw new Error(response.error || 'Failed to add blocker');
37
+ return error(response.error || 'Failed to add blocker');
37
38
  }
38
- return { result: response.data };
39
+ return success(response.data);
39
40
  };
40
41
  export const resolveBlocker = async (args, _ctx) => {
41
42
  const { blocker_id, resolution_note } = parseArgs(args, resolveBlockerSchema);
42
43
  const apiClient = getApiClient();
43
44
  const response = await apiClient.resolveBlocker(blocker_id, resolution_note);
44
45
  if (!response.ok) {
45
- throw new Error(response.error || 'Failed to resolve blocker');
46
+ return error(response.error || 'Failed to resolve blocker');
46
47
  }
47
- return { result: response.data };
48
+ return success(response.data);
48
49
  };
49
50
  export const getBlockers = async (args, _ctx) => {
50
51
  const { project_id, status, limit, offset, search_query } = parseArgs(args, getBlockersSchema);
@@ -56,18 +57,18 @@ export const getBlockers = async (args, _ctx) => {
56
57
  search_query
57
58
  });
58
59
  if (!response.ok) {
59
- throw new Error(response.error || 'Failed to fetch blockers');
60
+ return error(response.error || 'Failed to fetch blockers');
60
61
  }
61
- return { result: response.data };
62
+ return success(response.data);
62
63
  };
63
64
  export const deleteBlocker = async (args, _ctx) => {
64
65
  const { blocker_id } = parseArgs(args, deleteBlockerSchema);
65
66
  const apiClient = getApiClient();
66
67
  const response = await apiClient.deleteBlocker(blocker_id);
67
68
  if (!response.ok) {
68
- throw new Error(response.error || 'Failed to delete blocker');
69
+ return error(response.error || 'Failed to delete blocker');
69
70
  }
70
- return { result: response.data };
71
+ return success(response.data);
71
72
  };
72
73
  /**
73
74
  * Blockers handlers registry
@@ -105,7 +105,7 @@ export const createBodyOfWork = async (args, ctx) => {
105
105
  instance_id: session.instanceId
106
106
  });
107
107
  if (!response.ok) {
108
- throw new Error(`Failed to create body of work: ${response.error}`);
108
+ return { result: { error: response.error || 'Failed to create body of work' }, isError: true };
109
109
  }
110
110
  return {
111
111
  result: {
@@ -135,7 +135,7 @@ export const updateBodyOfWork = async (args, ctx) => {
135
135
  deploy_trigger
136
136
  });
137
137
  if (!response.ok) {
138
- throw new Error(`Failed to update body of work: ${response.error}`);
138
+ return { result: { error: response.error || 'Failed to update body of work' }, isError: true };
139
139
  }
140
140
  return { result: { success: true, body_of_work_id } };
141
141
  };
@@ -145,7 +145,7 @@ export const getBodyOfWork = async (args, ctx) => {
145
145
  // Response type varies based on summary_only
146
146
  const response = await apiClient.proxy('get_body_of_work', { body_of_work_id, summary_only });
147
147
  if (!response.ok) {
148
- throw new Error(`Failed to get body of work: ${response.error}`);
148
+ return { result: { error: response.error || 'Failed to get body of work' }, isError: true };
149
149
  }
150
150
  return { result: response.data };
151
151
  };
@@ -160,7 +160,7 @@ export const getBodiesOfWork = async (args, ctx) => {
160
160
  search_query
161
161
  });
162
162
  if (!response.ok) {
163
- throw new Error(`Failed to fetch bodies of work: ${response.error}`);
163
+ return { result: { error: response.error || 'Failed to fetch bodies of work' }, isError: true };
164
164
  }
165
165
  return { result: response.data };
166
166
  };
@@ -171,7 +171,7 @@ export const deleteBodyOfWork = async (args, ctx) => {
171
171
  body_of_work_id
172
172
  });
173
173
  if (!response.ok) {
174
- throw new Error(`Failed to delete body of work: ${response.error}`);
174
+ return { result: { error: response.error || 'Failed to delete body of work' }, isError: true };
175
175
  }
176
176
  return { result: { success: true, message: 'Body of work deleted. Tasks are preserved.' } };
177
177
  };
@@ -185,7 +185,7 @@ export const addTaskToBodyOfWork = async (args, ctx) => {
185
185
  order_index
186
186
  });
187
187
  if (!response.ok) {
188
- throw new Error(`Failed to add task to body of work: ${response.error}`);
188
+ return { result: { error: response.error || 'Failed to add task to body of work' }, isError: true };
189
189
  }
190
190
  return { result: response.data };
191
191
  };
@@ -194,7 +194,7 @@ export const removeTaskFromBodyOfWork = async (args, ctx) => {
194
194
  const apiClient = getApiClient();
195
195
  const response = await apiClient.proxy('remove_task_from_body_of_work', { task_id });
196
196
  if (!response.ok) {
197
- throw new Error(`Failed to remove task from body of work: ${response.error}`);
197
+ return { result: { error: response.error || 'Failed to remove task from body of work' }, isError: true };
198
198
  }
199
199
  return { result: response.data };
200
200
  };
@@ -203,14 +203,14 @@ export const activateBodyOfWork = async (args, ctx) => {
203
203
  const apiClient = getApiClient();
204
204
  const response = await apiClient.proxy('activate_body_of_work', { body_of_work_id });
205
205
  if (!response.ok) {
206
- throw new Error(`Failed to activate body of work: ${response.error}`);
206
+ return { result: { error: response.error || 'Failed to activate body of work' }, isError: true };
207
207
  }
208
208
  return { result: response.data };
209
209
  };
210
210
  export const addTaskDependency = async (args, ctx) => {
211
211
  const { body_of_work_id, task_id, depends_on_task_id } = parseArgs(args, addTaskDependencySchema);
212
212
  if (task_id === depends_on_task_id) {
213
- throw new Error('A task cannot depend on itself');
213
+ return { result: { error: 'A task cannot depend on itself' }, isError: true };
214
214
  }
215
215
  const apiClient = getApiClient();
216
216
  const response = await apiClient.proxy('add_task_dependency', {
@@ -219,7 +219,7 @@ export const addTaskDependency = async (args, ctx) => {
219
219
  depends_on_task_id
220
220
  });
221
221
  if (!response.ok) {
222
- throw new Error(`Failed to add task dependency: ${response.error}`);
222
+ return { result: { error: response.error || 'Failed to add task dependency' }, isError: true };
223
223
  }
224
224
  return { result: response.data };
225
225
  };
@@ -231,14 +231,14 @@ export const removeTaskDependency = async (args, ctx) => {
231
231
  depends_on_task_id
232
232
  });
233
233
  if (!response.ok) {
234
- throw new Error(`Failed to remove task dependency: ${response.error}`);
234
+ return { result: { error: response.error || 'Failed to remove task dependency' }, isError: true };
235
235
  }
236
236
  return { result: response.data };
237
237
  };
238
238
  export const getTaskDependencies = async (args, ctx) => {
239
239
  const { body_of_work_id, task_id } = parseArgs(args, getTaskDependenciesSchema);
240
240
  if (!body_of_work_id && !task_id) {
241
- throw new Error('Either body_of_work_id or task_id is required');
241
+ return { result: { error: 'Either body_of_work_id or task_id is required' }, isError: true };
242
242
  }
243
243
  const apiClient = getApiClient();
244
244
  const response = await apiClient.proxy('get_task_dependencies', {
@@ -246,7 +246,7 @@ export const getTaskDependencies = async (args, ctx) => {
246
246
  task_id
247
247
  });
248
248
  if (!response.ok) {
249
- throw new Error(`Failed to fetch task dependencies: ${response.error}`);
249
+ return { result: { error: response.error || 'Failed to fetch task dependencies' }, isError: true };
250
250
  }
251
251
  return { result: response.data };
252
252
  };
@@ -255,7 +255,7 @@ export const getNextBodyOfWorkTask = async (args, ctx) => {
255
255
  const apiClient = getApiClient();
256
256
  const response = await apiClient.proxy('get_next_body_of_work_task', { body_of_work_id });
257
257
  if (!response.ok) {
258
- throw new Error(`Failed to get next body of work task: ${response.error}`);
258
+ return { result: { error: response.error || 'Failed to get next body of work task' }, isError: true };
259
259
  }
260
260
  return { result: response.data };
261
261
  };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Connectors Handlers
3
+ *
4
+ * Handles external integration management:
5
+ * - get_connectors
6
+ * - get_connector
7
+ * - add_connector
8
+ * - update_connector
9
+ * - delete_connector
10
+ * - test_connector
11
+ * - get_connector_events
12
+ */
13
+ import type { Handler, HandlerRegistry } from './types.js';
14
+ /**
15
+ * Get all connectors for a project
16
+ */
17
+ export declare const getConnectors: Handler;
18
+ /**
19
+ * Get a single connector with full details
20
+ */
21
+ export declare const getConnector: Handler;
22
+ /**
23
+ * Add a new connector
24
+ */
25
+ export declare const addConnector: Handler;
26
+ /**
27
+ * Update a connector
28
+ */
29
+ export declare const updateConnector: Handler;
30
+ /**
31
+ * Delete a connector
32
+ */
33
+ export declare const deleteConnector: Handler;
34
+ /**
35
+ * Test a connector by sending a test event
36
+ */
37
+ export declare const testConnector: Handler;
38
+ /**
39
+ * Get connector event history
40
+ */
41
+ export declare const getConnectorEvents: Handler;
42
+ /**
43
+ * Connectors handlers registry
44
+ */
45
+ export declare const connectorHandlers: HandlerRegistry;