aws-runtime-bridge 1.7.50 → 1.8.0
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/dist/adapter/AcodeSdkAdapter.d.ts +30 -3
- package/dist/adapter/AcodeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/AcodeSdkAdapter.js +427 -105
- package/dist/adapter/AcodeSdkAdapter.test.js +1093 -86
- package/dist/adapter/ClaudeSdkAdapter.test.js +31 -8
- package/dist/adapter/CodexSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/CodexSdkAdapter.js +2 -0
- package/dist/adapter/OpencodeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/OpencodeSdkAdapter.js +2 -0
- package/dist/adapter/SdkProviderSpi.d.ts.map +1 -1
- package/dist/adapter/adapter.test.js +2 -2
- package/dist/adapter/idle-poll-loop.d.ts +4 -4
- package/dist/adapter/idle-poll-loop.d.ts.map +1 -1
- package/dist/adapter/idle-poll-loop.js +3 -3
- package/dist/adapter/idle-poll-loop.test.js +15 -1
- package/dist/adapter/types.d.ts +25 -6
- package/dist/adapter/types.d.ts.map +1 -1
- package/dist/adapter/types.js +221 -110
- package/dist/adapter/types.test.js +10 -3
- package/dist/routes/instance.d.ts.map +1 -1
- package/dist/routes/instance.js +6 -7
- package/dist/routes/runtime-binding.js +2 -2
- package/dist/routes/terminal.d.ts +20 -5
- package/dist/routes/terminal.d.ts.map +1 -1
- package/dist/routes/terminal.js +420 -170
- package/dist/routes/terminal.test.js +380 -208
- package/dist/services/mcp-launch-binding-queue.d.ts +1 -0
- package/dist/services/mcp-launch-binding-queue.d.ts.map +1 -1
- package/dist/services/mcp-launch-binding-queue.js +8 -2
- package/dist/services/mcp-launch-binding-queue.test.js +47 -4
- package/dist/services/session-output.d.ts +10 -6
- package/dist/services/session-output.d.ts.map +1 -1
- package/dist/services/session-output.js +29 -14
- package/dist/services/session-output.test.js +93 -39
- package/package/acode/dist/built-in-file-tools.d.ts +1 -1
- package/package/acode/dist/built-in-file-tools.d.ts.map +1 -1
- package/package/acode/dist/built-in-file-tools.js +388 -50
- package/package/acode/dist/runtime.d.ts +11 -3
- package/package/acode/dist/runtime.d.ts.map +1 -1
- package/package/acode/dist/runtime.js +902 -190
- package/package/acode/dist/types.d.ts +18 -5
- package/package/acode/dist/types.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.js +3 -2
- package/package/aws-client-agent-mcp/dist/mcp-server.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js +11 -9
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.js +1 -0
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/status-reporter.d.ts +2 -0
- package/package/aws-client-agent-mcp/dist/status-reporter.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/status-reporter.js +31 -3
- package/package/aws-client-agent-mcp/dist/status-reporter.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/types.d.ts +1 -1
- package/package/aws-client-agent-mcp/dist/types.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/types.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.js +2 -0
- package/package/aws-client-agent-mcp/dist/websocket-client.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.test.js +43 -0
- package/package/aws-client-agent-mcp/dist/websocket-client.test.js.map +1 -1
- package/package.json +1 -1
package/dist/adapter/types.js
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* 参考自 SpectrAI 项目的 adapter 设计,用于支持多种 AI Provider
|
|
6
6
|
*/
|
|
7
|
-
import { EventEmitter } from
|
|
8
|
-
const TEMP_CLIPBOARD_PASTE_PLACEHOLDER =
|
|
7
|
+
import { EventEmitter } from "node:events";
|
|
8
|
+
const TEMP_CLIPBOARD_PASTE_PLACEHOLDER = "[temp clipboard paste file]";
|
|
9
9
|
const WINDOWS_TEMP_CLIPBOARD_PASTE_PATH = /[A-Z]:(?:\\\\|\\)[^\r\n"'`]*?(?:\\\\|\\)mini-term-clipboard(?:\\\\|\\)paste-\d+\.txt/gi;
|
|
10
10
|
const POSIX_TEMP_CLIPBOARD_PASTE_PATH = /\/[^\r\n"'`]*?\/mini-term-clipboard\/paste-\d+\.txt/gi;
|
|
11
11
|
const BARE_TEMP_CLIPBOARD_PASTE_PATH = /mini-term-clipboard[\\/]paste-\d+\.txt/gi;
|
|
@@ -24,8 +24,12 @@ export function redactTransientClipboardPastePaths(text) {
|
|
|
24
24
|
* 主流程:剥离包裹引号 -> 要求整串匹配,避免误拦截显式读取该文件的正常命令。
|
|
25
25
|
*/
|
|
26
26
|
export function isTransientClipboardPasteFilePath(text) {
|
|
27
|
-
const trimmed = text.trim().replace(/^(["'])(.*)\1$/,
|
|
28
|
-
return [
|
|
27
|
+
const trimmed = text.trim().replace(/^(["'])(.*)\1$/, "$2");
|
|
28
|
+
return [
|
|
29
|
+
WINDOWS_TEMP_CLIPBOARD_PASTE_PATH,
|
|
30
|
+
POSIX_TEMP_CLIPBOARD_PASTE_PATH,
|
|
31
|
+
BARE_TEMP_CLIPBOARD_PASTE_PATH,
|
|
32
|
+
].some((pattern) => {
|
|
29
33
|
pattern.lastIndex = 0;
|
|
30
34
|
const match = pattern.exec(trimmed);
|
|
31
35
|
return Boolean(match && match[0] === trimmed);
|
|
@@ -35,13 +39,13 @@ export function isTransientClipboardPasteFilePath(text) {
|
|
|
35
39
|
* 递归脱敏工具展示参数,保留真实执行输入不变,仅用于日志/状态/时间线展示。
|
|
36
40
|
*/
|
|
37
41
|
export function redactTransientClipboardPastePathsInValue(value) {
|
|
38
|
-
if (typeof value ===
|
|
42
|
+
if (typeof value === "string") {
|
|
39
43
|
return redactTransientClipboardPastePaths(value);
|
|
40
44
|
}
|
|
41
45
|
if (Array.isArray(value)) {
|
|
42
46
|
return value.map((item) => redactTransientClipboardPastePathsInValue(item));
|
|
43
47
|
}
|
|
44
|
-
if (value && typeof value ===
|
|
48
|
+
if (value && typeof value === "object") {
|
|
45
49
|
return Object.fromEntries(Object.entries(value).map(([key, item]) => [
|
|
46
50
|
key,
|
|
47
51
|
redactTransientClipboardPastePathsInValue(item),
|
|
@@ -57,23 +61,63 @@ export function redactTransientClipboardPastePathsInValue(value) {
|
|
|
57
61
|
*/
|
|
58
62
|
const KNOWN_MCP_TOOLS = {
|
|
59
63
|
// aws-mcp 工具
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
64
|
+
get_colleague: "aws-mcp",
|
|
65
|
+
get_group_rooms: "aws-mcp",
|
|
66
|
+
get_profile: "aws-mcp",
|
|
67
|
+
get_status: "aws-mcp",
|
|
68
|
+
hire_colleague: "aws-mcp",
|
|
69
|
+
hire_colleagues_batch: "aws-mcp",
|
|
70
|
+
send_group: "aws-mcp",
|
|
71
|
+
send_private: "aws-mcp",
|
|
72
|
+
poll_message: "aws-mcp",
|
|
73
|
+
get_message: "aws-mcp",
|
|
74
|
+
get_dm_history: "aws-mcp",
|
|
75
|
+
get_group_history: "aws-mcp",
|
|
76
|
+
my_task: "aws-mcp",
|
|
77
|
+
submit_task_result: "aws-mcp",
|
|
78
|
+
reject_task: "aws-mcp",
|
|
79
|
+
terminate_task: "aws-mcp",
|
|
76
80
|
};
|
|
81
|
+
const AGENTSWORK_MCP_SERVER_ALIASES = new Set([
|
|
82
|
+
"aws-mcp",
|
|
83
|
+
"agents-work-studio",
|
|
84
|
+
]);
|
|
85
|
+
function canonicalizeMcpServer(serverName, toolName) {
|
|
86
|
+
const knownMcpServer = KNOWN_MCP_TOOLS[toolName.toLowerCase()];
|
|
87
|
+
if (knownMcpServer && AGENTSWORK_MCP_SERVER_ALIASES.has(serverName.toLowerCase())) {
|
|
88
|
+
return knownMcpServer;
|
|
89
|
+
}
|
|
90
|
+
return serverName;
|
|
91
|
+
}
|
|
92
|
+
export function getCanonicalMcpDetail(rawToolName) {
|
|
93
|
+
const normalizedRawToolName = rawToolName.trim();
|
|
94
|
+
if (!normalizedRawToolName)
|
|
95
|
+
return normalizedRawToolName;
|
|
96
|
+
if (normalizedRawToolName.includes("__")) {
|
|
97
|
+
const parts = normalizedRawToolName.split("__").filter(Boolean);
|
|
98
|
+
if (parts.length >= 3 && parts[0].toLowerCase() === "mcp") {
|
|
99
|
+
const serverName = parts[1];
|
|
100
|
+
const toolName = parts.slice(2).join("__");
|
|
101
|
+
return `${canonicalizeMcpServer(serverName, toolName)}/${toolName}`;
|
|
102
|
+
}
|
|
103
|
+
if (parts.length >= 2) {
|
|
104
|
+
const serverName = parts[0];
|
|
105
|
+
const toolName = parts.slice(1).join("__");
|
|
106
|
+
return `${canonicalizeMcpServer(serverName, toolName)}/${toolName}`;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const knownMcpServer = KNOWN_MCP_TOOLS[normalizedRawToolName.toLowerCase()];
|
|
110
|
+
return knownMcpServer
|
|
111
|
+
? `${knownMcpServer}/${normalizedRawToolName}`
|
|
112
|
+
: normalizedRawToolName;
|
|
113
|
+
}
|
|
114
|
+
function formatCanonicalMcpDetail(serverName, toolName) {
|
|
115
|
+
if (!serverName)
|
|
116
|
+
return toolName;
|
|
117
|
+
if (!toolName)
|
|
118
|
+
return serverName;
|
|
119
|
+
return `${canonicalizeMcpServer(serverName, toolName)}/${toolName}`;
|
|
120
|
+
}
|
|
77
121
|
/**
|
|
78
122
|
* 根据工具名称获取动作类型信息
|
|
79
123
|
* @param toolName 工具名称
|
|
@@ -82,32 +126,32 @@ const KNOWN_MCP_TOOLS = {
|
|
|
82
126
|
*/
|
|
83
127
|
export function getToolActionInfo(toolName, toolInput, metadata) {
|
|
84
128
|
if (!toolName) {
|
|
85
|
-
return { actionType:
|
|
129
|
+
return { actionType: "other", actionLabel: "调用工具" };
|
|
86
130
|
}
|
|
87
131
|
const name = toolName.toLowerCase();
|
|
88
|
-
const normalizedName = name.replace(/[_-]/g,
|
|
89
|
-
const semanticToolName = name.startsWith(
|
|
90
|
-
? name.split(
|
|
91
|
-
: name.includes(
|
|
92
|
-
? name.slice(name.indexOf(
|
|
132
|
+
const normalizedName = name.replace(/[_-]/g, "");
|
|
133
|
+
const semanticToolName = name.startsWith("mcp__")
|
|
134
|
+
? name.split("__").slice(2).join("__")
|
|
135
|
+
: name.includes("-mcp__")
|
|
136
|
+
? name.slice(name.indexOf("-mcp__") + 6)
|
|
93
137
|
: name;
|
|
94
|
-
const normalizedSemanticToolName = semanticToolName.replace(/[_-]/g,
|
|
138
|
+
const normalizedSemanticToolName = semanticToolName.replace(/[_-]/g, "");
|
|
95
139
|
const normalizeSkillList = (value) => {
|
|
96
140
|
if (!Array.isArray(value)) {
|
|
97
141
|
return [];
|
|
98
142
|
}
|
|
99
143
|
return value
|
|
100
|
-
.map((item) => String(item ??
|
|
144
|
+
.map((item) => String(item ?? "").trim())
|
|
101
145
|
.filter((item) => item.length > 0);
|
|
102
146
|
};
|
|
103
147
|
const firstString = (...values) => {
|
|
104
148
|
for (const value of values) {
|
|
105
|
-
if (typeof value ===
|
|
149
|
+
if (typeof value === "string" && value.trim()) {
|
|
106
150
|
return redactTransientClipboardPastePaths(value);
|
|
107
151
|
}
|
|
108
152
|
if (Array.isArray(value) && value.length > 0) {
|
|
109
153
|
const first = value[0];
|
|
110
|
-
if (typeof first ===
|
|
154
|
+
if (typeof first === "string" && first.trim()) {
|
|
111
155
|
return redactTransientClipboardPastePaths(first);
|
|
112
156
|
}
|
|
113
157
|
}
|
|
@@ -115,17 +159,16 @@ export function getToolActionInfo(toolName, toolInput, metadata) {
|
|
|
115
159
|
return undefined;
|
|
116
160
|
};
|
|
117
161
|
const matchesToolName = (...toolNames) => {
|
|
118
|
-
const normalizedToolNames = toolNames.map((item) => item.replace(/[_-]/g,
|
|
119
|
-
return normalizedToolNames.includes(normalizedName) ||
|
|
162
|
+
const normalizedToolNames = toolNames.map((item) => item.replace(/[_-]/g, ""));
|
|
163
|
+
return (normalizedToolNames.includes(normalizedName) ||
|
|
164
|
+
normalizedToolNames.includes(normalizedSemanticToolName));
|
|
120
165
|
};
|
|
121
|
-
// 调试日志:记录工具名
|
|
122
|
-
console.log(`[getToolActionInfo] toolName="${toolName}", name="${name}"`);
|
|
123
166
|
const loadSkills = normalizeSkillList(toolInput?.load_skills);
|
|
124
|
-
if ((name ===
|
|
167
|
+
if ((name === "task" || name === "task()") && loadSkills.length > 0) {
|
|
125
168
|
return {
|
|
126
|
-
actionType:
|
|
127
|
-
actionLabel:
|
|
128
|
-
actionDetail: loadSkills.join(
|
|
169
|
+
actionType: "skill",
|
|
170
|
+
actionLabel: "加载技能",
|
|
171
|
+
actionDetail: loadSkills.join(", "),
|
|
129
172
|
};
|
|
130
173
|
}
|
|
131
174
|
// Skill 调用
|
|
@@ -136,62 +179,94 @@ export function getToolActionInfo(toolName, toolInput, metadata) {
|
|
|
136
179
|
//
|
|
137
180
|
// 注意:SDK 发送的 tool_name 可能是 'Skill'(大写)或 'skill'(小写)
|
|
138
181
|
// 使用 toLowerCase() 统一处理
|
|
139
|
-
const isSkillTool = name ===
|
|
140
|
-
name ===
|
|
141
|
-
name ===
|
|
142
|
-
(name.includes(
|
|
143
|
-
|
|
182
|
+
const isSkillTool = name === "skill" ||
|
|
183
|
+
name === "load_skill" ||
|
|
184
|
+
name === "disclosecontext" ||
|
|
185
|
+
(name.includes("skill") &&
|
|
186
|
+
!name.startsWith("mcp__") &&
|
|
187
|
+
!name.includes("mcp_"));
|
|
144
188
|
if (isSkillTool) {
|
|
145
189
|
// Skill 参数可能有多种格式:
|
|
146
190
|
// 1. { skill: "skillName" }
|
|
147
191
|
// 2. { name: "skillName" }
|
|
148
192
|
// 3. { args: { name: "skillName", ... } } // task() 格式
|
|
149
193
|
// 4. { load_skills: ["skill1", "skill2"] } // task() 加载技能格式
|
|
150
|
-
let skillName =
|
|
194
|
+
let skillName = "";
|
|
151
195
|
// 检查 load_skills 格式(task 工具)
|
|
152
|
-
if (Array.isArray(toolInput?.load_skills) &&
|
|
153
|
-
|
|
196
|
+
if (Array.isArray(toolInput?.load_skills) &&
|
|
197
|
+
toolInput.load_skills.length > 0) {
|
|
198
|
+
skillName = toolInput.load_skills.join(", ");
|
|
154
199
|
}
|
|
155
200
|
// 检查 skill 参数
|
|
156
|
-
else if (typeof toolInput?.skill ===
|
|
201
|
+
else if (typeof toolInput?.skill === "string") {
|
|
157
202
|
skillName = toolInput.skill;
|
|
158
203
|
}
|
|
159
204
|
// 检查 name 参数
|
|
160
|
-
else if (typeof toolInput?.name ===
|
|
205
|
+
else if (typeof toolInput?.name === "string") {
|
|
161
206
|
skillName = toolInput.name;
|
|
162
207
|
}
|
|
163
208
|
// 检查嵌套的 args.name
|
|
164
|
-
else if (toolInput?.args && typeof toolInput.args ===
|
|
209
|
+
else if (toolInput?.args && typeof toolInput.args === "object") {
|
|
165
210
|
const args = toolInput.args;
|
|
166
|
-
if (typeof args.name ===
|
|
211
|
+
if (typeof args.name === "string") {
|
|
167
212
|
skillName = args.name;
|
|
168
213
|
}
|
|
169
|
-
else if (typeof args.skill ===
|
|
214
|
+
else if (typeof args.skill === "string") {
|
|
170
215
|
skillName = args.skill;
|
|
171
216
|
}
|
|
172
217
|
}
|
|
173
|
-
|
|
174
|
-
|
|
218
|
+
return {
|
|
219
|
+
actionType: "skill",
|
|
220
|
+
actionLabel: "使用技能",
|
|
221
|
+
actionDetail: skillName || undefined,
|
|
222
|
+
};
|
|
175
223
|
}
|
|
176
224
|
// 文件/命令工具即使走 MCP 命名,也优先按语义显示为读取/编辑/命令执行。
|
|
177
|
-
if (matchesToolName(
|
|
225
|
+
if (matchesToolName("edit", "editfile", "strreplace", "editcode", "apply_patch", "multiedit", "replace")) {
|
|
178
226
|
const filePath = firstString(toolInput?.file_path, toolInput?.filePath, toolInput?.path, toolInput?.target_file, toolInput?.targetFile);
|
|
179
|
-
return {
|
|
227
|
+
return {
|
|
228
|
+
actionType: "edit_file",
|
|
229
|
+
actionLabel: "编辑文件",
|
|
230
|
+
actionDetail: filePath,
|
|
231
|
+
};
|
|
180
232
|
}
|
|
181
|
-
if (matchesToolName(
|
|
233
|
+
if (matchesToolName("write", "writefile", "fswrite")) {
|
|
182
234
|
const filePath = firstString(toolInput?.file_path, toolInput?.filePath, toolInput?.path, toolInput?.target_file, toolInput?.targetFile);
|
|
183
|
-
return {
|
|
235
|
+
return {
|
|
236
|
+
actionType: "write_file",
|
|
237
|
+
actionLabel: "写入文件",
|
|
238
|
+
actionDetail: filePath,
|
|
239
|
+
};
|
|
184
240
|
}
|
|
185
|
-
if (matchesToolName(
|
|
241
|
+
if (matchesToolName("read", "readfile", "readcode", "readmultiplefiles", "read_file")) {
|
|
186
242
|
if (Array.isArray(toolInput?.paths)) {
|
|
187
|
-
return {
|
|
243
|
+
return {
|
|
244
|
+
actionType: "read_file",
|
|
245
|
+
actionLabel: "读取文件",
|
|
246
|
+
actionDetail: `${toolInput.paths.length}个文件`,
|
|
247
|
+
};
|
|
188
248
|
}
|
|
189
249
|
const filePath = firstString(toolInput?.file_path, toolInput?.filePath, toolInput?.path, toolInput?.paths, toolInput?.target_file, toolInput?.targetFile);
|
|
190
|
-
return {
|
|
250
|
+
return {
|
|
251
|
+
actionType: "read_file",
|
|
252
|
+
actionLabel: "读取文件",
|
|
253
|
+
actionDetail: filePath,
|
|
254
|
+
};
|
|
191
255
|
}
|
|
192
|
-
if (matchesToolName(
|
|
256
|
+
if (matchesToolName("bash", "shell", "command", "executepwsh", "controlpwshprocess", "execute", "run_command", "execute_command")) {
|
|
193
257
|
const command = firstString(toolInput?.command, toolInput?.cmd, toolInput?.argv);
|
|
194
|
-
return {
|
|
258
|
+
return {
|
|
259
|
+
actionType: "bash",
|
|
260
|
+
actionLabel: "执行命令",
|
|
261
|
+
actionDetail: command?.slice(0, 50),
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
if (matchesToolName("poll_message", "get_message")) {
|
|
265
|
+
return {
|
|
266
|
+
actionType: "idle",
|
|
267
|
+
actionLabel: "监听消息",
|
|
268
|
+
actionDetail: getCanonicalMcpDetail(toolName),
|
|
269
|
+
};
|
|
195
270
|
}
|
|
196
271
|
// MCP 工具调用
|
|
197
272
|
// 优先使用 metadata 中的 mcpServer 信息(SDK 直接提供)
|
|
@@ -202,101 +277,137 @@ export function getToolActionInfo(toolName, toolInput, metadata) {
|
|
|
202
277
|
// 4. xxx-mcp__tool (自定义格式,如 aws-mcp__get_profile)
|
|
203
278
|
// 5. 包含 'mcp_' 的工具名
|
|
204
279
|
// 6. Kiro 的 kiroPowers
|
|
205
|
-
//
|
|
280
|
+
//
|
|
206
281
|
// actionDetail 格式: server/tool(包含 MCP server 名称,便于用户识别工具来源)
|
|
207
282
|
// 优先检查 metadata 中的 MCP server 信息
|
|
208
283
|
if (metadata?.mcpServer) {
|
|
209
284
|
const mcpServer = metadata.mcpServer;
|
|
210
|
-
const mcpTool = toolName ||
|
|
211
|
-
const detail =
|
|
212
|
-
|
|
213
|
-
return { actionType: 'mcp', actionLabel: '调用MCP', actionDetail: detail };
|
|
285
|
+
const mcpTool = toolName || "";
|
|
286
|
+
const detail = formatCanonicalMcpDetail(mcpServer, mcpTool);
|
|
287
|
+
return { actionType: "mcp", actionLabel: "调用MCP", actionDetail: detail };
|
|
214
288
|
}
|
|
215
289
|
// 检查是否在已知 MCP 工具列表中
|
|
216
290
|
const knownMcpServer = KNOWN_MCP_TOOLS[toolName];
|
|
217
291
|
if (knownMcpServer) {
|
|
218
292
|
const detail = `${knownMcpServer}/${toolName}`;
|
|
219
|
-
|
|
220
|
-
return { actionType: 'mcp', actionLabel: '调用MCP', actionDetail: detail };
|
|
293
|
+
return { actionType: "mcp", actionLabel: "调用MCP", actionDetail: detail };
|
|
221
294
|
}
|
|
222
|
-
const isMcpTool = name.startsWith(
|
|
223
|
-
name.includes(
|
|
224
|
-
(name.includes(
|
|
225
|
-
name ===
|
|
295
|
+
const isMcpTool = name.startsWith("mcp__") ||
|
|
296
|
+
name.includes("-mcp__") ||
|
|
297
|
+
(name.includes("mcp_") && !name.includes("skill")) ||
|
|
298
|
+
name === "kiropowers";
|
|
226
299
|
if (isMcpTool) {
|
|
227
|
-
let mcpServer =
|
|
228
|
-
let mcpTool =
|
|
229
|
-
if (name.startsWith(
|
|
300
|
+
let mcpServer = "";
|
|
301
|
+
let mcpTool = "";
|
|
302
|
+
if (name.startsWith("mcp__")) {
|
|
230
303
|
// 标准格式: mcp__server__tool
|
|
231
|
-
const parts = toolName.split(
|
|
232
|
-
mcpServer = parts[1] ||
|
|
233
|
-
mcpTool = parts.slice(2).join(
|
|
304
|
+
const parts = toolName.split("__");
|
|
305
|
+
mcpServer = parts[1] || "";
|
|
306
|
+
mcpTool = parts.slice(2).join("__") || "";
|
|
234
307
|
}
|
|
235
|
-
else if (name.includes(
|
|
308
|
+
else if (name.includes("-mcp__")) {
|
|
236
309
|
// 自定义格式: xxx-mcp__tool (如 aws-mcp__get_profile)
|
|
237
|
-
const idx = name.indexOf(
|
|
310
|
+
const idx = name.indexOf("-mcp__");
|
|
238
311
|
mcpServer = name.substring(0, idx + 4); // "xxx-mcp"(保留完整 server 名)
|
|
239
312
|
mcpTool = name.substring(idx + 6); // 去掉 "-mcp__" 前缀,得到工具名
|
|
240
313
|
}
|
|
241
|
-
else if (name ===
|
|
242
|
-
mcpServer =
|
|
243
|
-
mcpTool = (toolInput?.powerName || toolInput?.action) ||
|
|
314
|
+
else if (name === "kiropowers") {
|
|
315
|
+
mcpServer = "kiro";
|
|
316
|
+
mcpTool = (toolInput?.powerName || toolInput?.action) || "";
|
|
244
317
|
}
|
|
245
318
|
else {
|
|
246
319
|
// 其他包含 mcp_ 的格式
|
|
247
|
-
mcpServer =
|
|
320
|
+
mcpServer = "mcp";
|
|
248
321
|
mcpTool = toolName;
|
|
249
322
|
}
|
|
250
323
|
// 格式: server/tool(便于用户识别 MCP server 来源)
|
|
251
|
-
const detail = mcpServer
|
|
252
|
-
return { actionType:
|
|
253
|
-
}
|
|
254
|
-
if (matchesToolName('poll_message', 'get_message')) {
|
|
255
|
-
return { actionType: 'idle', actionLabel: '监听消息', actionDetail: toolName };
|
|
324
|
+
const detail = formatCanonicalMcpDetail(mcpServer, mcpTool) || toolName;
|
|
325
|
+
return { actionType: "mcp", actionLabel: "调用MCP", actionDetail: detail };
|
|
256
326
|
}
|
|
257
327
|
// 文件编辑 (Kiro: strReplace, editCode)
|
|
258
|
-
if (matchesToolName(
|
|
328
|
+
if (matchesToolName("edit", "editfile", "strreplace", "editcode", "apply_patch", "multiedit", "replace")) {
|
|
259
329
|
const filePath = firstString(toolInput?.file_path, toolInput?.filePath, toolInput?.path, toolInput?.target_file, toolInput?.targetFile);
|
|
260
|
-
return {
|
|
330
|
+
return {
|
|
331
|
+
actionType: "edit_file",
|
|
332
|
+
actionLabel: "编辑文件",
|
|
333
|
+
actionDetail: filePath,
|
|
334
|
+
};
|
|
261
335
|
}
|
|
262
336
|
// 文件写入 (Kiro: fsWrite)
|
|
263
|
-
if (matchesToolName(
|
|
337
|
+
if (matchesToolName("write", "writefile", "fswrite")) {
|
|
264
338
|
const filePath = firstString(toolInput?.file_path, toolInput?.filePath, toolInput?.path, toolInput?.target_file, toolInput?.targetFile);
|
|
265
|
-
return {
|
|
339
|
+
return {
|
|
340
|
+
actionType: "write_file",
|
|
341
|
+
actionLabel: "写入文件",
|
|
342
|
+
actionDetail: filePath,
|
|
343
|
+
};
|
|
266
344
|
}
|
|
267
345
|
// 文件读取 (Kiro: readFile, readCode, readMultipleFiles)
|
|
268
|
-
if (matchesToolName(
|
|
346
|
+
if (matchesToolName("read", "readfile", "readcode", "readmultiplefiles", "read_file")) {
|
|
269
347
|
if (Array.isArray(toolInput?.paths)) {
|
|
270
|
-
return {
|
|
348
|
+
return {
|
|
349
|
+
actionType: "read_file",
|
|
350
|
+
actionLabel: "读取文件",
|
|
351
|
+
actionDetail: `${toolInput.paths.length}个文件`,
|
|
352
|
+
};
|
|
271
353
|
}
|
|
272
354
|
const filePath = firstString(toolInput?.file_path, toolInput?.filePath, toolInput?.path, toolInput?.paths, toolInput?.target_file, toolInput?.targetFile);
|
|
273
|
-
return {
|
|
355
|
+
return {
|
|
356
|
+
actionType: "read_file",
|
|
357
|
+
actionLabel: "读取文件",
|
|
358
|
+
actionDetail: filePath,
|
|
359
|
+
};
|
|
274
360
|
}
|
|
275
361
|
// Bash 命令 (Kiro: executePwsh, controlPwshProcess)
|
|
276
|
-
if (matchesToolName(
|
|
362
|
+
if (matchesToolName("bash", "shell", "command", "executepwsh", "controlpwshprocess", "execute", "run_command", "execute_command")) {
|
|
277
363
|
const command = firstString(toolInput?.command, toolInput?.cmd, toolInput?.argv);
|
|
278
|
-
return {
|
|
364
|
+
return {
|
|
365
|
+
actionType: "bash",
|
|
366
|
+
actionLabel: "执行命令",
|
|
367
|
+
actionDetail: command?.slice(0, 50),
|
|
368
|
+
};
|
|
279
369
|
}
|
|
280
370
|
// 文件搜索 (Kiro: grepSearch, fileSearch)
|
|
281
|
-
if (name ===
|
|
371
|
+
if (name === "glob" ||
|
|
372
|
+
name === "grep" ||
|
|
373
|
+
name === "find" ||
|
|
374
|
+
name === "search" ||
|
|
375
|
+
name === "grepsearch" ||
|
|
376
|
+
name === "filesearch") {
|
|
282
377
|
const query = (toolInput?.query || toolInput?.pattern);
|
|
283
|
-
return {
|
|
378
|
+
return {
|
|
379
|
+
actionType: "search",
|
|
380
|
+
actionLabel: "搜索文件",
|
|
381
|
+
actionDetail: query?.slice(0, 30),
|
|
382
|
+
};
|
|
284
383
|
}
|
|
285
384
|
// 网络操作 (Kiro: webFetch, remote_web_search)
|
|
286
|
-
if (name ===
|
|
385
|
+
if (name === "webfetch" ||
|
|
386
|
+
name === "websearch" ||
|
|
387
|
+
name === "fetch" ||
|
|
388
|
+
name === "http" ||
|
|
389
|
+
name === "remote_web_search") {
|
|
287
390
|
const url = (toolInput?.url || toolInput?.query);
|
|
288
|
-
return {
|
|
391
|
+
return {
|
|
392
|
+
actionType: "web",
|
|
393
|
+
actionLabel: "网络请求",
|
|
394
|
+
actionDetail: url?.slice(0, 50),
|
|
395
|
+
};
|
|
289
396
|
}
|
|
290
397
|
// LSP 操作
|
|
291
|
-
if (name.startsWith(
|
|
292
|
-
return { actionType:
|
|
398
|
+
if (name.startsWith("lsp") || name.includes("language_server")) {
|
|
399
|
+
return { actionType: "lsp", actionLabel: "LSP操作" };
|
|
293
400
|
}
|
|
294
401
|
// Notebook 编辑
|
|
295
|
-
if (name ===
|
|
296
|
-
return { actionType:
|
|
402
|
+
if (name === "notebookedit" || name.includes("notebook")) {
|
|
403
|
+
return { actionType: "notebook", actionLabel: "编辑Notebook" };
|
|
297
404
|
}
|
|
298
405
|
// 其他工具
|
|
299
|
-
return {
|
|
406
|
+
return {
|
|
407
|
+
actionType: "other",
|
|
408
|
+
actionLabel: "调用工具",
|
|
409
|
+
actionDetail: toolName,
|
|
410
|
+
};
|
|
300
411
|
}
|
|
301
412
|
// ============ Adapter 基类 ============
|
|
302
413
|
/**
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
import { getToolActionInfo, isTransientClipboardPasteFilePath, redactTransientClipboardPastePaths, redactTransientClipboardPastePathsInValue, } from './types.js';
|
|
3
3
|
describe('getToolActionInfo', () => {
|
|
4
|
-
it('reports poll_message as
|
|
4
|
+
it('reports poll_message as an idle MCP listening tool call', () => {
|
|
5
5
|
expect(getToolActionInfo('poll_message')).toEqual({
|
|
6
|
-
actionType: '
|
|
7
|
-
actionLabel: '
|
|
6
|
+
actionType: 'idle',
|
|
7
|
+
actionLabel: '监听消息',
|
|
8
|
+
actionDetail: 'aws-mcp/poll_message',
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
it('reports prefixed poll_message as a canonical idle MCP listening tool call', () => {
|
|
12
|
+
expect(getToolActionInfo('aws-mcp__poll_message')).toEqual({
|
|
13
|
+
actionType: 'idle',
|
|
14
|
+
actionLabel: '监听消息',
|
|
8
15
|
actionDetail: 'aws-mcp/poll_message',
|
|
9
16
|
});
|
|
10
17
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../src/routes/instance.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../src/routes/instance.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAqBrD,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAC/D,IAAI,CAEN;AAED,eAAO,MAAM,cAAc,4CAAW,CAAC;AAsJvC,wBAAgB,4BAA4B,CAAC,gBAAgB,EAAE,MAAM,GAAG;IACtE,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE;QACJ,EAAE,EAAE,OAAO,CAAC;QACZ,aAAa,CAAC,EAAE,SAAS,CAAC;QAC1B,oBAAoB,EAAE,OAAO,CAAC;QAC9B,qBAAqB,EAAE,OAAO,CAAC;QAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,CAqCA;AAED,MAAM,WAAW,4BAA4B;IAC3C,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,gBAAgB,CAAC;IAC/B,aAAa,EAAE,SAAS,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,iCAAiC;IACzC,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,8BAA8B,CAAC;IACtC,YAAY,EAAE,gBAAgB,CAAC;IAC/B,aAAa,EAAE,SAAS,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,sBAAsB,EAAE,MAAM,EAAE,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,KAAK,EACZ,0BAA0B,EAAE,MAAM,GACjC,4BAA4B,CAiB9B;AAoDD;;;GAGG;AACH,wBAAgB,sCAAsC,CACpD,UAAU,EAAE,MAAM,EAAE,GACnB,iCAAiC,CAUnC;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAQhF;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,cAAc,EAAE,MAAM,EAAE,EACxB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAC5C,MAAM,CAaR;AAED,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAC5C,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,iBAAiB,EAAE,WAAW,GAAG,SAAS,GAAG,YAAY,GAAG,OAAO,CAAC,CAAC,CAY3F"}
|
package/dist/routes/instance.js
CHANGED
|
@@ -2,16 +2,15 @@ import { Router } from "express";
|
|
|
2
2
|
import axios from "axios";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import { createHash, timingSafeEqual } from "node:crypto";
|
|
5
|
-
import { validateToken } from "../middleware/auth.js";
|
|
6
5
|
import { resolveSchedulerBaseUrlFrom } from "../config.js";
|
|
7
|
-
import {
|
|
8
|
-
import { loadInstanceState, saveInstanceState, } from "../services/instance-state.js";
|
|
9
|
-
import { initInstance } from "../services/instance-init-service.js";
|
|
10
|
-
import { discoverCcSwitchConfiguredItems, loadCcSwitchSdk } from "../services/cc-switch-sdk.js";
|
|
11
|
-
import { syncLegacyStateFromSdk } from "../services/instance-init-service.js";
|
|
12
|
-
import { detectToolStatuses, ensureToolsInstalled, SUPPORTED_INSTALLABLE_TOOLS, SUPPORTED_UNINSTALLABLE_TOOLS, uninstallTools, } from "../services/tool-installer.js";
|
|
6
|
+
import { validateToken } from "../middleware/auth.js";
|
|
13
7
|
import { getConfiguredConnectionKeys, requestRuntimeAccessTokenRefreshForServer } from "../services/auto-register.js";
|
|
8
|
+
import { discoverCcSwitchConfiguredItems, loadCcSwitchSdk } from "../services/cc-switch-sdk.js";
|
|
9
|
+
import { initInstance, syncLegacyStateFromSdk } from "../services/instance-init-service.js";
|
|
14
10
|
import { createBridgeLifecycleOperation, deliverPendingBridgeLifecycleNotifications, upsertBridgeLifecycleOperation, } from "../services/lifecycle-state.js";
|
|
11
|
+
import { loadInstanceState, saveInstanceState, } from "../services/instance-state.js";
|
|
12
|
+
import { getRuntimeAccessToken } from "../services/runtime-binding.js";
|
|
13
|
+
import { detectToolStatuses, ensureToolsInstalled, SUPPORTED_INSTALLABLE_TOOLS, SUPPORTED_UNINSTALLABLE_TOOLS, uninstallTools, } from "../services/tool-installer.js";
|
|
15
14
|
import { createLogger } from "../utils/logger.js";
|
|
16
15
|
const log = createLogger("instance");
|
|
17
16
|
const PANEL_TOOL_STATUS_KEYS = ["acode", "claude", "opencode", "codex"];
|
|
@@ -102,7 +102,7 @@ runtimeBindingRouter.post("/binding/claim-agent", (req, res) => {
|
|
|
102
102
|
res.status(403).json({ ok: false, error: "loopback request required" });
|
|
103
103
|
return;
|
|
104
104
|
}
|
|
105
|
-
const { workspacePath, serverUrl } = req.body || {};
|
|
105
|
+
const { agentId, workspacePath, serverUrl } = req.body || {};
|
|
106
106
|
if (!workspacePath || !String(workspacePath).trim()) {
|
|
107
107
|
res.status(400).json({ ok: false, error: "workspacePath is required" });
|
|
108
108
|
return;
|
|
@@ -111,7 +111,7 @@ runtimeBindingRouter.post("/binding/claim-agent", (req, res) => {
|
|
|
111
111
|
res.status(400).json({ ok: false, error: "serverUrl is required" });
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
|
-
const claimed = claimMcpLaunchBinding({ workspacePath, serverUrl });
|
|
114
|
+
const claimed = claimMcpLaunchBinding({ agentId, workspacePath, serverUrl });
|
|
115
115
|
if (!claimed) {
|
|
116
116
|
res.status(404).json({
|
|
117
117
|
ok: false,
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* 提供 SDK Agent 会话的启动、输入、调整大小和停止功能
|
|
5
5
|
* 终端 UI 仅作为 SDK Agent 的消息输入/状态输出载体
|
|
6
6
|
*/
|
|
7
|
-
import { TextDecoder } from
|
|
8
|
-
import { type AdapterSessionConfig, type ProviderEvent, type RuntimeStatusActionInfo } from
|
|
9
|
-
import type { PersistedSession } from
|
|
7
|
+
import { TextDecoder } from "node:util";
|
|
8
|
+
import { type AdapterSessionConfig, type ProviderEvent, type RuntimeStatusActionInfo } from "../adapter/index.js";
|
|
9
|
+
import type { PersistedSession } from "../types.js";
|
|
10
10
|
export declare const terminalRouter: import("express-serve-static-core").Router;
|
|
11
11
|
export interface SdkSessionEntry {
|
|
12
12
|
agentId: string;
|
|
@@ -15,6 +15,7 @@ export interface SdkSessionEntry {
|
|
|
15
15
|
config: AdapterSessionConfig;
|
|
16
16
|
providerId: string;
|
|
17
17
|
seq: number;
|
|
18
|
+
runtimeAccessToken?: string;
|
|
18
19
|
currentRuntimeStatus?: string;
|
|
19
20
|
currentRuntimeActionType?: string;
|
|
20
21
|
currentRuntimeActionLabel?: string;
|
|
@@ -25,6 +26,10 @@ export declare function resolveStatusChangeUsage(actionInfo?: RuntimeStatusActio
|
|
|
25
26
|
inputTokens: number;
|
|
26
27
|
outputTokens: number;
|
|
27
28
|
} | undefined;
|
|
29
|
+
export declare function buildAcodeCommandOutputPath(workspacePath: string, now?: Date): string;
|
|
30
|
+
export declare function countTerminalOutputLines(output: string): number;
|
|
31
|
+
export declare function formatCommandOutputSpilloverNotice(outputPath: string, lineLimit?: number): string;
|
|
32
|
+
export declare function formatCommandInactivityTimeoutNotice(timeoutMs?: number): string;
|
|
28
33
|
/**
|
|
29
34
|
* 标准化终端输入:将前端回车符还原为 shell 可执行命令文本。
|
|
30
35
|
*/
|
|
@@ -53,13 +58,13 @@ export declare function parseTerminalDirectoryChangeTarget(command: string): str
|
|
|
53
58
|
export declare function resolveSdkSessionDisplayStatus(adapterStatus?: string, currentRuntimeStatus?: string): string;
|
|
54
59
|
export interface PersistedSessionReuseDecision {
|
|
55
60
|
reusable: boolean;
|
|
56
|
-
reason:
|
|
61
|
+
reason: "active-pid" | "missing-pid" | "dead-pid" | "in-process-provider";
|
|
57
62
|
}
|
|
58
63
|
/**
|
|
59
64
|
* Decide whether a persisted SDK session can be reused for a start request.
|
|
60
65
|
* Main flow: require a live PID, then reject in-process providers whose adapter control channel cannot be restored.
|
|
61
66
|
*/
|
|
62
|
-
export declare function evaluatePersistedSessionReuse(session: Pick<PersistedSession,
|
|
67
|
+
export declare function evaluatePersistedSessionReuse(session: Pick<PersistedSession, "pid"> & Partial<Pick<PersistedSession, "command">>, isPidRunning?: (pid: number) => boolean): PersistedSessionReuseDecision;
|
|
63
68
|
/**
|
|
64
69
|
* 生成显示在终端输出流中的工作目录提示符。
|
|
65
70
|
*/
|
|
@@ -86,5 +91,15 @@ export declare function buildClaudeCodeLaunchConfig(savedClaudeConfig: {
|
|
|
86
91
|
*/
|
|
87
92
|
export declare function buildToolResultTimelineActionInfo(event: ProviderEvent): RuntimeStatusActionInfo | undefined;
|
|
88
93
|
export declare function formatSdkOutputEvent(event: ProviderEvent): string | undefined;
|
|
94
|
+
/**
|
|
95
|
+
* 主干流程:把 provider 事件转换为面板运行状态。
|
|
96
|
+
*
|
|
97
|
+
* text_delta 表示助手正在生成;thinking 表示推理/内部过程。
|
|
98
|
+
* tool_use_start 表示正在执行工具;turn_complete 才表示真正空闲。
|
|
99
|
+
*/
|
|
100
|
+
export declare function resolveRuntimeStatusFromProviderEvent(event: ProviderEvent): {
|
|
101
|
+
status: string;
|
|
102
|
+
actionInfo?: RuntimeStatusActionInfo;
|
|
103
|
+
} | undefined;
|
|
89
104
|
export declare function resolveSdkProviderId(command?: string): string;
|
|
90
105
|
//# sourceMappingURL=terminal.d.ts.map
|