@schoolai/shipyard-mcp 0.4.0 → 0.4.1-nightly.20260127
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 +13 -9
- package/apps/server/dist/index.js +193 -117
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -47,7 +47,11 @@ Shipyard is just an MCP server. One command or a simple JSON config—works with
|
|
|
47
47
|
Full experience with hooks, skills, and auto-task creation:
|
|
48
48
|
|
|
49
49
|
```bash
|
|
50
|
-
|
|
50
|
+
# Step 1: Add the marketplace
|
|
51
|
+
/plugin marketplace add https://github.com/SchoolAI/shipyard.git
|
|
52
|
+
|
|
53
|
+
# Step 2: Install the plugin
|
|
54
|
+
/plugin install shipyard@schoolai-shipyard
|
|
51
55
|
```
|
|
52
56
|
|
|
53
57
|
### Cursor
|
|
@@ -59,7 +63,7 @@ Add to `~/.cursor/mcp.json`:
|
|
|
59
63
|
"mcpServers": {
|
|
60
64
|
"shipyard": {
|
|
61
65
|
"command": "npx",
|
|
62
|
-
"args": ["-y", "@schoolai/shipyard-mcp@latest"]
|
|
66
|
+
"args": ["-y", "-p", "@schoolai/shipyard-mcp@latest", "mcp-server-shipyard"]
|
|
63
67
|
}
|
|
64
68
|
}
|
|
65
69
|
}
|
|
@@ -70,7 +74,7 @@ Add to `~/.cursor/mcp.json`:
|
|
|
70
74
|
Add via CLI:
|
|
71
75
|
|
|
72
76
|
```bash
|
|
73
|
-
codex mcp add shipyard -- npx -y @schoolai/shipyard-mcp@latest
|
|
77
|
+
codex mcp add shipyard -- npx -y -p @schoolai/shipyard-mcp@latest mcp-server-shipyard
|
|
74
78
|
```
|
|
75
79
|
|
|
76
80
|
Or add to `~/.codex/config.toml`:
|
|
@@ -78,13 +82,13 @@ Or add to `~/.codex/config.toml`:
|
|
|
78
82
|
```toml
|
|
79
83
|
[mcp_servers.shipyard]
|
|
80
84
|
command = "npx"
|
|
81
|
-
args = ["-y", "@schoolai/shipyard-mcp@latest"]
|
|
85
|
+
args = ["-y", "-p", "@schoolai/shipyard-mcp@latest", "mcp-server-shipyard"]
|
|
82
86
|
```
|
|
83
87
|
|
|
84
88
|
### VS Code / GitHub Copilot
|
|
85
89
|
|
|
86
90
|
```bash
|
|
87
|
-
code --add-mcp '{"name":"shipyard","command":"npx","args":["-y","@schoolai/shipyard-mcp@latest"]}'
|
|
91
|
+
code --add-mcp '{"name":"shipyard","command":"npx","args":["-y","-p","@schoolai/shipyard-mcp@latest","mcp-server-shipyard"]}'
|
|
88
92
|
```
|
|
89
93
|
|
|
90
94
|
<details>
|
|
@@ -102,7 +106,7 @@ Add to your config file:
|
|
|
102
106
|
"mcpServers": {
|
|
103
107
|
"shipyard": {
|
|
104
108
|
"command": "npx",
|
|
105
|
-
"args": ["-y", "@schoolai/shipyard-mcp@latest"]
|
|
109
|
+
"args": ["-y", "-p", "@schoolai/shipyard-mcp@latest", "mcp-server-shipyard"]
|
|
106
110
|
}
|
|
107
111
|
}
|
|
108
112
|
}
|
|
@@ -117,7 +121,7 @@ Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
|
117
121
|
"mcpServers": {
|
|
118
122
|
"shipyard": {
|
|
119
123
|
"command": "npx",
|
|
120
|
-
"args": ["-y", "@schoolai/shipyard-mcp@latest"]
|
|
124
|
+
"args": ["-y", "-p", "@schoolai/shipyard-mcp@latest", "mcp-server-shipyard"]
|
|
121
125
|
}
|
|
122
126
|
}
|
|
123
127
|
}
|
|
@@ -139,7 +143,7 @@ Add to `~/.config/zed/settings.json`:
|
|
|
139
143
|
"shipyard": {
|
|
140
144
|
"command": {
|
|
141
145
|
"path": "npx",
|
|
142
|
-
"args": ["-y", "@schoolai/shipyard-mcp@latest"]
|
|
146
|
+
"args": ["-y", "-p", "@schoolai/shipyard-mcp@latest", "mcp-server-shipyard"]
|
|
143
147
|
}
|
|
144
148
|
}
|
|
145
149
|
}
|
|
@@ -154,7 +158,7 @@ Create `.continue/mcpServers/shipyard.yaml`:
|
|
|
154
158
|
mcpServers:
|
|
155
159
|
- name: Shipyard
|
|
156
160
|
command: npx
|
|
157
|
-
args: ["-y", "@schoolai/shipyard-mcp@latest"]
|
|
161
|
+
args: ["-y", "-p", "@schoolai/shipyard-mcp@latest", "mcp-server-shipyard"]
|
|
158
162
|
```
|
|
159
163
|
|
|
160
164
|
</details>
|
|
@@ -81,7 +81,7 @@ import * as os from "os";
|
|
|
81
81
|
import * as path from "path";
|
|
82
82
|
import * as vm from "vm";
|
|
83
83
|
import ffmpegInstaller from "@ffmpeg-installer/ffmpeg";
|
|
84
|
-
import { z as
|
|
84
|
+
import { z as z13 } from "zod";
|
|
85
85
|
|
|
86
86
|
// src/tools/add-artifact.ts
|
|
87
87
|
import { writeFile as writeFile2 } from "fs/promises";
|
|
@@ -1360,8 +1360,63 @@ Make sure:
|
|
|
1360
1360
|
}
|
|
1361
1361
|
};
|
|
1362
1362
|
|
|
1363
|
-
// src/tools/
|
|
1363
|
+
// src/tools/post-update.ts
|
|
1364
1364
|
import { z as z6 } from "zod";
|
|
1365
|
+
var PostUpdateInput = z6.object({
|
|
1366
|
+
taskId: z6.string().describe("The task ID"),
|
|
1367
|
+
sessionToken: z6.string().describe("Session token from plan approval"),
|
|
1368
|
+
message: z6.string().describe("Update content (markdown)")
|
|
1369
|
+
});
|
|
1370
|
+
function errorResponse2(message) {
|
|
1371
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
1372
|
+
}
|
|
1373
|
+
function successResponse2(message) {
|
|
1374
|
+
return { content: [{ type: "text", text: message }] };
|
|
1375
|
+
}
|
|
1376
|
+
var postUpdateTool = {
|
|
1377
|
+
definition: {
|
|
1378
|
+
name: TOOL_NAMES.POST_UPDATE,
|
|
1379
|
+
description: `Post a progress update to the task timeline.
|
|
1380
|
+
|
|
1381
|
+
Use this to communicate status updates to humans watching your work:
|
|
1382
|
+
- "Starting work on authentication module"
|
|
1383
|
+
- "Milestone: API integration complete"
|
|
1384
|
+
- "Found edge case with rate limiting, investigating"
|
|
1385
|
+
|
|
1386
|
+
Updates appear in the Activity tab and keep reviewers informed.`,
|
|
1387
|
+
inputSchema: {
|
|
1388
|
+
type: "object",
|
|
1389
|
+
properties: {
|
|
1390
|
+
taskId: { type: "string", description: "The task ID" },
|
|
1391
|
+
sessionToken: { type: "string", description: "Session token from plan approval" },
|
|
1392
|
+
message: { type: "string", description: "Update content (markdown supported)" }
|
|
1393
|
+
},
|
|
1394
|
+
required: ["taskId", "sessionToken", "message"]
|
|
1395
|
+
}
|
|
1396
|
+
},
|
|
1397
|
+
handler: async (args) => {
|
|
1398
|
+
const input = PostUpdateInput.parse(args);
|
|
1399
|
+
const { taskId, sessionToken, message } = input;
|
|
1400
|
+
const doc = await getOrCreateDoc(taskId);
|
|
1401
|
+
const metadata = getPlanMetadata(doc);
|
|
1402
|
+
if (!metadata) {
|
|
1403
|
+
return errorResponse2(`Task "${taskId}" not found.`);
|
|
1404
|
+
}
|
|
1405
|
+
if (!metadata.sessionTokenHash || !verifySessionToken(sessionToken, metadata.sessionTokenHash)) {
|
|
1406
|
+
return errorResponse2(`Invalid session token for task "${taskId}".`);
|
|
1407
|
+
}
|
|
1408
|
+
const actorName = await getGitHubUsername();
|
|
1409
|
+
const eventId = logPlanEvent(doc, "agent_activity", actorName, {
|
|
1410
|
+
activityType: "update",
|
|
1411
|
+
message
|
|
1412
|
+
});
|
|
1413
|
+
logger.info({ taskId, eventId, messageLength: message.length }, "Agent update posted");
|
|
1414
|
+
return successResponse2(`Update posted to task "${taskId}".`);
|
|
1415
|
+
}
|
|
1416
|
+
};
|
|
1417
|
+
|
|
1418
|
+
// src/tools/read-diff-comments.ts
|
|
1419
|
+
import { z as z7 } from "zod";
|
|
1365
1420
|
function getStalenessContext(doc) {
|
|
1366
1421
|
const planMetadata = getPlanMetadata(doc);
|
|
1367
1422
|
const cwd = extractCwdFromMetadata(planMetadata);
|
|
@@ -1389,12 +1444,12 @@ function extractCwdFromMetadata(metadata) {
|
|
|
1389
1444
|
}
|
|
1390
1445
|
return void 0;
|
|
1391
1446
|
}
|
|
1392
|
-
var ReadDiffCommentsInput =
|
|
1393
|
-
taskId:
|
|
1394
|
-
sessionToken:
|
|
1395
|
-
includeLocal:
|
|
1396
|
-
includePR:
|
|
1397
|
-
includeResolved:
|
|
1447
|
+
var ReadDiffCommentsInput = z7.object({
|
|
1448
|
+
taskId: z7.string().describe("The task ID to read diff comments from"),
|
|
1449
|
+
sessionToken: z7.string().describe("Session token from create_task"),
|
|
1450
|
+
includeLocal: z7.boolean().optional().describe("Include local (uncommitted) diff comments (default: true)"),
|
|
1451
|
+
includePR: z7.boolean().optional().describe("Include PR review diff comments (default: true)"),
|
|
1452
|
+
includeResolved: z7.boolean().optional().describe("Include resolved comments (default: false)")
|
|
1398
1453
|
});
|
|
1399
1454
|
var readDiffCommentsTool = {
|
|
1400
1455
|
definition: {
|
|
@@ -1495,7 +1550,7 @@ OUTPUT FORMAT:
|
|
|
1495
1550
|
};
|
|
1496
1551
|
|
|
1497
1552
|
// src/tools/read-task.ts
|
|
1498
|
-
import { z as
|
|
1553
|
+
import { z as z8 } from "zod";
|
|
1499
1554
|
|
|
1500
1555
|
// src/export-markdown.ts
|
|
1501
1556
|
import { ServerBlockNoteEditor as ServerBlockNoteEditor4 } from "@blocknote/server-util";
|
|
@@ -1757,12 +1812,12 @@ function formatResponseValue(response) {
|
|
|
1757
1812
|
}
|
|
1758
1813
|
|
|
1759
1814
|
// src/tools/read-task.ts
|
|
1760
|
-
var ReadTaskInput =
|
|
1761
|
-
taskId:
|
|
1762
|
-
sessionToken:
|
|
1763
|
-
includeAnnotations:
|
|
1764
|
-
includeLinkedPRs:
|
|
1765
|
-
includePRComments:
|
|
1815
|
+
var ReadTaskInput = z8.object({
|
|
1816
|
+
taskId: z8.string().describe("The task ID to read"),
|
|
1817
|
+
sessionToken: z8.string().describe("Session token from create_task"),
|
|
1818
|
+
includeAnnotations: z8.boolean().optional().describe("Include comment threads/annotations in the response (default: false)"),
|
|
1819
|
+
includeLinkedPRs: z8.boolean().optional().describe("Include linked PRs section in the response (default: false)"),
|
|
1820
|
+
includePRComments: z8.boolean().optional().describe(
|
|
1766
1821
|
"Include inline PR review comments (diff line comments) in the response (default: false)"
|
|
1767
1822
|
)
|
|
1768
1823
|
});
|
|
@@ -1887,9 +1942,9 @@ OUTPUT INCLUDES:
|
|
|
1887
1942
|
};
|
|
1888
1943
|
|
|
1889
1944
|
// src/tools/regenerate-session-token.ts
|
|
1890
|
-
import { z as
|
|
1891
|
-
var RegenerateSessionTokenInput =
|
|
1892
|
-
taskId:
|
|
1945
|
+
import { z as z9 } from "zod";
|
|
1946
|
+
var RegenerateSessionTokenInput = z9.object({
|
|
1947
|
+
taskId: z9.string().describe("The task ID to regenerate token for")
|
|
1893
1948
|
});
|
|
1894
1949
|
var regenerateSessionTokenTool = {
|
|
1895
1950
|
definition: {
|
|
@@ -2022,10 +2077,10 @@ Use this token for add_artifact, read_task, link_pr, and other task operations.`
|
|
|
2022
2077
|
};
|
|
2023
2078
|
|
|
2024
2079
|
// src/tools/setup-review-notification.ts
|
|
2025
|
-
import { z as
|
|
2026
|
-
var SetupReviewNotificationInput =
|
|
2027
|
-
taskId:
|
|
2028
|
-
pollIntervalSeconds:
|
|
2080
|
+
import { z as z10 } from "zod";
|
|
2081
|
+
var SetupReviewNotificationInput = z10.object({
|
|
2082
|
+
taskId: z10.string().describe("Task ID to monitor"),
|
|
2083
|
+
pollIntervalSeconds: z10.number().optional().default(30).describe("Polling interval in seconds (default: 30)")
|
|
2029
2084
|
});
|
|
2030
2085
|
var setupReviewNotificationTool = {
|
|
2031
2086
|
definition: {
|
|
@@ -2143,31 +2198,31 @@ The script:
|
|
|
2143
2198
|
|
|
2144
2199
|
// src/tools/update-block-content.ts
|
|
2145
2200
|
import { ServerBlockNoteEditor as ServerBlockNoteEditor5 } from "@blocknote/server-util";
|
|
2146
|
-
import { z as
|
|
2147
|
-
var BlockOperationSchema =
|
|
2148
|
-
|
|
2149
|
-
type:
|
|
2150
|
-
blockId:
|
|
2151
|
-
content:
|
|
2201
|
+
import { z as z11 } from "zod";
|
|
2202
|
+
var BlockOperationSchema = z11.discriminatedUnion("type", [
|
|
2203
|
+
z11.object({
|
|
2204
|
+
type: z11.literal("update"),
|
|
2205
|
+
blockId: z11.string().describe("The block ID to update (from read_plan output)"),
|
|
2206
|
+
content: z11.string().describe("New markdown content for this block")
|
|
2152
2207
|
}),
|
|
2153
|
-
|
|
2154
|
-
type:
|
|
2155
|
-
afterBlockId:
|
|
2156
|
-
content:
|
|
2208
|
+
z11.object({
|
|
2209
|
+
type: z11.literal("insert"),
|
|
2210
|
+
afterBlockId: z11.string().nullable().describe("Insert after this block ID (null = insert at beginning)"),
|
|
2211
|
+
content: z11.string().describe("Markdown content to insert as new block(s)")
|
|
2157
2212
|
}),
|
|
2158
|
-
|
|
2159
|
-
type:
|
|
2160
|
-
blockId:
|
|
2213
|
+
z11.object({
|
|
2214
|
+
type: z11.literal("delete"),
|
|
2215
|
+
blockId: z11.string().describe("The block ID to delete")
|
|
2161
2216
|
}),
|
|
2162
|
-
|
|
2163
|
-
type:
|
|
2164
|
-
content:
|
|
2217
|
+
z11.object({
|
|
2218
|
+
type: z11.literal("replace_all"),
|
|
2219
|
+
content: z11.string().describe("Complete markdown content to replace the entire plan")
|
|
2165
2220
|
})
|
|
2166
2221
|
]);
|
|
2167
|
-
var UpdateBlockContentInput =
|
|
2168
|
-
taskId:
|
|
2169
|
-
sessionToken:
|
|
2170
|
-
operations:
|
|
2222
|
+
var UpdateBlockContentInput = z11.object({
|
|
2223
|
+
taskId: z11.string().describe("The task ID to modify"),
|
|
2224
|
+
sessionToken: z11.string().describe("Session token from create_task"),
|
|
2225
|
+
operations: z11.array(BlockOperationSchema).min(1).describe("Array of operations to perform atomically")
|
|
2171
2226
|
});
|
|
2172
2227
|
var updateBlockContentTool = {
|
|
2173
2228
|
definition: {
|
|
@@ -2429,7 +2484,7 @@ async function applyOperation(blocks, operation, editor) {
|
|
|
2429
2484
|
// src/tools/update-task.ts
|
|
2430
2485
|
import { ServerBlockNoteEditor as ServerBlockNoteEditor6 } from "@blocknote/server-util";
|
|
2431
2486
|
import { nanoid as nanoid3 } from "nanoid";
|
|
2432
|
-
import { z as
|
|
2487
|
+
import { z as z12 } from "zod";
|
|
2433
2488
|
function buildStatusTransition(targetStatus, actorName) {
|
|
2434
2489
|
const now = Date.now();
|
|
2435
2490
|
switch (targetStatus) {
|
|
@@ -2462,12 +2517,12 @@ function buildStatusTransition(targetStatus, actorName) {
|
|
|
2462
2517
|
return null;
|
|
2463
2518
|
}
|
|
2464
2519
|
}
|
|
2465
|
-
var UpdateTaskInput =
|
|
2466
|
-
taskId:
|
|
2467
|
-
sessionToken:
|
|
2468
|
-
title:
|
|
2469
|
-
status:
|
|
2470
|
-
tags:
|
|
2520
|
+
var UpdateTaskInput = z12.object({
|
|
2521
|
+
taskId: z12.string().describe("The task ID to update"),
|
|
2522
|
+
sessionToken: z12.string().describe("Session token from create_task"),
|
|
2523
|
+
title: z12.string().optional().describe("New title"),
|
|
2524
|
+
status: z12.enum(["draft", "pending_review", "changes_requested", "in_progress", "completed"]).optional().describe("New status"),
|
|
2525
|
+
tags: z12.array(z12.string()).optional().describe("Updated tags (replaces existing tags)")
|
|
2471
2526
|
});
|
|
2472
2527
|
var updateTaskTool = {
|
|
2473
2528
|
definition: {
|
|
@@ -2622,15 +2677,50 @@ STATUSES:
|
|
|
2622
2677
|
|
|
2623
2678
|
// src/tools/execute-code.ts
|
|
2624
2679
|
function getToolResultText(result) {
|
|
2680
|
+
if (!result || !Array.isArray(result.content)) return "";
|
|
2625
2681
|
const first = result.content[0];
|
|
2626
2682
|
if (!first || typeof first !== "object") return "";
|
|
2627
2683
|
const record = Object.fromEntries(Object.entries(first));
|
|
2628
2684
|
const text = record.text;
|
|
2629
2685
|
return typeof text === "string" ? text : "";
|
|
2630
2686
|
}
|
|
2687
|
+
async function serializeError(error) {
|
|
2688
|
+
const { z: z14 } = await import("zod");
|
|
2689
|
+
if (error instanceof z14.ZodError) {
|
|
2690
|
+
const formattedIssues = error.issues.map((issue) => ` - ${issue.path.join(".")}: ${issue.message}`).join("\n");
|
|
2691
|
+
const message2 = `Validation error:
|
|
2692
|
+
${formattedIssues}`;
|
|
2693
|
+
return {
|
|
2694
|
+
details: { name: "ZodError", message: message2, issues: error.issues, stack: error.stack },
|
|
2695
|
+
message: message2,
|
|
2696
|
+
stack: error.stack
|
|
2697
|
+
};
|
|
2698
|
+
}
|
|
2699
|
+
if (error instanceof Error) {
|
|
2700
|
+
return {
|
|
2701
|
+
details: {
|
|
2702
|
+
name: error.name,
|
|
2703
|
+
message: error.message,
|
|
2704
|
+
stack: error.stack,
|
|
2705
|
+
cause: error.cause instanceof Error ? error.cause.message : error.cause
|
|
2706
|
+
},
|
|
2707
|
+
message: error.message,
|
|
2708
|
+
stack: error.stack
|
|
2709
|
+
};
|
|
2710
|
+
}
|
|
2711
|
+
if (error && typeof error === "object") {
|
|
2712
|
+
const message2 = "message" in error && typeof error.message === "string" ? error.message : JSON.stringify(error).slice(0, 500) || "Unknown error";
|
|
2713
|
+
return {
|
|
2714
|
+
details: { raw: JSON.stringify(error).slice(0, 1e3) },
|
|
2715
|
+
message: message2
|
|
2716
|
+
};
|
|
2717
|
+
}
|
|
2718
|
+
const message = String(error) || "Unknown error";
|
|
2719
|
+
return { details: { raw: message }, message };
|
|
2720
|
+
}
|
|
2631
2721
|
var BUNDLED_DOCS = `Execute TypeScript code that calls Shipyard APIs. Use this for multi-step workflows to reduce round-trips.
|
|
2632
2722
|
|
|
2633
|
-
\u26A0\uFE0F IMPORTANT LIMITATION: Dynamic imports (\`await import()\`) are NOT supported in the VM execution context. Use only the pre-provided functions in the execution environment (createTask, readTask, readDiffComments, updateTask, addArtifact, completeTask, updateBlockContent, linkPR, requestUserInput, regenerateSessionToken). All necessary APIs are already available in the sandbox.
|
|
2723
|
+
\u26A0\uFE0F IMPORTANT LIMITATION: Dynamic imports (\`await import()\`) are NOT supported in the VM execution context. Use only the pre-provided functions in the execution environment (createTask, readTask, readDiffComments, updateTask, addArtifact, completeTask, updateBlockContent, linkPR, requestUserInput, regenerateSessionToken, postUpdate). All necessary APIs are already available in the sandbox.
|
|
2634
2724
|
|
|
2635
2725
|
## Available APIs
|
|
2636
2726
|
|
|
@@ -3087,6 +3177,40 @@ await addArtifact({
|
|
|
3087
3177
|
|
|
3088
3178
|
---
|
|
3089
3179
|
|
|
3180
|
+
### postUpdate(opts): Promise<{ success, isError?, error? }>
|
|
3181
|
+
Post a progress update to the task timeline.
|
|
3182
|
+
|
|
3183
|
+
Use this to communicate status updates to humans watching your work:
|
|
3184
|
+
- "Starting work on authentication module"
|
|
3185
|
+
- "Milestone: API integration complete"
|
|
3186
|
+
- "Found edge case with rate limiting, investigating"
|
|
3187
|
+
|
|
3188
|
+
Updates appear in the Activity tab and keep reviewers informed.
|
|
3189
|
+
|
|
3190
|
+
Parameters:
|
|
3191
|
+
- taskId (string): The task ID
|
|
3192
|
+
- sessionToken (string): Session token from createTask
|
|
3193
|
+
- message (string): Update content (markdown supported)
|
|
3194
|
+
|
|
3195
|
+
Returns:
|
|
3196
|
+
- success: Boolean indicating update was posted (true on success, false on error)
|
|
3197
|
+
- isError: Boolean indicating if an error occurred
|
|
3198
|
+
- error: Error message (only present when isError is true)
|
|
3199
|
+
|
|
3200
|
+
Example:
|
|
3201
|
+
\`\`\`typescript
|
|
3202
|
+
const result = await postUpdate({
|
|
3203
|
+
taskId,
|
|
3204
|
+
sessionToken,
|
|
3205
|
+
message: "Starting work on authentication module"
|
|
3206
|
+
});
|
|
3207
|
+
if (result.isError) {
|
|
3208
|
+
console.log('Failed:', result.error);
|
|
3209
|
+
}
|
|
3210
|
+
\`\`\`
|
|
3211
|
+
|
|
3212
|
+
---
|
|
3213
|
+
|
|
3090
3214
|
## Common Pattern
|
|
3091
3215
|
|
|
3092
3216
|
\`\`\`typescript
|
|
@@ -3126,8 +3250,8 @@ const result = await addArtifact({
|
|
|
3126
3250
|
return { taskId: task.taskId, snapshotUrl: result.snapshotUrl };
|
|
3127
3251
|
\`\`\`
|
|
3128
3252
|
`;
|
|
3129
|
-
var ExecuteCodeInput =
|
|
3130
|
-
code:
|
|
3253
|
+
var ExecuteCodeInput = z13.object({
|
|
3254
|
+
code: z13.string().describe("TypeScript code to execute")
|
|
3131
3255
|
});
|
|
3132
3256
|
var scriptTracker = [];
|
|
3133
3257
|
async function createTask(opts) {
|
|
@@ -3423,6 +3547,14 @@ async function regenerateSessionToken(taskId) {
|
|
|
3423
3547
|
taskId
|
|
3424
3548
|
};
|
|
3425
3549
|
}
|
|
3550
|
+
async function postUpdate(opts) {
|
|
3551
|
+
const result = await postUpdateTool.handler(opts);
|
|
3552
|
+
const text = getToolResultText(result);
|
|
3553
|
+
if (result.isError) {
|
|
3554
|
+
return { isError: true, error: text, success: false };
|
|
3555
|
+
}
|
|
3556
|
+
return { isError: false, success: true };
|
|
3557
|
+
}
|
|
3426
3558
|
var executeCodeTool = {
|
|
3427
3559
|
definition: {
|
|
3428
3560
|
name: TOOL_NAMES.EXECUTE_CODE,
|
|
@@ -3484,6 +3616,7 @@ var executeCodeTool = {
|
|
|
3484
3616
|
linkPR: linkPR2,
|
|
3485
3617
|
requestUserInput,
|
|
3486
3618
|
regenerateSessionToken,
|
|
3619
|
+
postUpdate,
|
|
3487
3620
|
encodeVideo,
|
|
3488
3621
|
child_process,
|
|
3489
3622
|
fs,
|
|
@@ -3528,71 +3661,20 @@ The script will exit when the human approves or requests changes.`
|
|
|
3528
3661
|
}
|
|
3529
3662
|
return { content };
|
|
3530
3663
|
} catch (error) {
|
|
3531
|
-
|
|
3532
|
-
|
|
3664
|
+
const { details, message, stack } = await serializeError(error);
|
|
3665
|
+
logger.error({ error: details, code }, "Code execution failed");
|
|
3666
|
+
const errorText = stack ? `Execution error: ${message}
|
|
3667
|
+
|
|
3668
|
+
Stack trace:
|
|
3669
|
+
${stack}` : `Execution error: ${message}`;
|
|
3533
3670
|
return {
|
|
3534
|
-
content: [{ type: "text", text:
|
|
3671
|
+
content: [{ type: "text", text: errorText }],
|
|
3535
3672
|
isError: true
|
|
3536
3673
|
};
|
|
3537
3674
|
}
|
|
3538
3675
|
}
|
|
3539
3676
|
};
|
|
3540
3677
|
|
|
3541
|
-
// src/tools/post-update.ts
|
|
3542
|
-
import { z as z13 } from "zod";
|
|
3543
|
-
var PostUpdateInput = z13.object({
|
|
3544
|
-
taskId: z13.string().describe("The task ID"),
|
|
3545
|
-
sessionToken: z13.string().describe("Session token from plan approval"),
|
|
3546
|
-
message: z13.string().describe("Update content (markdown)")
|
|
3547
|
-
});
|
|
3548
|
-
function errorResponse2(message) {
|
|
3549
|
-
return { content: [{ type: "text", text: message }], isError: true };
|
|
3550
|
-
}
|
|
3551
|
-
function successResponse2(message) {
|
|
3552
|
-
return { content: [{ type: "text", text: message }] };
|
|
3553
|
-
}
|
|
3554
|
-
var postUpdateTool = {
|
|
3555
|
-
definition: {
|
|
3556
|
-
name: TOOL_NAMES.POST_UPDATE,
|
|
3557
|
-
description: `Post a progress update to the task timeline.
|
|
3558
|
-
|
|
3559
|
-
Use this to communicate status updates to humans watching your work:
|
|
3560
|
-
- "Starting work on authentication module"
|
|
3561
|
-
- "Milestone: API integration complete"
|
|
3562
|
-
- "Found edge case with rate limiting, investigating"
|
|
3563
|
-
|
|
3564
|
-
Updates appear in the Activity tab and keep reviewers informed.`,
|
|
3565
|
-
inputSchema: {
|
|
3566
|
-
type: "object",
|
|
3567
|
-
properties: {
|
|
3568
|
-
taskId: { type: "string", description: "The task ID" },
|
|
3569
|
-
sessionToken: { type: "string", description: "Session token from plan approval" },
|
|
3570
|
-
message: { type: "string", description: "Update content (markdown supported)" }
|
|
3571
|
-
},
|
|
3572
|
-
required: ["taskId", "sessionToken", "message"]
|
|
3573
|
-
}
|
|
3574
|
-
},
|
|
3575
|
-
handler: async (args) => {
|
|
3576
|
-
const input = PostUpdateInput.parse(args);
|
|
3577
|
-
const { taskId, sessionToken, message } = input;
|
|
3578
|
-
const doc = await getOrCreateDoc(taskId);
|
|
3579
|
-
const metadata = getPlanMetadata(doc);
|
|
3580
|
-
if (!metadata) {
|
|
3581
|
-
return errorResponse2(`Task "${taskId}" not found.`);
|
|
3582
|
-
}
|
|
3583
|
-
if (!metadata.sessionTokenHash || !verifySessionToken(sessionToken, metadata.sessionTokenHash)) {
|
|
3584
|
-
return errorResponse2(`Invalid session token for task "${taskId}".`);
|
|
3585
|
-
}
|
|
3586
|
-
const actorName = await getGitHubUsername();
|
|
3587
|
-
const eventId = logPlanEvent(doc, "agent_activity", actorName, {
|
|
3588
|
-
activityType: "update",
|
|
3589
|
-
message
|
|
3590
|
-
});
|
|
3591
|
-
logger.info({ taskId, eventId, messageLength: message.length }, "Agent update posted");
|
|
3592
|
-
return successResponse2(`Update posted to task "${taskId}".`);
|
|
3593
|
-
}
|
|
3594
|
-
};
|
|
3595
|
-
|
|
3596
3678
|
// src/index.ts
|
|
3597
3679
|
var registryPort = await isRegistryRunning();
|
|
3598
3680
|
if (!registryPort) {
|
|
@@ -3637,19 +3719,13 @@ var server = new Server(
|
|
|
3637
3719
|
}
|
|
3638
3720
|
);
|
|
3639
3721
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
3640
|
-
tools: [executeCodeTool.definition
|
|
3722
|
+
tools: [executeCodeTool.definition]
|
|
3641
3723
|
}));
|
|
3642
3724
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
3643
3725
|
const { name, arguments: args } = request.params;
|
|
3644
3726
|
if (name === TOOL_NAMES.EXECUTE_CODE) {
|
|
3645
3727
|
return await executeCodeTool.handler(args ?? {});
|
|
3646
3728
|
}
|
|
3647
|
-
if (name === TOOL_NAMES.POST_UPDATE) {
|
|
3648
|
-
return await postUpdateTool.handler(args ?? {});
|
|
3649
|
-
}
|
|
3650
|
-
if (name === TOOL_NAMES.READ_DIFF_COMMENTS) {
|
|
3651
|
-
return await readDiffCommentsTool.handler(args ?? {});
|
|
3652
|
-
}
|
|
3653
3729
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
3654
3730
|
});
|
|
3655
3731
|
var transport = new StdioServerTransport();
|