capyai 0.3.5 → 0.3.6
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/AGENTS.md +24 -12
- package/README.md +1 -1
- package/package.json +1 -1
- package/skills/capy/SKILL.md +1 -1
- package/src/api.ts +9 -2
- package/src/mcp.ts +63 -6
- package/src/types.ts +18 -1
package/AGENTS.md
CHANGED
|
@@ -81,19 +81,22 @@ Config file locations:
|
|
|
81
81
|
- Claude Desktop: `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
|
|
82
82
|
- Cursor: `.cursor/mcp.json`
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
17 MCP tools with full CLI parity:
|
|
85
85
|
|
|
86
86
|
| Tool | What it does | Annotations |
|
|
87
87
|
|------|-------------|-------------|
|
|
88
88
|
| `capy_captain` | Start Captain thread | openWorld |
|
|
89
89
|
| `capy_build` | Start Build agent | openWorld |
|
|
90
|
+
| `capy_start` | Start/resume a backlog task | openWorld |
|
|
90
91
|
| `capy_wait` | Block until done | readOnly, idempotent |
|
|
91
92
|
| `capy_review` | Run quality gates | readOnly |
|
|
92
93
|
| `capy_approve` | Approve task | openWorld |
|
|
93
94
|
| `capy_retry` | Retry with context | openWorld |
|
|
95
|
+
| `capy_re_review` | Trigger Greptile re-review | openWorld |
|
|
94
96
|
| `capy_status` | Task/thread details or dashboard | readOnly, idempotent |
|
|
95
|
-
| `capy_list` | List tasks (filterable) | readOnly, idempotent |
|
|
96
|
-
| `capy_threads` | List threads | readOnly, idempotent |
|
|
97
|
+
| `capy_list` | List tasks (filterable, paginated) | readOnly, idempotent |
|
|
98
|
+
| `capy_threads` | List threads (paginated) | readOnly, idempotent |
|
|
99
|
+
| `capy_thread_messages` | Read thread conversation history | readOnly, idempotent |
|
|
97
100
|
| `capy_diff` | View diff | readOnly |
|
|
98
101
|
| `capy_msg` | Message task/thread | openWorld |
|
|
99
102
|
| `capy_stop` | Stop task/thread | destructive |
|
|
@@ -203,21 +206,30 @@ Every command supports `--json` for structured output. Errors always return `{ "
|
|
|
203
206
|
|---------|-------------|
|
|
204
207
|
| `capy captain "<prompt>"` | Start Captain thread |
|
|
205
208
|
| `capy build "<prompt>"` | Start Build agent (small isolated tasks) |
|
|
209
|
+
| `capy start <id>` | Start/resume a backlog task |
|
|
210
|
+
| `capy stop <id> [reason]` | Stop a running task |
|
|
211
|
+
| `capy msg <id> "<text>"` | Message a running task |
|
|
206
212
|
| `capy wait <id> --timeout=N` | Block until terminal state |
|
|
207
213
|
| `capy review <id>` | Run quality gates (pass/fail) |
|
|
214
|
+
| `capy re-review <id>` | Trigger fresh Greptile review |
|
|
208
215
|
| `capy approve <id>` | Approve if gates pass |
|
|
209
|
-
| `capy retry <id> --fix="..."` | Retry with context |
|
|
210
|
-
| `capy status` | Dashboard |
|
|
211
|
-
| `capy list [status]` | List tasks |
|
|
212
|
-
| `capy get <id>` | Task
|
|
213
|
-
| `capy diff <id>` | View diff |
|
|
214
|
-
| `capy pr <id
|
|
215
|
-
| `capy watch <id>` | Cron poll + notify |
|
|
216
|
-
| `capy
|
|
217
|
-
| `capy
|
|
216
|
+
| `capy retry <id> --fix="..."` | Retry with context from failure |
|
|
217
|
+
| `capy status` | Dashboard (all threads + tasks) |
|
|
218
|
+
| `capy list [status]` | List tasks (filter: in_progress, needs_review, backlog, archived) |
|
|
219
|
+
| `capy get <id>` | Task details (jams, PR state, credits) |
|
|
220
|
+
| `capy diff <id>` | View diff (file-by-file with patches) |
|
|
221
|
+
| `capy pr <id> [title]` | Create PR for a task |
|
|
222
|
+
| `capy watch <id>` | Cron poll + notify on completion |
|
|
223
|
+
| `capy unwatch <id>` | Stop watching |
|
|
224
|
+
| `capy watches` | List active watches |
|
|
225
|
+
| `capy threads list` | List Captain threads |
|
|
226
|
+
| `capy threads get <id>` | Thread details (tasks, PRs) |
|
|
218
227
|
| `capy threads msg <id> "<text>"` | Message a thread |
|
|
228
|
+
| `capy threads stop <id>` | Stop a thread |
|
|
229
|
+
| `capy threads messages <id>` | Read thread conversation history |
|
|
219
230
|
| `capy config [key] [value]` | Get/set config |
|
|
220
231
|
| `capy models` | List available models |
|
|
232
|
+
| `capy tools` | Show all commands + env vars |
|
|
221
233
|
|
|
222
234
|
### Prompting tips
|
|
223
235
|
|
package/README.md
CHANGED
|
@@ -87,7 +87,7 @@ For agents that prefer MCP over CLI:
|
|
|
87
87
|
}
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
17 tools with full CLI parity: `capy_captain`, `capy_build`, `capy_start`, `capy_wait`, `capy_review`, `capy_approve`, `capy_retry`, `capy_re_review`, `capy_status`, `capy_list`, `capy_threads`, `capy_thread_messages`, `capy_diff`, `capy_msg`, `capy_stop`, `capy_pr`, `capy_models`.
|
|
91
91
|
|
|
92
92
|
## Config
|
|
93
93
|
|
package/package.json
CHANGED
package/skills/capy/SKILL.md
CHANGED
package/src/api.ts
CHANGED
|
@@ -72,6 +72,11 @@ export async function listModelsWithKey(apiKey: string, server = "https://capy.a
|
|
|
72
72
|
return data.models || [];
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
export async function getProject(id?: string): Promise<Project & { createdAt?: string; updatedAt?: string }> {
|
|
76
|
+
const pid = id || config.load().projectId;
|
|
77
|
+
return request("GET", `/projects/${pid}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
75
80
|
// --- Threads ---
|
|
76
81
|
export async function createThread(prompt: string, model?: string, repos?: unknown[]): Promise<Thread> {
|
|
77
82
|
const cfg = config.load();
|
|
@@ -83,10 +88,11 @@ export async function createThread(prompt: string, model?: string, repos?: unkno
|
|
|
83
88
|
});
|
|
84
89
|
}
|
|
85
90
|
|
|
86
|
-
export async function listThreads(opts: { limit?: number; status?: string } = {}): Promise<ListResponse<Thread>> {
|
|
91
|
+
export async function listThreads(opts: { limit?: number; status?: string; cursor?: string } = {}): Promise<ListResponse<Thread>> {
|
|
87
92
|
const cfg = config.load();
|
|
88
93
|
const p = new URLSearchParams({ projectId: cfg.projectId, limit: String(opts.limit || 10) });
|
|
89
94
|
if (opts.status) p.set("status", opts.status);
|
|
95
|
+
if (opts.cursor) p.set("cursor", opts.cursor);
|
|
90
96
|
return request("GET", `/threads?${p}`);
|
|
91
97
|
}
|
|
92
98
|
|
|
@@ -121,10 +127,11 @@ export async function createTask(prompt: string, model?: string, opts: { title?:
|
|
|
121
127
|
});
|
|
122
128
|
}
|
|
123
129
|
|
|
124
|
-
export async function listTasks(opts: { limit?: number; status?: string } = {}): Promise<ListResponse<Task>> {
|
|
130
|
+
export async function listTasks(opts: { limit?: number; status?: string; cursor?: string } = {}): Promise<ListResponse<Task>> {
|
|
125
131
|
const cfg = config.load();
|
|
126
132
|
const p = new URLSearchParams({ projectId: cfg.projectId, limit: String(opts.limit || 30) });
|
|
127
133
|
if (opts.status) p.set("status", opts.status);
|
|
134
|
+
if (opts.cursor) p.set("cursor", opts.cursor);
|
|
128
135
|
return request("GET", `/tasks?${p}`);
|
|
129
136
|
}
|
|
130
137
|
|
package/src/mcp.ts
CHANGED
|
@@ -234,12 +234,13 @@ server.registerTool("capy_list", {
|
|
|
234
234
|
inputSchema: {
|
|
235
235
|
status: z.string().optional().describe("Filter by status"),
|
|
236
236
|
limit: z.number().optional().describe("Max results (default 30)"),
|
|
237
|
+
cursor: z.string().optional().describe("Pagination cursor from previous response"),
|
|
237
238
|
},
|
|
238
239
|
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
239
|
-
}, async ({ status, limit }) => {
|
|
240
|
+
}, async ({ status, limit, cursor }) => {
|
|
240
241
|
try {
|
|
241
|
-
const data = await api.listTasks({ status, limit: limit || 30 });
|
|
242
|
-
return text(data.items || []);
|
|
242
|
+
const data = await api.listTasks({ status, limit: limit || 30, cursor });
|
|
243
|
+
return text({ items: data.items || [], nextCursor: data.nextCursor, hasMore: data.hasMore });
|
|
243
244
|
} catch (e) { return err(e); }
|
|
244
245
|
});
|
|
245
246
|
|
|
@@ -247,12 +248,13 @@ server.registerTool("capy_threads", {
|
|
|
247
248
|
description: "List Captain threads",
|
|
248
249
|
inputSchema: {
|
|
249
250
|
limit: z.number().optional().describe("Max results (default 10)"),
|
|
251
|
+
cursor: z.string().optional().describe("Pagination cursor from previous response"),
|
|
250
252
|
},
|
|
251
253
|
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
252
|
-
}, async ({ limit }) => {
|
|
254
|
+
}, async ({ limit, cursor }) => {
|
|
253
255
|
try {
|
|
254
|
-
const data = await api.listThreads({ limit: limit || 10 });
|
|
255
|
-
return text(data.items || []);
|
|
256
|
+
const data = await api.listThreads({ limit: limit || 10, cursor });
|
|
257
|
+
return text({ items: data.items || [], nextCursor: data.nextCursor, hasMore: data.hasMore });
|
|
256
258
|
} catch (e) { return err(e); }
|
|
257
259
|
});
|
|
258
260
|
|
|
@@ -315,6 +317,61 @@ server.registerTool("capy_pr", {
|
|
|
315
317
|
} catch (e) { return err(e); }
|
|
316
318
|
});
|
|
317
319
|
|
|
320
|
+
server.registerTool("capy_start", {
|
|
321
|
+
description: "Start a backlog task (resume a task that was created but not yet running)",
|
|
322
|
+
inputSchema: {
|
|
323
|
+
id: z.string().describe("Task ID"),
|
|
324
|
+
model: z.string().optional().describe("Model ID override"),
|
|
325
|
+
},
|
|
326
|
+
annotations: { openWorldHint: true },
|
|
327
|
+
}, async ({ id, model }) => {
|
|
328
|
+
try {
|
|
329
|
+
const data = await api.startTask(id, model);
|
|
330
|
+
return text(data);
|
|
331
|
+
} catch (e) { return err(e); }
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
server.registerTool("capy_thread_messages", {
|
|
335
|
+
description: "Read the conversation history of a Captain thread",
|
|
336
|
+
inputSchema: {
|
|
337
|
+
id: z.string().describe("Thread ID"),
|
|
338
|
+
limit: z.number().optional().describe("Max messages (default 50)"),
|
|
339
|
+
},
|
|
340
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
341
|
+
}, async ({ id, limit }) => {
|
|
342
|
+
try {
|
|
343
|
+
const data = await api.getThreadMessages(id, { limit: limit || 50 });
|
|
344
|
+
return text(data.items || []);
|
|
345
|
+
} catch (e) { return err(e); }
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
server.registerTool("capy_re_review", {
|
|
349
|
+
description: "Trigger a fresh Greptile code review on a task's PR",
|
|
350
|
+
inputSchema: {
|
|
351
|
+
id: z.string().describe("Task ID"),
|
|
352
|
+
},
|
|
353
|
+
annotations: { openWorldHint: true },
|
|
354
|
+
}, async ({ id }) => {
|
|
355
|
+
try {
|
|
356
|
+
const greptileApi = await import("./greptile.js");
|
|
357
|
+
const task = await api.getTask(id);
|
|
358
|
+
const cfg = config.load();
|
|
359
|
+
|
|
360
|
+
if (!task.pullRequest?.number) {
|
|
361
|
+
return { content: [{ type: "text" as const, text: JSON.stringify({ error: { code: "no_pr", message: `Task ${task.identifier} has no PR` } }) }], isError: true as const };
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const repo = task.pullRequest.repoFullName || cfg.repos[0]?.repoFullName || "";
|
|
365
|
+
const prNum = task.pullRequest.number;
|
|
366
|
+
const defaultBranch = cfg.repos.find((r: { repoFullName: string; branch: string }) => r.repoFullName === repo)?.branch || "main";
|
|
367
|
+
|
|
368
|
+
const result = await greptileApi.freshReview(repo, prNum, defaultBranch);
|
|
369
|
+
const unaddressed = await greptileApi.getUnaddressedIssues(repo, prNum, defaultBranch);
|
|
370
|
+
|
|
371
|
+
return text({ task: task.identifier, pr: prNum, reviewStatus: result?.status || "triggered", unaddressed });
|
|
372
|
+
} catch (e) { return err(e); }
|
|
373
|
+
});
|
|
374
|
+
|
|
318
375
|
server.registerTool("capy_models", {
|
|
319
376
|
description: "List available AI models",
|
|
320
377
|
inputSchema: {},
|
package/src/types.ts
CHANGED
|
@@ -31,9 +31,16 @@ export interface Credits {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export interface Jam {
|
|
34
|
+
id?: string;
|
|
34
35
|
model?: string;
|
|
35
36
|
status?: string;
|
|
36
37
|
credits?: Credits | number;
|
|
38
|
+
pullRequest?: PullRequestRef;
|
|
39
|
+
branches?: Record<string, unknown>;
|
|
40
|
+
git?: unknown;
|
|
41
|
+
slackThreads?: unknown[];
|
|
42
|
+
createdAt?: string;
|
|
43
|
+
updatedAt?: string;
|
|
37
44
|
}
|
|
38
45
|
|
|
39
46
|
export interface PullRequestRef {
|
|
@@ -48,21 +55,29 @@ export interface PullRequestRef {
|
|
|
48
55
|
|
|
49
56
|
export interface Task {
|
|
50
57
|
id: string;
|
|
58
|
+
projectId?: string;
|
|
51
59
|
identifier: string;
|
|
52
60
|
title: string;
|
|
53
61
|
status: string;
|
|
54
62
|
prompt?: string;
|
|
55
|
-
|
|
63
|
+
labels?: string[];
|
|
56
64
|
pullRequest?: PullRequestRef;
|
|
65
|
+
slackThreads?: unknown[];
|
|
66
|
+
createdAt?: string;
|
|
67
|
+
updatedAt?: string;
|
|
57
68
|
jams?: Jam[];
|
|
58
69
|
}
|
|
59
70
|
|
|
60
71
|
export interface Thread {
|
|
61
72
|
id: string;
|
|
73
|
+
projectId?: string;
|
|
62
74
|
title?: string;
|
|
63
75
|
status: string;
|
|
64
76
|
tasks?: Task[];
|
|
65
77
|
pullRequests?: PullRequestRef[];
|
|
78
|
+
slackThreads?: unknown[];
|
|
79
|
+
createdAt?: string;
|
|
80
|
+
updatedAt?: string;
|
|
66
81
|
}
|
|
67
82
|
|
|
68
83
|
export interface ThreadMessage {
|
|
@@ -178,5 +193,7 @@ export interface ApiResponse {
|
|
|
178
193
|
|
|
179
194
|
export interface ListResponse<T> {
|
|
180
195
|
items?: T[];
|
|
196
|
+
nextCursor?: string;
|
|
197
|
+
hasMore?: boolean;
|
|
181
198
|
[key: string]: unknown;
|
|
182
199
|
}
|