@codelia/runtime 0.1.13 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +847 -91
- package/dist/index.js +837 -77
- package/package.json +9 -9
package/dist/index.cjs
CHANGED
|
@@ -23,12 +23,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
));
|
|
24
24
|
|
|
25
25
|
// src/runtime.ts
|
|
26
|
-
var
|
|
27
|
-
var
|
|
26
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
27
|
+
var import_storage10 = require("@codelia/storage");
|
|
28
28
|
|
|
29
29
|
// src/agent-factory.ts
|
|
30
30
|
var import_node_fs14 = require("fs");
|
|
31
|
-
var
|
|
31
|
+
var import_core18 = require("@codelia/core");
|
|
32
32
|
var import_storage5 = require("@codelia/storage");
|
|
33
33
|
|
|
34
34
|
// src/agents/context.ts
|
|
@@ -688,6 +688,10 @@ var DEFAULT_SKILLS_INITIAL_MAX_ENTRIES = 200;
|
|
|
688
688
|
var DEFAULT_SKILLS_INITIAL_MAX_BYTES = 32 * 1024;
|
|
689
689
|
var DEFAULT_SKILLS_SEARCH_DEFAULT_LIMIT = 8;
|
|
690
690
|
var DEFAULT_SKILLS_SEARCH_MAX_LIMIT = 50;
|
|
691
|
+
var DEFAULT_SEARCH_MODE = "auto";
|
|
692
|
+
var DEFAULT_SEARCH_NATIVE_PROVIDERS = ["openai", "anthropic"];
|
|
693
|
+
var DEFAULT_SEARCH_LOCAL_BACKEND = "ddg";
|
|
694
|
+
var DEFAULT_SEARCH_BRAVE_API_KEY_ENV = "BRAVE_SEARCH_API_KEY";
|
|
691
695
|
var readEnvValue = (key) => {
|
|
692
696
|
const value = process.env[key];
|
|
693
697
|
if (!value) return void 0;
|
|
@@ -778,6 +782,45 @@ var resolveSkillsConfig = async (workingDir) => {
|
|
|
778
782
|
const effective = import_config.configRegistry.resolve([globalConfig, projectConfig]);
|
|
779
783
|
return normalizeSkillsConfig(effective.skills);
|
|
780
784
|
};
|
|
785
|
+
var normalizeSearchConfig = (value) => {
|
|
786
|
+
const mode = value?.mode === "auto" || value?.mode === "native" || value?.mode === "local" ? value.mode : DEFAULT_SEARCH_MODE;
|
|
787
|
+
const providersRaw = value?.native?.providers ?? [
|
|
788
|
+
...DEFAULT_SEARCH_NATIVE_PROVIDERS
|
|
789
|
+
];
|
|
790
|
+
const providers = Array.from(
|
|
791
|
+
new Set(
|
|
792
|
+
providersRaw.map((entry) => entry.trim()).filter((entry) => entry.length > 0)
|
|
793
|
+
)
|
|
794
|
+
);
|
|
795
|
+
const searchContextSize = value?.native?.search_context_size;
|
|
796
|
+
const allowedDomains = value?.native?.allowed_domains?.length ? value.native.allowed_domains.map((entry) => entry.trim()).filter((entry) => entry.length > 0) : void 0;
|
|
797
|
+
const userLocation = value?.native?.user_location ? {
|
|
798
|
+
...value.native.user_location.city ? { city: value.native.user_location.city } : {},
|
|
799
|
+
...value.native.user_location.country ? { country: value.native.user_location.country } : {},
|
|
800
|
+
...value.native.user_location.region ? { region: value.native.user_location.region } : {},
|
|
801
|
+
...value.native.user_location.timezone ? { timezone: value.native.user_location.timezone } : {}
|
|
802
|
+
} : void 0;
|
|
803
|
+
const backend = value?.local?.backend === "ddg" || value?.local?.backend === "brave" ? value.local.backend : DEFAULT_SEARCH_LOCAL_BACKEND;
|
|
804
|
+
const braveApiKeyEnv = value?.local?.brave_api_key_env?.trim() || DEFAULT_SEARCH_BRAVE_API_KEY_ENV;
|
|
805
|
+
return {
|
|
806
|
+
mode,
|
|
807
|
+
native: {
|
|
808
|
+
providers: providers.length ? providers : [...DEFAULT_SEARCH_NATIVE_PROVIDERS],
|
|
809
|
+
...searchContextSize ? { searchContextSize } : {},
|
|
810
|
+
...allowedDomains && allowedDomains.length ? { allowedDomains } : {},
|
|
811
|
+
...userLocation && Object.keys(userLocation).length ? { userLocation } : {}
|
|
812
|
+
},
|
|
813
|
+
local: {
|
|
814
|
+
backend,
|
|
815
|
+
braveApiKeyEnv
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
};
|
|
819
|
+
var resolveSearchConfig = async (workingDir) => {
|
|
820
|
+
const { globalConfig, projectConfig } = await loadConfigLayers(workingDir);
|
|
821
|
+
const effective = import_config.configRegistry.resolve([globalConfig, projectConfig]);
|
|
822
|
+
return normalizeSearchConfig(effective.search);
|
|
823
|
+
};
|
|
781
824
|
var normalizeMcpTimeoutMs = (value) => {
|
|
782
825
|
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
783
826
|
return DEFAULT_MCP_REQUEST_TIMEOUT_MS;
|
|
@@ -813,6 +856,44 @@ var appendPermissionAllowRules = async (workingDir, rules) => {
|
|
|
813
856
|
const configPath = resolveProjectConfigPath(workingDir);
|
|
814
857
|
await (0, import_config_loader.appendPermissionAllowRules)(configPath, rules);
|
|
815
858
|
};
|
|
859
|
+
var hasDefinedGroup = (group, value) => {
|
|
860
|
+
switch (group) {
|
|
861
|
+
case "model":
|
|
862
|
+
return typeof value?.model?.name === "string" && value.model.name.trim().length > 0;
|
|
863
|
+
case "permissions":
|
|
864
|
+
return Array.isArray(value?.permissions?.allow) || Array.isArray(value?.permissions?.deny);
|
|
865
|
+
case "tui":
|
|
866
|
+
return typeof value?.tui?.theme === "string" && value.tui.theme.trim().length > 0;
|
|
867
|
+
default:
|
|
868
|
+
return false;
|
|
869
|
+
}
|
|
870
|
+
};
|
|
871
|
+
var resolveWriteTarget = async (workingDir, group) => {
|
|
872
|
+
const globalPath = resolveConfigPath();
|
|
873
|
+
const projectPath = resolveProjectConfigPath(workingDir);
|
|
874
|
+
const [globalConfig, projectConfig] = await Promise.all([
|
|
875
|
+
(0, import_config_loader.loadConfig)(globalPath),
|
|
876
|
+
(0, import_config_loader.loadConfig)(projectPath)
|
|
877
|
+
]);
|
|
878
|
+
if (hasDefinedGroup(group, projectConfig)) {
|
|
879
|
+
return { scope: "project", path: projectPath };
|
|
880
|
+
}
|
|
881
|
+
if (hasDefinedGroup(group, globalConfig)) {
|
|
882
|
+
return { scope: "global", path: globalPath };
|
|
883
|
+
}
|
|
884
|
+
const defaultScope = import_config.CONFIG_GROUP_DEFAULT_WRITE_SCOPE[group];
|
|
885
|
+
return defaultScope === "project" ? { scope: "project", path: projectPath } : { scope: "global", path: globalPath };
|
|
886
|
+
};
|
|
887
|
+
var updateModel = async (workingDir, model) => {
|
|
888
|
+
const target = await resolveWriteTarget(workingDir, "model");
|
|
889
|
+
await (0, import_config_loader.updateModelConfig)(target.path, model);
|
|
890
|
+
return target;
|
|
891
|
+
};
|
|
892
|
+
var updateTuiTheme = async (workingDir, theme) => {
|
|
893
|
+
const target = await resolveWriteTarget(workingDir, "tui");
|
|
894
|
+
await (0, import_config_loader.updateTuiConfig)(target.path, { theme });
|
|
895
|
+
return target;
|
|
896
|
+
};
|
|
816
897
|
var resolveReasoningEffort = (value) => {
|
|
817
898
|
return resolveModelLevelOption(value, "model.reasoning");
|
|
818
899
|
};
|
|
@@ -961,6 +1042,14 @@ var sendRunContext = (runId, contextLeftPercent) => {
|
|
|
961
1042
|
};
|
|
962
1043
|
send(notify);
|
|
963
1044
|
};
|
|
1045
|
+
var sendRunDiagnostics = (params) => {
|
|
1046
|
+
const notify = {
|
|
1047
|
+
jsonrpc: "2.0",
|
|
1048
|
+
method: "run.diagnostics",
|
|
1049
|
+
params
|
|
1050
|
+
};
|
|
1051
|
+
send(notify);
|
|
1052
|
+
};
|
|
964
1053
|
|
|
965
1054
|
// src/rpc/ui-requests.ts
|
|
966
1055
|
var requestUi = async (state, method, params) => {
|
|
@@ -4206,17 +4295,176 @@ ${reason} Use offset to read beyond line ${lastReadLine}.`;
|
|
|
4206
4295
|
}
|
|
4207
4296
|
});
|
|
4208
4297
|
|
|
4209
|
-
// src/tools/
|
|
4298
|
+
// src/tools/search.ts
|
|
4210
4299
|
var import_core11 = require("@codelia/core");
|
|
4211
4300
|
var import_zod10 = require("zod");
|
|
4212
|
-
var
|
|
4213
|
-
|
|
4214
|
-
|
|
4301
|
+
var normalizeDomain = (value) => value.trim().toLowerCase().replace(/\.+$/, "");
|
|
4302
|
+
var shouldKeepUrl = (url, allowedDomains) => {
|
|
4303
|
+
if (!allowedDomains.length) return true;
|
|
4304
|
+
try {
|
|
4305
|
+
const parsed = new URL(url);
|
|
4306
|
+
const host = parsed.hostname.toLowerCase();
|
|
4307
|
+
return allowedDomains.some((domain) => {
|
|
4308
|
+
const normalized = normalizeDomain(domain);
|
|
4309
|
+
return host === normalized || host.endsWith(`.${normalized}`);
|
|
4310
|
+
});
|
|
4311
|
+
} catch {
|
|
4312
|
+
return false;
|
|
4313
|
+
}
|
|
4314
|
+
};
|
|
4315
|
+
var normalizeEntries = (entries, allowedDomains, maxResults) => {
|
|
4316
|
+
return entries.filter((entry) => shouldKeepUrl(entry.url, allowedDomains)).slice(0, maxResults);
|
|
4317
|
+
};
|
|
4318
|
+
var parseDdg = (payload) => {
|
|
4319
|
+
const results = [];
|
|
4320
|
+
if (!payload || typeof payload !== "object") {
|
|
4321
|
+
return results;
|
|
4322
|
+
}
|
|
4323
|
+
const record = payload;
|
|
4324
|
+
const related = Array.isArray(record.RelatedTopics) ? record.RelatedTopics : [];
|
|
4325
|
+
for (const topic of related) {
|
|
4326
|
+
if (!topic || typeof topic !== "object") {
|
|
4327
|
+
continue;
|
|
4328
|
+
}
|
|
4329
|
+
const typed = topic;
|
|
4330
|
+
if (Array.isArray(typed.Topics)) {
|
|
4331
|
+
for (const child of typed.Topics) {
|
|
4332
|
+
if (!child || typeof child !== "object") continue;
|
|
4333
|
+
const row = child;
|
|
4334
|
+
const text2 = typeof row.Text === "string" ? row.Text : "";
|
|
4335
|
+
const url2 = typeof row.FirstURL === "string" ? row.FirstURL : "";
|
|
4336
|
+
if (!text2 || !url2) continue;
|
|
4337
|
+
results.push({
|
|
4338
|
+
title: text2.split(" - ")[0] ?? text2,
|
|
4339
|
+
url: url2,
|
|
4340
|
+
snippet: text2,
|
|
4341
|
+
source: "ddg"
|
|
4342
|
+
});
|
|
4343
|
+
}
|
|
4344
|
+
continue;
|
|
4345
|
+
}
|
|
4346
|
+
const text = typeof typed.Text === "string" ? typed.Text : "";
|
|
4347
|
+
const url = typeof typed.FirstURL === "string" ? typed.FirstURL : "";
|
|
4348
|
+
if (!text || !url) continue;
|
|
4349
|
+
results.push({
|
|
4350
|
+
title: text.split(" - ")[0] ?? text,
|
|
4351
|
+
url,
|
|
4352
|
+
snippet: text,
|
|
4353
|
+
source: "ddg"
|
|
4354
|
+
});
|
|
4355
|
+
}
|
|
4356
|
+
return results;
|
|
4357
|
+
};
|
|
4358
|
+
var parseBrave = (payload) => {
|
|
4359
|
+
const results = [];
|
|
4360
|
+
if (!payload || typeof payload !== "object") {
|
|
4361
|
+
return results;
|
|
4362
|
+
}
|
|
4363
|
+
const record = payload;
|
|
4364
|
+
const web = record.web;
|
|
4365
|
+
if (!web || typeof web !== "object") {
|
|
4366
|
+
return results;
|
|
4367
|
+
}
|
|
4368
|
+
const rows = Array.isArray(web.results) ? web.results : [];
|
|
4369
|
+
for (const row of rows) {
|
|
4370
|
+
if (!row || typeof row !== "object") continue;
|
|
4371
|
+
const typed = row;
|
|
4372
|
+
const title = typeof typed.title === "string" ? typed.title : "";
|
|
4373
|
+
const url = typeof typed.url === "string" ? typed.url : "";
|
|
4374
|
+
const snippet = typeof typed.description === "string" ? typed.description : "";
|
|
4375
|
+
if (!title || !url) continue;
|
|
4376
|
+
results.push({
|
|
4377
|
+
title,
|
|
4378
|
+
url,
|
|
4379
|
+
snippet,
|
|
4380
|
+
source: "brave"
|
|
4381
|
+
});
|
|
4382
|
+
}
|
|
4383
|
+
return results;
|
|
4384
|
+
};
|
|
4385
|
+
var runDdgSearch = async (query, maxResults, allowedDomains) => {
|
|
4386
|
+
const url = new URL("https://api.duckduckgo.com/");
|
|
4387
|
+
url.searchParams.set("q", query);
|
|
4388
|
+
url.searchParams.set("format", "json");
|
|
4389
|
+
url.searchParams.set("no_html", "1");
|
|
4390
|
+
url.searchParams.set("skip_disambig", "1");
|
|
4391
|
+
const response = await fetch(url);
|
|
4392
|
+
if (!response.ok) {
|
|
4393
|
+
throw new Error(`ddg request failed: status=${response.status}`);
|
|
4394
|
+
}
|
|
4395
|
+
const payload = await response.json();
|
|
4396
|
+
const parsed = parseDdg(payload);
|
|
4397
|
+
return normalizeEntries(parsed, allowedDomains, maxResults);
|
|
4398
|
+
};
|
|
4399
|
+
var runBraveSearch = async (query, maxResults, allowedDomains, apiKey) => {
|
|
4400
|
+
const url = new URL("https://api.search.brave.com/res/v1/web/search");
|
|
4401
|
+
url.searchParams.set("q", query);
|
|
4402
|
+
url.searchParams.set("count", String(maxResults));
|
|
4403
|
+
const response = await fetch(url, {
|
|
4404
|
+
headers: {
|
|
4405
|
+
Accept: "application/json",
|
|
4406
|
+
"X-Subscription-Token": apiKey
|
|
4407
|
+
}
|
|
4408
|
+
});
|
|
4409
|
+
if (!response.ok) {
|
|
4410
|
+
throw new Error(`brave request failed: status=${response.status}`);
|
|
4411
|
+
}
|
|
4412
|
+
const payload = await response.json();
|
|
4413
|
+
const parsed = parseBrave(payload);
|
|
4414
|
+
return normalizeEntries(parsed, allowedDomains, maxResults);
|
|
4415
|
+
};
|
|
4416
|
+
var createSearchTool = (options) => (0, import_core11.defineTool)({
|
|
4417
|
+
name: "search",
|
|
4418
|
+
description: "Search the web and return concise source candidates.",
|
|
4419
|
+
input: import_zod10.z.object({
|
|
4420
|
+
query: import_zod10.z.string().min(1).describe("Search query."),
|
|
4421
|
+
max_results: import_zod10.z.number().int().min(1).max(20).optional().describe("Max results. Default 5."),
|
|
4422
|
+
backend: import_zod10.z.enum(["ddg", "brave"]).optional().describe("Search backend. Default comes from config."),
|
|
4423
|
+
allowed_domains: import_zod10.z.array(import_zod10.z.string().min(1)).optional().describe("Optional allowlist of domains.")
|
|
4424
|
+
}),
|
|
4425
|
+
execute: async (input) => {
|
|
4426
|
+
const backend = input.backend ?? options.defaultBackend;
|
|
4427
|
+
const maxResults = input.max_results ?? 5;
|
|
4428
|
+
const allowedDomains = input.allowed_domains?.map((entry) => entry.trim()).filter((entry) => entry.length > 0) ?? [];
|
|
4429
|
+
try {
|
|
4430
|
+
let results;
|
|
4431
|
+
if (backend === "ddg") {
|
|
4432
|
+
results = await runDdgSearch(input.query, maxResults, allowedDomains);
|
|
4433
|
+
} else {
|
|
4434
|
+
const apiKey = process.env[options.braveApiKeyEnv]?.trim();
|
|
4435
|
+
if (!apiKey) {
|
|
4436
|
+
return `Missing ${options.braveApiKeyEnv} for brave backend.`;
|
|
4437
|
+
}
|
|
4438
|
+
results = await runBraveSearch(
|
|
4439
|
+
input.query,
|
|
4440
|
+
maxResults,
|
|
4441
|
+
allowedDomains,
|
|
4442
|
+
apiKey
|
|
4443
|
+
);
|
|
4444
|
+
}
|
|
4445
|
+
return {
|
|
4446
|
+
query: input.query,
|
|
4447
|
+
backend,
|
|
4448
|
+
count: results.length,
|
|
4449
|
+
results
|
|
4450
|
+
};
|
|
4451
|
+
} catch (error) {
|
|
4452
|
+
return `Error running search: ${String(error)}`;
|
|
4453
|
+
}
|
|
4454
|
+
}
|
|
4455
|
+
});
|
|
4456
|
+
|
|
4457
|
+
// src/tools/skill-load.ts
|
|
4458
|
+
var import_core12 = require("@codelia/core");
|
|
4459
|
+
var import_zod11 = require("zod");
|
|
4460
|
+
var SkillLoadInputSchema = import_zod11.z.object({
|
|
4461
|
+
name: import_zod11.z.string().min(1).optional().describe("Exact skill name to load."),
|
|
4462
|
+
path: import_zod11.z.string().min(1).optional().describe("Absolute or workspace-relative path to SKILL.md.")
|
|
4215
4463
|
}).refine((value) => !!value.name || !!value.path, {
|
|
4216
4464
|
message: "name or path is required",
|
|
4217
4465
|
path: ["name"]
|
|
4218
4466
|
});
|
|
4219
|
-
var createSkillLoadTool = (skillsResolverKey) => (0,
|
|
4467
|
+
var createSkillLoadTool = (skillsResolverKey) => (0, import_core12.defineTool)({
|
|
4220
4468
|
name: "skill_load",
|
|
4221
4469
|
description: "Load full SKILL.md content by exact name or path.",
|
|
4222
4470
|
input: SkillLoadInputSchema,
|
|
@@ -4262,15 +4510,15 @@ var createSkillLoadTool = (skillsResolverKey) => (0, import_core11.defineTool)({
|
|
|
4262
4510
|
});
|
|
4263
4511
|
|
|
4264
4512
|
// src/tools/skill-search.ts
|
|
4265
|
-
var
|
|
4266
|
-
var
|
|
4267
|
-
var createSkillSearchTool = (skillsResolverKey) => (0,
|
|
4513
|
+
var import_core13 = require("@codelia/core");
|
|
4514
|
+
var import_zod12 = require("zod");
|
|
4515
|
+
var createSkillSearchTool = (skillsResolverKey) => (0, import_core13.defineTool)({
|
|
4268
4516
|
name: "skill_search",
|
|
4269
4517
|
description: "Search installed local skills by name, description, or path.",
|
|
4270
|
-
input:
|
|
4271
|
-
query:
|
|
4272
|
-
limit:
|
|
4273
|
-
scope:
|
|
4518
|
+
input: import_zod12.z.object({
|
|
4519
|
+
query: import_zod12.z.string().min(1).describe("Search query text."),
|
|
4520
|
+
limit: import_zod12.z.number().int().positive().optional().describe("Optional max result count (clamped by config)."),
|
|
4521
|
+
scope: import_zod12.z.enum(["repo", "user"]).optional().describe("Optional scope filter.")
|
|
4274
4522
|
}),
|
|
4275
4523
|
execute: async (input, ctx) => {
|
|
4276
4524
|
try {
|
|
@@ -4293,17 +4541,17 @@ var createSkillSearchTool = (skillsResolverKey) => (0, import_core12.defineTool)
|
|
|
4293
4541
|
});
|
|
4294
4542
|
|
|
4295
4543
|
// src/tools/todo-read.ts
|
|
4296
|
-
var
|
|
4297
|
-
var
|
|
4544
|
+
var import_core14 = require("@codelia/core");
|
|
4545
|
+
var import_zod13 = require("zod");
|
|
4298
4546
|
|
|
4299
4547
|
// src/tools/todo-store.ts
|
|
4300
4548
|
var todoStore = /* @__PURE__ */ new Map();
|
|
4301
4549
|
|
|
4302
4550
|
// src/tools/todo-read.ts
|
|
4303
|
-
var createTodoReadTool = (sandboxKey) => (0,
|
|
4551
|
+
var createTodoReadTool = (sandboxKey) => (0, import_core14.defineTool)({
|
|
4304
4552
|
name: "todo_read",
|
|
4305
4553
|
description: "Read the in-session todo list.",
|
|
4306
|
-
input:
|
|
4554
|
+
input: import_zod13.z.object({}),
|
|
4307
4555
|
execute: async (_input, ctx) => {
|
|
4308
4556
|
const sandbox = await getSandboxContext(ctx, sandboxKey);
|
|
4309
4557
|
const todos = todoStore.get(sandbox.sessionId) ?? [];
|
|
@@ -4316,17 +4564,17 @@ var createTodoReadTool = (sandboxKey) => (0, import_core13.defineTool)({
|
|
|
4316
4564
|
});
|
|
4317
4565
|
|
|
4318
4566
|
// src/tools/todo-write.ts
|
|
4319
|
-
var
|
|
4320
|
-
var
|
|
4321
|
-
var createTodoWriteTool = (sandboxKey) => (0,
|
|
4567
|
+
var import_core15 = require("@codelia/core");
|
|
4568
|
+
var import_zod14 = require("zod");
|
|
4569
|
+
var createTodoWriteTool = (sandboxKey) => (0, import_core15.defineTool)({
|
|
4322
4570
|
name: "todo_write",
|
|
4323
4571
|
description: "Replace the in-session todo list.",
|
|
4324
|
-
input:
|
|
4325
|
-
todos:
|
|
4326
|
-
|
|
4327
|
-
content:
|
|
4328
|
-
status:
|
|
4329
|
-
activeForm:
|
|
4572
|
+
input: import_zod14.z.object({
|
|
4573
|
+
todos: import_zod14.z.array(
|
|
4574
|
+
import_zod14.z.object({
|
|
4575
|
+
content: import_zod14.z.string().describe("Todo item text."),
|
|
4576
|
+
status: import_zod14.z.enum(["pending", "in_progress", "completed"]).describe("Todo status."),
|
|
4577
|
+
activeForm: import_zod14.z.string().optional().describe("Optional in-progress phrasing for UI display.")
|
|
4330
4578
|
})
|
|
4331
4579
|
)
|
|
4332
4580
|
}),
|
|
@@ -4343,15 +4591,15 @@ var createTodoWriteTool = (sandboxKey) => (0, import_core14.defineTool)({
|
|
|
4343
4591
|
});
|
|
4344
4592
|
|
|
4345
4593
|
// src/tools/tool-output-cache.ts
|
|
4346
|
-
var
|
|
4347
|
-
var
|
|
4348
|
-
var createToolOutputCacheTool = (store) => (0,
|
|
4594
|
+
var import_core16 = require("@codelia/core");
|
|
4595
|
+
var import_zod15 = require("zod");
|
|
4596
|
+
var createToolOutputCacheTool = (store) => (0, import_core16.defineTool)({
|
|
4349
4597
|
name: "tool_output_cache",
|
|
4350
4598
|
description: "Read cached tool output by ref_id.",
|
|
4351
|
-
input:
|
|
4352
|
-
ref_id:
|
|
4353
|
-
offset:
|
|
4354
|
-
limit:
|
|
4599
|
+
input: import_zod15.z.object({
|
|
4600
|
+
ref_id: import_zod15.z.string().describe("Tool output reference ID."),
|
|
4601
|
+
offset: import_zod15.z.number().int().nonnegative().optional().describe("Optional 0-based line offset."),
|
|
4602
|
+
limit: import_zod15.z.number().int().positive().optional().describe("Optional max number of lines to return.")
|
|
4355
4603
|
}),
|
|
4356
4604
|
execute: async (input) => {
|
|
4357
4605
|
if (!store.read) {
|
|
@@ -4367,16 +4615,16 @@ var createToolOutputCacheTool = (store) => (0, import_core15.defineTool)({
|
|
|
4367
4615
|
}
|
|
4368
4616
|
}
|
|
4369
4617
|
});
|
|
4370
|
-
var createToolOutputCacheGrepTool = (store) => (0,
|
|
4618
|
+
var createToolOutputCacheGrepTool = (store) => (0, import_core16.defineTool)({
|
|
4371
4619
|
name: "tool_output_cache_grep",
|
|
4372
4620
|
description: "Search cached tool output by ref_id.",
|
|
4373
|
-
input:
|
|
4374
|
-
ref_id:
|
|
4375
|
-
pattern:
|
|
4376
|
-
regex:
|
|
4377
|
-
before:
|
|
4378
|
-
after:
|
|
4379
|
-
max_matches:
|
|
4621
|
+
input: import_zod15.z.object({
|
|
4622
|
+
ref_id: import_zod15.z.string().describe("Tool output reference ID."),
|
|
4623
|
+
pattern: import_zod15.z.string().describe("Text or regex pattern to search for."),
|
|
4624
|
+
regex: import_zod15.z.boolean().optional().describe("Interpret pattern as regex when true. Default false."),
|
|
4625
|
+
before: import_zod15.z.number().int().nonnegative().optional().describe("Context lines before each match. Default 0."),
|
|
4626
|
+
after: import_zod15.z.number().int().nonnegative().optional().describe("Context lines after each match. Default 0."),
|
|
4627
|
+
max_matches: import_zod15.z.number().int().positive().optional().describe("Maximum number of matches to return.")
|
|
4380
4628
|
}),
|
|
4381
4629
|
execute: async (input) => {
|
|
4382
4630
|
if (!store.grep) {
|
|
@@ -4399,14 +4647,14 @@ var createToolOutputCacheGrepTool = (store) => (0, import_core15.defineTool)({
|
|
|
4399
4647
|
// src/tools/write.ts
|
|
4400
4648
|
var import_node_fs13 = require("fs");
|
|
4401
4649
|
var import_node_path12 = __toESM(require("path"), 1);
|
|
4402
|
-
var
|
|
4403
|
-
var
|
|
4404
|
-
var createWriteTool = (sandboxKey) => (0,
|
|
4650
|
+
var import_core17 = require("@codelia/core");
|
|
4651
|
+
var import_zod16 = require("zod");
|
|
4652
|
+
var createWriteTool = (sandboxKey) => (0, import_core17.defineTool)({
|
|
4405
4653
|
name: "write",
|
|
4406
4654
|
description: "Write text to a file, creating parent directories if needed.",
|
|
4407
|
-
input:
|
|
4408
|
-
file_path:
|
|
4409
|
-
content:
|
|
4655
|
+
input: import_zod16.z.object({
|
|
4656
|
+
file_path: import_zod16.z.string().describe("File path under the sandbox root."),
|
|
4657
|
+
content: import_zod16.z.string().describe("UTF-8 text content to write.")
|
|
4410
4658
|
}),
|
|
4411
4659
|
execute: async (input, ctx) => {
|
|
4412
4660
|
let resolved;
|
|
@@ -4435,6 +4683,7 @@ var createTools = (sandboxKey, agentsResolverKey, skillsResolverKey, options = {
|
|
|
4435
4683
|
createAgentsResolveTool(sandboxKey, agentsResolverKey),
|
|
4436
4684
|
createSkillSearchTool(skillsResolverKey),
|
|
4437
4685
|
createSkillLoadTool(skillsResolverKey),
|
|
4686
|
+
...options.search ? [createSearchTool(options.search)] : [],
|
|
4438
4687
|
createGlobSearchTool(sandboxKey),
|
|
4439
4688
|
createGrepTool(sandboxKey),
|
|
4440
4689
|
...options.toolOutputCacheStore ? [
|
|
@@ -4483,9 +4732,9 @@ var normalizeLanguage = (value) => {
|
|
|
4483
4732
|
};
|
|
4484
4733
|
var languageFromFilePath = (filePath) => {
|
|
4485
4734
|
if (!filePath) return void 0;
|
|
4486
|
-
const
|
|
4487
|
-
if (!
|
|
4488
|
-
const normalizedPath =
|
|
4735
|
+
const path17 = filePath.trim().replace(/^["']|["']$/g, "");
|
|
4736
|
+
if (!path17 || path17 === "/dev/null") return void 0;
|
|
4737
|
+
const normalizedPath = path17.replace(/^a\//, "").replace(/^b\//, "");
|
|
4489
4738
|
const lastSlash = Math.max(
|
|
4490
4739
|
normalizedPath.lastIndexOf("/"),
|
|
4491
4740
|
normalizedPath.lastIndexOf("\\")
|
|
@@ -4556,6 +4805,25 @@ var envTruthy = (value) => {
|
|
|
4556
4805
|
return normalized === "1" || normalized === "true";
|
|
4557
4806
|
};
|
|
4558
4807
|
var OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
|
|
4808
|
+
var isNativeSearchProvider = (provider, allowedProviders) => allowedProviders.includes(provider);
|
|
4809
|
+
var buildHostedSearchToolDefinitions = (provider, options) => {
|
|
4810
|
+
if (options.mode === "local" || !isNativeSearchProvider(provider, options.native.providers)) {
|
|
4811
|
+
return [];
|
|
4812
|
+
}
|
|
4813
|
+
if (provider !== "openai" && provider !== "anthropic") {
|
|
4814
|
+
return [];
|
|
4815
|
+
}
|
|
4816
|
+
return [
|
|
4817
|
+
{
|
|
4818
|
+
type: "hosted_search",
|
|
4819
|
+
name: "web_search",
|
|
4820
|
+
provider,
|
|
4821
|
+
...options.native.searchContextSize ? { search_context_size: options.native.searchContextSize } : {},
|
|
4822
|
+
...options.native.allowedDomains ? { allowed_domains: options.native.allowedDomains } : {},
|
|
4823
|
+
...options.native.userLocation ? { user_location: options.native.userLocation } : {}
|
|
4824
|
+
}
|
|
4825
|
+
];
|
|
4826
|
+
};
|
|
4559
4827
|
var buildOpenAiClientOptions = (authResolver, auth) => {
|
|
4560
4828
|
if (auth.method === "api_key") {
|
|
4561
4829
|
return { apiKey: auth.api_key };
|
|
@@ -4792,7 +5060,7 @@ var createAgentFactory = (state, options = {}) => {
|
|
|
4792
5060
|
const agentsResolverKey = createAgentsResolverKey(agentsResolver);
|
|
4793
5061
|
const skillsResolverKey = createSkillsResolverKey(skillsResolver);
|
|
4794
5062
|
const toolOutputCacheStore = new import_storage5.ToolOutputCacheStoreImpl();
|
|
4795
|
-
const
|
|
5063
|
+
const baseLocalTools = createTools(
|
|
4796
5064
|
sandboxKey,
|
|
4797
5065
|
agentsResolverKey,
|
|
4798
5066
|
skillsResolverKey,
|
|
@@ -4800,7 +5068,7 @@ var createAgentFactory = (state, options = {}) => {
|
|
|
4800
5068
|
toolOutputCacheStore
|
|
4801
5069
|
}
|
|
4802
5070
|
);
|
|
4803
|
-
const editTool =
|
|
5071
|
+
const editTool = baseLocalTools.find(
|
|
4804
5072
|
(tool) => tool.definition.name === "edit"
|
|
4805
5073
|
);
|
|
4806
5074
|
let mcpTools = [];
|
|
@@ -4823,9 +5091,6 @@ var createAgentFactory = (state, options = {}) => {
|
|
|
4823
5091
|
(0, import_logger.log)(`failed to load mcp tools: ${String(error)}`);
|
|
4824
5092
|
}
|
|
4825
5093
|
}
|
|
4826
|
-
const tools = [...localTools, ...mcpTools];
|
|
4827
|
-
state.tools = tools;
|
|
4828
|
-
state.toolDefinitions = tools.map((tool) => tool.definition);
|
|
4829
5094
|
const baseSystemPrompt = await loadSystemPrompt(ctx.workingDir);
|
|
4830
5095
|
const withAgentsContext = appendInitialAgentsContext(
|
|
4831
5096
|
baseSystemPrompt,
|
|
@@ -4861,12 +5126,35 @@ var createAgentFactory = (state, options = {}) => {
|
|
|
4861
5126
|
const authResolver = await AuthResolver.create(state, import_logger.log);
|
|
4862
5127
|
const provider = await authResolver.resolveProvider(modelConfig.provider);
|
|
4863
5128
|
const providerAuth = await authResolver.resolveProviderAuth(provider);
|
|
5129
|
+
const searchConfig = await resolveSearchConfig(ctx.workingDir);
|
|
5130
|
+
const hostedSearchDefinitions = buildHostedSearchToolDefinitions(
|
|
5131
|
+
provider,
|
|
5132
|
+
searchConfig
|
|
5133
|
+
);
|
|
5134
|
+
if (searchConfig.mode === "native" && hostedSearchDefinitions.length === 0) {
|
|
5135
|
+
throw new Error(
|
|
5136
|
+
`search.mode=native is enabled, but native search is unavailable for provider '${provider}'.`
|
|
5137
|
+
);
|
|
5138
|
+
}
|
|
5139
|
+
const useLocalSearchTool = searchConfig.mode === "local" || searchConfig.mode === "auto" && hostedSearchDefinitions.length === 0;
|
|
5140
|
+
const localSearchTools = useLocalSearchTool ? [
|
|
5141
|
+
createSearchTool({
|
|
5142
|
+
defaultBackend: searchConfig.local.backend,
|
|
5143
|
+
braveApiKeyEnv: searchConfig.local.braveApiKeyEnv
|
|
5144
|
+
})
|
|
5145
|
+
] : [];
|
|
5146
|
+
const tools = [...baseLocalTools, ...localSearchTools, ...mcpTools];
|
|
5147
|
+
state.tools = tools;
|
|
5148
|
+
state.toolDefinitions = [
|
|
5149
|
+
...tools.map((tool) => tool.definition),
|
|
5150
|
+
...hostedSearchDefinitions
|
|
5151
|
+
];
|
|
4864
5152
|
let llm;
|
|
4865
5153
|
switch (provider) {
|
|
4866
5154
|
case "openai": {
|
|
4867
5155
|
const reasoningEffort = resolveReasoningEffort(modelConfig.reasoning);
|
|
4868
5156
|
const textVerbosity = resolveTextVerbosity(modelConfig.verbosity);
|
|
4869
|
-
llm = new
|
|
5157
|
+
llm = new import_core18.ChatOpenAI({
|
|
4870
5158
|
clientOptions: buildOpenAiClientOptions(authResolver, providerAuth),
|
|
4871
5159
|
...modelConfig.name ? { model: modelConfig.name } : {},
|
|
4872
5160
|
...reasoningEffort ? { reasoningEffort } : {},
|
|
@@ -4877,7 +5165,7 @@ var createAgentFactory = (state, options = {}) => {
|
|
|
4877
5165
|
case "openrouter": {
|
|
4878
5166
|
const reasoningEffort = resolveReasoningEffort(modelConfig.reasoning);
|
|
4879
5167
|
const textVerbosity = resolveTextVerbosity(modelConfig.verbosity);
|
|
4880
|
-
llm = new
|
|
5168
|
+
llm = new import_core18.ChatOpenAI({
|
|
4881
5169
|
clientOptions: buildOpenRouterClientOptions(providerAuth),
|
|
4882
5170
|
...modelConfig.name ? { model: modelConfig.name } : {},
|
|
4883
5171
|
...reasoningEffort ? { reasoningEffort } : {},
|
|
@@ -4886,7 +5174,7 @@ var createAgentFactory = (state, options = {}) => {
|
|
|
4886
5174
|
break;
|
|
4887
5175
|
}
|
|
4888
5176
|
case "anthropic": {
|
|
4889
|
-
llm = new
|
|
5177
|
+
llm = new import_core18.ChatAnthropic({
|
|
4890
5178
|
clientOptions: {
|
|
4891
5179
|
apiKey: requireApiKeyAuth("Anthropic", providerAuth)
|
|
4892
5180
|
},
|
|
@@ -4900,11 +5188,18 @@ var createAgentFactory = (state, options = {}) => {
|
|
|
4900
5188
|
const modelRegistry = await buildModelRegistry(llm, {
|
|
4901
5189
|
strict: provider !== "openrouter"
|
|
4902
5190
|
});
|
|
4903
|
-
const
|
|
5191
|
+
const totalBudgetTrimEnabled = envTruthy(
|
|
5192
|
+
process.env.CODELIA_TOOL_OUTPUT_TOTAL_TRIM
|
|
5193
|
+
);
|
|
5194
|
+
const agent = new import_core18.Agent({
|
|
4904
5195
|
llm,
|
|
4905
5196
|
tools,
|
|
5197
|
+
hostedTools: hostedSearchDefinitions,
|
|
4906
5198
|
systemPrompt,
|
|
4907
|
-
modelRegistry: modelRegistry ??
|
|
5199
|
+
modelRegistry: modelRegistry ?? import_core18.DEFAULT_MODEL_REGISTRY,
|
|
5200
|
+
toolOutputCache: {
|
|
5201
|
+
totalBudgetTrim: totalBudgetTrimEnabled
|
|
5202
|
+
},
|
|
4908
5203
|
services: { toolOutputCacheStore },
|
|
4909
5204
|
canExecuteTool: async (call, rawArgs, toolCtx) => {
|
|
4910
5205
|
const decision = permissionService.evaluate(
|
|
@@ -5606,8 +5901,8 @@ var parseAuthorizationServerMetadata = (value) => {
|
|
|
5606
5901
|
var buildAuthorizationServerMetadataUrl = (issuer) => {
|
|
5607
5902
|
try {
|
|
5608
5903
|
const parsed = new URL(issuer);
|
|
5609
|
-
const
|
|
5610
|
-
const basePath =
|
|
5904
|
+
const path17 = parsed.pathname === "/" ? "" : parsed.pathname;
|
|
5905
|
+
const basePath = path17.startsWith("/") ? path17 : `/${path17}`;
|
|
5611
5906
|
const metadataPath = `/.well-known/oauth-authorization-server${basePath}`;
|
|
5612
5907
|
return new URL(metadataPath, `${parsed.origin}/`).toString();
|
|
5613
5908
|
} catch {
|
|
@@ -6264,9 +6559,8 @@ var McpManager = class {
|
|
|
6264
6559
|
};
|
|
6265
6560
|
|
|
6266
6561
|
// src/rpc/handlers.ts
|
|
6267
|
-
var
|
|
6268
|
-
var
|
|
6269
|
-
var import_storage8 = require("@codelia/storage");
|
|
6562
|
+
var import_protocol9 = require("@codelia/protocol");
|
|
6563
|
+
var import_storage9 = require("@codelia/storage");
|
|
6270
6564
|
|
|
6271
6565
|
// src/constants.ts
|
|
6272
6566
|
var SERVER_NAME = "codelia-runtime";
|
|
@@ -6642,8 +6936,7 @@ var createHistoryHandlers = ({
|
|
|
6642
6936
|
};
|
|
6643
6937
|
|
|
6644
6938
|
// src/rpc/model.ts
|
|
6645
|
-
var
|
|
6646
|
-
var import_core18 = require("@codelia/core");
|
|
6939
|
+
var import_core19 = require("@codelia/core");
|
|
6647
6940
|
var import_model_metadata2 = require("@codelia/model-metadata");
|
|
6648
6941
|
var import_protocol4 = require("@codelia/protocol");
|
|
6649
6942
|
var isSupportedProvider = (provider) => provider === "openai" || provider === "anthropic" || provider === "openrouter";
|
|
@@ -6887,7 +7180,7 @@ var buildProviderModelList = async ({
|
|
|
6887
7180
|
}
|
|
6888
7181
|
}
|
|
6889
7182
|
const models = sortModelsByReleaseDate(
|
|
6890
|
-
(0,
|
|
7183
|
+
(0, import_core19.listModels)(import_core19.DEFAULT_MODEL_REGISTRY, provider).map((model) => model.id),
|
|
6891
7184
|
provider,
|
|
6892
7185
|
providerEntries
|
|
6893
7186
|
);
|
|
@@ -6984,19 +7277,19 @@ var createModelHandlers = ({
|
|
|
6984
7277
|
return;
|
|
6985
7278
|
}
|
|
6986
7279
|
if (provider !== "openrouter") {
|
|
6987
|
-
const spec = (0,
|
|
7280
|
+
const spec = (0, import_core19.resolveModel)(import_core19.DEFAULT_MODEL_REGISTRY, name, provider);
|
|
6988
7281
|
if (!spec) {
|
|
6989
7282
|
sendError(id, { code: import_protocol4.RPC_ERROR_CODE.INVALID_PARAMS, message: `unknown model: ${name}` });
|
|
6990
7283
|
return;
|
|
6991
7284
|
}
|
|
6992
7285
|
}
|
|
6993
7286
|
try {
|
|
6994
|
-
const
|
|
6995
|
-
await (
|
|
7287
|
+
const workingDir = state.lastUiContext?.cwd ?? state.runtimeWorkingDir ?? process.cwd();
|
|
7288
|
+
const target = await updateModel(workingDir, { provider, name });
|
|
6996
7289
|
state.agent = null;
|
|
6997
7290
|
const result = { provider, name };
|
|
6998
7291
|
sendResult(id, result);
|
|
6999
|
-
log2(`model.set ${provider}/${name}`);
|
|
7292
|
+
log2(`model.set ${provider}/${name} scope=${target.scope} path=${target.path}`);
|
|
7000
7293
|
} catch (error) {
|
|
7001
7294
|
sendError(id, { code: import_protocol4.RPC_ERROR_CODE.RUNTIME_INTERNAL, message: String(error) });
|
|
7002
7295
|
}
|
|
@@ -7008,7 +7301,7 @@ var createModelHandlers = ({
|
|
|
7008
7301
|
var import_protocol5 = require("@codelia/protocol");
|
|
7009
7302
|
|
|
7010
7303
|
// src/rpc/run-debug.ts
|
|
7011
|
-
var
|
|
7304
|
+
var import_core20 = require("@codelia/core");
|
|
7012
7305
|
var DEBUG_MAX_CONTENT_CHARS = 2e3;
|
|
7013
7306
|
var DEBUG_MAX_LOG_CHARS = 2e4;
|
|
7014
7307
|
var DEBUG_MAX_EVENT_RESULT_CHARS = 500;
|
|
@@ -7025,7 +7318,7 @@ var stringifyUnknown = (value) => {
|
|
|
7025
7318
|
}
|
|
7026
7319
|
};
|
|
7027
7320
|
var contentToDebugText = (content, maxChars) => {
|
|
7028
|
-
const text = (0,
|
|
7321
|
+
const text = (0, import_core20.stringifyContent)(content, {
|
|
7029
7322
|
mode: "log",
|
|
7030
7323
|
joiner: "\n",
|
|
7031
7324
|
includeOtherPayload: true
|
|
@@ -7307,6 +7600,28 @@ var buildSessionState = (sessionId, runId, messages, invokeSeq) => ({
|
|
|
7307
7600
|
invoke_seq: invokeSeq,
|
|
7308
7601
|
messages
|
|
7309
7602
|
});
|
|
7603
|
+
var toTimestampMs = (value) => {
|
|
7604
|
+
const ms = Date.parse(value);
|
|
7605
|
+
return Number.isFinite(ms) ? ms : null;
|
|
7606
|
+
};
|
|
7607
|
+
var summarizeProviderMeta = (value) => {
|
|
7608
|
+
if (value === null || value === void 0) {
|
|
7609
|
+
return null;
|
|
7610
|
+
}
|
|
7611
|
+
if (typeof value === "string") {
|
|
7612
|
+
return value.length > 80 ? `${value.slice(0, 77)}...` : value;
|
|
7613
|
+
}
|
|
7614
|
+
if (Array.isArray(value)) {
|
|
7615
|
+
return `array(len=${value.length})`;
|
|
7616
|
+
}
|
|
7617
|
+
if (typeof value === "object") {
|
|
7618
|
+
const keys = Object.keys(value);
|
|
7619
|
+
if (keys.length === 0) return "object";
|
|
7620
|
+
const shown = keys.slice(0, 4).join(",");
|
|
7621
|
+
return keys.length > 4 ? `object(keys=${shown},...)` : `object(keys=${shown})`;
|
|
7622
|
+
}
|
|
7623
|
+
return typeof value;
|
|
7624
|
+
};
|
|
7310
7625
|
var createRunHandlers = ({
|
|
7311
7626
|
state,
|
|
7312
7627
|
getAgent,
|
|
@@ -7440,12 +7755,77 @@ var createRunHandlers = ({
|
|
|
7440
7755
|
const runAbortController = new AbortController();
|
|
7441
7756
|
activeRunAbort = { runId, controller: runAbortController };
|
|
7442
7757
|
const sessionStore = runEventStoreFactory.create({ runId, startedAt });
|
|
7443
|
-
const
|
|
7758
|
+
const sessionAppenderRaw = createSessionAppender(
|
|
7444
7759
|
sessionStore,
|
|
7445
7760
|
(error, record) => {
|
|
7446
7761
|
log2(`session-store error (${record.type}): ${String(error)}`);
|
|
7447
7762
|
}
|
|
7448
7763
|
);
|
|
7764
|
+
const pendingLlmRequests = /* @__PURE__ */ new Map();
|
|
7765
|
+
const emitRunDiagnostics = (params2) => {
|
|
7766
|
+
if (!state.diagnosticsEnabled) return;
|
|
7767
|
+
try {
|
|
7768
|
+
sendRunDiagnostics(params2);
|
|
7769
|
+
} catch (error) {
|
|
7770
|
+
log2(`run diagnostics emit failed: ${String(error)}`);
|
|
7771
|
+
}
|
|
7772
|
+
};
|
|
7773
|
+
const sessionAppend = (record) => {
|
|
7774
|
+
if (state.diagnosticsEnabled) {
|
|
7775
|
+
try {
|
|
7776
|
+
if (record.type === "llm.request") {
|
|
7777
|
+
const modelName = record.model?.name ?? record.input.model ?? "unknown";
|
|
7778
|
+
pendingLlmRequests.set(record.seq, {
|
|
7779
|
+
ts: record.ts,
|
|
7780
|
+
provider: record.model?.provider,
|
|
7781
|
+
model: modelName
|
|
7782
|
+
});
|
|
7783
|
+
}
|
|
7784
|
+
if (record.type === "llm.response") {
|
|
7785
|
+
const request = pendingLlmRequests.get(record.seq);
|
|
7786
|
+
pendingLlmRequests.delete(record.seq);
|
|
7787
|
+
const usage = record.output.usage ?? null;
|
|
7788
|
+
const cacheReadTokens = usage?.input_cached_tokens ?? 0;
|
|
7789
|
+
const cacheCreationTokens = usage?.input_cache_creation_tokens ?? 0;
|
|
7790
|
+
const inputTokens = usage?.input_tokens ?? 0;
|
|
7791
|
+
const hitState = usage ? cacheReadTokens > 0 ? "hit" : "miss" : "unknown";
|
|
7792
|
+
const responseTsMs = toTimestampMs(record.ts);
|
|
7793
|
+
const requestTsMs = request ? toTimestampMs(request.ts) : null;
|
|
7794
|
+
const latencyMs = responseTsMs !== null && requestTsMs !== null ? Math.max(0, responseTsMs - requestTsMs) : 0;
|
|
7795
|
+
const model = usage?.model ?? request?.model ?? "unknown";
|
|
7796
|
+
const diagnostics = {
|
|
7797
|
+
run_id: runId,
|
|
7798
|
+
seq: record.seq,
|
|
7799
|
+
...request?.provider ? { provider: request.provider } : {},
|
|
7800
|
+
model,
|
|
7801
|
+
request_ts: request?.ts ?? record.ts,
|
|
7802
|
+
response_ts: record.ts,
|
|
7803
|
+
latency_ms: latencyMs,
|
|
7804
|
+
stop_reason: record.output.stop_reason ?? null,
|
|
7805
|
+
usage,
|
|
7806
|
+
cache: {
|
|
7807
|
+
hit_state: hitState,
|
|
7808
|
+
cache_read_tokens: cacheReadTokens,
|
|
7809
|
+
cache_creation_tokens: cacheCreationTokens,
|
|
7810
|
+
cache_read_ratio: usage ? cacheReadTokens / Math.max(inputTokens, 1) : null
|
|
7811
|
+
},
|
|
7812
|
+
cost_usd: null,
|
|
7813
|
+
provider_meta_summary: summarizeProviderMeta(
|
|
7814
|
+
record.output.provider_meta
|
|
7815
|
+
)
|
|
7816
|
+
};
|
|
7817
|
+
emitRunDiagnostics({
|
|
7818
|
+
run_id: runId,
|
|
7819
|
+
kind: "llm_call",
|
|
7820
|
+
call: diagnostics
|
|
7821
|
+
});
|
|
7822
|
+
}
|
|
7823
|
+
} catch (error) {
|
|
7824
|
+
log2(`run diagnostics build failed: ${String(error)}`);
|
|
7825
|
+
}
|
|
7826
|
+
}
|
|
7827
|
+
sessionAppenderRaw(record);
|
|
7828
|
+
};
|
|
7449
7829
|
state.sessionAppend = sessionAppend;
|
|
7450
7830
|
const session = {
|
|
7451
7831
|
run_id: runId,
|
|
@@ -7498,6 +7878,13 @@ var createRunHandlers = ({
|
|
|
7498
7878
|
let finalResponse;
|
|
7499
7879
|
let sessionSaveChain = Promise.resolve();
|
|
7500
7880
|
let lastSessionSaveAt = 0;
|
|
7881
|
+
const emitRunSummaryDiagnostics = () => {
|
|
7882
|
+
emitRunDiagnostics({
|
|
7883
|
+
run_id: runId,
|
|
7884
|
+
kind: "run_summary",
|
|
7885
|
+
summary: runtimeAgent.getUsageSummary()
|
|
7886
|
+
});
|
|
7887
|
+
};
|
|
7501
7888
|
const queueSessionSave = async (reason) => {
|
|
7502
7889
|
sessionSaveChain = sessionSaveChain.then(async () => {
|
|
7503
7890
|
if (!sessionId) return;
|
|
@@ -7592,6 +7979,7 @@ var createRunHandlers = ({
|
|
|
7592
7979
|
normalizeRunHistoryAfterCancel(runId, runtimeAgent);
|
|
7593
7980
|
}
|
|
7594
7981
|
await queueSessionSave("terminal");
|
|
7982
|
+
emitRunSummaryDiagnostics();
|
|
7595
7983
|
const status = state.cancelRequested ? "cancelled" : "completed";
|
|
7596
7984
|
emitRunStatus(runId, status);
|
|
7597
7985
|
emitRunEnd(
|
|
@@ -7604,11 +7992,13 @@ var createRunHandlers = ({
|
|
|
7604
7992
|
if (state.cancelRequested || isAbortLikeError(err)) {
|
|
7605
7993
|
normalizeRunHistoryAfterCancel(runId, runtimeAgent);
|
|
7606
7994
|
await queueSessionSave("cancelled");
|
|
7995
|
+
emitRunSummaryDiagnostics();
|
|
7607
7996
|
emitRunStatus(runId, "cancelled", err.message || "cancelled");
|
|
7608
7997
|
emitRunEnd(runId, "cancelled", finalResponse);
|
|
7609
7998
|
return;
|
|
7610
7999
|
}
|
|
7611
8000
|
await queueSessionSave("error");
|
|
8001
|
+
emitRunSummaryDiagnostics();
|
|
7612
8002
|
emitRunStatus(runId, "error", err.message);
|
|
7613
8003
|
appendSession({
|
|
7614
8004
|
type: "run.error",
|
|
@@ -7788,7 +8178,313 @@ var createToolHandlers = ({
|
|
|
7788
8178
|
};
|
|
7789
8179
|
};
|
|
7790
8180
|
|
|
8181
|
+
// src/rpc/shell.ts
|
|
8182
|
+
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
8183
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
8184
|
+
var import_node_child_process5 = require("child_process");
|
|
8185
|
+
var import_storage8 = require("@codelia/storage");
|
|
8186
|
+
var import_protocol8 = require("@codelia/protocol");
|
|
8187
|
+
var DEFAULT_EXCERPT_LINES = 80;
|
|
8188
|
+
var MAX_INLINE_OUTPUT_BYTES = 64 * 1024;
|
|
8189
|
+
var COMMAND_PREVIEW_CHARS = 400;
|
|
8190
|
+
var truncateCommandPreview = (value) => {
|
|
8191
|
+
const trimmed = value.trim();
|
|
8192
|
+
if (trimmed.length <= COMMAND_PREVIEW_CHARS) return trimmed;
|
|
8193
|
+
return `${trimmed.slice(0, COMMAND_PREVIEW_CHARS)}...[truncated]`;
|
|
8194
|
+
};
|
|
8195
|
+
var utf8ByteLength = (value) => Buffer.byteLength(value, "utf8");
|
|
8196
|
+
var truncateUtf8Prefix = (value, maxBytes) => {
|
|
8197
|
+
if (maxBytes <= 0 || value.length === 0) return "";
|
|
8198
|
+
let bytes = 0;
|
|
8199
|
+
let out = "";
|
|
8200
|
+
for (const ch of value) {
|
|
8201
|
+
const next = utf8ByteLength(ch);
|
|
8202
|
+
if (bytes + next > maxBytes) break;
|
|
8203
|
+
out += ch;
|
|
8204
|
+
bytes += next;
|
|
8205
|
+
}
|
|
8206
|
+
return out;
|
|
8207
|
+
};
|
|
8208
|
+
var truncateUtf8Suffix = (value, maxBytes) => {
|
|
8209
|
+
if (maxBytes <= 0 || value.length === 0) return "";
|
|
8210
|
+
let bytes = 0;
|
|
8211
|
+
const chars = Array.from(value);
|
|
8212
|
+
const out = [];
|
|
8213
|
+
for (let idx = chars.length - 1; idx >= 0; idx -= 1) {
|
|
8214
|
+
const ch = chars[idx];
|
|
8215
|
+
const next = utf8ByteLength(ch);
|
|
8216
|
+
if (bytes + next > maxBytes) break;
|
|
8217
|
+
out.push(ch);
|
|
8218
|
+
bytes += next;
|
|
8219
|
+
}
|
|
8220
|
+
out.reverse();
|
|
8221
|
+
return out.join("");
|
|
8222
|
+
};
|
|
8223
|
+
var excerptByLines = (value) => {
|
|
8224
|
+
const lines = value.split(/\r?\n/);
|
|
8225
|
+
if (lines.length <= DEFAULT_EXCERPT_LINES * 2) {
|
|
8226
|
+
return value;
|
|
8227
|
+
}
|
|
8228
|
+
const head = lines.slice(0, DEFAULT_EXCERPT_LINES);
|
|
8229
|
+
const tail = lines.slice(lines.length - DEFAULT_EXCERPT_LINES);
|
|
8230
|
+
const omitted = lines.length - head.length - tail.length;
|
|
8231
|
+
return [...head, `...[${omitted} lines omitted]...`, ...tail].join("\n");
|
|
8232
|
+
};
|
|
8233
|
+
var excerptByBytes = (value, maxBytes) => {
|
|
8234
|
+
if (utf8ByteLength(value) <= maxBytes) return value;
|
|
8235
|
+
const marker = "\n...[truncated by size]...\n";
|
|
8236
|
+
const markerBytes = utf8ByteLength(marker);
|
|
8237
|
+
if (maxBytes <= markerBytes + 2) {
|
|
8238
|
+
return truncateUtf8Prefix(value, maxBytes);
|
|
8239
|
+
}
|
|
8240
|
+
const budget = maxBytes - markerBytes;
|
|
8241
|
+
const headBytes = Math.floor(budget / 2);
|
|
8242
|
+
const tailBytes = budget - headBytes;
|
|
8243
|
+
const head = truncateUtf8Prefix(value, headBytes);
|
|
8244
|
+
const tail = truncateUtf8Suffix(value, tailBytes);
|
|
8245
|
+
return `${head}${marker}${tail}`;
|
|
8246
|
+
};
|
|
8247
|
+
var needsInlineTruncation = (value) => value.split(/\r?\n/).length > DEFAULT_EXCERPT_LINES * 2 || utf8ByteLength(value) > MAX_INLINE_OUTPUT_BYTES;
|
|
8248
|
+
var excerptText = (value) => excerptByBytes(excerptByLines(value), MAX_INLINE_OUTPUT_BYTES);
|
|
8249
|
+
var isWithin2 = (basePath, candidatePath) => {
|
|
8250
|
+
const relative = import_node_path15.default.relative(basePath, candidatePath);
|
|
8251
|
+
return relative === "" || !relative.startsWith("..") && !import_node_path15.default.isAbsolute(relative);
|
|
8252
|
+
};
|
|
8253
|
+
var resolveShellCwd = (state, requestedCwd) => {
|
|
8254
|
+
const workingDir = state.runtimeWorkingDir ?? process.cwd();
|
|
8255
|
+
const rootDir = state.runtimeSandboxRoot ?? workingDir;
|
|
8256
|
+
if (!requestedCwd) return workingDir;
|
|
8257
|
+
const resolved = import_node_path15.default.resolve(workingDir, requestedCwd);
|
|
8258
|
+
if (!isWithin2(rootDir, resolved)) {
|
|
8259
|
+
return null;
|
|
8260
|
+
}
|
|
8261
|
+
return resolved;
|
|
8262
|
+
};
|
|
8263
|
+
var runShellWithUserShell = async (command, options) => {
|
|
8264
|
+
if (process.platform === "win32") {
|
|
8265
|
+
return runShellCommand(command, options);
|
|
8266
|
+
}
|
|
8267
|
+
const shellPath = process.env.SHELL?.trim() || "";
|
|
8268
|
+
if (!shellPath) {
|
|
8269
|
+
return runShellCommand(command, options);
|
|
8270
|
+
}
|
|
8271
|
+
return new Promise((resolve, reject) => {
|
|
8272
|
+
const child = (0, import_node_child_process5.spawn)(shellPath, ["-lc", command], {
|
|
8273
|
+
cwd: options.cwd,
|
|
8274
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
8275
|
+
signal: options.signal
|
|
8276
|
+
});
|
|
8277
|
+
let stdout = "";
|
|
8278
|
+
let stderr = "";
|
|
8279
|
+
let totalBytes = 0;
|
|
8280
|
+
let settled = false;
|
|
8281
|
+
let timedOut = false;
|
|
8282
|
+
let timeoutHandle;
|
|
8283
|
+
const finish = (handler) => {
|
|
8284
|
+
if (settled) return;
|
|
8285
|
+
settled = true;
|
|
8286
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
8287
|
+
handler();
|
|
8288
|
+
};
|
|
8289
|
+
const consumeChunk = (chunk, stream) => {
|
|
8290
|
+
const text = chunk.toString("utf8");
|
|
8291
|
+
totalBytes += Buffer.byteLength(text, "utf8");
|
|
8292
|
+
if (totalBytes > options.maxOutputBytes) {
|
|
8293
|
+
const error = Object.assign(
|
|
8294
|
+
new Error(
|
|
8295
|
+
`Command output exceeded max buffer of ${options.maxOutputBytes} bytes`
|
|
8296
|
+
),
|
|
8297
|
+
{
|
|
8298
|
+
code: "MAXBUFFER",
|
|
8299
|
+
stdout,
|
|
8300
|
+
stderr,
|
|
8301
|
+
killed: true,
|
|
8302
|
+
signal: "SIGTERM"
|
|
8303
|
+
}
|
|
8304
|
+
);
|
|
8305
|
+
try {
|
|
8306
|
+
child.kill("SIGTERM");
|
|
8307
|
+
} catch {
|
|
8308
|
+
}
|
|
8309
|
+
finish(() => reject(error));
|
|
8310
|
+
return;
|
|
8311
|
+
}
|
|
8312
|
+
if (stream === "stdout") stdout += text;
|
|
8313
|
+
else stderr += text;
|
|
8314
|
+
};
|
|
8315
|
+
child.stdout?.on("data", (chunk) => consumeChunk(chunk, "stdout"));
|
|
8316
|
+
child.stderr?.on("data", (chunk) => consumeChunk(chunk, "stderr"));
|
|
8317
|
+
child.on("error", (error) => {
|
|
8318
|
+
const enriched = Object.assign(error, {
|
|
8319
|
+
stdout,
|
|
8320
|
+
stderr
|
|
8321
|
+
});
|
|
8322
|
+
finish(() => reject(enriched));
|
|
8323
|
+
});
|
|
8324
|
+
child.on("close", (code, signal) => {
|
|
8325
|
+
if (timedOut) {
|
|
8326
|
+
const timeoutError = Object.assign(
|
|
8327
|
+
new Error(
|
|
8328
|
+
`Command timed out after ${Math.trunc(options.timeoutMs / 1e3)}s`
|
|
8329
|
+
),
|
|
8330
|
+
{
|
|
8331
|
+
code: "ETIMEDOUT",
|
|
8332
|
+
stdout,
|
|
8333
|
+
stderr,
|
|
8334
|
+
killed: true,
|
|
8335
|
+
signal: signal ?? "SIGTERM"
|
|
8336
|
+
}
|
|
8337
|
+
);
|
|
8338
|
+
finish(() => reject(timeoutError));
|
|
8339
|
+
return;
|
|
8340
|
+
}
|
|
8341
|
+
if (code === 0) {
|
|
8342
|
+
finish(() => resolve({ stdout, stderr }));
|
|
8343
|
+
return;
|
|
8344
|
+
}
|
|
8345
|
+
const failure = Object.assign(
|
|
8346
|
+
new Error(
|
|
8347
|
+
`Command failed with exit code ${code ?? "unknown"}${signal ? ` signal ${signal}` : ""}`
|
|
8348
|
+
),
|
|
8349
|
+
{ code, stdout, stderr, killed: false, signal }
|
|
8350
|
+
);
|
|
8351
|
+
finish(() => reject(failure));
|
|
8352
|
+
});
|
|
8353
|
+
timeoutHandle = setTimeout(() => {
|
|
8354
|
+
timedOut = true;
|
|
8355
|
+
try {
|
|
8356
|
+
child.kill("SIGTERM");
|
|
8357
|
+
} catch {
|
|
8358
|
+
}
|
|
8359
|
+
setTimeout(() => {
|
|
8360
|
+
try {
|
|
8361
|
+
if (!child.killed) child.kill("SIGKILL");
|
|
8362
|
+
} catch {
|
|
8363
|
+
}
|
|
8364
|
+
}, 2e3).unref();
|
|
8365
|
+
}, options.timeoutMs);
|
|
8366
|
+
});
|
|
8367
|
+
};
|
|
8368
|
+
var createShellHandlers = ({
|
|
8369
|
+
state,
|
|
8370
|
+
log: log2
|
|
8371
|
+
}) => {
|
|
8372
|
+
const outputCache = new import_storage8.ToolOutputCacheStoreImpl();
|
|
8373
|
+
const handleShellExec = async (id, params) => {
|
|
8374
|
+
const command = params?.command?.trim() ?? "";
|
|
8375
|
+
if (!command) {
|
|
8376
|
+
sendError(id, {
|
|
8377
|
+
code: import_protocol8.RPC_ERROR_CODE.INVALID_PARAMS,
|
|
8378
|
+
message: "command is required"
|
|
8379
|
+
});
|
|
8380
|
+
return;
|
|
8381
|
+
}
|
|
8382
|
+
const requestedTimeout = params?.timeout_seconds ?? DEFAULT_TIMEOUT_SECONDS;
|
|
8383
|
+
if (!Number.isFinite(requestedTimeout) || requestedTimeout <= 0) {
|
|
8384
|
+
sendError(id, {
|
|
8385
|
+
code: import_protocol8.RPC_ERROR_CODE.INVALID_PARAMS,
|
|
8386
|
+
message: "timeout_seconds must be a positive number"
|
|
8387
|
+
});
|
|
8388
|
+
return;
|
|
8389
|
+
}
|
|
8390
|
+
const timeoutSeconds = Math.max(
|
|
8391
|
+
1,
|
|
8392
|
+
Math.min(Math.trunc(requestedTimeout), MAX_TIMEOUT_SECONDS)
|
|
8393
|
+
);
|
|
8394
|
+
const cwd = resolveShellCwd(state, params?.cwd);
|
|
8395
|
+
if (!cwd) {
|
|
8396
|
+
sendError(id, {
|
|
8397
|
+
code: import_protocol8.RPC_ERROR_CODE.INVALID_PARAMS,
|
|
8398
|
+
message: "cwd is outside sandbox root"
|
|
8399
|
+
});
|
|
8400
|
+
return;
|
|
8401
|
+
}
|
|
8402
|
+
const startedAt = Date.now();
|
|
8403
|
+
const commandSummary = summarizeCommand(command);
|
|
8404
|
+
const commandPreview = truncateCommandPreview(command);
|
|
8405
|
+
log2(
|
|
8406
|
+
`shell.exec.start origin=ui_bang cwd=${cwd} timeout_s=${timeoutSeconds} command="${commandSummary}"`
|
|
8407
|
+
);
|
|
8408
|
+
let rawStdout = "";
|
|
8409
|
+
let rawStderr = "";
|
|
8410
|
+
let exitCode = 0;
|
|
8411
|
+
let signal = null;
|
|
8412
|
+
try {
|
|
8413
|
+
const result2 = await runShellWithUserShell(command, {
|
|
8414
|
+
cwd,
|
|
8415
|
+
timeoutMs: timeoutSeconds * 1e3,
|
|
8416
|
+
maxOutputBytes: MAX_OUTPUT_BYTES
|
|
8417
|
+
});
|
|
8418
|
+
rawStdout = result2.stdout;
|
|
8419
|
+
rawStderr = result2.stderr;
|
|
8420
|
+
} catch (error) {
|
|
8421
|
+
const execError = error;
|
|
8422
|
+
rawStdout = execError.stdout ?? "";
|
|
8423
|
+
rawStderr = execError.stderr ?? "";
|
|
8424
|
+
exitCode = typeof execError.code === "number" ? execError.code : null;
|
|
8425
|
+
signal = execError.signal ?? null;
|
|
8426
|
+
}
|
|
8427
|
+
const stdoutTruncated = needsInlineTruncation(rawStdout);
|
|
8428
|
+
const stderrTruncated = needsInlineTruncation(rawStderr);
|
|
8429
|
+
const stdout = stdoutTruncated ? excerptText(rawStdout) : rawStdout;
|
|
8430
|
+
const stderr = stderrTruncated ? excerptText(rawStderr) : rawStderr;
|
|
8431
|
+
const combinedTruncated = stdoutTruncated || stderrTruncated;
|
|
8432
|
+
let stdoutCacheId;
|
|
8433
|
+
let stderrCacheId;
|
|
8434
|
+
if (stdoutTruncated && rawStdout.trim()) {
|
|
8435
|
+
const saved = await outputCache.save({
|
|
8436
|
+
tool_call_id: `shell_exec_stdout_${import_node_crypto6.default.randomUUID()}`,
|
|
8437
|
+
tool_name: "shell.exec",
|
|
8438
|
+
content: rawStdout
|
|
8439
|
+
});
|
|
8440
|
+
stdoutCacheId = saved.id;
|
|
8441
|
+
}
|
|
8442
|
+
if (stderrTruncated && rawStderr.trim()) {
|
|
8443
|
+
const saved = await outputCache.save({
|
|
8444
|
+
tool_call_id: `shell_exec_stderr_${import_node_crypto6.default.randomUUID()}`,
|
|
8445
|
+
tool_name: "shell.exec",
|
|
8446
|
+
content: rawStderr
|
|
8447
|
+
});
|
|
8448
|
+
stderrCacheId = saved.id;
|
|
8449
|
+
}
|
|
8450
|
+
const result = {
|
|
8451
|
+
command_preview: commandPreview,
|
|
8452
|
+
exit_code: exitCode,
|
|
8453
|
+
signal,
|
|
8454
|
+
stdout,
|
|
8455
|
+
stderr,
|
|
8456
|
+
truncated: {
|
|
8457
|
+
stdout: stdoutTruncated,
|
|
8458
|
+
stderr: stderrTruncated,
|
|
8459
|
+
combined: combinedTruncated
|
|
8460
|
+
},
|
|
8461
|
+
duration_ms: Date.now() - startedAt,
|
|
8462
|
+
...stdoutCacheId ? { stdout_cache_id: stdoutCacheId } : {},
|
|
8463
|
+
...stderrCacheId ? { stderr_cache_id: stderrCacheId } : {}
|
|
8464
|
+
};
|
|
8465
|
+
sendResult(id, result);
|
|
8466
|
+
log2(
|
|
8467
|
+
`shell.exec.done origin=ui_bang duration_ms=${result.duration_ms} exit_code=${String(result.exit_code)} signal=${result.signal ?? "-"}`
|
|
8468
|
+
);
|
|
8469
|
+
};
|
|
8470
|
+
return {
|
|
8471
|
+
handleShellExec
|
|
8472
|
+
};
|
|
8473
|
+
};
|
|
8474
|
+
|
|
7791
8475
|
// src/rpc/handlers.ts
|
|
8476
|
+
var SUPPORTED_TUI_THEMES = /* @__PURE__ */ new Set([
|
|
8477
|
+
"codelia",
|
|
8478
|
+
"ocean",
|
|
8479
|
+
"forest",
|
|
8480
|
+
"rose",
|
|
8481
|
+
"sakura",
|
|
8482
|
+
"mauve",
|
|
8483
|
+
"plum",
|
|
8484
|
+
"iris",
|
|
8485
|
+
"crimson",
|
|
8486
|
+
"wine"
|
|
8487
|
+
]);
|
|
7792
8488
|
var createRuntimeHandlers = ({
|
|
7793
8489
|
state,
|
|
7794
8490
|
getAgent,
|
|
@@ -7798,14 +8494,14 @@ var createRuntimeHandlers = ({
|
|
|
7798
8494
|
runEventStoreFactory: injectedRunEventStoreFactory,
|
|
7799
8495
|
buildProviderModelList: injectedBuildProviderModelList
|
|
7800
8496
|
}) => {
|
|
7801
|
-
const sessionStateStore = injectedSessionStateStore ?? new
|
|
8497
|
+
const sessionStateStore = injectedSessionStateStore ?? new import_storage9.SessionStateStoreImpl({
|
|
7802
8498
|
onError: (error, context) => {
|
|
7803
8499
|
log2(
|
|
7804
8500
|
`session-state ${context.action} error${context.detail ? ` (${context.detail})` : ""}: ${String(error)}`
|
|
7805
8501
|
);
|
|
7806
8502
|
}
|
|
7807
8503
|
});
|
|
7808
|
-
const runEventStoreFactory = injectedRunEventStoreFactory ?? new
|
|
8504
|
+
const runEventStoreFactory = injectedRunEventStoreFactory ?? new import_storage9.RunEventStoreFactoryImpl();
|
|
7809
8505
|
const mcpManager = injectedMcpManager ?? {
|
|
7810
8506
|
start: async () => void 0,
|
|
7811
8507
|
list: () => ({ servers: [] })
|
|
@@ -7893,10 +8589,15 @@ var createRuntimeHandlers = ({
|
|
|
7893
8589
|
log2("startup onboarding skipped (model not selected)");
|
|
7894
8590
|
return;
|
|
7895
8591
|
}
|
|
7896
|
-
const
|
|
7897
|
-
await (
|
|
8592
|
+
const workingDir = state.lastUiContext?.cwd ?? state.runtimeWorkingDir ?? process.cwd();
|
|
8593
|
+
const modelTarget = await updateModel(workingDir, {
|
|
8594
|
+
provider,
|
|
8595
|
+
name: selectedModel
|
|
8596
|
+
});
|
|
7898
8597
|
state.agent = null;
|
|
7899
|
-
log2(
|
|
8598
|
+
log2(
|
|
8599
|
+
`startup onboarding completed: ${provider}/${selectedModel} scope=${modelTarget.scope} path=${modelTarget.path}`
|
|
8600
|
+
);
|
|
7900
8601
|
};
|
|
7901
8602
|
const launchStartupOnboarding = () => {
|
|
7902
8603
|
if (startupOnboardingStarted) {
|
|
@@ -7942,17 +8643,24 @@ var createRuntimeHandlers = ({
|
|
|
7942
8643
|
state,
|
|
7943
8644
|
getAgent
|
|
7944
8645
|
});
|
|
8646
|
+
const { handleShellExec } = createShellHandlers({
|
|
8647
|
+
state,
|
|
8648
|
+
log: log2
|
|
8649
|
+
});
|
|
7945
8650
|
const handleInitialize = (id, params) => {
|
|
7946
8651
|
const result = {
|
|
7947
8652
|
protocol_version: PROTOCOL_VERSION,
|
|
7948
8653
|
server: { name: SERVER_NAME, version: SERVER_VERSION },
|
|
7949
8654
|
server_capabilities: {
|
|
7950
8655
|
supports_run_cancel: true,
|
|
8656
|
+
supports_run_diagnostics: true,
|
|
8657
|
+
supports_shell_exec: true,
|
|
7951
8658
|
supports_ui_requests: true,
|
|
7952
8659
|
supports_mcp_list: true,
|
|
7953
8660
|
supports_skills_list: true,
|
|
7954
8661
|
supports_context_inspect: true,
|
|
7955
8662
|
supports_tool_call: true,
|
|
8663
|
+
supports_theme_set: true,
|
|
7956
8664
|
supports_permission_preflight_events: true
|
|
7957
8665
|
}
|
|
7958
8666
|
};
|
|
@@ -7968,9 +8676,43 @@ var createRuntimeHandlers = ({
|
|
|
7968
8676
|
`ui.context.update cwd=${params.cwd ?? "-"} file=${params.active_file?.path ?? "-"}`
|
|
7969
8677
|
);
|
|
7970
8678
|
};
|
|
8679
|
+
const handleThemeSet = async (id, params) => {
|
|
8680
|
+
if (state.activeRunId) {
|
|
8681
|
+
sendError(id, { code: import_protocol9.RPC_ERROR_CODE.RUNTIME_BUSY, message: "runtime busy" });
|
|
8682
|
+
return;
|
|
8683
|
+
}
|
|
8684
|
+
const name = params?.name?.trim().toLowerCase();
|
|
8685
|
+
if (!name) {
|
|
8686
|
+
sendError(id, { code: import_protocol9.RPC_ERROR_CODE.INVALID_PARAMS, message: "theme name is required" });
|
|
8687
|
+
return;
|
|
8688
|
+
}
|
|
8689
|
+
if (!SUPPORTED_TUI_THEMES.has(name)) {
|
|
8690
|
+
sendError(id, {
|
|
8691
|
+
code: import_protocol9.RPC_ERROR_CODE.INVALID_PARAMS,
|
|
8692
|
+
message: `unsupported theme: ${name}`
|
|
8693
|
+
});
|
|
8694
|
+
return;
|
|
8695
|
+
}
|
|
8696
|
+
const workingDir = state.lastUiContext?.cwd ?? state.runtimeWorkingDir ?? process.cwd();
|
|
8697
|
+
try {
|
|
8698
|
+
const target = await updateTuiTheme(workingDir, name);
|
|
8699
|
+
const result = {
|
|
8700
|
+
name,
|
|
8701
|
+
scope: target.scope,
|
|
8702
|
+
path: target.path
|
|
8703
|
+
};
|
|
8704
|
+
sendResult(id, result);
|
|
8705
|
+
log2(`theme.set ${name} scope=${target.scope} path=${target.path}`);
|
|
8706
|
+
} catch (error) {
|
|
8707
|
+
sendError(id, { code: import_protocol9.RPC_ERROR_CODE.RUNTIME_INTERNAL, message: String(error) });
|
|
8708
|
+
}
|
|
8709
|
+
};
|
|
7971
8710
|
const handleAuthLogout = async (id, params) => {
|
|
7972
8711
|
if (state.activeRunId) {
|
|
7973
|
-
sendError(id, {
|
|
8712
|
+
sendError(id, {
|
|
8713
|
+
code: import_protocol9.RPC_ERROR_CODE.RUNTIME_BUSY,
|
|
8714
|
+
message: "runtime busy"
|
|
8715
|
+
});
|
|
7974
8716
|
return;
|
|
7975
8717
|
}
|
|
7976
8718
|
const clearSession = params?.clear_session ?? true;
|
|
@@ -7978,7 +8720,7 @@ var createRuntimeHandlers = ({
|
|
|
7978
8720
|
const supportsConfirm = !!state.uiCapabilities?.supports_confirm;
|
|
7979
8721
|
if (!supportsConfirm) {
|
|
7980
8722
|
sendError(id, {
|
|
7981
|
-
code:
|
|
8723
|
+
code: import_protocol9.RPC_ERROR_CODE.RUNTIME_INTERNAL,
|
|
7982
8724
|
message: "UI confirmation is required for logout"
|
|
7983
8725
|
});
|
|
7984
8726
|
return;
|
|
@@ -8020,7 +8762,7 @@ var createRuntimeHandlers = ({
|
|
|
8020
8762
|
log2(`auth.logout session_cleared=${clearSession}`);
|
|
8021
8763
|
} catch (error) {
|
|
8022
8764
|
sendError(id, {
|
|
8023
|
-
code:
|
|
8765
|
+
code: import_protocol9.RPC_ERROR_CODE.RUNTIME_INTERNAL,
|
|
8024
8766
|
message: `auth logout failed: ${String(error)}`
|
|
8025
8767
|
});
|
|
8026
8768
|
}
|
|
@@ -8045,6 +8787,8 @@ var createRuntimeHandlers = ({
|
|
|
8045
8787
|
return handleModelSet(req.id, req.params);
|
|
8046
8788
|
case "tool.call":
|
|
8047
8789
|
return handleToolCall(req.id, req.params);
|
|
8790
|
+
case "shell.exec":
|
|
8791
|
+
return handleShellExec(req.id, req.params);
|
|
8048
8792
|
case "mcp.list":
|
|
8049
8793
|
await mcpManager.start?.();
|
|
8050
8794
|
return sendResult(
|
|
@@ -8055,8 +8799,13 @@ var createRuntimeHandlers = ({
|
|
|
8055
8799
|
return handleSkillsList(req.id, req.params);
|
|
8056
8800
|
case "context.inspect":
|
|
8057
8801
|
return handleContextInspect(req.id, req.params);
|
|
8802
|
+
case "theme.set":
|
|
8803
|
+
return handleThemeSet(req.id, req.params);
|
|
8058
8804
|
default:
|
|
8059
|
-
return sendError(req.id, {
|
|
8805
|
+
return sendError(req.id, {
|
|
8806
|
+
code: import_protocol9.RPC_ERROR_CODE.METHOD_NOT_FOUND,
|
|
8807
|
+
message: "method not found"
|
|
8808
|
+
});
|
|
8060
8809
|
}
|
|
8061
8810
|
};
|
|
8062
8811
|
const handleNotification = (note) => {
|
|
@@ -8083,7 +8832,7 @@ var createRuntimeHandlers = ({
|
|
|
8083
8832
|
};
|
|
8084
8833
|
|
|
8085
8834
|
// src/runtime-state.ts
|
|
8086
|
-
var
|
|
8835
|
+
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
8087
8836
|
var RuntimeState = class {
|
|
8088
8837
|
runSeq = /* @__PURE__ */ new Map();
|
|
8089
8838
|
uiRequestCounter = 0;
|
|
@@ -8106,11 +8855,12 @@ var RuntimeState = class {
|
|
|
8106
8855
|
loadedSkillVersions = /* @__PURE__ */ new Map();
|
|
8107
8856
|
runtimeWorkingDir = null;
|
|
8108
8857
|
runtimeSandboxRoot = null;
|
|
8858
|
+
diagnosticsEnabled = false;
|
|
8109
8859
|
nextRunId() {
|
|
8110
|
-
return
|
|
8860
|
+
return import_node_crypto7.default.randomUUID();
|
|
8111
8861
|
}
|
|
8112
8862
|
nextSessionId() {
|
|
8113
|
-
return
|
|
8863
|
+
return import_node_crypto7.default.randomUUID();
|
|
8114
8864
|
}
|
|
8115
8865
|
beginRun(runId, uiContext) {
|
|
8116
8866
|
this.activeRunId = runId;
|
|
@@ -8199,13 +8949,19 @@ var RuntimeState = class {
|
|
|
8199
8949
|
};
|
|
8200
8950
|
|
|
8201
8951
|
// src/runtime.ts
|
|
8952
|
+
var envTruthy2 = (value) => {
|
|
8953
|
+
if (!value) return false;
|
|
8954
|
+
const normalized = value.trim().toLowerCase();
|
|
8955
|
+
return normalized === "1" || normalized === "true";
|
|
8956
|
+
};
|
|
8202
8957
|
var startRuntime = () => {
|
|
8203
8958
|
void (async () => {
|
|
8204
8959
|
const state = new RuntimeState();
|
|
8205
|
-
|
|
8960
|
+
state.diagnosticsEnabled = envTruthy2(process.env.CODELIA_DIAGNOSTICS);
|
|
8961
|
+
const workingDir = process.env.CODELIA_SANDBOX_ROOT ? import_node_path16.default.resolve(process.env.CODELIA_SANDBOX_ROOT) : process.cwd();
|
|
8206
8962
|
state.runtimeWorkingDir = workingDir;
|
|
8207
8963
|
state.runtimeSandboxRoot = workingDir;
|
|
8208
|
-
const sessionStateStore = new
|
|
8964
|
+
const sessionStateStore = new import_storage10.SessionStateStoreImpl({
|
|
8209
8965
|
onError: (error, context) => {
|
|
8210
8966
|
(0, import_logger.log)(
|
|
8211
8967
|
`Error: session-state ${context.action} error${context.detail ? ` (${context.detail})` : ""}: ${String(error)}`
|