@vibescope/mcp-server 0.0.1
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.
- package/README.md +98 -0
- package/dist/cli.d.ts +34 -0
- package/dist/cli.js +356 -0
- package/dist/cli.test.d.ts +1 -0
- package/dist/cli.test.js +367 -0
- package/dist/handlers/__test-utils__.d.ts +72 -0
- package/dist/handlers/__test-utils__.js +176 -0
- package/dist/handlers/blockers.d.ts +18 -0
- package/dist/handlers/blockers.js +81 -0
- package/dist/handlers/bodies-of-work.d.ts +34 -0
- package/dist/handlers/bodies-of-work.js +614 -0
- package/dist/handlers/checkouts.d.ts +37 -0
- package/dist/handlers/checkouts.js +377 -0
- package/dist/handlers/cost.d.ts +39 -0
- package/dist/handlers/cost.js +247 -0
- package/dist/handlers/decisions.d.ts +16 -0
- package/dist/handlers/decisions.js +64 -0
- package/dist/handlers/deployment.d.ts +36 -0
- package/dist/handlers/deployment.js +1062 -0
- package/dist/handlers/discovery.d.ts +14 -0
- package/dist/handlers/discovery.js +870 -0
- package/dist/handlers/fallback.d.ts +18 -0
- package/dist/handlers/fallback.js +216 -0
- package/dist/handlers/findings.d.ts +18 -0
- package/dist/handlers/findings.js +110 -0
- package/dist/handlers/git-issues.d.ts +22 -0
- package/dist/handlers/git-issues.js +247 -0
- package/dist/handlers/ideas.d.ts +19 -0
- package/dist/handlers/ideas.js +188 -0
- package/dist/handlers/index.d.ts +29 -0
- package/dist/handlers/index.js +65 -0
- package/dist/handlers/knowledge-query.d.ts +22 -0
- package/dist/handlers/knowledge-query.js +253 -0
- package/dist/handlers/knowledge.d.ts +12 -0
- package/dist/handlers/knowledge.js +108 -0
- package/dist/handlers/milestones.d.ts +20 -0
- package/dist/handlers/milestones.js +179 -0
- package/dist/handlers/organizations.d.ts +36 -0
- package/dist/handlers/organizations.js +428 -0
- package/dist/handlers/progress.d.ts +14 -0
- package/dist/handlers/progress.js +149 -0
- package/dist/handlers/project.d.ts +20 -0
- package/dist/handlers/project.js +278 -0
- package/dist/handlers/requests.d.ts +16 -0
- package/dist/handlers/requests.js +131 -0
- package/dist/handlers/roles.d.ts +30 -0
- package/dist/handlers/roles.js +281 -0
- package/dist/handlers/session.d.ts +20 -0
- package/dist/handlers/session.js +791 -0
- package/dist/handlers/tasks.d.ts +52 -0
- package/dist/handlers/tasks.js +1111 -0
- package/dist/handlers/tasks.test.d.ts +1 -0
- package/dist/handlers/tasks.test.js +431 -0
- package/dist/handlers/types.d.ts +94 -0
- package/dist/handlers/types.js +1 -0
- package/dist/handlers/validation.d.ts +16 -0
- package/dist/handlers/validation.js +188 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2707 -0
- package/dist/knowledge.d.ts +6 -0
- package/dist/knowledge.js +121 -0
- package/dist/tools.d.ts +2 -0
- package/dist/tools.js +2498 -0
- package/dist/utils.d.ts +149 -0
- package/dist/utils.js +317 -0
- package/dist/utils.test.d.ts +1 -0
- package/dist/utils.test.js +532 -0
- package/dist/validators.d.ts +35 -0
- package/dist/validators.js +111 -0
- package/dist/validators.test.d.ts +1 -0
- package/dist/validators.test.js +176 -0
- package/package.json +44 -0
- package/src/cli.test.ts +442 -0
- package/src/cli.ts +439 -0
- package/src/handlers/__test-utils__.ts +217 -0
- package/src/handlers/blockers.test.ts +390 -0
- package/src/handlers/blockers.ts +110 -0
- package/src/handlers/bodies-of-work.test.ts +1276 -0
- package/src/handlers/bodies-of-work.ts +783 -0
- package/src/handlers/cost.test.ts +436 -0
- package/src/handlers/cost.ts +322 -0
- package/src/handlers/decisions.test.ts +401 -0
- package/src/handlers/decisions.ts +86 -0
- package/src/handlers/deployment.test.ts +516 -0
- package/src/handlers/deployment.ts +1289 -0
- package/src/handlers/discovery.test.ts +254 -0
- package/src/handlers/discovery.ts +969 -0
- package/src/handlers/fallback.test.ts +687 -0
- package/src/handlers/fallback.ts +260 -0
- package/src/handlers/findings.test.ts +565 -0
- package/src/handlers/findings.ts +153 -0
- package/src/handlers/ideas.test.ts +753 -0
- package/src/handlers/ideas.ts +247 -0
- package/src/handlers/index.ts +69 -0
- package/src/handlers/milestones.test.ts +584 -0
- package/src/handlers/milestones.ts +217 -0
- package/src/handlers/organizations.test.ts +997 -0
- package/src/handlers/organizations.ts +550 -0
- package/src/handlers/progress.test.ts +369 -0
- package/src/handlers/progress.ts +188 -0
- package/src/handlers/project.test.ts +562 -0
- package/src/handlers/project.ts +352 -0
- package/src/handlers/requests.test.ts +531 -0
- package/src/handlers/requests.ts +150 -0
- package/src/handlers/session.test.ts +459 -0
- package/src/handlers/session.ts +912 -0
- package/src/handlers/tasks.test.ts +602 -0
- package/src/handlers/tasks.ts +1393 -0
- package/src/handlers/types.ts +88 -0
- package/src/handlers/validation.test.ts +880 -0
- package/src/handlers/validation.ts +223 -0
- package/src/index.ts +3205 -0
- package/src/knowledge.ts +132 -0
- package/src/tmpclaude-0078-cwd +1 -0
- package/src/tmpclaude-0ee1-cwd +1 -0
- package/src/tmpclaude-2dd5-cwd +1 -0
- package/src/tmpclaude-344c-cwd +1 -0
- package/src/tmpclaude-3860-cwd +1 -0
- package/src/tmpclaude-4b63-cwd +1 -0
- package/src/tmpclaude-5c73-cwd +1 -0
- package/src/tmpclaude-5ee3-cwd +1 -0
- package/src/tmpclaude-6795-cwd +1 -0
- package/src/tmpclaude-709e-cwd +1 -0
- package/src/tmpclaude-9839-cwd +1 -0
- package/src/tmpclaude-d829-cwd +1 -0
- package/src/tmpclaude-e072-cwd +1 -0
- package/src/tmpclaude-f6ee-cwd +1 -0
- package/src/utils.test.ts +681 -0
- package/src/utils.ts +375 -0
- package/src/validators.test.ts +223 -0
- package/src/validators.ts +122 -0
- package/tmpclaude-0439-cwd +1 -0
- package/tmpclaude-132f-cwd +1 -0
- package/tmpclaude-15bb-cwd +1 -0
- package/tmpclaude-165a-cwd +1 -0
- package/tmpclaude-1ba9-cwd +1 -0
- package/tmpclaude-21a3-cwd +1 -0
- package/tmpclaude-2a38-cwd +1 -0
- package/tmpclaude-2adf-cwd +1 -0
- package/tmpclaude-2f56-cwd +1 -0
- package/tmpclaude-3626-cwd +1 -0
- package/tmpclaude-3727-cwd +1 -0
- package/tmpclaude-40bc-cwd +1 -0
- package/tmpclaude-436f-cwd +1 -0
- package/tmpclaude-4783-cwd +1 -0
- package/tmpclaude-4b6d-cwd +1 -0
- package/tmpclaude-4ba4-cwd +1 -0
- package/tmpclaude-51e6-cwd +1 -0
- package/tmpclaude-5ecf-cwd +1 -0
- package/tmpclaude-6f97-cwd +1 -0
- package/tmpclaude-7fb2-cwd +1 -0
- package/tmpclaude-825c-cwd +1 -0
- package/tmpclaude-8baf-cwd +1 -0
- package/tmpclaude-8d9f-cwd +1 -0
- package/tmpclaude-975c-cwd +1 -0
- package/tmpclaude-9983-cwd +1 -0
- package/tmpclaude-a045-cwd +1 -0
- package/tmpclaude-ac4a-cwd +1 -0
- package/tmpclaude-b593-cwd +1 -0
- package/tmpclaude-b891-cwd +1 -0
- package/tmpclaude-c032-cwd +1 -0
- package/tmpclaude-cf43-cwd +1 -0
- package/tmpclaude-d040-cwd +1 -0
- package/tmpclaude-dcdd-cwd +1 -0
- package/tmpclaude-dcee-cwd +1 -0
- package/tmpclaude-e16b-cwd +1 -0
- package/tmpclaude-ecd2-cwd +1 -0
- package/tmpclaude-f48d-cwd +1 -0
- package/tsconfig.json +16 -0
- package/vitest.config.ts +13 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,3205 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
|
+
import {
|
|
6
|
+
CallToolRequestSchema,
|
|
7
|
+
ListToolsRequestSchema,
|
|
8
|
+
type Tool,
|
|
9
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
10
|
+
import { createClient } from '@supabase/supabase-js';
|
|
11
|
+
import { randomUUID } from 'crypto';
|
|
12
|
+
import {
|
|
13
|
+
ValidationError,
|
|
14
|
+
validateRequired,
|
|
15
|
+
validateUUID,
|
|
16
|
+
validateTaskStatus,
|
|
17
|
+
validateProjectStatus,
|
|
18
|
+
validatePriority,
|
|
19
|
+
validateProgressPercentage,
|
|
20
|
+
validateEstimatedMinutes,
|
|
21
|
+
validateEnvironment,
|
|
22
|
+
VALID_TASK_STATUSES,
|
|
23
|
+
VALID_PROJECT_STATUSES,
|
|
24
|
+
VALID_BLOCKER_STATUSES,
|
|
25
|
+
VALID_DEPLOYMENT_STATUSES,
|
|
26
|
+
VALID_ENVIRONMENTS,
|
|
27
|
+
} from './validators.js';
|
|
28
|
+
import {
|
|
29
|
+
AGENT_PERSONAS,
|
|
30
|
+
FALLBACK_ACTIVITIES,
|
|
31
|
+
getRandomFallbackActivity,
|
|
32
|
+
selectPersona,
|
|
33
|
+
RateLimiter,
|
|
34
|
+
extractProjectNameFromGitUrl,
|
|
35
|
+
isValidStatusTransition,
|
|
36
|
+
} from './utils.js';
|
|
37
|
+
import { hashApiKey } from './cli.js';
|
|
38
|
+
import { buildHandlerRegistry, type HandlerContext } from './handlers/index.js';
|
|
39
|
+
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// Agent Instance Tracking
|
|
42
|
+
// ============================================================================
|
|
43
|
+
|
|
44
|
+
// Unique identifier for this agent instance (survives tool calls within same session)
|
|
45
|
+
const INSTANCE_ID = randomUUID();
|
|
46
|
+
|
|
47
|
+
// Current session ID (set when start_work_session is called)
|
|
48
|
+
let currentSessionId: string | null = null;
|
|
49
|
+
|
|
50
|
+
// Assigned persona for this agent instance
|
|
51
|
+
let currentPersona: string | null = null;
|
|
52
|
+
|
|
53
|
+
// Token usage tracking for this session
|
|
54
|
+
interface ModelTokens {
|
|
55
|
+
input: number;
|
|
56
|
+
output: number;
|
|
57
|
+
}
|
|
58
|
+
interface TokenUsage {
|
|
59
|
+
callCount: number;
|
|
60
|
+
totalTokens: number;
|
|
61
|
+
byTool: Record<string, { calls: number; tokens: number }>;
|
|
62
|
+
byModel: Record<string, ModelTokens>;
|
|
63
|
+
currentModel: string | null;
|
|
64
|
+
}
|
|
65
|
+
let sessionTokenUsage: TokenUsage = {
|
|
66
|
+
callCount: 0,
|
|
67
|
+
totalTokens: 0,
|
|
68
|
+
byTool: {},
|
|
69
|
+
byModel: {},
|
|
70
|
+
currentModel: null,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Estimate tokens from JSON (rough: ~4 chars per token)
|
|
74
|
+
function estimateTokens(obj: unknown): number {
|
|
75
|
+
return Math.ceil(JSON.stringify(obj).length / 4);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Track token usage for a tool call (input = args, output = response)
|
|
79
|
+
function trackTokenUsage(toolName: string, args: unknown, response: unknown): void {
|
|
80
|
+
const inputTokens = estimateTokens(args);
|
|
81
|
+
const outputTokens = estimateTokens(response);
|
|
82
|
+
const totalTokens = inputTokens + outputTokens;
|
|
83
|
+
|
|
84
|
+
sessionTokenUsage.callCount++;
|
|
85
|
+
sessionTokenUsage.totalTokens += totalTokens;
|
|
86
|
+
|
|
87
|
+
if (!sessionTokenUsage.byTool[toolName]) {
|
|
88
|
+
sessionTokenUsage.byTool[toolName] = { calls: 0, tokens: 0 };
|
|
89
|
+
}
|
|
90
|
+
sessionTokenUsage.byTool[toolName].calls++;
|
|
91
|
+
sessionTokenUsage.byTool[toolName].tokens += totalTokens;
|
|
92
|
+
|
|
93
|
+
// Track by model if a model is set
|
|
94
|
+
const model = sessionTokenUsage.currentModel;
|
|
95
|
+
if (model) {
|
|
96
|
+
if (!sessionTokenUsage.byModel[model]) {
|
|
97
|
+
sessionTokenUsage.byModel[model] = { input: 0, output: 0 };
|
|
98
|
+
}
|
|
99
|
+
sessionTokenUsage.byModel[model].input += inputTokens;
|
|
100
|
+
sessionTokenUsage.byModel[model].output += outputTokens;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Global rate limiter instance (60 requests per minute per API key)
|
|
105
|
+
const rateLimiter = new RateLimiter(60, 60000);
|
|
106
|
+
|
|
107
|
+
// Cleanup expired entries every 5 minutes (store interval ID for cleanup)
|
|
108
|
+
const rateLimiterCleanupInterval = setInterval(() => rateLimiter.cleanup(), 5 * 60 * 1000);
|
|
109
|
+
|
|
110
|
+
// Cleanup on process exit to prevent memory leaks
|
|
111
|
+
process.on('exit', () => clearInterval(rateLimiterCleanupInterval));
|
|
112
|
+
process.on('SIGINT', () => { clearInterval(rateLimiterCleanupInterval); process.exit(0); });
|
|
113
|
+
process.on('SIGTERM', () => { clearInterval(rateLimiterCleanupInterval); process.exit(0); });
|
|
114
|
+
|
|
115
|
+
// Build handler registry from modular handlers
|
|
116
|
+
const handlerRegistry = buildHandlerRegistry();
|
|
117
|
+
|
|
118
|
+
// ============================================================================
|
|
119
|
+
// Embedded Knowledge Base (on-demand help topics)
|
|
120
|
+
// ============================================================================
|
|
121
|
+
|
|
122
|
+
const KNOWLEDGE_BASE: Record<string, string> = {
|
|
123
|
+
getting_started: `# Getting Started
|
|
124
|
+
1. Call start_work_session(git_url, model: "opus"|"sonnet"|"haiku") to initialize
|
|
125
|
+
- IMPORTANT: Pass your model for accurate cost tracking
|
|
126
|
+
- Check your system prompt for "You are powered by the model named..." to find it
|
|
127
|
+
2. Response includes next_task - start working on it immediately
|
|
128
|
+
3. Use update_task to mark in_progress and track progress
|
|
129
|
+
4. Call complete_task when done - it returns your next task
|
|
130
|
+
5. Use get_help(topic) when you need guidance on specific workflows`,
|
|
131
|
+
|
|
132
|
+
tasks: `# Task Workflow
|
|
133
|
+
- Mark task in_progress with update_task before starting
|
|
134
|
+
- Update progress_percentage regularly (every 15-20% progress)
|
|
135
|
+
- Include progress_note to auto-log milestones
|
|
136
|
+
- One task at a time - complete current before starting another
|
|
137
|
+
- complete_task returns next_task and context counts (validation, blockers, deployment)
|
|
138
|
+
- Priority: 1=highest, 5=lowest`,
|
|
139
|
+
|
|
140
|
+
validation: `# Task Validation
|
|
141
|
+
Completed tasks need validation before deployment. PRIORITIZE validation over new tasks.
|
|
142
|
+
1. Check: get_tasks_awaiting_validation(project_id)
|
|
143
|
+
2. Claim: claim_validation(task_id) - marks "being reviewed" on dashboard
|
|
144
|
+
3. Review code changes and run tests
|
|
145
|
+
4. Complete: validate_task(task_id, approved: true/false, validation_notes: "...")
|
|
146
|
+
Self-validation allowed when single-agent or to unblock deployment.`,
|
|
147
|
+
|
|
148
|
+
deployment: `# Deployment Workflow
|
|
149
|
+
1. Ensure all completed tasks are validated first
|
|
150
|
+
2. request_deployment(project_id, environment: "production")
|
|
151
|
+
3. claim_deployment_validation(project_id) - claim for validation
|
|
152
|
+
4. Run: pnpm build && pnpm test
|
|
153
|
+
5. report_validation(project_id, build_passed: true, tests_passed: true)
|
|
154
|
+
6. start_deployment(project_id) - returns project's deployment_instructions
|
|
155
|
+
7. Follow the instructions (e.g., push to main, run deploy command)
|
|
156
|
+
8. complete_deployment(project_id, success: true, summary: "...")`,
|
|
157
|
+
|
|
158
|
+
git: `# Git Workflow
|
|
159
|
+
Call get_git_workflow(project_id) for project-specific config.
|
|
160
|
+
Workflows: none, trunk-based, github-flow, git-flow
|
|
161
|
+
- trunk-based: commit directly to main
|
|
162
|
+
- github-flow: feature branches, merge via PR
|
|
163
|
+
- git-flow: develop/release branches
|
|
164
|
+
Update task git_branch when working on a branch.`,
|
|
165
|
+
|
|
166
|
+
blockers: `# Working with Blockers
|
|
167
|
+
When stuck and need human input:
|
|
168
|
+
1. add_blocker(project_id, description: "What's blocking")
|
|
169
|
+
2. Ask your question to the user
|
|
170
|
+
3. resolve_blocker(blocker_id, resolution_note: "How resolved")
|
|
171
|
+
Only use for genuine blockers requiring decisions - not routine questions.`,
|
|
172
|
+
|
|
173
|
+
milestones: `# Task Milestones
|
|
174
|
+
For complex tasks, break into milestones:
|
|
175
|
+
1. add_milestone(task_id, title: "Design schema")
|
|
176
|
+
2. add_milestone(task_id, title: "Implement API")
|
|
177
|
+
3. Update with complete_milestone(milestone_id) as you go
|
|
178
|
+
Dashboard shows progress bar with completed/total.`,
|
|
179
|
+
|
|
180
|
+
fallback: `# Fallback Activities
|
|
181
|
+
When no tasks available, get_next_task suggests activities:
|
|
182
|
+
- feature_ideation, code_review, performance_audit
|
|
183
|
+
- security_review, test_coverage, documentation_review
|
|
184
|
+
1. start_fallback_activity(project_id, activity: "code_review")
|
|
185
|
+
2. Do the work, use add_finding for issues, add_idea for improvements
|
|
186
|
+
3. stop_fallback_activity(project_id, summary: "...")`,
|
|
187
|
+
|
|
188
|
+
session: `# Session Management
|
|
189
|
+
- start_work_session(git_url, model) initializes and returns next_task
|
|
190
|
+
- ALWAYS pass model parameter ("opus", "sonnet", "haiku") for cost tracking
|
|
191
|
+
- Use mode:'lite' (default) or mode:'full' for complete context
|
|
192
|
+
- heartbeat every 30-60 seconds maintains active status
|
|
193
|
+
- end_work_session releases claimed tasks and returns summary
|
|
194
|
+
- NEVER STOP: After completing a task, immediately start the next one
|
|
195
|
+
- When context grows large: /clear then start_work_session to continue fresh
|
|
196
|
+
- Your progress is saved to the dashboard - nothing is lost on /clear`,
|
|
197
|
+
|
|
198
|
+
tokens: `# Token Efficiency
|
|
199
|
+
Be mindful of token costs - every tool call has a cost.
|
|
200
|
+
- Use mode:'lite' (default) - saves ~85% vs full mode
|
|
201
|
+
- Call get_token_usage() to check consumption
|
|
202
|
+
- /compact when context grows large
|
|
203
|
+
- Batch related updates when possible
|
|
204
|
+
- Trust lite mode; only use full mode for initial exploration`,
|
|
205
|
+
|
|
206
|
+
topics: `# Available Help Topics
|
|
207
|
+
- getting_started: Basic workflow overview
|
|
208
|
+
- tasks: Working on tasks, progress tracking
|
|
209
|
+
- validation: Cross-agent task validation
|
|
210
|
+
- deployment: Deployment coordination
|
|
211
|
+
- git: Git workflow configuration
|
|
212
|
+
- blockers: Handling blockers
|
|
213
|
+
- milestones: Breaking down complex tasks
|
|
214
|
+
- fallback: Background activities when idle
|
|
215
|
+
- session: Session management
|
|
216
|
+
- tokens: Token efficiency tips`,
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
// ============================================================================
|
|
221
|
+
// Types
|
|
222
|
+
// ============================================================================
|
|
223
|
+
|
|
224
|
+
interface Database {
|
|
225
|
+
public: {
|
|
226
|
+
Tables: {
|
|
227
|
+
api_keys: {
|
|
228
|
+
Row: {
|
|
229
|
+
id: string;
|
|
230
|
+
user_id: string;
|
|
231
|
+
key_hash: string;
|
|
232
|
+
name: string;
|
|
233
|
+
last_used_at: string | null;
|
|
234
|
+
};
|
|
235
|
+
Insert: {
|
|
236
|
+
id?: string;
|
|
237
|
+
user_id: string;
|
|
238
|
+
key_hash: string;
|
|
239
|
+
name: string;
|
|
240
|
+
last_used_at?: string | null;
|
|
241
|
+
};
|
|
242
|
+
Update: {
|
|
243
|
+
id?: string;
|
|
244
|
+
user_id?: string;
|
|
245
|
+
key_hash?: string;
|
|
246
|
+
name?: string;
|
|
247
|
+
last_used_at?: string | null;
|
|
248
|
+
};
|
|
249
|
+
};
|
|
250
|
+
projects: {
|
|
251
|
+
Row: {
|
|
252
|
+
id: string;
|
|
253
|
+
user_id: string;
|
|
254
|
+
name: string;
|
|
255
|
+
description: string | null;
|
|
256
|
+
goal: string | null;
|
|
257
|
+
status: string;
|
|
258
|
+
git_url: string | null;
|
|
259
|
+
agent_instructions: string | null;
|
|
260
|
+
tech_stack: string[] | null;
|
|
261
|
+
git_workflow: 'none' | 'trunk-based' | 'github-flow' | 'git-flow';
|
|
262
|
+
git_main_branch: string;
|
|
263
|
+
git_develop_branch: string | null;
|
|
264
|
+
git_auto_branch: boolean;
|
|
265
|
+
git_auto_tag: boolean;
|
|
266
|
+
created_at: string;
|
|
267
|
+
updated_at: string;
|
|
268
|
+
};
|
|
269
|
+
Insert: {
|
|
270
|
+
id?: string;
|
|
271
|
+
user_id: string;
|
|
272
|
+
name: string;
|
|
273
|
+
description?: string | null;
|
|
274
|
+
goal?: string | null;
|
|
275
|
+
status?: string;
|
|
276
|
+
git_url?: string | null;
|
|
277
|
+
agent_instructions?: string | null;
|
|
278
|
+
tech_stack?: string[] | null;
|
|
279
|
+
git_workflow?: 'none' | 'trunk-based' | 'github-flow' | 'git-flow';
|
|
280
|
+
git_main_branch?: string;
|
|
281
|
+
git_develop_branch?: string | null;
|
|
282
|
+
git_auto_branch?: boolean;
|
|
283
|
+
git_auto_tag?: boolean;
|
|
284
|
+
created_at?: string;
|
|
285
|
+
updated_at?: string;
|
|
286
|
+
};
|
|
287
|
+
Update: {
|
|
288
|
+
id?: string;
|
|
289
|
+
user_id?: string;
|
|
290
|
+
name?: string;
|
|
291
|
+
description?: string | null;
|
|
292
|
+
goal?: string | null;
|
|
293
|
+
status?: string;
|
|
294
|
+
git_url?: string | null;
|
|
295
|
+
agent_instructions?: string | null;
|
|
296
|
+
tech_stack?: string[] | null;
|
|
297
|
+
git_workflow?: 'none' | 'trunk-based' | 'github-flow' | 'git-flow';
|
|
298
|
+
git_main_branch?: string;
|
|
299
|
+
git_develop_branch?: string | null;
|
|
300
|
+
git_auto_branch?: boolean;
|
|
301
|
+
git_auto_tag?: boolean;
|
|
302
|
+
created_at?: string;
|
|
303
|
+
updated_at?: string;
|
|
304
|
+
};
|
|
305
|
+
};
|
|
306
|
+
tasks: {
|
|
307
|
+
Row: {
|
|
308
|
+
id: string;
|
|
309
|
+
project_id: string;
|
|
310
|
+
title: string;
|
|
311
|
+
description: string | null;
|
|
312
|
+
priority: number;
|
|
313
|
+
status: string;
|
|
314
|
+
created_by: string;
|
|
315
|
+
created_at: string;
|
|
316
|
+
completed_at: string | null;
|
|
317
|
+
progress_percentage: number;
|
|
318
|
+
estimated_minutes: number | null;
|
|
319
|
+
started_at: string | null;
|
|
320
|
+
working_agent_session_id: string | null;
|
|
321
|
+
git_branch: string | null;
|
|
322
|
+
references: { url: string; label?: string }[] | null;
|
|
323
|
+
};
|
|
324
|
+
Insert: {
|
|
325
|
+
id?: string;
|
|
326
|
+
project_id: string;
|
|
327
|
+
title: string;
|
|
328
|
+
description?: string | null;
|
|
329
|
+
priority?: number;
|
|
330
|
+
status?: string;
|
|
331
|
+
created_by?: string;
|
|
332
|
+
created_at?: string;
|
|
333
|
+
completed_at?: string | null;
|
|
334
|
+
progress_percentage?: number;
|
|
335
|
+
estimated_minutes?: number | null;
|
|
336
|
+
started_at?: string | null;
|
|
337
|
+
working_agent_session_id?: string | null;
|
|
338
|
+
git_branch?: string | null;
|
|
339
|
+
references?: { url: string; label?: string }[] | null;
|
|
340
|
+
};
|
|
341
|
+
Update: {
|
|
342
|
+
id?: string;
|
|
343
|
+
project_id?: string;
|
|
344
|
+
title?: string;
|
|
345
|
+
description?: string | null;
|
|
346
|
+
priority?: number;
|
|
347
|
+
status?: string;
|
|
348
|
+
created_by?: string;
|
|
349
|
+
created_at?: string;
|
|
350
|
+
completed_at?: string | null;
|
|
351
|
+
progress_percentage?: number;
|
|
352
|
+
estimated_minutes?: number | null;
|
|
353
|
+
started_at?: string | null;
|
|
354
|
+
working_agent_session_id?: string | null;
|
|
355
|
+
git_branch?: string | null;
|
|
356
|
+
references?: { url: string; label?: string }[] | null;
|
|
357
|
+
};
|
|
358
|
+
};
|
|
359
|
+
progress_logs: {
|
|
360
|
+
Row: {
|
|
361
|
+
id: string;
|
|
362
|
+
project_id: string;
|
|
363
|
+
task_id: string | null;
|
|
364
|
+
summary: string;
|
|
365
|
+
details: string | null;
|
|
366
|
+
created_by: string;
|
|
367
|
+
created_at: string;
|
|
368
|
+
};
|
|
369
|
+
Insert: {
|
|
370
|
+
id?: string;
|
|
371
|
+
project_id: string;
|
|
372
|
+
task_id?: string | null;
|
|
373
|
+
summary: string;
|
|
374
|
+
details?: string | null;
|
|
375
|
+
created_by?: string;
|
|
376
|
+
created_at?: string;
|
|
377
|
+
};
|
|
378
|
+
Update: {
|
|
379
|
+
id?: string;
|
|
380
|
+
project_id?: string;
|
|
381
|
+
task_id?: string | null;
|
|
382
|
+
summary?: string;
|
|
383
|
+
details?: string | null;
|
|
384
|
+
created_by?: string;
|
|
385
|
+
created_at?: string;
|
|
386
|
+
};
|
|
387
|
+
};
|
|
388
|
+
blockers: {
|
|
389
|
+
Row: {
|
|
390
|
+
id: string;
|
|
391
|
+
project_id: string;
|
|
392
|
+
description: string;
|
|
393
|
+
status: string;
|
|
394
|
+
created_by: string;
|
|
395
|
+
created_at: string;
|
|
396
|
+
resolved_at: string | null;
|
|
397
|
+
resolution_note: string | null;
|
|
398
|
+
};
|
|
399
|
+
Insert: {
|
|
400
|
+
id?: string;
|
|
401
|
+
project_id: string;
|
|
402
|
+
description: string;
|
|
403
|
+
status?: string;
|
|
404
|
+
created_by?: string;
|
|
405
|
+
created_at?: string;
|
|
406
|
+
resolved_at?: string | null;
|
|
407
|
+
resolution_note?: string | null;
|
|
408
|
+
};
|
|
409
|
+
Update: {
|
|
410
|
+
id?: string;
|
|
411
|
+
project_id?: string;
|
|
412
|
+
description?: string;
|
|
413
|
+
status?: string;
|
|
414
|
+
created_by?: string;
|
|
415
|
+
created_at?: string;
|
|
416
|
+
resolved_at?: string | null;
|
|
417
|
+
resolution_note?: string | null;
|
|
418
|
+
};
|
|
419
|
+
};
|
|
420
|
+
ideas: {
|
|
421
|
+
Row: {
|
|
422
|
+
id: string;
|
|
423
|
+
project_id: string;
|
|
424
|
+
title: string;
|
|
425
|
+
description: string | null;
|
|
426
|
+
created_by: string;
|
|
427
|
+
created_at: string;
|
|
428
|
+
};
|
|
429
|
+
Insert: {
|
|
430
|
+
id?: string;
|
|
431
|
+
project_id: string;
|
|
432
|
+
title: string;
|
|
433
|
+
description?: string | null;
|
|
434
|
+
created_by?: string;
|
|
435
|
+
created_at?: string;
|
|
436
|
+
};
|
|
437
|
+
Update: {
|
|
438
|
+
id?: string;
|
|
439
|
+
project_id?: string;
|
|
440
|
+
title?: string;
|
|
441
|
+
description?: string | null;
|
|
442
|
+
created_by?: string;
|
|
443
|
+
created_at?: string;
|
|
444
|
+
};
|
|
445
|
+
};
|
|
446
|
+
decisions: {
|
|
447
|
+
Row: {
|
|
448
|
+
id: string;
|
|
449
|
+
project_id: string;
|
|
450
|
+
title: string;
|
|
451
|
+
description: string;
|
|
452
|
+
rationale: string | null;
|
|
453
|
+
alternatives_considered: string[] | null;
|
|
454
|
+
created_by: string;
|
|
455
|
+
created_at: string;
|
|
456
|
+
};
|
|
457
|
+
Insert: {
|
|
458
|
+
id?: string;
|
|
459
|
+
project_id: string;
|
|
460
|
+
title: string;
|
|
461
|
+
description: string;
|
|
462
|
+
rationale?: string | null;
|
|
463
|
+
alternatives_considered?: string[] | null;
|
|
464
|
+
created_by?: string;
|
|
465
|
+
created_at?: string;
|
|
466
|
+
};
|
|
467
|
+
Update: {
|
|
468
|
+
id?: string;
|
|
469
|
+
project_id?: string;
|
|
470
|
+
title?: string;
|
|
471
|
+
description?: string;
|
|
472
|
+
rationale?: string | null;
|
|
473
|
+
alternatives_considered?: string[] | null;
|
|
474
|
+
created_by?: string;
|
|
475
|
+
created_at?: string;
|
|
476
|
+
};
|
|
477
|
+
};
|
|
478
|
+
agent_sessions: {
|
|
479
|
+
Row: {
|
|
480
|
+
id: string;
|
|
481
|
+
api_key_id: string;
|
|
482
|
+
project_id: string;
|
|
483
|
+
last_synced_at: string;
|
|
484
|
+
agent_name: string | null;
|
|
485
|
+
agent_version: string | null;
|
|
486
|
+
instance_id: string | null;
|
|
487
|
+
current_task_id: string | null;
|
|
488
|
+
status: string;
|
|
489
|
+
};
|
|
490
|
+
Insert: {
|
|
491
|
+
id?: string;
|
|
492
|
+
api_key_id: string;
|
|
493
|
+
project_id: string;
|
|
494
|
+
last_synced_at?: string;
|
|
495
|
+
agent_name?: string | null;
|
|
496
|
+
agent_version?: string | null;
|
|
497
|
+
instance_id?: string | null;
|
|
498
|
+
current_task_id?: string | null;
|
|
499
|
+
status?: string;
|
|
500
|
+
};
|
|
501
|
+
Update: {
|
|
502
|
+
id?: string;
|
|
503
|
+
api_key_id?: string;
|
|
504
|
+
project_id?: string;
|
|
505
|
+
last_synced_at?: string;
|
|
506
|
+
agent_name?: string | null;
|
|
507
|
+
agent_version?: string | null;
|
|
508
|
+
instance_id?: string | null;
|
|
509
|
+
current_task_id?: string | null;
|
|
510
|
+
status?: string;
|
|
511
|
+
};
|
|
512
|
+
};
|
|
513
|
+
agent_heartbeats: {
|
|
514
|
+
Row: {
|
|
515
|
+
id: string;
|
|
516
|
+
session_id: string;
|
|
517
|
+
created_at: string;
|
|
518
|
+
};
|
|
519
|
+
Insert: {
|
|
520
|
+
id?: string;
|
|
521
|
+
session_id: string;
|
|
522
|
+
created_at?: string;
|
|
523
|
+
};
|
|
524
|
+
Update: {
|
|
525
|
+
id?: string;
|
|
526
|
+
session_id?: string;
|
|
527
|
+
created_at?: string;
|
|
528
|
+
};
|
|
529
|
+
};
|
|
530
|
+
task_milestones: {
|
|
531
|
+
Row: {
|
|
532
|
+
id: string;
|
|
533
|
+
task_id: string;
|
|
534
|
+
title: string;
|
|
535
|
+
description: string | null;
|
|
536
|
+
order_index: number;
|
|
537
|
+
status: string;
|
|
538
|
+
created_by: string;
|
|
539
|
+
created_at: string;
|
|
540
|
+
completed_at: string | null;
|
|
541
|
+
created_by_session_id: string | null;
|
|
542
|
+
};
|
|
543
|
+
Insert: {
|
|
544
|
+
id?: string;
|
|
545
|
+
task_id: string;
|
|
546
|
+
title: string;
|
|
547
|
+
description?: string | null;
|
|
548
|
+
order_index?: number;
|
|
549
|
+
status?: string;
|
|
550
|
+
created_by?: string;
|
|
551
|
+
created_at?: string;
|
|
552
|
+
completed_at?: string | null;
|
|
553
|
+
created_by_session_id?: string | null;
|
|
554
|
+
};
|
|
555
|
+
Update: {
|
|
556
|
+
id?: string;
|
|
557
|
+
task_id?: string;
|
|
558
|
+
title?: string;
|
|
559
|
+
description?: string | null;
|
|
560
|
+
order_index?: number;
|
|
561
|
+
status?: string;
|
|
562
|
+
created_by?: string;
|
|
563
|
+
created_at?: string;
|
|
564
|
+
completed_at?: string | null;
|
|
565
|
+
created_by_session_id?: string | null;
|
|
566
|
+
};
|
|
567
|
+
};
|
|
568
|
+
};
|
|
569
|
+
Views: Record<string, never>;
|
|
570
|
+
Functions: Record<string, never>;
|
|
571
|
+
Enums: Record<string, never>;
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
interface AuthContext {
|
|
576
|
+
userId: string;
|
|
577
|
+
apiKeyId: string;
|
|
578
|
+
organizationId?: string;
|
|
579
|
+
scope: 'personal' | 'organization';
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
interface UserUpdates {
|
|
583
|
+
tasks: Array<{ id: string; title: string; created_at: string }>;
|
|
584
|
+
blockers: Array<{ id: string; description: string; created_at: string }>;
|
|
585
|
+
ideas: Array<{ id: string; title: string; created_at: string }>;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// ============================================================================
|
|
589
|
+
// Configuration
|
|
590
|
+
// ============================================================================
|
|
591
|
+
|
|
592
|
+
// Default Supabase URL for Vibescope production instance
|
|
593
|
+
const DEFAULT_SUPABASE_URL = 'https://uuneucmuubpgswvfijwd.supabase.co';
|
|
594
|
+
|
|
595
|
+
const SUPABASE_URL = process.env.SUPABASE_URL || process.env.PUBLIC_SUPABASE_URL || DEFAULT_SUPABASE_URL;
|
|
596
|
+
const SUPABASE_SERVICE_KEY = process.env.SUPABASE_SERVICE_KEY;
|
|
597
|
+
const API_KEY = process.env.VIBESCOPE_API_KEY;
|
|
598
|
+
|
|
599
|
+
if (!SUPABASE_SERVICE_KEY) {
|
|
600
|
+
console.error('Missing required environment variable: SUPABASE_SERVICE_KEY');
|
|
601
|
+
process.exit(1);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
if (!API_KEY) {
|
|
605
|
+
console.error('Missing required environment variable: VIBESCOPE_API_KEY');
|
|
606
|
+
process.exit(1);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// ============================================================================
|
|
610
|
+
// Database Client
|
|
611
|
+
// ============================================================================
|
|
612
|
+
|
|
613
|
+
// Using untyped client for MCP server - data validation happens at runtime
|
|
614
|
+
const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_KEY);
|
|
615
|
+
|
|
616
|
+
// ============================================================================
|
|
617
|
+
// Authentication
|
|
618
|
+
// ============================================================================
|
|
619
|
+
|
|
620
|
+
async function validateApiKey(apiKey: string): Promise<AuthContext | null> {
|
|
621
|
+
const keyHash = hashApiKey(apiKey);
|
|
622
|
+
|
|
623
|
+
const { data, error } = await supabase
|
|
624
|
+
.from('api_keys')
|
|
625
|
+
.select('id, user_id, organization_id, scope, is_valid')
|
|
626
|
+
.eq('key_hash', keyHash)
|
|
627
|
+
.single();
|
|
628
|
+
|
|
629
|
+
if (error || !data) {
|
|
630
|
+
return null;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// Check if key has been invalidated (e.g., user left org)
|
|
634
|
+
if (data.is_valid === false) {
|
|
635
|
+
return null;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// For org-scoped keys, verify user is still a member
|
|
639
|
+
if (data.scope === 'organization' && data.organization_id) {
|
|
640
|
+
const { data: member } = await supabase
|
|
641
|
+
.from('organization_members')
|
|
642
|
+
.select('role')
|
|
643
|
+
.eq('organization_id', data.organization_id)
|
|
644
|
+
.eq('user_id', data.user_id)
|
|
645
|
+
.single();
|
|
646
|
+
|
|
647
|
+
if (!member) {
|
|
648
|
+
// User is no longer a member, invalidate the key
|
|
649
|
+
await supabase
|
|
650
|
+
.from('api_keys')
|
|
651
|
+
.update({ is_valid: false })
|
|
652
|
+
.eq('id', data.id);
|
|
653
|
+
return null;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// Update last_used_at
|
|
658
|
+
await supabase
|
|
659
|
+
.from('api_keys')
|
|
660
|
+
.update({ last_used_at: new Date().toISOString() })
|
|
661
|
+
.eq('id', data.id);
|
|
662
|
+
|
|
663
|
+
return {
|
|
664
|
+
userId: data.user_id,
|
|
665
|
+
apiKeyId: data.id,
|
|
666
|
+
organizationId: data.organization_id || undefined,
|
|
667
|
+
scope: data.scope || 'personal',
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// ============================================================================
|
|
672
|
+
// Session Status Checking (Multi-Agent Coordination)
|
|
673
|
+
// ============================================================================
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Check if an agent session is active or stale.
|
|
677
|
+
* A session is considered stale if:
|
|
678
|
+
* - It doesn't exist (orphaned reference)
|
|
679
|
+
* - Its status is 'disconnected'
|
|
680
|
+
* - Its last_synced_at is older than 5 minutes
|
|
681
|
+
*/
|
|
682
|
+
async function checkSessionStatus(
|
|
683
|
+
sessionId: string
|
|
684
|
+
): Promise<{ exists: boolean; isActive: boolean; agentName?: string }> {
|
|
685
|
+
const { data: session } = await supabase
|
|
686
|
+
.from('agent_sessions')
|
|
687
|
+
.select('id, status, last_synced_at, agent_name, instance_id')
|
|
688
|
+
.eq('id', sessionId)
|
|
689
|
+
.single();
|
|
690
|
+
|
|
691
|
+
if (!session) {
|
|
692
|
+
return { exists: false, isActive: false };
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
const lastSync = new Date(session.last_synced_at).getTime();
|
|
696
|
+
const fiveMinutesAgo = Date.now() - 5 * 60 * 1000;
|
|
697
|
+
const isActive = session.status !== 'disconnected' && lastSync > fiveMinutesAgo;
|
|
698
|
+
|
|
699
|
+
return {
|
|
700
|
+
exists: true,
|
|
701
|
+
isActive,
|
|
702
|
+
agentName: session.agent_name || `Agent ${session.instance_id?.slice(0, 8) || sessionId.slice(0, 8)}`,
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// ============================================================================
|
|
707
|
+
// User Updates Tracking
|
|
708
|
+
// ============================================================================
|
|
709
|
+
|
|
710
|
+
async function getUserUpdates(
|
|
711
|
+
auth: AuthContext,
|
|
712
|
+
projectId: string
|
|
713
|
+
): Promise<UserUpdates | undefined> {
|
|
714
|
+
// Get session's last_synced_at - prefer currentSessionId for accuracy
|
|
715
|
+
let lastSyncedAt: string;
|
|
716
|
+
|
|
717
|
+
if (currentSessionId) {
|
|
718
|
+
const { data: session } = await supabase
|
|
719
|
+
.from('agent_sessions')
|
|
720
|
+
.select('last_synced_at')
|
|
721
|
+
.eq('id', currentSessionId)
|
|
722
|
+
.single();
|
|
723
|
+
lastSyncedAt = session?.last_synced_at || new Date(0).toISOString();
|
|
724
|
+
} else {
|
|
725
|
+
const { data: session } = await supabase
|
|
726
|
+
.from('agent_sessions')
|
|
727
|
+
.select('last_synced_at')
|
|
728
|
+
.eq('api_key_id', auth.apiKeyId)
|
|
729
|
+
.eq('project_id', projectId)
|
|
730
|
+
.single();
|
|
731
|
+
lastSyncedAt = session?.last_synced_at || new Date(0).toISOString();
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// Fetch user-created items since last sync (limit to 5 each for context efficiency)
|
|
735
|
+
const [tasksResult, blockersResult, ideasResult] = await Promise.all([
|
|
736
|
+
supabase
|
|
737
|
+
.from('tasks')
|
|
738
|
+
.select('id, title, created_at')
|
|
739
|
+
.eq('project_id', projectId)
|
|
740
|
+
.eq('created_by', 'user')
|
|
741
|
+
.gt('created_at', lastSyncedAt)
|
|
742
|
+
.order('created_at', { ascending: false })
|
|
743
|
+
.limit(5),
|
|
744
|
+
supabase
|
|
745
|
+
.from('blockers')
|
|
746
|
+
.select('id, description, created_at')
|
|
747
|
+
.eq('project_id', projectId)
|
|
748
|
+
.eq('created_by', 'user')
|
|
749
|
+
.gt('created_at', lastSyncedAt)
|
|
750
|
+
.order('created_at', { ascending: false })
|
|
751
|
+
.limit(5),
|
|
752
|
+
supabase
|
|
753
|
+
.from('ideas')
|
|
754
|
+
.select('id, title, created_at')
|
|
755
|
+
.eq('project_id', projectId)
|
|
756
|
+
.eq('created_by', 'user')
|
|
757
|
+
.gt('created_at', lastSyncedAt)
|
|
758
|
+
.order('created_at', { ascending: false })
|
|
759
|
+
.limit(5),
|
|
760
|
+
]);
|
|
761
|
+
|
|
762
|
+
const tasks = tasksResult.data || [];
|
|
763
|
+
const blockers = blockersResult.data || [];
|
|
764
|
+
const ideas = ideasResult.data || [];
|
|
765
|
+
|
|
766
|
+
// Return undefined if no new updates (saves context window space)
|
|
767
|
+
if (tasks.length === 0 && blockers.length === 0 && ideas.length === 0) {
|
|
768
|
+
return undefined;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
return { tasks, blockers, ideas };
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// ============================================================================
|
|
775
|
+
// Tool Definitions
|
|
776
|
+
// ============================================================================
|
|
777
|
+
|
|
778
|
+
const tools: Tool[] = [
|
|
779
|
+
{
|
|
780
|
+
name: 'start_work_session',
|
|
781
|
+
description: `CALL THIS FIRST when beginning work on a project.
|
|
782
|
+
Returns session info, persona, and next task. Use mode:'full' for complete context.`,
|
|
783
|
+
inputSchema: {
|
|
784
|
+
type: 'object',
|
|
785
|
+
properties: {
|
|
786
|
+
project_id: {
|
|
787
|
+
type: 'string',
|
|
788
|
+
description: 'Project UUID',
|
|
789
|
+
},
|
|
790
|
+
git_url: {
|
|
791
|
+
type: 'string',
|
|
792
|
+
description: 'Git repository URL. Used to find project if project_id not provided.',
|
|
793
|
+
},
|
|
794
|
+
mode: {
|
|
795
|
+
type: 'string',
|
|
796
|
+
enum: ['lite', 'full'],
|
|
797
|
+
description: 'Response mode: lite (default, minimal tokens) or full (complete context)',
|
|
798
|
+
},
|
|
799
|
+
model: {
|
|
800
|
+
type: 'string',
|
|
801
|
+
enum: ['opus', 'sonnet', 'haiku'],
|
|
802
|
+
description: 'Claude model being used (for accurate cost tracking). E.g., "opus", "sonnet", "haiku".',
|
|
803
|
+
},
|
|
804
|
+
},
|
|
805
|
+
},
|
|
806
|
+
},
|
|
807
|
+
{
|
|
808
|
+
name: 'get_help',
|
|
809
|
+
description: 'Get guidance on a specific topic. Use when unsure about workflows.',
|
|
810
|
+
inputSchema: {
|
|
811
|
+
type: 'object',
|
|
812
|
+
properties: {
|
|
813
|
+
topic: {
|
|
814
|
+
type: 'string',
|
|
815
|
+
enum: ['getting_started', 'tasks', 'validation', 'deployment', 'git', 'blockers', 'milestones', 'fallback', 'session', 'tokens', 'topics'],
|
|
816
|
+
description: 'Help topic. Use "topics" to list all available.',
|
|
817
|
+
},
|
|
818
|
+
},
|
|
819
|
+
required: ['topic'],
|
|
820
|
+
},
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
name: 'get_token_usage',
|
|
824
|
+
description: 'Get token usage stats for this session. Monitor efficiency.',
|
|
825
|
+
inputSchema: {
|
|
826
|
+
type: 'object',
|
|
827
|
+
properties: {},
|
|
828
|
+
},
|
|
829
|
+
},
|
|
830
|
+
// Cost monitoring tools
|
|
831
|
+
{
|
|
832
|
+
name: 'get_cost_summary',
|
|
833
|
+
description: 'Get cost summary (daily/weekly/monthly) for a project.',
|
|
834
|
+
inputSchema: {
|
|
835
|
+
type: 'object',
|
|
836
|
+
properties: {
|
|
837
|
+
project_id: {
|
|
838
|
+
type: 'string',
|
|
839
|
+
description: 'Project UUID',
|
|
840
|
+
},
|
|
841
|
+
period: {
|
|
842
|
+
type: 'string',
|
|
843
|
+
enum: ['daily', 'weekly', 'monthly'],
|
|
844
|
+
description: 'Summary period (default: daily)',
|
|
845
|
+
},
|
|
846
|
+
limit: {
|
|
847
|
+
type: 'number',
|
|
848
|
+
description: 'Max records to return (default: 30)',
|
|
849
|
+
},
|
|
850
|
+
},
|
|
851
|
+
required: ['project_id'],
|
|
852
|
+
},
|
|
853
|
+
},
|
|
854
|
+
{
|
|
855
|
+
name: 'get_cost_alerts',
|
|
856
|
+
description: 'Get cost alerts for the current user.',
|
|
857
|
+
inputSchema: {
|
|
858
|
+
type: 'object',
|
|
859
|
+
properties: {
|
|
860
|
+
project_id: {
|
|
861
|
+
type: 'string',
|
|
862
|
+
description: 'Filter by project (optional)',
|
|
863
|
+
},
|
|
864
|
+
},
|
|
865
|
+
},
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
name: 'add_cost_alert',
|
|
869
|
+
description: 'Add a cost alert threshold.',
|
|
870
|
+
inputSchema: {
|
|
871
|
+
type: 'object',
|
|
872
|
+
properties: {
|
|
873
|
+
project_id: {
|
|
874
|
+
type: 'string',
|
|
875
|
+
description: 'Project UUID (null for all projects)',
|
|
876
|
+
},
|
|
877
|
+
threshold_amount: {
|
|
878
|
+
type: 'number',
|
|
879
|
+
description: 'Amount in USD that triggers the alert',
|
|
880
|
+
},
|
|
881
|
+
threshold_period: {
|
|
882
|
+
type: 'string',
|
|
883
|
+
enum: ['daily', 'weekly', 'monthly'],
|
|
884
|
+
description: 'Period for the threshold',
|
|
885
|
+
},
|
|
886
|
+
alert_type: {
|
|
887
|
+
type: 'string',
|
|
888
|
+
enum: ['warning', 'critical'],
|
|
889
|
+
description: 'Alert severity (default: warning)',
|
|
890
|
+
},
|
|
891
|
+
},
|
|
892
|
+
required: ['threshold_amount', 'threshold_period'],
|
|
893
|
+
},
|
|
894
|
+
},
|
|
895
|
+
{
|
|
896
|
+
name: 'update_cost_alert',
|
|
897
|
+
description: 'Update a cost alert.',
|
|
898
|
+
inputSchema: {
|
|
899
|
+
type: 'object',
|
|
900
|
+
properties: {
|
|
901
|
+
alert_id: {
|
|
902
|
+
type: 'string',
|
|
903
|
+
description: 'Alert UUID',
|
|
904
|
+
},
|
|
905
|
+
threshold_amount: {
|
|
906
|
+
type: 'number',
|
|
907
|
+
description: 'New threshold amount in USD',
|
|
908
|
+
},
|
|
909
|
+
threshold_period: {
|
|
910
|
+
type: 'string',
|
|
911
|
+
enum: ['daily', 'weekly', 'monthly'],
|
|
912
|
+
description: 'New period',
|
|
913
|
+
},
|
|
914
|
+
alert_type: {
|
|
915
|
+
type: 'string',
|
|
916
|
+
enum: ['warning', 'critical'],
|
|
917
|
+
description: 'New alert type',
|
|
918
|
+
},
|
|
919
|
+
enabled: {
|
|
920
|
+
type: 'boolean',
|
|
921
|
+
description: 'Enable or disable the alert',
|
|
922
|
+
},
|
|
923
|
+
},
|
|
924
|
+
required: ['alert_id'],
|
|
925
|
+
},
|
|
926
|
+
},
|
|
927
|
+
{
|
|
928
|
+
name: 'delete_cost_alert',
|
|
929
|
+
description: 'Delete a cost alert.',
|
|
930
|
+
inputSchema: {
|
|
931
|
+
type: 'object',
|
|
932
|
+
properties: {
|
|
933
|
+
alert_id: {
|
|
934
|
+
type: 'string',
|
|
935
|
+
description: 'Alert UUID to delete',
|
|
936
|
+
},
|
|
937
|
+
},
|
|
938
|
+
required: ['alert_id'],
|
|
939
|
+
},
|
|
940
|
+
},
|
|
941
|
+
{
|
|
942
|
+
name: 'get_task_costs',
|
|
943
|
+
description: 'Get cost breakdown by task for a project.',
|
|
944
|
+
inputSchema: {
|
|
945
|
+
type: 'object',
|
|
946
|
+
properties: {
|
|
947
|
+
project_id: {
|
|
948
|
+
type: 'string',
|
|
949
|
+
description: 'Project UUID',
|
|
950
|
+
},
|
|
951
|
+
limit: {
|
|
952
|
+
type: 'number',
|
|
953
|
+
description: 'Max tasks to return (default: 20)',
|
|
954
|
+
},
|
|
955
|
+
},
|
|
956
|
+
required: ['project_id'],
|
|
957
|
+
},
|
|
958
|
+
},
|
|
959
|
+
{
|
|
960
|
+
name: 'discover_tools',
|
|
961
|
+
description: 'List tools by category. Use get_tool_info for details.',
|
|
962
|
+
inputSchema: {
|
|
963
|
+
type: 'object',
|
|
964
|
+
properties: {
|
|
965
|
+
category: {
|
|
966
|
+
type: 'string',
|
|
967
|
+
enum: ['session', 'project', 'tasks', 'milestones', 'progress', 'blockers', 'decisions', 'ideas', 'findings', 'validation', 'deployment', 'fallback', 'requests', 'organizations', 'cost'],
|
|
968
|
+
description: 'Category to list (omit for all categories)',
|
|
969
|
+
},
|
|
970
|
+
},
|
|
971
|
+
},
|
|
972
|
+
},
|
|
973
|
+
{
|
|
974
|
+
name: 'get_tool_info',
|
|
975
|
+
description: 'Get detailed tool documentation.',
|
|
976
|
+
inputSchema: {
|
|
977
|
+
type: 'object',
|
|
978
|
+
properties: {
|
|
979
|
+
tool_name: {
|
|
980
|
+
type: 'string',
|
|
981
|
+
description: 'Tool name',
|
|
982
|
+
},
|
|
983
|
+
},
|
|
984
|
+
required: ['tool_name'],
|
|
985
|
+
},
|
|
986
|
+
},
|
|
987
|
+
{
|
|
988
|
+
name: 'get_project_context',
|
|
989
|
+
description: 'Get full project context: goals, instructions, tasks, blockers, decisions.',
|
|
990
|
+
inputSchema: {
|
|
991
|
+
type: 'object',
|
|
992
|
+
properties: {
|
|
993
|
+
project_id: {
|
|
994
|
+
type: 'string',
|
|
995
|
+
description: 'Project UUID. If not provided, will list all projects.',
|
|
996
|
+
},
|
|
997
|
+
git_url: {
|
|
998
|
+
type: 'string',
|
|
999
|
+
description: 'Git repository URL. Used to find project if project_id not provided.',
|
|
1000
|
+
},
|
|
1001
|
+
},
|
|
1002
|
+
},
|
|
1003
|
+
},
|
|
1004
|
+
{
|
|
1005
|
+
name: 'get_git_workflow',
|
|
1006
|
+
description: 'Get git workflow config and branching instructions for the project.',
|
|
1007
|
+
inputSchema: {
|
|
1008
|
+
type: 'object',
|
|
1009
|
+
properties: {
|
|
1010
|
+
project_id: {
|
|
1011
|
+
type: 'string',
|
|
1012
|
+
description: 'Project UUID',
|
|
1013
|
+
},
|
|
1014
|
+
task_id: {
|
|
1015
|
+
type: 'string',
|
|
1016
|
+
description: 'Optional task ID to include branch naming suggestion',
|
|
1017
|
+
},
|
|
1018
|
+
},
|
|
1019
|
+
required: ['project_id'],
|
|
1020
|
+
},
|
|
1021
|
+
},
|
|
1022
|
+
{
|
|
1023
|
+
name: 'create_project',
|
|
1024
|
+
description: 'Create a new project to track in Vibescope.',
|
|
1025
|
+
inputSchema: {
|
|
1026
|
+
type: 'object',
|
|
1027
|
+
properties: {
|
|
1028
|
+
name: {
|
|
1029
|
+
type: 'string',
|
|
1030
|
+
description: 'Project display name',
|
|
1031
|
+
},
|
|
1032
|
+
description: {
|
|
1033
|
+
type: 'string',
|
|
1034
|
+
description: 'Brief project description',
|
|
1035
|
+
},
|
|
1036
|
+
goal: {
|
|
1037
|
+
type: 'string',
|
|
1038
|
+
description: 'What does "done" look like for this project?',
|
|
1039
|
+
},
|
|
1040
|
+
git_url: {
|
|
1041
|
+
type: 'string',
|
|
1042
|
+
description: 'Git repository URL (if available)',
|
|
1043
|
+
},
|
|
1044
|
+
tech_stack: {
|
|
1045
|
+
type: 'array',
|
|
1046
|
+
items: { type: 'string' },
|
|
1047
|
+
description: 'Technologies used (e.g., ["TypeScript", "React", "PostgreSQL"])',
|
|
1048
|
+
},
|
|
1049
|
+
},
|
|
1050
|
+
required: ['name'],
|
|
1051
|
+
},
|
|
1052
|
+
},
|
|
1053
|
+
{
|
|
1054
|
+
name: 'update_project',
|
|
1055
|
+
description: 'Update project details (name, description, goal, settings).',
|
|
1056
|
+
inputSchema: {
|
|
1057
|
+
type: 'object',
|
|
1058
|
+
properties: {
|
|
1059
|
+
project_id: {
|
|
1060
|
+
type: 'string',
|
|
1061
|
+
description: 'Project UUID',
|
|
1062
|
+
},
|
|
1063
|
+
name: { type: 'string' },
|
|
1064
|
+
description: { type: 'string' },
|
|
1065
|
+
goal: { type: 'string' },
|
|
1066
|
+
git_url: { type: 'string' },
|
|
1067
|
+
tech_stack: {
|
|
1068
|
+
type: 'array',
|
|
1069
|
+
items: { type: 'string' },
|
|
1070
|
+
},
|
|
1071
|
+
status: {
|
|
1072
|
+
type: 'string',
|
|
1073
|
+
enum: ['active', 'paused', 'completed', 'archived'],
|
|
1074
|
+
},
|
|
1075
|
+
git_workflow: {
|
|
1076
|
+
type: 'string',
|
|
1077
|
+
enum: ['none', 'trunk-based', 'github-flow', 'git-flow'],
|
|
1078
|
+
description: 'Git workflow: none (no branching), trunk-based (commit to main), github-flow (feature branches + PR), git-flow (develop/release branches)',
|
|
1079
|
+
},
|
|
1080
|
+
git_main_branch: {
|
|
1081
|
+
type: 'string',
|
|
1082
|
+
description: 'Main branch name (default: main)',
|
|
1083
|
+
},
|
|
1084
|
+
git_develop_branch: {
|
|
1085
|
+
type: 'string',
|
|
1086
|
+
description: 'Development branch name (used with git-flow)',
|
|
1087
|
+
},
|
|
1088
|
+
git_auto_branch: {
|
|
1089
|
+
type: 'boolean',
|
|
1090
|
+
description: 'Automatically create feature branches for new tasks',
|
|
1091
|
+
},
|
|
1092
|
+
git_auto_tag: {
|
|
1093
|
+
type: 'boolean',
|
|
1094
|
+
description: 'Automatically tag deployments on main branch',
|
|
1095
|
+
},
|
|
1096
|
+
deployment_instructions: {
|
|
1097
|
+
type: 'string',
|
|
1098
|
+
description: 'Instructions for how to deploy (e.g., "Push to main for Vercel auto-deploy", "Run fly deploy")',
|
|
1099
|
+
},
|
|
1100
|
+
},
|
|
1101
|
+
required: ['project_id'],
|
|
1102
|
+
},
|
|
1103
|
+
},
|
|
1104
|
+
{
|
|
1105
|
+
name: 'update_project_readme',
|
|
1106
|
+
description: 'Sync README content to the dashboard.',
|
|
1107
|
+
inputSchema: {
|
|
1108
|
+
type: 'object',
|
|
1109
|
+
properties: {
|
|
1110
|
+
project_id: {
|
|
1111
|
+
type: 'string',
|
|
1112
|
+
description: 'Project UUID',
|
|
1113
|
+
},
|
|
1114
|
+
readme_content: {
|
|
1115
|
+
type: 'string',
|
|
1116
|
+
description: 'README content in markdown format',
|
|
1117
|
+
},
|
|
1118
|
+
},
|
|
1119
|
+
required: ['project_id', 'readme_content'],
|
|
1120
|
+
},
|
|
1121
|
+
},
|
|
1122
|
+
{
|
|
1123
|
+
name: 'get_tasks',
|
|
1124
|
+
description: 'Get tasks for a project, optionally filtered by status. By default returns only root tasks (not subtasks).',
|
|
1125
|
+
inputSchema: {
|
|
1126
|
+
type: 'object',
|
|
1127
|
+
properties: {
|
|
1128
|
+
project_id: {
|
|
1129
|
+
type: 'string',
|
|
1130
|
+
description: 'Project UUID',
|
|
1131
|
+
},
|
|
1132
|
+
status: {
|
|
1133
|
+
type: 'string',
|
|
1134
|
+
enum: ['backlog', 'pending', 'in_progress', 'completed', 'cancelled'],
|
|
1135
|
+
description: 'Filter by status (optional)',
|
|
1136
|
+
},
|
|
1137
|
+
limit: {
|
|
1138
|
+
type: 'number',
|
|
1139
|
+
description: 'Max number of tasks to return (default 50)',
|
|
1140
|
+
},
|
|
1141
|
+
include_subtasks: {
|
|
1142
|
+
type: 'boolean',
|
|
1143
|
+
description: 'Include subtasks in results (default false). Use get_subtasks for subtasks of a specific task.',
|
|
1144
|
+
},
|
|
1145
|
+
},
|
|
1146
|
+
required: ['project_id'],
|
|
1147
|
+
},
|
|
1148
|
+
},
|
|
1149
|
+
{
|
|
1150
|
+
name: 'get_next_task',
|
|
1151
|
+
description: 'Get highest priority pending task. Skips claimed tasks. Check deployment_blocks_tasks first.',
|
|
1152
|
+
inputSchema: {
|
|
1153
|
+
type: 'object',
|
|
1154
|
+
properties: {
|
|
1155
|
+
project_id: {
|
|
1156
|
+
type: 'string',
|
|
1157
|
+
description: 'Project UUID',
|
|
1158
|
+
},
|
|
1159
|
+
},
|
|
1160
|
+
required: ['project_id'],
|
|
1161
|
+
},
|
|
1162
|
+
},
|
|
1163
|
+
{
|
|
1164
|
+
name: 'add_task',
|
|
1165
|
+
description: 'Add a new task. Priority 1=highest, 5=lowest. Include estimated_minutes. Use blocking=true for deployment finalization tasks that must complete before other work.',
|
|
1166
|
+
inputSchema: {
|
|
1167
|
+
type: 'object',
|
|
1168
|
+
properties: {
|
|
1169
|
+
project_id: {
|
|
1170
|
+
type: 'string',
|
|
1171
|
+
description: 'Project UUID',
|
|
1172
|
+
},
|
|
1173
|
+
title: {
|
|
1174
|
+
type: 'string',
|
|
1175
|
+
description: 'Task title',
|
|
1176
|
+
},
|
|
1177
|
+
description: {
|
|
1178
|
+
type: 'string',
|
|
1179
|
+
description: 'Detailed description',
|
|
1180
|
+
},
|
|
1181
|
+
priority: {
|
|
1182
|
+
type: 'number',
|
|
1183
|
+
minimum: 1,
|
|
1184
|
+
maximum: 5,
|
|
1185
|
+
description: 'Priority 1-5 (1 = highest)',
|
|
1186
|
+
},
|
|
1187
|
+
estimated_minutes: {
|
|
1188
|
+
type: 'number',
|
|
1189
|
+
minimum: 1,
|
|
1190
|
+
description: 'Estimated time to complete in minutes',
|
|
1191
|
+
},
|
|
1192
|
+
blocking: {
|
|
1193
|
+
type: 'boolean',
|
|
1194
|
+
description: 'When true, this task blocks all other work until complete (used for deployment finalization)',
|
|
1195
|
+
},
|
|
1196
|
+
},
|
|
1197
|
+
required: ['project_id', 'title'],
|
|
1198
|
+
},
|
|
1199
|
+
},
|
|
1200
|
+
{
|
|
1201
|
+
name: 'update_task',
|
|
1202
|
+
description: 'Update task status, progress, or details. Include progress_note with progress_percentage.',
|
|
1203
|
+
inputSchema: {
|
|
1204
|
+
type: 'object',
|
|
1205
|
+
properties: {
|
|
1206
|
+
task_id: {
|
|
1207
|
+
type: 'string',
|
|
1208
|
+
description: 'Task UUID',
|
|
1209
|
+
},
|
|
1210
|
+
title: { type: 'string' },
|
|
1211
|
+
description: { type: 'string' },
|
|
1212
|
+
priority: {
|
|
1213
|
+
type: 'number',
|
|
1214
|
+
minimum: 1,
|
|
1215
|
+
maximum: 5,
|
|
1216
|
+
},
|
|
1217
|
+
status: {
|
|
1218
|
+
type: 'string',
|
|
1219
|
+
enum: ['backlog', 'pending', 'in_progress', 'completed', 'cancelled'],
|
|
1220
|
+
},
|
|
1221
|
+
progress_percentage: {
|
|
1222
|
+
type: 'number',
|
|
1223
|
+
minimum: 0,
|
|
1224
|
+
maximum: 100,
|
|
1225
|
+
description: '0-100 completion percentage',
|
|
1226
|
+
},
|
|
1227
|
+
progress_note: {
|
|
1228
|
+
type: 'string',
|
|
1229
|
+
description: 'Brief note (auto-logged)',
|
|
1230
|
+
},
|
|
1231
|
+
estimated_minutes: {
|
|
1232
|
+
type: 'number',
|
|
1233
|
+
minimum: 1,
|
|
1234
|
+
description: 'Revised time estimate',
|
|
1235
|
+
},
|
|
1236
|
+
git_branch: {
|
|
1237
|
+
type: 'string',
|
|
1238
|
+
description: 'Git branch associated with this task',
|
|
1239
|
+
},
|
|
1240
|
+
},
|
|
1241
|
+
required: ['task_id'],
|
|
1242
|
+
},
|
|
1243
|
+
},
|
|
1244
|
+
{
|
|
1245
|
+
name: 'complete_task',
|
|
1246
|
+
description: 'Mark task done. Returns next_task and context counts (validation, blockers, deployment).',
|
|
1247
|
+
inputSchema: {
|
|
1248
|
+
type: 'object',
|
|
1249
|
+
properties: {
|
|
1250
|
+
task_id: {
|
|
1251
|
+
type: 'string',
|
|
1252
|
+
description: 'Task UUID',
|
|
1253
|
+
},
|
|
1254
|
+
summary: {
|
|
1255
|
+
type: 'string',
|
|
1256
|
+
description: 'Brief summary of what was done',
|
|
1257
|
+
},
|
|
1258
|
+
},
|
|
1259
|
+
required: ['task_id'],
|
|
1260
|
+
},
|
|
1261
|
+
},
|
|
1262
|
+
{
|
|
1263
|
+
name: 'log_progress',
|
|
1264
|
+
description: `Log progress update. Record significant milestones or observations.`,
|
|
1265
|
+
inputSchema: {
|
|
1266
|
+
type: 'object',
|
|
1267
|
+
properties: {
|
|
1268
|
+
project_id: {
|
|
1269
|
+
type: 'string',
|
|
1270
|
+
description: 'Project UUID',
|
|
1271
|
+
},
|
|
1272
|
+
task_id: {
|
|
1273
|
+
type: 'string',
|
|
1274
|
+
description: 'Task UUID (optional, links progress to specific task)',
|
|
1275
|
+
},
|
|
1276
|
+
summary: {
|
|
1277
|
+
type: 'string',
|
|
1278
|
+
description: 'Brief summary of progress',
|
|
1279
|
+
},
|
|
1280
|
+
details: {
|
|
1281
|
+
type: 'string',
|
|
1282
|
+
description: 'Detailed notes (optional)',
|
|
1283
|
+
},
|
|
1284
|
+
},
|
|
1285
|
+
required: ['project_id', 'summary'],
|
|
1286
|
+
},
|
|
1287
|
+
},
|
|
1288
|
+
{
|
|
1289
|
+
name: 'add_blocker',
|
|
1290
|
+
description: `Record a blocker preventing progress.`,
|
|
1291
|
+
inputSchema: {
|
|
1292
|
+
type: 'object',
|
|
1293
|
+
properties: {
|
|
1294
|
+
project_id: {
|
|
1295
|
+
type: 'string',
|
|
1296
|
+
description: 'Project UUID',
|
|
1297
|
+
},
|
|
1298
|
+
description: {
|
|
1299
|
+
type: 'string',
|
|
1300
|
+
description: 'What is blocking progress?',
|
|
1301
|
+
},
|
|
1302
|
+
},
|
|
1303
|
+
required: ['project_id', 'description'],
|
|
1304
|
+
},
|
|
1305
|
+
},
|
|
1306
|
+
{
|
|
1307
|
+
name: 'resolve_blocker',
|
|
1308
|
+
description: `Mark a blocker as resolved.`,
|
|
1309
|
+
inputSchema: {
|
|
1310
|
+
type: 'object',
|
|
1311
|
+
properties: {
|
|
1312
|
+
blocker_id: {
|
|
1313
|
+
type: 'string',
|
|
1314
|
+
description: 'Blocker UUID',
|
|
1315
|
+
},
|
|
1316
|
+
resolution_note: {
|
|
1317
|
+
type: 'string',
|
|
1318
|
+
description: 'How was it resolved?',
|
|
1319
|
+
},
|
|
1320
|
+
},
|
|
1321
|
+
required: ['blocker_id'],
|
|
1322
|
+
},
|
|
1323
|
+
},
|
|
1324
|
+
{
|
|
1325
|
+
name: 'get_blockers',
|
|
1326
|
+
description: `Get blockers for a project, optionally filtered by status.`,
|
|
1327
|
+
inputSchema: {
|
|
1328
|
+
type: 'object',
|
|
1329
|
+
properties: {
|
|
1330
|
+
project_id: {
|
|
1331
|
+
type: 'string',
|
|
1332
|
+
description: 'Project UUID',
|
|
1333
|
+
},
|
|
1334
|
+
status: {
|
|
1335
|
+
type: 'string',
|
|
1336
|
+
enum: ['open', 'resolved'],
|
|
1337
|
+
description: 'Filter by status (default: open)',
|
|
1338
|
+
},
|
|
1339
|
+
},
|
|
1340
|
+
required: ['project_id'],
|
|
1341
|
+
},
|
|
1342
|
+
},
|
|
1343
|
+
{
|
|
1344
|
+
name: 'log_decision',
|
|
1345
|
+
description: `Record an architectural or technical decision with rationale.`,
|
|
1346
|
+
inputSchema: {
|
|
1347
|
+
type: 'object',
|
|
1348
|
+
properties: {
|
|
1349
|
+
project_id: {
|
|
1350
|
+
type: 'string',
|
|
1351
|
+
description: 'Project UUID',
|
|
1352
|
+
},
|
|
1353
|
+
title: {
|
|
1354
|
+
type: 'string',
|
|
1355
|
+
description: 'Decision title (e.g., "Use PostgreSQL for database")',
|
|
1356
|
+
},
|
|
1357
|
+
description: {
|
|
1358
|
+
type: 'string',
|
|
1359
|
+
description: 'What was decided',
|
|
1360
|
+
},
|
|
1361
|
+
rationale: {
|
|
1362
|
+
type: 'string',
|
|
1363
|
+
description: 'Why this decision was made',
|
|
1364
|
+
},
|
|
1365
|
+
alternatives_considered: {
|
|
1366
|
+
type: 'array',
|
|
1367
|
+
items: { type: 'string' },
|
|
1368
|
+
description: 'Other options that were considered',
|
|
1369
|
+
},
|
|
1370
|
+
},
|
|
1371
|
+
required: ['project_id', 'title', 'description'],
|
|
1372
|
+
},
|
|
1373
|
+
},
|
|
1374
|
+
{
|
|
1375
|
+
name: 'get_decisions',
|
|
1376
|
+
description: `Get recorded decisions for a project.`,
|
|
1377
|
+
inputSchema: {
|
|
1378
|
+
type: 'object',
|
|
1379
|
+
properties: {
|
|
1380
|
+
project_id: {
|
|
1381
|
+
type: 'string',
|
|
1382
|
+
description: 'Project UUID',
|
|
1383
|
+
},
|
|
1384
|
+
},
|
|
1385
|
+
required: ['project_id'],
|
|
1386
|
+
},
|
|
1387
|
+
},
|
|
1388
|
+
{
|
|
1389
|
+
name: 'add_idea',
|
|
1390
|
+
description: `Record an idea for improvements or features. Starts as 'raw', can progress to 'shipped'.`,
|
|
1391
|
+
inputSchema: {
|
|
1392
|
+
type: 'object',
|
|
1393
|
+
properties: {
|
|
1394
|
+
project_id: {
|
|
1395
|
+
type: 'string',
|
|
1396
|
+
description: 'Project UUID',
|
|
1397
|
+
},
|
|
1398
|
+
title: {
|
|
1399
|
+
type: 'string',
|
|
1400
|
+
description: 'Idea title',
|
|
1401
|
+
},
|
|
1402
|
+
description: {
|
|
1403
|
+
type: 'string',
|
|
1404
|
+
description: 'Detailed description',
|
|
1405
|
+
},
|
|
1406
|
+
status: {
|
|
1407
|
+
type: 'string',
|
|
1408
|
+
enum: ['raw', 'exploring', 'planned', 'in_development', 'shipped'],
|
|
1409
|
+
description: 'Development stage (default: raw)',
|
|
1410
|
+
},
|
|
1411
|
+
},
|
|
1412
|
+
required: ['project_id', 'title'],
|
|
1413
|
+
},
|
|
1414
|
+
},
|
|
1415
|
+
{
|
|
1416
|
+
name: 'update_idea',
|
|
1417
|
+
description: `Update an idea's status or details.`,
|
|
1418
|
+
inputSchema: {
|
|
1419
|
+
type: 'object',
|
|
1420
|
+
properties: {
|
|
1421
|
+
idea_id: {
|
|
1422
|
+
type: 'string',
|
|
1423
|
+
description: 'Idea UUID',
|
|
1424
|
+
},
|
|
1425
|
+
title: {
|
|
1426
|
+
type: 'string',
|
|
1427
|
+
description: 'Updated title',
|
|
1428
|
+
},
|
|
1429
|
+
description: {
|
|
1430
|
+
type: 'string',
|
|
1431
|
+
description: 'Updated description',
|
|
1432
|
+
},
|
|
1433
|
+
status: {
|
|
1434
|
+
type: 'string',
|
|
1435
|
+
enum: ['raw', 'exploring', 'planned', 'in_development', 'shipped'],
|
|
1436
|
+
description: 'New development stage',
|
|
1437
|
+
},
|
|
1438
|
+
doc_url: {
|
|
1439
|
+
type: 'string',
|
|
1440
|
+
description: 'URL to feature documentation/specification',
|
|
1441
|
+
},
|
|
1442
|
+
},
|
|
1443
|
+
required: ['idea_id'],
|
|
1444
|
+
},
|
|
1445
|
+
},
|
|
1446
|
+
{
|
|
1447
|
+
name: 'get_ideas',
|
|
1448
|
+
description: `Get recorded ideas for a project, optionally filtered by status.`,
|
|
1449
|
+
inputSchema: {
|
|
1450
|
+
type: 'object',
|
|
1451
|
+
properties: {
|
|
1452
|
+
project_id: {
|
|
1453
|
+
type: 'string',
|
|
1454
|
+
description: 'Project UUID',
|
|
1455
|
+
},
|
|
1456
|
+
status: {
|
|
1457
|
+
type: 'string',
|
|
1458
|
+
enum: ['raw', 'exploring', 'planned', 'in_development', 'shipped'],
|
|
1459
|
+
description: 'Filter by status (optional)',
|
|
1460
|
+
},
|
|
1461
|
+
},
|
|
1462
|
+
required: ['project_id'],
|
|
1463
|
+
},
|
|
1464
|
+
},
|
|
1465
|
+
{
|
|
1466
|
+
name: 'delete_task',
|
|
1467
|
+
description: `Delete a task.`,
|
|
1468
|
+
inputSchema: {
|
|
1469
|
+
type: 'object',
|
|
1470
|
+
properties: {
|
|
1471
|
+
task_id: {
|
|
1472
|
+
type: 'string',
|
|
1473
|
+
description: 'Task UUID',
|
|
1474
|
+
},
|
|
1475
|
+
},
|
|
1476
|
+
required: ['task_id'],
|
|
1477
|
+
},
|
|
1478
|
+
},
|
|
1479
|
+
{
|
|
1480
|
+
name: 'add_task_reference',
|
|
1481
|
+
description: 'Add a reference URL to a task (docs, PRs, issues).',
|
|
1482
|
+
inputSchema: {
|
|
1483
|
+
type: 'object',
|
|
1484
|
+
properties: {
|
|
1485
|
+
task_id: {
|
|
1486
|
+
type: 'string',
|
|
1487
|
+
description: 'Task UUID',
|
|
1488
|
+
},
|
|
1489
|
+
url: {
|
|
1490
|
+
type: 'string',
|
|
1491
|
+
description: 'URL to add as reference',
|
|
1492
|
+
},
|
|
1493
|
+
label: {
|
|
1494
|
+
type: 'string',
|
|
1495
|
+
description: 'Optional label/title for the reference',
|
|
1496
|
+
},
|
|
1497
|
+
},
|
|
1498
|
+
required: ['task_id', 'url'],
|
|
1499
|
+
},
|
|
1500
|
+
},
|
|
1501
|
+
{
|
|
1502
|
+
name: 'remove_task_reference',
|
|
1503
|
+
description: `Remove a reference link from a task by URL.`,
|
|
1504
|
+
inputSchema: {
|
|
1505
|
+
type: 'object',
|
|
1506
|
+
properties: {
|
|
1507
|
+
task_id: {
|
|
1508
|
+
type: 'string',
|
|
1509
|
+
description: 'Task UUID',
|
|
1510
|
+
},
|
|
1511
|
+
url: {
|
|
1512
|
+
type: 'string',
|
|
1513
|
+
description: 'URL of the reference to remove',
|
|
1514
|
+
},
|
|
1515
|
+
},
|
|
1516
|
+
required: ['task_id', 'url'],
|
|
1517
|
+
},
|
|
1518
|
+
},
|
|
1519
|
+
{
|
|
1520
|
+
name: 'delete_idea',
|
|
1521
|
+
description: `Delete an idea.`,
|
|
1522
|
+
inputSchema: {
|
|
1523
|
+
type: 'object',
|
|
1524
|
+
properties: {
|
|
1525
|
+
idea_id: {
|
|
1526
|
+
type: 'string',
|
|
1527
|
+
description: 'Idea UUID',
|
|
1528
|
+
},
|
|
1529
|
+
},
|
|
1530
|
+
required: ['idea_id'],
|
|
1531
|
+
},
|
|
1532
|
+
},
|
|
1533
|
+
{
|
|
1534
|
+
name: 'convert_idea_to_task',
|
|
1535
|
+
description: `Convert an idea to a task. Creates a task from the idea's title and description, links them, and optionally updates the idea status to 'in_development'. Useful for planned ideas that are ready for implementation.`,
|
|
1536
|
+
inputSchema: {
|
|
1537
|
+
type: 'object',
|
|
1538
|
+
properties: {
|
|
1539
|
+
idea_id: {
|
|
1540
|
+
type: 'string',
|
|
1541
|
+
description: 'Idea UUID to convert',
|
|
1542
|
+
},
|
|
1543
|
+
priority: {
|
|
1544
|
+
type: 'number',
|
|
1545
|
+
minimum: 1,
|
|
1546
|
+
maximum: 5,
|
|
1547
|
+
description: 'Task priority 1-5 (default: 3, 1 = highest)',
|
|
1548
|
+
},
|
|
1549
|
+
estimated_minutes: {
|
|
1550
|
+
type: 'number',
|
|
1551
|
+
minimum: 1,
|
|
1552
|
+
description: 'Estimated time to complete in minutes',
|
|
1553
|
+
},
|
|
1554
|
+
update_status: {
|
|
1555
|
+
type: 'boolean',
|
|
1556
|
+
description: "Update idea status to 'in_development' (default: true)",
|
|
1557
|
+
},
|
|
1558
|
+
},
|
|
1559
|
+
required: ['idea_id'],
|
|
1560
|
+
},
|
|
1561
|
+
},
|
|
1562
|
+
// Findings (knowledge base)
|
|
1563
|
+
{
|
|
1564
|
+
name: 'add_finding',
|
|
1565
|
+
description: 'Record a finding from an audit/review (performance, security, code quality, etc).',
|
|
1566
|
+
inputSchema: {
|
|
1567
|
+
type: 'object',
|
|
1568
|
+
properties: {
|
|
1569
|
+
project_id: { type: 'string', description: 'Project UUID' },
|
|
1570
|
+
category: { type: 'string', enum: ['performance', 'security', 'code_quality', 'accessibility', 'documentation', 'architecture', 'testing', 'other'], description: 'Category of the finding (default: other)' },
|
|
1571
|
+
title: { type: 'string', description: 'Brief title describing the finding' },
|
|
1572
|
+
description: { type: 'string', description: 'Detailed description of the finding, including impact and suggested fix' },
|
|
1573
|
+
severity: { type: 'string', enum: ['info', 'low', 'medium', 'high', 'critical'], description: 'Severity level (default: info)' },
|
|
1574
|
+
file_path: { type: 'string', description: 'File path where the issue was found (optional)' },
|
|
1575
|
+
line_number: { type: 'number', description: 'Line number in the file (optional)' },
|
|
1576
|
+
related_task_id: { type: 'string', description: 'ID of related task if this finding came from a task (optional)' },
|
|
1577
|
+
},
|
|
1578
|
+
required: ['project_id', 'title'],
|
|
1579
|
+
},
|
|
1580
|
+
},
|
|
1581
|
+
{
|
|
1582
|
+
name: 'get_findings',
|
|
1583
|
+
description: `Get findings for a project, optionally filtered by category, severity, or status.`,
|
|
1584
|
+
inputSchema: {
|
|
1585
|
+
type: 'object',
|
|
1586
|
+
properties: {
|
|
1587
|
+
project_id: { type: 'string', description: 'Project UUID' },
|
|
1588
|
+
category: { type: 'string', enum: ['performance', 'security', 'code_quality', 'accessibility', 'documentation', 'architecture', 'testing', 'other'], description: 'Filter by category (optional)' },
|
|
1589
|
+
severity: { type: 'string', enum: ['info', 'low', 'medium', 'high', 'critical'], description: 'Filter by severity (optional)' },
|
|
1590
|
+
status: { type: 'string', enum: ['open', 'addressed', 'dismissed', 'wontfix'], description: 'Filter by status (default: all)' },
|
|
1591
|
+
limit: { type: 'number', description: 'Max number of findings to return (default 50)' },
|
|
1592
|
+
},
|
|
1593
|
+
required: ['project_id'],
|
|
1594
|
+
},
|
|
1595
|
+
},
|
|
1596
|
+
{
|
|
1597
|
+
name: 'update_finding',
|
|
1598
|
+
description: `Update a finding's status or details. Use to mark findings as addressed or dismissed.`,
|
|
1599
|
+
inputSchema: {
|
|
1600
|
+
type: 'object',
|
|
1601
|
+
properties: {
|
|
1602
|
+
finding_id: { type: 'string', description: 'Finding UUID' },
|
|
1603
|
+
status: { type: 'string', enum: ['open', 'addressed', 'dismissed', 'wontfix'], description: 'New status' },
|
|
1604
|
+
resolution_note: { type: 'string', description: 'Note explaining how the finding was addressed or why it was dismissed' },
|
|
1605
|
+
title: { type: 'string', description: 'Updated title' },
|
|
1606
|
+
description: { type: 'string', description: 'Updated description' },
|
|
1607
|
+
severity: { type: 'string', enum: ['info', 'low', 'medium', 'high', 'critical'], description: 'Updated severity' },
|
|
1608
|
+
},
|
|
1609
|
+
required: ['finding_id'],
|
|
1610
|
+
},
|
|
1611
|
+
},
|
|
1612
|
+
{
|
|
1613
|
+
name: 'delete_finding',
|
|
1614
|
+
description: `Delete a finding.`,
|
|
1615
|
+
inputSchema: {
|
|
1616
|
+
type: 'object',
|
|
1617
|
+
properties: {
|
|
1618
|
+
finding_id: { type: 'string', description: 'Finding UUID' },
|
|
1619
|
+
},
|
|
1620
|
+
required: ['finding_id'],
|
|
1621
|
+
},
|
|
1622
|
+
},
|
|
1623
|
+
{
|
|
1624
|
+
name: 'delete_blocker',
|
|
1625
|
+
description: `Delete a blocker.`,
|
|
1626
|
+
inputSchema: {
|
|
1627
|
+
type: 'object',
|
|
1628
|
+
properties: {
|
|
1629
|
+
blocker_id: {
|
|
1630
|
+
type: 'string',
|
|
1631
|
+
description: 'Blocker UUID',
|
|
1632
|
+
},
|
|
1633
|
+
},
|
|
1634
|
+
required: ['blocker_id'],
|
|
1635
|
+
},
|
|
1636
|
+
},
|
|
1637
|
+
{
|
|
1638
|
+
name: 'delete_decision',
|
|
1639
|
+
description: `Delete a decision.`,
|
|
1640
|
+
inputSchema: {
|
|
1641
|
+
type: 'object',
|
|
1642
|
+
properties: {
|
|
1643
|
+
decision_id: {
|
|
1644
|
+
type: 'string',
|
|
1645
|
+
description: 'Decision UUID',
|
|
1646
|
+
},
|
|
1647
|
+
},
|
|
1648
|
+
required: ['decision_id'],
|
|
1649
|
+
},
|
|
1650
|
+
},
|
|
1651
|
+
{
|
|
1652
|
+
name: 'get_activity_feed',
|
|
1653
|
+
description: `Get combined activity feed (tasks, progress, blockers, decisions) in chronological order.`,
|
|
1654
|
+
inputSchema: {
|
|
1655
|
+
type: 'object',
|
|
1656
|
+
properties: {
|
|
1657
|
+
project_id: {
|
|
1658
|
+
type: 'string',
|
|
1659
|
+
description: 'Project UUID',
|
|
1660
|
+
},
|
|
1661
|
+
types: {
|
|
1662
|
+
type: 'array',
|
|
1663
|
+
items: {
|
|
1664
|
+
type: 'string',
|
|
1665
|
+
enum: ['task', 'progress', 'blocker', 'decision'],
|
|
1666
|
+
},
|
|
1667
|
+
description: 'Filter by activity types (default: all)',
|
|
1668
|
+
},
|
|
1669
|
+
created_by: {
|
|
1670
|
+
type: 'string',
|
|
1671
|
+
enum: ['agent', 'user'],
|
|
1672
|
+
description: 'Filter by creator (default: all)',
|
|
1673
|
+
},
|
|
1674
|
+
since: {
|
|
1675
|
+
type: 'string',
|
|
1676
|
+
description: 'ISO date string - only return activity after this time',
|
|
1677
|
+
},
|
|
1678
|
+
limit: {
|
|
1679
|
+
type: 'number',
|
|
1680
|
+
description: 'Max number of items to return (default 50, max 200)',
|
|
1681
|
+
},
|
|
1682
|
+
},
|
|
1683
|
+
required: ['project_id'],
|
|
1684
|
+
},
|
|
1685
|
+
},
|
|
1686
|
+
{
|
|
1687
|
+
name: 'batch_update_tasks',
|
|
1688
|
+
description: 'Update multiple tasks at once. Include progress_note with progress_percentage.',
|
|
1689
|
+
inputSchema: {
|
|
1690
|
+
type: 'object',
|
|
1691
|
+
properties: {
|
|
1692
|
+
updates: {
|
|
1693
|
+
type: 'array',
|
|
1694
|
+
description: 'Array of task updates to apply',
|
|
1695
|
+
items: {
|
|
1696
|
+
type: 'object',
|
|
1697
|
+
properties: {
|
|
1698
|
+
task_id: { type: 'string', description: 'Task UUID' },
|
|
1699
|
+
status: { type: 'string', enum: ['backlog', 'pending', 'in_progress', 'completed', 'cancelled'] },
|
|
1700
|
+
progress_percentage: { type: 'number', minimum: 0, maximum: 100 },
|
|
1701
|
+
progress_note: { type: 'string', description: 'Brief note about what was achieved' },
|
|
1702
|
+
priority: { type: 'number', minimum: 1, maximum: 5 },
|
|
1703
|
+
},
|
|
1704
|
+
required: ['task_id'],
|
|
1705
|
+
},
|
|
1706
|
+
},
|
|
1707
|
+
},
|
|
1708
|
+
required: ['updates'],
|
|
1709
|
+
},
|
|
1710
|
+
},
|
|
1711
|
+
{
|
|
1712
|
+
name: 'batch_complete_tasks',
|
|
1713
|
+
description: `Mark multiple tasks as completed at once.`,
|
|
1714
|
+
inputSchema: {
|
|
1715
|
+
type: 'object',
|
|
1716
|
+
properties: {
|
|
1717
|
+
completions: {
|
|
1718
|
+
type: 'array',
|
|
1719
|
+
description: 'Array of task completions',
|
|
1720
|
+
items: {
|
|
1721
|
+
type: 'object',
|
|
1722
|
+
properties: {
|
|
1723
|
+
task_id: { type: 'string', description: 'Task UUID' },
|
|
1724
|
+
summary: { type: 'string', description: 'Optional completion summary' },
|
|
1725
|
+
},
|
|
1726
|
+
required: ['task_id'],
|
|
1727
|
+
},
|
|
1728
|
+
},
|
|
1729
|
+
},
|
|
1730
|
+
required: ['completions'],
|
|
1731
|
+
},
|
|
1732
|
+
},
|
|
1733
|
+
// =========================================================================
|
|
1734
|
+
// Subtask Tools
|
|
1735
|
+
// =========================================================================
|
|
1736
|
+
{
|
|
1737
|
+
name: 'add_subtask',
|
|
1738
|
+
description: `Add a subtask to break down a larger task into smaller workable pieces.
|
|
1739
|
+
Subtasks can be claimed and worked on independently by any agent.
|
|
1740
|
+
Subtasks inherit the project from their parent task.
|
|
1741
|
+
Max depth is 1 (subtasks cannot have their own subtasks).`,
|
|
1742
|
+
inputSchema: {
|
|
1743
|
+
type: 'object',
|
|
1744
|
+
properties: {
|
|
1745
|
+
parent_task_id: {
|
|
1746
|
+
type: 'string',
|
|
1747
|
+
description: 'UUID of the parent task to add subtask to',
|
|
1748
|
+
},
|
|
1749
|
+
title: {
|
|
1750
|
+
type: 'string',
|
|
1751
|
+
description: 'Subtask title',
|
|
1752
|
+
},
|
|
1753
|
+
description: {
|
|
1754
|
+
type: 'string',
|
|
1755
|
+
description: 'Detailed description (optional)',
|
|
1756
|
+
},
|
|
1757
|
+
priority: {
|
|
1758
|
+
type: 'number',
|
|
1759
|
+
minimum: 1,
|
|
1760
|
+
maximum: 5,
|
|
1761
|
+
description: 'Priority 1-5 (1 = highest). Defaults to parent task priority.',
|
|
1762
|
+
},
|
|
1763
|
+
estimated_minutes: {
|
|
1764
|
+
type: 'number',
|
|
1765
|
+
minimum: 1,
|
|
1766
|
+
description: 'Estimated time to complete in minutes',
|
|
1767
|
+
},
|
|
1768
|
+
},
|
|
1769
|
+
required: ['parent_task_id', 'title'],
|
|
1770
|
+
},
|
|
1771
|
+
},
|
|
1772
|
+
{
|
|
1773
|
+
name: 'get_subtasks',
|
|
1774
|
+
description: `Get subtasks for a parent task.
|
|
1775
|
+
Returns subtasks with aggregate completion stats.`,
|
|
1776
|
+
inputSchema: {
|
|
1777
|
+
type: 'object',
|
|
1778
|
+
properties: {
|
|
1779
|
+
parent_task_id: {
|
|
1780
|
+
type: 'string',
|
|
1781
|
+
description: 'UUID of the parent task',
|
|
1782
|
+
},
|
|
1783
|
+
status: {
|
|
1784
|
+
type: 'string',
|
|
1785
|
+
enum: ['backlog', 'pending', 'in_progress', 'completed', 'cancelled'],
|
|
1786
|
+
description: 'Filter by status (optional)',
|
|
1787
|
+
},
|
|
1788
|
+
},
|
|
1789
|
+
required: ['parent_task_id'],
|
|
1790
|
+
},
|
|
1791
|
+
},
|
|
1792
|
+
{
|
|
1793
|
+
name: 'heartbeat',
|
|
1794
|
+
description: `Send heartbeat to maintain 'active' status. Call every 30-60 seconds.`,
|
|
1795
|
+
inputSchema: {
|
|
1796
|
+
type: 'object',
|
|
1797
|
+
properties: {
|
|
1798
|
+
session_id: {
|
|
1799
|
+
type: 'string',
|
|
1800
|
+
description: 'Session ID from start_work_session (optional, uses current session if not provided)',
|
|
1801
|
+
},
|
|
1802
|
+
},
|
|
1803
|
+
},
|
|
1804
|
+
},
|
|
1805
|
+
{
|
|
1806
|
+
name: 'end_work_session',
|
|
1807
|
+
description: `End session and release claimed tasks. Returns session summary.`,
|
|
1808
|
+
inputSchema: {
|
|
1809
|
+
type: 'object',
|
|
1810
|
+
properties: {
|
|
1811
|
+
session_id: {
|
|
1812
|
+
type: 'string',
|
|
1813
|
+
description: 'Session ID to end (optional, uses current session if not provided)',
|
|
1814
|
+
},
|
|
1815
|
+
},
|
|
1816
|
+
},
|
|
1817
|
+
},
|
|
1818
|
+
// =========================================================================
|
|
1819
|
+
// Task Validation Tools
|
|
1820
|
+
// =========================================================================
|
|
1821
|
+
{
|
|
1822
|
+
name: 'get_tasks_awaiting_validation',
|
|
1823
|
+
description: `Get completed tasks not yet validated.`,
|
|
1824
|
+
inputSchema: {
|
|
1825
|
+
type: 'object',
|
|
1826
|
+
properties: {
|
|
1827
|
+
project_id: {
|
|
1828
|
+
type: 'string',
|
|
1829
|
+
description: 'Project UUID',
|
|
1830
|
+
},
|
|
1831
|
+
},
|
|
1832
|
+
required: ['project_id'],
|
|
1833
|
+
},
|
|
1834
|
+
},
|
|
1835
|
+
{
|
|
1836
|
+
name: 'claim_validation',
|
|
1837
|
+
description: 'Claim a completed task for review. Shows "being reviewed" on dashboard.',
|
|
1838
|
+
inputSchema: {
|
|
1839
|
+
type: 'object',
|
|
1840
|
+
properties: {
|
|
1841
|
+
task_id: {
|
|
1842
|
+
type: 'string',
|
|
1843
|
+
description: 'Task UUID to claim for review',
|
|
1844
|
+
},
|
|
1845
|
+
},
|
|
1846
|
+
required: ['task_id'],
|
|
1847
|
+
},
|
|
1848
|
+
},
|
|
1849
|
+
{
|
|
1850
|
+
name: 'validate_task',
|
|
1851
|
+
description: 'Validate a completed task. Include test results in validation_notes.',
|
|
1852
|
+
inputSchema: {
|
|
1853
|
+
type: 'object',
|
|
1854
|
+
properties: {
|
|
1855
|
+
task_id: {
|
|
1856
|
+
type: 'string',
|
|
1857
|
+
description: 'Task UUID to validate',
|
|
1858
|
+
},
|
|
1859
|
+
validation_notes: {
|
|
1860
|
+
type: 'string',
|
|
1861
|
+
description: 'Notes about the validation (what was checked, any issues found)',
|
|
1862
|
+
},
|
|
1863
|
+
approved: {
|
|
1864
|
+
type: 'boolean',
|
|
1865
|
+
description: 'Whether the task passes validation (true = approved, false = needs more work)',
|
|
1866
|
+
},
|
|
1867
|
+
},
|
|
1868
|
+
required: ['task_id', 'approved'],
|
|
1869
|
+
},
|
|
1870
|
+
},
|
|
1871
|
+
// =========================================================================
|
|
1872
|
+
// Deployment Coordination Tools
|
|
1873
|
+
// =========================================================================
|
|
1874
|
+
{
|
|
1875
|
+
name: 'request_deployment',
|
|
1876
|
+
description: 'Request a deployment. Requires validation first. One active deployment per project.',
|
|
1877
|
+
inputSchema: {
|
|
1878
|
+
type: 'object',
|
|
1879
|
+
properties: {
|
|
1880
|
+
project_id: {
|
|
1881
|
+
type: 'string',
|
|
1882
|
+
description: 'Project UUID',
|
|
1883
|
+
},
|
|
1884
|
+
environment: {
|
|
1885
|
+
type: 'string',
|
|
1886
|
+
enum: ['development', 'staging', 'production'],
|
|
1887
|
+
description: 'Target environment (default: production)',
|
|
1888
|
+
},
|
|
1889
|
+
version_bump: {
|
|
1890
|
+
type: 'string',
|
|
1891
|
+
enum: ['patch', 'minor', 'major'],
|
|
1892
|
+
description: 'Version bump: major/minor/patch (default: patch)',
|
|
1893
|
+
},
|
|
1894
|
+
notes: {
|
|
1895
|
+
type: 'string',
|
|
1896
|
+
description: 'Optional notes about this deployment',
|
|
1897
|
+
},
|
|
1898
|
+
git_ref: {
|
|
1899
|
+
type: 'string',
|
|
1900
|
+
description: 'Git branch or commit being deployed',
|
|
1901
|
+
},
|
|
1902
|
+
},
|
|
1903
|
+
required: ['project_id'],
|
|
1904
|
+
},
|
|
1905
|
+
},
|
|
1906
|
+
{
|
|
1907
|
+
name: 'claim_deployment_validation',
|
|
1908
|
+
description: `Claim pending deployment for validation. Run build+tests, then call report_validation.`,
|
|
1909
|
+
inputSchema: {
|
|
1910
|
+
type: 'object',
|
|
1911
|
+
properties: {
|
|
1912
|
+
project_id: {
|
|
1913
|
+
type: 'string',
|
|
1914
|
+
description: 'Project UUID',
|
|
1915
|
+
},
|
|
1916
|
+
},
|
|
1917
|
+
required: ['project_id'],
|
|
1918
|
+
},
|
|
1919
|
+
},
|
|
1920
|
+
{
|
|
1921
|
+
name: 'report_validation',
|
|
1922
|
+
description: `Report build/test results. If passed, status->'ready'. If failed, creates investigation task.`,
|
|
1923
|
+
inputSchema: {
|
|
1924
|
+
type: 'object',
|
|
1925
|
+
properties: {
|
|
1926
|
+
project_id: {
|
|
1927
|
+
type: 'string',
|
|
1928
|
+
description: 'Project UUID',
|
|
1929
|
+
},
|
|
1930
|
+
build_passed: {
|
|
1931
|
+
type: 'boolean',
|
|
1932
|
+
description: 'Whether the build succeeded',
|
|
1933
|
+
},
|
|
1934
|
+
tests_passed: {
|
|
1935
|
+
type: 'boolean',
|
|
1936
|
+
description: 'Whether the tests passed',
|
|
1937
|
+
},
|
|
1938
|
+
error_message: {
|
|
1939
|
+
type: 'string',
|
|
1940
|
+
description: 'Error details if validation failed',
|
|
1941
|
+
},
|
|
1942
|
+
},
|
|
1943
|
+
required: ['project_id', 'build_passed', 'tests_passed'],
|
|
1944
|
+
},
|
|
1945
|
+
},
|
|
1946
|
+
{
|
|
1947
|
+
name: 'check_deployment_status',
|
|
1948
|
+
description: `Get active deployment status and details.`,
|
|
1949
|
+
inputSchema: {
|
|
1950
|
+
type: 'object',
|
|
1951
|
+
properties: {
|
|
1952
|
+
project_id: {
|
|
1953
|
+
type: 'string',
|
|
1954
|
+
description: 'Project UUID',
|
|
1955
|
+
},
|
|
1956
|
+
},
|
|
1957
|
+
required: ['project_id'],
|
|
1958
|
+
},
|
|
1959
|
+
},
|
|
1960
|
+
{
|
|
1961
|
+
name: 'start_deployment',
|
|
1962
|
+
description: `Start deployment (requires 'ready' status). Sets status to 'deploying'.`,
|
|
1963
|
+
inputSchema: {
|
|
1964
|
+
type: 'object',
|
|
1965
|
+
properties: {
|
|
1966
|
+
project_id: {
|
|
1967
|
+
type: 'string',
|
|
1968
|
+
description: 'Project UUID',
|
|
1969
|
+
},
|
|
1970
|
+
},
|
|
1971
|
+
required: ['project_id'],
|
|
1972
|
+
},
|
|
1973
|
+
},
|
|
1974
|
+
{
|
|
1975
|
+
name: 'complete_deployment',
|
|
1976
|
+
description: `Mark deployment as complete (success or failure).`,
|
|
1977
|
+
inputSchema: {
|
|
1978
|
+
type: 'object',
|
|
1979
|
+
properties: {
|
|
1980
|
+
project_id: {
|
|
1981
|
+
type: 'string',
|
|
1982
|
+
description: 'Project UUID',
|
|
1983
|
+
},
|
|
1984
|
+
success: {
|
|
1985
|
+
type: 'boolean',
|
|
1986
|
+
description: 'Whether the deployment succeeded',
|
|
1987
|
+
},
|
|
1988
|
+
summary: {
|
|
1989
|
+
type: 'string',
|
|
1990
|
+
description: 'Summary of what was deployed or why it failed',
|
|
1991
|
+
},
|
|
1992
|
+
},
|
|
1993
|
+
required: ['project_id', 'success'],
|
|
1994
|
+
},
|
|
1995
|
+
},
|
|
1996
|
+
{
|
|
1997
|
+
name: 'cancel_deployment',
|
|
1998
|
+
description: `Cancel active deployment. Sets status to 'failed'.`,
|
|
1999
|
+
inputSchema: {
|
|
2000
|
+
type: 'object',
|
|
2001
|
+
properties: {
|
|
2002
|
+
project_id: {
|
|
2003
|
+
type: 'string',
|
|
2004
|
+
description: 'Project UUID',
|
|
2005
|
+
},
|
|
2006
|
+
reason: {
|
|
2007
|
+
type: 'string',
|
|
2008
|
+
description: 'Reason for cancellation',
|
|
2009
|
+
},
|
|
2010
|
+
},
|
|
2011
|
+
required: ['project_id'],
|
|
2012
|
+
},
|
|
2013
|
+
},
|
|
2014
|
+
{
|
|
2015
|
+
name: 'add_deployment_requirement',
|
|
2016
|
+
description: `Add a pre-deployment requirement (migration, env var, config change). These are shown as a checklist before deployment.`,
|
|
2017
|
+
inputSchema: {
|
|
2018
|
+
type: 'object',
|
|
2019
|
+
properties: {
|
|
2020
|
+
project_id: {
|
|
2021
|
+
type: 'string',
|
|
2022
|
+
description: 'Project UUID',
|
|
2023
|
+
},
|
|
2024
|
+
type: {
|
|
2025
|
+
type: 'string',
|
|
2026
|
+
description: 'Type of requirement',
|
|
2027
|
+
enum: ['migration', 'env_var', 'config', 'manual', 'breaking_change', 'agent_task'],
|
|
2028
|
+
},
|
|
2029
|
+
title: {
|
|
2030
|
+
type: 'string',
|
|
2031
|
+
description: 'Brief description (e.g., "Run migration: 20250114_token_tracking.sql")',
|
|
2032
|
+
},
|
|
2033
|
+
description: {
|
|
2034
|
+
type: 'string',
|
|
2035
|
+
description: 'Optional detailed instructions',
|
|
2036
|
+
},
|
|
2037
|
+
file_path: {
|
|
2038
|
+
type: 'string',
|
|
2039
|
+
description: 'Optional file path reference',
|
|
2040
|
+
},
|
|
2041
|
+
stage: {
|
|
2042
|
+
type: 'string',
|
|
2043
|
+
description: 'Deployment stage: preparation (default), deployment, or verification',
|
|
2044
|
+
enum: ['preparation', 'deployment', 'verification'],
|
|
2045
|
+
},
|
|
2046
|
+
blocking: {
|
|
2047
|
+
type: 'boolean',
|
|
2048
|
+
description: 'When true, converted task blocks all other work until complete',
|
|
2049
|
+
},
|
|
2050
|
+
},
|
|
2051
|
+
required: ['project_id', 'type', 'title'],
|
|
2052
|
+
},
|
|
2053
|
+
},
|
|
2054
|
+
{
|
|
2055
|
+
name: 'complete_deployment_requirement',
|
|
2056
|
+
description: `Mark a deployment requirement as completed.`,
|
|
2057
|
+
inputSchema: {
|
|
2058
|
+
type: 'object',
|
|
2059
|
+
properties: {
|
|
2060
|
+
requirement_id: {
|
|
2061
|
+
type: 'string',
|
|
2062
|
+
description: 'Requirement UUID',
|
|
2063
|
+
},
|
|
2064
|
+
},
|
|
2065
|
+
required: ['requirement_id'],
|
|
2066
|
+
},
|
|
2067
|
+
},
|
|
2068
|
+
{
|
|
2069
|
+
name: 'get_deployment_requirements',
|
|
2070
|
+
description: `Get pending deployment requirements for a project.`,
|
|
2071
|
+
inputSchema: {
|
|
2072
|
+
type: 'object',
|
|
2073
|
+
properties: {
|
|
2074
|
+
project_id: {
|
|
2075
|
+
type: 'string',
|
|
2076
|
+
description: 'Project UUID',
|
|
2077
|
+
},
|
|
2078
|
+
status: {
|
|
2079
|
+
type: 'string',
|
|
2080
|
+
description: 'Filter by status (default: pending)',
|
|
2081
|
+
enum: ['pending', 'completed', 'converted_to_task', 'all'],
|
|
2082
|
+
},
|
|
2083
|
+
stage: {
|
|
2084
|
+
type: 'string',
|
|
2085
|
+
description: 'Filter by stage (optional)',
|
|
2086
|
+
enum: ['preparation', 'deployment', 'verification', 'all'],
|
|
2087
|
+
},
|
|
2088
|
+
},
|
|
2089
|
+
required: ['project_id'],
|
|
2090
|
+
},
|
|
2091
|
+
},
|
|
2092
|
+
{
|
|
2093
|
+
name: 'schedule_deployment',
|
|
2094
|
+
description: `Schedule a deployment for a specific time. Supports one-time and recurring schedules with auto-trigger or manual trigger modes.`,
|
|
2095
|
+
inputSchema: {
|
|
2096
|
+
type: 'object',
|
|
2097
|
+
properties: {
|
|
2098
|
+
project_id: {
|
|
2099
|
+
type: 'string',
|
|
2100
|
+
description: 'Project UUID',
|
|
2101
|
+
},
|
|
2102
|
+
scheduled_at: {
|
|
2103
|
+
type: 'string',
|
|
2104
|
+
description: 'ISO 8601 datetime for when the deployment should be triggered',
|
|
2105
|
+
},
|
|
2106
|
+
schedule_type: {
|
|
2107
|
+
type: 'string',
|
|
2108
|
+
description: 'Schedule type: once (one-time), daily, weekly, or monthly',
|
|
2109
|
+
enum: ['once', 'daily', 'weekly', 'monthly'],
|
|
2110
|
+
},
|
|
2111
|
+
auto_trigger: {
|
|
2112
|
+
type: 'boolean',
|
|
2113
|
+
description: 'Whether agents should automatically trigger this deployment when due (default: true)',
|
|
2114
|
+
},
|
|
2115
|
+
environment: {
|
|
2116
|
+
type: 'string',
|
|
2117
|
+
description: 'Target environment (default: production)',
|
|
2118
|
+
enum: ['development', 'staging', 'production'],
|
|
2119
|
+
},
|
|
2120
|
+
version_bump: {
|
|
2121
|
+
type: 'string',
|
|
2122
|
+
description: 'Version bump: patch, minor, or major (default: patch)',
|
|
2123
|
+
enum: ['patch', 'minor', 'major'],
|
|
2124
|
+
},
|
|
2125
|
+
notes: {
|
|
2126
|
+
type: 'string',
|
|
2127
|
+
description: 'Optional notes about this scheduled deployment',
|
|
2128
|
+
},
|
|
2129
|
+
git_ref: {
|
|
2130
|
+
type: 'string',
|
|
2131
|
+
description: 'Optional git branch or commit to deploy',
|
|
2132
|
+
},
|
|
2133
|
+
},
|
|
2134
|
+
required: ['project_id', 'scheduled_at'],
|
|
2135
|
+
},
|
|
2136
|
+
},
|
|
2137
|
+
{
|
|
2138
|
+
name: 'get_scheduled_deployments',
|
|
2139
|
+
description: `Get scheduled deployments for a project.`,
|
|
2140
|
+
inputSchema: {
|
|
2141
|
+
type: 'object',
|
|
2142
|
+
properties: {
|
|
2143
|
+
project_id: {
|
|
2144
|
+
type: 'string',
|
|
2145
|
+
description: 'Project UUID',
|
|
2146
|
+
},
|
|
2147
|
+
include_disabled: {
|
|
2148
|
+
type: 'boolean',
|
|
2149
|
+
description: 'Include disabled schedules (default: false)',
|
|
2150
|
+
},
|
|
2151
|
+
},
|
|
2152
|
+
required: ['project_id'],
|
|
2153
|
+
},
|
|
2154
|
+
},
|
|
2155
|
+
{
|
|
2156
|
+
name: 'update_scheduled_deployment',
|
|
2157
|
+
description: `Update a scheduled deployment's configuration.`,
|
|
2158
|
+
inputSchema: {
|
|
2159
|
+
type: 'object',
|
|
2160
|
+
properties: {
|
|
2161
|
+
schedule_id: {
|
|
2162
|
+
type: 'string',
|
|
2163
|
+
description: 'Schedule UUID',
|
|
2164
|
+
},
|
|
2165
|
+
scheduled_at: {
|
|
2166
|
+
type: 'string',
|
|
2167
|
+
description: 'New scheduled time (ISO 8601)',
|
|
2168
|
+
},
|
|
2169
|
+
schedule_type: {
|
|
2170
|
+
type: 'string',
|
|
2171
|
+
description: 'New schedule type',
|
|
2172
|
+
enum: ['once', 'daily', 'weekly', 'monthly'],
|
|
2173
|
+
},
|
|
2174
|
+
auto_trigger: {
|
|
2175
|
+
type: 'boolean',
|
|
2176
|
+
description: 'Whether to auto-trigger',
|
|
2177
|
+
},
|
|
2178
|
+
enabled: {
|
|
2179
|
+
type: 'boolean',
|
|
2180
|
+
description: 'Enable or disable the schedule',
|
|
2181
|
+
},
|
|
2182
|
+
environment: {
|
|
2183
|
+
type: 'string',
|
|
2184
|
+
description: 'Target environment',
|
|
2185
|
+
enum: ['development', 'staging', 'production'],
|
|
2186
|
+
},
|
|
2187
|
+
version_bump: {
|
|
2188
|
+
type: 'string',
|
|
2189
|
+
description: 'Version bump type',
|
|
2190
|
+
enum: ['patch', 'minor', 'major'],
|
|
2191
|
+
},
|
|
2192
|
+
notes: {
|
|
2193
|
+
type: 'string',
|
|
2194
|
+
description: 'Notes about this deployment',
|
|
2195
|
+
},
|
|
2196
|
+
git_ref: {
|
|
2197
|
+
type: 'string',
|
|
2198
|
+
description: 'Git branch or commit to deploy',
|
|
2199
|
+
},
|
|
2200
|
+
},
|
|
2201
|
+
required: ['schedule_id'],
|
|
2202
|
+
},
|
|
2203
|
+
},
|
|
2204
|
+
{
|
|
2205
|
+
name: 'delete_scheduled_deployment',
|
|
2206
|
+
description: `Delete a scheduled deployment.`,
|
|
2207
|
+
inputSchema: {
|
|
2208
|
+
type: 'object',
|
|
2209
|
+
properties: {
|
|
2210
|
+
schedule_id: {
|
|
2211
|
+
type: 'string',
|
|
2212
|
+
description: 'Schedule UUID',
|
|
2213
|
+
},
|
|
2214
|
+
},
|
|
2215
|
+
required: ['schedule_id'],
|
|
2216
|
+
},
|
|
2217
|
+
},
|
|
2218
|
+
{
|
|
2219
|
+
name: 'trigger_scheduled_deployment',
|
|
2220
|
+
description: `Manually trigger a scheduled deployment. Creates a new deployment and updates the schedule.`,
|
|
2221
|
+
inputSchema: {
|
|
2222
|
+
type: 'object',
|
|
2223
|
+
properties: {
|
|
2224
|
+
schedule_id: {
|
|
2225
|
+
type: 'string',
|
|
2226
|
+
description: 'Schedule UUID',
|
|
2227
|
+
},
|
|
2228
|
+
},
|
|
2229
|
+
required: ['schedule_id'],
|
|
2230
|
+
},
|
|
2231
|
+
},
|
|
2232
|
+
{
|
|
2233
|
+
name: 'check_due_deployments',
|
|
2234
|
+
description: `Check for scheduled deployments that are due. Returns schedules where: enabled AND auto_trigger AND scheduled_at <= NOW().`,
|
|
2235
|
+
inputSchema: {
|
|
2236
|
+
type: 'object',
|
|
2237
|
+
properties: {
|
|
2238
|
+
project_id: {
|
|
2239
|
+
type: 'string',
|
|
2240
|
+
description: 'Project UUID',
|
|
2241
|
+
},
|
|
2242
|
+
},
|
|
2243
|
+
required: ['project_id'],
|
|
2244
|
+
},
|
|
2245
|
+
},
|
|
2246
|
+
{
|
|
2247
|
+
name: 'start_fallback_activity',
|
|
2248
|
+
description: `Start a background activity when no tasks available.`,
|
|
2249
|
+
inputSchema: {
|
|
2250
|
+
type: 'object',
|
|
2251
|
+
properties: {
|
|
2252
|
+
project_id: {
|
|
2253
|
+
type: 'string',
|
|
2254
|
+
description: 'Project UUID',
|
|
2255
|
+
},
|
|
2256
|
+
activity: {
|
|
2257
|
+
type: 'string',
|
|
2258
|
+
description: 'The fallback activity type (e.g., code_review, security_review)',
|
|
2259
|
+
enum: [
|
|
2260
|
+
'feature_ideation',
|
|
2261
|
+
'code_review',
|
|
2262
|
+
'performance_audit',
|
|
2263
|
+
'ux_review',
|
|
2264
|
+
'cost_analysis',
|
|
2265
|
+
'security_review',
|
|
2266
|
+
'test_coverage',
|
|
2267
|
+
'documentation_review',
|
|
2268
|
+
'dependency_audit',
|
|
2269
|
+
'validate_completed_tasks',
|
|
2270
|
+
],
|
|
2271
|
+
},
|
|
2272
|
+
},
|
|
2273
|
+
required: ['project_id', 'activity'],
|
|
2274
|
+
},
|
|
2275
|
+
},
|
|
2276
|
+
{
|
|
2277
|
+
name: 'stop_fallback_activity',
|
|
2278
|
+
description: `Stop current fallback activity. Auto-clears when starting a regular task.`,
|
|
2279
|
+
inputSchema: {
|
|
2280
|
+
type: 'object',
|
|
2281
|
+
properties: {
|
|
2282
|
+
project_id: {
|
|
2283
|
+
type: 'string',
|
|
2284
|
+
description: 'Project UUID',
|
|
2285
|
+
},
|
|
2286
|
+
summary: {
|
|
2287
|
+
type: 'string',
|
|
2288
|
+
description: 'Optional summary of what was accomplished during this activity',
|
|
2289
|
+
},
|
|
2290
|
+
},
|
|
2291
|
+
required: ['project_id'],
|
|
2292
|
+
},
|
|
2293
|
+
},
|
|
2294
|
+
{
|
|
2295
|
+
name: 'get_activity_history',
|
|
2296
|
+
description: `Get background activity completion history.`,
|
|
2297
|
+
inputSchema: {
|
|
2298
|
+
type: 'object',
|
|
2299
|
+
properties: {
|
|
2300
|
+
project_id: {
|
|
2301
|
+
type: 'string',
|
|
2302
|
+
description: 'Project UUID',
|
|
2303
|
+
},
|
|
2304
|
+
activity_type: {
|
|
2305
|
+
type: 'string',
|
|
2306
|
+
description: 'Optional: filter to a specific activity type',
|
|
2307
|
+
},
|
|
2308
|
+
limit: {
|
|
2309
|
+
type: 'number',
|
|
2310
|
+
description: 'Max number of history entries to return (default 50)',
|
|
2311
|
+
},
|
|
2312
|
+
},
|
|
2313
|
+
required: ['project_id'],
|
|
2314
|
+
},
|
|
2315
|
+
},
|
|
2316
|
+
{
|
|
2317
|
+
name: 'get_activity_schedules',
|
|
2318
|
+
description: `Get background activity schedules.`,
|
|
2319
|
+
inputSchema: {
|
|
2320
|
+
type: 'object',
|
|
2321
|
+
properties: {
|
|
2322
|
+
project_id: {
|
|
2323
|
+
type: 'string',
|
|
2324
|
+
description: 'Project UUID',
|
|
2325
|
+
},
|
|
2326
|
+
},
|
|
2327
|
+
required: ['project_id'],
|
|
2328
|
+
},
|
|
2329
|
+
},
|
|
2330
|
+
// =========================================================================
|
|
2331
|
+
// Agent Request Tools
|
|
2332
|
+
// =========================================================================
|
|
2333
|
+
{
|
|
2334
|
+
name: 'get_pending_requests',
|
|
2335
|
+
description: `Get unacknowledged user requests for this agent/project.`,
|
|
2336
|
+
inputSchema: {
|
|
2337
|
+
type: 'object',
|
|
2338
|
+
properties: {
|
|
2339
|
+
project_id: {
|
|
2340
|
+
type: 'string',
|
|
2341
|
+
description: 'Project UUID',
|
|
2342
|
+
},
|
|
2343
|
+
},
|
|
2344
|
+
required: ['project_id'],
|
|
2345
|
+
},
|
|
2346
|
+
},
|
|
2347
|
+
{
|
|
2348
|
+
name: 'acknowledge_request',
|
|
2349
|
+
description: `Mark a user request as handled.`,
|
|
2350
|
+
inputSchema: {
|
|
2351
|
+
type: 'object',
|
|
2352
|
+
properties: {
|
|
2353
|
+
request_id: {
|
|
2354
|
+
type: 'string',
|
|
2355
|
+
description: 'Request UUID to acknowledge',
|
|
2356
|
+
},
|
|
2357
|
+
},
|
|
2358
|
+
required: ['request_id'],
|
|
2359
|
+
},
|
|
2360
|
+
},
|
|
2361
|
+
{
|
|
2362
|
+
name: 'answer_question',
|
|
2363
|
+
description: `Answer a question from the user. Use this when the user has asked a question via the dashboard.
|
|
2364
|
+
The answer will be displayed to the user and the question marked as answered.`,
|
|
2365
|
+
inputSchema: {
|
|
2366
|
+
type: 'object',
|
|
2367
|
+
properties: {
|
|
2368
|
+
request_id: {
|
|
2369
|
+
type: 'string',
|
|
2370
|
+
description: 'Request UUID of the question to answer',
|
|
2371
|
+
},
|
|
2372
|
+
answer: {
|
|
2373
|
+
type: 'string',
|
|
2374
|
+
description: 'Your answer to the user\'s question',
|
|
2375
|
+
},
|
|
2376
|
+
},
|
|
2377
|
+
required: ['request_id', 'answer'],
|
|
2378
|
+
},
|
|
2379
|
+
},
|
|
2380
|
+
// ============================================================================
|
|
2381
|
+
// Milestone Tools
|
|
2382
|
+
// ============================================================================
|
|
2383
|
+
{
|
|
2384
|
+
name: 'add_milestone',
|
|
2385
|
+
description: `Add a milestone to a task.
|
|
2386
|
+
Milestones help break down large tasks into smaller trackable steps.
|
|
2387
|
+
Use this to show progress on complex tasks and help gauge completion.`,
|
|
2388
|
+
inputSchema: {
|
|
2389
|
+
type: 'object',
|
|
2390
|
+
properties: {
|
|
2391
|
+
task_id: {
|
|
2392
|
+
type: 'string',
|
|
2393
|
+
description: 'Task UUID to add milestone to',
|
|
2394
|
+
},
|
|
2395
|
+
title: {
|
|
2396
|
+
type: 'string',
|
|
2397
|
+
description: 'Milestone title (brief description of what needs to be done)',
|
|
2398
|
+
},
|
|
2399
|
+
description: {
|
|
2400
|
+
type: 'string',
|
|
2401
|
+
description: 'Optional detailed description',
|
|
2402
|
+
},
|
|
2403
|
+
order_index: {
|
|
2404
|
+
type: 'number',
|
|
2405
|
+
minimum: 0,
|
|
2406
|
+
description: 'Order of this milestone (0-based, defaults to end of list)',
|
|
2407
|
+
},
|
|
2408
|
+
},
|
|
2409
|
+
required: ['task_id', 'title'],
|
|
2410
|
+
},
|
|
2411
|
+
},
|
|
2412
|
+
{
|
|
2413
|
+
name: 'update_milestone',
|
|
2414
|
+
description: `Update a milestone's title, description, status, or order.`,
|
|
2415
|
+
inputSchema: {
|
|
2416
|
+
type: 'object',
|
|
2417
|
+
properties: {
|
|
2418
|
+
milestone_id: {
|
|
2419
|
+
type: 'string',
|
|
2420
|
+
description: 'Milestone UUID',
|
|
2421
|
+
},
|
|
2422
|
+
title: {
|
|
2423
|
+
type: 'string',
|
|
2424
|
+
description: 'Updated title',
|
|
2425
|
+
},
|
|
2426
|
+
description: {
|
|
2427
|
+
type: 'string',
|
|
2428
|
+
description: 'Updated description',
|
|
2429
|
+
},
|
|
2430
|
+
status: {
|
|
2431
|
+
type: 'string',
|
|
2432
|
+
enum: ['pending', 'in_progress', 'completed'],
|
|
2433
|
+
description: 'Milestone status',
|
|
2434
|
+
},
|
|
2435
|
+
order_index: {
|
|
2436
|
+
type: 'number',
|
|
2437
|
+
minimum: 0,
|
|
2438
|
+
description: 'Updated order',
|
|
2439
|
+
},
|
|
2440
|
+
},
|
|
2441
|
+
required: ['milestone_id'],
|
|
2442
|
+
},
|
|
2443
|
+
},
|
|
2444
|
+
{
|
|
2445
|
+
name: 'complete_milestone',
|
|
2446
|
+
description: `Mark a milestone as completed. This is a convenience wrapper for update_milestone with status=completed.`,
|
|
2447
|
+
inputSchema: {
|
|
2448
|
+
type: 'object',
|
|
2449
|
+
properties: {
|
|
2450
|
+
milestone_id: {
|
|
2451
|
+
type: 'string',
|
|
2452
|
+
description: 'Milestone UUID',
|
|
2453
|
+
},
|
|
2454
|
+
},
|
|
2455
|
+
required: ['milestone_id'],
|
|
2456
|
+
},
|
|
2457
|
+
},
|
|
2458
|
+
{
|
|
2459
|
+
name: 'delete_milestone',
|
|
2460
|
+
description: `Delete a milestone from a task.`,
|
|
2461
|
+
inputSchema: {
|
|
2462
|
+
type: 'object',
|
|
2463
|
+
properties: {
|
|
2464
|
+
milestone_id: {
|
|
2465
|
+
type: 'string',
|
|
2466
|
+
description: 'Milestone UUID',
|
|
2467
|
+
},
|
|
2468
|
+
},
|
|
2469
|
+
required: ['milestone_id'],
|
|
2470
|
+
},
|
|
2471
|
+
},
|
|
2472
|
+
{
|
|
2473
|
+
name: 'get_milestones',
|
|
2474
|
+
description: `Get all milestones for a task, ordered by order_index.`,
|
|
2475
|
+
inputSchema: {
|
|
2476
|
+
type: 'object',
|
|
2477
|
+
properties: {
|
|
2478
|
+
task_id: {
|
|
2479
|
+
type: 'string',
|
|
2480
|
+
description: 'Task UUID',
|
|
2481
|
+
},
|
|
2482
|
+
},
|
|
2483
|
+
required: ['task_id'],
|
|
2484
|
+
},
|
|
2485
|
+
},
|
|
2486
|
+
// ============================================================================
|
|
2487
|
+
// Bodies of Work Tools
|
|
2488
|
+
// ============================================================================
|
|
2489
|
+
{
|
|
2490
|
+
name: 'create_body_of_work',
|
|
2491
|
+
description: `Create a new body of work to group tasks into phases (pre/core/post).
|
|
2492
|
+
Bodies of work allow organizing related tasks with optional auto-deployment on completion.`,
|
|
2493
|
+
inputSchema: {
|
|
2494
|
+
type: 'object',
|
|
2495
|
+
properties: {
|
|
2496
|
+
project_id: {
|
|
2497
|
+
type: 'string',
|
|
2498
|
+
description: 'Project UUID',
|
|
2499
|
+
},
|
|
2500
|
+
title: {
|
|
2501
|
+
type: 'string',
|
|
2502
|
+
description: 'Title for the body of work',
|
|
2503
|
+
},
|
|
2504
|
+
description: {
|
|
2505
|
+
type: 'string',
|
|
2506
|
+
description: 'Optional description',
|
|
2507
|
+
},
|
|
2508
|
+
auto_deploy_on_completion: {
|
|
2509
|
+
type: 'boolean',
|
|
2510
|
+
description: 'Automatically request deployment when all tasks complete (default: false)',
|
|
2511
|
+
},
|
|
2512
|
+
deploy_environment: {
|
|
2513
|
+
type: 'string',
|
|
2514
|
+
enum: ['development', 'staging', 'production'],
|
|
2515
|
+
description: 'Target environment for auto-deploy (default: production)',
|
|
2516
|
+
},
|
|
2517
|
+
deploy_version_bump: {
|
|
2518
|
+
type: 'string',
|
|
2519
|
+
enum: ['patch', 'minor', 'major'],
|
|
2520
|
+
description: 'Version bump for auto-deploy (default: minor)',
|
|
2521
|
+
},
|
|
2522
|
+
deploy_trigger: {
|
|
2523
|
+
type: 'string',
|
|
2524
|
+
enum: ['all_completed', 'all_completed_validated'],
|
|
2525
|
+
description: 'When to trigger auto-deploy: all_completed (immediate) or all_completed_validated (requires validation, default)',
|
|
2526
|
+
},
|
|
2527
|
+
},
|
|
2528
|
+
required: ['project_id', 'title'],
|
|
2529
|
+
},
|
|
2530
|
+
},
|
|
2531
|
+
{
|
|
2532
|
+
name: 'update_body_of_work',
|
|
2533
|
+
description: `Update a body of work's settings.`,
|
|
2534
|
+
inputSchema: {
|
|
2535
|
+
type: 'object',
|
|
2536
|
+
properties: {
|
|
2537
|
+
body_of_work_id: {
|
|
2538
|
+
type: 'string',
|
|
2539
|
+
description: 'Body of work UUID',
|
|
2540
|
+
},
|
|
2541
|
+
title: {
|
|
2542
|
+
type: 'string',
|
|
2543
|
+
description: 'Updated title',
|
|
2544
|
+
},
|
|
2545
|
+
description: {
|
|
2546
|
+
type: 'string',
|
|
2547
|
+
description: 'Updated description',
|
|
2548
|
+
},
|
|
2549
|
+
auto_deploy_on_completion: {
|
|
2550
|
+
type: 'boolean',
|
|
2551
|
+
description: 'Auto-deploy setting',
|
|
2552
|
+
},
|
|
2553
|
+
deploy_environment: {
|
|
2554
|
+
type: 'string',
|
|
2555
|
+
enum: ['development', 'staging', 'production'],
|
|
2556
|
+
description: 'Target environment',
|
|
2557
|
+
},
|
|
2558
|
+
deploy_version_bump: {
|
|
2559
|
+
type: 'string',
|
|
2560
|
+
enum: ['patch', 'minor', 'major'],
|
|
2561
|
+
description: 'Version bump type',
|
|
2562
|
+
},
|
|
2563
|
+
deploy_trigger: {
|
|
2564
|
+
type: 'string',
|
|
2565
|
+
enum: ['all_completed', 'all_completed_validated'],
|
|
2566
|
+
description: 'When to trigger auto-deploy',
|
|
2567
|
+
},
|
|
2568
|
+
},
|
|
2569
|
+
required: ['body_of_work_id'],
|
|
2570
|
+
},
|
|
2571
|
+
},
|
|
2572
|
+
{
|
|
2573
|
+
name: 'get_body_of_work',
|
|
2574
|
+
description: `Get a body of work with all its tasks organized by phase.`,
|
|
2575
|
+
inputSchema: {
|
|
2576
|
+
type: 'object',
|
|
2577
|
+
properties: {
|
|
2578
|
+
body_of_work_id: {
|
|
2579
|
+
type: 'string',
|
|
2580
|
+
description: 'Body of work UUID',
|
|
2581
|
+
},
|
|
2582
|
+
},
|
|
2583
|
+
required: ['body_of_work_id'],
|
|
2584
|
+
},
|
|
2585
|
+
},
|
|
2586
|
+
{
|
|
2587
|
+
name: 'get_bodies_of_work',
|
|
2588
|
+
description: `List bodies of work for a project with task counts per phase.`,
|
|
2589
|
+
inputSchema: {
|
|
2590
|
+
type: 'object',
|
|
2591
|
+
properties: {
|
|
2592
|
+
project_id: {
|
|
2593
|
+
type: 'string',
|
|
2594
|
+
description: 'Project UUID',
|
|
2595
|
+
},
|
|
2596
|
+
status: {
|
|
2597
|
+
type: 'string',
|
|
2598
|
+
enum: ['draft', 'active', 'completed', 'cancelled'],
|
|
2599
|
+
description: 'Filter by status (optional)',
|
|
2600
|
+
},
|
|
2601
|
+
},
|
|
2602
|
+
required: ['project_id'],
|
|
2603
|
+
},
|
|
2604
|
+
},
|
|
2605
|
+
{
|
|
2606
|
+
name: 'delete_body_of_work',
|
|
2607
|
+
description: `Delete a body of work. Tasks are preserved but no longer grouped.`,
|
|
2608
|
+
inputSchema: {
|
|
2609
|
+
type: 'object',
|
|
2610
|
+
properties: {
|
|
2611
|
+
body_of_work_id: {
|
|
2612
|
+
type: 'string',
|
|
2613
|
+
description: 'Body of work UUID',
|
|
2614
|
+
},
|
|
2615
|
+
},
|
|
2616
|
+
required: ['body_of_work_id'],
|
|
2617
|
+
},
|
|
2618
|
+
},
|
|
2619
|
+
{
|
|
2620
|
+
name: 'add_task_to_body_of_work',
|
|
2621
|
+
description: `Add a task to a body of work in a specific phase.
|
|
2622
|
+
Phases control execution order: pre tasks run first, then core, then post.`,
|
|
2623
|
+
inputSchema: {
|
|
2624
|
+
type: 'object',
|
|
2625
|
+
properties: {
|
|
2626
|
+
body_of_work_id: {
|
|
2627
|
+
type: 'string',
|
|
2628
|
+
description: 'Body of work UUID',
|
|
2629
|
+
},
|
|
2630
|
+
task_id: {
|
|
2631
|
+
type: 'string',
|
|
2632
|
+
description: 'Task UUID to add',
|
|
2633
|
+
},
|
|
2634
|
+
phase: {
|
|
2635
|
+
type: 'string',
|
|
2636
|
+
enum: ['pre', 'core', 'post'],
|
|
2637
|
+
description: 'Task phase (default: core)',
|
|
2638
|
+
},
|
|
2639
|
+
order_index: {
|
|
2640
|
+
type: 'number',
|
|
2641
|
+
description: 'Order within phase (auto-assigned if not specified)',
|
|
2642
|
+
},
|
|
2643
|
+
},
|
|
2644
|
+
required: ['body_of_work_id', 'task_id'],
|
|
2645
|
+
},
|
|
2646
|
+
},
|
|
2647
|
+
{
|
|
2648
|
+
name: 'remove_task_from_body_of_work',
|
|
2649
|
+
description: `Remove a task from its body of work. The task is preserved.`,
|
|
2650
|
+
inputSchema: {
|
|
2651
|
+
type: 'object',
|
|
2652
|
+
properties: {
|
|
2653
|
+
task_id: {
|
|
2654
|
+
type: 'string',
|
|
2655
|
+
description: 'Task UUID to remove',
|
|
2656
|
+
},
|
|
2657
|
+
},
|
|
2658
|
+
required: ['task_id'],
|
|
2659
|
+
},
|
|
2660
|
+
},
|
|
2661
|
+
{
|
|
2662
|
+
name: 'activate_body_of_work',
|
|
2663
|
+
description: `Activate a draft body of work to start execution.
|
|
2664
|
+
Requires at least one task. Once active, tasks can be worked on following phase order.`,
|
|
2665
|
+
inputSchema: {
|
|
2666
|
+
type: 'object',
|
|
2667
|
+
properties: {
|
|
2668
|
+
body_of_work_id: {
|
|
2669
|
+
type: 'string',
|
|
2670
|
+
description: 'Body of work UUID',
|
|
2671
|
+
},
|
|
2672
|
+
},
|
|
2673
|
+
required: ['body_of_work_id'],
|
|
2674
|
+
},
|
|
2675
|
+
},
|
|
2676
|
+
{
|
|
2677
|
+
name: 'add_task_dependency',
|
|
2678
|
+
description: `Add a dependency between tasks in a body of work.
|
|
2679
|
+
The dependent task cannot start until the dependency is completed. Prevents circular dependencies.`,
|
|
2680
|
+
inputSchema: {
|
|
2681
|
+
type: 'object',
|
|
2682
|
+
properties: {
|
|
2683
|
+
body_of_work_id: {
|
|
2684
|
+
type: 'string',
|
|
2685
|
+
description: 'Body of work UUID',
|
|
2686
|
+
},
|
|
2687
|
+
task_id: {
|
|
2688
|
+
type: 'string',
|
|
2689
|
+
description: 'Task that depends on another task',
|
|
2690
|
+
},
|
|
2691
|
+
depends_on_task_id: {
|
|
2692
|
+
type: 'string',
|
|
2693
|
+
description: 'Task that must complete first',
|
|
2694
|
+
},
|
|
2695
|
+
},
|
|
2696
|
+
required: ['body_of_work_id', 'task_id', 'depends_on_task_id'],
|
|
2697
|
+
},
|
|
2698
|
+
},
|
|
2699
|
+
{
|
|
2700
|
+
name: 'remove_task_dependency',
|
|
2701
|
+
description: `Remove a dependency between tasks.`,
|
|
2702
|
+
inputSchema: {
|
|
2703
|
+
type: 'object',
|
|
2704
|
+
properties: {
|
|
2705
|
+
task_id: {
|
|
2706
|
+
type: 'string',
|
|
2707
|
+
description: 'Task UUID',
|
|
2708
|
+
},
|
|
2709
|
+
depends_on_task_id: {
|
|
2710
|
+
type: 'string',
|
|
2711
|
+
description: 'Dependency task UUID',
|
|
2712
|
+
},
|
|
2713
|
+
},
|
|
2714
|
+
required: ['task_id', 'depends_on_task_id'],
|
|
2715
|
+
},
|
|
2716
|
+
},
|
|
2717
|
+
{
|
|
2718
|
+
name: 'get_task_dependencies',
|
|
2719
|
+
description: `Get task dependencies for a body of work or specific task.`,
|
|
2720
|
+
inputSchema: {
|
|
2721
|
+
type: 'object',
|
|
2722
|
+
properties: {
|
|
2723
|
+
body_of_work_id: {
|
|
2724
|
+
type: 'string',
|
|
2725
|
+
description: 'Body of work UUID (optional if task_id provided)',
|
|
2726
|
+
},
|
|
2727
|
+
task_id: {
|
|
2728
|
+
type: 'string',
|
|
2729
|
+
description: 'Specific task UUID (optional if body_of_work_id provided)',
|
|
2730
|
+
},
|
|
2731
|
+
},
|
|
2732
|
+
},
|
|
2733
|
+
},
|
|
2734
|
+
{
|
|
2735
|
+
name: 'get_next_body_of_work_task',
|
|
2736
|
+
description: `Get the next available task from a body of work.
|
|
2737
|
+
Considers phase order (pre → core → post) and task dependencies.
|
|
2738
|
+
Only returns tasks where all dependencies are completed.`,
|
|
2739
|
+
inputSchema: {
|
|
2740
|
+
type: 'object',
|
|
2741
|
+
properties: {
|
|
2742
|
+
body_of_work_id: {
|
|
2743
|
+
type: 'string',
|
|
2744
|
+
description: 'Body of work UUID',
|
|
2745
|
+
},
|
|
2746
|
+
},
|
|
2747
|
+
required: ['body_of_work_id'],
|
|
2748
|
+
},
|
|
2749
|
+
},
|
|
2750
|
+
// ============================================================================
|
|
2751
|
+
// Organization Tools
|
|
2752
|
+
// ============================================================================
|
|
2753
|
+
{
|
|
2754
|
+
name: 'list_organizations',
|
|
2755
|
+
description: 'List organizations the current user belongs to.',
|
|
2756
|
+
inputSchema: {
|
|
2757
|
+
type: 'object',
|
|
2758
|
+
properties: {},
|
|
2759
|
+
},
|
|
2760
|
+
},
|
|
2761
|
+
{
|
|
2762
|
+
name: 'create_organization',
|
|
2763
|
+
description: 'Create a new organization. You become the owner.',
|
|
2764
|
+
inputSchema: {
|
|
2765
|
+
type: 'object',
|
|
2766
|
+
properties: {
|
|
2767
|
+
name: {
|
|
2768
|
+
type: 'string',
|
|
2769
|
+
description: 'Organization display name',
|
|
2770
|
+
},
|
|
2771
|
+
description: {
|
|
2772
|
+
type: 'string',
|
|
2773
|
+
description: 'Brief description of the organization',
|
|
2774
|
+
},
|
|
2775
|
+
slug: {
|
|
2776
|
+
type: 'string',
|
|
2777
|
+
description: 'URL-friendly identifier (auto-generated from name if not provided)',
|
|
2778
|
+
},
|
|
2779
|
+
},
|
|
2780
|
+
required: ['name'],
|
|
2781
|
+
},
|
|
2782
|
+
},
|
|
2783
|
+
{
|
|
2784
|
+
name: 'update_organization',
|
|
2785
|
+
description: 'Update organization details. Requires admin role.',
|
|
2786
|
+
inputSchema: {
|
|
2787
|
+
type: 'object',
|
|
2788
|
+
properties: {
|
|
2789
|
+
organization_id: {
|
|
2790
|
+
type: 'string',
|
|
2791
|
+
description: 'Organization UUID',
|
|
2792
|
+
},
|
|
2793
|
+
name: {
|
|
2794
|
+
type: 'string',
|
|
2795
|
+
description: 'New organization name',
|
|
2796
|
+
},
|
|
2797
|
+
description: {
|
|
2798
|
+
type: 'string',
|
|
2799
|
+
description: 'New description',
|
|
2800
|
+
},
|
|
2801
|
+
logo_url: {
|
|
2802
|
+
type: 'string',
|
|
2803
|
+
description: 'URL to organization logo',
|
|
2804
|
+
},
|
|
2805
|
+
},
|
|
2806
|
+
required: ['organization_id'],
|
|
2807
|
+
},
|
|
2808
|
+
},
|
|
2809
|
+
{
|
|
2810
|
+
name: 'delete_organization',
|
|
2811
|
+
description: 'Delete an organization. Requires owner role. Removes all shares.',
|
|
2812
|
+
inputSchema: {
|
|
2813
|
+
type: 'object',
|
|
2814
|
+
properties: {
|
|
2815
|
+
organization_id: {
|
|
2816
|
+
type: 'string',
|
|
2817
|
+
description: 'Organization UUID',
|
|
2818
|
+
},
|
|
2819
|
+
},
|
|
2820
|
+
required: ['organization_id'],
|
|
2821
|
+
},
|
|
2822
|
+
},
|
|
2823
|
+
{
|
|
2824
|
+
name: 'list_org_members',
|
|
2825
|
+
description: 'List members of an organization.',
|
|
2826
|
+
inputSchema: {
|
|
2827
|
+
type: 'object',
|
|
2828
|
+
properties: {
|
|
2829
|
+
organization_id: {
|
|
2830
|
+
type: 'string',
|
|
2831
|
+
description: 'Organization UUID',
|
|
2832
|
+
},
|
|
2833
|
+
},
|
|
2834
|
+
required: ['organization_id'],
|
|
2835
|
+
},
|
|
2836
|
+
},
|
|
2837
|
+
{
|
|
2838
|
+
name: 'invite_member',
|
|
2839
|
+
description: 'Invite a user to an organization by email. Requires admin role.',
|
|
2840
|
+
inputSchema: {
|
|
2841
|
+
type: 'object',
|
|
2842
|
+
properties: {
|
|
2843
|
+
organization_id: {
|
|
2844
|
+
type: 'string',
|
|
2845
|
+
description: 'Organization UUID',
|
|
2846
|
+
},
|
|
2847
|
+
email: {
|
|
2848
|
+
type: 'string',
|
|
2849
|
+
description: 'Email address to invite',
|
|
2850
|
+
},
|
|
2851
|
+
role: {
|
|
2852
|
+
type: 'string',
|
|
2853
|
+
enum: ['admin', 'member', 'viewer'],
|
|
2854
|
+
description: 'Role to assign (default: member)',
|
|
2855
|
+
},
|
|
2856
|
+
},
|
|
2857
|
+
required: ['organization_id', 'email'],
|
|
2858
|
+
},
|
|
2859
|
+
},
|
|
2860
|
+
{
|
|
2861
|
+
name: 'update_member_role',
|
|
2862
|
+
description: 'Change a member\'s role. Requires admin role. Cannot change owner.',
|
|
2863
|
+
inputSchema: {
|
|
2864
|
+
type: 'object',
|
|
2865
|
+
properties: {
|
|
2866
|
+
organization_id: {
|
|
2867
|
+
type: 'string',
|
|
2868
|
+
description: 'Organization UUID',
|
|
2869
|
+
},
|
|
2870
|
+
user_id: {
|
|
2871
|
+
type: 'string',
|
|
2872
|
+
description: 'User UUID to update',
|
|
2873
|
+
},
|
|
2874
|
+
role: {
|
|
2875
|
+
type: 'string',
|
|
2876
|
+
enum: ['admin', 'member', 'viewer'],
|
|
2877
|
+
description: 'New role to assign',
|
|
2878
|
+
},
|
|
2879
|
+
},
|
|
2880
|
+
required: ['organization_id', 'user_id', 'role'],
|
|
2881
|
+
},
|
|
2882
|
+
},
|
|
2883
|
+
{
|
|
2884
|
+
name: 'remove_member',
|
|
2885
|
+
description: 'Remove a member from an organization. Requires admin role.',
|
|
2886
|
+
inputSchema: {
|
|
2887
|
+
type: 'object',
|
|
2888
|
+
properties: {
|
|
2889
|
+
organization_id: {
|
|
2890
|
+
type: 'string',
|
|
2891
|
+
description: 'Organization UUID',
|
|
2892
|
+
},
|
|
2893
|
+
user_id: {
|
|
2894
|
+
type: 'string',
|
|
2895
|
+
description: 'User UUID to remove',
|
|
2896
|
+
},
|
|
2897
|
+
},
|
|
2898
|
+
required: ['organization_id', 'user_id'],
|
|
2899
|
+
},
|
|
2900
|
+
},
|
|
2901
|
+
{
|
|
2902
|
+
name: 'leave_organization',
|
|
2903
|
+
description: 'Leave an organization. Owner cannot leave without transferring ownership.',
|
|
2904
|
+
inputSchema: {
|
|
2905
|
+
type: 'object',
|
|
2906
|
+
properties: {
|
|
2907
|
+
organization_id: {
|
|
2908
|
+
type: 'string',
|
|
2909
|
+
description: 'Organization UUID',
|
|
2910
|
+
},
|
|
2911
|
+
},
|
|
2912
|
+
required: ['organization_id'],
|
|
2913
|
+
},
|
|
2914
|
+
},
|
|
2915
|
+
{
|
|
2916
|
+
name: 'share_project_with_org',
|
|
2917
|
+
description: 'Share a project with an organization. You must own the project.',
|
|
2918
|
+
inputSchema: {
|
|
2919
|
+
type: 'object',
|
|
2920
|
+
properties: {
|
|
2921
|
+
project_id: {
|
|
2922
|
+
type: 'string',
|
|
2923
|
+
description: 'Project UUID',
|
|
2924
|
+
},
|
|
2925
|
+
organization_id: {
|
|
2926
|
+
type: 'string',
|
|
2927
|
+
description: 'Organization UUID to share with',
|
|
2928
|
+
},
|
|
2929
|
+
permission: {
|
|
2930
|
+
type: 'string',
|
|
2931
|
+
enum: ['read', 'write', 'admin'],
|
|
2932
|
+
description: 'Permission level (default: read)',
|
|
2933
|
+
},
|
|
2934
|
+
},
|
|
2935
|
+
required: ['project_id', 'organization_id'],
|
|
2936
|
+
},
|
|
2937
|
+
},
|
|
2938
|
+
{
|
|
2939
|
+
name: 'update_project_share',
|
|
2940
|
+
description: 'Update the permission level for a project share.',
|
|
2941
|
+
inputSchema: {
|
|
2942
|
+
type: 'object',
|
|
2943
|
+
properties: {
|
|
2944
|
+
project_id: {
|
|
2945
|
+
type: 'string',
|
|
2946
|
+
description: 'Project UUID',
|
|
2947
|
+
},
|
|
2948
|
+
organization_id: {
|
|
2949
|
+
type: 'string',
|
|
2950
|
+
description: 'Organization UUID',
|
|
2951
|
+
},
|
|
2952
|
+
permission: {
|
|
2953
|
+
type: 'string',
|
|
2954
|
+
enum: ['read', 'write', 'admin'],
|
|
2955
|
+
description: 'New permission level',
|
|
2956
|
+
},
|
|
2957
|
+
},
|
|
2958
|
+
required: ['project_id', 'organization_id', 'permission'],
|
|
2959
|
+
},
|
|
2960
|
+
},
|
|
2961
|
+
{
|
|
2962
|
+
name: 'unshare_project',
|
|
2963
|
+
description: 'Remove a project share from an organization.',
|
|
2964
|
+
inputSchema: {
|
|
2965
|
+
type: 'object',
|
|
2966
|
+
properties: {
|
|
2967
|
+
project_id: {
|
|
2968
|
+
type: 'string',
|
|
2969
|
+
description: 'Project UUID',
|
|
2970
|
+
},
|
|
2971
|
+
organization_id: {
|
|
2972
|
+
type: 'string',
|
|
2973
|
+
description: 'Organization UUID',
|
|
2974
|
+
},
|
|
2975
|
+
},
|
|
2976
|
+
required: ['project_id', 'organization_id'],
|
|
2977
|
+
},
|
|
2978
|
+
},
|
|
2979
|
+
{
|
|
2980
|
+
name: 'list_project_shares',
|
|
2981
|
+
description: 'List all organizations a project is shared with.',
|
|
2982
|
+
inputSchema: {
|
|
2983
|
+
type: 'object',
|
|
2984
|
+
properties: {
|
|
2985
|
+
project_id: {
|
|
2986
|
+
type: 'string',
|
|
2987
|
+
description: 'Project UUID',
|
|
2988
|
+
},
|
|
2989
|
+
},
|
|
2990
|
+
required: ['project_id'],
|
|
2991
|
+
},
|
|
2992
|
+
},
|
|
2993
|
+
];
|
|
2994
|
+
|
|
2995
|
+
// ============================================================================
|
|
2996
|
+
// Tool Handlers
|
|
2997
|
+
// ============================================================================
|
|
2998
|
+
|
|
2999
|
+
async function handleTool(
|
|
3000
|
+
auth: AuthContext,
|
|
3001
|
+
name: string,
|
|
3002
|
+
args: Record<string, unknown>
|
|
3003
|
+
): Promise<{ result: unknown; user_updates?: UserUpdates; reminder?: string }> {
|
|
3004
|
+
// Update session on every tool call:
|
|
3005
|
+
// - last_synced_at: keeps session alive and visible as "active" on dashboard
|
|
3006
|
+
// - tool_call_count: incremented for token efficiency tracking
|
|
3007
|
+
// - last_tool_at: timestamp of last tool call
|
|
3008
|
+
// Skip for start_work_session since it handles its own session setup
|
|
3009
|
+
if (currentSessionId && name !== 'start_work_session') {
|
|
3010
|
+
const now = new Date().toISOString();
|
|
3011
|
+
await supabase.rpc('increment_tool_call_count', {
|
|
3012
|
+
p_session_id: currentSessionId,
|
|
3013
|
+
p_timestamp: now
|
|
3014
|
+
}).then(({ error }) => {
|
|
3015
|
+
// Fallback to direct update if RPC doesn't exist (pre-migration)
|
|
3016
|
+
if (error) {
|
|
3017
|
+
return supabase
|
|
3018
|
+
.from('agent_sessions')
|
|
3019
|
+
.update({ last_synced_at: now })
|
|
3020
|
+
.eq('id', currentSessionId);
|
|
3021
|
+
}
|
|
3022
|
+
});
|
|
3023
|
+
}
|
|
3024
|
+
|
|
3025
|
+
// Check if handler exists in the modular registry
|
|
3026
|
+
const handler = handlerRegistry[name];
|
|
3027
|
+
if (handler) {
|
|
3028
|
+
// Build handler context
|
|
3029
|
+
const ctx: HandlerContext = {
|
|
3030
|
+
supabase,
|
|
3031
|
+
auth,
|
|
3032
|
+
session: {
|
|
3033
|
+
instanceId: INSTANCE_ID,
|
|
3034
|
+
currentSessionId,
|
|
3035
|
+
currentPersona,
|
|
3036
|
+
tokenUsage: sessionTokenUsage,
|
|
3037
|
+
},
|
|
3038
|
+
updateSession: (updates) => {
|
|
3039
|
+
if (updates.currentSessionId !== undefined) currentSessionId = updates.currentSessionId;
|
|
3040
|
+
if (updates.currentPersona !== undefined) currentPersona = updates.currentPersona;
|
|
3041
|
+
if (updates.tokenUsage !== undefined) sessionTokenUsage = updates.tokenUsage;
|
|
3042
|
+
},
|
|
3043
|
+
};
|
|
3044
|
+
|
|
3045
|
+
const handlerResult = await handler(args, ctx);
|
|
3046
|
+
return handlerResult as { result: unknown; user_updates?: UserUpdates; reminder?: string };
|
|
3047
|
+
}
|
|
3048
|
+
|
|
3049
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
3050
|
+
}
|
|
3051
|
+
|
|
3052
|
+
// ============================================================================
|
|
3053
|
+
// Server Setup
|
|
3054
|
+
// ============================================================================
|
|
3055
|
+
|
|
3056
|
+
async function main() {
|
|
3057
|
+
// Validate API key on startup
|
|
3058
|
+
const auth = await validateApiKey(API_KEY!);
|
|
3059
|
+
if (!auth) {
|
|
3060
|
+
console.error('Invalid API key');
|
|
3061
|
+
process.exit(1);
|
|
3062
|
+
}
|
|
3063
|
+
|
|
3064
|
+
const server = new Server(
|
|
3065
|
+
{
|
|
3066
|
+
name: 'vibescope',
|
|
3067
|
+
version: '0.1.0',
|
|
3068
|
+
},
|
|
3069
|
+
{
|
|
3070
|
+
capabilities: {
|
|
3071
|
+
tools: {},
|
|
3072
|
+
},
|
|
3073
|
+
}
|
|
3074
|
+
);
|
|
3075
|
+
|
|
3076
|
+
// List available tools
|
|
3077
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
3078
|
+
return { tools };
|
|
3079
|
+
});
|
|
3080
|
+
|
|
3081
|
+
// Get reminder nudge - only for critical workflow reminders to save context
|
|
3082
|
+
function getReminder(toolName: string): string | null {
|
|
3083
|
+
// Most reminders removed to reduce context bloat - instructions are in CLAUDE.md
|
|
3084
|
+
// Only keep critical continuation reminder for complete_task
|
|
3085
|
+
const reminders: Record<string, string> = {
|
|
3086
|
+
'complete_task': 'CONTINUE WORKING: Call get_next_task or start the next_task. If awaiting_validation tasks exist, validate them FIRST before new work. If context is large, run /clear then start_work_session to refresh.',
|
|
3087
|
+
'batch_complete_tasks': 'CONTINUE WORKING: Call get_next_task. If awaiting_validation tasks exist, validate them FIRST before new work.',
|
|
3088
|
+
};
|
|
3089
|
+
return reminders[toolName] ?? null;
|
|
3090
|
+
}
|
|
3091
|
+
|
|
3092
|
+
// Handle tool calls
|
|
3093
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
3094
|
+
const { name, arguments: args } = request.params;
|
|
3095
|
+
|
|
3096
|
+
// Check rate limit
|
|
3097
|
+
const rateCheck = rateLimiter.check(auth.apiKeyId);
|
|
3098
|
+
if (!rateCheck.allowed) {
|
|
3099
|
+
const resetSeconds = Math.ceil(rateCheck.resetIn / 1000);
|
|
3100
|
+
return {
|
|
3101
|
+
content: [
|
|
3102
|
+
{
|
|
3103
|
+
type: 'text',
|
|
3104
|
+
text: `Rate limit exceeded. Too many requests. Please wait ${resetSeconds} seconds before trying again. (Limit: 60 requests per minute)`,
|
|
3105
|
+
},
|
|
3106
|
+
],
|
|
3107
|
+
isError: true,
|
|
3108
|
+
};
|
|
3109
|
+
}
|
|
3110
|
+
|
|
3111
|
+
try {
|
|
3112
|
+
const toolArgs = (args as Record<string, unknown>) || {};
|
|
3113
|
+
const { result, user_updates } = await handleTool(
|
|
3114
|
+
auth,
|
|
3115
|
+
name,
|
|
3116
|
+
toolArgs
|
|
3117
|
+
);
|
|
3118
|
+
|
|
3119
|
+
// Track token usage for this call (both input args and output result)
|
|
3120
|
+
trackTokenUsage(name, toolArgs, result);
|
|
3121
|
+
|
|
3122
|
+
const content: { type: 'text'; text: string }[] = [
|
|
3123
|
+
{
|
|
3124
|
+
type: 'text',
|
|
3125
|
+
text: JSON.stringify(result, null, 2),
|
|
3126
|
+
},
|
|
3127
|
+
];
|
|
3128
|
+
|
|
3129
|
+
// Include reminder nudge if applicable
|
|
3130
|
+
const reminder = getReminder(name);
|
|
3131
|
+
if (reminder) {
|
|
3132
|
+
content.push({
|
|
3133
|
+
type: 'text',
|
|
3134
|
+
text: `\n--- ${reminder} ---`,
|
|
3135
|
+
});
|
|
3136
|
+
}
|
|
3137
|
+
|
|
3138
|
+
// Include user updates only if there are new items (null means no updates)
|
|
3139
|
+
if (user_updates) {
|
|
3140
|
+
content.push({
|
|
3141
|
+
type: 'text',
|
|
3142
|
+
text: `\n--- New User Updates ---\n${JSON.stringify(user_updates, null, 2)}`,
|
|
3143
|
+
});
|
|
3144
|
+
}
|
|
3145
|
+
|
|
3146
|
+
// Add rate limit warning if getting low
|
|
3147
|
+
if (rateCheck.remaining < 10) {
|
|
3148
|
+
content.push({
|
|
3149
|
+
type: 'text',
|
|
3150
|
+
text: `\n--- Rate Limit Warning: ${rateCheck.remaining} requests remaining this minute ---`,
|
|
3151
|
+
});
|
|
3152
|
+
}
|
|
3153
|
+
|
|
3154
|
+
return { content };
|
|
3155
|
+
} catch (error) {
|
|
3156
|
+
// Handle validation errors with structured output
|
|
3157
|
+
if (error instanceof ValidationError) {
|
|
3158
|
+
return {
|
|
3159
|
+
content: [
|
|
3160
|
+
{
|
|
3161
|
+
type: 'text',
|
|
3162
|
+
text: JSON.stringify(error.toJSON(), null, 2),
|
|
3163
|
+
},
|
|
3164
|
+
],
|
|
3165
|
+
isError: true,
|
|
3166
|
+
};
|
|
3167
|
+
}
|
|
3168
|
+
|
|
3169
|
+
// Handle database errors with better context
|
|
3170
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
3171
|
+
let hint: string | undefined;
|
|
3172
|
+
|
|
3173
|
+
if (errorMessage.includes('violates foreign key constraint')) {
|
|
3174
|
+
hint = 'The referenced ID does not exist. Check that the project_id, task_id, or other IDs are correct.';
|
|
3175
|
+
} else if (errorMessage.includes('duplicate key')) {
|
|
3176
|
+
hint = 'A record with this identifier already exists.';
|
|
3177
|
+
} else if (errorMessage.includes('not found') || errorMessage.includes('no rows')) {
|
|
3178
|
+
hint = 'The requested resource was not found. Verify the ID is correct.';
|
|
3179
|
+
}
|
|
3180
|
+
|
|
3181
|
+
return {
|
|
3182
|
+
content: [
|
|
3183
|
+
{
|
|
3184
|
+
type: 'text',
|
|
3185
|
+
text: JSON.stringify({
|
|
3186
|
+
error: 'operation_failed',
|
|
3187
|
+
message: errorMessage,
|
|
3188
|
+
hint,
|
|
3189
|
+
}, null, 2),
|
|
3190
|
+
},
|
|
3191
|
+
],
|
|
3192
|
+
isError: true,
|
|
3193
|
+
};
|
|
3194
|
+
}
|
|
3195
|
+
});
|
|
3196
|
+
|
|
3197
|
+
// Start server
|
|
3198
|
+
const transport = new StdioServerTransport();
|
|
3199
|
+
await server.connect(transport);
|
|
3200
|
+
}
|
|
3201
|
+
|
|
3202
|
+
main().catch((error) => {
|
|
3203
|
+
console.error('Fatal error:', error);
|
|
3204
|
+
process.exit(1);
|
|
3205
|
+
});
|