godot-daedalus_backend 1.0.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/README.md +101 -0
- package/bin/godot-daedalus-backend.js +4 -0
- package/bin/godot-daedalus-mcp.js +4 -0
- package/bin/godot-daedalus-terminal-mcp.js +4 -0
- package/bin/run-tsx-entry.js +26 -0
- package/package.json +54 -0
- package/scripts/deepseek-tokenizer-server.py +54 -0
- package/src/app-paths.ts +36 -0
- package/src/main.ts +21 -0
- package/src/mcp/content-length-protocol.ts +68 -0
- package/src/mcp/custom-mcp-config-store.ts +397 -0
- package/src/mcp/godot-diagnostics-bridge.ts +1298 -0
- package/src/mcp/godot-editor-bridge.ts +307 -0
- package/src/mcp/godot-mcp-server.ts +3484 -0
- package/src/mcp/godot-paths.ts +151 -0
- package/src/mcp/godot-project-settings.ts +233 -0
- package/src/mcp/godot-tool-registration.ts +46 -0
- package/src/mcp/mcp-config.ts +48 -0
- package/src/mcp/mcp-host.ts +393 -0
- package/src/mcp/mcp-session.ts +81 -0
- package/src/mcp/terminal-mcp-server.ts +576 -0
- package/src/mcp/tscn-tools.ts +302 -0
- package/src/mcp/types.ts +12 -0
- package/src/ping-client.ts +24 -0
- package/src/prompts/registry.ts +97 -0
- package/src/prompts/templates/backend-helper.md +25 -0
- package/src/prompts/templates/gdscript-reviewer.md +19 -0
- package/src/prompts/templates/godot-assistant.md +225 -0
- package/src/prompts/templates/scene-architect.md +15 -0
- package/src/prompts/templates/session-compressor.md +33 -0
- package/src/protocol/schema.ts +486 -0
- package/src/protocol/types.ts +77 -0
- package/src/providers/deepseek-agent.ts +1014 -0
- package/src/providers/deepseek-client.ts +114 -0
- package/src/providers/deepseek-dsml-tools.ts +90 -0
- package/src/providers/deepseek-loose-tools.ts +450 -0
- package/src/providers/provider-config-store.ts +164 -0
- package/src/server/client-session.ts +93 -0
- package/src/server/request-dispatcher.ts +74 -0
- package/src/server/response-helpers.ts +33 -0
- package/src/server/send-json.ts +8 -0
- package/src/server/websocket-server.ts +3997 -0
- package/src/session/session-compressor.ts +68 -0
- package/src/session/session-store.ts +669 -0
- package/src/skills/registry.ts +180 -0
- package/src/skills/templates/backend-helper.md +12 -0
- package/src/skills/templates/file-creator.md +14 -0
- package/src/skills/templates/gdscript-review.md +12 -0
- package/src/skills/templates/godot-project-init.md +29 -0
- package/src/skills/templates/scene-builder.md +12 -0
- package/src/tokens/deepseek-tokenizer-counter.ts +233 -0
- package/src/tokens/model-profiles.ts +38 -0
- package/src/tokens/token-counter-factory.ts +52 -0
- package/src/tokens/token-counter.ts +22 -0
- package/src/tools/approval-gateway.ts +111 -0
- package/src/tools/llm-tools.ts +1415 -0
- package/src/tools/tool-dispatcher.ts +147 -0
- package/src/tools/tool-event-describer.ts +387 -0
- package/src/tools/tool-idempotency.ts +373 -0
- package/src/tools/tool-policy-table.ts +61 -0
- package/src/tools/tool-policy.ts +73 -0
- package/src/workflow/llm-planner.ts +407 -0
- package/src/workflow/planner.ts +201 -0
- package/src/workflow/runner.ts +141 -0
- package/src/workflow/types.ts +69 -0
- package/src/workspace/registry.ts +104 -0
- package/src/workspace/types.ts +7 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { ChatCompletionMessageToolCall, ChatCompletionToolMessageParam } from "openai/resources/chat/completions";
|
|
2
|
+
import type { McpHost } from "../mcp/mcp-host.js";
|
|
3
|
+
import { type ApprovalGateway, type PendingApproval } from "./approval-gateway.js";
|
|
4
|
+
import { describeToolEvent, type ToolEventDisplay } from "./tool-event-describer.js";
|
|
5
|
+
import { executeLlmToolWithIdempotency } from "./tool-idempotency.js";
|
|
6
|
+
|
|
7
|
+
export type ToolEvent =
|
|
8
|
+
| { type: "ai.delta"; text: string }
|
|
9
|
+
| { type: "ai.thinking.delta"; text: string }
|
|
10
|
+
| { type: "ai.thinking.done" }
|
|
11
|
+
| ({ type: "tool.call"; step: number; toolCallId: string; toolName: string; args: Record<string, unknown> } & ToolEventDisplay)
|
|
12
|
+
| { type: "tool.result"; step: number; toolCallId: string; toolName: string; resultChars: number; truncated: boolean; cached?: boolean }
|
|
13
|
+
| { type: "tool.error"; step: number; toolCallId: string; toolName: string; message: string }
|
|
14
|
+
| ({ type: "tool.approval_required"; step: number; toolCallId: string; toolName: string; approvalId: string; reason: string; args: Record<string, unknown> } & ToolEventDisplay);
|
|
15
|
+
|
|
16
|
+
export type OnToolEvent = (event: ToolEvent) => void;
|
|
17
|
+
|
|
18
|
+
export class ToolApprovalRequiredError extends Error {
|
|
19
|
+
readonly pendingApproval: PendingApproval;
|
|
20
|
+
|
|
21
|
+
constructor(pendingApproval: PendingApproval) {
|
|
22
|
+
super(`Tool approval required: ${pendingApproval.approvalId}`);
|
|
23
|
+
this.name = "ToolApprovalRequiredError";
|
|
24
|
+
this.pendingApproval = pendingApproval;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function executeSingleToolCall(
|
|
29
|
+
mcpHost: McpHost,
|
|
30
|
+
toolCall: ChatCompletionMessageToolCall,
|
|
31
|
+
step: number,
|
|
32
|
+
gateway: ApprovalGateway,
|
|
33
|
+
onEvent?: OnToolEvent
|
|
34
|
+
): Promise<ChatCompletionToolMessageParam> {
|
|
35
|
+
if (toolCall.type !== "function") {
|
|
36
|
+
return {
|
|
37
|
+
role: "tool",
|
|
38
|
+
tool_call_id: toolCall.id,
|
|
39
|
+
content: "Error: Unsupported tool call type"
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const functionName: string = toolCall.function.name;
|
|
44
|
+
|
|
45
|
+
let argsParsed: Record<string, unknown>;
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
argsParsed = JSON.parse(toolCall.function.arguments) as Record<string, unknown>;
|
|
49
|
+
} catch {
|
|
50
|
+
const message: string = `Invalid JSON arguments: ${toolCall.function.arguments}`;
|
|
51
|
+
onEvent?.({ type: "tool.error", step, toolCallId: toolCall.id, toolName: functionName, message });
|
|
52
|
+
return {
|
|
53
|
+
role: "tool",
|
|
54
|
+
tool_call_id: toolCall.id,
|
|
55
|
+
content: `Error: ${message}`
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const decision = await gateway.evaluate(functionName, argsParsed, toolCall.id);
|
|
60
|
+
|
|
61
|
+
if (decision.action === "deny") {
|
|
62
|
+
onEvent?.({ type: "tool.error", step, toolCallId: toolCall.id, toolName: functionName, message: decision.reason });
|
|
63
|
+
return {
|
|
64
|
+
role: "tool",
|
|
65
|
+
tool_call_id: toolCall.id,
|
|
66
|
+
content: `Error: ${decision.reason}`
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (decision.action === "request_approval") {
|
|
71
|
+
const pending = gateway.requestApproval(functionName, argsParsed, toolCall.id, decision.reason, mcpHost.getActiveWorkspaceId());
|
|
72
|
+
onEvent?.({
|
|
73
|
+
type: "tool.approval_required",
|
|
74
|
+
step,
|
|
75
|
+
toolCallId: toolCall.id,
|
|
76
|
+
toolName: functionName,
|
|
77
|
+
approvalId: pending.approvalId,
|
|
78
|
+
reason: decision.reason,
|
|
79
|
+
args: argsParsed,
|
|
80
|
+
...describeToolEvent(functionName, argsParsed)
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
throw new ToolApprovalRequiredError(pending);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (onEvent) {
|
|
87
|
+
onEvent({
|
|
88
|
+
type: "tool.call",
|
|
89
|
+
step,
|
|
90
|
+
toolCallId: toolCall.id,
|
|
91
|
+
toolName: functionName,
|
|
92
|
+
args: argsParsed,
|
|
93
|
+
...describeToolEvent(functionName, argsParsed)
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
const result = await executeLlmToolWithIdempotency(mcpHost, functionName, argsParsed);
|
|
99
|
+
|
|
100
|
+
if (onEvent) {
|
|
101
|
+
onEvent({
|
|
102
|
+
type: "tool.result",
|
|
103
|
+
step,
|
|
104
|
+
toolCallId: toolCall.id,
|
|
105
|
+
toolName: functionName,
|
|
106
|
+
resultChars: result.rawContentLength,
|
|
107
|
+
truncated: result.truncated,
|
|
108
|
+
cached: result.reused
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
role: "tool",
|
|
114
|
+
tool_call_id: toolCall.id,
|
|
115
|
+
content: result.content
|
|
116
|
+
};
|
|
117
|
+
} catch (error: unknown) {
|
|
118
|
+
const message: string = error instanceof Error ? error.message : "MCP tool call failed";
|
|
119
|
+
|
|
120
|
+
if (onEvent) {
|
|
121
|
+
onEvent({ type: "tool.error", step, toolCallId: toolCall.id, toolName: functionName, message });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
role: "tool",
|
|
126
|
+
tool_call_id: toolCall.id,
|
|
127
|
+
content: `Error: ${message}`
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export async function dispatchToolCalls(
|
|
133
|
+
mcpHost: McpHost,
|
|
134
|
+
toolCalls: ChatCompletionMessageToolCall[],
|
|
135
|
+
step: number,
|
|
136
|
+
gateway: ApprovalGateway,
|
|
137
|
+
onEvent?: OnToolEvent
|
|
138
|
+
): Promise<ChatCompletionToolMessageParam[]> {
|
|
139
|
+
const results: ChatCompletionToolMessageParam[] = [];
|
|
140
|
+
|
|
141
|
+
for (const toolCall of toolCalls) {
|
|
142
|
+
const result = await executeSingleToolCall(mcpHost, toolCall, step, gateway, onEvent);
|
|
143
|
+
results.push(result);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return results;
|
|
147
|
+
}
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import { getDynamicMcpToolMetadata, isDynamicMcpToolName } from "./llm-tools.js";
|
|
2
|
+
|
|
3
|
+
export type ToolEventCategory =
|
|
4
|
+
| "read"
|
|
5
|
+
| "write"
|
|
6
|
+
| "search"
|
|
7
|
+
| "terminal"
|
|
8
|
+
| "scene"
|
|
9
|
+
| "approval"
|
|
10
|
+
| "propose"
|
|
11
|
+
| "docs"
|
|
12
|
+
| "unknown";
|
|
13
|
+
|
|
14
|
+
export type ToolEventTarget = {
|
|
15
|
+
kind: "file" | "scene" | "command" | "query" | "approval" | "unknown";
|
|
16
|
+
path?: string;
|
|
17
|
+
line?: number;
|
|
18
|
+
label?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type ToolEventDisplay = {
|
|
22
|
+
serverId: string;
|
|
23
|
+
serverName: string;
|
|
24
|
+
category: ToolEventCategory;
|
|
25
|
+
title: string;
|
|
26
|
+
summary: string;
|
|
27
|
+
target: ToolEventTarget;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function getStringArg(args: Record<string, unknown>, key: string): string | undefined {
|
|
31
|
+
const value: unknown = args[key];
|
|
32
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function parseOperationJson(args: Record<string, unknown>): Record<string, unknown> {
|
|
36
|
+
const operationJson: string | undefined = getStringArg(args, "operationJson");
|
|
37
|
+
if (operationJson === undefined) {
|
|
38
|
+
return {};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const parsed: unknown = JSON.parse(operationJson);
|
|
43
|
+
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
|
|
44
|
+
? parsed as Record<string, unknown>
|
|
45
|
+
: {};
|
|
46
|
+
} catch {
|
|
47
|
+
return {};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function createDisplay(
|
|
52
|
+
serverId: string,
|
|
53
|
+
serverName: string,
|
|
54
|
+
category: ToolEventCategory,
|
|
55
|
+
title: string,
|
|
56
|
+
summary: string,
|
|
57
|
+
target: ToolEventTarget
|
|
58
|
+
): ToolEventDisplay {
|
|
59
|
+
return { serverId, serverName, category, title, summary, target };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function describeToolEvent(toolName: string, args: Record<string, unknown>): ToolEventDisplay {
|
|
63
|
+
if (isDynamicMcpToolName(toolName)) {
|
|
64
|
+
const metadata = getDynamicMcpToolMetadata(toolName);
|
|
65
|
+
const serverId: string = metadata?.serverId ?? "custom";
|
|
66
|
+
const serverName: string = metadata?.serverName ?? "Custom MCP";
|
|
67
|
+
const originalToolName: string = metadata?.toolName ?? toolName;
|
|
68
|
+
return createDisplay(serverId, serverName, "write", "自定义 MCP 工具", `${serverName}: ${originalToolName}`, {
|
|
69
|
+
kind: "unknown",
|
|
70
|
+
label: originalToolName
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (toolName.startsWith("mcp_godot_editor_")) {
|
|
75
|
+
const scenePath: string | undefined = getStringArg(args, "scenePath");
|
|
76
|
+
const nodePath: string | undefined = getStringArg(args, "nodePath");
|
|
77
|
+
const targetLabel: string = nodePath ?? scenePath ?? "Godot Editor";
|
|
78
|
+
|
|
79
|
+
if (toolName.includes("get_context")) {
|
|
80
|
+
return createDisplay("godot_editor", "Godot Editor", "read", "读取编辑器上下文", "读取当前编辑器在线状态与场景上下文", {
|
|
81
|
+
kind: "unknown",
|
|
82
|
+
label: "Godot Editor"
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (toolName.includes("get_selected_nodes")) {
|
|
87
|
+
return createDisplay("godot_editor", "Godot Editor", "read", "读取选中节点", "读取当前编辑器选中的节点", {
|
|
88
|
+
kind: "scene",
|
|
89
|
+
label: "selected nodes"
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (toolName.includes("inspect_node")) {
|
|
94
|
+
const target: ToolEventTarget = scenePath === undefined ? {
|
|
95
|
+
kind: "scene",
|
|
96
|
+
label: targetLabel
|
|
97
|
+
} : {
|
|
98
|
+
kind: "scene",
|
|
99
|
+
path: scenePath,
|
|
100
|
+
label: targetLabel
|
|
101
|
+
};
|
|
102
|
+
return createDisplay("godot_editor", "Godot Editor", "read", "查看在线节点", `查看 ${targetLabel}`, {
|
|
103
|
+
...target
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (toolName.includes("apply_scene_patch")) {
|
|
108
|
+
const target: ToolEventTarget = scenePath === undefined ? {
|
|
109
|
+
kind: "scene",
|
|
110
|
+
label: "当前场景"
|
|
111
|
+
} : {
|
|
112
|
+
kind: "scene",
|
|
113
|
+
path: scenePath,
|
|
114
|
+
label: scenePath
|
|
115
|
+
};
|
|
116
|
+
return createDisplay("godot_editor", "Godot Editor", "scene", "编辑在线场景", `编辑 ${scenePath ?? "当前场景"}`, {
|
|
117
|
+
...target
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (toolName.startsWith("mcp_godot_")) {
|
|
123
|
+
const relativePath: string | undefined = getStringArg(args, "relativePath") ?? getStringArg(args, "scenePath");
|
|
124
|
+
const resourcePath: string | undefined = getStringArg(args, "resourcePath") ?? relativePath;
|
|
125
|
+
const settingKey: string | undefined = getStringArg(args, "key");
|
|
126
|
+
|
|
127
|
+
if (toolName.includes("lsp_get_status")) {
|
|
128
|
+
return createDisplay("godot_diagnostics", "Godot Diagnostics", "read", "检查 LSP 状态", "探测 Godot GDScript LSP", {
|
|
129
|
+
kind: "unknown",
|
|
130
|
+
label: "Godot LSP"
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (toolName.includes("lsp_get_file_diagnostics")) {
|
|
135
|
+
const targetLabel: string = resourcePath ?? "script";
|
|
136
|
+
return createDisplay("godot_diagnostics", "Godot Diagnostics", "read", "读取脚本诊断", `读取 ${targetLabel} 的 LSP 诊断`, {
|
|
137
|
+
kind: "file",
|
|
138
|
+
path: targetLabel,
|
|
139
|
+
label: targetLabel
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (toolName.includes("lsp_get_document_symbols")) {
|
|
144
|
+
const targetLabel: string = resourcePath ?? "script";
|
|
145
|
+
return createDisplay("godot_diagnostics", "Godot Diagnostics", "read", "查看脚本符号", `查看 ${targetLabel} 的符号结构`, {
|
|
146
|
+
kind: "file",
|
|
147
|
+
path: targetLabel,
|
|
148
|
+
label: targetLabel
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (toolName.includes("lsp_hover")) {
|
|
153
|
+
const targetLabel: string = resourcePath ?? "script";
|
|
154
|
+
return createDisplay("godot_diagnostics", "Godot Diagnostics", "read", "查看 Hover 信息", `查看 ${targetLabel} 的符号说明`, {
|
|
155
|
+
kind: "file",
|
|
156
|
+
path: targetLabel,
|
|
157
|
+
label: targetLabel
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (toolName.includes("lsp_goto_definition")) {
|
|
162
|
+
const targetLabel: string = resourcePath ?? "script";
|
|
163
|
+
return createDisplay("godot_diagnostics", "Godot Diagnostics", "read", "查找定义", `查找 ${targetLabel} 中的定义`, {
|
|
164
|
+
kind: "file",
|
|
165
|
+
path: targetLabel,
|
|
166
|
+
label: targetLabel
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (toolName.includes("dap_get_status")) {
|
|
171
|
+
return createDisplay("godot_diagnostics", "Godot Diagnostics", "read", "检查 DAP 状态", "探测 Godot DAP 调试会话", {
|
|
172
|
+
kind: "unknown",
|
|
173
|
+
label: "Godot DAP"
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (toolName.includes("dap_get_last_error")) {
|
|
178
|
+
return createDisplay("godot_diagnostics", "Godot Diagnostics", "read", "读取运行错误", "读取 Godot DAP 最近运行错误", {
|
|
179
|
+
kind: "unknown",
|
|
180
|
+
label: "last runtime error"
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (toolName.includes("dap_get_stack_trace")) {
|
|
185
|
+
return createDisplay("godot_diagnostics", "Godot Diagnostics", "read", "读取调用栈", "读取 Godot DAP 调用栈", {
|
|
186
|
+
kind: "unknown",
|
|
187
|
+
label: "stack trace"
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (toolName.includes("dap_get_variables")) {
|
|
192
|
+
const reference: string = String(args["variablesReference"] ?? "variables");
|
|
193
|
+
return createDisplay("godot_diagnostics", "Godot Diagnostics", "read", "读取变量", `读取变量引用 ${reference}`, {
|
|
194
|
+
kind: "unknown",
|
|
195
|
+
label: reference
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (toolName.includes("get_project_log_config")) {
|
|
200
|
+
return createDisplay("godot", "Godot", "read", "读取日志配置", "解析 Godot 项目日志路径", {
|
|
201
|
+
kind: "unknown",
|
|
202
|
+
label: "project log config"
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (toolName.includes("list_project_logs")) {
|
|
207
|
+
return createDisplay("godot", "Godot", "read", "列出项目日志", "列出 Godot 项目日志文件", {
|
|
208
|
+
kind: "file",
|
|
209
|
+
label: "project logs"
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (toolName.includes("read_project_log")) {
|
|
214
|
+
const fileName: string = getStringArg(args, "fileName") ?? "godot.log";
|
|
215
|
+
return createDisplay("godot", "Godot", "read", "读取项目日志", `读取 ${fileName}`, {
|
|
216
|
+
kind: "file",
|
|
217
|
+
label: fileName
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (toolName.includes("get_project_settings")) {
|
|
222
|
+
return createDisplay("godot", "Godot", "read", "读取项目设置", "读取 project.godot 设置", {
|
|
223
|
+
kind: "file",
|
|
224
|
+
path: "project.godot",
|
|
225
|
+
label: "project.godot"
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (toolName.includes("get_editor_config_summary")) {
|
|
230
|
+
return createDisplay("godot", "Godot", "read", "读取编辑器摘要", "读取 Godot 编辑器设置与项目编辑状态摘要", {
|
|
231
|
+
kind: "unknown",
|
|
232
|
+
label: "Godot editor config"
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (toolName.includes("get_editor_settings")) {
|
|
237
|
+
return createDisplay("godot", "Godot", "read", "读取编辑器设置", "读取 editor_settings 配置", {
|
|
238
|
+
kind: "file",
|
|
239
|
+
label: "editor_settings"
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (toolName.includes("list_editor_config_files")) {
|
|
244
|
+
return createDisplay("godot", "Godot", "read", "列出编辑器配置", "列出可读的 Godot 编辑器配置文件", {
|
|
245
|
+
kind: "file",
|
|
246
|
+
label: "editor config files"
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (toolName.includes("read_editor_config_file")) {
|
|
251
|
+
const fileId: string = getStringArg(args, "fileId") ?? getStringArg(args, "filePath") ?? "editor config";
|
|
252
|
+
return createDisplay("godot", "Godot", "read", "读取编辑器配置", `读取 ${fileId}`, {
|
|
253
|
+
kind: "file",
|
|
254
|
+
label: fileId
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (toolName.includes("get_editor_project_state")) {
|
|
259
|
+
return createDisplay("godot", "Godot", "read", "读取编辑器状态", "读取当前项目 .godot/editor 状态", {
|
|
260
|
+
kind: "file",
|
|
261
|
+
path: ".godot/editor",
|
|
262
|
+
label: ".godot/editor"
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (toolName.includes("get_recent_projects")) {
|
|
267
|
+
return createDisplay("godot", "Godot", "read", "读取最近项目", "读取 Godot 最近项目与目录", {
|
|
268
|
+
kind: "file",
|
|
269
|
+
label: "projects.cfg"
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (toolName.includes("propose_set_project_setting") || toolName.includes("propose_unset_project_setting")) {
|
|
274
|
+
const targetLabel: string = settingKey ?? "project setting";
|
|
275
|
+
return createDisplay("godot", "Godot", "propose", "预览项目设置修改", `预览 ${targetLabel}`, {
|
|
276
|
+
kind: "file",
|
|
277
|
+
path: "project.godot",
|
|
278
|
+
label: targetLabel
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (toolName.includes("set_project_setting") || toolName.includes("unset_project_setting")) {
|
|
283
|
+
const targetLabel: string = settingKey ?? "project setting";
|
|
284
|
+
return createDisplay("godot", "Godot", "write", "修改项目设置", `修改 ${targetLabel}`, {
|
|
285
|
+
kind: "file",
|
|
286
|
+
path: "project.godot",
|
|
287
|
+
label: targetLabel
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (toolName.includes("read_text_file")) {
|
|
292
|
+
const filePath: string = relativePath ?? "unknown file";
|
|
293
|
+
return createDisplay("godot", "Godot", "read", "读取文件", `读取 ${filePath}`, {
|
|
294
|
+
kind: "file",
|
|
295
|
+
path: filePath,
|
|
296
|
+
label: filePath
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (toolName.includes("search_text")) {
|
|
301
|
+
const query: string = getStringArg(args, "query") ?? "";
|
|
302
|
+
return createDisplay("godot", "Godot", "search", "搜索文本", `搜索 ${query}`, {
|
|
303
|
+
kind: "query",
|
|
304
|
+
label: query
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (toolName.includes("propose_")) {
|
|
309
|
+
const targetKind: ToolEventTarget["kind"] = toolName.includes("scene") || toolName.includes("scene_patch") || relativePath?.endsWith(".tscn")
|
|
310
|
+
? "scene"
|
|
311
|
+
: "file";
|
|
312
|
+
const targetLabel: string = relativePath ?? (targetKind === "scene" ? "unknown scene" : "unknown file");
|
|
313
|
+
const title: string = targetKind === "scene" ? "预览场景修改" : "预览文件修改";
|
|
314
|
+
return createDisplay("godot", "Godot", "propose", title, `${title} ${targetLabel}`, {
|
|
315
|
+
kind: targetKind,
|
|
316
|
+
path: targetLabel,
|
|
317
|
+
label: targetLabel
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (toolName.includes("scene")) {
|
|
322
|
+
const scenePath: string = relativePath ?? "unknown scene";
|
|
323
|
+
const category: ToolEventCategory = toolName.includes("inspect") ? "read" : "scene";
|
|
324
|
+
const title: string = toolName.includes("inspect") ? "查看场景" : "编辑场景";
|
|
325
|
+
return createDisplay("godot", "Godot", category, title, `${title} ${scenePath}`, {
|
|
326
|
+
kind: "scene",
|
|
327
|
+
path: scenePath,
|
|
328
|
+
label: scenePath
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (toolName.includes("create_text_file") || toolName.includes("overwrite_text_file") || toolName.includes("replace_text_in_file") || toolName.includes("delete_file")) {
|
|
333
|
+
const filePath: string = relativePath ?? "unknown file";
|
|
334
|
+
return createDisplay("godot", "Godot", "write", "写入文件", `写入 ${filePath}`, {
|
|
335
|
+
kind: "file",
|
|
336
|
+
path: filePath,
|
|
337
|
+
label: filePath
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return createDisplay("godot", "Godot", "unknown", "Godot 工具", toolName, {
|
|
342
|
+
kind: "unknown",
|
|
343
|
+
label: toolName
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (toolName === "mcp_terminal_run_godot_scene_script") {
|
|
348
|
+
const operation: Record<string, unknown> = parseOperationJson(args);
|
|
349
|
+
const scenePath: string = typeof operation.scene_path === "string"
|
|
350
|
+
? operation.scene_path
|
|
351
|
+
: typeof operation.path === "string"
|
|
352
|
+
? operation.path
|
|
353
|
+
: "scene operation";
|
|
354
|
+
return createDisplay("terminal", "Terminal", "scene", "执行 Godot 场景脚本", `场景操作 ${scenePath}`, {
|
|
355
|
+
kind: "scene",
|
|
356
|
+
path: scenePath,
|
|
357
|
+
label: scenePath
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (toolName.startsWith("mcp_terminal_")) {
|
|
362
|
+
const presetName: string = getStringArg(args, "presetName") ?? toolName;
|
|
363
|
+
const resourcePath: string | undefined = getStringArg(args, "resourcePath");
|
|
364
|
+
const label: string = resourcePath === undefined ? presetName : `${presetName} ${resourcePath}`;
|
|
365
|
+
const target: ToolEventTarget = resourcePath === undefined ? {
|
|
366
|
+
kind: "command",
|
|
367
|
+
label
|
|
368
|
+
} : {
|
|
369
|
+
kind: "command",
|
|
370
|
+
path: resourcePath,
|
|
371
|
+
label
|
|
372
|
+
};
|
|
373
|
+
return createDisplay("terminal", "Terminal", "terminal", "运行终端命令", label, target);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (toolName.includes("context7") || toolName.includes("library") || toolName.includes("docs")) {
|
|
377
|
+
return createDisplay("context7", "Context7", "docs", "查询文档", toolName, {
|
|
378
|
+
kind: "query",
|
|
379
|
+
label: toolName
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return createDisplay("unknown", "MCP", "unknown", "MCP 工具", toolName, {
|
|
384
|
+
kind: "unknown",
|
|
385
|
+
label: toolName
|
|
386
|
+
});
|
|
387
|
+
}
|