@yukino.js/yukino 0.0.1
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 +320 -0
- package/dist/acp-IVY5HZR4.js +14 -0
- package/dist/agent-QANDY7FO.js +4 -0
- package/dist/anthropic-6YLT4JZR.js +4 -0
- package/dist/bwrap-MLSZLWHD.js +4 -0
- package/dist/chunk-2LHY3FND.js +67 -0
- package/dist/chunk-3KKA6537.js +4 -0
- package/dist/chunk-3QL446GD.js +4 -0
- package/dist/chunk-4GE22WHI.js +4 -0
- package/dist/chunk-5VOCXSSX.js +5 -0
- package/dist/chunk-77W2UPS2.js +4 -0
- package/dist/chunk-7MKA3SHV.js +4 -0
- package/dist/chunk-AGSYLE4E.js +16 -0
- package/dist/chunk-CU3IISCC.js +4 -0
- package/dist/chunk-GYBJR2RB.js +65 -0
- package/dist/chunk-HLE7243Q.js +4 -0
- package/dist/chunk-HMZQYFYG.js +4 -0
- package/dist/chunk-JFKC4VCA.js +4 -0
- package/dist/chunk-K4BYVVW7.js +5 -0
- package/dist/chunk-KCMBAHWU.js +4 -0
- package/dist/chunk-L2BWSPCF.js +10 -0
- package/dist/chunk-MDPSQ6L7.js +44 -0
- package/dist/chunk-OFC2GD5K.js +4 -0
- package/dist/chunk-RAS3ORX3.js +164 -0
- package/dist/chunk-RCXKUD3Y.js +4 -0
- package/dist/chunk-SAJCBGHL.js +4 -0
- package/dist/chunk-SOO5OXX2.js +237 -0
- package/dist/chunk-T4O4GQVL.js +607 -0
- package/dist/chunk-UPNNYP7M.js +60 -0
- package/dist/chunk-VCIRD267.js +4 -0
- package/dist/chunk-VU3JWAJR.js +4 -0
- package/dist/chunk-VWUGGYUP.js +6 -0
- package/dist/chunk-XO7ITAWR.js +4 -0
- package/dist/devtools-YWVUN4HX.js +7 -0
- package/dist/esm-57CJEGGK.js +4 -0
- package/dist/esm-6L5BJ5GT.js +4 -0
- package/dist/esm-DIYJ5HX6.js +4 -0
- package/dist/esm-HW2JMFYC.js +4 -0
- package/dist/esm-RPR2GBJ2.js +4 -0
- package/dist/esm-YKAO4ES6.js +4 -0
- package/dist/esm-ZTIYTMTS.js +229 -0
- package/dist/getMachineId-bsd-E27XJQLX.js +4 -0
- package/dist/getMachineId-darwin-35UPAIXP.js +5 -0
- package/dist/getMachineId-linux-MKXIYT6A.js +4 -0
- package/dist/getMachineId-unsupported-ZXVGGFX2.js +4 -0
- package/dist/getMachineId-win-RNVIYJG5.js +4 -0
- package/dist/lib/agent-6FZX4P2Y.js +16 -0
- package/dist/lib/anthropic-IP23YZ3P.js +21 -0
- package/dist/lib/bwrap-2OL7VPSO.js +7 -0
- package/dist/lib/chunk-2VF3XTGH.js +3382 -0
- package/dist/lib/chunk-5DVQ64YL.js +619 -0
- package/dist/lib/chunk-5TGXH7BX.js +624 -0
- package/dist/lib/chunk-6OMQD7MK.js +591 -0
- package/dist/lib/chunk-AZRC67RW.js +512 -0
- package/dist/lib/chunk-F2YJG72O.js +150 -0
- package/dist/lib/chunk-FFM2LB4C.js +132 -0
- package/dist/lib/chunk-FLKB4BK7.js +50 -0
- package/dist/lib/chunk-I34MAQRE.js +255 -0
- package/dist/lib/chunk-KA6POJKI.js +889 -0
- package/dist/lib/chunk-MLKGABMK.js +9 -0
- package/dist/lib/chunk-O7ELJUEK.js +262 -0
- package/dist/lib/chunk-QYBQT2DM.js +655 -0
- package/dist/lib/chunk-YIWNQ7OA.js +47 -0
- package/dist/lib/index.d.ts +8581 -0
- package/dist/lib/index.js +15905 -0
- package/dist/lib/openai-EMJ6U4FW.js +15 -0
- package/dist/lib/permissions-KZ5ACZAX.js +19 -0
- package/dist/lib/providers-2CGZPBFI.js +9 -0
- package/dist/lib/sandbox-runtime-CCQ3X3SM.js +9 -0
- package/dist/lib/seatbelt-WO7YWKLR.js +7 -0
- package/dist/lib/tool-filter-CKHZUUBQ.js +21 -0
- package/dist/main.js +332 -0
- package/dist/node-634LOHDX.js +15 -0
- package/dist/openai-YXYO5OW6.js +34 -0
- package/dist/permissions-VCDMNX3L.js +4 -0
- package/dist/providers-HNMBGGW6.js +4 -0
- package/dist/sandbox-runtime-ELKAYRIL.js +4 -0
- package/dist/seatbelt-JOCANLYS.js +4 -0
- package/dist/server-ZHQILOBP.js +4 -0
- package/dist/src-43CPCEK2.js +12 -0
- package/dist/src-JBRNH4FA.js +4 -0
- package/dist/src-R4BSSIJJ.js +4 -0
- package/dist/src-X6JWWHHT.js +4 -0
- package/dist/tool-filter-BQZDV3TF.js +4 -0
- package/dist/turndown.es-NQ3KDXM7.js +83 -0
- package/package.json +146 -0
|
@@ -0,0 +1,655 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createChildLogger
|
|
3
|
+
} from "./chunk-6OMQD7MK.js";
|
|
4
|
+
import {
|
|
5
|
+
__export
|
|
6
|
+
} from "./chunk-MLKGABMK.js";
|
|
7
|
+
|
|
8
|
+
// src/config/index.ts
|
|
9
|
+
var config_exports = {};
|
|
10
|
+
__export(config_exports, {
|
|
11
|
+
ConfigError: () => ConfigError,
|
|
12
|
+
DEFAULT_CONTEXT_WINDOW: () => DEFAULT_CONTEXT_WINDOW,
|
|
13
|
+
DEFAULT_MAX_OUTPUT_TOKENS: () => DEFAULT_MAX_OUTPUT_TOKENS,
|
|
14
|
+
DEFAULT_THINKING_LEVEL: () => DEFAULT_THINKING_LEVEL,
|
|
15
|
+
HookConfigSchema: () => HookConfigSchema,
|
|
16
|
+
MIN_THINKING_ANSWER_TOKENS: () => MIN_THINKING_ANSWER_TOKENS,
|
|
17
|
+
MIN_THINKING_BUDGET_TOKENS: () => MIN_THINKING_BUDGET_TOKENS,
|
|
18
|
+
ProviderConfigSchema: () => ProviderConfigSchema,
|
|
19
|
+
THINKING_BUDGETS: () => THINKING_BUDGETS,
|
|
20
|
+
THINKING_LEVELS: () => THINKING_LEVELS,
|
|
21
|
+
clampThinkingLevel: () => clampThinkingLevel,
|
|
22
|
+
forkEnabled: () => forkEnabled,
|
|
23
|
+
getContextWindow: () => getContextWindow,
|
|
24
|
+
getMaxOutputTokens: () => getMaxOutputTokens,
|
|
25
|
+
getSupportedThinkingLevels: () => getSupportedThinkingLevels,
|
|
26
|
+
getThinkingLevel: () => getThinkingLevel,
|
|
27
|
+
globalConfigPath: () => globalConfigPath,
|
|
28
|
+
isValidThinkingLevel: () => isValidThinkingLevel,
|
|
29
|
+
loadConfig: () => loadConfig,
|
|
30
|
+
loadProjectMcpServers: () => loadProjectMcpServers,
|
|
31
|
+
resolveAPIKey: () => resolveAPIKey,
|
|
32
|
+
thinkingBudgetForLevel: () => thinkingBudgetForLevel,
|
|
33
|
+
toAnthropicThinkingEffort: () => toAnthropicThinkingEffort,
|
|
34
|
+
toReasoningEffort: () => toReasoningEffort,
|
|
35
|
+
withProjectMcpServers: () => withProjectMcpServers,
|
|
36
|
+
withProviderDefaults: () => withProviderDefaults
|
|
37
|
+
});
|
|
38
|
+
import { existsSync, readFileSync } from "fs";
|
|
39
|
+
import { homedir } from "os";
|
|
40
|
+
import { join } from "path";
|
|
41
|
+
import {
|
|
42
|
+
getParseErrorMessage,
|
|
43
|
+
safeParse
|
|
44
|
+
} from "@modelcontextprotocol/sdk/server/zod-compat.js";
|
|
45
|
+
import yaml from "js-yaml";
|
|
46
|
+
import { z } from "zod";
|
|
47
|
+
var log = createChildLogger({ module: "config" });
|
|
48
|
+
var ENV_KEY_MAP = {
|
|
49
|
+
anthropic: "ANTHROPIC_API_KEY",
|
|
50
|
+
openai: "OPENAI_API_KEY",
|
|
51
|
+
"openai-compat": "OPENAI_API_KEY"
|
|
52
|
+
};
|
|
53
|
+
function isKeyofTypeofEnvKeyMap(k) {
|
|
54
|
+
return VALID_PROTOCOLS.has(k);
|
|
55
|
+
}
|
|
56
|
+
var VALID_PROTOCOLS = new Set(Object.keys(ENV_KEY_MAP));
|
|
57
|
+
var ConfigError = class extends Error {
|
|
58
|
+
constructor(message) {
|
|
59
|
+
super(message);
|
|
60
|
+
this.name = "ConfigError";
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
function globalConfigPath() {
|
|
64
|
+
return join(homedir(), ".yukino", "config.yaml");
|
|
65
|
+
}
|
|
66
|
+
var THINKING_LEVELS = [
|
|
67
|
+
"off",
|
|
68
|
+
"minimal",
|
|
69
|
+
"low",
|
|
70
|
+
"medium",
|
|
71
|
+
"high",
|
|
72
|
+
"xhigh",
|
|
73
|
+
"max"
|
|
74
|
+
];
|
|
75
|
+
var ReasoningEffortSchema = z.enum([
|
|
76
|
+
"none",
|
|
77
|
+
"minimal",
|
|
78
|
+
"low",
|
|
79
|
+
"medium",
|
|
80
|
+
"high",
|
|
81
|
+
"xhigh",
|
|
82
|
+
"max"
|
|
83
|
+
]);
|
|
84
|
+
var AnthropicEffortSchema = z.enum(["low", "medium", "high", "xhigh", "max"]);
|
|
85
|
+
var ThinkingLevelMapSchema = z.strictObject({
|
|
86
|
+
off: z.literal("none").nullable().optional(),
|
|
87
|
+
minimal: ReasoningEffortSchema.nullable().optional(),
|
|
88
|
+
low: ReasoningEffortSchema.nullable().optional(),
|
|
89
|
+
medium: ReasoningEffortSchema.nullable().optional(),
|
|
90
|
+
high: ReasoningEffortSchema.nullable().optional(),
|
|
91
|
+
xhigh: ReasoningEffortSchema.nullable().optional(),
|
|
92
|
+
max: ReasoningEffortSchema.nullable().optional()
|
|
93
|
+
});
|
|
94
|
+
var ProviderConfigSchema = z.looseObject({
|
|
95
|
+
name: z.string(),
|
|
96
|
+
/**
|
|
97
|
+
* enum: ["anthropic", "openai", "openai-compat"]
|
|
98
|
+
*/
|
|
99
|
+
protocol: z.enum(["anthropic", "openai", "openai-compat"]),
|
|
100
|
+
base_url: z.string(),
|
|
101
|
+
model: z.string(),
|
|
102
|
+
api_key: z.string().optional(),
|
|
103
|
+
thinking: z.enum(THINKING_LEVELS).optional(),
|
|
104
|
+
/** Explicit capability metadata, never inferred from model names. */
|
|
105
|
+
reasoning: z.boolean().optional(),
|
|
106
|
+
thinking_level_map: ThinkingLevelMapSchema.optional(),
|
|
107
|
+
/** Only Anthropic uses this mode; existing configurations use budgets. */
|
|
108
|
+
thinking_mode: z.enum(["budget", "adaptive"]).optional(),
|
|
109
|
+
context_window: z.coerce.number().optional(),
|
|
110
|
+
/**
|
|
111
|
+
* The model's output ceiling (PI's `model.maxTokens`). Clamped to the
|
|
112
|
+
* context window; reasoning shares this ceiling instead of raising it.
|
|
113
|
+
*/
|
|
114
|
+
max_output_tokens: z.coerce.number().optional()
|
|
115
|
+
});
|
|
116
|
+
var DEFAULT_THINKING_LEVEL = "high";
|
|
117
|
+
var DEFAULT_CONTEXT_WINDOW = 1e6;
|
|
118
|
+
var DEFAULT_MAX_OUTPUT_TOKENS = 128e3;
|
|
119
|
+
var THINKING_BUDGETS = {
|
|
120
|
+
minimal: 1024,
|
|
121
|
+
low: 2048,
|
|
122
|
+
medium: 8192,
|
|
123
|
+
high: 16384,
|
|
124
|
+
xhigh: 32768,
|
|
125
|
+
max: 65536
|
|
126
|
+
};
|
|
127
|
+
var MIN_THINKING_BUDGET_TOKENS = 1024;
|
|
128
|
+
var MIN_THINKING_ANSWER_TOKENS = 1024;
|
|
129
|
+
function isValidThinkingLevel(value) {
|
|
130
|
+
return THINKING_LEVELS.some((level) => level === value);
|
|
131
|
+
}
|
|
132
|
+
function getThinkingLevel(provider) {
|
|
133
|
+
return clampThinkingLevel(
|
|
134
|
+
provider,
|
|
135
|
+
provider.thinking ?? DEFAULT_THINKING_LEVEL
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
function thinkingBudgetForLevel(level) {
|
|
139
|
+
return level === "off" ? 0 : THINKING_BUDGETS[level];
|
|
140
|
+
}
|
|
141
|
+
function toReasoningEffort(level, provider) {
|
|
142
|
+
if (provider?.reasoning === false) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
if (level === "off") {
|
|
146
|
+
return "none";
|
|
147
|
+
}
|
|
148
|
+
const mapped = provider?.thinking_level_map?.[level];
|
|
149
|
+
if (mapped !== void 0) {
|
|
150
|
+
return mapped;
|
|
151
|
+
}
|
|
152
|
+
if (provider?.protocol === "anthropic" && provider.thinking_mode === "adaptive") {
|
|
153
|
+
if (level === "minimal") {
|
|
154
|
+
return "low";
|
|
155
|
+
}
|
|
156
|
+
if (level === "xhigh") {
|
|
157
|
+
return "high";
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return level;
|
|
161
|
+
}
|
|
162
|
+
function toAnthropicThinkingEffort(level, provider) {
|
|
163
|
+
const parsed = AnthropicEffortSchema.safeParse(
|
|
164
|
+
toReasoningEffort(level, provider)
|
|
165
|
+
);
|
|
166
|
+
return parsed.success ? parsed.data : null;
|
|
167
|
+
}
|
|
168
|
+
function getSupportedThinkingLevels(provider) {
|
|
169
|
+
if (provider.reasoning === false || provider.protocol === "anthropic" && provider.thinking_mode !== "adaptive" && getMaxOutputTokens(provider) < MIN_THINKING_BUDGET_TOKENS + MIN_THINKING_ANSWER_TOKENS) {
|
|
170
|
+
return ["off"];
|
|
171
|
+
}
|
|
172
|
+
return THINKING_LEVELS.filter((level) => {
|
|
173
|
+
if (level === "off") {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
if (provider.protocol === "anthropic" && provider.thinking_mode === "adaptive") {
|
|
177
|
+
return toAnthropicThinkingEffort(level, provider) !== null;
|
|
178
|
+
}
|
|
179
|
+
const effort = toReasoningEffort(level, provider);
|
|
180
|
+
return effort !== null && effort !== "none";
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
function clampThinkingLevel(provider, level) {
|
|
184
|
+
const supported = getSupportedThinkingLevels(provider);
|
|
185
|
+
let effective = "off";
|
|
186
|
+
for (const candidate of THINKING_LEVELS) {
|
|
187
|
+
if (supported.includes(candidate)) {
|
|
188
|
+
effective = candidate;
|
|
189
|
+
}
|
|
190
|
+
if (candidate === level) {
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return effective;
|
|
195
|
+
}
|
|
196
|
+
function withProviderDefaults(provider) {
|
|
197
|
+
return {
|
|
198
|
+
...provider,
|
|
199
|
+
thinking: getThinkingLevel(provider),
|
|
200
|
+
context_window: getContextWindow(provider),
|
|
201
|
+
max_output_tokens: getMaxOutputTokens(provider)
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function getContextWindow(provider) {
|
|
205
|
+
return Number.isSafeInteger(provider.context_window) && (provider.context_window ?? 0) > 0 ? provider.context_window ?? DEFAULT_CONTEXT_WINDOW : DEFAULT_CONTEXT_WINDOW;
|
|
206
|
+
}
|
|
207
|
+
function getMaxOutputTokens(provider) {
|
|
208
|
+
const configured = provider.max_output_tokens;
|
|
209
|
+
const maxOutput = Number.isSafeInteger(configured) && (configured ?? 0) > 0 ? configured ?? DEFAULT_MAX_OUTPUT_TOKENS : DEFAULT_MAX_OUTPUT_TOKENS;
|
|
210
|
+
return Math.min(maxOutput, getContextWindow(provider));
|
|
211
|
+
}
|
|
212
|
+
function resolveAPIKey(p) {
|
|
213
|
+
if (p.api_key) {
|
|
214
|
+
return p.api_key;
|
|
215
|
+
}
|
|
216
|
+
const envVar = isKeyofTypeofEnvKeyMap(p.protocol) ? ENV_KEY_MAP[p.protocol] : "";
|
|
217
|
+
if (!envVar) {
|
|
218
|
+
return "";
|
|
219
|
+
}
|
|
220
|
+
return process.env[envVar] ?? "";
|
|
221
|
+
}
|
|
222
|
+
var MCPServerConfigSchema = z.object({
|
|
223
|
+
name: z.string(),
|
|
224
|
+
command: z.string().optional(),
|
|
225
|
+
args: z.array(z.string()).optional(),
|
|
226
|
+
url: z.string().optional(),
|
|
227
|
+
transport: z.string().optional(),
|
|
228
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
229
|
+
env: z.record(z.string(), z.string()).optional()
|
|
230
|
+
});
|
|
231
|
+
var HookConfigSchema = z.object({
|
|
232
|
+
id: z.string().optional(),
|
|
233
|
+
event: z.string(),
|
|
234
|
+
condition: z.string().optional(),
|
|
235
|
+
action: z.object({
|
|
236
|
+
type: z.string(),
|
|
237
|
+
command: z.string().optional(),
|
|
238
|
+
url: z.string().optional(),
|
|
239
|
+
method: z.string().optional(),
|
|
240
|
+
prompt: z.string().optional()
|
|
241
|
+
}),
|
|
242
|
+
reject: z.boolean().optional(),
|
|
243
|
+
once: z.boolean().optional(),
|
|
244
|
+
async: z.boolean().optional(),
|
|
245
|
+
on_error: z.string().optional()
|
|
246
|
+
});
|
|
247
|
+
var SandboxYamlConfigSchema = z.object({
|
|
248
|
+
enabled: z.boolean().optional(),
|
|
249
|
+
backend: z.enum(["native", "sandbox-runtime"]).optional(),
|
|
250
|
+
auto_allow: z.boolean().optional(),
|
|
251
|
+
network_enabled: z.boolean().optional()
|
|
252
|
+
});
|
|
253
|
+
var AppConfigSchema = z.looseObject({
|
|
254
|
+
providers: z.array(ProviderConfigSchema),
|
|
255
|
+
permission_mode: z.string().optional(),
|
|
256
|
+
mcp_servers: z.array(MCPServerConfigSchema).default([]),
|
|
257
|
+
hooks: z.array(HookConfigSchema).default([]),
|
|
258
|
+
sandbox: SandboxYamlConfigSchema.optional(),
|
|
259
|
+
enable_coordinator_mode: z.boolean().optional(),
|
|
260
|
+
/**
|
|
261
|
+
* Whether to fork when subagent_type is omitted. Enabled by default, so this
|
|
262
|
+
* field is left as undefined to represent "not specified in config". Using a
|
|
263
|
+
* concrete boolean would make it impossible to distinguish "not set" from
|
|
264
|
+
* "explicitly false", and the latter could never be turned back off.
|
|
265
|
+
*/
|
|
266
|
+
enable_fork: z.boolean().optional()
|
|
267
|
+
});
|
|
268
|
+
function forkEnabled(cfg) {
|
|
269
|
+
return cfg.enable_fork !== false;
|
|
270
|
+
}
|
|
271
|
+
function isRecord(value) {
|
|
272
|
+
return typeof value === "object" && value !== null;
|
|
273
|
+
}
|
|
274
|
+
function loadSingleFile(path) {
|
|
275
|
+
const data = readFileSync(path, "utf-8");
|
|
276
|
+
const raw = yaml.load(data);
|
|
277
|
+
if (!isRecord(raw)) {
|
|
278
|
+
log.error({ path }, "invalid yaml");
|
|
279
|
+
return { providers: [], mcp_servers: [], hooks: [] };
|
|
280
|
+
}
|
|
281
|
+
const parsed = safeParse(AppConfigSchema, raw);
|
|
282
|
+
if (parsed.success) {
|
|
283
|
+
const data2 = parsed.data;
|
|
284
|
+
return {
|
|
285
|
+
...data2,
|
|
286
|
+
providers: data2.providers.map(withProviderDefaults)
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
log.error({ error: parsed.error }, "config error");
|
|
290
|
+
let providers = [];
|
|
291
|
+
let permissionMode;
|
|
292
|
+
let mcpServers = [];
|
|
293
|
+
let hooks = [];
|
|
294
|
+
let sandbox = void 0;
|
|
295
|
+
let enableCoordinatorMode = false;
|
|
296
|
+
let enableFork = true;
|
|
297
|
+
if ("providers" in raw) {
|
|
298
|
+
const parsed2 = safeParse(z.array(ProviderConfigSchema), raw.providers);
|
|
299
|
+
if (parsed2.success) {
|
|
300
|
+
providers = parsed2.data.map(withProviderDefaults);
|
|
301
|
+
} else {
|
|
302
|
+
throw new ConfigError(
|
|
303
|
+
`Invalid provider configuration in ${path}: ${getParseErrorMessage(parsed2.error)}`
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if ("permission_mode" in raw && typeof raw.permission_mode === "string") {
|
|
308
|
+
permissionMode = raw.permission_mode;
|
|
309
|
+
}
|
|
310
|
+
if ("mcp_servers" in raw) {
|
|
311
|
+
const parsed2 = safeParse(z.array(MCPServerConfigSchema), raw.mcp_servers);
|
|
312
|
+
if (parsed2.success) {
|
|
313
|
+
mcpServers = parsed2.data;
|
|
314
|
+
} else {
|
|
315
|
+
throw new ConfigError(
|
|
316
|
+
`Invalid MCP server configuration in ${path}: ${getParseErrorMessage(parsed2.error)}`
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if ("hooks" in raw) {
|
|
321
|
+
const parsed2 = safeParse(z.array(HookConfigSchema), raw.hooks);
|
|
322
|
+
if (parsed2.success) {
|
|
323
|
+
hooks = parsed2.data;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if ("sandbox" in raw) {
|
|
327
|
+
const parsed2 = safeParse(SandboxYamlConfigSchema, raw.sandbox);
|
|
328
|
+
if (parsed2.success) {
|
|
329
|
+
sandbox = parsed2.data;
|
|
330
|
+
} else {
|
|
331
|
+
throw new ConfigError(
|
|
332
|
+
`Invalid sandbox configuration in ${path}: ${getParseErrorMessage(parsed2.error)}`
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
if ("enable_coordinator_mode" in raw) {
|
|
337
|
+
enableCoordinatorMode = Boolean(raw.enable_coordinator_mode);
|
|
338
|
+
}
|
|
339
|
+
if ("enable_fork" in raw) {
|
|
340
|
+
enableFork = Boolean(raw.enable_fork);
|
|
341
|
+
}
|
|
342
|
+
return {
|
|
343
|
+
providers,
|
|
344
|
+
permission_mode: permissionMode,
|
|
345
|
+
mcp_servers: mcpServers,
|
|
346
|
+
hooks,
|
|
347
|
+
sandbox,
|
|
348
|
+
enable_coordinator_mode: enableCoordinatorMode,
|
|
349
|
+
enable_fork: enableFork
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
function validateProviders(config) {
|
|
353
|
+
if (config.providers.length === 0) {
|
|
354
|
+
throw new ConfigError("At least one provider MUST be configured.");
|
|
355
|
+
}
|
|
356
|
+
const requiredFields = ["name", "protocol", "base_url", "model"];
|
|
357
|
+
const baseUrls = /* @__PURE__ */ new Map();
|
|
358
|
+
for (let i = 0; i < config.providers.length; i++) {
|
|
359
|
+
const p = config.providers[i];
|
|
360
|
+
const values = {
|
|
361
|
+
name: p.name,
|
|
362
|
+
protocol: p.protocol,
|
|
363
|
+
base_url: p.base_url,
|
|
364
|
+
model: p.model
|
|
365
|
+
};
|
|
366
|
+
const missing = requiredFields.filter((field) => !values[field].trim());
|
|
367
|
+
if (missing.length > 0) {
|
|
368
|
+
throw new ConfigError(
|
|
369
|
+
`Provider #${String(i + 1)}: missing fields: ${missing.join(", ")}`
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
if (!VALID_PROTOCOLS.has(p.protocol)) {
|
|
373
|
+
throw new ConfigError(
|
|
374
|
+
`Provider #${String(i + 1)}: invalid protocol '${p.protocol}', MUST be one of: ${Array.from(VALID_PROTOCOLS).join(", ")}`
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
const previous = baseUrls.get(p.base_url);
|
|
378
|
+
if (previous !== void 0) {
|
|
379
|
+
throw new ConfigError(
|
|
380
|
+
`Provider #${String(i + 1)}: duplicate base_url '${p.base_url}' (already used by provider #${String(previous + 1)}).`
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
baseUrls.set(p.base_url, i);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
function validateMcpServers(config) {
|
|
387
|
+
const names = /* @__PURE__ */ new Map();
|
|
388
|
+
for (let i = 0; i < config.mcp_servers.length; i++) {
|
|
389
|
+
const server = config.mcp_servers[i];
|
|
390
|
+
const position = `MCP server #${String(i + 1)}`;
|
|
391
|
+
if (!server.name.trim()) {
|
|
392
|
+
throw new ConfigError(`${position}: name must not be empty.`);
|
|
393
|
+
}
|
|
394
|
+
const previous = names.get(server.name);
|
|
395
|
+
if (previous !== void 0) {
|
|
396
|
+
throw new ConfigError(
|
|
397
|
+
`${position}: duplicate name '${server.name}' (already used by MCP server #${String(previous + 1)}).`
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
names.set(server.name, i);
|
|
401
|
+
const hasCommand = Boolean(server.command?.trim());
|
|
402
|
+
const hasUrl = Boolean(server.url?.trim());
|
|
403
|
+
if (hasCommand === hasUrl) {
|
|
404
|
+
throw new ConfigError(
|
|
405
|
+
`${position} '${server.name}': configure exactly one of command or url.`
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
if (hasCommand && server.transport && server.transport !== "stdio") {
|
|
409
|
+
throw new ConfigError(
|
|
410
|
+
`${position} '${server.name}': command servers must use stdio.`
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
if (hasUrl && server.transport && !["http", "sse"].includes(server.transport)) {
|
|
414
|
+
throw new ConfigError(
|
|
415
|
+
`${position} '${server.name}': URL transport must be http or sse.`
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
var PROJECT_MCP_FILENAME = ".mcp.json";
|
|
421
|
+
var McpJsonEntrySchema = z.looseObject({
|
|
422
|
+
command: z.string().optional(),
|
|
423
|
+
args: z.array(z.string()).optional(),
|
|
424
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
425
|
+
type: z.enum(["stdio", "sse", "http"]).optional(),
|
|
426
|
+
url: z.string().optional(),
|
|
427
|
+
headers: z.record(z.string(), z.string()).optional()
|
|
428
|
+
});
|
|
429
|
+
var McpJsonFileSchema = z.looseObject({
|
|
430
|
+
// Parse entries independently below so one bad server does not disable every
|
|
431
|
+
// valid server in the project file.
|
|
432
|
+
mcpServers: z.record(z.string(), z.unknown()).default({})
|
|
433
|
+
});
|
|
434
|
+
function mcpServerFromJsonEntry(name, entry) {
|
|
435
|
+
const transport = entry.type ?? (entry.command !== void 0 ? "stdio" : "http");
|
|
436
|
+
if (transport === "stdio") {
|
|
437
|
+
if (!entry.command || entry.url !== void 0) {
|
|
438
|
+
return null;
|
|
439
|
+
}
|
|
440
|
+
return { name, command: entry.command, args: entry.args, env: entry.env };
|
|
441
|
+
}
|
|
442
|
+
if (!entry.url || entry.command !== void 0) {
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
return { name, url: entry.url, transport, headers: entry.headers };
|
|
446
|
+
}
|
|
447
|
+
function loadProjectMcpServers(workDir) {
|
|
448
|
+
const path = join(workDir, PROJECT_MCP_FILENAME);
|
|
449
|
+
if (!existsSync(path)) {
|
|
450
|
+
return [];
|
|
451
|
+
}
|
|
452
|
+
let raw;
|
|
453
|
+
try {
|
|
454
|
+
raw = JSON.parse(readFileSync(path, "utf-8"));
|
|
455
|
+
} catch (err) {
|
|
456
|
+
log.error({ err, path }, "invalid .mcp.json");
|
|
457
|
+
return [];
|
|
458
|
+
}
|
|
459
|
+
const parsed = safeParse(McpJsonFileSchema, raw);
|
|
460
|
+
if (!parsed.success) {
|
|
461
|
+
log.error({ error: parsed.error, path }, "invalid .mcp.json");
|
|
462
|
+
return [];
|
|
463
|
+
}
|
|
464
|
+
const servers = [];
|
|
465
|
+
for (const [name, rawEntry] of Object.entries(parsed.data.mcpServers)) {
|
|
466
|
+
const parsedEntry = safeParse(McpJsonEntrySchema, rawEntry);
|
|
467
|
+
if (!name.trim() || !parsedEntry.success) {
|
|
468
|
+
log.warn(
|
|
469
|
+
{
|
|
470
|
+
name,
|
|
471
|
+
path,
|
|
472
|
+
error: parsedEntry.success ? void 0 : parsedEntry.error
|
|
473
|
+
},
|
|
474
|
+
"skipping invalid .mcp.json server entry"
|
|
475
|
+
);
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
478
|
+
const server = mcpServerFromJsonEntry(name, parsedEntry.data);
|
|
479
|
+
if (server) {
|
|
480
|
+
servers.push(server);
|
|
481
|
+
} else {
|
|
482
|
+
log.warn({ name, path }, "skipping invalid .mcp.json server entry");
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return servers;
|
|
486
|
+
}
|
|
487
|
+
function withProjectMcpServers(config, workDir) {
|
|
488
|
+
const projectServers = loadProjectMcpServers(workDir);
|
|
489
|
+
if (projectServers.length === 0) {
|
|
490
|
+
return config;
|
|
491
|
+
}
|
|
492
|
+
const known = new Set(config.mcp_servers.map((s) => s.name));
|
|
493
|
+
return {
|
|
494
|
+
...config,
|
|
495
|
+
mcp_servers: [
|
|
496
|
+
...config.mcp_servers,
|
|
497
|
+
...projectServers.filter((s) => !known.has(s.name))
|
|
498
|
+
]
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
function loadConfig(path, options = {}) {
|
|
502
|
+
if (path) {
|
|
503
|
+
const config2 = loadSingleFile(path);
|
|
504
|
+
validateMcpServers(config2);
|
|
505
|
+
if (!options.allowEmptyProviders || config2.providers.length > 0) {
|
|
506
|
+
validateProviders(config2);
|
|
507
|
+
}
|
|
508
|
+
return config2;
|
|
509
|
+
}
|
|
510
|
+
const candidate = globalConfigPath();
|
|
511
|
+
if (!existsSync(candidate)) {
|
|
512
|
+
if (options.allowEmptyProviders) {
|
|
513
|
+
return { providers: [], mcp_servers: [], hooks: [] };
|
|
514
|
+
}
|
|
515
|
+
throw new ConfigError(`No config file found, expected ${candidate}.`);
|
|
516
|
+
}
|
|
517
|
+
const config = loadSingleFile(candidate);
|
|
518
|
+
validateMcpServers(config);
|
|
519
|
+
if (!options.allowEmptyProviders || config.providers.length > 0) {
|
|
520
|
+
validateProviders(config);
|
|
521
|
+
}
|
|
522
|
+
return config;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// src/conversation/pairing.ts
|
|
526
|
+
var pairing_exports = {};
|
|
527
|
+
__export(pairing_exports, {
|
|
528
|
+
INTERRUPTED_TOOL_RESULT: () => INTERRUPTED_TOOL_RESULT,
|
|
529
|
+
REJECTED_TOOL_RESULT: () => REJECTED_TOOL_RESULT,
|
|
530
|
+
ensureToolPairing: () => ensureToolPairing
|
|
531
|
+
});
|
|
532
|
+
var INTERRUPTED_TOOL_RESULT = "Tool execution was interrupted. The tool may or may not have completed; verify before relying on its effects.";
|
|
533
|
+
var REJECTED_TOOL_RESULT = "The user rejected this tool use. Nothing was changed (for file edits, the new content was NOT written).";
|
|
534
|
+
function ensureToolPairing(messages) {
|
|
535
|
+
const out = [];
|
|
536
|
+
for (let i = 0; i < messages.length; i++) {
|
|
537
|
+
const m = messages[i];
|
|
538
|
+
if (m.role === "assistant" && m.toolUses?.length) {
|
|
539
|
+
out.push(m);
|
|
540
|
+
const pending = new Set(m.toolUses.map((tu) => tu.toolUseId));
|
|
541
|
+
const results = [];
|
|
542
|
+
const resultMessages = [];
|
|
543
|
+
while (i + 1 < messages.length) {
|
|
544
|
+
const next = messages[i + 1];
|
|
545
|
+
if (next.role !== "user" || !next.toolResults?.length || next.toolUses?.length) {
|
|
546
|
+
break;
|
|
547
|
+
}
|
|
548
|
+
i++;
|
|
549
|
+
resultMessages.push(next);
|
|
550
|
+
for (const tr of next.toolResults) {
|
|
551
|
+
if (pending.delete(tr.toolUseId)) {
|
|
552
|
+
results.push(tr);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
for (const toolUseId of pending) {
|
|
557
|
+
results.push({ toolUseId, content: INTERRUPTED_TOOL_RESULT, isError: true });
|
|
558
|
+
}
|
|
559
|
+
out.push({
|
|
560
|
+
...resultMessages[0] ?? { role: "user", content: "" },
|
|
561
|
+
toolResults: results
|
|
562
|
+
});
|
|
563
|
+
for (const remaining of resultMessages.slice(1)) {
|
|
564
|
+
if (remaining.content.length > 0 || remaining.thinkingBlocks?.length) {
|
|
565
|
+
out.push({ ...remaining, toolResults: [] });
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
if ((m.toolResults?.length ?? 0) > 0) {
|
|
571
|
+
if (m.content.length === 0 && !m.toolUses?.length && !m.thinkingBlocks?.length) {
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
574
|
+
out.push({ ...m, toolResults: [] });
|
|
575
|
+
} else {
|
|
576
|
+
out.push(m);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return out;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// src/llm/errors.ts
|
|
583
|
+
var errors_exports = {};
|
|
584
|
+
__export(errors_exports, {
|
|
585
|
+
AuthenticationError: () => AuthenticationError,
|
|
586
|
+
ContextTooLongError: () => ContextTooLongError,
|
|
587
|
+
LLMError: () => LLMError,
|
|
588
|
+
NetworkError: () => NetworkError,
|
|
589
|
+
RateLimitError: () => RateLimitError
|
|
590
|
+
});
|
|
591
|
+
var LLMError = class extends Error {
|
|
592
|
+
constructor(message) {
|
|
593
|
+
super(message);
|
|
594
|
+
this.name = "LLMError";
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
var AuthenticationError = class extends LLMError {
|
|
598
|
+
constructor(message) {
|
|
599
|
+
super(message);
|
|
600
|
+
this.name = "AuthenticationError";
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
var RateLimitError = class extends LLMError {
|
|
604
|
+
retryAfter;
|
|
605
|
+
constructor(message, retryAfter) {
|
|
606
|
+
super(message);
|
|
607
|
+
this.name = "RateLimitError";
|
|
608
|
+
this.retryAfter = retryAfter;
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
var NetworkError = class extends LLMError {
|
|
612
|
+
constructor(message) {
|
|
613
|
+
super(message);
|
|
614
|
+
this.name = "NetworkError";
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
var ContextTooLongError = class extends LLMError {
|
|
618
|
+
constructor(message) {
|
|
619
|
+
super(message);
|
|
620
|
+
this.name = "ContextTooLongError";
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
export {
|
|
625
|
+
globalConfigPath,
|
|
626
|
+
THINKING_LEVELS,
|
|
627
|
+
ProviderConfigSchema,
|
|
628
|
+
DEFAULT_THINKING_LEVEL,
|
|
629
|
+
DEFAULT_CONTEXT_WINDOW,
|
|
630
|
+
DEFAULT_MAX_OUTPUT_TOKENS,
|
|
631
|
+
MIN_THINKING_ANSWER_TOKENS,
|
|
632
|
+
isValidThinkingLevel,
|
|
633
|
+
getThinkingLevel,
|
|
634
|
+
thinkingBudgetForLevel,
|
|
635
|
+
toReasoningEffort,
|
|
636
|
+
toAnthropicThinkingEffort,
|
|
637
|
+
getSupportedThinkingLevels,
|
|
638
|
+
clampThinkingLevel,
|
|
639
|
+
getContextWindow,
|
|
640
|
+
getMaxOutputTokens,
|
|
641
|
+
resolveAPIKey,
|
|
642
|
+
forkEnabled,
|
|
643
|
+
withProjectMcpServers,
|
|
644
|
+
loadConfig,
|
|
645
|
+
config_exports,
|
|
646
|
+
REJECTED_TOOL_RESULT,
|
|
647
|
+
ensureToolPairing,
|
|
648
|
+
pairing_exports,
|
|
649
|
+
LLMError,
|
|
650
|
+
AuthenticationError,
|
|
651
|
+
RateLimitError,
|
|
652
|
+
NetworkError,
|
|
653
|
+
ContextTooLongError,
|
|
654
|
+
errors_exports
|
|
655
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__export
|
|
3
|
+
} from "./chunk-MLKGABMK.js";
|
|
4
|
+
|
|
5
|
+
// src/sandbox/bwrap.ts
|
|
6
|
+
var bwrap_exports = {};
|
|
7
|
+
__export(bwrap_exports, {
|
|
8
|
+
BwrapSandbox: () => BwrapSandbox
|
|
9
|
+
});
|
|
10
|
+
import { execFileSync } from "child_process";
|
|
11
|
+
var BwrapSandbox = class {
|
|
12
|
+
implementation = "bwrap";
|
|
13
|
+
detected;
|
|
14
|
+
available() {
|
|
15
|
+
if (this.detected !== void 0) {
|
|
16
|
+
return this.detected;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
execFileSync("which", ["bwrap"], { stdio: "ignore" });
|
|
20
|
+
this.detected = true;
|
|
21
|
+
} catch {
|
|
22
|
+
this.detected = false;
|
|
23
|
+
}
|
|
24
|
+
return this.detected;
|
|
25
|
+
}
|
|
26
|
+
prepare(command, config) {
|
|
27
|
+
const args = ["--unshare-user", "--unshare-pid"];
|
|
28
|
+
args.push("--ro-bind", "/", "/");
|
|
29
|
+
for (const path of config.allowWrite) {
|
|
30
|
+
args.push("--bind", path, path);
|
|
31
|
+
}
|
|
32
|
+
for (const path of config.denyWrite) {
|
|
33
|
+
args.push("--ro-bind", path, path);
|
|
34
|
+
}
|
|
35
|
+
if (!config.networkEnabled) {
|
|
36
|
+
args.push("--unshare-net");
|
|
37
|
+
}
|
|
38
|
+
args.push("--proc", "/proc");
|
|
39
|
+
args.push("--", "bash", "-c", command);
|
|
40
|
+
return { executable: "bwrap", args };
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export {
|
|
45
|
+
BwrapSandbox,
|
|
46
|
+
bwrap_exports
|
|
47
|
+
};
|