@compyle/unagent 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/LICENSE +21 -0
- package/README.md +547 -0
- package/dist/agents/agent-as-tool.d.ts +4 -0
- package/dist/agents/agent-as-tool.d.ts.map +1 -0
- package/dist/agents/agent-as-tool.js +105 -0
- package/dist/agents/agent-as-tool.js.map +1 -0
- package/dist/agents/define-agent.d.ts +101 -0
- package/dist/agents/define-agent.d.ts.map +1 -0
- package/dist/agents/define-agent.js +866 -0
- package/dist/agents/define-agent.js.map +1 -0
- package/dist/agents/index.d.ts +3 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +3 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/bridge/node-bridge.d.ts +2 -0
- package/dist/bridge/node-bridge.d.ts.map +1 -0
- package/dist/bridge/node-bridge.js +772 -0
- package/dist/bridge/node-bridge.js.map +1 -0
- package/dist/client/base-client.d.ts +86 -0
- package/dist/client/base-client.d.ts.map +1 -0
- package/dist/client/base-client.js +254 -0
- package/dist/client/base-client.js.map +1 -0
- package/dist/client/claude.d.ts +66 -0
- package/dist/client/claude.d.ts.map +1 -0
- package/dist/client/claude.js +846 -0
- package/dist/client/claude.js.map +1 -0
- package/dist/client/codex/codex-client.d.ts +78 -0
- package/dist/client/codex/codex-client.d.ts.map +1 -0
- package/dist/client/codex/codex-client.js +906 -0
- package/dist/client/codex/codex-client.js.map +1 -0
- package/dist/client/codex/codex-home.d.ts +6 -0
- package/dist/client/codex/codex-home.d.ts.map +1 -0
- package/dist/client/codex/codex-home.js +26 -0
- package/dist/client/codex/codex-home.js.map +1 -0
- package/dist/client/codex/config/config-loader.d.ts +8 -0
- package/dist/client/codex/config/config-loader.d.ts.map +1 -0
- package/dist/client/codex/config/config-loader.js +137 -0
- package/dist/client/codex/config/config-loader.js.map +1 -0
- package/dist/client/codex/config/config-types.d.ts +43 -0
- package/dist/client/codex/config/config-types.d.ts.map +1 -0
- package/dist/client/codex/config/config-types.js +2 -0
- package/dist/client/codex/config/config-types.js.map +1 -0
- package/dist/client/codex/config/config-writer.d.ts +24 -0
- package/dist/client/codex/config/config-writer.d.ts.map +1 -0
- package/dist/client/codex/config/config-writer.js +353 -0
- package/dist/client/codex/config/config-writer.js.map +1 -0
- package/dist/client/codex/config/index.d.ts +7 -0
- package/dist/client/codex/config/index.d.ts.map +1 -0
- package/dist/client/codex/config/index.js +6 -0
- package/dist/client/codex/config/index.js.map +1 -0
- package/dist/client/codex/config/mcp-config-generator.d.ts +7 -0
- package/dist/client/codex/config/mcp-config-generator.d.ts.map +1 -0
- package/dist/client/codex/config/mcp-config-generator.js +140 -0
- package/dist/client/codex/config/mcp-config-generator.js.map +1 -0
- package/dist/client/codex/config/tools-config-writer.d.ts +2 -0
- package/dist/client/codex/config/tools-config-writer.d.ts.map +1 -0
- package/dist/client/codex/config/tools-config-writer.js +21 -0
- package/dist/client/codex/config/tools-config-writer.js.map +1 -0
- package/dist/client/codex/index.d.ts +4 -0
- package/dist/client/codex/index.d.ts.map +1 -0
- package/dist/client/codex/index.js +3 -0
- package/dist/client/codex/index.js.map +1 -0
- package/dist/client/config-utils.d.ts +4 -0
- package/dist/client/config-utils.d.ts.map +1 -0
- package/dist/client/config-utils.js +32 -0
- package/dist/client/config-utils.js.map +1 -0
- package/dist/client/extra-headers.d.ts +12 -0
- package/dist/client/extra-headers.d.ts.map +1 -0
- package/dist/client/extra-headers.js +102 -0
- package/dist/client/extra-headers.js.map +1 -0
- package/dist/client/field-mappings.d.ts +3 -0
- package/dist/client/field-mappings.d.ts.map +1 -0
- package/dist/client/field-mappings.js +40 -0
- package/dist/client/field-mappings.js.map +1 -0
- package/dist/client/transformers/content-utils.d.ts +34 -0
- package/dist/client/transformers/content-utils.d.ts.map +1 -0
- package/dist/client/transformers/content-utils.js +237 -0
- package/dist/client/transformers/content-utils.js.map +1 -0
- package/dist/events/event-bus.d.ts +19 -0
- package/dist/events/event-bus.d.ts.map +1 -0
- package/dist/events/event-bus.js +134 -0
- package/dist/events/event-bus.js.map +1 -0
- package/dist/events/event-types.d.ts +53 -0
- package/dist/events/event-types.d.ts.map +1 -0
- package/dist/events/event-types.js +6 -0
- package/dist/events/event-types.js.map +1 -0
- package/dist/events/index.d.ts +4 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +4 -0
- package/dist/events/index.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/messages/index.d.ts +3 -0
- package/dist/messages/index.d.ts.map +1 -0
- package/dist/messages/index.js +3 -0
- package/dist/messages/index.js.map +1 -0
- package/dist/messages/message-types.d.ts +60 -0
- package/dist/messages/message-types.d.ts.map +1 -0
- package/dist/messages/message-types.js +6 -0
- package/dist/messages/message-types.js.map +1 -0
- package/dist/messages/message-utils.d.ts +51 -0
- package/dist/messages/message-utils.d.ts.map +1 -0
- package/dist/messages/message-utils.js +343 -0
- package/dist/messages/message-utils.js.map +1 -0
- package/dist/tools/define-tool.d.ts +6 -0
- package/dist/tools/define-tool.d.ts.map +1 -0
- package/dist/tools/define-tool.js +83 -0
- package/dist/tools/define-tool.js.map +1 -0
- package/dist/tools/index.d.ts +6 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +6 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/mcp-stdio-proxy.d.ts +2 -0
- package/dist/tools/mcp-stdio-proxy.d.ts.map +1 -0
- package/dist/tools/mcp-stdio-proxy.js +31 -0
- package/dist/tools/mcp-stdio-proxy.js.map +1 -0
- package/dist/tools/tool-call-context.d.ts +8 -0
- package/dist/tools/tool-call-context.d.ts.map +1 -0
- package/dist/tools/tool-call-context.js +44 -0
- package/dist/tools/tool-call-context.js.map +1 -0
- package/dist/tools/tool-registry.d.ts +14 -0
- package/dist/tools/tool-registry.d.ts.map +1 -0
- package/dist/tools/tool-registry.js +47 -0
- package/dist/tools/tool-registry.js.map +1 -0
- package/dist/tools/tool-result-converter.d.ts +3 -0
- package/dist/tools/tool-result-converter.d.ts.map +1 -0
- package/dist/tools/tool-result-converter.js +38 -0
- package/dist/tools/tool-result-converter.js.map +1 -0
- package/dist/tools/tool-service-manager.d.ts +12 -0
- package/dist/tools/tool-service-manager.d.ts.map +1 -0
- package/dist/tools/tool-service-manager.js +118 -0
- package/dist/tools/tool-service-manager.js.map +1 -0
- package/dist/tools/tool-stdio-mcp-service.d.ts +29 -0
- package/dist/tools/tool-stdio-mcp-service.d.ts.map +1 -0
- package/dist/tools/tool-stdio-mcp-service.js +185 -0
- package/dist/tools/tool-stdio-mcp-service.js.map +1 -0
- package/dist/tools/tool-types.d.ts +29 -0
- package/dist/tools/tool-types.d.ts.map +1 -0
- package/dist/tools/tool-types.js +2 -0
- package/dist/tools/tool-types.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,846 @@
|
|
|
1
|
+
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as os from "os";
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
import { BaseClient, } from "./base-client.js";
|
|
6
|
+
import { ClientType, } from "../events/index.js";
|
|
7
|
+
import { createAssistantMessage, createToolCallResultMessage, createUserMessage, normalizeMessage, } from "../messages/index.js";
|
|
8
|
+
import { toContentArray, getTextValue, getImageUrl, stringifyContent, buildToolResultFromBlock, buildToolUseFromRecord, ToolCallTracker, } from "./transformers/content-utils.js";
|
|
9
|
+
import { convertSnakeCaseToCamelCase } from "./config-utils.js";
|
|
10
|
+
import { CLAUDE_FIELD_MAPPINGS } from "./field-mappings.js";
|
|
11
|
+
import { extractCustomTools, isRegisteredTool } from "../tools/define-tool.js";
|
|
12
|
+
import { getAgentToolServiceCommand, resolveToolServiceOwner } from "../tools/tool-service-manager.js";
|
|
13
|
+
export class ClaudeClient extends BaseClient {
|
|
14
|
+
agentConfig;
|
|
15
|
+
toolCallTracker = new ToolCallTracker();
|
|
16
|
+
stderrBuffer = "";
|
|
17
|
+
stderrBufferLimit = 16000;
|
|
18
|
+
activeQuery;
|
|
19
|
+
constructor(config) {
|
|
20
|
+
super(ClientType.CLAUDE, config);
|
|
21
|
+
this.agentConfig = convertSnakeCaseToCamelCase(config, CLAUDE_FIELD_MAPPINGS);
|
|
22
|
+
}
|
|
23
|
+
async run(params) {
|
|
24
|
+
const events = [];
|
|
25
|
+
this.toolCallTracker.reset();
|
|
26
|
+
this.resetStderrBuffer();
|
|
27
|
+
let finalData = null;
|
|
28
|
+
let errorOccurred = false;
|
|
29
|
+
let sessionStarted = false;
|
|
30
|
+
const { controller, cleanup } = this.createAbortController(params.signal);
|
|
31
|
+
try {
|
|
32
|
+
const queryOptions = await this.buildQueryOptions({ abortController: controller });
|
|
33
|
+
const queryRunner = query({
|
|
34
|
+
prompt: params.query,
|
|
35
|
+
options: queryOptions,
|
|
36
|
+
});
|
|
37
|
+
this.activeQuery = queryRunner;
|
|
38
|
+
for await (const message of queryRunner) {
|
|
39
|
+
if (!sessionStarted && this.isInitMessage(message)) {
|
|
40
|
+
const initSessionId = this.getInitSessionId(message);
|
|
41
|
+
if (initSessionId) {
|
|
42
|
+
await this.emitSessionStart(params, events, initSessionId);
|
|
43
|
+
await this.emitUserItemEvents(params.query, events);
|
|
44
|
+
sessionStarted = true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const convertedEvents = this.convertMessageToEvents(message);
|
|
48
|
+
events.push(...convertedEvents);
|
|
49
|
+
for (const event of convertedEvents) {
|
|
50
|
+
await this.emit(event);
|
|
51
|
+
}
|
|
52
|
+
if (message.type === "text" && message.content) {
|
|
53
|
+
finalData = message;
|
|
54
|
+
}
|
|
55
|
+
if (message.type === "assistant" && message.message) {
|
|
56
|
+
finalData = message.message;
|
|
57
|
+
}
|
|
58
|
+
if (message.type === "message" && message.role === "assistant") {
|
|
59
|
+
finalData = message;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (this.isAbortRequested()) {
|
|
63
|
+
await this.emitSessionEnd(events, "aborted");
|
|
64
|
+
return {
|
|
65
|
+
success: false,
|
|
66
|
+
error: new Error("Aborted"),
|
|
67
|
+
events,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
await this.emitSessionEnd(events);
|
|
71
|
+
return {
|
|
72
|
+
success: !errorOccurred,
|
|
73
|
+
data: finalData,
|
|
74
|
+
events,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
if (this.isAbortRequested()) {
|
|
79
|
+
await this.emitSessionEnd(events, "aborted");
|
|
80
|
+
return {
|
|
81
|
+
success: false,
|
|
82
|
+
error: error,
|
|
83
|
+
events,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
await this.emitErrorEvent("run", error, events, this.getStderrContext());
|
|
87
|
+
await this.emitSessionEnd(events, "error");
|
|
88
|
+
return {
|
|
89
|
+
success: false,
|
|
90
|
+
error: error,
|
|
91
|
+
events,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
this.activeQuery = undefined;
|
|
96
|
+
cleanup();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async runStream(params) {
|
|
100
|
+
this.toolCallTracker.reset();
|
|
101
|
+
this.resetStderrBuffer();
|
|
102
|
+
const { controller, cleanup } = this.createAbortController(params.signal);
|
|
103
|
+
try {
|
|
104
|
+
const queryOptions = await this.buildQueryOptions({ abortController: controller });
|
|
105
|
+
const eventStream = this.createEventStream(params, queryOptions);
|
|
106
|
+
return {
|
|
107
|
+
events: this.wrapEventStream(eventStream, () => {
|
|
108
|
+
this.activeQuery = undefined;
|
|
109
|
+
cleanup();
|
|
110
|
+
}),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
const aborted = this.isAbortRequested();
|
|
115
|
+
cleanup();
|
|
116
|
+
if (aborted) {
|
|
117
|
+
const sessionEndEvent = await this.emitSessionEnd(undefined, "aborted");
|
|
118
|
+
return {
|
|
119
|
+
events: (async function* () {
|
|
120
|
+
yield sessionEndEvent;
|
|
121
|
+
})(),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
const errorEvent = await this.emitErrorEvent("runStream", error, undefined, this.getStderrContext());
|
|
125
|
+
const sessionEndEvent = await this.emitSessionEnd(undefined, "error");
|
|
126
|
+
return {
|
|
127
|
+
events: (async function* () {
|
|
128
|
+
yield errorEvent;
|
|
129
|
+
yield sessionEndEvent;
|
|
130
|
+
})(),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async resume(params) {
|
|
135
|
+
this.toolCallTracker.reset();
|
|
136
|
+
this.resetStderrBuffer();
|
|
137
|
+
const { controller, cleanup } = this.createAbortController();
|
|
138
|
+
try {
|
|
139
|
+
const queryOptions = await this.buildQueryOptions({ abortController: controller });
|
|
140
|
+
const eventStream = this.createEventStream({ query: params.query || "[resuming session]", sessionId: params.sessionId }, queryOptions, params.sessionId);
|
|
141
|
+
return {
|
|
142
|
+
events: this.wrapEventStream(eventStream, () => {
|
|
143
|
+
this.activeQuery = undefined;
|
|
144
|
+
cleanup();
|
|
145
|
+
}),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
const aborted = this.isAbortRequested();
|
|
150
|
+
cleanup();
|
|
151
|
+
if (aborted) {
|
|
152
|
+
const sessionEndEvent = await this.emitSessionEnd(undefined, "aborted");
|
|
153
|
+
return {
|
|
154
|
+
events: (async function* () {
|
|
155
|
+
yield sessionEndEvent;
|
|
156
|
+
})(),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const errorEvent = await this.emitErrorEvent("resume", error, undefined, {
|
|
160
|
+
...this.getStderrContext(),
|
|
161
|
+
sessionId: params.sessionId,
|
|
162
|
+
});
|
|
163
|
+
const sessionEndEvent = await this.emitSessionEnd(undefined, "error");
|
|
164
|
+
return {
|
|
165
|
+
events: (async function* () {
|
|
166
|
+
yield errorEvent;
|
|
167
|
+
yield sessionEndEvent;
|
|
168
|
+
})(),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async buildQueryOptions(overrides) {
|
|
173
|
+
const options = {};
|
|
174
|
+
let toolRegistryServer = null;
|
|
175
|
+
const toolServerName = "custom-tools";
|
|
176
|
+
const permissionMode = resolveString(this.agentConfig.permissionMode);
|
|
177
|
+
if (permissionMode) {
|
|
178
|
+
options.permissionMode = permissionMode === "auto" ? "default" : permissionMode;
|
|
179
|
+
}
|
|
180
|
+
const systemPrompt = resolveString(this.agentConfig.systemPrompt);
|
|
181
|
+
if (systemPrompt !== undefined) {
|
|
182
|
+
options.systemPrompt = systemPrompt;
|
|
183
|
+
}
|
|
184
|
+
if (this.agentConfig.model) {
|
|
185
|
+
options.model = this.agentConfig.model;
|
|
186
|
+
}
|
|
187
|
+
if (this.agentConfig.agents) {
|
|
188
|
+
const normalizedAgents = {};
|
|
189
|
+
for (const [name, agent] of Object.entries(this.agentConfig.agents)) {
|
|
190
|
+
const { customTools, toolNames } = splitAgentTools(agent.tools);
|
|
191
|
+
const extraCustomTools = Array.isArray(agent.customTools) ? agent.customTools : [];
|
|
192
|
+
const agentCustomTools = [...customTools, ...extraCustomTools];
|
|
193
|
+
const allowedTools = normalizeToolNameList(agent.allowedTools);
|
|
194
|
+
const disallowedTools = normalizeToolNameList(agent.disallowedTools);
|
|
195
|
+
const agentToolNames = mergeToolNames([
|
|
196
|
+
...toolNames,
|
|
197
|
+
...allowedTools,
|
|
198
|
+
...agentCustomTools.map((tool) => tool.name),
|
|
199
|
+
]);
|
|
200
|
+
const prompt = agent.prompt || agent.systemPrompt;
|
|
201
|
+
const agentOwner = getToolServiceOwner(agent);
|
|
202
|
+
const toolServerConfig = agentOwner && agentCustomTools.length > 0
|
|
203
|
+
? await buildToolServerConfig(agentOwner, agentCustomTools, toolServerName)
|
|
204
|
+
: null;
|
|
205
|
+
const agentMcpServers = mergeAgentMcpServers(normalizeAgentMcpServers(agent.mcpServers), toolServerConfig);
|
|
206
|
+
normalizedAgents[name] = {
|
|
207
|
+
description: agent.description ?? "",
|
|
208
|
+
prompt: prompt || "",
|
|
209
|
+
...(agentToolNames.length > 0 ? { tools: agentToolNames } : {}),
|
|
210
|
+
...(disallowedTools.length > 0 ? { disallowedTools } : {}),
|
|
211
|
+
...(agent.model ? { model: agent.model } : {}),
|
|
212
|
+
...(agentMcpServers ? { mcpServers: agentMcpServers } : {}),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
options.agents = normalizedAgents;
|
|
216
|
+
}
|
|
217
|
+
const customTools = extractCustomTools(this.agentConfig.tools);
|
|
218
|
+
if (customTools.length > 0) {
|
|
219
|
+
const toolServiceOwner = getToolServiceOwner(this.agentConfig);
|
|
220
|
+
if (toolServiceOwner) {
|
|
221
|
+
toolRegistryServer = await buildToolServerConfig(toolServiceOwner, customTools, toolServerName);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const allowedTools = normalizeToolNameList(this.agentConfig.allowedTools);
|
|
225
|
+
if (allowedTools.length > 0) {
|
|
226
|
+
options.allowedTools = allowedTools;
|
|
227
|
+
}
|
|
228
|
+
const disallowedTools = normalizeToolNameList(this.agentConfig.disallowedTools);
|
|
229
|
+
if (disallowedTools.length > 0) {
|
|
230
|
+
options.disallowedTools = disallowedTools;
|
|
231
|
+
}
|
|
232
|
+
const mcpServers = this.agentConfig.mcpServers;
|
|
233
|
+
if (mcpServers) {
|
|
234
|
+
options.mcpServers = {
|
|
235
|
+
...(toolRegistryServer || {}),
|
|
236
|
+
...mcpServers,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
else if (toolRegistryServer) {
|
|
240
|
+
options.mcpServers = toolRegistryServer;
|
|
241
|
+
}
|
|
242
|
+
if (this.agentConfig.hooks) {
|
|
243
|
+
options.hooks = this.agentConfig.hooks;
|
|
244
|
+
}
|
|
245
|
+
if (this.agentConfig.resume) {
|
|
246
|
+
options.resume = this.agentConfig.resume;
|
|
247
|
+
}
|
|
248
|
+
const envOverrides = {};
|
|
249
|
+
let hasEnvOverrides = false;
|
|
250
|
+
if (this.agentConfig.apiKey) {
|
|
251
|
+
envOverrides.ANTHROPIC_API_KEY = this.agentConfig.apiKey;
|
|
252
|
+
hasEnvOverrides = true;
|
|
253
|
+
}
|
|
254
|
+
if (this.agentConfig.baseURL) {
|
|
255
|
+
envOverrides.ANTHROPIC_BASE_URL = this.agentConfig.baseURL;
|
|
256
|
+
hasEnvOverrides = true;
|
|
257
|
+
}
|
|
258
|
+
if (this.agentConfig.authToken) {
|
|
259
|
+
envOverrides.ANTHROPIC_AUTH_TOKEN = this.agentConfig.authToken;
|
|
260
|
+
hasEnvOverrides = true;
|
|
261
|
+
}
|
|
262
|
+
if (this.agentConfig.env && Object.keys(this.agentConfig.env).length > 0) {
|
|
263
|
+
Object.assign(envOverrides, this.agentConfig.env);
|
|
264
|
+
hasEnvOverrides = true;
|
|
265
|
+
}
|
|
266
|
+
if (hasEnvOverrides) {
|
|
267
|
+
options.env = {
|
|
268
|
+
...process.env,
|
|
269
|
+
...envOverrides,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
options.stderr = (chunk) => {
|
|
273
|
+
this.captureStderr(chunk);
|
|
274
|
+
};
|
|
275
|
+
const settingSources = normalizeToolNameList(this.agentConfig.settingSources);
|
|
276
|
+
if (settingSources.length > 0) {
|
|
277
|
+
options.settingSources = [...settingSources];
|
|
278
|
+
}
|
|
279
|
+
else if (this.agentConfig.useProjectConfig) {
|
|
280
|
+
options.settingSources = ["project"];
|
|
281
|
+
}
|
|
282
|
+
const skillDir = resolveString(this.agentConfig.skillDir);
|
|
283
|
+
if (skillDir) {
|
|
284
|
+
ensureClaudeSkillPlugin(skillDir);
|
|
285
|
+
options.plugins = [{ type: "local", path: skillDir }];
|
|
286
|
+
}
|
|
287
|
+
const addDirs = normalizeToolNameList(this.agentConfig.addDirs);
|
|
288
|
+
if (addDirs.length > 0) {
|
|
289
|
+
options.additionalDirectories = [...addDirs];
|
|
290
|
+
}
|
|
291
|
+
const cwd = this.agentConfig.cwd ?? this.agentConfig.workingDirectory;
|
|
292
|
+
if (cwd) {
|
|
293
|
+
options.cwd = cwd;
|
|
294
|
+
}
|
|
295
|
+
if (overrides?.abortController) {
|
|
296
|
+
options.abortController = overrides.abortController;
|
|
297
|
+
}
|
|
298
|
+
return options;
|
|
299
|
+
}
|
|
300
|
+
abort() {
|
|
301
|
+
super.abort();
|
|
302
|
+
if (this.activeQuery) {
|
|
303
|
+
this.activeQuery.close();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
getSessionDir() {
|
|
307
|
+
const envClaudConfigDir = this.agentConfig.env?.CLAUDE_CONFIG_DIR;
|
|
308
|
+
const baseDir = envClaudConfigDir || path.join(os.homedir(), ".claude");
|
|
309
|
+
return path.join(baseDir, "projects");
|
|
310
|
+
}
|
|
311
|
+
async *createEventStream(params, queryOptions, resumeSessionId) {
|
|
312
|
+
let endReason;
|
|
313
|
+
let sessionStarted = false;
|
|
314
|
+
try {
|
|
315
|
+
const finalOptions = resumeSessionId
|
|
316
|
+
? { ...queryOptions, resume: resumeSessionId }
|
|
317
|
+
: queryOptions;
|
|
318
|
+
const queryRunner = query({
|
|
319
|
+
prompt: params.query,
|
|
320
|
+
options: finalOptions,
|
|
321
|
+
});
|
|
322
|
+
this.activeQuery = queryRunner;
|
|
323
|
+
for await (const message of queryRunner) {
|
|
324
|
+
if (!sessionStarted && this.isInitMessage(message)) {
|
|
325
|
+
const initSessionId = this.getInitSessionId(message) ?? resumeSessionId;
|
|
326
|
+
if (initSessionId) {
|
|
327
|
+
const sessionStartEvent = await this.emitSessionStart(params, undefined, initSessionId);
|
|
328
|
+
yield sessionStartEvent;
|
|
329
|
+
const userEvents = await this.emitUserItemEvents(params.query);
|
|
330
|
+
for (const event of userEvents) {
|
|
331
|
+
yield event;
|
|
332
|
+
}
|
|
333
|
+
sessionStarted = true;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const events = this.convertMessageToEvents(message);
|
|
337
|
+
for (const event of events) {
|
|
338
|
+
await this.emit(event);
|
|
339
|
+
yield event;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
catch (error) {
|
|
344
|
+
if (this.isAbortRequested()) {
|
|
345
|
+
endReason = "aborted";
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
const errorEvent = {
|
|
349
|
+
type: "error",
|
|
350
|
+
...this.createBaseEvent(),
|
|
351
|
+
error: error,
|
|
352
|
+
context: { stage: "streamIteration", ...this.getStderrContext() },
|
|
353
|
+
};
|
|
354
|
+
await this.emit(errorEvent);
|
|
355
|
+
yield errorEvent;
|
|
356
|
+
endReason = "error";
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (!sessionStarted && resumeSessionId) {
|
|
360
|
+
const sessionStartEvent = await this.emitSessionStart(params, undefined, resumeSessionId);
|
|
361
|
+
yield sessionStartEvent;
|
|
362
|
+
const userEvents = await this.emitUserItemEvents(params.query);
|
|
363
|
+
for (const event of userEvents) {
|
|
364
|
+
yield event;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
if (!endReason && this.isAbortRequested()) {
|
|
368
|
+
endReason = "aborted";
|
|
369
|
+
}
|
|
370
|
+
const sessionEndEvent = await this.emitSessionEnd(undefined, endReason);
|
|
371
|
+
yield sessionEndEvent;
|
|
372
|
+
}
|
|
373
|
+
isInitMessage(message) {
|
|
374
|
+
return Boolean(message &&
|
|
375
|
+
typeof message === "object" &&
|
|
376
|
+
message.type === "system" &&
|
|
377
|
+
message.subtype === "init");
|
|
378
|
+
}
|
|
379
|
+
getInitSessionId(message) {
|
|
380
|
+
const raw = message.session_id;
|
|
381
|
+
return typeof raw === "string" && raw.trim() ? raw : undefined;
|
|
382
|
+
}
|
|
383
|
+
convertMessageToEvents(message) {
|
|
384
|
+
const events = [];
|
|
385
|
+
const convertedMessage = this.convertToMessage(message);
|
|
386
|
+
if (convertedMessage) {
|
|
387
|
+
const normalized = convertedMessage;
|
|
388
|
+
const startMessage = { ...normalized, content: [] };
|
|
389
|
+
const itemStartEvent = {
|
|
390
|
+
type: "item.start",
|
|
391
|
+
...this.createBaseEvent(),
|
|
392
|
+
message: startMessage,
|
|
393
|
+
};
|
|
394
|
+
const itemChunkEvent = {
|
|
395
|
+
type: "item.chunk",
|
|
396
|
+
...this.createBaseEvent(),
|
|
397
|
+
message: normalized,
|
|
398
|
+
};
|
|
399
|
+
const itemEndEvent = {
|
|
400
|
+
type: "item.end",
|
|
401
|
+
...this.createBaseEvent(),
|
|
402
|
+
message: normalized,
|
|
403
|
+
};
|
|
404
|
+
events.push(itemStartEvent, itemChunkEvent, itemEndEvent);
|
|
405
|
+
}
|
|
406
|
+
switch (message.type) {
|
|
407
|
+
case "system":
|
|
408
|
+
if (message.subtype === "init") {
|
|
409
|
+
if (message.session_id) {
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
break;
|
|
413
|
+
case "error":
|
|
414
|
+
const errorEvent = {
|
|
415
|
+
type: "error",
|
|
416
|
+
...this.createBaseEvent(),
|
|
417
|
+
error: new Error(message.error?.message || String(message.error)),
|
|
418
|
+
context: {
|
|
419
|
+
stage: "agentExecution",
|
|
420
|
+
details: message.error,
|
|
421
|
+
},
|
|
422
|
+
};
|
|
423
|
+
events.push(errorEvent);
|
|
424
|
+
break;
|
|
425
|
+
default:
|
|
426
|
+
break;
|
|
427
|
+
}
|
|
428
|
+
return events;
|
|
429
|
+
}
|
|
430
|
+
buildAssistantMessageFromContent(content, model) {
|
|
431
|
+
const blocks = toContentArray(content);
|
|
432
|
+
const textParts = [];
|
|
433
|
+
const toolCalls = [];
|
|
434
|
+
const thinkingParts = [];
|
|
435
|
+
let thinkingSignature;
|
|
436
|
+
for (const block of blocks) {
|
|
437
|
+
if (typeof block === "string") {
|
|
438
|
+
textParts.push(block);
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
if (!block || typeof block !== "object") {
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
const record = block;
|
|
445
|
+
const blockType = typeof record.type === "string" ? record.type : undefined;
|
|
446
|
+
if (blockType === "text") {
|
|
447
|
+
const text = getTextValue(record);
|
|
448
|
+
if (text !== null) {
|
|
449
|
+
textParts.push(text);
|
|
450
|
+
}
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
if (blockType === "tool_use") {
|
|
454
|
+
const { id, name } = this.toolCallTracker.registerToolUse(record);
|
|
455
|
+
const toolUse = buildToolUseFromRecord(record, id);
|
|
456
|
+
toolUse.id = id;
|
|
457
|
+
toolUse.name = name;
|
|
458
|
+
toolCalls.push(toolUse);
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
if (blockType === "thinking") {
|
|
462
|
+
const text = getTextValue(record);
|
|
463
|
+
if (text !== null) {
|
|
464
|
+
thinkingParts.push(text);
|
|
465
|
+
}
|
|
466
|
+
if (!thinkingSignature && typeof record.signature === "string") {
|
|
467
|
+
thinkingSignature = record.signature;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
if (textParts.length === 0 && toolCalls.length === 0 && thinkingParts.length === 0) {
|
|
472
|
+
return null;
|
|
473
|
+
}
|
|
474
|
+
return createAssistantMessage({
|
|
475
|
+
text: textParts.length > 0 ? textParts.join("\n") : undefined,
|
|
476
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
477
|
+
thinking: thinkingParts.length > 0
|
|
478
|
+
? { content: thinkingParts.join("\n"), signature: thinkingSignature }
|
|
479
|
+
: undefined,
|
|
480
|
+
model,
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
buildUserOrToolResultMessageFromContent(content) {
|
|
484
|
+
const blocks = toContentArray(content);
|
|
485
|
+
const toolResults = [];
|
|
486
|
+
const textParts = [];
|
|
487
|
+
const images = [];
|
|
488
|
+
for (const block of blocks) {
|
|
489
|
+
if (typeof block === "string") {
|
|
490
|
+
textParts.push(block);
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
if (!block || typeof block !== "object") {
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
const record = block;
|
|
497
|
+
const blockType = typeof record.type === "string" ? record.type : undefined;
|
|
498
|
+
if (blockType === "tool_result") {
|
|
499
|
+
const toolResult = buildToolResultFromBlock(record);
|
|
500
|
+
if (toolResult) {
|
|
501
|
+
const { id: toolUseId } = this.toolCallTracker.resolveToolResult(record);
|
|
502
|
+
toolResults.push({
|
|
503
|
+
toolUseId,
|
|
504
|
+
content: toolResult.content,
|
|
505
|
+
isError: toolResult.isError,
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
if (blockType === "text") {
|
|
511
|
+
const text = getTextValue(record);
|
|
512
|
+
if (text !== null) {
|
|
513
|
+
textParts.push(text);
|
|
514
|
+
}
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
if (blockType === "image") {
|
|
518
|
+
const url = getImageUrl(record);
|
|
519
|
+
if (url) {
|
|
520
|
+
images.push(url);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if (toolResults.length > 0) {
|
|
525
|
+
return createToolCallResultMessage(toolResults.map((result) => ({
|
|
526
|
+
tool_use_id: result.toolUseId,
|
|
527
|
+
content: result.content,
|
|
528
|
+
isError: result.isError,
|
|
529
|
+
})));
|
|
530
|
+
}
|
|
531
|
+
if (textParts.length === 0 && images.length === 0) {
|
|
532
|
+
return null;
|
|
533
|
+
}
|
|
534
|
+
if (images.length === 0) {
|
|
535
|
+
return createUserMessage(textParts.join("\n"));
|
|
536
|
+
}
|
|
537
|
+
return createUserMessage({ text: textParts.join("\n"), images });
|
|
538
|
+
}
|
|
539
|
+
resetStderrBuffer() {
|
|
540
|
+
this.stderrBuffer = "";
|
|
541
|
+
}
|
|
542
|
+
captureStderr(chunk) {
|
|
543
|
+
if (!chunk) {
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
this.stderrBuffer += chunk;
|
|
547
|
+
if (this.stderrBuffer.length > this.stderrBufferLimit) {
|
|
548
|
+
this.stderrBuffer = this.stderrBuffer.slice(-this.stderrBufferLimit);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
getStderrContext() {
|
|
552
|
+
const stderr = this.stderrBuffer.trim();
|
|
553
|
+
if (!stderr) {
|
|
554
|
+
return {};
|
|
555
|
+
}
|
|
556
|
+
return { stderr };
|
|
557
|
+
}
|
|
558
|
+
getModel(messageModel) {
|
|
559
|
+
return messageModel
|
|
560
|
+
?? this.agentConfig.model
|
|
561
|
+
?? "claude-sonnet-4-5-20250929";
|
|
562
|
+
}
|
|
563
|
+
convertToMessage(message) {
|
|
564
|
+
let msg = null;
|
|
565
|
+
switch (message.type) {
|
|
566
|
+
case "system":
|
|
567
|
+
case "usage":
|
|
568
|
+
case "result":
|
|
569
|
+
case "error":
|
|
570
|
+
break;
|
|
571
|
+
case "assistant": {
|
|
572
|
+
const content = message.message?.content ?? message.content;
|
|
573
|
+
msg = this.buildAssistantMessageFromContent(content, this.getModel(message.model));
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
case "user": {
|
|
577
|
+
const content = message.message?.content ?? message.content;
|
|
578
|
+
msg = this.buildUserOrToolResultMessageFromContent(content);
|
|
579
|
+
break;
|
|
580
|
+
}
|
|
581
|
+
case "message": {
|
|
582
|
+
const role = message.role ?? message.message?.role;
|
|
583
|
+
const content = message.content ?? message.message?.content;
|
|
584
|
+
if (role === "assistant") {
|
|
585
|
+
msg = this.buildAssistantMessageFromContent(content, this.getModel(message.model));
|
|
586
|
+
}
|
|
587
|
+
else if (role === "user") {
|
|
588
|
+
msg = this.buildUserOrToolResultMessageFromContent(content);
|
|
589
|
+
}
|
|
590
|
+
break;
|
|
591
|
+
}
|
|
592
|
+
case "text":
|
|
593
|
+
if (message.content) {
|
|
594
|
+
msg = createAssistantMessage({ text: String(message.content), model: this.getModel(message.model) });
|
|
595
|
+
}
|
|
596
|
+
break;
|
|
597
|
+
case "thinking":
|
|
598
|
+
if (message.content) {
|
|
599
|
+
msg = createAssistantMessage({
|
|
600
|
+
thinking: {
|
|
601
|
+
content: String(message.content),
|
|
602
|
+
signature: message.signature,
|
|
603
|
+
},
|
|
604
|
+
model: this.getModel(message.model),
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
break;
|
|
608
|
+
case "tool_use":
|
|
609
|
+
const toolUseRecord = message;
|
|
610
|
+
const { id: toolUseId, name: toolUseName } = this.toolCallTracker.registerToolUse(toolUseRecord);
|
|
611
|
+
const toolUse = buildToolUseFromRecord(toolUseRecord, toolUseId);
|
|
612
|
+
toolUse.id = toolUseId;
|
|
613
|
+
toolUse.name = toolUseName;
|
|
614
|
+
msg = createAssistantMessage({ toolCalls: [toolUse], model: this.getModel(message.model) });
|
|
615
|
+
break;
|
|
616
|
+
case "tool_result":
|
|
617
|
+
const toolResultRecord = message;
|
|
618
|
+
const { id: toolResultId } = this.toolCallTracker.resolveToolResult(toolResultRecord);
|
|
619
|
+
let resultContent = "";
|
|
620
|
+
if (typeof message.content === "string" && message.content.length > 0) {
|
|
621
|
+
resultContent = message.content;
|
|
622
|
+
}
|
|
623
|
+
else if (message.content !== undefined && message.content !== null) {
|
|
624
|
+
resultContent = stringifyContent(message.content);
|
|
625
|
+
}
|
|
626
|
+
if (!resultContent && message.result !== undefined && message.result !== null) {
|
|
627
|
+
resultContent = stringifyContent(message.result);
|
|
628
|
+
}
|
|
629
|
+
msg = createToolCallResultMessage([
|
|
630
|
+
{
|
|
631
|
+
tool_use_id: toolResultId,
|
|
632
|
+
content: resultContent,
|
|
633
|
+
isError: message.is_error || false,
|
|
634
|
+
},
|
|
635
|
+
]);
|
|
636
|
+
break;
|
|
637
|
+
default:
|
|
638
|
+
if (message.content !== undefined && message.content !== null) {
|
|
639
|
+
msg = createAssistantMessage({
|
|
640
|
+
text: stringifyContent(message.content),
|
|
641
|
+
model: this.getModel(message.model),
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
else {
|
|
645
|
+
msg = createAssistantMessage({
|
|
646
|
+
text: stringifyContent(message),
|
|
647
|
+
model: this.getModel(message.model),
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
break;
|
|
651
|
+
}
|
|
652
|
+
const parentToolUseId = this.getParentToolUseId(message);
|
|
653
|
+
if (msg && parentToolUseId) {
|
|
654
|
+
msg = { ...msg, parent_tool_use_id: parentToolUseId };
|
|
655
|
+
}
|
|
656
|
+
return msg ? normalizeMessage(this.applyParentToolUseId(msg)) : null;
|
|
657
|
+
}
|
|
658
|
+
getParentToolUseId(message) {
|
|
659
|
+
const topLevel = typeof message.parent_tool_use_id === "string"
|
|
660
|
+
? message.parent_tool_use_id
|
|
661
|
+
: typeof message.parentToolUseId === "string"
|
|
662
|
+
? message.parentToolUseId
|
|
663
|
+
: undefined;
|
|
664
|
+
if (topLevel) {
|
|
665
|
+
return topLevel;
|
|
666
|
+
}
|
|
667
|
+
const nested = message.message;
|
|
668
|
+
if (!nested || typeof nested !== "object") {
|
|
669
|
+
return undefined;
|
|
670
|
+
}
|
|
671
|
+
const nestedRecord = nested;
|
|
672
|
+
const nestedDirect = typeof nestedRecord.parent_tool_use_id === "string"
|
|
673
|
+
? nestedRecord.parent_tool_use_id
|
|
674
|
+
: typeof nestedRecord.parentToolUseId === "string"
|
|
675
|
+
? nestedRecord.parentToolUseId
|
|
676
|
+
: undefined;
|
|
677
|
+
if (nestedDirect) {
|
|
678
|
+
return nestedDirect;
|
|
679
|
+
}
|
|
680
|
+
const meta = nestedRecord.metadata;
|
|
681
|
+
if (meta && typeof meta === "object") {
|
|
682
|
+
const metaRecord = meta;
|
|
683
|
+
const metaValue = typeof metaRecord.parent_tool_use_id === "string"
|
|
684
|
+
? metaRecord.parent_tool_use_id
|
|
685
|
+
: typeof metaRecord.parentToolUseId === "string"
|
|
686
|
+
? metaRecord.parentToolUseId
|
|
687
|
+
: undefined;
|
|
688
|
+
if (metaValue) {
|
|
689
|
+
return metaValue;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
const messageMeta = message.metadata;
|
|
693
|
+
if (messageMeta) {
|
|
694
|
+
const metaValue = typeof messageMeta.parent_tool_use_id === "string"
|
|
695
|
+
? messageMeta.parent_tool_use_id
|
|
696
|
+
: typeof messageMeta.parentToolUseId === "string"
|
|
697
|
+
? messageMeta.parentToolUseId
|
|
698
|
+
: undefined;
|
|
699
|
+
if (metaValue) {
|
|
700
|
+
return metaValue;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
return undefined;
|
|
704
|
+
}
|
|
705
|
+
getAgentConfig() {
|
|
706
|
+
return { ...this.agentConfig };
|
|
707
|
+
}
|
|
708
|
+
updateAgentConfig(config) {
|
|
709
|
+
this.agentConfig = { ...this.agentConfig, ...config };
|
|
710
|
+
}
|
|
711
|
+
setAllowedTools(tools) {
|
|
712
|
+
this.agentConfig.allowedTools = tools;
|
|
713
|
+
}
|
|
714
|
+
setPermissionMode(mode) {
|
|
715
|
+
this.agentConfig.permissionMode = mode;
|
|
716
|
+
}
|
|
717
|
+
addMcpServer(name, config) {
|
|
718
|
+
if (!this.agentConfig.mcpServers) {
|
|
719
|
+
this.agentConfig.mcpServers = {};
|
|
720
|
+
}
|
|
721
|
+
this.agentConfig.mcpServers[name] = config;
|
|
722
|
+
}
|
|
723
|
+
addAgent(name, config) {
|
|
724
|
+
if (!this.agentConfig.agents) {
|
|
725
|
+
this.agentConfig.agents = {};
|
|
726
|
+
}
|
|
727
|
+
this.agentConfig.agents[name] = config;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
function splitAgentTools(tools) {
|
|
731
|
+
const customTools = [];
|
|
732
|
+
const toolNames = [];
|
|
733
|
+
const addTool = (tool) => {
|
|
734
|
+
if (isRegisteredTool(tool)) {
|
|
735
|
+
customTools.push(tool);
|
|
736
|
+
toolNames.push(tool.name);
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
if (typeof tool === "string" && tool.length > 0) {
|
|
740
|
+
toolNames.push(tool);
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
throw new Error("Agent tools must be RegisteredTool instances or tool name strings");
|
|
744
|
+
};
|
|
745
|
+
if (tools === undefined || tools === null) {
|
|
746
|
+
return { customTools, toolNames };
|
|
747
|
+
}
|
|
748
|
+
if (Array.isArray(tools)) {
|
|
749
|
+
for (const tool of tools) {
|
|
750
|
+
addTool(tool);
|
|
751
|
+
}
|
|
752
|
+
return { customTools, toolNames };
|
|
753
|
+
}
|
|
754
|
+
addTool(tools);
|
|
755
|
+
return { customTools, toolNames };
|
|
756
|
+
}
|
|
757
|
+
function normalizeToolNameList(value) {
|
|
758
|
+
if (!value) {
|
|
759
|
+
return [];
|
|
760
|
+
}
|
|
761
|
+
if (Array.isArray(value)) {
|
|
762
|
+
return value.filter((item) => typeof item === "string" && item.length > 0);
|
|
763
|
+
}
|
|
764
|
+
if (typeof value === "string" && value.length > 0) {
|
|
765
|
+
return [value];
|
|
766
|
+
}
|
|
767
|
+
return [];
|
|
768
|
+
}
|
|
769
|
+
function mergeToolNames(toolNames) {
|
|
770
|
+
return Array.from(new Set(toolNames));
|
|
771
|
+
}
|
|
772
|
+
function normalizeAgentMcpServers(value) {
|
|
773
|
+
if (!value) {
|
|
774
|
+
return undefined;
|
|
775
|
+
}
|
|
776
|
+
if (Array.isArray(value)) {
|
|
777
|
+
return value;
|
|
778
|
+
}
|
|
779
|
+
return [value];
|
|
780
|
+
}
|
|
781
|
+
function mergeAgentMcpServers(existing, toolServerConfig) {
|
|
782
|
+
if (!toolServerConfig) {
|
|
783
|
+
return existing;
|
|
784
|
+
}
|
|
785
|
+
if (existing && existing.length > 0) {
|
|
786
|
+
return [toolServerConfig, ...existing];
|
|
787
|
+
}
|
|
788
|
+
return [toolServerConfig];
|
|
789
|
+
}
|
|
790
|
+
async function buildToolServerConfig(owner, tools, serverName) {
|
|
791
|
+
if (tools.length === 0) {
|
|
792
|
+
return null;
|
|
793
|
+
}
|
|
794
|
+
const command = await getAgentToolServiceCommand(owner, tools, {
|
|
795
|
+
name: serverName,
|
|
796
|
+
version: "1.0.0",
|
|
797
|
+
});
|
|
798
|
+
return {
|
|
799
|
+
[serverName]: {
|
|
800
|
+
type: "stdio",
|
|
801
|
+
command: command.command,
|
|
802
|
+
args: command.args,
|
|
803
|
+
...(command.env ? { env: command.env } : {}),
|
|
804
|
+
},
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
function getToolServiceOwner(value) {
|
|
808
|
+
const owner = resolveToolServiceOwner(value);
|
|
809
|
+
if (owner) {
|
|
810
|
+
return owner;
|
|
811
|
+
}
|
|
812
|
+
return isRecord(value) ? value : null;
|
|
813
|
+
}
|
|
814
|
+
function isRecord(value) {
|
|
815
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
816
|
+
}
|
|
817
|
+
function resolveString(value) {
|
|
818
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
819
|
+
}
|
|
820
|
+
function ensureClaudeSkillPlugin(skillDir) {
|
|
821
|
+
const pluginContent = {
|
|
822
|
+
name: "load-custom-skill-plugin",
|
|
823
|
+
description: "plugin to load custom skills",
|
|
824
|
+
version: "1.0.0",
|
|
825
|
+
skills: "./",
|
|
826
|
+
};
|
|
827
|
+
fs.mkdirSync(path.join(skillDir, ".claude-plugin"), { recursive: true });
|
|
828
|
+
const pluginPath = path.join(skillDir, ".claude-plugin", "plugin.json");
|
|
829
|
+
const serialized = `${JSON.stringify(pluginContent, null, 2)}\n`;
|
|
830
|
+
let shouldWrite = true;
|
|
831
|
+
if (fs.existsSync(pluginPath)) {
|
|
832
|
+
try {
|
|
833
|
+
const existing = fs.readFileSync(pluginPath, "utf-8");
|
|
834
|
+
if (existing === serialized) {
|
|
835
|
+
shouldWrite = false;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
catch {
|
|
839
|
+
shouldWrite = true;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
if (shouldWrite) {
|
|
843
|
+
fs.writeFileSync(pluginPath, serialized, "utf-8");
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
//# sourceMappingURL=claude.js.map
|