@akira-tl/forgerelay 0.3.3 → 0.3.5
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/CHANGELOG.md +24 -0
- package/README.md +2 -2
- package/capabilities/artifacts-review/GUIDE.md +2 -4
- package/capabilities/managed-worktrees/GUIDE.md +12 -7
- package/capabilities/shell-processes/GUIDE.md +10 -8
- package/dist/artifact-tools.js +0 -128
- package/dist/capabilities.js +4 -7
- package/dist/hooks.js +12 -0
- package/dist/mcp/server-instructions.js +7 -13
- package/dist/review-checkpoints.js +4 -4
- package/dist/server.js +217 -365
- package/dist/ui/.vite/manifest.json +280 -280
- package/dist/ui/assets/{angular-html-CQmCUfkv.js → angular-html-BT2Z6jee.js} +1 -1
- package/dist/ui/assets/{angular-ts-BSbfxpMS.js → angular-ts-BwPE8YDt.js} +1 -1
- package/dist/ui/assets/{apl-CWCaH-E3.js → apl-CGbONVvU.js} +1 -1
- package/dist/ui/assets/{astro-R_p4G0xA.js → astro-DIAPy7cj.js} +1 -1
- package/dist/ui/assets/{blade-irHensDY.js → blade-Cgtd19Ky.js} +1 -1
- package/dist/ui/assets/{c-_XEQUoq6.js → c-acnvZ8tm.js} +1 -1
- package/dist/ui/assets/{cobol-Css6VQjJ.js → cobol-G-7HLVKW.js} +1 -1
- package/dist/ui/assets/{coffee-CpXUkyDm.js → coffee-DQFyKxEB.js} +1 -1
- package/dist/ui/assets/{cpp-BQHsPWwI.js → cpp-UyrmHXan.js} +1 -1
- package/dist/ui/assets/{crystal-Cbv8J9Fm.js → crystal-DuiWhEO3.js} +1 -1
- package/dist/ui/assets/{css-D8DkrS3U.js → css-D_WCbY6m.js} +1 -1
- package/dist/ui/assets/{edge-bBL_XDAG.js → edge-COkalhFi.js} +1 -1
- package/dist/ui/assets/{elixir-CQjsM9sA.js → elixir-cdlzbYR1.js} +1 -1
- package/dist/ui/assets/{elm-DLFl-jEZ.js → elm-ZwDYuYpb.js} +1 -1
- package/dist/ui/assets/{erb-BJjsdB_Q.js → erb-C8WG9TtC.js} +1 -1
- package/dist/ui/assets/{git-rebase-CqP5A2s0.js → git-rebase-CMlDVJBT.js} +1 -1
- package/dist/ui/assets/{glimmer-js-B5Hh_7xe.js → glimmer-js-DeLOQlol.js} +1 -1
- package/dist/ui/assets/{glimmer-ts-oaeSAC8s.js → glimmer-ts-DTEM04TK.js} +1 -1
- package/dist/ui/assets/{glsl-BylkOpcF.js → glsl-IJV4SB-M.js} +1 -1
- package/dist/ui/assets/{graphql-DsVRvP6S.js → graphql-PM-WDnoB.js} +1 -1
- package/dist/ui/assets/{hack-D4N5abT_.js → hack-C14sh6Lh.js} +1 -1
- package/dist/ui/assets/{haml-CIAJQIox.js → haml-B_5nS6Kx.js} +1 -1
- package/dist/ui/assets/{handlebars-DDEZyNXR.js → handlebars-eS-J0O-M.js} +1 -1
- package/dist/ui/assets/{heavy-payload-DafM8yjB.js → heavy-payload-BKB0QDOI.js} +1 -1
- package/dist/ui/assets/{html-zDy-3lvy.js → html-C3TPjrC5.js} +1 -1
- package/dist/ui/assets/{html-derivative-CZ91Y2d5.js → html-derivative-BlVZU2id.js} +1 -1
- package/dist/ui/assets/{http-ezaodZRf.js → http-BmbZzA5x.js} +1 -1
- package/dist/ui/assets/{hurl-BmL0o7TO.js → hurl-Dnd_YpOD.js} +1 -1
- package/dist/ui/assets/{java-Q2C0vwbH.js → java-ne9HdIVn.js} +1 -1
- package/dist/ui/assets/{javascript-UDhBkHE3.js → javascript-DpHT58rr.js} +1 -1
- package/dist/ui/assets/{jinja-BWRskcYS.js → jinja-DTvkZdHA.js} +1 -1
- package/dist/ui/assets/{jison-B18BY9Ds.js → jison-DUJG-tmh.js} +1 -1
- package/dist/ui/assets/{json-DNj7MpRr.js → json-DJmnBdxW.js} +1 -1
- package/dist/ui/assets/{jsx-CVpHJ6cr.js → jsx-BclJnZnN.js} +1 -1
- package/dist/ui/assets/{julia-CJBNBS9c.js → julia-P5B4pHFa.js} +1 -1
- package/dist/ui/assets/{just-Bmu2JCQT.js → just-DYaoh7C6.js} +1 -1
- package/dist/ui/assets/{latex-BB7F93KY.js → latex-CI5lnkWV.js} +1 -1
- package/dist/ui/assets/{liquid-Btnomc6E.js → liquid-D3LnAs_z.js} +1 -1
- package/dist/ui/assets/{lua-D0FYT9Vo.js → lua-dZC7ZQIY.js} +1 -1
- package/dist/ui/assets/{marko-MHLw0ZlK.js → marko-CRDrjqfS.js} +1 -1
- package/dist/ui/assets/{mdc-CSr-suGy.js → mdc-ZzwgmJVn.js} +1 -1
- package/dist/ui/assets/{nginx-ur1l6E-g.js → nginx-BAvFXGSV.js} +1 -1
- package/dist/ui/assets/{nim-B2k0IugA.js → nim-BHIFawe9.js} +1 -1
- package/dist/ui/assets/{perl-BqOHxFDn.js → perl-C_f5AnLa.js} +1 -1
- package/dist/ui/assets/{php-DzPK6O1_.js → php-DDqpegL5.js} +1 -1
- package/dist/ui/assets/{pug-D169OZkr.js → pug-CSaAZXyd.js} +1 -1
- package/dist/ui/assets/{qml-BtemJTC4.js → qml-CNHvRs_z.js} +1 -1
- package/dist/ui/assets/{r-BGVHu0bd.js → r-CAfoQND2.js} +1 -1
- package/dist/ui/assets/{razor-Diisjg1d.js → razor-BDfAPy7I.js} +1 -1
- package/dist/ui/assets/{regexp-B2F5vMZ6.js → regexp-Mug5jltQ.js} +1 -1
- package/dist/ui/assets/{review-payload-B-3I3Oj_.js → review-payload-D7GIdYDj.js} +1 -1
- package/dist/ui/assets/{rst-BxpeZwuT.js → rst-BzPP2gle.js} +1 -1
- package/dist/ui/assets/{ruby-DrCq4riN.js → ruby-CQjzokzX.js} +1 -1
- package/dist/ui/assets/{sas-CI_2W-1n.js → sas-Bp37KGr7.js} +1 -1
- package/dist/ui/assets/{scrollbar-DHsDF5w-.js → scrollbar-HUMBdLLK.js} +3 -3
- package/dist/ui/assets/{scss-BxtyHZ1p.js → scss-C_Z1DYnw.js} +1 -1
- package/dist/ui/assets/{shellscript-BY_YYrHT.js → shellscript-CLfJpn3I.js} +1 -1
- package/dist/ui/assets/{shellsession-C6uBrLmA.js → shellsession-CNc62UhY.js} +1 -1
- package/dist/ui/assets/{soy-BHM9gdPh.js → soy-CF44SpBo.js} +1 -1
- package/dist/ui/assets/{sql-XmhfEGz_.js → sql-CYnzfiQ1.js} +1 -1
- package/dist/ui/assets/{stata-BbHY7NEo.js → stata-DVeMA68W.js} +1 -1
- package/dist/ui/assets/{surrealql-CD49DZ3E.js → surrealql-52sF96Yv.js} +1 -1
- package/dist/ui/assets/{svelte-CbYsEYJY.js → svelte-ydwT7UbF.js} +1 -1
- package/dist/ui/assets/{templ-B5JoUxEB.js → templ-BXcoVoGh.js} +1 -1
- package/dist/ui/assets/{tex-DZcOfTZK.js → tex-COsYFp7O.js} +1 -1
- package/dist/ui/assets/{ts-tags-BeU-xqc0.js → ts-tags-CF--LE1s.js} +1 -1
- package/dist/ui/assets/{tsx-V7W1xGl3.js → tsx-DLBt2-2f.js} +1 -1
- package/dist/ui/assets/{twig-MIaJo5BU.js → twig-YoM-DiI5.js} +1 -1
- package/dist/ui/assets/{typescript-C0WESuVc.js → typescript-Ce9JGkNI.js} +1 -1
- package/dist/ui/assets/{vue-eJHwc9ra.js → vue-B5LDEy4l.js} +1 -1
- package/dist/ui/assets/{vue-html-CLmBujTU.js → vue-html-CPdGGk4T.js} +1 -1
- package/dist/ui/assets/{vue-vine-BP5kjIGb.js → vue-vine-B5bjgk0a.js} +1 -1
- package/dist/ui/assets/{workspace-app-C1qR5cAY.js → workspace-app-Cm9EX5x4.js} +3 -3
- package/dist/ui/assets/{xml-j7pmyP48.js → xml-Cun8xb0T.js} +1 -1
- package/dist/ui/assets/{xsl-5VFHbg6o.js → xsl-wls_CEK_.js} +1 -1
- package/dist/ui/assets/{yaml-DxFAt-KU.js → yaml-BxuXn9OL.js} +1 -1
- package/dist/ui/workspace-app.html +1 -1
- package/docs/artifact-exchange.md +4 -3
- package/docs/chatgpt-coding-workflow.md +31 -27
- package/docs/configuration.md +27 -20
- package/docs/debugging.md +3 -3
- package/docs/gotchas.md +9 -8
- package/docs/security.md +6 -5
- package/package.json +1 -1
- package/scripts/debug/accept.mjs +80 -25
package/dist/server.js
CHANGED
|
@@ -17,7 +17,7 @@ import { applyPatch } from "./apply-patch.js";
|
|
|
17
17
|
import { buildCapabilityFingerprint } from "./capabilities.js";
|
|
18
18
|
import { CapabilityError, createCapabilityRegistry, } from "./capability-registry.js";
|
|
19
19
|
import { deletePath, renamePath } from "./file-mutations.js";
|
|
20
|
-
import { downloadIncomingArtifact, isArtifactDownloadSupportedPlatform,
|
|
20
|
+
import { downloadIncomingArtifact, isArtifactDownloadSupportedPlatform, } from "./artifact-tools.js";
|
|
21
21
|
import { ArtifactError } from "./artifact-error.js";
|
|
22
22
|
import { loadConfig } from "./config.js";
|
|
23
23
|
import { attachHookReports, HookRunner, runToolWithHooks } from "./hooks.js";
|
|
@@ -25,7 +25,7 @@ import { checkHookConfiguration } from "./hook-cli.js";
|
|
|
25
25
|
import { buildServerInstructions, buildShellMutationPolicy, buildToolDescriptions, toolNames, } from "./mcp/server-instructions.js";
|
|
26
26
|
import { createOpenAIIncomingArtifactAdapter, IncomingArtifactAdapterRegistry, } from "./incoming-artifacts.js";
|
|
27
27
|
import { logEvent, requestIp, requestPath, commandPreview, transportSessionIdPrefix, workspaceLogLabel, } from "./logger.js";
|
|
28
|
-
import { editFileTool,
|
|
28
|
+
import { editFileTool, readFileTool, writeFileTool, } from "./pi-tools.js";
|
|
29
29
|
import { SingleUserOAuthProvider } from "./oauth-provider.js";
|
|
30
30
|
import { McpTransportRegistry, } from "./mcp-sessions.js";
|
|
31
31
|
import { ProcessManager, resolveProcessId, } from "./process-sessions.js";
|
|
@@ -67,7 +67,7 @@ function shouldAttachWidget(mode, kind) {
|
|
|
67
67
|
case "off":
|
|
68
68
|
return false;
|
|
69
69
|
case "changes":
|
|
70
|
-
return kind === "workspace" || kind === "
|
|
70
|
+
return kind === "workspace" || kind === "capability";
|
|
71
71
|
case "full":
|
|
72
72
|
return true;
|
|
73
73
|
}
|
|
@@ -461,7 +461,7 @@ function attachCompletedProcessNotices(processSessions, workspaceId, result) {
|
|
|
461
461
|
}
|
|
462
462
|
function processOutputSchema() {
|
|
463
463
|
return resultOutputSchema({
|
|
464
|
-
processId: z.number().int().positive().optional().describe("Canonical process handle for
|
|
464
|
+
processId: z.number().int().positive().optional().describe("Canonical process handle for bash(action=\"process\") or the active command adapter."),
|
|
465
465
|
sessionId: z.number().int().positive().optional().describe("Deprecated alias of processId for compatibility."),
|
|
466
466
|
running: z.boolean(),
|
|
467
467
|
exitCode: z.number().int().optional(),
|
|
@@ -613,6 +613,8 @@ function registerProcessTools(server, config, workspaces, processSessions, hooks
|
|
|
613
613
|
});
|
|
614
614
|
});
|
|
615
615
|
}
|
|
616
|
+
if (config.toolMode !== "codex")
|
|
617
|
+
return;
|
|
616
618
|
registerAppTool(server, "write_stdin", {
|
|
617
619
|
title: "Write to process",
|
|
618
620
|
description: "Poll or write characters to a running process returned by bash or exec_command. Omit chars or pass an empty string to poll. Waiting never kills the process; pass \\u0003 to explicitly send Ctrl-C.",
|
|
@@ -709,7 +711,6 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
709
711
|
files: review.files,
|
|
710
712
|
},
|
|
711
713
|
card: {
|
|
712
|
-
tool: "show_changes",
|
|
713
714
|
summary: review.summary,
|
|
714
715
|
files: review.files,
|
|
715
716
|
payload: { patch: review.patch },
|
|
@@ -1118,9 +1119,10 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
1118
1119
|
...(execution.card
|
|
1119
1120
|
? {
|
|
1120
1121
|
_meta: {
|
|
1121
|
-
tool:
|
|
1122
|
+
tool: toolNames.capability,
|
|
1122
1123
|
card: {
|
|
1123
1124
|
workspaceId,
|
|
1125
|
+
capabilityName: name,
|
|
1124
1126
|
summary: execution.card.summary ?? {},
|
|
1125
1127
|
files: execution.card.files,
|
|
1126
1128
|
payload: execution.card.payload ?? {},
|
|
@@ -1165,53 +1167,25 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
1165
1167
|
});
|
|
1166
1168
|
});
|
|
1167
1169
|
registerAppTool(server, toolNames.closeWorkspace, {
|
|
1168
|
-
title: "Close
|
|
1169
|
-
description: "
|
|
1170
|
-
inputSchema: {
|
|
1171
|
-
workspaceId: z.string().describe("Logical workspace ID to release."),
|
|
1172
|
-
},
|
|
1173
|
-
outputSchema: resultOutputSchema({ workspaceId: z.string() }),
|
|
1174
|
-
_meta: {},
|
|
1175
|
-
annotations: WRITE_TOOL_ANNOTATIONS,
|
|
1176
|
-
}, async ({ workspaceId }) => {
|
|
1177
|
-
const workspace = workspaces.getWorkspace(workspaceId);
|
|
1178
|
-
return runToolWithHooks(hooks, {
|
|
1179
|
-
tool: toolNames.closeWorkspace,
|
|
1180
|
-
invocation: workspaceHookInvocation(workspace),
|
|
1181
|
-
payload: { workspaceId },
|
|
1182
|
-
operation: async () => {
|
|
1183
|
-
if (processSessions.activeWorkspaceIds().has(workspaceId)) {
|
|
1184
|
-
throw new Error(`Workspace ${workspaceId} still owns a running process or an unconsumed process completion. Poll or consume it before closing this workspace.`);
|
|
1185
|
-
}
|
|
1186
|
-
workspaces.closeWorkspace(workspaceId);
|
|
1187
|
-
const result = `Closed logical workspace ${workspaceId}. Physical project files were not removed.`;
|
|
1188
|
-
return {
|
|
1189
|
-
content: [textBlock(result)],
|
|
1190
|
-
structuredContent: { result, workspaceId },
|
|
1191
|
-
};
|
|
1192
|
-
},
|
|
1193
|
-
});
|
|
1194
|
-
});
|
|
1195
|
-
registerAppTool(server, toolNames.closeWorktree, {
|
|
1196
|
-
title: "Close worktree",
|
|
1197
|
-
description: "Finalize a managed worktree after its task is complete and verified. ForgeRelay may commit remaining changes, integrate the target branch when safe, and clean up the managed worktree. Read the managed-worktrees capability guide for advanced close, safety, and failure semantics.",
|
|
1170
|
+
title: "Close workspace",
|
|
1171
|
+
description: "Close one workspace after the user chooses cleanup. Checkout-backed workspaces release only the logical handle. Managed-worktree-backed workspaces finalize the existing safe worktree lifecycle, including hooks, commit/integration, and cleanup; provide commitMessage for that mode. Running or unconsumed processes prevent closure.",
|
|
1198
1172
|
inputSchema: {
|
|
1199
|
-
workspaceId: z
|
|
1200
|
-
.string()
|
|
1201
|
-
.describe("Managed worktree workspace identifier returned by open_workspace."),
|
|
1173
|
+
workspaceId: z.string().describe("Workspace identifier to close."),
|
|
1202
1174
|
commitMessage: z
|
|
1203
1175
|
.string()
|
|
1204
1176
|
.min(1)
|
|
1205
|
-
.
|
|
1177
|
+
.optional()
|
|
1178
|
+
.describe("Required only for a managed-worktree-backed workspace; concise Git commit message for remaining worktree changes."),
|
|
1206
1179
|
},
|
|
1207
1180
|
outputSchema: resultOutputSchema({
|
|
1208
1181
|
workspaceId: z.string(),
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1182
|
+
mode: z.enum(["checkout", "worktree"]),
|
|
1183
|
+
sourceRoot: z.string().optional(),
|
|
1184
|
+
branch: z.string().optional(),
|
|
1185
|
+
targetBranch: z.string().optional(),
|
|
1186
|
+
commitSha: z.string().optional(),
|
|
1187
|
+
mergedSha: z.string().optional(),
|
|
1188
|
+
committed: z.boolean().optional(),
|
|
1215
1189
|
cleanupWarning: z.string().optional(),
|
|
1216
1190
|
}),
|
|
1217
1191
|
_meta: {},
|
|
@@ -1219,49 +1193,70 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
1219
1193
|
}, async ({ workspaceId, commitMessage }, extra) => {
|
|
1220
1194
|
const workspace = workspaces.getWorkspace(workspaceId);
|
|
1221
1195
|
return runToolWithHooks(hooks, {
|
|
1222
|
-
tool: toolNames.
|
|
1196
|
+
tool: toolNames.closeWorkspace,
|
|
1223
1197
|
invocation: workspaceHookInvocation(workspace),
|
|
1224
|
-
payload: { commitMessage },
|
|
1225
|
-
afterCwd: (response) => response.structuredContent
|
|
1198
|
+
payload: { workspaceId, commitMessage, mode: workspace.mode },
|
|
1199
|
+
afterCwd: (response) => "sourceRoot" in response.structuredContent &&
|
|
1200
|
+
typeof response.structuredContent.sourceRoot === "string"
|
|
1201
|
+
? response.structuredContent.sourceRoot
|
|
1202
|
+
: undefined,
|
|
1226
1203
|
operation: async () => {
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1204
|
+
if (workspace.mode === "worktree") {
|
|
1205
|
+
if (!commitMessage) {
|
|
1206
|
+
throw new Error(`Managed-worktree-backed workspace ${workspaceId} requires commitMessage when closing.`);
|
|
1207
|
+
}
|
|
1208
|
+
const busyWorkspaceIds = workspaces
|
|
1209
|
+
.workspaceIdsForPhysicalWorkspace(workspace)
|
|
1210
|
+
.filter((id) => processSessions.activeWorkspaceIds().has(id));
|
|
1211
|
+
if (busyWorkspaceIds.length > 0) {
|
|
1212
|
+
throw new Error(`Cannot close this worktree-backed workspace while logical workspace processes are still running or awaiting completion delivery: ${busyWorkspaceIds.join(", ")}.`);
|
|
1213
|
+
}
|
|
1214
|
+
const startedAt = performance.now();
|
|
1215
|
+
const closed = await workspaces.closeWorktree(workspaceId, commitMessage);
|
|
1216
|
+
const result = [
|
|
1217
|
+
`Closed managed-worktree-backed workspace ${workspaceId}.`,
|
|
1218
|
+
`Merged ${closed.branch} into ${closed.targetBranch} by fast-forward.`,
|
|
1219
|
+
`Source checkout: ${closed.sourceRoot}`,
|
|
1220
|
+
`Commit: ${closed.commitSha}`,
|
|
1221
|
+
closed.cleanupWarning
|
|
1222
|
+
? `Cleanup warning: ${closed.cleanupWarning}`
|
|
1223
|
+
: "The managed worktree directory and branch were removed.",
|
|
1224
|
+
].join("\n");
|
|
1225
|
+
logToolCall(config, {
|
|
1226
|
+
tool: toolNames.closeWorkspace,
|
|
1227
|
+
...workspaceLogContext(workspace, extra.sessionId),
|
|
1228
|
+
path: closed.sourceRoot,
|
|
1229
|
+
success: true,
|
|
1230
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
1231
|
+
});
|
|
1232
|
+
return attachHookReports({
|
|
1233
|
+
content: [textBlock(result)],
|
|
1234
|
+
structuredContent: {
|
|
1235
|
+
result,
|
|
1236
|
+
workspaceId,
|
|
1237
|
+
mode: "worktree",
|
|
1238
|
+
sourceRoot: closed.sourceRoot,
|
|
1239
|
+
branch: closed.branch,
|
|
1240
|
+
targetBranch: closed.targetBranch,
|
|
1241
|
+
commitSha: closed.commitSha,
|
|
1242
|
+
mergedSha: closed.mergedSha,
|
|
1243
|
+
committed: closed.committed,
|
|
1244
|
+
cleanupWarning: closed.cleanupWarning,
|
|
1245
|
+
},
|
|
1246
|
+
}, closed.hookReports);
|
|
1232
1247
|
}
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
`
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
tool: toolNames.closeWorktree,
|
|
1246
|
-
...workspaceLogContext(workspace, extra.sessionId),
|
|
1247
|
-
path: closed.sourceRoot,
|
|
1248
|
-
success: true,
|
|
1249
|
-
durationMs: Math.round(performance.now() - startedAt),
|
|
1250
|
-
});
|
|
1251
|
-
return attachHookReports({
|
|
1252
|
-
content: [{ type: "text", text: result }],
|
|
1253
|
-
structuredContent: {
|
|
1254
|
-
result,
|
|
1255
|
-
workspaceId,
|
|
1256
|
-
sourceRoot: closed.sourceRoot,
|
|
1257
|
-
branch: closed.branch,
|
|
1258
|
-
targetBranch: closed.targetBranch,
|
|
1259
|
-
commitSha: closed.commitSha,
|
|
1260
|
-
mergedSha: closed.mergedSha,
|
|
1261
|
-
committed: closed.committed,
|
|
1262
|
-
cleanupWarning: closed.cleanupWarning,
|
|
1263
|
-
},
|
|
1264
|
-
}, closed.hookReports);
|
|
1248
|
+
if (commitMessage !== undefined) {
|
|
1249
|
+
throw new Error("close_workspace commitMessage is only valid for managed-worktree-backed workspaces.");
|
|
1250
|
+
}
|
|
1251
|
+
if (processSessions.activeWorkspaceIds().has(workspaceId)) {
|
|
1252
|
+
throw new Error(`Workspace ${workspaceId} still owns a running process or an unconsumed process completion. Poll or consume it before closing this workspace.`);
|
|
1253
|
+
}
|
|
1254
|
+
workspaces.closeWorkspace(workspaceId);
|
|
1255
|
+
const result = `Closed checkout-backed workspace ${workspaceId}. Physical project files were not removed.`;
|
|
1256
|
+
return {
|
|
1257
|
+
content: [textBlock(result)],
|
|
1258
|
+
structuredContent: { result, workspaceId, mode: "checkout" },
|
|
1259
|
+
};
|
|
1265
1260
|
},
|
|
1266
1261
|
});
|
|
1267
1262
|
});
|
|
@@ -1721,255 +1716,6 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
1721
1716
|
});
|
|
1722
1717
|
});
|
|
1723
1718
|
}
|
|
1724
|
-
if (config.widgets === "changes") {
|
|
1725
|
-
registerAppTool(server, "show_changes", {
|
|
1726
|
-
title: "Show changes",
|
|
1727
|
-
description: "Show the changes made in this turn for an open workspace. Call this once after the final related file change and before your final response so the user can review the combined diff. Do not call it after each individual file change.",
|
|
1728
|
-
inputSchema: {
|
|
1729
|
-
workspaceId: z
|
|
1730
|
-
.string()
|
|
1731
|
-
.describe("Workspace identifier returned by open_workspace."),
|
|
1732
|
-
},
|
|
1733
|
-
outputSchema: resultOutputSchema(),
|
|
1734
|
-
...toolWidgetDescriptorMeta(config, "show_changes"),
|
|
1735
|
-
annotations: { readOnlyHint: true },
|
|
1736
|
-
}, async ({ workspaceId }, extra) => {
|
|
1737
|
-
const workspace = workspaces.getWorkspace(workspaceId);
|
|
1738
|
-
return runToolWithHooks(hooks, {
|
|
1739
|
-
tool: "show_changes",
|
|
1740
|
-
invocation: workspaceHookInvocation(workspace),
|
|
1741
|
-
operation: async () => {
|
|
1742
|
-
const startedAt = performance.now();
|
|
1743
|
-
const review = await reviewWorkspaceChanges(reviewCheckpoints, workspace);
|
|
1744
|
-
const content = [textBlock(review.result)];
|
|
1745
|
-
logToolCall(config, {
|
|
1746
|
-
tool: "show_changes",
|
|
1747
|
-
...workspaceLogContext(workspace, extra.sessionId),
|
|
1748
|
-
success: true,
|
|
1749
|
-
durationMs: Math.round(performance.now() - startedAt),
|
|
1750
|
-
});
|
|
1751
|
-
return {
|
|
1752
|
-
content,
|
|
1753
|
-
_meta: {
|
|
1754
|
-
tool: "show_changes",
|
|
1755
|
-
card: {
|
|
1756
|
-
workspaceId,
|
|
1757
|
-
summary: review.summary,
|
|
1758
|
-
files: review.files,
|
|
1759
|
-
payload: {
|
|
1760
|
-
patch: review.patch,
|
|
1761
|
-
},
|
|
1762
|
-
},
|
|
1763
|
-
},
|
|
1764
|
-
structuredContent: {
|
|
1765
|
-
result: contentText(content),
|
|
1766
|
-
},
|
|
1767
|
-
};
|
|
1768
|
-
},
|
|
1769
|
-
});
|
|
1770
|
-
});
|
|
1771
|
-
}
|
|
1772
|
-
if (config.toolMode === "full") {
|
|
1773
|
-
registerAppTool(server, toolNames.grep, {
|
|
1774
|
-
title: "Grep",
|
|
1775
|
-
description: "Search file contents inside an open workspace or the OS temp directory. Use this before broad reads when looking for symbols, text, or usage sites. Respects project ignore rules. Call open_workspace first and pass workspaceId.",
|
|
1776
|
-
inputSchema: {
|
|
1777
|
-
workspaceId: z
|
|
1778
|
-
.string()
|
|
1779
|
-
.describe("Workspace identifier returned by open_workspace."),
|
|
1780
|
-
pattern: z.string().describe("Search pattern."),
|
|
1781
|
-
path: z
|
|
1782
|
-
.string()
|
|
1783
|
-
.optional()
|
|
1784
|
-
.describe("Optional path or glob scope relative to the workspace root, or an absolute path inside the OS temp directory."),
|
|
1785
|
-
include: z.string().optional().describe("Optional include glob."),
|
|
1786
|
-
},
|
|
1787
|
-
outputSchema: resultOutputSchema(),
|
|
1788
|
-
...toolWidgetDescriptorMeta(config, "search"),
|
|
1789
|
-
annotations: { readOnlyHint: true },
|
|
1790
|
-
}, async ({ workspaceId, ...input }, extra) => {
|
|
1791
|
-
const workspace = workspaces.getWorkspace(workspaceId);
|
|
1792
|
-
return runToolWithHooks(hooks, {
|
|
1793
|
-
tool: toolNames.grep,
|
|
1794
|
-
invocation: workspaceHookInvocation(workspace),
|
|
1795
|
-
payload: { pattern: input.pattern, path: input.path, include: input.include },
|
|
1796
|
-
isFailure: toolResultIsError,
|
|
1797
|
-
operation: async () => {
|
|
1798
|
-
const startedAt = performance.now();
|
|
1799
|
-
const response = await grepFilesTool(input, {
|
|
1800
|
-
cwd: workspace.root,
|
|
1801
|
-
root: workspace.root,
|
|
1802
|
-
fileRoots: workspaces.fileToolRoots(workspace),
|
|
1803
|
-
});
|
|
1804
|
-
if (response.isError) {
|
|
1805
|
-
logFailedToolResponse(config, {
|
|
1806
|
-
tool: toolNames.grep,
|
|
1807
|
-
...workspaceLogContext(workspace, extra.sessionId),
|
|
1808
|
-
path: input.path,
|
|
1809
|
-
}, response.content, startedAt);
|
|
1810
|
-
return response;
|
|
1811
|
-
}
|
|
1812
|
-
const summary = {
|
|
1813
|
-
pattern: input.pattern,
|
|
1814
|
-
scope: input.path ?? ".",
|
|
1815
|
-
...textSummary(response.content),
|
|
1816
|
-
};
|
|
1817
|
-
logToolCall(config, {
|
|
1818
|
-
tool: toolNames.grep,
|
|
1819
|
-
...workspaceLogContext(workspace, extra.sessionId),
|
|
1820
|
-
path: input.path,
|
|
1821
|
-
success: true,
|
|
1822
|
-
durationMs: Math.round(performance.now() - startedAt),
|
|
1823
|
-
});
|
|
1824
|
-
return {
|
|
1825
|
-
...response,
|
|
1826
|
-
_meta: {
|
|
1827
|
-
tool: toolNames.grep,
|
|
1828
|
-
card: {
|
|
1829
|
-
workspaceId,
|
|
1830
|
-
path: input.path,
|
|
1831
|
-
summary,
|
|
1832
|
-
payload: { content: response.content },
|
|
1833
|
-
},
|
|
1834
|
-
},
|
|
1835
|
-
structuredContent: {
|
|
1836
|
-
result: contentText(response.content),
|
|
1837
|
-
},
|
|
1838
|
-
};
|
|
1839
|
-
},
|
|
1840
|
-
});
|
|
1841
|
-
});
|
|
1842
|
-
registerAppTool(server, toolNames.glob, {
|
|
1843
|
-
title: "Glob",
|
|
1844
|
-
description: "Find files by glob pattern inside an open workspace or the OS temp directory. Use this to discover filenames or narrow file sets before reading. Respects project ignore rules. Call open_workspace first and pass workspaceId.",
|
|
1845
|
-
inputSchema: {
|
|
1846
|
-
workspaceId: z
|
|
1847
|
-
.string()
|
|
1848
|
-
.describe("Workspace identifier returned by open_workspace."),
|
|
1849
|
-
pattern: z.string().describe("File glob pattern."),
|
|
1850
|
-
path: z
|
|
1851
|
-
.string()
|
|
1852
|
-
.optional()
|
|
1853
|
-
.describe("Optional path scope relative to the workspace root, or an absolute path inside the OS temp directory."),
|
|
1854
|
-
},
|
|
1855
|
-
outputSchema: resultOutputSchema(),
|
|
1856
|
-
...toolWidgetDescriptorMeta(config, "search"),
|
|
1857
|
-
annotations: { readOnlyHint: true },
|
|
1858
|
-
}, async ({ workspaceId, ...input }, extra) => {
|
|
1859
|
-
const workspace = workspaces.getWorkspace(workspaceId);
|
|
1860
|
-
return runToolWithHooks(hooks, {
|
|
1861
|
-
tool: toolNames.glob,
|
|
1862
|
-
invocation: workspaceHookInvocation(workspace),
|
|
1863
|
-
payload: { pattern: input.pattern, path: input.path },
|
|
1864
|
-
isFailure: toolResultIsError,
|
|
1865
|
-
operation: async () => {
|
|
1866
|
-
const startedAt = performance.now();
|
|
1867
|
-
const response = await findFilesTool(input, {
|
|
1868
|
-
cwd: workspace.root,
|
|
1869
|
-
root: workspace.root,
|
|
1870
|
-
fileRoots: workspaces.fileToolRoots(workspace),
|
|
1871
|
-
});
|
|
1872
|
-
if (response.isError) {
|
|
1873
|
-
logFailedToolResponse(config, {
|
|
1874
|
-
tool: toolNames.glob,
|
|
1875
|
-
...workspaceLogContext(workspace, extra.sessionId),
|
|
1876
|
-
path: input.path,
|
|
1877
|
-
}, response.content, startedAt);
|
|
1878
|
-
return response;
|
|
1879
|
-
}
|
|
1880
|
-
const summary = {
|
|
1881
|
-
pattern: input.pattern,
|
|
1882
|
-
scope: input.path ?? ".",
|
|
1883
|
-
...textSummary(response.content),
|
|
1884
|
-
};
|
|
1885
|
-
logToolCall(config, {
|
|
1886
|
-
tool: toolNames.glob,
|
|
1887
|
-
...workspaceLogContext(workspace, extra.sessionId),
|
|
1888
|
-
path: input.path,
|
|
1889
|
-
success: true,
|
|
1890
|
-
durationMs: Math.round(performance.now() - startedAt),
|
|
1891
|
-
});
|
|
1892
|
-
return {
|
|
1893
|
-
...response,
|
|
1894
|
-
_meta: {
|
|
1895
|
-
tool: toolNames.glob,
|
|
1896
|
-
card: {
|
|
1897
|
-
workspaceId,
|
|
1898
|
-
path: input.path,
|
|
1899
|
-
summary,
|
|
1900
|
-
payload: { content: response.content },
|
|
1901
|
-
},
|
|
1902
|
-
},
|
|
1903
|
-
structuredContent: {
|
|
1904
|
-
result: contentText(response.content),
|
|
1905
|
-
},
|
|
1906
|
-
};
|
|
1907
|
-
},
|
|
1908
|
-
});
|
|
1909
|
-
});
|
|
1910
|
-
registerAppTool(server, toolNames.ls, {
|
|
1911
|
-
title: "Ls",
|
|
1912
|
-
description: "List a directory inside an open workspace or the OS temp directory. Use this for directory inspection before reading files. Call open_workspace first and pass workspaceId.",
|
|
1913
|
-
inputSchema: {
|
|
1914
|
-
workspaceId: z
|
|
1915
|
-
.string()
|
|
1916
|
-
.describe("Workspace identifier returned by open_workspace."),
|
|
1917
|
-
path: z
|
|
1918
|
-
.string()
|
|
1919
|
-
.describe("Directory path to list, relative to the workspace root or absolute inside the OS temp directory."),
|
|
1920
|
-
},
|
|
1921
|
-
outputSchema: resultOutputSchema(),
|
|
1922
|
-
...toolWidgetDescriptorMeta(config, "directory"),
|
|
1923
|
-
annotations: { readOnlyHint: true },
|
|
1924
|
-
}, async ({ workspaceId, ...input }, extra) => {
|
|
1925
|
-
const workspace = workspaces.getWorkspace(workspaceId);
|
|
1926
|
-
return runToolWithHooks(hooks, {
|
|
1927
|
-
tool: toolNames.ls,
|
|
1928
|
-
invocation: workspaceHookInvocation(workspace),
|
|
1929
|
-
payload: { path: input.path },
|
|
1930
|
-
isFailure: toolResultIsError,
|
|
1931
|
-
operation: async () => {
|
|
1932
|
-
const startedAt = performance.now();
|
|
1933
|
-
const response = await listDirectoryTool(input, {
|
|
1934
|
-
cwd: workspace.root,
|
|
1935
|
-
root: workspace.root,
|
|
1936
|
-
fileRoots: workspaces.fileToolRoots(workspace),
|
|
1937
|
-
});
|
|
1938
|
-
if (response.isError) {
|
|
1939
|
-
logFailedToolResponse(config, {
|
|
1940
|
-
tool: toolNames.ls,
|
|
1941
|
-
...workspaceLogContext(workspace, extra.sessionId),
|
|
1942
|
-
path: input.path,
|
|
1943
|
-
}, response.content, startedAt);
|
|
1944
|
-
return response;
|
|
1945
|
-
}
|
|
1946
|
-
const summary = textSummary(response.content);
|
|
1947
|
-
logToolCall(config, {
|
|
1948
|
-
tool: toolNames.ls,
|
|
1949
|
-
...workspaceLogContext(workspace, extra.sessionId),
|
|
1950
|
-
path: input.path,
|
|
1951
|
-
success: true,
|
|
1952
|
-
durationMs: Math.round(performance.now() - startedAt),
|
|
1953
|
-
});
|
|
1954
|
-
return {
|
|
1955
|
-
...response,
|
|
1956
|
-
_meta: {
|
|
1957
|
-
tool: toolNames.ls,
|
|
1958
|
-
card: {
|
|
1959
|
-
workspaceId,
|
|
1960
|
-
path: input.path,
|
|
1961
|
-
summary,
|
|
1962
|
-
payload: { content: response.content },
|
|
1963
|
-
},
|
|
1964
|
-
},
|
|
1965
|
-
structuredContent: {
|
|
1966
|
-
result: contentText(response.content),
|
|
1967
|
-
},
|
|
1968
|
-
};
|
|
1969
|
-
},
|
|
1970
|
-
});
|
|
1971
|
-
});
|
|
1972
|
-
}
|
|
1973
1719
|
if (config.toolMode !== "codex") {
|
|
1974
1720
|
registerAppTool(server, toolNames.shell, {
|
|
1975
1721
|
title: "Bash",
|
|
@@ -1978,73 +1724,179 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
1978
1724
|
workspaceId: z
|
|
1979
1725
|
.string()
|
|
1980
1726
|
.describe("Workspace identifier returned by open_workspace."),
|
|
1727
|
+
action: z
|
|
1728
|
+
.enum(["run", "process"])
|
|
1729
|
+
.optional()
|
|
1730
|
+
.describe("Defaults to run. Use process with a returned processId to poll, interact, resize, or interrupt a running command."),
|
|
1981
1731
|
command: z
|
|
1982
1732
|
.string()
|
|
1983
|
-
.
|
|
1733
|
+
.optional()
|
|
1734
|
+
.describe(`${toolDescriptions.shellCommand} Required for action=run.`),
|
|
1735
|
+
processId: z
|
|
1736
|
+
.number()
|
|
1737
|
+
.int()
|
|
1738
|
+
.positive()
|
|
1739
|
+
.optional()
|
|
1740
|
+
.describe("Process identifier returned by a previous bash action=run call. Required for action=process."),
|
|
1741
|
+
input: z
|
|
1742
|
+
.string()
|
|
1743
|
+
.optional()
|
|
1744
|
+
.describe("Characters to write for action=process. Omit to poll/wait without input."),
|
|
1745
|
+
interrupt: z
|
|
1746
|
+
.boolean()
|
|
1747
|
+
.optional()
|
|
1748
|
+
.describe("For action=process, send SIGINT to the process. Cannot be combined with input."),
|
|
1749
|
+
tty: z
|
|
1750
|
+
.boolean()
|
|
1751
|
+
.optional()
|
|
1752
|
+
.describe("For action=run, allocate a pseudo-terminal for interactive commands. Defaults to false."),
|
|
1753
|
+
columns: z
|
|
1754
|
+
.number()
|
|
1755
|
+
.int()
|
|
1756
|
+
.min(1)
|
|
1757
|
+
.max(1_000)
|
|
1758
|
+
.optional()
|
|
1759
|
+
.describe("Initial PTY width for action=run, or resize width for action=process."),
|
|
1760
|
+
rows: z
|
|
1761
|
+
.number()
|
|
1762
|
+
.int()
|
|
1763
|
+
.min(1)
|
|
1764
|
+
.max(1_000)
|
|
1765
|
+
.optional()
|
|
1766
|
+
.describe("Initial PTY height for action=run, or resize height for action=process."),
|
|
1984
1767
|
workingDirectory: z
|
|
1985
1768
|
.string()
|
|
1986
1769
|
.optional()
|
|
1987
|
-
.describe("
|
|
1770
|
+
.describe("For action=run, working directory relative to the workspace root. Defaults to the workspace root."),
|
|
1771
|
+
yieldTimeMs: z
|
|
1772
|
+
.number()
|
|
1773
|
+
.int()
|
|
1774
|
+
.min(0)
|
|
1775
|
+
.max(300_000)
|
|
1776
|
+
.optional()
|
|
1777
|
+
.describe("Milliseconds to wait before returning. Run preserves the existing 300000ms default; process polling defaults to 5000ms and interaction to 250ms."),
|
|
1778
|
+
maxOutputTokens: z
|
|
1779
|
+
.number()
|
|
1780
|
+
.int()
|
|
1781
|
+
.positive()
|
|
1782
|
+
.max(100_000)
|
|
1783
|
+
.optional()
|
|
1784
|
+
.describe("Approximate output token budget. Defaults to 10000."),
|
|
1988
1785
|
},
|
|
1989
1786
|
outputSchema: processOutputSchema(),
|
|
1990
1787
|
...toolWidgetDescriptorMeta(config, "shell"),
|
|
1991
1788
|
annotations: SHELL_TOOL_ANNOTATIONS,
|
|
1992
|
-
}, async ({ workspaceId, command, workingDirectory }, extra) => {
|
|
1789
|
+
}, async ({ workspaceId, action = "run", command, processId, input, interrupt, tty, columns, rows, workingDirectory, yieldTimeMs, maxOutputTokens, }, extra) => {
|
|
1993
1790
|
const workspace = workspaces.getWorkspace(workspaceId);
|
|
1791
|
+
if (action === "run") {
|
|
1792
|
+
if (!command)
|
|
1793
|
+
throw new Error("bash action=run requires command.");
|
|
1794
|
+
if (processId !== undefined || input !== undefined || interrupt !== undefined) {
|
|
1795
|
+
throw new Error("bash action=run does not accept processId, input, or interrupt.");
|
|
1796
|
+
}
|
|
1797
|
+
return runToolWithHooks(hooks, {
|
|
1798
|
+
tool: toolNames.shell,
|
|
1799
|
+
invocation: workspaceHookInvocation(workspace),
|
|
1800
|
+
payload: {
|
|
1801
|
+
action,
|
|
1802
|
+
command,
|
|
1803
|
+
workingDirectory: workingDirectory ?? ".",
|
|
1804
|
+
},
|
|
1805
|
+
isFailure: toolResultIsError,
|
|
1806
|
+
operation: async () => {
|
|
1807
|
+
const startedAt = performance.now();
|
|
1808
|
+
const cwd = workspaces.resolveWorkingDirectory(workspace, workingDirectory);
|
|
1809
|
+
const snapshot = await processSessions.start({
|
|
1810
|
+
workspaceId,
|
|
1811
|
+
command,
|
|
1812
|
+
cwd,
|
|
1813
|
+
workspaceRoot: workspace.root,
|
|
1814
|
+
tty,
|
|
1815
|
+
columns,
|
|
1816
|
+
rows,
|
|
1817
|
+
yieldTimeMs: yieldTimeMs ?? 300_000,
|
|
1818
|
+
maxOutputTokens,
|
|
1819
|
+
});
|
|
1820
|
+
logToolCall(config, {
|
|
1821
|
+
tool: toolNames.shell,
|
|
1822
|
+
...workspaceLogContext(workspace, extra.sessionId),
|
|
1823
|
+
workingDirectory: workingDirectory ?? ".",
|
|
1824
|
+
command,
|
|
1825
|
+
commandLength: command.length,
|
|
1826
|
+
exitCode: snapshot.exitCode,
|
|
1827
|
+
running: snapshot.running,
|
|
1828
|
+
processId: snapshot.processId,
|
|
1829
|
+
success: snapshot.running || (snapshot.exitCode === 0 && !snapshot.signal),
|
|
1830
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
1831
|
+
});
|
|
1832
|
+
const response = processToolResponse(toolNames.shell, workspaceId, snapshot, {
|
|
1833
|
+
action,
|
|
1834
|
+
command,
|
|
1835
|
+
workingDirectory: workingDirectory ?? ".",
|
|
1836
|
+
running: snapshot.running,
|
|
1837
|
+
exitCode: snapshot.exitCode,
|
|
1838
|
+
wallTimeMs: snapshot.wallTimeMs,
|
|
1839
|
+
});
|
|
1840
|
+
return !snapshot.running && (snapshot.signal || snapshot.exitCode !== 0)
|
|
1841
|
+
? { ...response, isError: true }
|
|
1842
|
+
: response;
|
|
1843
|
+
},
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
if (command !== undefined || workingDirectory !== undefined || tty !== undefined) {
|
|
1847
|
+
throw new Error("bash action=process does not accept command, workingDirectory, or tty.");
|
|
1848
|
+
}
|
|
1849
|
+
if (processId === undefined)
|
|
1850
|
+
throw new Error("bash action=process requires processId.");
|
|
1851
|
+
if (interrupt && input !== undefined) {
|
|
1852
|
+
throw new Error("bash action=process cannot combine interrupt with input.");
|
|
1853
|
+
}
|
|
1994
1854
|
return runToolWithHooks(hooks, {
|
|
1995
1855
|
tool: toolNames.shell,
|
|
1996
1856
|
invocation: workspaceHookInvocation(workspace),
|
|
1997
1857
|
payload: {
|
|
1998
|
-
|
|
1999
|
-
|
|
1858
|
+
action,
|
|
1859
|
+
processId,
|
|
1860
|
+
inputLength: input?.length ?? 0,
|
|
1861
|
+
interrupt: interrupt ?? false,
|
|
1862
|
+
columns,
|
|
1863
|
+
rows,
|
|
2000
1864
|
},
|
|
2001
1865
|
isFailure: toolResultIsError,
|
|
2002
1866
|
operation: async () => {
|
|
2003
1867
|
const startedAt = performance.now();
|
|
2004
|
-
const
|
|
2005
|
-
const snapshot = await processSessions.start({
|
|
1868
|
+
const snapshot = await processSessions.write({
|
|
2006
1869
|
workspaceId,
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
1870
|
+
processId,
|
|
1871
|
+
chars: interrupt ? "\u0003" : input,
|
|
1872
|
+
columns,
|
|
1873
|
+
rows,
|
|
1874
|
+
yieldTimeMs,
|
|
1875
|
+
maxOutputTokens,
|
|
2011
1876
|
});
|
|
2012
1877
|
logToolCall(config, {
|
|
2013
1878
|
tool: toolNames.shell,
|
|
2014
1879
|
...workspaceLogContext(workspace, extra.sessionId),
|
|
2015
|
-
workingDirectory: workingDirectory ?? ".",
|
|
2016
|
-
command,
|
|
2017
|
-
commandLength: command.length,
|
|
2018
1880
|
exitCode: snapshot.exitCode,
|
|
2019
1881
|
running: snapshot.running,
|
|
2020
1882
|
processId: snapshot.processId,
|
|
2021
|
-
success: snapshot.running ||
|
|
1883
|
+
success: snapshot.running || snapshot.exitCode === 0,
|
|
2022
1884
|
durationMs: Math.round(performance.now() - startedAt),
|
|
2023
1885
|
});
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
1886
|
+
return processToolResponse(toolNames.shell, workspaceId, snapshot, {
|
|
1887
|
+
action,
|
|
1888
|
+
processId,
|
|
1889
|
+
inputLength: input?.length ?? 0,
|
|
1890
|
+
interrupt: interrupt ?? false,
|
|
2027
1891
|
running: snapshot.running,
|
|
2028
1892
|
exitCode: snapshot.exitCode,
|
|
2029
1893
|
wallTimeMs: snapshot.wallTimeMs,
|
|
2030
1894
|
});
|
|
2031
|
-
return !snapshot.running && (snapshot.signal || snapshot.exitCode !== 0)
|
|
2032
|
-
? { ...response, isError: true }
|
|
2033
|
-
: response;
|
|
2034
1895
|
},
|
|
2035
1896
|
});
|
|
2036
1897
|
});
|
|
2037
1898
|
}
|
|
2038
1899
|
registerProcessTools(server, config, workspaces, processSessions, hooks);
|
|
2039
|
-
if (config.artifactsEnabled && isArtifactDownloadSupportedPlatform()) {
|
|
2040
|
-
registerArtifactTools(server, {
|
|
2041
|
-
config,
|
|
2042
|
-
workspaces,
|
|
2043
|
-
hooks,
|
|
2044
|
-
incomingArtifactAdapters,
|
|
2045
|
-
incomingArtifactRegistry,
|
|
2046
|
-
});
|
|
2047
|
-
}
|
|
2048
1900
|
return server;
|
|
2049
1901
|
}
|
|
2050
1902
|
export function createServer(config = loadConfig(), options = {}) {
|