@mastra/code-sdk 1.8.4-alpha.6 → 1.9.0-alpha.8
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 +190 -0
- package/dist/acp/agent.d.ts +30 -17
- package/dist/acp/agent.d.ts.map +1 -1
- package/dist/acp/agent.js +294 -103
- package/dist/acp/agent.js.map +1 -1
- package/dist/acp/errors.d.ts +3 -0
- package/dist/acp/errors.d.ts.map +1 -0
- package/dist/acp/errors.js +14 -0
- package/dist/acp/errors.js.map +1 -0
- package/dist/acp/event-mapper.d.ts +6 -1
- package/dist/acp/event-mapper.d.ts.map +1 -1
- package/dist/acp/event-mapper.js +116 -56
- package/dist/acp/event-mapper.js.map +1 -1
- package/dist/acp/index.d.ts +1 -4
- package/dist/acp/index.d.ts.map +1 -1
- package/dist/acp/index.js +6 -48
- package/dist/acp/index.js.map +1 -1
- package/dist/acp/runtime.d.ts +5 -0
- package/dist/acp/runtime.d.ts.map +1 -0
- package/dist/acp/runtime.js +80 -0
- package/dist/acp/runtime.js.map +1 -0
- package/dist/acp/server.d.ts +3 -6
- package/dist/acp/server.d.ts.map +1 -1
- package/dist/acp/server.js +22 -19
- package/dist/acp/server.js.map +1 -1
- package/dist/acp/skills.d.ts +6 -0
- package/dist/acp/skills.d.ts.map +1 -0
- package/dist/acp/skills.js +33 -0
- package/dist/acp/skills.js.map +1 -0
- package/dist/agents/model.js +1 -1
- package/dist/agents/prompts/agent-instructions.js +2 -2
- package/dist/agents/workspace.js +1 -1
- package/dist/analytics.js +2 -2
- package/dist/auth/providers/kimi-coding.js +1 -1
- package/dist/auth/storage.js +2 -2
- package/dist/clipboard/index.js +2 -2
- package/dist/headless/run-mc.d.ts.map +1 -1
- package/dist/headless/run-mc.js +14 -0
- package/dist/headless/run-mc.js.map +1 -1
- package/dist/hooks/config.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/lsp/server.js +1 -1
- package/dist/lsp/workspace.js +1 -1
- package/dist/mcp/config.js +1 -1
- package/dist/mcp/manager.d.ts.map +1 -1
- package/dist/mcp/manager.js +2 -1
- package/dist/mcp/manager.js.map +1 -1
- package/dist/mcp/state.js +1 -1
- package/dist/mcp/types.d.ts +2 -0
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/onboarding/settings.js +3 -3
- package/dist/plugins/dependencies.js +1 -1
- package/dist/plugins/install.js +1 -1
- package/dist/plugins/loader.js +3 -3
- package/dist/plugins/manager.js +1 -1
- package/dist/plugins/manifest.js +1 -1
- package/dist/plugins/package-link.js +1 -1
- package/dist/plugins/paths.js +1 -1
- package/dist/plugins/registry.js +1 -1
- package/dist/plugins/scaffold.js +1 -1
- package/dist/process-memory-diagnostics.js +2 -2
- package/dist/providers/amazon-bedrock-gateway.js +1 -1
- package/dist/providers/openai-codex.js +1 -1
- package/dist/schema.js +1 -1
- package/dist/tools/request-sandbox-access.js +5 -4
- package/dist/tools/request-sandbox-access.js.map +1 -1
- package/dist/utils/debug-log.js +1 -1
- package/dist/utils/project.js +3 -3
- package/dist/utils/signals-pubsub.js +1 -1
- package/dist/utils/slash-command-loader.js +1 -1
- package/dist/utils/slash-command-processor.js +1 -1
- package/dist/utils/storage-maintenance.js +1 -1
- package/dist/utils/thread-lock.js +1 -1
- package/dist/utils/update-check.js +2 -2
- package/dist/workflows/register-primitives.js +1 -1
- package/package.json +18 -14
package/dist/acp/event-mapper.js
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import { mastraDBMessageToSignal } from "@mastra/core/signals";
|
|
2
1
|
//#region src/acp/event-mapper.ts
|
|
3
|
-
function getSignalText(message) {
|
|
4
|
-
const contents = mastraDBMessageToSignal(message).contents;
|
|
5
|
-
if (typeof contents === "string") return contents;
|
|
6
|
-
if (!Array.isArray(contents)) return "";
|
|
7
|
-
return contents.filter((part) => part.type === "text").map((part) => part.text).join("\n");
|
|
8
|
-
}
|
|
9
2
|
let autoApprove = false;
|
|
10
3
|
/**
|
|
11
4
|
* Enable or disable automatic tool approval (set via --dangerous-auto-approve CLI flag).
|
|
@@ -33,45 +26,29 @@ function mapToolKind(toolName) {
|
|
|
33
26
|
* a session update.
|
|
34
27
|
*/
|
|
35
28
|
function handleAgentControllerEvent(event, state, connection, session) {
|
|
36
|
-
if (!state) return;
|
|
29
|
+
if (!state || state.finished) return;
|
|
37
30
|
switch (event.type) {
|
|
38
31
|
case "agent_start":
|
|
39
|
-
state.
|
|
32
|
+
state.suspended = false;
|
|
33
|
+
if (state.cancelled && !state.cancelSuspensions?.size) session.completeDeferredAbort();
|
|
40
34
|
break;
|
|
41
|
-
case "message_start":
|
|
35
|
+
case "message_start":
|
|
42
36
|
if (event.message.role === "assistant") {
|
|
43
37
|
state.activeAssistantMessageId = event.message.id;
|
|
44
|
-
state.lastTextLength = 0;
|
|
45
38
|
break;
|
|
46
39
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (text) sendUpdate(connection, state.sessionId, {
|
|
40
|
+
break;
|
|
41
|
+
case "message_update":
|
|
42
|
+
if (event.event.type === "text-delta" && event.id === state.activeAssistantMessageId && event.event.delta) sendUpdate(connection, state.sessionId, {
|
|
50
43
|
sessionUpdate: "agent_message_chunk",
|
|
51
44
|
content: {
|
|
52
45
|
type: "text",
|
|
53
|
-
text
|
|
46
|
+
text: event.event.delta
|
|
54
47
|
}
|
|
55
48
|
});
|
|
56
49
|
break;
|
|
57
|
-
}
|
|
58
|
-
case "message_update":
|
|
59
|
-
if (event.event.type === "text-delta" && event.id === state.activeAssistantMessageId && event.event.delta) {
|
|
60
|
-
state.lastTextLength += event.event.delta.length;
|
|
61
|
-
sendUpdate(connection, state.sessionId, {
|
|
62
|
-
sessionUpdate: "agent_message_chunk",
|
|
63
|
-
content: {
|
|
64
|
-
type: "text",
|
|
65
|
-
text: event.event.delta
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
break;
|
|
70
50
|
case "message_end":
|
|
71
|
-
if (event.id === state.activeAssistantMessageId)
|
|
72
|
-
state.activeAssistantMessageId = void 0;
|
|
73
|
-
state.lastTextLength = 0;
|
|
74
|
-
}
|
|
51
|
+
if (event.id === state.activeAssistantMessageId) state.activeAssistantMessageId = void 0;
|
|
75
52
|
break;
|
|
76
53
|
case "tool_start":
|
|
77
54
|
sendUpdate(connection, state.sessionId, {
|
|
@@ -93,18 +70,32 @@ function handleAgentControllerEvent(event, state, connection, session) {
|
|
|
93
70
|
break;
|
|
94
71
|
case "tool_approval_required":
|
|
95
72
|
handleToolApproval(state, connection, session, event).catch((err) => {
|
|
96
|
-
|
|
73
|
+
failTurn(state, session, err);
|
|
97
74
|
});
|
|
98
75
|
break;
|
|
99
76
|
case "tool_suspended":
|
|
100
77
|
handleToolSuspended(state, connection, session, event).catch((err) => {
|
|
101
|
-
|
|
78
|
+
failTurn(state, session, err);
|
|
102
79
|
});
|
|
103
80
|
break;
|
|
104
81
|
case "usage_update":
|
|
105
82
|
accumulateUsage(state.usage, event.usage);
|
|
106
83
|
break;
|
|
84
|
+
case "error":
|
|
85
|
+
state.error = event.error;
|
|
86
|
+
if (event.finishReason === "length") state.stopReason = "max_tokens";
|
|
87
|
+
else if (event.finishReason === "content-filter") state.stopReason = "refusal";
|
|
88
|
+
break;
|
|
107
89
|
case "agent_end":
|
|
90
|
+
if (event.reason === "suspended") {
|
|
91
|
+
state.suspended = true;
|
|
92
|
+
if (state.cancelled && !state.cancelSuspensions?.size) {
|
|
93
|
+
session.stream.detach();
|
|
94
|
+
state.resolve("aborted");
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
state.finished = true;
|
|
108
99
|
state.resolve(event.reason ?? "complete");
|
|
109
100
|
break;
|
|
110
101
|
default: break;
|
|
@@ -119,8 +110,18 @@ function sendUpdate(connection, sessionId, update) {
|
|
|
119
110
|
});
|
|
120
111
|
}
|
|
121
112
|
async function handleToolApproval(state, connection, session, event) {
|
|
113
|
+
if (state.cancelled) {
|
|
114
|
+
session.respondToToolApproval({
|
|
115
|
+
decision: "decline",
|
|
116
|
+
toolCallId: event.toolCallId
|
|
117
|
+
});
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
122
120
|
if (autoApprove) {
|
|
123
|
-
session.respondToToolApproval({
|
|
121
|
+
session.respondToToolApproval({
|
|
122
|
+
decision: "approve",
|
|
123
|
+
toolCallId: event.toolCallId
|
|
124
|
+
});
|
|
124
125
|
return;
|
|
125
126
|
}
|
|
126
127
|
const req = {
|
|
@@ -142,21 +143,78 @@ async function handleToolApproval(state, connection, session, event) {
|
|
|
142
143
|
};
|
|
143
144
|
try {
|
|
144
145
|
const resp = await connection.requestPermission(req);
|
|
146
|
+
if (state.finished || state.cancelled) return;
|
|
145
147
|
if (resp.outcome.outcome === "selected") {
|
|
146
148
|
const decision = resp.outcome.optionId === "approve" ? "approve" : "decline";
|
|
147
|
-
session.respondToToolApproval({
|
|
148
|
-
|
|
149
|
+
session.respondToToolApproval({
|
|
150
|
+
decision,
|
|
151
|
+
toolCallId: event.toolCallId
|
|
152
|
+
});
|
|
153
|
+
} else session.respondToToolApproval({
|
|
154
|
+
decision: "decline",
|
|
155
|
+
toolCallId: event.toolCallId
|
|
156
|
+
});
|
|
149
157
|
} catch (err) {
|
|
158
|
+
if (state.finished || state.cancelled) return;
|
|
150
159
|
process.stderr.write(`[acp] requestPermission error: ${err}\n`);
|
|
151
|
-
session.respondToToolApproval({
|
|
160
|
+
session.respondToToolApproval({
|
|
161
|
+
decision: "decline",
|
|
162
|
+
toolCallId: event.toolCallId
|
|
163
|
+
});
|
|
152
164
|
}
|
|
153
165
|
}
|
|
154
166
|
async function handleToolSuspended(state, connection, session, event) {
|
|
155
167
|
const { toolCallId, toolName, args, suspendPayload } = event;
|
|
156
|
-
|
|
157
|
-
|
|
168
|
+
const isSandboxAccess = toolName === "request_access" || typeof suspendPayload === "object" && suspendPayload !== null && "kind" in suspendPayload && suspendPayload.kind === "sandbox_access_request";
|
|
169
|
+
if (isSandboxAccess || toolName === "submit_plan") {
|
|
170
|
+
state.cancelSuspensions ??= /* @__PURE__ */ new Map();
|
|
171
|
+
state.cancelSuspensions.set(toolCallId, () => session.resumeToolCall({
|
|
158
172
|
toolCallId,
|
|
159
|
-
resumeData: "
|
|
173
|
+
resumeData: isSandboxAccess ? "No" : { action: "rejected" },
|
|
174
|
+
resolveOnToolEnd: true
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
if (state.cancelled) {
|
|
178
|
+
try {
|
|
179
|
+
await state.cancelSuspensions?.get(toolCallId)?.();
|
|
180
|
+
} finally {
|
|
181
|
+
state.cancelSuspensions?.delete(toolCallId);
|
|
182
|
+
if (!state.finished) {
|
|
183
|
+
session.completeDeferredAbort();
|
|
184
|
+
state.resolve("aborted");
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (isSandboxAccess) {
|
|
190
|
+
let approved = autoApprove;
|
|
191
|
+
if (!autoApprove) try {
|
|
192
|
+
const response = await connection.requestPermission({
|
|
193
|
+
sessionId: state.sessionId,
|
|
194
|
+
toolCall: {
|
|
195
|
+
toolCallId,
|
|
196
|
+
title: toolName,
|
|
197
|
+
rawInput: JSON.stringify(args)
|
|
198
|
+
},
|
|
199
|
+
options: [{
|
|
200
|
+
optionId: "approve",
|
|
201
|
+
name: "Allow access",
|
|
202
|
+
kind: "allow_once"
|
|
203
|
+
}, {
|
|
204
|
+
optionId: "reject",
|
|
205
|
+
name: "Deny access",
|
|
206
|
+
kind: "reject_once"
|
|
207
|
+
}]
|
|
208
|
+
});
|
|
209
|
+
approved = response.outcome.outcome === "selected" && response.outcome.optionId === "approve";
|
|
210
|
+
} catch {
|
|
211
|
+
approved = false;
|
|
212
|
+
}
|
|
213
|
+
if (state.finished || state.cancelled) return;
|
|
214
|
+
state.cancelSuspensions?.delete(toolCallId);
|
|
215
|
+
await session.respondToToolSuspension({
|
|
216
|
+
toolCallId,
|
|
217
|
+
resumeData: approved ? "Yes" : "No"
|
|
160
218
|
});
|
|
161
219
|
return;
|
|
162
220
|
}
|
|
@@ -178,25 +236,27 @@ async function handleToolSuspended(state, connection, session, event) {
|
|
|
178
236
|
kind: "reject_once"
|
|
179
237
|
}]
|
|
180
238
|
};
|
|
239
|
+
let action = "rejected";
|
|
181
240
|
try {
|
|
182
241
|
const resp = await connection.requestPermission(req);
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
resumeData: { action: "rejected" }
|
|
192
|
-
});
|
|
193
|
-
}
|
|
242
|
+
if (resp.outcome.outcome === "selected" && resp.outcome.optionId === "approve") action = "approved";
|
|
243
|
+
} catch {}
|
|
244
|
+
if (state.finished || state.cancelled) return;
|
|
245
|
+
state.cancelSuspensions?.delete(toolCallId);
|
|
246
|
+
await session.respondToToolSuspension({
|
|
247
|
+
toolCallId,
|
|
248
|
+
resumeData: { action }
|
|
249
|
+
});
|
|
194
250
|
return;
|
|
195
251
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
252
|
+
throw new Error(`Tool "${toolName}" requires an interaction that this ACP server does not support`);
|
|
253
|
+
}
|
|
254
|
+
function failTurn(state, session, error) {
|
|
255
|
+
if (state.finished || state.cancelled) return;
|
|
256
|
+
state.error = error instanceof Error ? error : new Error(String(error));
|
|
257
|
+
state.finished = true;
|
|
258
|
+
state.resolve("error");
|
|
259
|
+
session.abort();
|
|
200
260
|
}
|
|
201
261
|
function accumulateUsage(target, usage) {
|
|
202
262
|
target.promptTokens += usage.promptTokens;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-mapper.js","names":[],"sources":["../../src/acp/event-mapper.ts"],"sourcesContent":["import type { SessionNotification, RequestPermissionRequest, AgentSideConnection } from '@agentclientprotocol/sdk';\nimport type { AgentControllerEvent, MastraDBMessage, Session, TokenUsage } from '@mastra/core/agent-controller';\nimport { mastraDBMessageToSignal } from '@mastra/core/signals';\n\nfunction getSignalText(message: MastraDBMessage): string {\n const contents = mastraDBMessageToSignal(message).contents;\n if (typeof contents === 'string') return contents;\n if (!Array.isArray(contents)) return '';\n return contents\n .filter((part): part is Extract<(typeof contents)[number], { type: 'text' }> => part.type === 'text')\n .map(part => part.text)\n .join('\\n');\n}\n\nlet autoApprove = false;\n\n/**\n * Enable or disable automatic tool approval (set via --dangerous-auto-approve CLI flag).\n */\nexport function setAutoApprove(value: boolean): void {\n autoApprove = value;\n}\n\n/**\n * Map a mastracode tool name to an ACP ToolKind.\n */\nfunction mapToolKind(\n toolName: string,\n): 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'think' | 'fetch' | 'other' {\n const name = toolName.toLowerCase();\n if (name.includes('edit') || name.includes('write') || name.includes('replace') || name.includes('patch'))\n return 'edit';\n if (name.includes('read') || name.includes('view') || name.includes('list') || name.includes('find')) return 'read';\n if (name.includes('delete') || name.includes('remove')) return 'delete';\n if (name.includes('search') || name.includes('grep') || name.includes('query')) return 'search';\n if (name.includes('execute') || name.includes('run') || name.includes('command') || name.includes('shell'))\n return 'execute';\n if (\n name.includes('fetch') ||\n name.includes('curl') ||\n name.includes('http') ||\n name.includes('browse') ||\n name.includes('navigate')\n )\n return 'fetch';\n if (name.includes('think') || name.includes('reason')) return 'think';\n return 'other';\n}\n\n/**\n * Accumulated state for an active prompt turn.\n */\nexport interface PromptState {\n sessionId: string;\n activeAssistantMessageId?: string;\n lastTextLength: number;\n usage: TokenUsage;\n resolve: (reason: 'complete' | 'aborted' | 'error' | 'suspended') => void;\n}\n\n/**\n * Translate an AgentControllerEvent into an ACP SessionNotification and send it\n * via the provided connection. Returns null for events that don't produce\n * a session update.\n */\nexport function handleAgentControllerEvent(\n event: AgentControllerEvent,\n state: PromptState | null,\n connection: AgentSideConnection,\n session: Session,\n): void {\n if (!state) return;\n\n switch (event.type) {\n case 'agent_start':\n state.lastTextLength = 0;\n break;\n\n case 'message_start': {\n if (event.message.role === 'assistant') {\n state.activeAssistantMessageId = event.message.id;\n state.lastTextLength = 0;\n break;\n }\n if (event.message.role !== 'signal') break;\n const text = getSignalText(event.message);\n if (text) {\n sendUpdate(connection, state.sessionId, {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text },\n });\n }\n break;\n }\n\n case 'message_update':\n if (event.event.type === 'text-delta' && event.id === state.activeAssistantMessageId && event.event.delta) {\n state.lastTextLength += event.event.delta.length;\n sendUpdate(connection, state.sessionId, {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: event.event.delta },\n });\n }\n break;\n\n case 'message_end':\n if (event.id === state.activeAssistantMessageId) {\n state.activeAssistantMessageId = undefined;\n state.lastTextLength = 0;\n }\n break;\n\n case 'tool_start':\n sendUpdate(connection, state.sessionId, {\n sessionUpdate: 'tool_call',\n toolCallId: event.toolCallId,\n title: event.toolName,\n kind: mapToolKind(event.toolName),\n status: 'in_progress',\n rawInput: JSON.stringify(event.args),\n });\n break;\n\n case 'tool_end':\n sendUpdate(connection, state.sessionId, {\n sessionUpdate: 'tool_call_update',\n toolCallId: event.toolCallId,\n status: event.isError ? 'failed' : 'completed',\n rawOutput: typeof event.result === 'string' ? event.result : JSON.stringify(event.result),\n });\n break;\n\n case 'tool_approval_required':\n void handleToolApproval(state, connection, session, event).catch(err => {\n process.stderr.write(`[acp] handleToolApproval error: ${err}\\n`);\n });\n break;\n\n case 'tool_suspended':\n void handleToolSuspended(state, connection, session, event).catch(err => {\n process.stderr.write(`[acp] handleToolSuspended error: ${err}\\n`);\n });\n break;\n\n case 'usage_update':\n accumulateUsage(state.usage, event.usage);\n break;\n\n case 'agent_end':\n state.resolve(event.reason ?? 'complete');\n break;\n\n // Ignored in v1: om_*, subagent_*, workspace_*, task_updated, etc.\n default:\n break;\n }\n}\n\nfunction sendUpdate(connection: AgentSideConnection, sessionId: string, update: SessionNotification['update']): void {\n connection.sessionUpdate({ sessionId, update }).catch(err => {\n process.stderr.write(`[acp] sessionUpdate error: ${err}\\n`);\n });\n}\n\nasync function handleToolApproval(\n state: PromptState,\n connection: AgentSideConnection,\n session: Session,\n event: Extract<AgentControllerEvent, { type: 'tool_approval_required' }>,\n): Promise<void> {\n // Auto-approve if --dangerous-auto-approve flag is set\n if (autoApprove) {\n session.respondToToolApproval({ decision: 'approve' });\n return;\n }\n\n const req: RequestPermissionRequest = {\n sessionId: state.sessionId,\n toolCall: {\n toolCallId: event.toolCallId,\n title: event.toolName,\n rawInput: JSON.stringify(event.args),\n },\n options: [\n { optionId: 'approve', name: 'Allow', kind: 'allow_once' },\n { optionId: 'reject', name: 'Reject', kind: 'reject_once' },\n ],\n };\n\n try {\n const resp = await connection.requestPermission(req);\n if (resp.outcome.outcome === 'selected') {\n const decision = resp.outcome.optionId === 'approve' ? 'approve' : 'decline';\n session.respondToToolApproval({ decision });\n } else {\n session.respondToToolApproval({ decision: 'decline' });\n }\n } catch (err) {\n process.stderr.write(`[acp] requestPermission error: ${err}\\n`);\n session.respondToToolApproval({ decision: 'decline' });\n }\n}\n\nasync function handleToolSuspended(\n state: PromptState,\n connection: AgentSideConnection,\n session: Session,\n event: Extract<AgentControllerEvent, { type: 'tool_suspended' }>,\n): Promise<void> {\n const { toolCallId, toolName, args, suspendPayload } = event;\n\n // Auto-resolve certain suspensions (mirrors headless.ts autoResolve)\n if (toolName === 'request_access' || (suspendPayload as any)?.kind === 'sandbox_access_request') {\n void session.respondToToolSuspension({ toolCallId, resumeData: 'Yes' });\n return;\n }\n\n if (toolName === 'submit_plan') {\n // Request permission for plan approval\n const req: RequestPermissionRequest = {\n sessionId: state.sessionId,\n toolCall: {\n toolCallId,\n title: toolName,\n rawInput: JSON.stringify(args),\n },\n options: [\n { optionId: 'approve', name: 'Approve Plan', kind: 'allow_once' },\n { optionId: 'reject', name: 'Reject Plan', kind: 'reject_once' },\n ],\n };\n\n try {\n const resp = await connection.requestPermission(req);\n const action =\n resp.outcome.outcome === 'selected' && resp.outcome.optionId === 'approve' ? 'approved' : 'rejected';\n void session.respondToToolSuspension({ toolCallId, resumeData: { action } });\n } catch {\n void session.respondToToolSuspension({ toolCallId, resumeData: { action: 'rejected' } });\n }\n return;\n }\n\n // For ask_user and other suspensions, auto-resolve\n void session.respondToToolSuspension({\n toolCallId,\n resumeData: 'Proceed with your best judgment. Do not ask further questions.',\n });\n}\n\nfunction accumulateUsage(target: TokenUsage, usage: TokenUsage): void {\n target.promptTokens += usage.promptTokens;\n target.completionTokens += usage.completionTokens;\n target.totalTokens += usage.totalTokens;\n if (usage.reasoningTokens) target.reasoningTokens = (target.reasoningTokens ?? 0) + usage.reasoningTokens;\n if (usage.cachedInputTokens) target.cachedInputTokens = (target.cachedInputTokens ?? 0) + usage.cachedInputTokens;\n if (usage.cacheCreationInputTokens) {\n target.cacheCreationInputTokens = (target.cacheCreationInputTokens ?? 0) + usage.cacheCreationInputTokens;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"event-mapper.js","names":[],"sources":["../../src/acp/event-mapper.ts"],"sourcesContent":["import type { SessionNotification, RequestPermissionRequest, AgentSideConnection } from '@agentclientprotocol/sdk';\nimport type { AgentControllerEvent, Session, TokenUsage } from '@mastra/core/agent-controller';\n\nlet autoApprove = false;\n\n/**\n * Enable or disable automatic tool approval (set via --dangerous-auto-approve CLI flag).\n */\nexport function setAutoApprove(value: boolean): void {\n autoApprove = value;\n}\n\n/**\n * Map a mastracode tool name to an ACP ToolKind.\n */\nfunction mapToolKind(\n toolName: string,\n): 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'think' | 'fetch' | 'other' {\n const name = toolName.toLowerCase();\n if (name.includes('edit') || name.includes('write') || name.includes('replace') || name.includes('patch'))\n return 'edit';\n if (name.includes('read') || name.includes('view') || name.includes('list') || name.includes('find')) return 'read';\n if (name.includes('delete') || name.includes('remove')) return 'delete';\n if (name.includes('search') || name.includes('grep') || name.includes('query')) return 'search';\n if (name.includes('execute') || name.includes('run') || name.includes('command') || name.includes('shell'))\n return 'execute';\n if (\n name.includes('fetch') ||\n name.includes('curl') ||\n name.includes('http') ||\n name.includes('browse') ||\n name.includes('navigate')\n )\n return 'fetch';\n if (name.includes('think') || name.includes('reason')) return 'think';\n return 'other';\n}\n\n/**\n * Accumulated state for an active prompt turn.\n */\nexport interface PromptState {\n sessionId: string;\n activeAssistantMessageId?: string;\n usage: TokenUsage;\n error?: Error;\n stopReason?: 'max_tokens' | 'refusal';\n finished?: boolean;\n cancelled?: boolean;\n suspended?: boolean;\n cancelSuspensions?: Map<string, () => Promise<void>>;\n resolve: (reason: 'complete' | 'aborted' | 'error' | 'suspended') => void;\n}\n\n/**\n * Translate an AgentControllerEvent into an ACP SessionNotification and send it\n * via the provided connection. Returns null for events that don't produce\n * a session update.\n */\nexport function handleAgentControllerEvent(\n event: AgentControllerEvent,\n state: PromptState | null,\n connection: AgentSideConnection,\n session: Session,\n): void {\n if (!state || state.finished) return;\n\n switch (event.type) {\n case 'agent_start':\n state.suspended = false;\n // Startup can arm its controller after cancel first called abort().\n if (state.cancelled && !state.cancelSuspensions?.size) session.completeDeferredAbort();\n break;\n\n case 'message_start': {\n if (event.message.role === 'assistant') {\n state.activeAssistantMessageId = event.message.id;\n break;\n }\n break;\n }\n\n case 'message_update':\n if (event.event.type === 'text-delta' && event.id === state.activeAssistantMessageId && event.event.delta) {\n sendUpdate(connection, state.sessionId, {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: event.event.delta },\n });\n }\n break;\n\n case 'message_end':\n if (event.id === state.activeAssistantMessageId) {\n state.activeAssistantMessageId = undefined;\n }\n break;\n\n case 'tool_start':\n sendUpdate(connection, state.sessionId, {\n sessionUpdate: 'tool_call',\n toolCallId: event.toolCallId,\n title: event.toolName,\n kind: mapToolKind(event.toolName),\n status: 'in_progress',\n rawInput: JSON.stringify(event.args),\n });\n break;\n\n case 'tool_end':\n sendUpdate(connection, state.sessionId, {\n sessionUpdate: 'tool_call_update',\n toolCallId: event.toolCallId,\n status: event.isError ? 'failed' : 'completed',\n rawOutput: typeof event.result === 'string' ? event.result : JSON.stringify(event.result),\n });\n break;\n\n case 'tool_approval_required':\n void handleToolApproval(state, connection, session, event).catch(err => {\n failTurn(state, session, err);\n });\n break;\n\n case 'tool_suspended':\n void handleToolSuspended(state, connection, session, event).catch(err => {\n failTurn(state, session, err);\n });\n break;\n\n case 'usage_update':\n accumulateUsage(state.usage, event.usage);\n break;\n\n case 'error':\n state.error = event.error;\n if (event.finishReason === 'length') state.stopReason = 'max_tokens';\n else if (event.finishReason === 'content-filter') state.stopReason = 'refusal';\n break;\n\n case 'agent_end':\n // A suspended run continues after the client answers the permission request.\n if (event.reason === 'suspended') {\n state.suspended = true;\n if (state.cancelled && !state.cancelSuspensions?.size) {\n session.stream.detach();\n state.resolve('aborted');\n }\n break;\n }\n state.finished = true;\n state.resolve(event.reason ?? 'complete');\n break;\n\n // Ignored in v1: om_*, subagent_*, workspace_*, task_updated, etc.\n default:\n break;\n }\n}\n\nfunction sendUpdate(connection: AgentSideConnection, sessionId: string, update: SessionNotification['update']): void {\n connection.sessionUpdate({ sessionId, update }).catch(err => {\n process.stderr.write(`[acp] sessionUpdate error: ${err}\\n`);\n });\n}\n\nasync function handleToolApproval(\n state: PromptState,\n connection: AgentSideConnection,\n session: Session,\n event: Extract<AgentControllerEvent, { type: 'tool_approval_required' }>,\n): Promise<void> {\n if (state.cancelled) {\n session.respondToToolApproval({ decision: 'decline', toolCallId: event.toolCallId });\n return;\n }\n // Auto-approve if --dangerous-auto-approve flag is set\n if (autoApprove) {\n session.respondToToolApproval({ decision: 'approve', toolCallId: event.toolCallId });\n return;\n }\n\n const req: RequestPermissionRequest = {\n sessionId: state.sessionId,\n toolCall: {\n toolCallId: event.toolCallId,\n title: event.toolName,\n rawInput: JSON.stringify(event.args),\n },\n options: [\n { optionId: 'approve', name: 'Allow', kind: 'allow_once' },\n { optionId: 'reject', name: 'Reject', kind: 'reject_once' },\n ],\n };\n\n try {\n const resp = await connection.requestPermission(req);\n if (state.finished || state.cancelled) return;\n if (resp.outcome.outcome === 'selected') {\n const decision = resp.outcome.optionId === 'approve' ? 'approve' : 'decline';\n session.respondToToolApproval({ decision, toolCallId: event.toolCallId });\n } else {\n session.respondToToolApproval({ decision: 'decline', toolCallId: event.toolCallId });\n }\n } catch (err) {\n if (state.finished || state.cancelled) return;\n process.stderr.write(`[acp] requestPermission error: ${err}\\n`);\n session.respondToToolApproval({ decision: 'decline', toolCallId: event.toolCallId });\n }\n}\n\nasync function handleToolSuspended(\n state: PromptState,\n connection: AgentSideConnection,\n session: Session,\n event: Extract<AgentControllerEvent, { type: 'tool_suspended' }>,\n): Promise<void> {\n const { toolCallId, toolName, args, suspendPayload } = event;\n\n const isSandboxAccess =\n toolName === 'request_access' ||\n (typeof suspendPayload === 'object' &&\n suspendPayload !== null &&\n 'kind' in suspendPayload &&\n suspendPayload.kind === 'sandbox_access_request');\n if (isSandboxAccess || toolName === 'submit_plan') {\n state.cancelSuspensions ??= new Map();\n state.cancelSuspensions.set(toolCallId, () =>\n session.resumeToolCall({\n toolCallId,\n resumeData: isSandboxAccess ? 'No' : { action: 'rejected' },\n resolveOnToolEnd: true,\n }),\n );\n }\n if (state.cancelled) {\n try {\n await state.cancelSuspensions?.get(toolCallId)?.();\n } finally {\n state.cancelSuspensions?.delete(toolCallId);\n if (!state.finished) {\n session.completeDeferredAbort();\n state.resolve('aborted');\n }\n }\n return;\n }\n if (isSandboxAccess) {\n let approved = autoApprove;\n if (!autoApprove) {\n try {\n const response = await connection.requestPermission({\n sessionId: state.sessionId,\n toolCall: { toolCallId, title: toolName, rawInput: JSON.stringify(args) },\n options: [\n { optionId: 'approve', name: 'Allow access', kind: 'allow_once' },\n { optionId: 'reject', name: 'Deny access', kind: 'reject_once' },\n ],\n });\n approved = response.outcome.outcome === 'selected' && response.outcome.optionId === 'approve';\n } catch {\n approved = false;\n }\n }\n if (state.finished || state.cancelled) return;\n state.cancelSuspensions?.delete(toolCallId);\n await session.respondToToolSuspension({ toolCallId, resumeData: approved ? 'Yes' : 'No' });\n return;\n }\n\n if (toolName === 'submit_plan') {\n // Request permission for plan approval\n const req: RequestPermissionRequest = {\n sessionId: state.sessionId,\n toolCall: {\n toolCallId,\n title: toolName,\n rawInput: JSON.stringify(args),\n },\n options: [\n { optionId: 'approve', name: 'Approve Plan', kind: 'allow_once' },\n { optionId: 'reject', name: 'Reject Plan', kind: 'reject_once' },\n ],\n };\n\n let action: 'approved' | 'rejected' = 'rejected';\n try {\n const resp = await connection.requestPermission(req);\n if (resp.outcome.outcome === 'selected' && resp.outcome.optionId === 'approve') action = 'approved';\n } catch {\n // A missing answer never grants permission.\n }\n if (state.finished || state.cancelled) return;\n state.cancelSuspensions?.delete(toolCallId);\n await session.respondToToolSuspension({ toolCallId, resumeData: { action } });\n return;\n }\n\n throw new Error(`Tool \"${toolName}\" requires an interaction that this ACP server does not support`);\n}\n\nfunction failTurn(state: PromptState, session: Session, error: unknown): void {\n if (state.finished || state.cancelled) return;\n state.error = error instanceof Error ? error : new Error(String(error));\n state.finished = true;\n state.resolve('error');\n session.abort();\n}\n\nfunction accumulateUsage(target: TokenUsage, usage: TokenUsage): void {\n target.promptTokens += usage.promptTokens;\n target.completionTokens += usage.completionTokens;\n target.totalTokens += usage.totalTokens;\n if (usage.reasoningTokens) target.reasoningTokens = (target.reasoningTokens ?? 0) + usage.reasoningTokens;\n if (usage.cachedInputTokens) target.cachedInputTokens = (target.cachedInputTokens ?? 0) + usage.cachedInputTokens;\n if (usage.cacheCreationInputTokens) {\n target.cacheCreationInputTokens = (target.cacheCreationInputTokens ?? 0) + usage.cacheCreationInputTokens;\n }\n}\n"],"mappings":"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"}
|
package/dist/acp/index.d.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Entry point for ACP server mode.
|
|
3
|
-
* Initializes mastracode and runs the ACP protocol over stdio.
|
|
4
|
-
*/
|
|
1
|
+
/** Entry point for Mastra Code's ACP server over stdio. */
|
|
5
2
|
export declare function acpMain(options?: {
|
|
6
3
|
dangerousAutoApprove?: boolean;
|
|
7
4
|
coAuthor?: {
|
package/dist/acp/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/acp/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/acp/index.ts"],"names":[],"mappings":"AAIA,2DAA2D;AAC3D,wBAAsB,OAAO,CAAC,OAAO,CAAC,EAAE;IACtC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9C,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhB"}
|
package/dist/acp/index.js
CHANGED
|
@@ -1,63 +1,21 @@
|
|
|
1
1
|
import { setAutoApprove } from "./event-mapper.js";
|
|
2
|
-
import {
|
|
3
|
-
import { createMastraCode } from "../index.js";
|
|
2
|
+
import { createAcpSession } from "./runtime.js";
|
|
4
3
|
import { runAcpServer } from "./server.js";
|
|
5
4
|
//#region src/acp/index.ts
|
|
6
|
-
/**
|
|
7
|
-
* Entry point for ACP server mode.
|
|
8
|
-
* Initializes mastracode and runs the ACP protocol over stdio.
|
|
9
|
-
*/
|
|
5
|
+
/** Entry point for Mastra Code's ACP server over stdio. */
|
|
10
6
|
async function acpMain(options) {
|
|
11
|
-
|
|
7
|
+
setAutoApprove(options?.dangerousAutoApprove === true);
|
|
12
8
|
const originalConsoleLog = console.log;
|
|
13
9
|
console.log = (...args) => {
|
|
14
10
|
process.stderr.write(args.map(String).join(" ") + "\n");
|
|
15
11
|
};
|
|
16
|
-
let result;
|
|
17
12
|
try {
|
|
18
|
-
|
|
19
|
-
coAuthor: options?.coAuthor,
|
|
20
|
-
unixSocketPubSub: false,
|
|
21
|
-
disableMcp: false,
|
|
22
|
-
disableHooks: false
|
|
23
|
-
});
|
|
24
|
-
const { controller, mcpManager, signalsPubSub } = result;
|
|
25
|
-
const modes = [
|
|
26
|
-
{
|
|
27
|
-
id: "build",
|
|
28
|
-
name: "Build"
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
id: "plan",
|
|
32
|
-
name: "Plan"
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
id: "fast",
|
|
36
|
-
name: "Fast"
|
|
37
|
-
}
|
|
38
|
-
];
|
|
39
|
-
const cleanup = async () => {
|
|
40
|
-
releaseAllThreadLocks();
|
|
41
|
-
const closeSignalsPubSub = signalsPubSub?.close;
|
|
42
|
-
await Promise.allSettled([
|
|
43
|
-
mcpManager?.disconnect(),
|
|
44
|
-
controller?.getMastra()?.stopWorkers(),
|
|
45
|
-
controller?.stopIntervals(),
|
|
46
|
-
closeSignalsPubSub?.()
|
|
47
|
-
]);
|
|
48
|
-
console.log = originalConsoleLog;
|
|
49
|
-
};
|
|
50
|
-
const handleSignal = async () => {
|
|
51
|
-
await cleanup();
|
|
52
|
-
process.exit(0);
|
|
53
|
-
};
|
|
54
|
-
process.on("SIGINT", handleSignal);
|
|
55
|
-
process.on("SIGTERM", handleSignal);
|
|
56
|
-
await runAcpServer(controller, modes, cleanup);
|
|
13
|
+
await runAcpServer((request) => createAcpSession(request, { coAuthor: options?.coAuthor }));
|
|
57
14
|
} catch (error) {
|
|
58
15
|
process.stderr.write(`[acp] Fatal error: ${error}\n`);
|
|
59
|
-
console.log = originalConsoleLog;
|
|
60
16
|
process.exit(1);
|
|
17
|
+
} finally {
|
|
18
|
+
console.log = originalConsoleLog;
|
|
61
19
|
}
|
|
62
20
|
}
|
|
63
21
|
//#endregion
|
package/dist/acp/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/acp/index.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/acp/index.ts"],"sourcesContent":["import { setAutoApprove } from './event-mapper.js';\nimport { createAcpSession } from './runtime.js';\nimport { runAcpServer } from './server.js';\n\n/** Entry point for Mastra Code's ACP server over stdio. */\nexport async function acpMain(options?: {\n dangerousAutoApprove?: boolean;\n coAuthor?: { name?: string; email?: string };\n}): Promise<void> {\n setAutoApprove(options?.dangerousAutoApprove === true);\n // stdout is reserved for the JSON-RPC stream.\n // eslint-disable-next-line no-console\n const originalConsoleLog = console.log;\n // eslint-disable-next-line no-console\n console.log = (...args: unknown[]) => {\n process.stderr.write(args.map(String).join(' ') + '\\n');\n };\n try {\n await runAcpServer(request => createAcpSession(request, { coAuthor: options?.coAuthor }));\n } catch (error) {\n process.stderr.write(`[acp] Fatal error: ${error}\\n`);\n process.exit(1);\n } finally {\n // eslint-disable-next-line no-console\n console.log = originalConsoleLog;\n }\n}\n"],"mappings":";;;;;AAKA,eAAsB,QAAQ,SAGZ;CAChB,eAAe,SAAS,yBAAyB,IAAI;CAGrD,MAAM,qBAAqB,QAAQ;CAEnC,QAAQ,OAAO,GAAG,SAAoB;EACpC,QAAQ,OAAO,MAAM,KAAK,IAAI,MAAM,CAAC,CAAC,KAAK,GAAG,IAAI,IAAI;CACxD;CACA,IAAI;EACF,MAAM,cAAa,YAAW,iBAAiB,SAAS,EAAE,UAAU,SAAS,SAAS,CAAC,CAAC;CAC1F,SAAS,OAAO;EACd,QAAQ,OAAO,MAAM,sBAAsB,MAAM,GAAG;EACpD,QAAQ,KAAK,CAAC;CAChB,UAAU;EAER,QAAQ,MAAM;CAChB;AACF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { NewSessionRequest } from '@agentclientprotocol/sdk';
|
|
2
|
+
import type { MastraCodeConfig } from '../index.js';
|
|
3
|
+
import type { AcpSessionRuntime } from './agent.js';
|
|
4
|
+
export declare function createAcpSession(request: NewSessionRequest, options?: Pick<MastraCodeConfig, 'coAuthor'>): Promise<AcpSessionRuntime>;
|
|
5
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/acp/runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGpD,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,iBAAiB,EAC1B,OAAO,GAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAM,GAC/C,OAAO,CAAC,iBAAiB,CAAC,CAgF5B"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { withCleanupFailure } from "./errors.js";
|
|
2
|
+
import { loadSettings, resolveDefaultThinkingLevel } from "../onboarding/settings.js";
|
|
3
|
+
import { createMastraCode } from "../index.js";
|
|
4
|
+
import { RequestError } from "@agentclientprotocol/sdk";
|
|
5
|
+
//#region src/acp/runtime.ts
|
|
6
|
+
async function createAcpSession(request, options = {}) {
|
|
7
|
+
const names = /* @__PURE__ */ new Set();
|
|
8
|
+
const servers = request.mcpServers.map((server) => {
|
|
9
|
+
if ("type" in server && server.type === "sse") throw RequestError.invalidParams(void 0, "Legacy SSE MCP servers are unsupported; use HTTP or stdio");
|
|
10
|
+
if (names.has(server.name)) throw RequestError.invalidParams(void 0, `Duplicate MCP server name: ${server.name}`);
|
|
11
|
+
names.add(server.name);
|
|
12
|
+
const config = "command" in server ? {
|
|
13
|
+
command: server.command,
|
|
14
|
+
args: server.args,
|
|
15
|
+
env: Object.fromEntries(server.env.map((item) => [item.name, item.value])),
|
|
16
|
+
cwd: request.cwd
|
|
17
|
+
} : {
|
|
18
|
+
url: server.url,
|
|
19
|
+
headers: Object.fromEntries(server.headers.map((item) => [item.name, item.value]))
|
|
20
|
+
};
|
|
21
|
+
return [server.name, config];
|
|
22
|
+
});
|
|
23
|
+
const result = await createMastraCode({
|
|
24
|
+
coAuthor: options.coAuthor,
|
|
25
|
+
cwd: request.cwd,
|
|
26
|
+
initialState: {
|
|
27
|
+
projectPath: request.cwd,
|
|
28
|
+
yolo: false,
|
|
29
|
+
permissionRules: {
|
|
30
|
+
categories: {},
|
|
31
|
+
tools: { ask_user: "deny" }
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
mcpServers: Object.fromEntries(servers),
|
|
35
|
+
disabledTools: ["ask_user"],
|
|
36
|
+
unixSocketPubSub: false,
|
|
37
|
+
disableMcp: false,
|
|
38
|
+
disableHooks: false,
|
|
39
|
+
disableEnvFile: true
|
|
40
|
+
});
|
|
41
|
+
const settings = loadSettings();
|
|
42
|
+
let cleanupPromise;
|
|
43
|
+
const runtime = {
|
|
44
|
+
controller: result.controller,
|
|
45
|
+
session: result.session,
|
|
46
|
+
modes: result.controller.listModes(),
|
|
47
|
+
getSkills: async () => (await result.controller.resolveWorkspace({ session: result.session }))?.skills,
|
|
48
|
+
getThinkingLevel: () => result.session.state.get().thinkingLevel ?? resolveDefaultThinkingLevel(settings, result.session.mode.get()).level,
|
|
49
|
+
cleanup: () => cleanupPromise ??= (async () => {
|
|
50
|
+
result.session.abort();
|
|
51
|
+
result.session.thread.detachFromCurrent();
|
|
52
|
+
result.stopPluginSignalProviders();
|
|
53
|
+
result.githubSignals?.stopAllPolling();
|
|
54
|
+
await Promise.allSettled([
|
|
55
|
+
result.session.thread.clearAndReleaseLock(),
|
|
56
|
+
result.mcpManager?.disconnect(),
|
|
57
|
+
result.controller.getMastra()?.stopWorkers(),
|
|
58
|
+
result.controller.stopIntervals(),
|
|
59
|
+
result.signalsPubSub?.close?.()
|
|
60
|
+
]);
|
|
61
|
+
await result.storage.close();
|
|
62
|
+
})()
|
|
63
|
+
};
|
|
64
|
+
try {
|
|
65
|
+
const failed = (await result.mcpManager?.initInBackground())?.failed.filter((server) => names.has(server.name)) ?? [];
|
|
66
|
+
if (failed.length) throw RequestError.internalError(void 0, failed.map((server) => `MCP server ${server.name}: ${server.error ?? "connection failed"}`).join("; "));
|
|
67
|
+
return runtime;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
try {
|
|
70
|
+
await runtime.cleanup?.();
|
|
71
|
+
} catch (cleanupError) {
|
|
72
|
+
throw withCleanupFailure(error, cleanupError);
|
|
73
|
+
}
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
export { createAcpSession };
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","names":[],"sources":["../../src/acp/runtime.ts"],"sourcesContent":["import { RequestError } from '@agentclientprotocol/sdk';\nimport type { NewSessionRequest } from '@agentclientprotocol/sdk';\nimport { createMastraCode } from '../index.js';\nimport type { MastraCodeConfig } from '../index.js';\nimport type { McpServerConfig } from '../mcp/types.js';\nimport { loadSettings, resolveDefaultThinkingLevel } from '../onboarding/settings.js';\nimport type { AcpSessionRuntime } from './agent.js';\nimport { withCleanupFailure } from './errors.js';\n\nexport async function createAcpSession(\n request: NewSessionRequest,\n options: Pick<MastraCodeConfig, 'coAuthor'> = {},\n): Promise<AcpSessionRuntime> {\n const names = new Set<string>();\n const servers = request.mcpServers.map(server => {\n if ('type' in server && server.type === 'sse')\n throw RequestError.invalidParams(undefined, 'Legacy SSE MCP servers are unsupported; use HTTP or stdio');\n if (names.has(server.name))\n throw RequestError.invalidParams(undefined, `Duplicate MCP server name: ${server.name}`);\n names.add(server.name);\n const config: McpServerConfig =\n 'command' in server\n ? {\n command: server.command,\n args: server.args,\n env: Object.fromEntries(server.env.map(item => [item.name, item.value])),\n cwd: request.cwd,\n }\n : { url: server.url, headers: Object.fromEntries(server.headers.map(item => [item.name, item.value])) };\n return [server.name, config] as const;\n });\n const result = await createMastraCode({\n coAuthor: options.coAuthor,\n cwd: request.cwd,\n initialState: {\n projectPath: request.cwd,\n yolo: false,\n permissionRules: { categories: {}, tools: { ask_user: 'deny' } },\n },\n mcpServers: Object.fromEntries(servers),\n // ACP clients can answer permission requests, but have no free-text tool response method.\n disabledTools: ['ask_user'],\n unixSocketPubSub: false,\n disableMcp: false,\n disableHooks: false,\n // Project environment files must not mutate other ACP sessions.\n disableEnvFile: true,\n });\n const settings = loadSettings();\n let cleanupPromise: Promise<void> | undefined;\n const runtime: AcpSessionRuntime = {\n controller: result.controller,\n session: result.session,\n modes: result.controller.listModes(),\n getSkills: async () => (await result.controller.resolveWorkspace({ session: result.session }))?.skills,\n getThinkingLevel: () =>\n result.session.state.get().thinkingLevel ??\n resolveDefaultThinkingLevel(settings, result.session.mode.get()).level,\n cleanup: () =>\n (cleanupPromise ??= (async () => {\n result.session.abort();\n result.session.thread.detachFromCurrent();\n result.stopPluginSignalProviders();\n result.githubSignals?.stopAllPolling();\n await Promise.allSettled([\n result.session.thread.clearAndReleaseLock(),\n result.mcpManager?.disconnect(),\n result.controller.getMastra()?.stopWorkers(),\n result.controller.stopIntervals(),\n (result.signalsPubSub as { close?: () => void | Promise<void> } | undefined)?.close?.(),\n ]);\n await result.storage.close();\n })()),\n };\n try {\n const status = await result.mcpManager?.initInBackground();\n const failed = status?.failed.filter(server => names.has(server.name)) ?? [];\n if (failed.length)\n throw RequestError.internalError(\n undefined,\n failed.map(server => `MCP server ${server.name}: ${server.error ?? 'connection failed'}`).join('; '),\n );\n\n return runtime;\n } catch (error) {\n try {\n await runtime.cleanup?.();\n } catch (cleanupError) {\n throw withCleanupFailure(error, cleanupError);\n }\n throw error;\n }\n}\n"],"mappings":";;;;;AASA,eAAsB,iBACpB,SACA,UAA8C,CAAC,GACnB;CAC5B,MAAM,wBAAQ,IAAI,IAAY;CAC9B,MAAM,UAAU,QAAQ,WAAW,KAAI,WAAU;EAC/C,IAAI,UAAU,UAAU,OAAO,SAAS,OACtC,MAAM,aAAa,cAAc,KAAA,GAAW,2DAA2D;EACzG,IAAI,MAAM,IAAI,OAAO,IAAI,GACvB,MAAM,aAAa,cAAc,KAAA,GAAW,8BAA8B,OAAO,MAAM;EACzF,MAAM,IAAI,OAAO,IAAI;EACrB,MAAM,SACJ,aAAa,SACT;GACE,SAAS,OAAO;GAChB,MAAM,OAAO;GACb,KAAK,OAAO,YAAY,OAAO,IAAI,KAAI,SAAQ,CAAC,KAAK,MAAM,KAAK,KAAK,CAAC,CAAC;GACvE,KAAK,QAAQ;EACf,IACA;GAAE,KAAK,OAAO;GAAK,SAAS,OAAO,YAAY,OAAO,QAAQ,KAAI,SAAQ,CAAC,KAAK,MAAM,KAAK,KAAK,CAAC,CAAC;EAAE;EAC1G,OAAO,CAAC,OAAO,MAAM,MAAM;CAC7B,CAAC;CACD,MAAM,SAAS,MAAM,iBAAiB;EACpC,UAAU,QAAQ;EAClB,KAAK,QAAQ;EACb,cAAc;GACZ,aAAa,QAAQ;GACrB,MAAM;GACN,iBAAiB;IAAE,YAAY,CAAC;IAAG,OAAO,EAAE,UAAU,OAAO;GAAE;EACjE;EACA,YAAY,OAAO,YAAY,OAAO;EAEtC,eAAe,CAAC,UAAU;EAC1B,kBAAkB;EAClB,YAAY;EACZ,cAAc;EAEd,gBAAgB;CAClB,CAAC;CACD,MAAM,WAAW,aAAa;CAC9B,IAAI;CACJ,MAAM,UAA6B;EACjC,YAAY,OAAO;EACnB,SAAS,OAAO;EAChB,OAAO,OAAO,WAAW,UAAU;EACnC,WAAW,aAAa,MAAM,OAAO,WAAW,iBAAiB,EAAE,SAAS,OAAO,QAAQ,CAAC,EAAA,EAAI;EAChG,wBACE,OAAO,QAAQ,MAAM,IAAI,CAAC,CAAC,iBAC3B,4BAA4B,UAAU,OAAO,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC;EACnE,eACG,oBAAoB,YAAY;GAC/B,OAAO,QAAQ,MAAM;GACrB,OAAO,QAAQ,OAAO,kBAAkB;GACxC,OAAO,0BAA0B;GACjC,OAAO,eAAe,eAAe;GACrC,MAAM,QAAQ,WAAW;IACvB,OAAO,QAAQ,OAAO,oBAAoB;IAC1C,OAAO,YAAY,WAAW;IAC9B,OAAO,WAAW,UAAU,CAAC,EAAE,YAAY;IAC3C,OAAO,WAAW,cAAc;IAC/B,OAAO,eAAsE,QAAQ;GACxF,CAAC;GACD,MAAM,OAAO,QAAQ,MAAM;EAC7B,EAAA,CAAG;CACP;CACA,IAAI;EAEF,MAAM,UAAS,MADM,OAAO,YAAY,iBAAiB,EAAA,EAClC,OAAO,QAAO,WAAU,MAAM,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC;EAC3E,IAAI,OAAO,QACT,MAAM,aAAa,cACjB,KAAA,GACA,OAAO,KAAI,WAAU,cAAc,OAAO,KAAK,IAAI,OAAO,SAAS,qBAAqB,CAAC,CAAC,KAAK,IAAI,CACrG;EAEF,OAAO;CACT,SAAS,OAAO;EACd,IAAI;GACF,MAAM,QAAQ,UAAU;EAC1B,SAAS,cAAc;GACrB,MAAM,mBAAmB,OAAO,YAAY;EAC9C;EACA,MAAM;CACR;AACF"}
|
package/dist/acp/server.d.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
* This sets up the JSON-RPC stream and keeps the process alive until the client disconnects.
|
|
5
|
-
*/
|
|
6
|
-
export declare function runAcpServer(controller: AgentController, modes: AgentControllerMode[], cleanup?: () => Promise<void>): Promise<void>;
|
|
1
|
+
import type { AcpSessionFactory } from './agent.js';
|
|
2
|
+
/** Run the ACP server over stdio and release its sessions on disconnect. */
|
|
3
|
+
export declare function runAcpServer(createSession: AcpSessionFactory): Promise<void>;
|
|
7
4
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/acp/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/acp/server.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/acp/server.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,4EAA4E;AAC5E,wBAAsB,YAAY,CAAC,aAAa,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmClF"}
|
package/dist/acp/server.js
CHANGED
|
@@ -1,32 +1,35 @@
|
|
|
1
1
|
import { MastraCodeAcpAgent } from "./agent.js";
|
|
2
2
|
import { AgentSideConnection, ndJsonStream } from "@agentclientprotocol/sdk";
|
|
3
|
-
import { randomUUID } from "crypto";
|
|
4
3
|
import { Readable, Writable } from "stream";
|
|
5
4
|
//#region src/acp/server.ts
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
* This sets up the JSON-RPC stream and keeps the process alive until the client disconnects.
|
|
9
|
-
*/
|
|
10
|
-
async function runAcpServer(controller, modes, cleanup) {
|
|
5
|
+
/** Run the ACP server over stdio and release its sessions on disconnect. */
|
|
6
|
+
async function runAcpServer(createSession) {
|
|
11
7
|
const input = Readable.toWeb(process.stdin);
|
|
12
|
-
const
|
|
13
|
-
let session;
|
|
8
|
+
const output = Writable.toWeb(process.stdout);
|
|
14
9
|
let agent;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
let cleanupPromise;
|
|
11
|
+
let shutdownPromise;
|
|
12
|
+
const dispose = () => cleanupPromise ??= Promise.resolve().then(() => agent?.dispose());
|
|
13
|
+
const handleSignal = () => {
|
|
14
|
+
shutdownPromise ??= dispose().then(() => process.exit(0), (error) => {
|
|
15
|
+
process.stderr.write(`[acp] Shutdown failed: ${error}\n`);
|
|
16
|
+
process.exit(1);
|
|
19
17
|
});
|
|
20
|
-
|
|
18
|
+
};
|
|
19
|
+
process.on("SIGINT", handleSignal);
|
|
20
|
+
process.on("SIGTERM", handleSignal);
|
|
21
|
+
try {
|
|
21
22
|
await new AgentSideConnection((conn) => {
|
|
22
|
-
agent = new MastraCodeAcpAgent(conn,
|
|
23
|
+
agent = new MastraCodeAcpAgent(conn, createSession);
|
|
23
24
|
return agent;
|
|
24
|
-
},
|
|
25
|
+
}, ndJsonStream(output, input)).closed;
|
|
25
26
|
} finally {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
try {
|
|
28
|
+
await dispose();
|
|
29
|
+
} finally {
|
|
30
|
+
process.off("SIGINT", handleSignal);
|
|
31
|
+
process.off("SIGTERM", handleSignal);
|
|
32
|
+
}
|
|
30
33
|
}
|
|
31
34
|
}
|
|
32
35
|
//#endregion
|
package/dist/acp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","names":[],"sources":["../../src/acp/server.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"server.js","names":[],"sources":["../../src/acp/server.ts"],"sourcesContent":["import { Readable, Writable } from 'node:stream';\nimport { AgentSideConnection, ndJsonStream } from '@agentclientprotocol/sdk';\nimport { MastraCodeAcpAgent } from './agent.js';\nimport type { AcpSessionFactory } from './agent.js';\n\n/** Run the ACP server over stdio and release its sessions on disconnect. */\nexport async function runAcpServer(createSession: AcpSessionFactory): Promise<void> {\n const input = Readable.toWeb(process.stdin) as ReadableStream<Uint8Array>;\n const output = Writable.toWeb(process.stdout) as WritableStream<Uint8Array>;\n let agent: MastraCodeAcpAgent | undefined;\n let cleanupPromise: Promise<void> | undefined;\n let shutdownPromise: Promise<void> | undefined;\n const dispose = () => (cleanupPromise ??= Promise.resolve().then(() => agent?.dispose()));\n const handleSignal = () => {\n shutdownPromise ??= dispose().then(\n () => process.exit(0),\n error => {\n process.stderr.write(`[acp] Shutdown failed: ${error}\\n`);\n process.exit(1);\n },\n );\n };\n process.on('SIGINT', handleSignal);\n process.on('SIGTERM', handleSignal);\n try {\n const connection = new AgentSideConnection(\n conn => {\n agent = new MastraCodeAcpAgent(conn, createSession);\n return agent;\n },\n ndJsonStream(output, input),\n );\n await connection.closed;\n } finally {\n try {\n await dispose();\n } finally {\n process.off('SIGINT', handleSignal);\n process.off('SIGTERM', handleSignal);\n }\n }\n}\n"],"mappings":";;;;;AAMA,eAAsB,aAAa,eAAiD;CAClF,MAAM,QAAQ,SAAS,MAAM,QAAQ,KAAK;CAC1C,MAAM,SAAS,SAAS,MAAM,QAAQ,MAAM;CAC5C,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,MAAM,gBAAiB,mBAAmB,QAAQ,QAAQ,CAAC,CAAC,WAAW,OAAO,QAAQ,CAAC;CACvF,MAAM,qBAAqB;EACzB,oBAAoB,QAAQ,CAAC,CAAC,WACtB,QAAQ,KAAK,CAAC,IACpB,UAAS;GACP,QAAQ,OAAO,MAAM,0BAA0B,MAAM,GAAG;GACxD,QAAQ,KAAK,CAAC;EAChB,CACF;CACF;CACA,QAAQ,GAAG,UAAU,YAAY;CACjC,QAAQ,GAAG,WAAW,YAAY;CAClC,IAAI;EAQF,MAAM,IAPiB,qBACrB,SAAQ;GACN,QAAQ,IAAI,mBAAmB,MAAM,aAAa;GAClD,OAAO;EACT,GACA,aAAa,QAAQ,KAAK,CAEb,CAAC,CAAC;CACnB,UAAU;EACR,IAAI;GACF,MAAM,QAAQ;EAChB,UAAU;GACR,QAAQ,IAAI,UAAU,YAAY;GAClC,QAAQ,IAAI,WAAW,YAAY;EACrC;CACF;AACF"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AvailableCommand } from '@agentclientprotocol/sdk';
|
|
2
|
+
import type { WorkspaceSkills } from '@mastra/core/workspace';
|
|
3
|
+
export type AcpSkills = Pick<WorkspaceSkills, 'list' | 'get' | 'maybeRefresh'>;
|
|
4
|
+
export declare function listSkillCommands(skills?: AcpSkills): Promise<AvailableCommand[]>;
|
|
5
|
+
export declare function expandSkillCommand(content: string, skills: AcpSkills | undefined, commands: AvailableCommand[]): Promise<string>;
|
|
6
|
+
//# sourceMappingURL=skills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/acp/skills.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,OAAO,KAAK,EAAiB,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE7E,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,KAAK,GAAG,cAAc,CAAC,CAAC;AAU/E,wBAAsB,iBAAiB,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAQvF;AAED,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,SAAS,GAAG,SAAS,EAC7B,QAAQ,EAAE,gBAAgB,EAAE,GAC3B,OAAO,CAAC,MAAM,CAAC,CAoBjB"}
|