zidane 2.0.1 → 2.2.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 +40 -26
- package/dist/{agent-D-ZFMbSd.d.ts → agent-vPBFXnu-.d.ts} +389 -274
- package/dist/{chunk-SZA4FKW5.js → chunk-2EQT4EHD.js} +4 -3
- package/dist/{chunk-PJUUYBKF.js → chunk-37GD7NL3.js} +45 -16
- package/dist/{chunk-LVC7NQUZ.js → chunk-BW3WTFIR.js} +1 -1
- package/dist/{chunk-FRNFVKWW.js → chunk-CDRXC7A7.js} +64 -33
- package/dist/{chunk-PASFWG7S.js → chunk-F5UBXERT.js} +309 -77
- package/dist/{chunk-7JTBBZ2U.js → chunk-LNN5UTS2.js} +8 -0
- package/dist/{chunk-VG2E6YK3.js → chunk-PMCQOMV4.js} +4 -2
- package/dist/{chunk-LN4LLLHA.js → chunk-S3FCOMRI.js} +63 -20
- package/dist/{chunk-OVQ4N64O.js → chunk-SP5NA6WF.js} +6 -12
- package/dist/{chunk-BCXXXJ3G.js → chunk-TPXPVEH6.js} +99 -58
- package/dist/contexts.js +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.js +16 -16
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +1 -1
- package/dist/presets.d.ts +33 -0
- package/dist/presets.js +15 -0
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +3 -3
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/session.js +3 -3
- package/dist/{skills-use-C4KFVla0.d.ts → skills-use-39cCsA7_.d.ts} +4 -4
- package/dist/skills.d.ts +3 -9
- package/dist/skills.js +3 -5
- package/dist/spawn-Czx3owjX.d.ts +152 -0
- package/dist/tools.d.ts +6 -4
- package/dist/tools.js +5 -5
- package/dist/types.d.ts +3 -2
- package/dist/types.js +1 -1
- package/package.json +5 -5
- package/dist/harnesses.d.ts +0 -4
- package/dist/harnesses.js +0 -17
- package/dist/spawn-RoqpjYLZ.d.ts +0 -99
|
@@ -165,10 +165,11 @@ function createProcessContext(config) {
|
|
|
165
165
|
});
|
|
166
166
|
return { stdout, stderr, exitCode: 0 };
|
|
167
167
|
} catch (err) {
|
|
168
|
+
const e = err;
|
|
168
169
|
return {
|
|
169
|
-
stdout:
|
|
170
|
-
stderr:
|
|
171
|
-
exitCode:
|
|
170
|
+
stdout: typeof e.stdout === "string" ? e.stdout : "",
|
|
171
|
+
stderr: typeof e.stderr === "string" ? e.stderr : typeof e.message === "string" ? e.message : String(err),
|
|
172
|
+
exitCode: typeof e.code === "number" ? e.code : 1
|
|
172
173
|
};
|
|
173
174
|
}
|
|
174
175
|
},
|
|
@@ -69,8 +69,11 @@ function resultToString(content) {
|
|
|
69
69
|
if (!content || !Array.isArray(content))
|
|
70
70
|
return "";
|
|
71
71
|
return content.map((block) => {
|
|
72
|
-
if (block
|
|
73
|
-
|
|
72
|
+
if (block && typeof block === "object" && block.type === "text") {
|
|
73
|
+
const text = block.text;
|
|
74
|
+
if (typeof text === "string")
|
|
75
|
+
return text;
|
|
76
|
+
}
|
|
74
77
|
return JSON.stringify(block);
|
|
75
78
|
}).join("\n");
|
|
76
79
|
}
|
|
@@ -144,6 +147,7 @@ async function connectMcpServers(configs, _clientFactory, hooks) {
|
|
|
144
147
|
const connections = [];
|
|
145
148
|
const tools = {};
|
|
146
149
|
const errors = [];
|
|
150
|
+
let closed = false;
|
|
147
151
|
for (const config of configs) {
|
|
148
152
|
try {
|
|
149
153
|
const client = _clientFactory ? _clientFactory() : new Client({ name: "zidane", version: "1.0.0" });
|
|
@@ -162,8 +166,8 @@ async function connectMcpServers(configs, _clientFactory, hooks) {
|
|
|
162
166
|
inputSchema: tool.inputSchema ?? { type: "object", properties: {} }
|
|
163
167
|
},
|
|
164
168
|
execute: async (input, ctx) => {
|
|
165
|
-
const { turnId, callId } = ctx;
|
|
166
|
-
const displayName = ctx.
|
|
169
|
+
const { turnId, callId, signal } = ctx;
|
|
170
|
+
const displayName = ctx.toolAliases?.[namespacedName] ?? namespacedName;
|
|
167
171
|
const gateCtx = {
|
|
168
172
|
turnId,
|
|
169
173
|
callId,
|
|
@@ -188,13 +192,12 @@ async function connectMcpServers(configs, _clientFactory, hooks) {
|
|
|
188
192
|
});
|
|
189
193
|
const timeout = config.toolTimeout ?? 3e4;
|
|
190
194
|
try {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
]).finally(() => clearTimeout(timer));
|
|
195
|
+
const result = await raceWithTimeoutAndSignal(
|
|
196
|
+
() => client.callTool({ name: tool.name, arguments: effectiveInput }),
|
|
197
|
+
timeout,
|
|
198
|
+
`MCP tool "${tool.name}" on server "${config.name}" timed out after ${timeout}ms`,
|
|
199
|
+
signal
|
|
200
|
+
);
|
|
198
201
|
let output = packMcpResult(result.content);
|
|
199
202
|
const transformCtx = {
|
|
200
203
|
turnId,
|
|
@@ -218,6 +221,7 @@ async function connectMcpServers(configs, _clientFactory, hooks) {
|
|
|
218
221
|
});
|
|
219
222
|
return output;
|
|
220
223
|
} catch (err) {
|
|
224
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
221
225
|
await hooks?.callHook("mcp:tool:error", {
|
|
222
226
|
turnId,
|
|
223
227
|
callId,
|
|
@@ -225,7 +229,7 @@ async function connectMcpServers(configs, _clientFactory, hooks) {
|
|
|
225
229
|
tool: tool.name,
|
|
226
230
|
displayName,
|
|
227
231
|
input: effectiveInput,
|
|
228
|
-
error
|
|
232
|
+
error
|
|
229
233
|
});
|
|
230
234
|
await hooks?.callHook("mcp:tool:after", {
|
|
231
235
|
turnId,
|
|
@@ -234,9 +238,9 @@ async function connectMcpServers(configs, _clientFactory, hooks) {
|
|
|
234
238
|
tool: tool.name,
|
|
235
239
|
displayName,
|
|
236
240
|
input: effectiveInput,
|
|
237
|
-
result:
|
|
241
|
+
result: error.message
|
|
238
242
|
});
|
|
239
|
-
throw
|
|
243
|
+
throw error;
|
|
240
244
|
}
|
|
241
245
|
}
|
|
242
246
|
};
|
|
@@ -247,8 +251,9 @@ async function connectMcpServers(configs, _clientFactory, hooks) {
|
|
|
247
251
|
tools: toolNames
|
|
248
252
|
});
|
|
249
253
|
} catch (err) {
|
|
250
|
-
|
|
251
|
-
|
|
254
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
255
|
+
errors.push({ name: config.name, error });
|
|
256
|
+
await hooks?.callHook("mcp:error", { name: config.name, error });
|
|
252
257
|
}
|
|
253
258
|
}
|
|
254
259
|
if (errors.length > 0 && connections.length === 0) {
|
|
@@ -258,6 +263,9 @@ async function connectMcpServers(configs, _clientFactory, hooks) {
|
|
|
258
263
|
return {
|
|
259
264
|
tools,
|
|
260
265
|
close: async () => {
|
|
266
|
+
if (closed)
|
|
267
|
+
return;
|
|
268
|
+
closed = true;
|
|
261
269
|
await Promise.allSettled(
|
|
262
270
|
connections.map(async ({ name, client }) => {
|
|
263
271
|
await hooks?.callHook("mcp:close", { name });
|
|
@@ -267,6 +275,27 @@ async function connectMcpServers(configs, _clientFactory, hooks) {
|
|
|
267
275
|
}
|
|
268
276
|
};
|
|
269
277
|
}
|
|
278
|
+
async function raceWithTimeoutAndSignal(task, timeoutMs, timeoutMessage, signal) {
|
|
279
|
+
if (signal?.aborted)
|
|
280
|
+
throw new Error("MCP tool call aborted");
|
|
281
|
+
let timer;
|
|
282
|
+
let onAbort;
|
|
283
|
+
try {
|
|
284
|
+
return await new Promise((resolvePromise, rejectPromise) => {
|
|
285
|
+
timer = setTimeout(() => rejectPromise(new Error(timeoutMessage)), timeoutMs);
|
|
286
|
+
if (signal) {
|
|
287
|
+
onAbort = () => rejectPromise(new Error("MCP tool call aborted"));
|
|
288
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
289
|
+
}
|
|
290
|
+
task().then(resolvePromise, rejectPromise);
|
|
291
|
+
});
|
|
292
|
+
} finally {
|
|
293
|
+
if (timer)
|
|
294
|
+
clearTimeout(timer);
|
|
295
|
+
if (signal && onAbort)
|
|
296
|
+
signal.removeEventListener("abort", onAbort);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
270
299
|
|
|
271
300
|
export {
|
|
272
301
|
normalizeMcpServers,
|
|
@@ -5,27 +5,39 @@ import {
|
|
|
5
5
|
toAnthropic,
|
|
6
6
|
toolResultsMessage,
|
|
7
7
|
userMessage
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-S3FCOMRI.js";
|
|
9
9
|
import {
|
|
10
10
|
matchesContextExceeded
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
|
|
13
|
-
// src/providers/anthropic.ts
|
|
14
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
15
|
-
import { resolve as resolve2 } from "path";
|
|
11
|
+
} from "./chunk-LNN5UTS2.js";
|
|
16
12
|
|
|
17
13
|
// src/providers/oauth.ts
|
|
18
|
-
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
14
|
+
import { existsSync, readFileSync, renameSync, writeFileSync } from "fs";
|
|
19
15
|
import { resolve } from "path";
|
|
20
16
|
import { getOAuthApiKey } from "@yaelg/pi-ai/oauth";
|
|
21
|
-
|
|
17
|
+
function credentialsFilePath() {
|
|
18
|
+
return resolve(process.cwd(), ".credentials.json");
|
|
19
|
+
}
|
|
20
|
+
var CREDENTIALS_FILE_MODE = 384;
|
|
21
|
+
var refreshLocks = /* @__PURE__ */ new Map();
|
|
22
22
|
function readOAuthCredentials() {
|
|
23
|
-
|
|
23
|
+
const path = credentialsFilePath();
|
|
24
|
+
if (!existsSync(path))
|
|
24
25
|
return {};
|
|
25
|
-
|
|
26
|
+
try {
|
|
27
|
+
const raw = readFileSync(path, "utf-8");
|
|
28
|
+
const parsed = JSON.parse(raw);
|
|
29
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
30
|
+
return {};
|
|
31
|
+
return parsed;
|
|
32
|
+
} catch {
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
26
35
|
}
|
|
27
36
|
function writeOAuthCredentials(credentials) {
|
|
28
|
-
|
|
37
|
+
const path = credentialsFilePath();
|
|
38
|
+
const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
39
|
+
writeFileSync(tmp, JSON.stringify(credentials, null, 2), { mode: CREDENTIALS_FILE_MODE });
|
|
40
|
+
renameSync(tmp, path);
|
|
29
41
|
}
|
|
30
42
|
function credentialsFromParams(params, extraKeys = []) {
|
|
31
43
|
if (typeof params?.access !== "string" || typeof params.refresh !== "string" || typeof params.expires !== "number")
|
|
@@ -45,7 +57,10 @@ async function resolveOAuthApiKey(options, callbacks) {
|
|
|
45
57
|
return options.params.apiKey;
|
|
46
58
|
const paramsCredentials = credentialsFromParams(options.params, options.extraCredentialKeys);
|
|
47
59
|
if (paramsCredentials) {
|
|
48
|
-
return await
|
|
60
|
+
return await withRefreshLock(
|
|
61
|
+
`params:${options.providerId}`,
|
|
62
|
+
() => resolveCredentialSource("params", paramsCredentials)
|
|
63
|
+
);
|
|
49
64
|
}
|
|
50
65
|
if (typeof options.params?.access === "string")
|
|
51
66
|
return options.params.access;
|
|
@@ -53,21 +68,23 @@ async function resolveOAuthApiKey(options, callbacks) {
|
|
|
53
68
|
return process.env[options.envKey];
|
|
54
69
|
const readCredentials = options.readCredentials ?? readOAuthCredentials;
|
|
55
70
|
const writeCredentials = options.writeCredentials ?? writeOAuthCredentials;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
71
|
+
return await withRefreshLock(`file:${options.providerId}`, async () => {
|
|
72
|
+
const allCredentials = readCredentials();
|
|
73
|
+
const storedCredentials = allCredentials[options.providerId];
|
|
74
|
+
if (!storedCredentials)
|
|
75
|
+
throw new Error(options.missingError);
|
|
76
|
+
return await resolveCredentialSource("file", storedCredentials, allCredentials, writeCredentials);
|
|
77
|
+
});
|
|
78
|
+
async function resolveCredentialSource(source, current, allCredentials, persistCredentials) {
|
|
62
79
|
try {
|
|
63
80
|
const refreshOAuthApiKey = options.getOAuthApiKey ?? getOAuthApiKey;
|
|
64
81
|
const result = await refreshOAuthApiKey(options.providerId, { [options.providerId]: current });
|
|
65
82
|
if (!result)
|
|
66
83
|
throw new Error(options.missingError);
|
|
67
84
|
if (result.newCredentials !== current) {
|
|
68
|
-
if (source === "file" &&
|
|
69
|
-
|
|
70
|
-
persistCredentials(
|
|
85
|
+
if (source === "file" && allCredentials && persistCredentials) {
|
|
86
|
+
allCredentials[options.providerId] = result.newCredentials;
|
|
87
|
+
persistCredentials(allCredentials);
|
|
71
88
|
}
|
|
72
89
|
await callbacks?.onOAuthRefresh?.({
|
|
73
90
|
provider: options.provider,
|
|
@@ -84,9 +101,22 @@ async function resolveOAuthApiKey(options, callbacks) {
|
|
|
84
101
|
}
|
|
85
102
|
}
|
|
86
103
|
}
|
|
104
|
+
async function withRefreshLock(key, fn) {
|
|
105
|
+
const existing = refreshLocks.get(key);
|
|
106
|
+
if (existing)
|
|
107
|
+
return existing;
|
|
108
|
+
const task = (async () => {
|
|
109
|
+
try {
|
|
110
|
+
return await fn();
|
|
111
|
+
} finally {
|
|
112
|
+
refreshLocks.delete(key);
|
|
113
|
+
}
|
|
114
|
+
})();
|
|
115
|
+
refreshLocks.set(key, task);
|
|
116
|
+
return task;
|
|
117
|
+
}
|
|
87
118
|
|
|
88
119
|
// src/providers/anthropic.ts
|
|
89
|
-
var CREDENTIALS_FILE2 = resolve2(process.cwd(), ".credentials.json");
|
|
90
120
|
var _sdkCtor = null;
|
|
91
121
|
async function loadAnthropicSdk() {
|
|
92
122
|
if (_sdkCtor)
|
|
@@ -109,11 +139,9 @@ function getConfiguredApiKey(anthropicParams) {
|
|
|
109
139
|
return anthropicParams.access;
|
|
110
140
|
if (process.env.ANTHROPIC_API_KEY)
|
|
111
141
|
return process.env.ANTHROPIC_API_KEY;
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return creds.anthropic.access;
|
|
116
|
-
}
|
|
142
|
+
const access = readOAuthCredentials().anthropic?.access;
|
|
143
|
+
if (typeof access === "string" && access.length > 0)
|
|
144
|
+
return access;
|
|
117
145
|
throw new Error("No API key found. Run `bun run auth` first.");
|
|
118
146
|
}
|
|
119
147
|
function createClient(SDK, apiKey, isOAuth, baseURL) {
|
|
@@ -183,10 +211,13 @@ function classifyAnthropicError(err) {
|
|
|
183
211
|
message
|
|
184
212
|
};
|
|
185
213
|
}
|
|
214
|
+
const status = anyErr.status;
|
|
215
|
+
const retryable = typeof status === "number" ? status === 429 || status >= 500 && status !== 501 : void 0;
|
|
186
216
|
return {
|
|
187
217
|
kind: "provider_error",
|
|
188
|
-
providerCode: nativeType ?? (
|
|
189
|
-
message
|
|
218
|
+
providerCode: nativeType ?? (status ? String(status) : void 0),
|
|
219
|
+
message,
|
|
220
|
+
...retryable !== void 0 ? { retryable } : {}
|
|
190
221
|
};
|
|
191
222
|
}
|
|
192
223
|
function anthropicPromptMessage(parts) {
|
|
@@ -368,11 +399,11 @@ function anthropic(anthropicParams) {
|
|
|
368
399
|
// src/providers/cerebras.ts
|
|
369
400
|
var BASE_URL = "https://api.cerebras.ai/v1";
|
|
370
401
|
function getApiKey(params) {
|
|
371
|
-
if (params?.apiKey)
|
|
402
|
+
if (typeof params?.apiKey === "string" && params.apiKey.length > 0)
|
|
372
403
|
return params.apiKey;
|
|
373
404
|
if (process.env.CEREBRAS_API_KEY)
|
|
374
405
|
return process.env.CEREBRAS_API_KEY;
|
|
375
|
-
throw new Error("No Cerebras API key found.
|
|
406
|
+
throw new Error("No Cerebras API key found. Pass `apiKey` or set CEREBRAS_API_KEY in your environment.");
|
|
376
407
|
}
|
|
377
408
|
function cerebras(params) {
|
|
378
409
|
const apiKey = getApiKey(params);
|
|
@@ -650,11 +681,11 @@ function openai(params) {
|
|
|
650
681
|
// src/providers/openrouter.ts
|
|
651
682
|
var BASE_URL2 = "https://openrouter.ai/api/v1";
|
|
652
683
|
function getApiKey2(params) {
|
|
653
|
-
if (params?.apiKey)
|
|
684
|
+
if (typeof params?.apiKey === "string" && params.apiKey.length > 0)
|
|
654
685
|
return params.apiKey;
|
|
655
686
|
if (process.env.OPENROUTER_API_KEY)
|
|
656
687
|
return process.env.OPENROUTER_API_KEY;
|
|
657
|
-
throw new Error("No OpenRouter API key found.
|
|
688
|
+
throw new Error("No OpenRouter API key found. Pass `apiKey` or set OPENROUTER_API_KEY in your environment.");
|
|
658
689
|
}
|
|
659
690
|
function openrouter(params) {
|
|
660
691
|
const apiKey = getApiKey2(params);
|