@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,91 @@
1
+ /**
2
+ * Cloud Agents Handlers
3
+ *
4
+ * Handles cloud agent management:
5
+ * - cleanup_stale_cloud_agents
6
+ * - list_cloud_agents
7
+ */
8
+ import { success, error } from './types.js';
9
+ import { parseArgs, uuidValidator, createEnumValidator } from '../validators.js';
10
+ import { getApiClient } from '../api-client.js';
11
+ // Argument schemas
12
+ const cleanupStaleAgentsSchema = {
13
+ project_id: { type: 'string', required: true, validate: uuidValidator },
14
+ stale_minutes: { type: 'number', default: 5 },
15
+ include_running: { type: 'boolean', default: false },
16
+ dry_run: { type: 'boolean', default: false },
17
+ };
18
+ const listCloudAgentsSchema = {
19
+ project_id: { type: 'string', required: true, validate: uuidValidator },
20
+ status: {
21
+ type: 'string',
22
+ default: 'all',
23
+ validate: createEnumValidator(['starting', 'running', 'stopped', 'failed', 'all'])
24
+ },
25
+ };
26
+ /**
27
+ * Clean up stale cloud agents that failed to start or lost connection.
28
+ * Only operates on agents in the specified project (security scoped).
29
+ */
30
+ export const cleanupStaleCloudAgents = async (args, ctx) => {
31
+ const { project_id, stale_minutes, include_running, dry_run } = parseArgs(args, cleanupStaleAgentsSchema);
32
+ // Ensure user has an active session with this project (security check)
33
+ if (ctx.session.currentProjectId && ctx.session.currentProjectId !== project_id) {
34
+ return error('Cannot cleanup agents for a different project than your current session');
35
+ }
36
+ const apiClient = getApiClient();
37
+ // Call the cleanup endpoint via fetch (since it's a new endpoint not in the client)
38
+ const response = await apiClient.proxy('cleanup_stale_cloud_agents', {
39
+ project_id,
40
+ staleMinutes: stale_minutes,
41
+ includeRunning: include_running,
42
+ dryRun: dry_run,
43
+ });
44
+ if (!response.ok) {
45
+ return error(response.error || 'Failed to cleanup stale agents');
46
+ }
47
+ const data = response.data;
48
+ if (dry_run) {
49
+ return success({
50
+ dryRun: true,
51
+ wouldClean: data.wouldClean || 0,
52
+ agents: data.agents,
53
+ message: `Found ${data.wouldClean || 0} stale agents that would be cleaned up`
54
+ });
55
+ }
56
+ return success({
57
+ cleaned: data.cleaned,
58
+ failed: data.failed || 0,
59
+ agents: data.agents,
60
+ message: `Cleaned up ${data.cleaned} stale agents`
61
+ });
62
+ };
63
+ /**
64
+ * List cloud agents for a project with optional status filter.
65
+ */
66
+ export const listCloudAgents = async (args, ctx) => {
67
+ const { project_id, status } = parseArgs(args, listCloudAgentsSchema);
68
+ // Ensure user has an active session with this project (security check)
69
+ if (ctx.session.currentProjectId && ctx.session.currentProjectId !== project_id) {
70
+ return error('Cannot list agents for a different project than your current session');
71
+ }
72
+ const apiClient = getApiClient();
73
+ const response = await apiClient.proxy('list_cloud_agents', {
74
+ project_id,
75
+ status: status === 'all' ? undefined : status,
76
+ });
77
+ if (!response.ok) {
78
+ return error(response.error || 'Failed to list cloud agents');
79
+ }
80
+ return success({
81
+ agents: response.data.agents,
82
+ count: response.data.agents.length
83
+ });
84
+ };
85
+ /**
86
+ * Cloud agents handlers registry
87
+ */
88
+ export const cloudAgentHandlers = {
89
+ cleanup_stale_cloud_agents: cleanupStaleCloudAgents,
90
+ list_cloud_agents: listCloudAgents,
91
+ };
@@ -316,6 +316,13 @@ export const TOOL_CATEGORIES = {
316
316
  { name: 'get_connector_events', brief: 'Event history' },
317
317
  ],
318
318
  },
319
+ cloud_agents: {
320
+ description: 'Cloud agent management and cleanup',
321
+ tools: [
322
+ { name: 'cleanup_stale_cloud_agents', brief: 'Clean up stale cloud agents' },
323
+ { name: 'list_cloud_agents', brief: 'List cloud agents for project' },
324
+ ],
325
+ },
319
326
  };
320
327
  export const discoverTools = async (args) => {
321
328
  const { category } = parseArgs(args, discoverToolsSchema);
@@ -27,6 +27,7 @@ export * from './sprints.js';
27
27
  export * from './file-checkouts.js';
28
28
  export * from './roles.js';
29
29
  export * from './connectors.js';
30
+ export * from './cloud-agents.js';
30
31
  import type { HandlerRegistry } from './types.js';
31
32
  /**
32
33
  * Build the complete handler registry from all modules
@@ -27,6 +27,7 @@ export * from './sprints.js';
27
27
  export * from './file-checkouts.js';
28
28
  export * from './roles.js';
29
29
  export * from './connectors.js';
30
+ export * from './cloud-agents.js';
30
31
  import { milestoneHandlers } from './milestones.js';
31
32
  import { sessionHandlers } from './session.js';
32
33
  import { ideaHandlers } from './ideas.js';
@@ -49,6 +50,7 @@ import { sprintHandlers } from './sprints.js';
49
50
  import { fileCheckoutHandlers } from './file-checkouts.js';
50
51
  import { roleHandlers } from './roles.js';
51
52
  import { connectorHandlers } from './connectors.js';
53
+ import { cloudAgentHandlers } from './cloud-agents.js';
52
54
  /**
53
55
  * Build the complete handler registry from all modules
54
56
  */
@@ -76,5 +78,6 @@ export function buildHandlerRegistry() {
76
78
  ...fileCheckoutHandlers,
77
79
  ...roleHandlers,
78
80
  ...connectorHandlers,
81
+ ...cloudAgentHandlers,
79
82
  };
80
83
  }
@@ -26,6 +26,7 @@ const startWorkSessionSchema = {
26
26
  role: { type: 'string', default: 'developer' }, // Open-ended - any role name accepted
27
27
  hostname: { type: 'string' }, // Machine hostname for worktree tracking
28
28
  agent_type: { type: 'string' }, // Open-ended - any agent type accepted
29
+ agent_name: { type: 'string' }, // Explicit agent name for cloud/remote agents (skips persona pool)
29
30
  };
30
31
  const heartbeatSchema = {
31
32
  session_id: { type: 'string' },
@@ -39,7 +40,7 @@ const getHelpSchema = {
39
40
  topic: { type: 'string', required: true },
40
41
  };
41
42
  export const startWorkSession = async (args, ctx) => {
42
- const { project_id, git_url, mode, model, role, hostname: providedHostname, agent_type } = parseArgs(args, startWorkSessionSchema);
43
+ const { project_id, git_url, mode, model, role, hostname: providedHostname, agent_type, agent_name } = parseArgs(args, startWorkSessionSchema);
43
44
  // Use auto-detected hostname if not provided - enables machine-aware worktree filtering
44
45
  const hostname = providedHostname || MACHINE_HOSTNAME;
45
46
  // Normalize git_url and track if it was changed - helps agents understand URL matching
@@ -78,6 +79,7 @@ export const startWorkSession = async (args, ctx) => {
78
79
  role: role,
79
80
  hostname, // Machine hostname for worktree tracking
80
81
  agent_type: agent_type, // Agent type for onboarding
82
+ agent_name: agent_name, // Explicit name for cloud/remote agents
81
83
  });
82
84
  if (!response.ok) {
83
85
  // Include additional error details if available
@@ -24,6 +24,7 @@
24
24
  import os from 'os';
25
25
  import { parseArgs, uuidValidator, taskStatusValidator, priorityValidator, progressValidator, minutesValidator, createEnumValidator, ValidationError, } from '../validators.js';
26
26
  import { getApiClient } from '../api-client.js';
27
+ import { capPagination, PAGINATION_LIMITS } from '../utils.js';
27
28
  // Auto-detect machine hostname for worktree tracking
28
29
  const MACHINE_HOSTNAME = os.hostname();
29
30
  // Valid task types
@@ -715,9 +716,8 @@ export const searchTasks = async (args, ctx) => {
715
716
  },
716
717
  };
717
718
  }
718
- // Cap limit at 20, safe offset
719
- const cappedLimit = Math.min(limit ?? 10, 20);
720
- const safeOffset = Math.max(0, offset ?? 0);
719
+ // Cap pagination to safe values
720
+ const { cappedLimit, safeOffset } = capPagination(limit ?? 10, offset, PAGINATION_LIMITS.TASK_LIMIT);
721
721
  const api = getApiClient();
722
722
  const response = await api.searchTasks(project_id, {
723
723
  query,
@@ -745,9 +745,8 @@ export const searchTasks = async (args, ctx) => {
745
745
  */
746
746
  export const getTasksByPriority = async (args, ctx) => {
747
747
  const { project_id, priority, priority_max, status, limit, offset } = parseArgs(args, getTasksByPrioritySchema);
748
- // Cap limit at 20, safe offset
749
- const cappedLimit = Math.min(limit ?? 10, 20);
750
- const safeOffset = Math.max(0, offset ?? 0);
748
+ // Cap pagination to safe values
749
+ const { cappedLimit, safeOffset } = capPagination(limit ?? 10, offset, PAGINATION_LIMITS.TASK_LIMIT);
751
750
  const api = getApiClient();
752
751
  const response = await api.getTasksByPriority(project_id, {
753
752
  priority,
@@ -776,9 +775,8 @@ export const getTasksByPriority = async (args, ctx) => {
776
775
  */
777
776
  export const getRecentTasks = async (args, ctx) => {
778
777
  const { project_id, order, status, limit, offset } = parseArgs(args, getRecentTasksSchema);
779
- // Cap limit at 20, safe offset
780
- const cappedLimit = Math.min(limit ?? 10, 20);
781
- const safeOffset = Math.max(0, offset ?? 0);
778
+ // Cap pagination to safe values
779
+ const { cappedLimit, safeOffset } = capPagination(limit ?? 10, offset, PAGINATION_LIMITS.TASK_LIMIT);
782
780
  const api = getApiClient();
783
781
  const response = await api.getRecentTasks(project_id, {
784
782
  order: order,
@@ -843,10 +841,10 @@ export const getStaleWorktrees = async (args, ctx) => {
843
841
  const { project_id, hostname: providedHostname, limit, offset } = parseArgs(args, getStaleWorktreesSchema);
844
842
  // Use auto-detected hostname if not provided - filters to only worktrees on THIS machine
845
843
  const hostname = providedHostname || MACHINE_HOSTNAME;
846
- // Cap limit to prevent context bloating
847
- const cappedLimit = Math.min(limit ?? 20, 50);
844
+ // Cap pagination to safe values
845
+ const { cappedLimit, safeOffset } = capPagination(limit, offset, PAGINATION_LIMITS.DEFAULT_MAX_LIMIT);
848
846
  const api = getApiClient();
849
- const response = await api.getStaleWorktrees(project_id, { hostname, limit: cappedLimit, offset });
847
+ const response = await api.getStaleWorktrees(project_id, { hostname, limit: cappedLimit, offset: safeOffset });
850
848
  if (!response.ok) {
851
849
  return { result: { error: response.error || 'Failed to get stale worktrees' }, isError: true };
852
850
  }
@@ -44,6 +44,7 @@ export interface SessionState {
44
44
  currentSessionId: string | null;
45
45
  currentPersona: string | null;
46
46
  currentRole: AgentRole | null;
47
+ currentProjectId: string | null;
47
48
  tokenUsage: TokenUsage;
48
49
  }
49
50
  /**
@@ -73,7 +74,7 @@ export interface HandlerContext {
73
74
  auth: AuthContext;
74
75
  session: SessionState;
75
76
  /** Update session state (for handlers that modify session) */
76
- updateSession: (updates: Partial<Pick<SessionState, 'currentSessionId' | 'currentPersona' | 'currentRole' | 'tokenUsage'>>) => void;
77
+ updateSession: (updates: Partial<Pick<SessionState, 'currentSessionId' | 'currentPersona' | 'currentRole' | 'currentProjectId' | 'tokenUsage'>>) => void;
77
78
  /** Get user updates since last sync (for session handlers) */
78
79
  getUserUpdates?: (projectId: string) => Promise<UserUpdates | undefined>;
79
80
  /** Select an available persona for the agent */
@@ -21,6 +21,7 @@ const validateTaskSchema = {
21
21
  approved: { type: 'boolean', required: true },
22
22
  validation_notes: { type: 'string' },
23
23
  skip_pr_check: { type: 'boolean' },
24
+ // Note: pr_checks_passing may arrive as string from some MCP clients, handled in validateTask
24
25
  pr_checks_passing: { type: 'boolean' },
25
26
  };
26
27
  export const getTasksAwaitingValidation = async (args, _ctx) => {
@@ -79,12 +80,15 @@ export const validateTask = async (args, ctx) => {
79
80
  const { task_id, approved, validation_notes, skip_pr_check, pr_checks_passing } = parseArgs(args, validateTaskSchema);
80
81
  const { session } = ctx;
81
82
  const currentSessionId = session.currentSessionId;
83
+ // Ensure pr_checks_passing is a proper boolean (MCP may send as string)
84
+ // Cast to unknown first to satisfy TypeScript
85
+ const checksPassingBool = pr_checks_passing === true || pr_checks_passing === 'true';
82
86
  const apiClient = getApiClient();
83
87
  const response = await apiClient.validateTask(task_id, {
84
88
  approved,
85
89
  validation_notes,
86
90
  skip_pr_check,
87
- pr_checks_passing,
91
+ pr_checks_passing: pr_checks_passing !== undefined ? checksPassingBool : undefined,
88
92
  }, currentSessionId || undefined);
89
93
  if (!response.ok) {
90
94
  // Handle PR required error specially
package/dist/index.js CHANGED
@@ -5,9 +5,9 @@ import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextpro
5
5
  import { randomUUID } from 'crypto';
6
6
  import { initApiClient, getApiClient } from './api-client.js';
7
7
  import { ValidationError, } from './validators.js';
8
- import { RateLimiter, } from './utils.js';
8
+ import { RateLimiter, getErrorMessage, } from './utils.js';
9
9
  import { buildHandlerRegistry } from './handlers/index.js';
10
- import { tools } from './tools.js';
10
+ import { tools } from './tools/index.js';
11
11
  import { createTokenUsage, trackTokenUsage as trackTokens, } from './token-tracking.js';
12
12
  // ============================================================================
13
13
  // Agent Instance Tracking
@@ -20,6 +20,8 @@ let currentSessionId = null;
20
20
  let currentPersona = null;
21
21
  // Current role for this agent instance
22
22
  let currentRole = null;
23
+ // Current project ID for this agent instance
24
+ let currentProjectId = null;
23
25
  // Token usage tracking for this session (using token-tracking module)
24
26
  let sessionTokenUsage = createTokenUsage();
25
27
  // Wrapper function to track token usage with the session's usage object
@@ -177,6 +179,7 @@ async function handleTool(auth, name, args) {
177
179
  currentSessionId,
178
180
  currentPersona,
179
181
  currentRole,
182
+ currentProjectId,
180
183
  tokenUsage: sessionTokenUsage,
181
184
  },
182
185
  updateSession: (updates) => {
@@ -186,6 +189,8 @@ async function handleTool(auth, name, args) {
186
189
  currentPersona = updates.currentPersona;
187
190
  if (updates.currentRole !== undefined)
188
191
  currentRole = updates.currentRole;
192
+ if (updates.currentProjectId !== undefined)
193
+ currentProjectId = updates.currentProjectId;
189
194
  if (updates.tokenUsage !== undefined)
190
195
  sessionTokenUsage = updates.tokenUsage;
191
196
  },
@@ -293,7 +298,7 @@ async function main() {
293
298
  };
294
299
  }
295
300
  // Handle database errors with better context
296
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
301
+ const errorMessage = getErrorMessage(error);
297
302
  let hint;
298
303
  if (errorMessage.includes('violates foreign key constraint')) {
299
304
  hint = 'The referenced ID does not exist. Check that the project_id, task_id, or other IDs are correct.';
@@ -4,6 +4,7 @@
4
4
  * Functions for estimating and tracking token usage across MCP tool calls.
5
5
  * Extracted from index.ts to enable unit testing.
6
6
  */
7
+ import { getErrorMessage } from './utils.js';
7
8
  // ============================================================================
8
9
  // Token Estimation
9
10
  // ============================================================================
@@ -21,8 +22,7 @@ export function estimateTokens(obj) {
21
22
  }
22
23
  catch (error) {
23
24
  // Log warning when serialization fails (e.g., circular references, BigInt)
24
- const errorMessage = error instanceof Error ? error.message : String(error);
25
- console.warn(`[Vibescope] Token estimation failed: ${errorMessage}. Returning minimal estimate of 1 token.`);
25
+ console.warn(`[Vibescope] Token estimation failed: ${getErrorMessage(error)}. Returning minimal estimate of 1 token.`);
26
26
  return 1;
27
27
  }
28
28
  }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Blocker Tool Definitions
3
+ *
4
+ * Tools for managing blockers:
5
+ * - add_blocker
6
+ * - resolve_blocker
7
+ * - get_blocker
8
+ * - get_blockers
9
+ * - get_blockers_stats
10
+ * - delete_blocker
11
+ */
12
+ import type { Tool } from './types.js';
13
+ export declare const blockerTools: Tool[];
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Blocker Tool Definitions
3
+ *
4
+ * Tools for managing blockers:
5
+ * - add_blocker
6
+ * - resolve_blocker
7
+ * - get_blocker
8
+ * - get_blockers
9
+ * - get_blockers_stats
10
+ * - delete_blocker
11
+ */
12
+ export const blockerTools = [
13
+ {
14
+ name: 'add_blocker',
15
+ description: `Record a blocker preventing progress.`,
16
+ inputSchema: {
17
+ type: 'object',
18
+ properties: {
19
+ project_id: {
20
+ type: 'string',
21
+ description: 'Project UUID',
22
+ },
23
+ description: {
24
+ type: 'string',
25
+ description: 'What is blocking progress?',
26
+ },
27
+ },
28
+ required: ['project_id', 'description'],
29
+ },
30
+ },
31
+ {
32
+ name: 'resolve_blocker',
33
+ description: `Mark a blocker as resolved.`,
34
+ inputSchema: {
35
+ type: 'object',
36
+ properties: {
37
+ blocker_id: {
38
+ type: 'string',
39
+ description: 'Blocker UUID',
40
+ },
41
+ resolution_note: {
42
+ type: 'string',
43
+ description: 'How was it resolved?',
44
+ },
45
+ },
46
+ required: ['blocker_id'],
47
+ },
48
+ },
49
+ {
50
+ name: 'get_blocker',
51
+ description: `Get a single blocker by ID. More token-efficient than get_blockers when you need details for a specific blocker.`,
52
+ inputSchema: {
53
+ type: 'object',
54
+ properties: {
55
+ blocker_id: {
56
+ type: 'string',
57
+ description: 'Blocker UUID',
58
+ },
59
+ },
60
+ required: ['blocker_id'],
61
+ },
62
+ },
63
+ {
64
+ name: 'get_blockers',
65
+ description: `Get blockers for a project, optionally filtered by status.`,
66
+ inputSchema: {
67
+ type: 'object',
68
+ properties: {
69
+ project_id: {
70
+ type: 'string',
71
+ description: 'Project UUID',
72
+ },
73
+ status: {
74
+ type: 'string',
75
+ enum: ['open', 'resolved'],
76
+ description: 'Filter by status (default: open)',
77
+ },
78
+ limit: {
79
+ type: 'number',
80
+ description: 'Max number of blockers to return (default 10, max 200)',
81
+ },
82
+ offset: {
83
+ type: 'number',
84
+ description: 'Number of blockers to skip for pagination (default 0)',
85
+ },
86
+ search_query: {
87
+ type: 'string',
88
+ description: 'Search blockers by description',
89
+ },
90
+ },
91
+ required: ['project_id'],
92
+ },
93
+ },
94
+ {
95
+ name: 'get_blockers_stats',
96
+ description: `Get aggregate statistics about blockers for a project. Returns total count and breakdown by status. Much more token-efficient than get_blockers when you just need to understand the overall state.`,
97
+ inputSchema: {
98
+ type: 'object',
99
+ properties: {
100
+ project_id: { type: 'string', description: 'Project UUID' },
101
+ },
102
+ required: ['project_id'],
103
+ },
104
+ },
105
+ {
106
+ name: 'delete_blocker',
107
+ description: `Delete a blocker.`,
108
+ inputSchema: {
109
+ type: 'object',
110
+ properties: {
111
+ blocker_id: {
112
+ type: 'string',
113
+ description: 'Blocker UUID',
114
+ },
115
+ },
116
+ required: ['blocker_id'],
117
+ },
118
+ },
119
+ ];
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Bodies of Work Tool Definitions
3
+ *
4
+ * Tools for managing grouped task collections:
5
+ * - create_body_of_work
6
+ * - update_body_of_work
7
+ * - get_body_of_work
8
+ * - get_bodies_of_work
9
+ * - delete_body_of_work
10
+ * - add_task_to_body_of_work
11
+ * - remove_task_from_body_of_work
12
+ * - activate_body_of_work
13
+ * - add_task_dependency
14
+ * - remove_task_dependency
15
+ * - get_task_dependencies
16
+ * - get_next_body_of_work_task
17
+ */
18
+ import type { Tool } from './types.js';
19
+ export declare const bodiesOfWorkTools: Tool[];