@vibescope/mcp-server 0.5.0 → 0.5.2

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 (162) hide show
  1. package/CHANGELOG.md +84 -84
  2. package/README.md +194 -194
  3. package/dist/api-client/tasks.d.ts +1 -0
  4. package/dist/cli-init.js +21 -21
  5. package/dist/cli.js +26 -26
  6. package/dist/handlers/session.js +3 -1
  7. package/dist/handlers/tasks.js +7 -1
  8. package/dist/handlers/tool-docs.js +1216 -1216
  9. package/dist/index.js +73 -73
  10. package/dist/templates/agent-guidelines.d.ts +1 -1
  11. package/dist/templates/agent-guidelines.js +205 -205
  12. package/dist/templates/help-content.js +1621 -1621
  13. package/dist/tools/bodies-of-work.js +6 -6
  14. package/dist/tools/cloud-agents.js +22 -22
  15. package/dist/tools/milestones.js +2 -2
  16. package/dist/tools/requests.js +1 -1
  17. package/dist/tools/session.js +11 -11
  18. package/dist/tools/sprints.js +9 -9
  19. package/dist/tools/tasks.js +43 -35
  20. package/dist/tools/worktrees.js +14 -14
  21. package/dist/utils.js +11 -11
  22. package/docs/TOOLS.md +2687 -2685
  23. package/package.json +53 -53
  24. package/scripts/generate-docs.ts +212 -212
  25. package/scripts/version-bump.ts +203 -203
  26. package/src/api-client/blockers.ts +86 -86
  27. package/src/api-client/bodies-of-work.ts +194 -194
  28. package/src/api-client/chat.ts +50 -50
  29. package/src/api-client/connectors.ts +152 -152
  30. package/src/api-client/cost.ts +185 -185
  31. package/src/api-client/decisions.ts +87 -87
  32. package/src/api-client/deployment.ts +313 -313
  33. package/src/api-client/discovery.ts +81 -81
  34. package/src/api-client/fallback.ts +52 -52
  35. package/src/api-client/file-checkouts.ts +115 -115
  36. package/src/api-client/findings.ts +100 -100
  37. package/src/api-client/git-issues.ts +88 -88
  38. package/src/api-client/ideas.ts +112 -112
  39. package/src/api-client/index.ts +592 -592
  40. package/src/api-client/milestones.ts +83 -83
  41. package/src/api-client/organizations.ts +185 -185
  42. package/src/api-client/progress.ts +94 -94
  43. package/src/api-client/project.ts +181 -181
  44. package/src/api-client/requests.ts +54 -54
  45. package/src/api-client/session.ts +220 -220
  46. package/src/api-client/sprints.ts +227 -227
  47. package/src/api-client/subtasks.ts +57 -57
  48. package/src/api-client/tasks.ts +451 -450
  49. package/src/api-client/types.ts +32 -32
  50. package/src/api-client/validation.ts +60 -60
  51. package/src/api-client/worktrees.ts +53 -53
  52. package/src/api-client.test.ts +847 -847
  53. package/src/api-client.ts +2728 -2728
  54. package/src/cli-init.ts +558 -558
  55. package/src/cli.test.ts +284 -284
  56. package/src/cli.ts +204 -204
  57. package/src/handlers/__test-setup__.ts +240 -240
  58. package/src/handlers/__test-utils__.ts +89 -89
  59. package/src/handlers/blockers.test.ts +468 -468
  60. package/src/handlers/blockers.ts +172 -172
  61. package/src/handlers/bodies-of-work.test.ts +704 -704
  62. package/src/handlers/bodies-of-work.ts +526 -526
  63. package/src/handlers/chat.test.ts +185 -185
  64. package/src/handlers/chat.ts +101 -101
  65. package/src/handlers/cloud-agents.test.ts +438 -438
  66. package/src/handlers/cloud-agents.ts +156 -156
  67. package/src/handlers/connectors.test.ts +834 -834
  68. package/src/handlers/connectors.ts +229 -229
  69. package/src/handlers/cost.test.ts +462 -462
  70. package/src/handlers/cost.ts +285 -285
  71. package/src/handlers/decisions.test.ts +382 -382
  72. package/src/handlers/decisions.ts +153 -153
  73. package/src/handlers/deployment.test.ts +551 -551
  74. package/src/handlers/deployment.ts +570 -570
  75. package/src/handlers/discovery.test.ts +206 -206
  76. package/src/handlers/discovery.ts +433 -433
  77. package/src/handlers/fallback.test.ts +537 -537
  78. package/src/handlers/fallback.ts +194 -194
  79. package/src/handlers/file-checkouts.test.ts +750 -750
  80. package/src/handlers/file-checkouts.ts +185 -185
  81. package/src/handlers/findings.test.ts +633 -633
  82. package/src/handlers/findings.ts +239 -239
  83. package/src/handlers/git-issues.test.ts +631 -631
  84. package/src/handlers/git-issues.ts +136 -136
  85. package/src/handlers/ideas.test.ts +644 -644
  86. package/src/handlers/ideas.ts +207 -207
  87. package/src/handlers/index.ts +93 -93
  88. package/src/handlers/milestones.test.ts +475 -475
  89. package/src/handlers/milestones.ts +180 -180
  90. package/src/handlers/organizations.test.ts +826 -826
  91. package/src/handlers/organizations.ts +315 -315
  92. package/src/handlers/progress.test.ts +269 -269
  93. package/src/handlers/progress.ts +77 -77
  94. package/src/handlers/project.test.ts +546 -546
  95. package/src/handlers/project.ts +245 -245
  96. package/src/handlers/requests.test.ts +303 -303
  97. package/src/handlers/requests.ts +99 -99
  98. package/src/handlers/roles.test.ts +305 -305
  99. package/src/handlers/roles.ts +219 -219
  100. package/src/handlers/session.test.ts +998 -998
  101. package/src/handlers/session.ts +1107 -1105
  102. package/src/handlers/sprints.test.ts +732 -732
  103. package/src/handlers/sprints.ts +537 -537
  104. package/src/handlers/tasks.test.ts +931 -931
  105. package/src/handlers/tasks.ts +1144 -1137
  106. package/src/handlers/tool-categories.test.ts +66 -66
  107. package/src/handlers/tool-docs.test.ts +511 -511
  108. package/src/handlers/tool-docs.ts +1595 -1595
  109. package/src/handlers/types.test.ts +259 -259
  110. package/src/handlers/types.ts +176 -176
  111. package/src/handlers/validation.test.ts +582 -582
  112. package/src/handlers/validation.ts +164 -164
  113. package/src/handlers/version.ts +63 -63
  114. package/src/index.test.ts +674 -674
  115. package/src/index.ts +884 -884
  116. package/src/setup.test.ts +243 -243
  117. package/src/setup.ts +410 -410
  118. package/src/templates/agent-guidelines.ts +233 -233
  119. package/src/templates/help-content.ts +1751 -1751
  120. package/src/token-tracking.test.ts +463 -463
  121. package/src/token-tracking.ts +167 -167
  122. package/src/tools/blockers.ts +122 -122
  123. package/src/tools/bodies-of-work.ts +283 -283
  124. package/src/tools/chat.ts +72 -72
  125. package/src/tools/cloud-agents.ts +101 -101
  126. package/src/tools/connectors.ts +191 -191
  127. package/src/tools/cost.ts +111 -111
  128. package/src/tools/decisions.ts +111 -111
  129. package/src/tools/deployment.ts +455 -455
  130. package/src/tools/discovery.ts +76 -76
  131. package/src/tools/fallback.ts +111 -111
  132. package/src/tools/features.ts +154 -154
  133. package/src/tools/file-checkouts.ts +145 -145
  134. package/src/tools/findings.ts +101 -101
  135. package/src/tools/git-issues.ts +130 -130
  136. package/src/tools/ideas.ts +162 -162
  137. package/src/tools/index.ts +145 -145
  138. package/src/tools/milestones.ts +118 -118
  139. package/src/tools/organizations.ts +224 -224
  140. package/src/tools/persona-templates.ts +25 -25
  141. package/src/tools/progress.ts +73 -73
  142. package/src/tools/project.ts +210 -210
  143. package/src/tools/requests.ts +68 -68
  144. package/src/tools/roles.ts +112 -112
  145. package/src/tools/session.ts +181 -181
  146. package/src/tools/sprints.ts +298 -298
  147. package/src/tools/tasks.ts +583 -575
  148. package/src/tools/tools.test.ts +222 -222
  149. package/src/tools/types.ts +9 -9
  150. package/src/tools/validation.ts +75 -75
  151. package/src/tools/version.ts +34 -34
  152. package/src/tools/worktrees.ts +66 -66
  153. package/src/tools.test.ts +416 -416
  154. package/src/utils.test.ts +1014 -1014
  155. package/src/utils.ts +586 -586
  156. package/src/validators.test.ts +223 -223
  157. package/src/validators.ts +249 -249
  158. package/src/version.ts +162 -162
  159. package/tsconfig.json +16 -16
  160. package/vitest.config.ts +14 -14
  161. package/dist/tools.d.ts +0 -2
  162. package/dist/tools.js +0 -3602
@@ -1,592 +1,592 @@
1
- /**
2
- * Vibescope API Client
3
- *
4
- * HTTP client for communicating with the Vibescope API.
5
- * All database operations are handled server-side through these endpoints.
6
- *
7
- * This module composes domain-specific API methods into a unified client.
8
- */
9
-
10
- import type { ApiClientConfig, ApiResponse, RetryConfig, RequestFn, ProxyFn } from './types.js';
11
- import { createSessionMethods, type SessionMethods } from './session.js';
12
- import { createProjectMethods, type ProjectMethods } from './project.js';
13
- import { createBlockersMethods, type BlockersMethods } from './blockers.js';
14
- import { createCostMethods, type CostMethods } from './cost.js';
15
- import { createWorktreesMethods, type WorktreesMethods } from './worktrees.js';
16
- import { createDiscoveryMethods, type DiscoveryMethods } from './discovery.js';
17
- import { createDecisionsMethods, type DecisionsMethods } from './decisions.js';
18
- import { createIdeasMethods, type IdeasMethods } from './ideas.js';
19
- import { createTasksMethods, type TasksMethods } from './tasks.js';
20
- import { createFindingsMethods, type FindingsMethods } from './findings.js';
21
- import { createMilestonesMethods, type MilestonesMethods } from './milestones.js';
22
- import { createValidationMethods, type ValidationMethods } from './validation.js';
23
- import { createFallbackMethods, type FallbackMethods } from './fallback.js';
24
- import { createRequestsMethods, type RequestsMethods } from './requests.js';
25
- import { createDeploymentMethods, type DeploymentMethods } from './deployment.js';
26
- import { createOrganizationsMethods, type OrganizationsMethods } from './organizations.js';
27
- import { createBodiesOfWorkMethods, type BodiesOfWorkMethods } from './bodies-of-work.js';
28
- import { createGitIssuesMethods, type GitIssuesMethods } from './git-issues.js';
29
- import { createFileCheckoutsMethods, type FileCheckoutsMethods } from './file-checkouts.js';
30
- import { createConnectorsMethods, type ConnectorsMethods } from './connectors.js';
31
- import { createSprintsMethods, type SprintsMethods } from './sprints.js';
32
- import { createSubtasksMethods, type SubtasksMethods } from './subtasks.js';
33
- import { createProgressMethods, type ProgressMethods } from './progress.js';
34
- import { createChatMethods, type ChatMethods } from './chat.js';
35
-
36
- // Re-export types
37
- export type { ApiClientConfig, ApiResponse, RetryConfig, RequestFn, ProxyFn } from './types.js';
38
- export type { SessionMethods } from './session.js';
39
- export type { ProjectMethods } from './project.js';
40
- export type { BlockersMethods } from './blockers.js';
41
- export type { CostMethods } from './cost.js';
42
- export type { WorktreesMethods } from './worktrees.js';
43
- export type { DiscoveryMethods } from './discovery.js';
44
- export type { DecisionsMethods } from './decisions.js';
45
- export type { IdeasMethods } from './ideas.js';
46
- export type { TasksMethods } from './tasks.js';
47
- export type { FindingsMethods } from './findings.js';
48
- export type { MilestonesMethods } from './milestones.js';
49
- export type { ValidationMethods } from './validation.js';
50
- export type { FallbackMethods } from './fallback.js';
51
- export type { RequestsMethods } from './requests.js';
52
- export type { DeploymentMethods } from './deployment.js';
53
- export type { OrganizationsMethods } from './organizations.js';
54
- export type { BodiesOfWorkMethods } from './bodies-of-work.js';
55
- export type { GitIssuesMethods } from './git-issues.js';
56
- export type { FileCheckoutsMethods } from './file-checkouts.js';
57
- export type { ConnectorsMethods } from './connectors.js';
58
- export type { SprintsMethods } from './sprints.js';
59
- export type { SubtasksMethods } from './subtasks.js';
60
- export type { ProgressMethods } from './progress.js';
61
- export type { ChatMethods } from './chat.js';
62
-
63
- const DEFAULT_API_URL = 'https://vibescope.dev';
64
-
65
- // Retry configuration defaults
66
- const DEFAULT_RETRY_STATUS_CODES = [429, 503, 504];
67
- const DEFAULT_MAX_RETRIES = 3;
68
- const DEFAULT_BASE_DELAY_MS = 1000;
69
- const DEFAULT_MAX_DELAY_MS = 30000;
70
-
71
- /**
72
- * Calculate delay for exponential backoff with jitter
73
- */
74
- function calculateBackoffDelay(
75
- attempt: number,
76
- baseDelayMs: number,
77
- maxDelayMs: number,
78
- retryAfter?: number
79
- ): number {
80
- if (retryAfter !== undefined && retryAfter > 0) {
81
- return Math.min(retryAfter * 1000, maxDelayMs);
82
- }
83
- const exponentialDelay = baseDelayMs * Math.pow(2, attempt);
84
- const jitter = Math.random() * 0.3 * exponentialDelay;
85
- return Math.min(exponentialDelay + jitter, maxDelayMs);
86
- }
87
-
88
- /**
89
- * Sleep for a specified duration
90
- */
91
- function sleep(ms: number): Promise<void> {
92
- return new Promise(resolve => setTimeout(resolve, ms));
93
- }
94
-
95
- /**
96
- * Combined interface for all API methods
97
- */
98
- export interface VibescopeApiClientMethods
99
- extends SessionMethods,
100
- ProjectMethods,
101
- BlockersMethods,
102
- CostMethods,
103
- WorktreesMethods,
104
- DiscoveryMethods,
105
- DecisionsMethods,
106
- IdeasMethods,
107
- TasksMethods,
108
- FindingsMethods,
109
- MilestonesMethods,
110
- ValidationMethods,
111
- FallbackMethods,
112
- RequestsMethods,
113
- DeploymentMethods,
114
- OrganizationsMethods,
115
- BodiesOfWorkMethods,
116
- GitIssuesMethods,
117
- FileCheckoutsMethods,
118
- ConnectorsMethods,
119
- SprintsMethods,
120
- SubtasksMethods,
121
- ProgressMethods,
122
- ChatMethods {}
123
-
124
- export class VibescopeApiClient implements VibescopeApiClientMethods {
125
- private apiKey: string;
126
- private baseUrl: string;
127
- private retryConfig: Required<RetryConfig>;
128
-
129
- // Domain method implementations
130
- private sessionMethods: SessionMethods;
131
- private projectMethods: ProjectMethods;
132
- private blockersMethods: BlockersMethods;
133
- private costMethods: CostMethods;
134
- private worktreesMethods: WorktreesMethods;
135
- private discoveryMethods: DiscoveryMethods;
136
- private decisionsMethods: DecisionsMethods;
137
- private ideasMethods: IdeasMethods;
138
- private tasksMethods: TasksMethods;
139
- private findingsMethods: FindingsMethods;
140
- private milestonesMethods: MilestonesMethods;
141
- private validationMethods: ValidationMethods;
142
- private fallbackMethods: FallbackMethods;
143
- private requestsMethods: RequestsMethods;
144
- private deploymentMethods: DeploymentMethods;
145
- private organizationsMethods: OrganizationsMethods;
146
- private bodiesOfWorkMethods: BodiesOfWorkMethods;
147
- private gitIssuesMethods: GitIssuesMethods;
148
- private fileCheckoutsMethods: FileCheckoutsMethods;
149
- private connectorsMethods: ConnectorsMethods;
150
- private sprintsMethods: SprintsMethods;
151
- private subtasksMethods: SubtasksMethods;
152
- private progressMethods: ProgressMethods;
153
- private chatMethods: ChatMethods;
154
-
155
- constructor(config: ApiClientConfig) {
156
- this.apiKey = config.apiKey;
157
- this.baseUrl = config.baseUrl || process.env.VIBESCOPE_API_URL || DEFAULT_API_URL;
158
- this.retryConfig = {
159
- maxRetries: config.retry?.maxRetries ?? DEFAULT_MAX_RETRIES,
160
- baseDelayMs: config.retry?.baseDelayMs ?? DEFAULT_BASE_DELAY_MS,
161
- maxDelayMs: config.retry?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS,
162
- retryStatusCodes: config.retry?.retryStatusCodes ?? DEFAULT_RETRY_STATUS_CODES,
163
- };
164
-
165
- // Create bound request and proxy functions for domain modules
166
- const request: RequestFn = this.request.bind(this);
167
- const proxy: ProxyFn = this.proxy.bind(this);
168
- const getApiKey = () => this.apiKey;
169
-
170
- // Initialize domain methods
171
- this.sessionMethods = createSessionMethods(request, getApiKey);
172
- this.projectMethods = createProjectMethods(request);
173
- this.blockersMethods = createBlockersMethods(request);
174
- this.costMethods = createCostMethods(request);
175
- this.worktreesMethods = createWorktreesMethods(request);
176
- this.discoveryMethods = createDiscoveryMethods(request);
177
- this.decisionsMethods = createDecisionsMethods(proxy);
178
- this.ideasMethods = createIdeasMethods(proxy);
179
- this.tasksMethods = createTasksMethods(request, proxy);
180
- this.findingsMethods = createFindingsMethods(proxy);
181
- this.milestonesMethods = createMilestonesMethods(proxy);
182
- this.validationMethods = createValidationMethods(proxy);
183
- this.fallbackMethods = createFallbackMethods(proxy);
184
- this.requestsMethods = createRequestsMethods(proxy);
185
- this.deploymentMethods = createDeploymentMethods(proxy);
186
- this.organizationsMethods = createOrganizationsMethods(proxy);
187
- this.bodiesOfWorkMethods = createBodiesOfWorkMethods(proxy);
188
- this.gitIssuesMethods = createGitIssuesMethods(proxy);
189
- this.fileCheckoutsMethods = createFileCheckoutsMethods(proxy);
190
- this.connectorsMethods = createConnectorsMethods(proxy);
191
- this.sprintsMethods = createSprintsMethods(proxy);
192
- this.subtasksMethods = createSubtasksMethods(proxy);
193
- this.progressMethods = createProgressMethods(request, proxy);
194
- this.chatMethods = createChatMethods(proxy);
195
- }
196
-
197
- private async request<T>(method: string, path: string, body?: unknown): Promise<ApiResponse<T>> {
198
- const url = `${this.baseUrl}${path}`;
199
- const { maxRetries, baseDelayMs, maxDelayMs, retryStatusCodes } = this.retryConfig;
200
- let lastError: Error | null = null;
201
- let lastResponse: Response | null = null;
202
-
203
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
204
- try {
205
- const response = await fetch(url, {
206
- method,
207
- headers: {
208
- 'Content-Type': 'application/json',
209
- 'X-API-Key': this.apiKey
210
- },
211
- body: body ? JSON.stringify(body) : undefined
212
- });
213
-
214
- if (retryStatusCodes.includes(response.status) && attempt < maxRetries) {
215
- lastResponse = response;
216
- const retryAfterHeader = response.headers.get('Retry-After');
217
- let retryAfter: number | undefined;
218
- if (retryAfterHeader) {
219
- const parsed = parseInt(retryAfterHeader, 10);
220
- if (!isNaN(parsed)) {
221
- retryAfter = parsed;
222
- }
223
- }
224
- const delay = calculateBackoffDelay(attempt, baseDelayMs, maxDelayMs, retryAfter);
225
- await sleep(delay);
226
- continue;
227
- }
228
-
229
- if (!response.ok) {
230
- const errorData = await response.json().catch(() => ({}));
231
- return {
232
- ok: false,
233
- status: response.status,
234
- error: errorData.error || errorData.message || `HTTP ${response.status}`
235
- };
236
- }
237
-
238
- const data = await response.json();
239
- return {
240
- ok: true,
241
- status: response.status,
242
- data
243
- };
244
- } catch (error) {
245
- lastError = error as Error;
246
- if (attempt < maxRetries) {
247
- const delay = calculateBackoffDelay(attempt, baseDelayMs, maxDelayMs);
248
- await sleep(delay);
249
- continue;
250
- }
251
- }
252
- }
253
-
254
- if (lastResponse && !lastResponse.ok) {
255
- return {
256
- ok: false,
257
- status: lastResponse.status,
258
- error: `Request failed after ${maxRetries + 1} attempts with status ${lastResponse.status}`
259
- };
260
- }
261
-
262
- return {
263
- ok: false,
264
- status: 0,
265
- error: lastError?.message || 'Request failed after all retries'
266
- };
267
- }
268
-
269
- /**
270
- * Generic proxy method for operations that go through the MCP proxy endpoint
271
- */
272
- async proxy<T>(operation: string, args: Record<string, unknown>, sessionContext?: {
273
- session_id?: string;
274
- project_id?: string;
275
- }): Promise<ApiResponse<T>> {
276
- return this.request('POST', '/api/mcp/proxy', {
277
- operation,
278
- args,
279
- ...sessionContext
280
- });
281
- }
282
-
283
- // ============================================================================
284
- // Session methods (delegated)
285
- // ============================================================================
286
- validateAuth = () => this.sessionMethods.validateAuth();
287
- startSession = (params: Parameters<SessionMethods['startSession']>[0]) => this.sessionMethods.startSession(params);
288
- heartbeat = (sessionId: string, options?: Parameters<SessionMethods['heartbeat']>[1]) => this.sessionMethods.heartbeat(sessionId, options);
289
- endSession = (sessionId: string) => this.sessionMethods.endSession(sessionId);
290
- signalIdle = (sessionId: string) => this.sessionMethods.signalIdle(sessionId);
291
- syncSession = (sessionId: string, params?: Parameters<SessionMethods['syncSession']>[1]) => this.sessionMethods.syncSession(sessionId, params);
292
- confirmAgentSetup = (projectId: string, agentType: string) => this.sessionMethods.confirmAgentSetup(projectId, agentType);
293
-
294
- // ============================================================================
295
- // Project methods (delegated)
296
- // ============================================================================
297
- listProjects = () => this.projectMethods.listProjects();
298
- createProject = (params: Parameters<ProjectMethods['createProject']>[0]) => this.projectMethods.createProject(params);
299
- getProject = (projectId: string, gitUrl?: string) => this.projectMethods.getProject(projectId, gitUrl);
300
- updateProject = (projectId: string, updates: Parameters<ProjectMethods['updateProject']>[1]) => this.projectMethods.updateProject(projectId, updates);
301
- getGitWorkflow = (projectId: string, taskId?: string) => this.projectMethods.getGitWorkflow(projectId, taskId);
302
- updateProjectReadme = (projectId: string, readmeContent: string) => this.projectMethods.updateProjectReadme(projectId, readmeContent);
303
- getProjectSummary = (projectId: string) => this.projectMethods.getProjectSummary(projectId);
304
-
305
- // ============================================================================
306
- // Blockers methods (delegated)
307
- // ============================================================================
308
- getBlockers = (projectId: string, params?: Parameters<BlockersMethods['getBlockers']>[1]) => this.blockersMethods.getBlockers(projectId, params);
309
- addBlocker = (projectId: string, description: string, sessionId?: string) => this.blockersMethods.addBlocker(projectId, description, sessionId);
310
- resolveBlocker = (blockerId: string, resolutionNote?: string) => this.blockersMethods.resolveBlocker(blockerId, resolutionNote);
311
- deleteBlocker = (blockerId: string) => this.blockersMethods.deleteBlocker(blockerId);
312
- getBlockersStats = (projectId: string) => this.blockersMethods.getBlockersStats(projectId);
313
-
314
- // ============================================================================
315
- // Cost methods (delegated)
316
- // ============================================================================
317
- getCostSummary = (projectId: string, params?: Parameters<CostMethods['getCostSummary']>[1]) => this.costMethods.getCostSummary(projectId, params);
318
- getCostAlerts = () => this.costMethods.getCostAlerts();
319
- addCostAlert = (params: Parameters<CostMethods['addCostAlert']>[0]) => this.costMethods.addCostAlert(params);
320
- updateCostAlert = (alertId: string, updates: Parameters<CostMethods['updateCostAlert']>[1]) => this.costMethods.updateCostAlert(alertId, updates);
321
- deleteCostAlert = (alertId: string) => this.costMethods.deleteCostAlert(alertId);
322
- getTaskCosts = (projectId: string, limit?: number) => this.costMethods.getTaskCosts(projectId, limit);
323
- getBodyOfWorkCosts = (params: Parameters<CostMethods['getBodyOfWorkCosts']>[0]) => this.costMethods.getBodyOfWorkCosts(params);
324
- getSprintCosts = (params: Parameters<CostMethods['getSprintCosts']>[0]) => this.costMethods.getSprintCosts(params);
325
- getTokenUsage = () => this.costMethods.getTokenUsage();
326
- reportTokenUsage = (sessionId: string, params: Parameters<CostMethods['reportTokenUsage']>[1]) => this.costMethods.reportTokenUsage(sessionId, params);
327
-
328
- // ============================================================================
329
- // Worktrees methods (delegated)
330
- // ============================================================================
331
- getStaleWorktrees = (projectId: string, params?: Parameters<WorktreesMethods['getStaleWorktrees']>[1]) => this.worktreesMethods.getStaleWorktrees(projectId, params);
332
- clearWorktreePath = (taskId: string) => this.worktreesMethods.clearWorktreePath(taskId);
333
-
334
- // ============================================================================
335
- // Discovery methods (delegated)
336
- // ============================================================================
337
- queryKnowledgeBase = (projectId: string, params?: Parameters<DiscoveryMethods['queryKnowledgeBase']>[1]) => this.discoveryMethods.queryKnowledgeBase(projectId, params);
338
- getHelpTopic = (slug: string) => this.discoveryMethods.getHelpTopic(slug);
339
- getHelpTopics = () => this.discoveryMethods.getHelpTopics();
340
-
341
- // ============================================================================
342
- // Decisions methods (delegated)
343
- // ============================================================================
344
- getDecisions = (projectId: string, options?: Parameters<DecisionsMethods['getDecisions']>[1]) => this.decisionsMethods.getDecisions(projectId, options);
345
- getDecision = (decisionId: string) => this.decisionsMethods.getDecision(decisionId);
346
- logDecision = (projectId: string, params: Parameters<DecisionsMethods['logDecision']>[1], sessionId?: string) => this.decisionsMethods.logDecision(projectId, params, sessionId);
347
- deleteDecision = (decisionId: string) => this.decisionsMethods.deleteDecision(decisionId);
348
- getDecisionsStats = (projectId: string) => this.decisionsMethods.getDecisionsStats(projectId);
349
-
350
- // ============================================================================
351
- // Ideas methods (delegated)
352
- // ============================================================================
353
- getIdeas = (projectId: string, params?: Parameters<IdeasMethods['getIdeas']>[1]) => this.ideasMethods.getIdeas(projectId, params);
354
- getIdea = (ideaId: string) => this.ideasMethods.getIdea(ideaId);
355
- addIdea = (projectId: string, params: Parameters<IdeasMethods['addIdea']>[1], sessionId?: string) => this.ideasMethods.addIdea(projectId, params, sessionId);
356
- updateIdea = (ideaId: string, updates: Parameters<IdeasMethods['updateIdea']>[1]) => this.ideasMethods.updateIdea(ideaId, updates);
357
- deleteIdea = (ideaId: string) => this.ideasMethods.deleteIdea(ideaId);
358
- convertIdeaToTask = (ideaId: string, params?: Parameters<IdeasMethods['convertIdeaToTask']>[1]) => this.ideasMethods.convertIdeaToTask(ideaId, params);
359
-
360
- // ============================================================================
361
- // Tasks methods (delegated)
362
- // ============================================================================
363
- getTasks = (projectId: string, params?: Parameters<TasksMethods['getTasks']>[1]) => this.tasksMethods.getTasks(projectId, params);
364
- createTask = (projectId: string, params: Parameters<TasksMethods['createTask']>[1]) => this.tasksMethods.createTask(projectId, params);
365
- getNextTask = (projectId: string, sessionId?: string) => this.tasksMethods.getNextTask(projectId, sessionId);
366
- getTask = (taskId: string) => this.tasksMethods.getTask(taskId);
367
- getTaskById = (taskId: string, params?: Parameters<TasksMethods['getTaskById']>[1]) => this.tasksMethods.getTaskById(taskId, params);
368
- searchTasks = (projectId: string, params: Parameters<TasksMethods['searchTasks']>[1]) => this.tasksMethods.searchTasks(projectId, params);
369
- getTasksByPriority = (projectId: string, params?: Parameters<TasksMethods['getTasksByPriority']>[1]) => this.tasksMethods.getTasksByPriority(projectId, params);
370
- getRecentTasks = (projectId: string, params?: Parameters<TasksMethods['getRecentTasks']>[1]) => this.tasksMethods.getRecentTasks(projectId, params);
371
- getTaskStats = (projectId: string) => this.tasksMethods.getTaskStats(projectId);
372
- updateTask = (taskId: string, updates: Parameters<TasksMethods['updateTask']>[1]) => this.tasksMethods.updateTask(taskId, updates);
373
- completeTask = (taskId: string, params: Parameters<TasksMethods['completeTask']>[1]) => this.tasksMethods.completeTask(taskId, params);
374
- deleteTask = (taskId: string) => this.tasksMethods.deleteTask(taskId);
375
- releaseTask = (taskId: string, params?: Parameters<TasksMethods['releaseTask']>[1]) => this.tasksMethods.releaseTask(taskId, params);
376
- cancelTask = (taskId: string, params?: Parameters<TasksMethods['cancelTask']>[1]) => this.tasksMethods.cancelTask(taskId, params);
377
- addTaskReference = (taskId: string, url: string, label?: string) => this.tasksMethods.addTaskReference(taskId, url, label);
378
- removeTaskReference = (taskId: string, url: string) => this.tasksMethods.removeTaskReference(taskId, url);
379
- batchUpdateTasks = (updates: Parameters<TasksMethods['batchUpdateTasks']>[0]) => this.tasksMethods.batchUpdateTasks(updates);
380
- batchCompleteTasks = (completions: Parameters<TasksMethods['batchCompleteTasks']>[0]) => this.tasksMethods.batchCompleteTasks(completions);
381
-
382
- // ============================================================================
383
- // Findings methods (delegated)
384
- // ============================================================================
385
- getFindings = (projectId: string, params?: Parameters<FindingsMethods['getFindings']>[1]) => this.findingsMethods.getFindings(projectId, params);
386
- getFinding = (findingId: string) => this.findingsMethods.getFinding(findingId);
387
- getFindingsStats = (projectId: string) => this.findingsMethods.getFindingsStats(projectId);
388
- addFinding = (projectId: string, params: Parameters<FindingsMethods['addFinding']>[1], sessionId?: string) => this.findingsMethods.addFinding(projectId, params, sessionId);
389
- updateFinding = (findingId: string, updates: Parameters<FindingsMethods['updateFinding']>[1]) => this.findingsMethods.updateFinding(findingId, updates);
390
- deleteFinding = (findingId: string) => this.findingsMethods.deleteFinding(findingId);
391
-
392
- // ============================================================================
393
- // Milestones methods (delegated)
394
- // ============================================================================
395
- getMilestones = (taskId: string) => this.milestonesMethods.getMilestones(taskId);
396
- addMilestone = (taskId: string, params: Parameters<MilestonesMethods['addMilestone']>[1], sessionId?: string) => this.milestonesMethods.addMilestone(taskId, params, sessionId);
397
- updateMilestone = (milestoneId: string, updates: Parameters<MilestonesMethods['updateMilestone']>[1]) => this.milestonesMethods.updateMilestone(milestoneId, updates);
398
- completeMilestone = (milestoneId: string) => this.milestonesMethods.completeMilestone(milestoneId);
399
- deleteMilestone = (milestoneId: string) => this.milestonesMethods.deleteMilestone(milestoneId);
400
-
401
- // ============================================================================
402
- // Validation methods (delegated)
403
- // ============================================================================
404
- getTasksAwaitingValidation = (projectId: string) => this.validationMethods.getTasksAwaitingValidation(projectId);
405
- claimValidation = (taskId: string, sessionId?: string) => this.validationMethods.claimValidation(taskId, sessionId);
406
- validateTask = (taskId: string, params: Parameters<ValidationMethods['validateTask']>[1], sessionId?: string) => this.validationMethods.validateTask(taskId, params, sessionId);
407
-
408
- // ============================================================================
409
- // Fallback activity methods (delegated)
410
- // ============================================================================
411
- startFallbackActivity = (projectId: string, activity: string, sessionId?: string) => this.fallbackMethods.startFallbackActivity(projectId, activity, sessionId);
412
- stopFallbackActivity = (projectId: string, summary?: string, sessionId?: string) => this.fallbackMethods.stopFallbackActivity(projectId, summary, sessionId);
413
-
414
- // ============================================================================
415
- // Requests methods (delegated)
416
- // ============================================================================
417
- getPendingRequests = (projectId: string, sessionId?: string, limit?: number, offset?: number) => this.requestsMethods.getPendingRequests(projectId, sessionId, limit, offset);
418
- acknowledgeRequest = (requestId: string, sessionId?: string) => this.requestsMethods.acknowledgeRequest(requestId, sessionId);
419
- answerQuestion = (requestId: string, answer: string, sessionId?: string) => this.requestsMethods.answerQuestion(requestId, answer, sessionId);
420
-
421
- // ============================================================================
422
- // Deployment methods (delegated)
423
- // ============================================================================
424
- requestDeployment = (projectId: string, params?: Parameters<DeploymentMethods['requestDeployment']>[1], sessionId?: string) => this.deploymentMethods.requestDeployment(projectId, params, sessionId);
425
- checkDeploymentStatus = (projectId: string) => this.deploymentMethods.checkDeploymentStatus(projectId);
426
- claimDeploymentValidation = (projectId: string, sessionId?: string) => this.deploymentMethods.claimDeploymentValidation(projectId, sessionId);
427
- reportValidation = (projectId: string, params: Parameters<DeploymentMethods['reportValidation']>[1]) => this.deploymentMethods.reportValidation(projectId, params);
428
- startDeployment = (projectId: string, sessionId?: string) => this.deploymentMethods.startDeployment(projectId, sessionId);
429
- completeDeployment = (projectId: string, params: Parameters<DeploymentMethods['completeDeployment']>[1]) => this.deploymentMethods.completeDeployment(projectId, params);
430
- cancelDeployment = (projectId: string, reason?: string) => this.deploymentMethods.cancelDeployment(projectId, reason);
431
- addDeploymentRequirement = (projectId: string, params: Parameters<DeploymentMethods['addDeploymentRequirement']>[1]) => this.deploymentMethods.addDeploymentRequirement(projectId, params);
432
- getDeploymentRequirements = (projectId: string, params?: Parameters<DeploymentMethods['getDeploymentRequirements']>[1]) => this.deploymentMethods.getDeploymentRequirements(projectId, params);
433
- getDeploymentRequirementsStats = (projectId: string) => this.deploymentMethods.getDeploymentRequirementsStats(projectId);
434
- completeDeploymentRequirement = (requirementId: string) => this.deploymentMethods.completeDeploymentRequirement(requirementId);
435
- reorderDeploymentRequirements = (projectId: string, params: Parameters<DeploymentMethods['reorderDeploymentRequirements']>[1]) => this.deploymentMethods.reorderDeploymentRequirements(projectId, params);
436
- scheduleDeployment = (projectId: string, params: Parameters<DeploymentMethods['scheduleDeployment']>[1]) => this.deploymentMethods.scheduleDeployment(projectId, params);
437
- getScheduledDeployments = (projectId: string, params?: Parameters<DeploymentMethods['getScheduledDeployments']>[1]) => this.deploymentMethods.getScheduledDeployments(projectId, params);
438
- updateScheduledDeployment = (scheduleId: string, updates: Parameters<DeploymentMethods['updateScheduledDeployment']>[1]) => this.deploymentMethods.updateScheduledDeployment(scheduleId, updates);
439
- deleteScheduledDeployment = (scheduleId: string) => this.deploymentMethods.deleteScheduledDeployment(scheduleId);
440
- triggerScheduledDeployment = (scheduleId: string, sessionId?: string) => this.deploymentMethods.triggerScheduledDeployment(scheduleId, sessionId);
441
- checkDueDeployments = (projectId: string) => this.deploymentMethods.checkDueDeployments(projectId);
442
-
443
- // ============================================================================
444
- // Organizations methods (delegated)
445
- // ============================================================================
446
- listOrganizations = () => this.organizationsMethods.listOrganizations();
447
- createOrganization = (params: Parameters<OrganizationsMethods['createOrganization']>[0]) => this.organizationsMethods.createOrganization(params);
448
- updateOrganization = (organizationId: string, updates: Parameters<OrganizationsMethods['updateOrganization']>[1]) => this.organizationsMethods.updateOrganization(organizationId, updates);
449
- deleteOrganization = (organizationId: string) => this.organizationsMethods.deleteOrganization(organizationId);
450
- listOrgMembers = (organizationId: string) => this.organizationsMethods.listOrgMembers(organizationId);
451
- inviteMember = (organizationId: string, email: string, role?: string) => this.organizationsMethods.inviteMember(organizationId, email, role);
452
- updateMemberRole = (organizationId: string, userId: string, role: string) => this.organizationsMethods.updateMemberRole(organizationId, userId, role);
453
- removeMember = (organizationId: string, userId: string) => this.organizationsMethods.removeMember(organizationId, userId);
454
- leaveOrganization = (organizationId: string) => this.organizationsMethods.leaveOrganization(organizationId);
455
- shareProjectWithOrg = (projectId: string, organizationId: string, permission?: string) => this.organizationsMethods.shareProjectWithOrg(projectId, organizationId, permission);
456
- unshareProject = (projectId: string, organizationId: string) => this.organizationsMethods.unshareProject(projectId, organizationId);
457
- updateProjectShare = (projectId: string, organizationId: string, permission: string) => this.organizationsMethods.updateProjectShare(projectId, organizationId, permission);
458
- listProjectShares = (projectId: string) => this.organizationsMethods.listProjectShares(projectId);
459
-
460
- // ============================================================================
461
- // Bodies of work methods (delegated)
462
- // ============================================================================
463
- createBodyOfWork = (projectId: string, params: Parameters<BodiesOfWorkMethods['createBodyOfWork']>[1]) => this.bodiesOfWorkMethods.createBodyOfWork(projectId, params);
464
- getBodyOfWork = (bodyOfWorkId: string) => this.bodiesOfWorkMethods.getBodyOfWork(bodyOfWorkId);
465
- getBodiesOfWork = (projectId: string, params?: Parameters<BodiesOfWorkMethods['getBodiesOfWork']>[1]) => this.bodiesOfWorkMethods.getBodiesOfWork(projectId, params);
466
- updateBodyOfWork = (bodyOfWorkId: string, updates: Parameters<BodiesOfWorkMethods['updateBodyOfWork']>[1]) => this.bodiesOfWorkMethods.updateBodyOfWork(bodyOfWorkId, updates);
467
- deleteBodyOfWork = (bodyOfWorkId: string) => this.bodiesOfWorkMethods.deleteBodyOfWork(bodyOfWorkId);
468
- addTaskToBodyOfWork = (bodyOfWorkId: string, taskId: string, phase?: string, orderIndex?: number) => this.bodiesOfWorkMethods.addTaskToBodyOfWork(bodyOfWorkId, taskId, phase, orderIndex);
469
- removeTaskFromBodyOfWork = (taskId: string) => this.bodiesOfWorkMethods.removeTaskFromBodyOfWork(taskId);
470
- activateBodyOfWork = (bodyOfWorkId: string) => this.bodiesOfWorkMethods.activateBodyOfWork(bodyOfWorkId);
471
- addTaskDependency = (bodyOfWorkId: string, taskId: string, dependsOnTaskId: string) => this.bodiesOfWorkMethods.addTaskDependency(bodyOfWorkId, taskId, dependsOnTaskId);
472
- removeTaskDependency = (taskId: string, dependsOnTaskId: string) => this.bodiesOfWorkMethods.removeTaskDependency(taskId, dependsOnTaskId);
473
- getTaskDependencies = (params: Parameters<BodiesOfWorkMethods['getTaskDependencies']>[0]) => this.bodiesOfWorkMethods.getTaskDependencies(params);
474
- getNextBodyOfWorkTask = (bodyOfWorkId: string) => this.bodiesOfWorkMethods.getNextBodyOfWorkTask(bodyOfWorkId);
475
-
476
- // ============================================================================
477
- // Git issues methods (delegated)
478
- // ============================================================================
479
- addGitIssue = (projectId: string, params: Parameters<GitIssuesMethods['addGitIssue']>[1], sessionId?: string) => this.gitIssuesMethods.addGitIssue(projectId, params, sessionId);
480
- resolveGitIssue = (gitIssueId: string, params?: Parameters<GitIssuesMethods['resolveGitIssue']>[1], sessionId?: string) => this.gitIssuesMethods.resolveGitIssue(gitIssueId, params, sessionId);
481
- getGitIssues = (projectId: string, params?: Parameters<GitIssuesMethods['getGitIssues']>[1]) => this.gitIssuesMethods.getGitIssues(projectId, params);
482
- deleteGitIssue = (gitIssueId: string) => this.gitIssuesMethods.deleteGitIssue(gitIssueId);
483
-
484
- // ============================================================================
485
- // File checkouts methods (delegated)
486
- // ============================================================================
487
- checkoutFile = (projectId: string, filePath: string, reason?: string, sessionId?: string) => this.fileCheckoutsMethods.checkoutFile(projectId, filePath, reason, sessionId);
488
- checkinFile = (params: Parameters<FileCheckoutsMethods['checkinFile']>[0], sessionId?: string) => this.fileCheckoutsMethods.checkinFile(params, sessionId);
489
- getFileCheckouts = (projectId: string, options?: Parameters<FileCheckoutsMethods['getFileCheckouts']>[1]) => this.fileCheckoutsMethods.getFileCheckouts(projectId, options);
490
- abandonCheckout = (params: Parameters<FileCheckoutsMethods['abandonCheckout']>[0]) => this.fileCheckoutsMethods.abandonCheckout(params);
491
- getFileCheckoutsStats = (projectId: string) => this.fileCheckoutsMethods.getFileCheckoutsStats(projectId);
492
- isFileAvailable = (projectId: string, filePath: string) => this.fileCheckoutsMethods.isFileAvailable(projectId, filePath);
493
-
494
- // ============================================================================
495
- // Connectors methods (delegated)
496
- // ============================================================================
497
- getConnectors = (projectId: string, params?: Parameters<ConnectorsMethods['getConnectors']>[1]) => this.connectorsMethods.getConnectors(projectId, params);
498
- getConnector = (connectorId: string) => this.connectorsMethods.getConnector(connectorId);
499
- addConnector = (projectId: string, params: Parameters<ConnectorsMethods['addConnector']>[1]) => this.connectorsMethods.addConnector(projectId, params);
500
- updateConnector = (connectorId: string, updates: Parameters<ConnectorsMethods['updateConnector']>[1]) => this.connectorsMethods.updateConnector(connectorId, updates);
501
- deleteConnector = (connectorId: string) => this.connectorsMethods.deleteConnector(connectorId);
502
- testConnector = (connectorId: string) => this.connectorsMethods.testConnector(connectorId);
503
- getConnectorEvents = (params: Parameters<ConnectorsMethods['getConnectorEvents']>[0]) => this.connectorsMethods.getConnectorEvents(params);
504
-
505
- // ============================================================================
506
- // Sprints methods (delegated)
507
- // ============================================================================
508
- createSprint = (projectId: string, params: Parameters<SprintsMethods['createSprint']>[1]) => this.sprintsMethods.createSprint(projectId, params);
509
- updateSprint = (sprintId: string, updates: Parameters<SprintsMethods['updateSprint']>[1]) => this.sprintsMethods.updateSprint(sprintId, updates);
510
- getSprint = (sprintId: string, summaryOnly?: boolean) => this.sprintsMethods.getSprint(sprintId, summaryOnly);
511
- getSprints = (projectId: string, params?: Parameters<SprintsMethods['getSprints']>[1]) => this.sprintsMethods.getSprints(projectId, params);
512
- deleteSprint = (sprintId: string) => this.sprintsMethods.deleteSprint(sprintId);
513
- startSprint = (sprintId: string) => this.sprintsMethods.startSprint(sprintId);
514
- completeSprint = (sprintId: string, params?: Parameters<SprintsMethods['completeSprint']>[1]) => this.sprintsMethods.completeSprint(sprintId, params);
515
- addTaskToSprint = (sprintId: string, taskId: string, params?: Parameters<SprintsMethods['addTaskToSprint']>[2]) => this.sprintsMethods.addTaskToSprint(sprintId, taskId, params);
516
- removeTaskFromSprint = (sprintId: string, taskId: string) => this.sprintsMethods.removeTaskFromSprint(sprintId, taskId);
517
- getSprintBacklog = (projectId: string, sprintId?: string, params?: Parameters<SprintsMethods['getSprintBacklog']>[2]) => this.sprintsMethods.getSprintBacklog(projectId, sprintId, params);
518
- getSprintVelocity = (projectId: string, limit?: number) => this.sprintsMethods.getSprintVelocity(projectId, limit);
519
-
520
- // ============================================================================
521
- // Subtasks methods (delegated)
522
- // ============================================================================
523
- addSubtask = (parentTaskId: string, params: Parameters<SubtasksMethods['addSubtask']>[1], sessionId?: string) => this.subtasksMethods.addSubtask(parentTaskId, params, sessionId);
524
- getSubtasks = (parentTaskId: string, status?: string) => this.subtasksMethods.getSubtasks(parentTaskId, status);
525
-
526
- // ============================================================================
527
- // Progress methods (delegated)
528
- // ============================================================================
529
- logProgress = (projectId: string, params: Parameters<ProgressMethods['logProgress']>[1]) => this.progressMethods.logProgress(projectId, params);
530
- getActivityFeed = (projectId: string, params?: Parameters<ProgressMethods['getActivityFeed']>[1]) => this.progressMethods.getActivityFeed(projectId, params);
531
- getActivityHistory = (projectId: string, params?: Parameters<ProgressMethods['getActivityHistory']>[1]) => this.progressMethods.getActivityHistory(projectId, params);
532
- getActivitySchedules = (projectId: string, params?: Parameters<ProgressMethods['getActivitySchedules']>[1]) => this.progressMethods.getActivitySchedules(projectId, params);
533
-
534
- // ============================================================================
535
- // Chat methods (delegated)
536
- // ============================================================================
537
- sendProjectMessage = (projectId: string, message: string, sessionId?: string) => this.chatMethods.sendProjectMessage(projectId, message, sessionId);
538
- getProjectMessages = (projectId: string, limit?: number) => this.chatMethods.getProjectMessages(projectId, limit);
539
- }
540
-
541
- // Singleton instance
542
- let apiClient: VibescopeApiClient | null = null;
543
-
544
- export function getApiClient(): VibescopeApiClient {
545
- if (!apiClient) {
546
- const apiKey = resolveApiKeyFromSources();
547
- apiClient = new VibescopeApiClient({ apiKey });
548
- }
549
- return apiClient;
550
- }
551
-
552
- /**
553
- * Resolve API key from multiple sources in priority order:
554
- * 1. VIBESCOPE_API_KEY env var (CI/cloud agents)
555
- * 2. ~/.vibescope/credentials.json (local dev)
556
- * 3. Error with helpful message
557
- */
558
- function resolveApiKeyFromSources(): string {
559
- // 1. Environment variable
560
- if (process.env.VIBESCOPE_API_KEY) {
561
- return process.env.VIBESCOPE_API_KEY;
562
- }
563
-
564
- // 2. Credentials file
565
- try {
566
- const { existsSync, readFileSync } = require('node:fs');
567
- const { homedir } = require('node:os');
568
- const { join } = require('node:path');
569
- const credPath = join(homedir(), '.vibescope', 'credentials.json');
570
- if (existsSync(credPath)) {
571
- const data = JSON.parse(readFileSync(credPath, 'utf-8'));
572
- if (data.apiKey) {
573
- return data.apiKey;
574
- }
575
- }
576
- } catch {
577
- // ignore read errors
578
- }
579
-
580
- // 3. Not found
581
- throw new Error(
582
- 'Vibescope API key not found.\n\n' +
583
- 'Set it up with:\n' +
584
- ' npx vibescope init\n\n' +
585
- 'Or set the VIBESCOPE_API_KEY environment variable.'
586
- );
587
- }
588
-
589
- export function initApiClient(config: ApiClientConfig): VibescopeApiClient {
590
- apiClient = new VibescopeApiClient(config);
591
- return apiClient;
592
- }
1
+ /**
2
+ * Vibescope API Client
3
+ *
4
+ * HTTP client for communicating with the Vibescope API.
5
+ * All database operations are handled server-side through these endpoints.
6
+ *
7
+ * This module composes domain-specific API methods into a unified client.
8
+ */
9
+
10
+ import type { ApiClientConfig, ApiResponse, RetryConfig, RequestFn, ProxyFn } from './types.js';
11
+ import { createSessionMethods, type SessionMethods } from './session.js';
12
+ import { createProjectMethods, type ProjectMethods } from './project.js';
13
+ import { createBlockersMethods, type BlockersMethods } from './blockers.js';
14
+ import { createCostMethods, type CostMethods } from './cost.js';
15
+ import { createWorktreesMethods, type WorktreesMethods } from './worktrees.js';
16
+ import { createDiscoveryMethods, type DiscoveryMethods } from './discovery.js';
17
+ import { createDecisionsMethods, type DecisionsMethods } from './decisions.js';
18
+ import { createIdeasMethods, type IdeasMethods } from './ideas.js';
19
+ import { createTasksMethods, type TasksMethods } from './tasks.js';
20
+ import { createFindingsMethods, type FindingsMethods } from './findings.js';
21
+ import { createMilestonesMethods, type MilestonesMethods } from './milestones.js';
22
+ import { createValidationMethods, type ValidationMethods } from './validation.js';
23
+ import { createFallbackMethods, type FallbackMethods } from './fallback.js';
24
+ import { createRequestsMethods, type RequestsMethods } from './requests.js';
25
+ import { createDeploymentMethods, type DeploymentMethods } from './deployment.js';
26
+ import { createOrganizationsMethods, type OrganizationsMethods } from './organizations.js';
27
+ import { createBodiesOfWorkMethods, type BodiesOfWorkMethods } from './bodies-of-work.js';
28
+ import { createGitIssuesMethods, type GitIssuesMethods } from './git-issues.js';
29
+ import { createFileCheckoutsMethods, type FileCheckoutsMethods } from './file-checkouts.js';
30
+ import { createConnectorsMethods, type ConnectorsMethods } from './connectors.js';
31
+ import { createSprintsMethods, type SprintsMethods } from './sprints.js';
32
+ import { createSubtasksMethods, type SubtasksMethods } from './subtasks.js';
33
+ import { createProgressMethods, type ProgressMethods } from './progress.js';
34
+ import { createChatMethods, type ChatMethods } from './chat.js';
35
+
36
+ // Re-export types
37
+ export type { ApiClientConfig, ApiResponse, RetryConfig, RequestFn, ProxyFn } from './types.js';
38
+ export type { SessionMethods } from './session.js';
39
+ export type { ProjectMethods } from './project.js';
40
+ export type { BlockersMethods } from './blockers.js';
41
+ export type { CostMethods } from './cost.js';
42
+ export type { WorktreesMethods } from './worktrees.js';
43
+ export type { DiscoveryMethods } from './discovery.js';
44
+ export type { DecisionsMethods } from './decisions.js';
45
+ export type { IdeasMethods } from './ideas.js';
46
+ export type { TasksMethods } from './tasks.js';
47
+ export type { FindingsMethods } from './findings.js';
48
+ export type { MilestonesMethods } from './milestones.js';
49
+ export type { ValidationMethods } from './validation.js';
50
+ export type { FallbackMethods } from './fallback.js';
51
+ export type { RequestsMethods } from './requests.js';
52
+ export type { DeploymentMethods } from './deployment.js';
53
+ export type { OrganizationsMethods } from './organizations.js';
54
+ export type { BodiesOfWorkMethods } from './bodies-of-work.js';
55
+ export type { GitIssuesMethods } from './git-issues.js';
56
+ export type { FileCheckoutsMethods } from './file-checkouts.js';
57
+ export type { ConnectorsMethods } from './connectors.js';
58
+ export type { SprintsMethods } from './sprints.js';
59
+ export type { SubtasksMethods } from './subtasks.js';
60
+ export type { ProgressMethods } from './progress.js';
61
+ export type { ChatMethods } from './chat.js';
62
+
63
+ const DEFAULT_API_URL = 'https://vibescope.dev';
64
+
65
+ // Retry configuration defaults
66
+ const DEFAULT_RETRY_STATUS_CODES = [429, 503, 504];
67
+ const DEFAULT_MAX_RETRIES = 3;
68
+ const DEFAULT_BASE_DELAY_MS = 1000;
69
+ const DEFAULT_MAX_DELAY_MS = 30000;
70
+
71
+ /**
72
+ * Calculate delay for exponential backoff with jitter
73
+ */
74
+ function calculateBackoffDelay(
75
+ attempt: number,
76
+ baseDelayMs: number,
77
+ maxDelayMs: number,
78
+ retryAfter?: number
79
+ ): number {
80
+ if (retryAfter !== undefined && retryAfter > 0) {
81
+ return Math.min(retryAfter * 1000, maxDelayMs);
82
+ }
83
+ const exponentialDelay = baseDelayMs * Math.pow(2, attempt);
84
+ const jitter = Math.random() * 0.3 * exponentialDelay;
85
+ return Math.min(exponentialDelay + jitter, maxDelayMs);
86
+ }
87
+
88
+ /**
89
+ * Sleep for a specified duration
90
+ */
91
+ function sleep(ms: number): Promise<void> {
92
+ return new Promise(resolve => setTimeout(resolve, ms));
93
+ }
94
+
95
+ /**
96
+ * Combined interface for all API methods
97
+ */
98
+ export interface VibescopeApiClientMethods
99
+ extends SessionMethods,
100
+ ProjectMethods,
101
+ BlockersMethods,
102
+ CostMethods,
103
+ WorktreesMethods,
104
+ DiscoveryMethods,
105
+ DecisionsMethods,
106
+ IdeasMethods,
107
+ TasksMethods,
108
+ FindingsMethods,
109
+ MilestonesMethods,
110
+ ValidationMethods,
111
+ FallbackMethods,
112
+ RequestsMethods,
113
+ DeploymentMethods,
114
+ OrganizationsMethods,
115
+ BodiesOfWorkMethods,
116
+ GitIssuesMethods,
117
+ FileCheckoutsMethods,
118
+ ConnectorsMethods,
119
+ SprintsMethods,
120
+ SubtasksMethods,
121
+ ProgressMethods,
122
+ ChatMethods {}
123
+
124
+ export class VibescopeApiClient implements VibescopeApiClientMethods {
125
+ private apiKey: string;
126
+ private baseUrl: string;
127
+ private retryConfig: Required<RetryConfig>;
128
+
129
+ // Domain method implementations
130
+ private sessionMethods: SessionMethods;
131
+ private projectMethods: ProjectMethods;
132
+ private blockersMethods: BlockersMethods;
133
+ private costMethods: CostMethods;
134
+ private worktreesMethods: WorktreesMethods;
135
+ private discoveryMethods: DiscoveryMethods;
136
+ private decisionsMethods: DecisionsMethods;
137
+ private ideasMethods: IdeasMethods;
138
+ private tasksMethods: TasksMethods;
139
+ private findingsMethods: FindingsMethods;
140
+ private milestonesMethods: MilestonesMethods;
141
+ private validationMethods: ValidationMethods;
142
+ private fallbackMethods: FallbackMethods;
143
+ private requestsMethods: RequestsMethods;
144
+ private deploymentMethods: DeploymentMethods;
145
+ private organizationsMethods: OrganizationsMethods;
146
+ private bodiesOfWorkMethods: BodiesOfWorkMethods;
147
+ private gitIssuesMethods: GitIssuesMethods;
148
+ private fileCheckoutsMethods: FileCheckoutsMethods;
149
+ private connectorsMethods: ConnectorsMethods;
150
+ private sprintsMethods: SprintsMethods;
151
+ private subtasksMethods: SubtasksMethods;
152
+ private progressMethods: ProgressMethods;
153
+ private chatMethods: ChatMethods;
154
+
155
+ constructor(config: ApiClientConfig) {
156
+ this.apiKey = config.apiKey;
157
+ this.baseUrl = config.baseUrl || process.env.VIBESCOPE_API_URL || DEFAULT_API_URL;
158
+ this.retryConfig = {
159
+ maxRetries: config.retry?.maxRetries ?? DEFAULT_MAX_RETRIES,
160
+ baseDelayMs: config.retry?.baseDelayMs ?? DEFAULT_BASE_DELAY_MS,
161
+ maxDelayMs: config.retry?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS,
162
+ retryStatusCodes: config.retry?.retryStatusCodes ?? DEFAULT_RETRY_STATUS_CODES,
163
+ };
164
+
165
+ // Create bound request and proxy functions for domain modules
166
+ const request: RequestFn = this.request.bind(this);
167
+ const proxy: ProxyFn = this.proxy.bind(this);
168
+ const getApiKey = () => this.apiKey;
169
+
170
+ // Initialize domain methods
171
+ this.sessionMethods = createSessionMethods(request, getApiKey);
172
+ this.projectMethods = createProjectMethods(request);
173
+ this.blockersMethods = createBlockersMethods(request);
174
+ this.costMethods = createCostMethods(request);
175
+ this.worktreesMethods = createWorktreesMethods(request);
176
+ this.discoveryMethods = createDiscoveryMethods(request);
177
+ this.decisionsMethods = createDecisionsMethods(proxy);
178
+ this.ideasMethods = createIdeasMethods(proxy);
179
+ this.tasksMethods = createTasksMethods(request, proxy);
180
+ this.findingsMethods = createFindingsMethods(proxy);
181
+ this.milestonesMethods = createMilestonesMethods(proxy);
182
+ this.validationMethods = createValidationMethods(proxy);
183
+ this.fallbackMethods = createFallbackMethods(proxy);
184
+ this.requestsMethods = createRequestsMethods(proxy);
185
+ this.deploymentMethods = createDeploymentMethods(proxy);
186
+ this.organizationsMethods = createOrganizationsMethods(proxy);
187
+ this.bodiesOfWorkMethods = createBodiesOfWorkMethods(proxy);
188
+ this.gitIssuesMethods = createGitIssuesMethods(proxy);
189
+ this.fileCheckoutsMethods = createFileCheckoutsMethods(proxy);
190
+ this.connectorsMethods = createConnectorsMethods(proxy);
191
+ this.sprintsMethods = createSprintsMethods(proxy);
192
+ this.subtasksMethods = createSubtasksMethods(proxy);
193
+ this.progressMethods = createProgressMethods(request, proxy);
194
+ this.chatMethods = createChatMethods(proxy);
195
+ }
196
+
197
+ private async request<T>(method: string, path: string, body?: unknown): Promise<ApiResponse<T>> {
198
+ const url = `${this.baseUrl}${path}`;
199
+ const { maxRetries, baseDelayMs, maxDelayMs, retryStatusCodes } = this.retryConfig;
200
+ let lastError: Error | null = null;
201
+ let lastResponse: Response | null = null;
202
+
203
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
204
+ try {
205
+ const response = await fetch(url, {
206
+ method,
207
+ headers: {
208
+ 'Content-Type': 'application/json',
209
+ 'X-API-Key': this.apiKey
210
+ },
211
+ body: body ? JSON.stringify(body) : undefined
212
+ });
213
+
214
+ if (retryStatusCodes.includes(response.status) && attempt < maxRetries) {
215
+ lastResponse = response;
216
+ const retryAfterHeader = response.headers.get('Retry-After');
217
+ let retryAfter: number | undefined;
218
+ if (retryAfterHeader) {
219
+ const parsed = parseInt(retryAfterHeader, 10);
220
+ if (!isNaN(parsed)) {
221
+ retryAfter = parsed;
222
+ }
223
+ }
224
+ const delay = calculateBackoffDelay(attempt, baseDelayMs, maxDelayMs, retryAfter);
225
+ await sleep(delay);
226
+ continue;
227
+ }
228
+
229
+ if (!response.ok) {
230
+ const errorData = await response.json().catch(() => ({}));
231
+ return {
232
+ ok: false,
233
+ status: response.status,
234
+ error: errorData.error || errorData.message || `HTTP ${response.status}`
235
+ };
236
+ }
237
+
238
+ const data = await response.json();
239
+ return {
240
+ ok: true,
241
+ status: response.status,
242
+ data
243
+ };
244
+ } catch (error) {
245
+ lastError = error as Error;
246
+ if (attempt < maxRetries) {
247
+ const delay = calculateBackoffDelay(attempt, baseDelayMs, maxDelayMs);
248
+ await sleep(delay);
249
+ continue;
250
+ }
251
+ }
252
+ }
253
+
254
+ if (lastResponse && !lastResponse.ok) {
255
+ return {
256
+ ok: false,
257
+ status: lastResponse.status,
258
+ error: `Request failed after ${maxRetries + 1} attempts with status ${lastResponse.status}`
259
+ };
260
+ }
261
+
262
+ return {
263
+ ok: false,
264
+ status: 0,
265
+ error: lastError?.message || 'Request failed after all retries'
266
+ };
267
+ }
268
+
269
+ /**
270
+ * Generic proxy method for operations that go through the MCP proxy endpoint
271
+ */
272
+ async proxy<T>(operation: string, args: Record<string, unknown>, sessionContext?: {
273
+ session_id?: string;
274
+ project_id?: string;
275
+ }): Promise<ApiResponse<T>> {
276
+ return this.request('POST', '/api/mcp/proxy', {
277
+ operation,
278
+ args,
279
+ ...sessionContext
280
+ });
281
+ }
282
+
283
+ // ============================================================================
284
+ // Session methods (delegated)
285
+ // ============================================================================
286
+ validateAuth = () => this.sessionMethods.validateAuth();
287
+ startSession = (params: Parameters<SessionMethods['startSession']>[0]) => this.sessionMethods.startSession(params);
288
+ heartbeat = (sessionId: string, options?: Parameters<SessionMethods['heartbeat']>[1]) => this.sessionMethods.heartbeat(sessionId, options);
289
+ endSession = (sessionId: string) => this.sessionMethods.endSession(sessionId);
290
+ signalIdle = (sessionId: string) => this.sessionMethods.signalIdle(sessionId);
291
+ syncSession = (sessionId: string, params?: Parameters<SessionMethods['syncSession']>[1]) => this.sessionMethods.syncSession(sessionId, params);
292
+ confirmAgentSetup = (projectId: string, agentType: string) => this.sessionMethods.confirmAgentSetup(projectId, agentType);
293
+
294
+ // ============================================================================
295
+ // Project methods (delegated)
296
+ // ============================================================================
297
+ listProjects = () => this.projectMethods.listProjects();
298
+ createProject = (params: Parameters<ProjectMethods['createProject']>[0]) => this.projectMethods.createProject(params);
299
+ getProject = (projectId: string, gitUrl?: string) => this.projectMethods.getProject(projectId, gitUrl);
300
+ updateProject = (projectId: string, updates: Parameters<ProjectMethods['updateProject']>[1]) => this.projectMethods.updateProject(projectId, updates);
301
+ getGitWorkflow = (projectId: string, taskId?: string) => this.projectMethods.getGitWorkflow(projectId, taskId);
302
+ updateProjectReadme = (projectId: string, readmeContent: string) => this.projectMethods.updateProjectReadme(projectId, readmeContent);
303
+ getProjectSummary = (projectId: string) => this.projectMethods.getProjectSummary(projectId);
304
+
305
+ // ============================================================================
306
+ // Blockers methods (delegated)
307
+ // ============================================================================
308
+ getBlockers = (projectId: string, params?: Parameters<BlockersMethods['getBlockers']>[1]) => this.blockersMethods.getBlockers(projectId, params);
309
+ addBlocker = (projectId: string, description: string, sessionId?: string) => this.blockersMethods.addBlocker(projectId, description, sessionId);
310
+ resolveBlocker = (blockerId: string, resolutionNote?: string) => this.blockersMethods.resolveBlocker(blockerId, resolutionNote);
311
+ deleteBlocker = (blockerId: string) => this.blockersMethods.deleteBlocker(blockerId);
312
+ getBlockersStats = (projectId: string) => this.blockersMethods.getBlockersStats(projectId);
313
+
314
+ // ============================================================================
315
+ // Cost methods (delegated)
316
+ // ============================================================================
317
+ getCostSummary = (projectId: string, params?: Parameters<CostMethods['getCostSummary']>[1]) => this.costMethods.getCostSummary(projectId, params);
318
+ getCostAlerts = () => this.costMethods.getCostAlerts();
319
+ addCostAlert = (params: Parameters<CostMethods['addCostAlert']>[0]) => this.costMethods.addCostAlert(params);
320
+ updateCostAlert = (alertId: string, updates: Parameters<CostMethods['updateCostAlert']>[1]) => this.costMethods.updateCostAlert(alertId, updates);
321
+ deleteCostAlert = (alertId: string) => this.costMethods.deleteCostAlert(alertId);
322
+ getTaskCosts = (projectId: string, limit?: number) => this.costMethods.getTaskCosts(projectId, limit);
323
+ getBodyOfWorkCosts = (params: Parameters<CostMethods['getBodyOfWorkCosts']>[0]) => this.costMethods.getBodyOfWorkCosts(params);
324
+ getSprintCosts = (params: Parameters<CostMethods['getSprintCosts']>[0]) => this.costMethods.getSprintCosts(params);
325
+ getTokenUsage = () => this.costMethods.getTokenUsage();
326
+ reportTokenUsage = (sessionId: string, params: Parameters<CostMethods['reportTokenUsage']>[1]) => this.costMethods.reportTokenUsage(sessionId, params);
327
+
328
+ // ============================================================================
329
+ // Worktrees methods (delegated)
330
+ // ============================================================================
331
+ getStaleWorktrees = (projectId: string, params?: Parameters<WorktreesMethods['getStaleWorktrees']>[1]) => this.worktreesMethods.getStaleWorktrees(projectId, params);
332
+ clearWorktreePath = (taskId: string) => this.worktreesMethods.clearWorktreePath(taskId);
333
+
334
+ // ============================================================================
335
+ // Discovery methods (delegated)
336
+ // ============================================================================
337
+ queryKnowledgeBase = (projectId: string, params?: Parameters<DiscoveryMethods['queryKnowledgeBase']>[1]) => this.discoveryMethods.queryKnowledgeBase(projectId, params);
338
+ getHelpTopic = (slug: string) => this.discoveryMethods.getHelpTopic(slug);
339
+ getHelpTopics = () => this.discoveryMethods.getHelpTopics();
340
+
341
+ // ============================================================================
342
+ // Decisions methods (delegated)
343
+ // ============================================================================
344
+ getDecisions = (projectId: string, options?: Parameters<DecisionsMethods['getDecisions']>[1]) => this.decisionsMethods.getDecisions(projectId, options);
345
+ getDecision = (decisionId: string) => this.decisionsMethods.getDecision(decisionId);
346
+ logDecision = (projectId: string, params: Parameters<DecisionsMethods['logDecision']>[1], sessionId?: string) => this.decisionsMethods.logDecision(projectId, params, sessionId);
347
+ deleteDecision = (decisionId: string) => this.decisionsMethods.deleteDecision(decisionId);
348
+ getDecisionsStats = (projectId: string) => this.decisionsMethods.getDecisionsStats(projectId);
349
+
350
+ // ============================================================================
351
+ // Ideas methods (delegated)
352
+ // ============================================================================
353
+ getIdeas = (projectId: string, params?: Parameters<IdeasMethods['getIdeas']>[1]) => this.ideasMethods.getIdeas(projectId, params);
354
+ getIdea = (ideaId: string) => this.ideasMethods.getIdea(ideaId);
355
+ addIdea = (projectId: string, params: Parameters<IdeasMethods['addIdea']>[1], sessionId?: string) => this.ideasMethods.addIdea(projectId, params, sessionId);
356
+ updateIdea = (ideaId: string, updates: Parameters<IdeasMethods['updateIdea']>[1]) => this.ideasMethods.updateIdea(ideaId, updates);
357
+ deleteIdea = (ideaId: string) => this.ideasMethods.deleteIdea(ideaId);
358
+ convertIdeaToTask = (ideaId: string, params?: Parameters<IdeasMethods['convertIdeaToTask']>[1]) => this.ideasMethods.convertIdeaToTask(ideaId, params);
359
+
360
+ // ============================================================================
361
+ // Tasks methods (delegated)
362
+ // ============================================================================
363
+ getTasks = (projectId: string, params?: Parameters<TasksMethods['getTasks']>[1]) => this.tasksMethods.getTasks(projectId, params);
364
+ createTask = (projectId: string, params: Parameters<TasksMethods['createTask']>[1]) => this.tasksMethods.createTask(projectId, params);
365
+ getNextTask = (projectId: string, sessionId?: string) => this.tasksMethods.getNextTask(projectId, sessionId);
366
+ getTask = (taskId: string) => this.tasksMethods.getTask(taskId);
367
+ getTaskById = (taskId: string, params?: Parameters<TasksMethods['getTaskById']>[1]) => this.tasksMethods.getTaskById(taskId, params);
368
+ searchTasks = (projectId: string, params: Parameters<TasksMethods['searchTasks']>[1]) => this.tasksMethods.searchTasks(projectId, params);
369
+ getTasksByPriority = (projectId: string, params?: Parameters<TasksMethods['getTasksByPriority']>[1]) => this.tasksMethods.getTasksByPriority(projectId, params);
370
+ getRecentTasks = (projectId: string, params?: Parameters<TasksMethods['getRecentTasks']>[1]) => this.tasksMethods.getRecentTasks(projectId, params);
371
+ getTaskStats = (projectId: string) => this.tasksMethods.getTaskStats(projectId);
372
+ updateTask = (taskId: string, updates: Parameters<TasksMethods['updateTask']>[1]) => this.tasksMethods.updateTask(taskId, updates);
373
+ completeTask = (taskId: string, params: Parameters<TasksMethods['completeTask']>[1]) => this.tasksMethods.completeTask(taskId, params);
374
+ deleteTask = (taskId: string) => this.tasksMethods.deleteTask(taskId);
375
+ releaseTask = (taskId: string, params?: Parameters<TasksMethods['releaseTask']>[1]) => this.tasksMethods.releaseTask(taskId, params);
376
+ cancelTask = (taskId: string, params?: Parameters<TasksMethods['cancelTask']>[1]) => this.tasksMethods.cancelTask(taskId, params);
377
+ addTaskReference = (taskId: string, url: string, label?: string) => this.tasksMethods.addTaskReference(taskId, url, label);
378
+ removeTaskReference = (taskId: string, url: string) => this.tasksMethods.removeTaskReference(taskId, url);
379
+ batchUpdateTasks = (updates: Parameters<TasksMethods['batchUpdateTasks']>[0]) => this.tasksMethods.batchUpdateTasks(updates);
380
+ batchCompleteTasks = (completions: Parameters<TasksMethods['batchCompleteTasks']>[0]) => this.tasksMethods.batchCompleteTasks(completions);
381
+
382
+ // ============================================================================
383
+ // Findings methods (delegated)
384
+ // ============================================================================
385
+ getFindings = (projectId: string, params?: Parameters<FindingsMethods['getFindings']>[1]) => this.findingsMethods.getFindings(projectId, params);
386
+ getFinding = (findingId: string) => this.findingsMethods.getFinding(findingId);
387
+ getFindingsStats = (projectId: string) => this.findingsMethods.getFindingsStats(projectId);
388
+ addFinding = (projectId: string, params: Parameters<FindingsMethods['addFinding']>[1], sessionId?: string) => this.findingsMethods.addFinding(projectId, params, sessionId);
389
+ updateFinding = (findingId: string, updates: Parameters<FindingsMethods['updateFinding']>[1]) => this.findingsMethods.updateFinding(findingId, updates);
390
+ deleteFinding = (findingId: string) => this.findingsMethods.deleteFinding(findingId);
391
+
392
+ // ============================================================================
393
+ // Milestones methods (delegated)
394
+ // ============================================================================
395
+ getMilestones = (taskId: string) => this.milestonesMethods.getMilestones(taskId);
396
+ addMilestone = (taskId: string, params: Parameters<MilestonesMethods['addMilestone']>[1], sessionId?: string) => this.milestonesMethods.addMilestone(taskId, params, sessionId);
397
+ updateMilestone = (milestoneId: string, updates: Parameters<MilestonesMethods['updateMilestone']>[1]) => this.milestonesMethods.updateMilestone(milestoneId, updates);
398
+ completeMilestone = (milestoneId: string) => this.milestonesMethods.completeMilestone(milestoneId);
399
+ deleteMilestone = (milestoneId: string) => this.milestonesMethods.deleteMilestone(milestoneId);
400
+
401
+ // ============================================================================
402
+ // Validation methods (delegated)
403
+ // ============================================================================
404
+ getTasksAwaitingValidation = (projectId: string) => this.validationMethods.getTasksAwaitingValidation(projectId);
405
+ claimValidation = (taskId: string, sessionId?: string) => this.validationMethods.claimValidation(taskId, sessionId);
406
+ validateTask = (taskId: string, params: Parameters<ValidationMethods['validateTask']>[1], sessionId?: string) => this.validationMethods.validateTask(taskId, params, sessionId);
407
+
408
+ // ============================================================================
409
+ // Fallback activity methods (delegated)
410
+ // ============================================================================
411
+ startFallbackActivity = (projectId: string, activity: string, sessionId?: string) => this.fallbackMethods.startFallbackActivity(projectId, activity, sessionId);
412
+ stopFallbackActivity = (projectId: string, summary?: string, sessionId?: string) => this.fallbackMethods.stopFallbackActivity(projectId, summary, sessionId);
413
+
414
+ // ============================================================================
415
+ // Requests methods (delegated)
416
+ // ============================================================================
417
+ getPendingRequests = (projectId: string, sessionId?: string, limit?: number, offset?: number) => this.requestsMethods.getPendingRequests(projectId, sessionId, limit, offset);
418
+ acknowledgeRequest = (requestId: string, sessionId?: string) => this.requestsMethods.acknowledgeRequest(requestId, sessionId);
419
+ answerQuestion = (requestId: string, answer: string, sessionId?: string) => this.requestsMethods.answerQuestion(requestId, answer, sessionId);
420
+
421
+ // ============================================================================
422
+ // Deployment methods (delegated)
423
+ // ============================================================================
424
+ requestDeployment = (projectId: string, params?: Parameters<DeploymentMethods['requestDeployment']>[1], sessionId?: string) => this.deploymentMethods.requestDeployment(projectId, params, sessionId);
425
+ checkDeploymentStatus = (projectId: string) => this.deploymentMethods.checkDeploymentStatus(projectId);
426
+ claimDeploymentValidation = (projectId: string, sessionId?: string) => this.deploymentMethods.claimDeploymentValidation(projectId, sessionId);
427
+ reportValidation = (projectId: string, params: Parameters<DeploymentMethods['reportValidation']>[1]) => this.deploymentMethods.reportValidation(projectId, params);
428
+ startDeployment = (projectId: string, sessionId?: string) => this.deploymentMethods.startDeployment(projectId, sessionId);
429
+ completeDeployment = (projectId: string, params: Parameters<DeploymentMethods['completeDeployment']>[1]) => this.deploymentMethods.completeDeployment(projectId, params);
430
+ cancelDeployment = (projectId: string, reason?: string) => this.deploymentMethods.cancelDeployment(projectId, reason);
431
+ addDeploymentRequirement = (projectId: string, params: Parameters<DeploymentMethods['addDeploymentRequirement']>[1]) => this.deploymentMethods.addDeploymentRequirement(projectId, params);
432
+ getDeploymentRequirements = (projectId: string, params?: Parameters<DeploymentMethods['getDeploymentRequirements']>[1]) => this.deploymentMethods.getDeploymentRequirements(projectId, params);
433
+ getDeploymentRequirementsStats = (projectId: string) => this.deploymentMethods.getDeploymentRequirementsStats(projectId);
434
+ completeDeploymentRequirement = (requirementId: string) => this.deploymentMethods.completeDeploymentRequirement(requirementId);
435
+ reorderDeploymentRequirements = (projectId: string, params: Parameters<DeploymentMethods['reorderDeploymentRequirements']>[1]) => this.deploymentMethods.reorderDeploymentRequirements(projectId, params);
436
+ scheduleDeployment = (projectId: string, params: Parameters<DeploymentMethods['scheduleDeployment']>[1]) => this.deploymentMethods.scheduleDeployment(projectId, params);
437
+ getScheduledDeployments = (projectId: string, params?: Parameters<DeploymentMethods['getScheduledDeployments']>[1]) => this.deploymentMethods.getScheduledDeployments(projectId, params);
438
+ updateScheduledDeployment = (scheduleId: string, updates: Parameters<DeploymentMethods['updateScheduledDeployment']>[1]) => this.deploymentMethods.updateScheduledDeployment(scheduleId, updates);
439
+ deleteScheduledDeployment = (scheduleId: string) => this.deploymentMethods.deleteScheduledDeployment(scheduleId);
440
+ triggerScheduledDeployment = (scheduleId: string, sessionId?: string) => this.deploymentMethods.triggerScheduledDeployment(scheduleId, sessionId);
441
+ checkDueDeployments = (projectId: string) => this.deploymentMethods.checkDueDeployments(projectId);
442
+
443
+ // ============================================================================
444
+ // Organizations methods (delegated)
445
+ // ============================================================================
446
+ listOrganizations = () => this.organizationsMethods.listOrganizations();
447
+ createOrganization = (params: Parameters<OrganizationsMethods['createOrganization']>[0]) => this.organizationsMethods.createOrganization(params);
448
+ updateOrganization = (organizationId: string, updates: Parameters<OrganizationsMethods['updateOrganization']>[1]) => this.organizationsMethods.updateOrganization(organizationId, updates);
449
+ deleteOrganization = (organizationId: string) => this.organizationsMethods.deleteOrganization(organizationId);
450
+ listOrgMembers = (organizationId: string) => this.organizationsMethods.listOrgMembers(organizationId);
451
+ inviteMember = (organizationId: string, email: string, role?: string) => this.organizationsMethods.inviteMember(organizationId, email, role);
452
+ updateMemberRole = (organizationId: string, userId: string, role: string) => this.organizationsMethods.updateMemberRole(organizationId, userId, role);
453
+ removeMember = (organizationId: string, userId: string) => this.organizationsMethods.removeMember(organizationId, userId);
454
+ leaveOrganization = (organizationId: string) => this.organizationsMethods.leaveOrganization(organizationId);
455
+ shareProjectWithOrg = (projectId: string, organizationId: string, permission?: string) => this.organizationsMethods.shareProjectWithOrg(projectId, organizationId, permission);
456
+ unshareProject = (projectId: string, organizationId: string) => this.organizationsMethods.unshareProject(projectId, organizationId);
457
+ updateProjectShare = (projectId: string, organizationId: string, permission: string) => this.organizationsMethods.updateProjectShare(projectId, organizationId, permission);
458
+ listProjectShares = (projectId: string) => this.organizationsMethods.listProjectShares(projectId);
459
+
460
+ // ============================================================================
461
+ // Bodies of work methods (delegated)
462
+ // ============================================================================
463
+ createBodyOfWork = (projectId: string, params: Parameters<BodiesOfWorkMethods['createBodyOfWork']>[1]) => this.bodiesOfWorkMethods.createBodyOfWork(projectId, params);
464
+ getBodyOfWork = (bodyOfWorkId: string) => this.bodiesOfWorkMethods.getBodyOfWork(bodyOfWorkId);
465
+ getBodiesOfWork = (projectId: string, params?: Parameters<BodiesOfWorkMethods['getBodiesOfWork']>[1]) => this.bodiesOfWorkMethods.getBodiesOfWork(projectId, params);
466
+ updateBodyOfWork = (bodyOfWorkId: string, updates: Parameters<BodiesOfWorkMethods['updateBodyOfWork']>[1]) => this.bodiesOfWorkMethods.updateBodyOfWork(bodyOfWorkId, updates);
467
+ deleteBodyOfWork = (bodyOfWorkId: string) => this.bodiesOfWorkMethods.deleteBodyOfWork(bodyOfWorkId);
468
+ addTaskToBodyOfWork = (bodyOfWorkId: string, taskId: string, phase?: string, orderIndex?: number) => this.bodiesOfWorkMethods.addTaskToBodyOfWork(bodyOfWorkId, taskId, phase, orderIndex);
469
+ removeTaskFromBodyOfWork = (taskId: string) => this.bodiesOfWorkMethods.removeTaskFromBodyOfWork(taskId);
470
+ activateBodyOfWork = (bodyOfWorkId: string) => this.bodiesOfWorkMethods.activateBodyOfWork(bodyOfWorkId);
471
+ addTaskDependency = (bodyOfWorkId: string, taskId: string, dependsOnTaskId: string) => this.bodiesOfWorkMethods.addTaskDependency(bodyOfWorkId, taskId, dependsOnTaskId);
472
+ removeTaskDependency = (taskId: string, dependsOnTaskId: string) => this.bodiesOfWorkMethods.removeTaskDependency(taskId, dependsOnTaskId);
473
+ getTaskDependencies = (params: Parameters<BodiesOfWorkMethods['getTaskDependencies']>[0]) => this.bodiesOfWorkMethods.getTaskDependencies(params);
474
+ getNextBodyOfWorkTask = (bodyOfWorkId: string) => this.bodiesOfWorkMethods.getNextBodyOfWorkTask(bodyOfWorkId);
475
+
476
+ // ============================================================================
477
+ // Git issues methods (delegated)
478
+ // ============================================================================
479
+ addGitIssue = (projectId: string, params: Parameters<GitIssuesMethods['addGitIssue']>[1], sessionId?: string) => this.gitIssuesMethods.addGitIssue(projectId, params, sessionId);
480
+ resolveGitIssue = (gitIssueId: string, params?: Parameters<GitIssuesMethods['resolveGitIssue']>[1], sessionId?: string) => this.gitIssuesMethods.resolveGitIssue(gitIssueId, params, sessionId);
481
+ getGitIssues = (projectId: string, params?: Parameters<GitIssuesMethods['getGitIssues']>[1]) => this.gitIssuesMethods.getGitIssues(projectId, params);
482
+ deleteGitIssue = (gitIssueId: string) => this.gitIssuesMethods.deleteGitIssue(gitIssueId);
483
+
484
+ // ============================================================================
485
+ // File checkouts methods (delegated)
486
+ // ============================================================================
487
+ checkoutFile = (projectId: string, filePath: string, reason?: string, sessionId?: string) => this.fileCheckoutsMethods.checkoutFile(projectId, filePath, reason, sessionId);
488
+ checkinFile = (params: Parameters<FileCheckoutsMethods['checkinFile']>[0], sessionId?: string) => this.fileCheckoutsMethods.checkinFile(params, sessionId);
489
+ getFileCheckouts = (projectId: string, options?: Parameters<FileCheckoutsMethods['getFileCheckouts']>[1]) => this.fileCheckoutsMethods.getFileCheckouts(projectId, options);
490
+ abandonCheckout = (params: Parameters<FileCheckoutsMethods['abandonCheckout']>[0]) => this.fileCheckoutsMethods.abandonCheckout(params);
491
+ getFileCheckoutsStats = (projectId: string) => this.fileCheckoutsMethods.getFileCheckoutsStats(projectId);
492
+ isFileAvailable = (projectId: string, filePath: string) => this.fileCheckoutsMethods.isFileAvailable(projectId, filePath);
493
+
494
+ // ============================================================================
495
+ // Connectors methods (delegated)
496
+ // ============================================================================
497
+ getConnectors = (projectId: string, params?: Parameters<ConnectorsMethods['getConnectors']>[1]) => this.connectorsMethods.getConnectors(projectId, params);
498
+ getConnector = (connectorId: string) => this.connectorsMethods.getConnector(connectorId);
499
+ addConnector = (projectId: string, params: Parameters<ConnectorsMethods['addConnector']>[1]) => this.connectorsMethods.addConnector(projectId, params);
500
+ updateConnector = (connectorId: string, updates: Parameters<ConnectorsMethods['updateConnector']>[1]) => this.connectorsMethods.updateConnector(connectorId, updates);
501
+ deleteConnector = (connectorId: string) => this.connectorsMethods.deleteConnector(connectorId);
502
+ testConnector = (connectorId: string) => this.connectorsMethods.testConnector(connectorId);
503
+ getConnectorEvents = (params: Parameters<ConnectorsMethods['getConnectorEvents']>[0]) => this.connectorsMethods.getConnectorEvents(params);
504
+
505
+ // ============================================================================
506
+ // Sprints methods (delegated)
507
+ // ============================================================================
508
+ createSprint = (projectId: string, params: Parameters<SprintsMethods['createSprint']>[1]) => this.sprintsMethods.createSprint(projectId, params);
509
+ updateSprint = (sprintId: string, updates: Parameters<SprintsMethods['updateSprint']>[1]) => this.sprintsMethods.updateSprint(sprintId, updates);
510
+ getSprint = (sprintId: string, summaryOnly?: boolean) => this.sprintsMethods.getSprint(sprintId, summaryOnly);
511
+ getSprints = (projectId: string, params?: Parameters<SprintsMethods['getSprints']>[1]) => this.sprintsMethods.getSprints(projectId, params);
512
+ deleteSprint = (sprintId: string) => this.sprintsMethods.deleteSprint(sprintId);
513
+ startSprint = (sprintId: string) => this.sprintsMethods.startSprint(sprintId);
514
+ completeSprint = (sprintId: string, params?: Parameters<SprintsMethods['completeSprint']>[1]) => this.sprintsMethods.completeSprint(sprintId, params);
515
+ addTaskToSprint = (sprintId: string, taskId: string, params?: Parameters<SprintsMethods['addTaskToSprint']>[2]) => this.sprintsMethods.addTaskToSprint(sprintId, taskId, params);
516
+ removeTaskFromSprint = (sprintId: string, taskId: string) => this.sprintsMethods.removeTaskFromSprint(sprintId, taskId);
517
+ getSprintBacklog = (projectId: string, sprintId?: string, params?: Parameters<SprintsMethods['getSprintBacklog']>[2]) => this.sprintsMethods.getSprintBacklog(projectId, sprintId, params);
518
+ getSprintVelocity = (projectId: string, limit?: number) => this.sprintsMethods.getSprintVelocity(projectId, limit);
519
+
520
+ // ============================================================================
521
+ // Subtasks methods (delegated)
522
+ // ============================================================================
523
+ addSubtask = (parentTaskId: string, params: Parameters<SubtasksMethods['addSubtask']>[1], sessionId?: string) => this.subtasksMethods.addSubtask(parentTaskId, params, sessionId);
524
+ getSubtasks = (parentTaskId: string, status?: string) => this.subtasksMethods.getSubtasks(parentTaskId, status);
525
+
526
+ // ============================================================================
527
+ // Progress methods (delegated)
528
+ // ============================================================================
529
+ logProgress = (projectId: string, params: Parameters<ProgressMethods['logProgress']>[1]) => this.progressMethods.logProgress(projectId, params);
530
+ getActivityFeed = (projectId: string, params?: Parameters<ProgressMethods['getActivityFeed']>[1]) => this.progressMethods.getActivityFeed(projectId, params);
531
+ getActivityHistory = (projectId: string, params?: Parameters<ProgressMethods['getActivityHistory']>[1]) => this.progressMethods.getActivityHistory(projectId, params);
532
+ getActivitySchedules = (projectId: string, params?: Parameters<ProgressMethods['getActivitySchedules']>[1]) => this.progressMethods.getActivitySchedules(projectId, params);
533
+
534
+ // ============================================================================
535
+ // Chat methods (delegated)
536
+ // ============================================================================
537
+ sendProjectMessage = (projectId: string, message: string, sessionId?: string) => this.chatMethods.sendProjectMessage(projectId, message, sessionId);
538
+ getProjectMessages = (projectId: string, limit?: number) => this.chatMethods.getProjectMessages(projectId, limit);
539
+ }
540
+
541
+ // Singleton instance
542
+ let apiClient: VibescopeApiClient | null = null;
543
+
544
+ export function getApiClient(): VibescopeApiClient {
545
+ if (!apiClient) {
546
+ const apiKey = resolveApiKeyFromSources();
547
+ apiClient = new VibescopeApiClient({ apiKey });
548
+ }
549
+ return apiClient;
550
+ }
551
+
552
+ /**
553
+ * Resolve API key from multiple sources in priority order:
554
+ * 1. VIBESCOPE_API_KEY env var (CI/cloud agents)
555
+ * 2. ~/.vibescope/credentials.json (local dev)
556
+ * 3. Error with helpful message
557
+ */
558
+ function resolveApiKeyFromSources(): string {
559
+ // 1. Environment variable
560
+ if (process.env.VIBESCOPE_API_KEY) {
561
+ return process.env.VIBESCOPE_API_KEY;
562
+ }
563
+
564
+ // 2. Credentials file
565
+ try {
566
+ const { existsSync, readFileSync } = require('node:fs');
567
+ const { homedir } = require('node:os');
568
+ const { join } = require('node:path');
569
+ const credPath = join(homedir(), '.vibescope', 'credentials.json');
570
+ if (existsSync(credPath)) {
571
+ const data = JSON.parse(readFileSync(credPath, 'utf-8'));
572
+ if (data.apiKey) {
573
+ return data.apiKey;
574
+ }
575
+ }
576
+ } catch {
577
+ // ignore read errors
578
+ }
579
+
580
+ // 3. Not found
581
+ throw new Error(
582
+ 'Vibescope API key not found.\n\n' +
583
+ 'Set it up with:\n' +
584
+ ' npx vibescope init\n\n' +
585
+ 'Or set the VIBESCOPE_API_KEY environment variable.'
586
+ );
587
+ }
588
+
589
+ export function initApiClient(config: ApiClientConfig): VibescopeApiClient {
590
+ apiClient = new VibescopeApiClient(config);
591
+ return apiClient;
592
+ }