@vibescope/mcp-server 0.3.0 → 0.3.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 (154) hide show
  1. package/dist/api-client/blockers.d.ts +46 -0
  2. package/dist/api-client/blockers.js +43 -0
  3. package/dist/api-client/cost.d.ts +112 -0
  4. package/dist/api-client/cost.js +76 -0
  5. package/dist/api-client/decisions.d.ts +55 -0
  6. package/dist/api-client/decisions.js +32 -0
  7. package/dist/api-client/discovery.d.ts +62 -0
  8. package/dist/api-client/discovery.js +21 -0
  9. package/dist/api-client/ideas.d.ts +75 -0
  10. package/dist/api-client/ideas.js +36 -0
  11. package/dist/api-client/index.d.ts +749 -0
  12. package/dist/api-client/index.js +291 -0
  13. package/dist/api-client/project.d.ts +132 -0
  14. package/dist/api-client/project.js +45 -0
  15. package/dist/api-client/session.d.ts +163 -0
  16. package/dist/api-client/session.js +52 -0
  17. package/dist/api-client/tasks.d.ts +328 -0
  18. package/dist/api-client/tasks.js +132 -0
  19. package/dist/api-client/types.d.ts +25 -0
  20. package/dist/api-client/types.js +4 -0
  21. package/dist/api-client/worktrees.d.ts +33 -0
  22. package/dist/api-client/worktrees.js +26 -0
  23. package/dist/api-client.d.ts +9 -0
  24. package/dist/api-client.js +104 -25
  25. package/dist/cli-init.d.ts +17 -0
  26. package/dist/cli-init.js +445 -0
  27. package/dist/cli.js +0 -0
  28. package/dist/handlers/cloud-agents.d.ts +21 -0
  29. package/dist/handlers/cloud-agents.js +91 -0
  30. package/dist/handlers/discovery.js +7 -0
  31. package/dist/handlers/index.d.ts +1 -0
  32. package/dist/handlers/index.js +3 -0
  33. package/dist/handlers/session.js +3 -1
  34. package/dist/handlers/tasks.js +10 -12
  35. package/dist/handlers/types.d.ts +2 -1
  36. package/dist/handlers/validation.js +5 -1
  37. package/dist/index.js +8 -3
  38. package/dist/token-tracking.js +2 -2
  39. package/dist/tools/blockers.d.ts +13 -0
  40. package/dist/tools/blockers.js +119 -0
  41. package/dist/tools/bodies-of-work.d.ts +19 -0
  42. package/dist/tools/bodies-of-work.js +280 -0
  43. package/dist/tools/cloud-agents.d.ts +9 -0
  44. package/dist/tools/cloud-agents.js +67 -0
  45. package/dist/tools/connectors.d.ts +14 -0
  46. package/dist/tools/connectors.js +188 -0
  47. package/dist/tools/cost.d.ts +11 -0
  48. package/dist/tools/cost.js +108 -0
  49. package/dist/tools/decisions.d.ts +12 -0
  50. package/dist/tools/decisions.js +108 -0
  51. package/dist/tools/deployment.d.ts +24 -0
  52. package/dist/tools/deployment.js +439 -0
  53. package/dist/tools/discovery.d.ts +10 -0
  54. package/dist/tools/discovery.js +73 -0
  55. package/dist/tools/fallback.d.ts +11 -0
  56. package/dist/tools/fallback.js +108 -0
  57. package/dist/tools/file-checkouts.d.ts +13 -0
  58. package/dist/tools/file-checkouts.js +141 -0
  59. package/dist/tools/findings.d.ts +13 -0
  60. package/dist/tools/findings.js +98 -0
  61. package/dist/tools/git-issues.d.ts +11 -0
  62. package/dist/tools/git-issues.js +127 -0
  63. package/dist/tools/ideas.d.ts +13 -0
  64. package/dist/tools/ideas.js +159 -0
  65. package/dist/tools/index.d.ts +71 -0
  66. package/dist/tools/index.js +98 -0
  67. package/dist/tools/milestones.d.ts +12 -0
  68. package/dist/tools/milestones.js +115 -0
  69. package/dist/tools/organizations.d.ts +17 -0
  70. package/dist/tools/organizations.js +221 -0
  71. package/dist/tools/progress.d.ts +9 -0
  72. package/dist/tools/progress.js +70 -0
  73. package/dist/tools/project.d.ts +13 -0
  74. package/dist/tools/project.js +199 -0
  75. package/dist/tools/requests.d.ts +10 -0
  76. package/dist/tools/requests.js +65 -0
  77. package/dist/tools/roles.d.ts +11 -0
  78. package/dist/tools/roles.js +109 -0
  79. package/dist/tools/session.d.ts +15 -0
  80. package/dist/tools/session.js +178 -0
  81. package/dist/tools/sprints.d.ts +18 -0
  82. package/dist/tools/sprints.js +295 -0
  83. package/dist/tools/tasks.d.ts +27 -0
  84. package/dist/tools/tasks.js +539 -0
  85. package/dist/tools/types.d.ts +7 -0
  86. package/dist/tools/types.js +6 -0
  87. package/dist/tools/validation.d.ts +10 -0
  88. package/dist/tools/validation.js +72 -0
  89. package/dist/tools/worktrees.d.ts +9 -0
  90. package/dist/tools/worktrees.js +63 -0
  91. package/dist/utils.d.ts +66 -0
  92. package/dist/utils.js +102 -0
  93. package/docs/TOOLS.md +55 -2
  94. package/package.json +5 -3
  95. package/scripts/generate-docs.ts +1 -1
  96. package/src/api-client/blockers.ts +86 -0
  97. package/src/api-client/cost.ts +185 -0
  98. package/src/api-client/decisions.ts +87 -0
  99. package/src/api-client/discovery.ts +81 -0
  100. package/src/api-client/ideas.ts +112 -0
  101. package/src/api-client/index.ts +378 -0
  102. package/src/api-client/project.ts +179 -0
  103. package/src/api-client/session.ts +220 -0
  104. package/src/api-client/tasks.ts +450 -0
  105. package/src/api-client/types.ts +32 -0
  106. package/src/api-client/worktrees.ts +53 -0
  107. package/src/api-client.test.ts +136 -9
  108. package/src/api-client.ts +125 -27
  109. package/src/cli-init.ts +504 -0
  110. package/src/handlers/__test-utils__.ts +2 -0
  111. package/src/handlers/cloud-agents.ts +138 -0
  112. package/src/handlers/discovery.ts +7 -0
  113. package/src/handlers/index.ts +3 -0
  114. package/src/handlers/session.ts +3 -1
  115. package/src/handlers/tasks.ts +10 -12
  116. package/src/handlers/tool-categories.test.ts +1 -1
  117. package/src/handlers/types.ts +2 -1
  118. package/src/handlers/validation.ts +6 -1
  119. package/src/index.test.ts +2 -2
  120. package/src/index.ts +8 -2
  121. package/src/token-tracking.ts +3 -2
  122. package/src/tools/blockers.ts +122 -0
  123. package/src/tools/bodies-of-work.ts +283 -0
  124. package/src/tools/cloud-agents.ts +70 -0
  125. package/src/tools/connectors.ts +191 -0
  126. package/src/tools/cost.ts +111 -0
  127. package/src/tools/decisions.ts +111 -0
  128. package/src/tools/deployment.ts +442 -0
  129. package/src/tools/discovery.ts +76 -0
  130. package/src/tools/fallback.ts +111 -0
  131. package/src/tools/file-checkouts.ts +145 -0
  132. package/src/tools/findings.ts +101 -0
  133. package/src/tools/git-issues.ts +130 -0
  134. package/src/tools/ideas.ts +162 -0
  135. package/src/tools/index.ts +131 -0
  136. package/src/tools/milestones.ts +118 -0
  137. package/src/tools/organizations.ts +224 -0
  138. package/src/tools/progress.ts +73 -0
  139. package/src/tools/project.ts +202 -0
  140. package/src/tools/requests.ts +68 -0
  141. package/src/tools/roles.ts +112 -0
  142. package/src/tools/session.ts +181 -0
  143. package/src/tools/sprints.ts +298 -0
  144. package/src/tools/tasks.ts +542 -0
  145. package/src/tools/tools.test.ts +222 -0
  146. package/src/tools/types.ts +9 -0
  147. package/src/tools/validation.ts +75 -0
  148. package/src/tools/worktrees.ts +66 -0
  149. package/src/tools.test.ts +1 -1
  150. package/src/utils.test.ts +229 -0
  151. package/src/utils.ts +117 -0
  152. package/dist/tools.d.ts +0 -2
  153. package/dist/tools.js +0 -3602
  154. package/src/tools.ts +0 -3607
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Git Worktree Tool Definitions
3
+ *
4
+ * Tools for managing git worktrees:
5
+ * - get_stale_worktrees: Get worktrees that need cleanup
6
+ * - clear_worktree_path: Clear worktree_path from a task after cleanup
7
+ */
8
+ export const worktreeTools = [
9
+ {
10
+ name: 'get_stale_worktrees',
11
+ description: `Get worktrees that need cleanup.
12
+
13
+ Returns tasks with worktree_path set where:
14
+ - Task is completed or cancelled (worktree should have been cleaned up)
15
+ - Task has been abandoned (no activity for 24+ hours while in_progress)
16
+
17
+ IMPORTANT: Pass hostname (os.hostname()) to only see worktrees created on THIS machine.
18
+ Worktrees created on other machines cannot be removed locally.
19
+
20
+ For each stale worktree:
21
+ 1. Run: git worktree remove <worktree_path>
22
+ 2. Call: clear_worktree_path(task_id)`,
23
+ inputSchema: {
24
+ type: 'object',
25
+ properties: {
26
+ project_id: {
27
+ type: 'string',
28
+ description: 'Project UUID',
29
+ },
30
+ hostname: {
31
+ type: 'string',
32
+ description: 'Machine hostname (os.hostname()). Only returns worktrees created on this machine, preventing attempts to clean up worktrees on other machines.',
33
+ },
34
+ limit: {
35
+ type: 'number',
36
+ description: 'Max worktrees to return (default: 50)',
37
+ },
38
+ offset: {
39
+ type: 'number',
40
+ description: 'Number of worktrees to skip for pagination (default: 0)',
41
+ },
42
+ },
43
+ required: ['project_id'],
44
+ },
45
+ },
46
+ {
47
+ name: 'clear_worktree_path',
48
+ description: `Clear the worktree_path from a task after cleanup.
49
+
50
+ Call this AFTER removing the worktree with git worktree remove.
51
+ This marks the task as cleaned up so it won't appear in get_stale_worktrees.`,
52
+ inputSchema: {
53
+ type: 'object',
54
+ properties: {
55
+ task_id: {
56
+ type: 'string',
57
+ description: 'Task UUID',
58
+ },
59
+ },
60
+ required: ['task_id'],
61
+ },
62
+ },
63
+ ];
package/dist/utils.d.ts CHANGED
@@ -159,3 +159,69 @@ export declare function extractProjectNameFromGitUrl(gitUrl: string): string;
159
159
  * // Returns: 'https://github.com/nonatomic/vibescope'
160
160
  */
161
161
  export declare function normalizeGitUrl(gitUrl: string | null | undefined): string | null;
162
+ /**
163
+ * Extract a human-readable message from any error type.
164
+ * Handles Error objects, strings, and unknown values.
165
+ *
166
+ * @example
167
+ * try { ... } catch (e) {
168
+ * console.error(getErrorMessage(e));
169
+ * }
170
+ */
171
+ export declare function getErrorMessage(error: unknown): string;
172
+ /**
173
+ * Type guard to check if a value is an object with an 'error' property.
174
+ * Useful for checking API responses that may contain application-level errors.
175
+ *
176
+ * @example
177
+ * if (hasErrorProperty(response.data)) {
178
+ * return error(getErrorMessage(response.data.error));
179
+ * }
180
+ */
181
+ export declare function hasErrorProperty(value: unknown): value is {
182
+ error: unknown;
183
+ };
184
+ /**
185
+ * Extract an error message from an API response body.
186
+ * Handles the common pattern where API returns { error: string } or { error: { message: string } }.
187
+ * Returns null if no error is found.
188
+ *
189
+ * @example
190
+ * const apiError = extractApiError(response.data);
191
+ * if (apiError) {
192
+ * return error(apiError);
193
+ * }
194
+ */
195
+ export declare function extractApiError(data: unknown): string | null;
196
+ /**
197
+ * Default pagination limits
198
+ */
199
+ export declare const PAGINATION_LIMITS: {
200
+ /** Default maximum limit for paginated results */
201
+ readonly DEFAULT_MAX_LIMIT: 50;
202
+ /** Default limit when not specified */
203
+ readonly DEFAULT_LIMIT: 20;
204
+ /** Smaller limit for task listings */
205
+ readonly TASK_LIMIT: 20;
206
+ };
207
+ /**
208
+ * Cap pagination parameters to safe values.
209
+ * Ensures limit is between 1 and maxLimit, and offset is non-negative.
210
+ *
211
+ * @param limit - Requested limit (will be capped between 1 and maxLimit)
212
+ * @param offset - Requested offset (will be made non-negative)
213
+ * @param maxLimit - Maximum allowed limit (default: PAGINATION_LIMITS.DEFAULT_MAX_LIMIT)
214
+ * @returns Object with cappedLimit and safeOffset
215
+ *
216
+ * @example
217
+ * const { cappedLimit, safeOffset } = capPagination(limit, offset);
218
+ * const { data } = await query.range(safeOffset, safeOffset + cappedLimit - 1);
219
+ *
220
+ * @example
221
+ * // With custom max limit
222
+ * const { cappedLimit, safeOffset } = capPagination(limit, offset, 20);
223
+ */
224
+ export declare function capPagination(limit: number | undefined, offset: number | undefined, maxLimit?: number): {
225
+ cappedLimit: number;
226
+ safeOffset: number;
227
+ };
package/dist/utils.js CHANGED
@@ -396,3 +396,105 @@ export function normalizeGitUrl(gitUrl) {
396
396
  normalized = normalized.toLowerCase();
397
397
  return normalized;
398
398
  }
399
+ // ============================================================================
400
+ // Error Handling Utilities
401
+ // Shared error extraction and type checking functions
402
+ // ============================================================================
403
+ /**
404
+ * Extract a human-readable message from any error type.
405
+ * Handles Error objects, strings, and unknown values.
406
+ *
407
+ * @example
408
+ * try { ... } catch (e) {
409
+ * console.error(getErrorMessage(e));
410
+ * }
411
+ */
412
+ export function getErrorMessage(error) {
413
+ if (error instanceof Error) {
414
+ return error.message;
415
+ }
416
+ if (typeof error === 'string') {
417
+ return error;
418
+ }
419
+ return String(error);
420
+ }
421
+ /**
422
+ * Type guard to check if a value is an object with an 'error' property.
423
+ * Useful for checking API responses that may contain application-level errors.
424
+ *
425
+ * @example
426
+ * if (hasErrorProperty(response.data)) {
427
+ * return error(getErrorMessage(response.data.error));
428
+ * }
429
+ */
430
+ export function hasErrorProperty(value) {
431
+ return typeof value === 'object' && value !== null && 'error' in value;
432
+ }
433
+ /**
434
+ * Extract an error message from an API response body.
435
+ * Handles the common pattern where API returns { error: string } or { error: { message: string } }.
436
+ * Returns null if no error is found.
437
+ *
438
+ * @example
439
+ * const apiError = extractApiError(response.data);
440
+ * if (apiError) {
441
+ * return error(apiError);
442
+ * }
443
+ */
444
+ export function extractApiError(data) {
445
+ if (!hasErrorProperty(data)) {
446
+ return null;
447
+ }
448
+ const err = data.error;
449
+ // Direct string error
450
+ if (typeof err === 'string') {
451
+ return err;
452
+ }
453
+ // Nested error object with message property
454
+ if (typeof err === 'object' && err !== null && 'message' in err) {
455
+ const msg = err.message;
456
+ if (typeof msg === 'string') {
457
+ return msg;
458
+ }
459
+ }
460
+ // Fallback for unknown error structure
461
+ return 'Unknown error';
462
+ }
463
+ // ============================================================================
464
+ // Pagination Utilities
465
+ // ============================================================================
466
+ /**
467
+ * Default pagination limits
468
+ */
469
+ export const PAGINATION_LIMITS = {
470
+ /** Default maximum limit for paginated results */
471
+ DEFAULT_MAX_LIMIT: 50,
472
+ /** Default limit when not specified */
473
+ DEFAULT_LIMIT: 20,
474
+ /** Smaller limit for task listings */
475
+ TASK_LIMIT: 20,
476
+ };
477
+ /**
478
+ * Cap pagination parameters to safe values.
479
+ * Ensures limit is between 1 and maxLimit, and offset is non-negative.
480
+ *
481
+ * @param limit - Requested limit (will be capped between 1 and maxLimit)
482
+ * @param offset - Requested offset (will be made non-negative)
483
+ * @param maxLimit - Maximum allowed limit (default: PAGINATION_LIMITS.DEFAULT_MAX_LIMIT)
484
+ * @returns Object with cappedLimit and safeOffset
485
+ *
486
+ * @example
487
+ * const { cappedLimit, safeOffset } = capPagination(limit, offset);
488
+ * const { data } = await query.range(safeOffset, safeOffset + cappedLimit - 1);
489
+ *
490
+ * @example
491
+ * // With custom max limit
492
+ * const { cappedLimit, safeOffset } = capPagination(limit, offset, 20);
493
+ */
494
+ export function capPagination(limit, offset, maxLimit = PAGINATION_LIMITS.DEFAULT_MAX_LIMIT) {
495
+ const effectiveLimit = limit ?? PAGINATION_LIMITS.DEFAULT_LIMIT;
496
+ return {
497
+ cappedLimit: Math.min(Math.max(1, effectiveLimit), maxLimit),
498
+ safeOffset: Math.max(0, offset ?? 0)
499
+ };
500
+ }
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-01-24
5
+ > Generated: 2026-02-06
6
6
  >
7
- > Total tools: 152
7
+ > Total tools: 154
8
8
 
9
9
  ## Table of Contents
10
10
 
@@ -33,6 +33,7 @@
33
33
  - [roles](#roles) - Agent role management (4 tools)
34
34
  - [file_locks](#file-locks) - File checkout/locking for multi-agent (6 tools)
35
35
  - [connectors](#connectors) - External integration connectors (7 tools)
36
+ - [cloud_agents](#cloud-agents) - Cloud agent management and cleanup (2 tools)
36
37
 
37
38
  ## session
38
39
 
@@ -59,6 +60,7 @@ Use mode:'full' for complete context, mode:'lite' (default) for minimal tokens.
59
60
  | `role` | `string` | No | Agent role (e.g., "developer", "validator", "deployer", "reviewer", "maintainer"). Custom roles accepted. |
60
61
  | `hostname` | `string` | No | Machine hostname for worktree tracking. Pass os.hostname() to filter stale worktrees to only those created on this machine. |
61
62
  | `agent_type` | `string` | No | Agent type (e.g., "claude", "gemini", "cursor", "windsurf"). Custom agent types accepted. |
63
+ | `agent_name` | `string` | No | Explicit agent name (for cloud/remote agents). If provided, uses this name instead of selecting from persona pool. Cloud agents should pass their spawner-assigned name. |
62
64
 
63
65
  ---
64
66
 
@@ -1025,6 +1027,7 @@ Validate a completed task. Include test results in validation_notes. For github-
1025
1027
  | `approved` | `boolean` | Yes | Whether the task passes validation (true = approved, false = needs more work) |
1026
1028
  | `pr_checks_passing` | `boolean` | No | REQUIRED when approving tasks with PRs. Confirm you verified PR checks are passing via `gh pr view <PR_NUMBER> --json statusCheckRollup`. Set to true only if all required checks pass. |
1027
1029
  | `skip_pr_check` | `boolean` | No | Skip PR existence check (use only for tasks that legitimately do not need a PR) |
1030
+ | `create_fix_task` | `boolean` | No | When rejecting (approved: false), create a new fix task linked to the original. The fix task will contain the rejection reason and be assigned the same git branch. |
1028
1031
 
1029
1032
  ---
1030
1033
 
@@ -2404,3 +2407,53 @@ Get event history for a connector or project. Shows delivery status and errors.
2404
2407
  | `offset` | `number` | No | Pagination offset (default: 0) |
2405
2408
 
2406
2409
  ---
2410
+
2411
+ ## cloud_agents
2412
+
2413
+ *Cloud agent management and cleanup*
2414
+
2415
+ ### cleanup_stale_cloud_agents
2416
+
2417
+ Clean up stale cloud agents that failed to start or lost connection.
2418
+
2419
+ Finds agents stuck in 'starting' status (or optionally 'running' with no heartbeat)
2420
+
2421
+ and marks them as failed. Only operates on the current session's project.
2422
+
2423
+ Use this when:
2424
+
2425
+ - You see agents stuck in "starting" status on the dashboard
2426
+
2427
+ - Cloud agents failed to spawn but weren't cleaned up
2428
+
2429
+ - You want to clear ghost agents from a previous session
2430
+
2431
+ SECURITY: This only affects agents in YOUR current project. Cannot access other users' projects.
2432
+
2433
+ **Parameters:**
2434
+
2435
+ | Parameter | Type | Required | Description |
2436
+ |-----------|------|----------|-------------|
2437
+ | `project_id` | `string` | Yes | Project UUID (required) |
2438
+ | `stale_minutes` | `number` | No | Consider agents stale after this many minutes (default: 5) |
2439
+ | `include_running` | `boolean` | No | Also clean up "running" agents with no recent heartbeat (default: false) |
2440
+ | `dry_run` | `boolean` | No | If true, just report what would be cleaned without actually cleaning (default: false) |
2441
+
2442
+ ---
2443
+
2444
+ ### list_cloud_agents
2445
+
2446
+ List cloud agents for a project.
2447
+
2448
+ Returns all spawned cloud agents for the project with their current status.
2449
+
2450
+ Use this to check the state of cloud agents before/after cleanup.
2451
+
2452
+ **Parameters:**
2453
+
2454
+ | Parameter | Type | Required | Description |
2455
+ |-----------|------|----------|-------------|
2456
+ | `project_id` | `string` | Yes | Project UUID (required) |
2457
+ | `status` | `"starting" | "running" | "stopped" | "failed" | "all"` | No | Filter by status (default: all) |
2458
+
2459
+ ---
package/package.json CHANGED
@@ -1,17 +1,19 @@
1
1
  {
2
2
  "name": "@vibescope/mcp-server",
3
- "version": "0.3.0",
3
+ "version": "0.3.3",
4
4
  "description": "MCP server for Vibescope - AI project tracking tools",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "bin": {
9
9
  "vibescope-mcp": "dist/index.js",
10
- "vibescope-cli": "dist/cli.js"
10
+ "vibescope-cli": "dist/cli.js",
11
+ "vibescope": "dist/cli-init.js",
12
+ "vibescope-init": "dist/cli-init.js"
11
13
  },
12
14
  "repository": {
13
15
  "type": "git",
14
- "url": "https://github.com/Nonatomic/Vibescope.git",
16
+ "url": "https://github.com/PaulNonatomic/Vibescope.git",
15
17
  "directory": "packages/mcp-server"
16
18
  },
17
19
  "publishConfig": {
@@ -9,7 +9,7 @@
9
9
  * npm run docs:generate
10
10
  */
11
11
 
12
- import { tools } from '../src/tools.js';
12
+ import { tools } from '../src/tools/index.js';
13
13
  import { TOOL_CATEGORIES } from '../src/handlers/discovery.js';
14
14
  import * as fs from 'fs';
15
15
  import * as path from 'path';
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Blockers API Methods
3
+ *
4
+ * Methods for blocker management:
5
+ * - getBlockers: List blockers for a project
6
+ * - addBlocker: Create a new blocker
7
+ * - resolveBlocker: Mark blocker as resolved
8
+ * - deleteBlocker: Delete a blocker
9
+ * - getBlockersStats: Get blocker statistics
10
+ */
11
+
12
+ import type { ApiResponse, RequestFn } from './types.js';
13
+
14
+ export interface BlockersMethods {
15
+ getBlockers(projectId: string, params?: {
16
+ status?: 'open' | 'resolved';
17
+ limit?: number;
18
+ offset?: number;
19
+ }): Promise<ApiResponse<{
20
+ blockers: Array<{
21
+ id: string;
22
+ description: string;
23
+ status: string;
24
+ created_at: string;
25
+ resolved_at?: string;
26
+ resolution_note?: string;
27
+ }>;
28
+ total_count: number;
29
+ has_more: boolean;
30
+ }>>;
31
+
32
+ addBlocker(projectId: string, description: string, sessionId?: string): Promise<ApiResponse<{
33
+ success: boolean;
34
+ blocker_id: string;
35
+ }>>;
36
+
37
+ resolveBlocker(blockerId: string, resolutionNote?: string): Promise<ApiResponse<{
38
+ success: boolean;
39
+ blocker_id: string;
40
+ }>>;
41
+
42
+ deleteBlocker(blockerId: string): Promise<ApiResponse<{
43
+ success: boolean;
44
+ }>>;
45
+
46
+ getBlockersStats(projectId: string): Promise<ApiResponse<{
47
+ total: number;
48
+ open: number;
49
+ resolved: number;
50
+ }>>;
51
+ }
52
+
53
+ export function createBlockersMethods(request: RequestFn): BlockersMethods {
54
+ return {
55
+ async getBlockers(projectId, params) {
56
+ const queryParams = new URLSearchParams();
57
+ if (params?.status) queryParams.set('status', params.status);
58
+ if (params?.limit) queryParams.set('limit', params.limit.toString());
59
+ if (params?.offset) queryParams.set('offset', params.offset.toString());
60
+ const query = queryParams.toString();
61
+ const url = `/api/mcp/projects/${projectId}/blockers${query ? `?${query}` : ''}`;
62
+ return request('GET', url);
63
+ },
64
+
65
+ async addBlocker(projectId, description, sessionId) {
66
+ return request('POST', `/api/mcp/projects/${projectId}/blockers`, {
67
+ description,
68
+ session_id: sessionId
69
+ });
70
+ },
71
+
72
+ async resolveBlocker(blockerId, resolutionNote) {
73
+ return request('PATCH', `/api/mcp/blockers/${blockerId}/resolve`, {
74
+ resolution_note: resolutionNote
75
+ });
76
+ },
77
+
78
+ async deleteBlocker(blockerId) {
79
+ return request('DELETE', `/api/mcp/blockers/${blockerId}`);
80
+ },
81
+
82
+ async getBlockersStats(projectId) {
83
+ return request('GET', `/api/mcp/projects/${projectId}/blockers/stats`);
84
+ }
85
+ };
86
+ }
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Cost API Methods
3
+ *
4
+ * Methods for cost tracking and alerts:
5
+ * - getCostSummary: Get cost summary by period
6
+ * - getCostAlerts: List cost alerts
7
+ * - addCostAlert: Create a cost alert
8
+ * - updateCostAlert: Update a cost alert
9
+ * - deleteCostAlert: Delete a cost alert
10
+ * - getTaskCosts: Get costs by task
11
+ * - getBodyOfWorkCosts: Get costs by body of work
12
+ * - getSprintCosts: Get costs by sprint
13
+ * - getTokenUsage: Get token usage stats
14
+ * - reportTokenUsage: Report token usage
15
+ */
16
+
17
+ import type { ApiResponse, RequestFn } from './types.js';
18
+
19
+ export interface CostMethods {
20
+ getCostSummary(projectId: string, params?: {
21
+ period?: 'daily' | 'weekly' | 'monthly';
22
+ limit?: number;
23
+ }): Promise<ApiResponse<{
24
+ summary: Array<{
25
+ period: string;
26
+ total_cost: number;
27
+ input_tokens: number;
28
+ output_tokens: number;
29
+ api_calls: number;
30
+ }>;
31
+ }>>;
32
+
33
+ getCostAlerts(): Promise<ApiResponse<{
34
+ alerts: Array<{
35
+ id: string;
36
+ project_id?: string;
37
+ threshold_amount: number;
38
+ threshold_period: string;
39
+ alert_type: string;
40
+ enabled: boolean;
41
+ }>;
42
+ }>>;
43
+
44
+ addCostAlert(params: {
45
+ project_id?: string;
46
+ threshold_amount: number;
47
+ threshold_period: 'daily' | 'weekly' | 'monthly';
48
+ alert_type?: 'warning' | 'critical';
49
+ }): Promise<ApiResponse<{
50
+ success: boolean;
51
+ alert_id: string;
52
+ }>>;
53
+
54
+ updateCostAlert(alertId: string, updates: {
55
+ threshold_amount?: number;
56
+ threshold_period?: 'daily' | 'weekly' | 'monthly';
57
+ alert_type?: 'warning' | 'critical';
58
+ enabled?: boolean;
59
+ }): Promise<ApiResponse<{
60
+ success: boolean;
61
+ alert_id: string;
62
+ }>>;
63
+
64
+ deleteCostAlert(alertId: string): Promise<ApiResponse<{
65
+ success: boolean;
66
+ }>>;
67
+
68
+ getTaskCosts(projectId: string, limit?: number): Promise<ApiResponse<{
69
+ tasks: Array<{
70
+ task_id: string;
71
+ task_title: string;
72
+ total_cost: number;
73
+ input_tokens: number;
74
+ output_tokens: number;
75
+ }>;
76
+ }>>;
77
+
78
+ getBodyOfWorkCosts(params: {
79
+ body_of_work_id?: string;
80
+ project_id?: string;
81
+ limit?: number;
82
+ }): Promise<ApiResponse<{
83
+ bodies_of_work: Array<{
84
+ body_of_work_id: string;
85
+ title: string;
86
+ total_cost: number;
87
+ task_count: number;
88
+ }>;
89
+ }>>;
90
+
91
+ getSprintCosts(params: {
92
+ sprint_id?: string;
93
+ project_id?: string;
94
+ limit?: number;
95
+ }): Promise<ApiResponse<{
96
+ sprints: Array<{
97
+ sprint_id: string;
98
+ name: string;
99
+ total_cost: number;
100
+ task_count: number;
101
+ }>;
102
+ }>>;
103
+
104
+ getTokenUsage(): Promise<ApiResponse<{
105
+ session_tokens: {
106
+ input: number;
107
+ output: number;
108
+ };
109
+ estimated_cost: number;
110
+ }>>;
111
+
112
+ reportTokenUsage(sessionId: string, params: {
113
+ input_tokens: number;
114
+ output_tokens: number;
115
+ model?: string;
116
+ }): Promise<ApiResponse<{
117
+ success: boolean;
118
+ session_id: string;
119
+ total_input_tokens: number;
120
+ total_output_tokens: number;
121
+ }>>;
122
+ }
123
+
124
+ export function createCostMethods(request: RequestFn): CostMethods {
125
+ return {
126
+ async getCostSummary(projectId, params) {
127
+ const queryParams = new URLSearchParams();
128
+ if (params?.period) queryParams.set('period', params.period);
129
+ if (params?.limit) queryParams.set('limit', params.limit.toString());
130
+ const query = queryParams.toString();
131
+ const url = `/api/mcp/projects/${projectId}/cost-summary${query ? `?${query}` : ''}`;
132
+ return request('GET', url);
133
+ },
134
+
135
+ async getCostAlerts() {
136
+ return request('GET', '/api/mcp/cost-alerts');
137
+ },
138
+
139
+ async addCostAlert(params) {
140
+ return request('POST', '/api/mcp/cost-alerts', params);
141
+ },
142
+
143
+ async updateCostAlert(alertId, updates) {
144
+ return request('PATCH', `/api/mcp/cost-alerts/${alertId}`, updates);
145
+ },
146
+
147
+ async deleteCostAlert(alertId) {
148
+ return request('DELETE', `/api/mcp/cost-alerts/${alertId}`);
149
+ },
150
+
151
+ async getTaskCosts(projectId, limit) {
152
+ const url = limit
153
+ ? `/api/mcp/projects/${projectId}/task-costs?limit=${limit}`
154
+ : `/api/mcp/projects/${projectId}/task-costs`;
155
+ return request('GET', url);
156
+ },
157
+
158
+ async getBodyOfWorkCosts(params) {
159
+ const queryParams = new URLSearchParams();
160
+ if (params.body_of_work_id) queryParams.set('body_of_work_id', params.body_of_work_id);
161
+ if (params.project_id) queryParams.set('project_id', params.project_id);
162
+ if (params.limit) queryParams.set('limit', params.limit.toString());
163
+ return request('GET', `/api/mcp/cost/bodies-of-work?${queryParams.toString()}`);
164
+ },
165
+
166
+ async getSprintCosts(params) {
167
+ const queryParams = new URLSearchParams();
168
+ if (params.sprint_id) queryParams.set('sprint_id', params.sprint_id);
169
+ if (params.project_id) queryParams.set('project_id', params.project_id);
170
+ if (params.limit) queryParams.set('limit', params.limit.toString());
171
+ return request('GET', `/api/mcp/cost/sprints?${queryParams.toString()}`);
172
+ },
173
+
174
+ async getTokenUsage() {
175
+ return request('GET', '/api/mcp/sessions/token-usage');
176
+ },
177
+
178
+ async reportTokenUsage(sessionId, params) {
179
+ return request('POST', '/api/mcp/sessions/token-usage', {
180
+ session_id: sessionId,
181
+ ...params
182
+ });
183
+ }
184
+ };
185
+ }