@codelia/runtime 0.1.13 → 0.1.15
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.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/runtime.ts
|
|
2
|
-
import
|
|
2
|
+
import path16 from "path";
|
|
3
3
|
import { SessionStateStoreImpl as SessionStateStoreImpl2 } from "@codelia/storage";
|
|
4
4
|
|
|
5
5
|
// src/agent-factory.ts
|
|
@@ -659,10 +659,12 @@ var openBrowser = (url) => {
|
|
|
659
659
|
// src/config.ts
|
|
660
660
|
import { promises as fs2 } from "fs";
|
|
661
661
|
import path2 from "path";
|
|
662
|
-
import { configRegistry } from "@codelia/config";
|
|
662
|
+
import { CONFIG_GROUP_DEFAULT_WRITE_SCOPE, configRegistry } from "@codelia/config";
|
|
663
663
|
import {
|
|
664
664
|
appendPermissionAllowRules as appendPermissionAllowRulesAtPath,
|
|
665
|
-
loadConfig
|
|
665
|
+
loadConfig,
|
|
666
|
+
updateModelConfig,
|
|
667
|
+
updateTuiConfig
|
|
666
668
|
} from "@codelia/config-loader";
|
|
667
669
|
import { getDefaultSystemPromptPath } from "@codelia/core";
|
|
668
670
|
import { StoragePathServiceImpl } from "@codelia/storage";
|
|
@@ -672,6 +674,10 @@ var DEFAULT_SKILLS_INITIAL_MAX_ENTRIES = 200;
|
|
|
672
674
|
var DEFAULT_SKILLS_INITIAL_MAX_BYTES = 32 * 1024;
|
|
673
675
|
var DEFAULT_SKILLS_SEARCH_DEFAULT_LIMIT = 8;
|
|
674
676
|
var DEFAULT_SKILLS_SEARCH_MAX_LIMIT = 50;
|
|
677
|
+
var DEFAULT_SEARCH_MODE = "auto";
|
|
678
|
+
var DEFAULT_SEARCH_NATIVE_PROVIDERS = ["openai", "anthropic"];
|
|
679
|
+
var DEFAULT_SEARCH_LOCAL_BACKEND = "ddg";
|
|
680
|
+
var DEFAULT_SEARCH_BRAVE_API_KEY_ENV = "BRAVE_SEARCH_API_KEY";
|
|
675
681
|
var readEnvValue = (key) => {
|
|
676
682
|
const value = process.env[key];
|
|
677
683
|
if (!value) return void 0;
|
|
@@ -762,6 +768,45 @@ var resolveSkillsConfig = async (workingDir) => {
|
|
|
762
768
|
const effective = configRegistry.resolve([globalConfig, projectConfig]);
|
|
763
769
|
return normalizeSkillsConfig(effective.skills);
|
|
764
770
|
};
|
|
771
|
+
var normalizeSearchConfig = (value) => {
|
|
772
|
+
const mode = value?.mode === "auto" || value?.mode === "native" || value?.mode === "local" ? value.mode : DEFAULT_SEARCH_MODE;
|
|
773
|
+
const providersRaw = value?.native?.providers ?? [
|
|
774
|
+
...DEFAULT_SEARCH_NATIVE_PROVIDERS
|
|
775
|
+
];
|
|
776
|
+
const providers = Array.from(
|
|
777
|
+
new Set(
|
|
778
|
+
providersRaw.map((entry) => entry.trim()).filter((entry) => entry.length > 0)
|
|
779
|
+
)
|
|
780
|
+
);
|
|
781
|
+
const searchContextSize = value?.native?.search_context_size;
|
|
782
|
+
const allowedDomains = value?.native?.allowed_domains?.length ? value.native.allowed_domains.map((entry) => entry.trim()).filter((entry) => entry.length > 0) : void 0;
|
|
783
|
+
const userLocation = value?.native?.user_location ? {
|
|
784
|
+
...value.native.user_location.city ? { city: value.native.user_location.city } : {},
|
|
785
|
+
...value.native.user_location.country ? { country: value.native.user_location.country } : {},
|
|
786
|
+
...value.native.user_location.region ? { region: value.native.user_location.region } : {},
|
|
787
|
+
...value.native.user_location.timezone ? { timezone: value.native.user_location.timezone } : {}
|
|
788
|
+
} : void 0;
|
|
789
|
+
const backend = value?.local?.backend === "ddg" || value?.local?.backend === "brave" ? value.local.backend : DEFAULT_SEARCH_LOCAL_BACKEND;
|
|
790
|
+
const braveApiKeyEnv = value?.local?.brave_api_key_env?.trim() || DEFAULT_SEARCH_BRAVE_API_KEY_ENV;
|
|
791
|
+
return {
|
|
792
|
+
mode,
|
|
793
|
+
native: {
|
|
794
|
+
providers: providers.length ? providers : [...DEFAULT_SEARCH_NATIVE_PROVIDERS],
|
|
795
|
+
...searchContextSize ? { searchContextSize } : {},
|
|
796
|
+
...allowedDomains && allowedDomains.length ? { allowedDomains } : {},
|
|
797
|
+
...userLocation && Object.keys(userLocation).length ? { userLocation } : {}
|
|
798
|
+
},
|
|
799
|
+
local: {
|
|
800
|
+
backend,
|
|
801
|
+
braveApiKeyEnv
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
};
|
|
805
|
+
var resolveSearchConfig = async (workingDir) => {
|
|
806
|
+
const { globalConfig, projectConfig } = await loadConfigLayers(workingDir);
|
|
807
|
+
const effective = configRegistry.resolve([globalConfig, projectConfig]);
|
|
808
|
+
return normalizeSearchConfig(effective.search);
|
|
809
|
+
};
|
|
765
810
|
var normalizeMcpTimeoutMs = (value) => {
|
|
766
811
|
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
767
812
|
return DEFAULT_MCP_REQUEST_TIMEOUT_MS;
|
|
@@ -797,6 +842,44 @@ var appendPermissionAllowRules = async (workingDir, rules) => {
|
|
|
797
842
|
const configPath = resolveProjectConfigPath(workingDir);
|
|
798
843
|
await appendPermissionAllowRulesAtPath(configPath, rules);
|
|
799
844
|
};
|
|
845
|
+
var hasDefinedGroup = (group, value) => {
|
|
846
|
+
switch (group) {
|
|
847
|
+
case "model":
|
|
848
|
+
return typeof value?.model?.name === "string" && value.model.name.trim().length > 0;
|
|
849
|
+
case "permissions":
|
|
850
|
+
return Array.isArray(value?.permissions?.allow) || Array.isArray(value?.permissions?.deny);
|
|
851
|
+
case "tui":
|
|
852
|
+
return typeof value?.tui?.theme === "string" && value.tui.theme.trim().length > 0;
|
|
853
|
+
default:
|
|
854
|
+
return false;
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
var resolveWriteTarget = async (workingDir, group) => {
|
|
858
|
+
const globalPath = resolveConfigPath();
|
|
859
|
+
const projectPath = resolveProjectConfigPath(workingDir);
|
|
860
|
+
const [globalConfig, projectConfig] = await Promise.all([
|
|
861
|
+
loadConfig(globalPath),
|
|
862
|
+
loadConfig(projectPath)
|
|
863
|
+
]);
|
|
864
|
+
if (hasDefinedGroup(group, projectConfig)) {
|
|
865
|
+
return { scope: "project", path: projectPath };
|
|
866
|
+
}
|
|
867
|
+
if (hasDefinedGroup(group, globalConfig)) {
|
|
868
|
+
return { scope: "global", path: globalPath };
|
|
869
|
+
}
|
|
870
|
+
const defaultScope = CONFIG_GROUP_DEFAULT_WRITE_SCOPE[group];
|
|
871
|
+
return defaultScope === "project" ? { scope: "project", path: projectPath } : { scope: "global", path: globalPath };
|
|
872
|
+
};
|
|
873
|
+
var updateModel = async (workingDir, model) => {
|
|
874
|
+
const target = await resolveWriteTarget(workingDir, "model");
|
|
875
|
+
await updateModelConfig(target.path, model);
|
|
876
|
+
return target;
|
|
877
|
+
};
|
|
878
|
+
var updateTuiTheme = async (workingDir, theme) => {
|
|
879
|
+
const target = await resolveWriteTarget(workingDir, "tui");
|
|
880
|
+
await updateTuiConfig(target.path, { theme });
|
|
881
|
+
return target;
|
|
882
|
+
};
|
|
800
883
|
var resolveReasoningEffort = (value) => {
|
|
801
884
|
return resolveModelLevelOption(value, "model.reasoning");
|
|
802
885
|
};
|
|
@@ -945,6 +1028,14 @@ var sendRunContext = (runId, contextLeftPercent) => {
|
|
|
945
1028
|
};
|
|
946
1029
|
send(notify);
|
|
947
1030
|
};
|
|
1031
|
+
var sendRunDiagnostics = (params) => {
|
|
1032
|
+
const notify = {
|
|
1033
|
+
jsonrpc: "2.0",
|
|
1034
|
+
method: "run.diagnostics",
|
|
1035
|
+
params
|
|
1036
|
+
};
|
|
1037
|
+
send(notify);
|
|
1038
|
+
};
|
|
948
1039
|
|
|
949
1040
|
// src/rpc/ui-requests.ts
|
|
950
1041
|
var requestUi = async (state, method, params) => {
|
|
@@ -4190,17 +4281,176 @@ ${reason} Use offset to read beyond line ${lastReadLine}.`;
|
|
|
4190
4281
|
}
|
|
4191
4282
|
});
|
|
4192
4283
|
|
|
4193
|
-
// src/tools/
|
|
4284
|
+
// src/tools/search.ts
|
|
4194
4285
|
import { defineTool as defineTool9 } from "@codelia/core";
|
|
4195
4286
|
import { z as z10 } from "zod";
|
|
4196
|
-
var
|
|
4197
|
-
|
|
4198
|
-
|
|
4287
|
+
var normalizeDomain = (value) => value.trim().toLowerCase().replace(/\.+$/, "");
|
|
4288
|
+
var shouldKeepUrl = (url, allowedDomains) => {
|
|
4289
|
+
if (!allowedDomains.length) return true;
|
|
4290
|
+
try {
|
|
4291
|
+
const parsed = new URL(url);
|
|
4292
|
+
const host = parsed.hostname.toLowerCase();
|
|
4293
|
+
return allowedDomains.some((domain) => {
|
|
4294
|
+
const normalized = normalizeDomain(domain);
|
|
4295
|
+
return host === normalized || host.endsWith(`.${normalized}`);
|
|
4296
|
+
});
|
|
4297
|
+
} catch {
|
|
4298
|
+
return false;
|
|
4299
|
+
}
|
|
4300
|
+
};
|
|
4301
|
+
var normalizeEntries = (entries, allowedDomains, maxResults) => {
|
|
4302
|
+
return entries.filter((entry) => shouldKeepUrl(entry.url, allowedDomains)).slice(0, maxResults);
|
|
4303
|
+
};
|
|
4304
|
+
var parseDdg = (payload) => {
|
|
4305
|
+
const results = [];
|
|
4306
|
+
if (!payload || typeof payload !== "object") {
|
|
4307
|
+
return results;
|
|
4308
|
+
}
|
|
4309
|
+
const record = payload;
|
|
4310
|
+
const related = Array.isArray(record.RelatedTopics) ? record.RelatedTopics : [];
|
|
4311
|
+
for (const topic of related) {
|
|
4312
|
+
if (!topic || typeof topic !== "object") {
|
|
4313
|
+
continue;
|
|
4314
|
+
}
|
|
4315
|
+
const typed = topic;
|
|
4316
|
+
if (Array.isArray(typed.Topics)) {
|
|
4317
|
+
for (const child of typed.Topics) {
|
|
4318
|
+
if (!child || typeof child !== "object") continue;
|
|
4319
|
+
const row = child;
|
|
4320
|
+
const text2 = typeof row.Text === "string" ? row.Text : "";
|
|
4321
|
+
const url2 = typeof row.FirstURL === "string" ? row.FirstURL : "";
|
|
4322
|
+
if (!text2 || !url2) continue;
|
|
4323
|
+
results.push({
|
|
4324
|
+
title: text2.split(" - ")[0] ?? text2,
|
|
4325
|
+
url: url2,
|
|
4326
|
+
snippet: text2,
|
|
4327
|
+
source: "ddg"
|
|
4328
|
+
});
|
|
4329
|
+
}
|
|
4330
|
+
continue;
|
|
4331
|
+
}
|
|
4332
|
+
const text = typeof typed.Text === "string" ? typed.Text : "";
|
|
4333
|
+
const url = typeof typed.FirstURL === "string" ? typed.FirstURL : "";
|
|
4334
|
+
if (!text || !url) continue;
|
|
4335
|
+
results.push({
|
|
4336
|
+
title: text.split(" - ")[0] ?? text,
|
|
4337
|
+
url,
|
|
4338
|
+
snippet: text,
|
|
4339
|
+
source: "ddg"
|
|
4340
|
+
});
|
|
4341
|
+
}
|
|
4342
|
+
return results;
|
|
4343
|
+
};
|
|
4344
|
+
var parseBrave = (payload) => {
|
|
4345
|
+
const results = [];
|
|
4346
|
+
if (!payload || typeof payload !== "object") {
|
|
4347
|
+
return results;
|
|
4348
|
+
}
|
|
4349
|
+
const record = payload;
|
|
4350
|
+
const web = record.web;
|
|
4351
|
+
if (!web || typeof web !== "object") {
|
|
4352
|
+
return results;
|
|
4353
|
+
}
|
|
4354
|
+
const rows = Array.isArray(web.results) ? web.results : [];
|
|
4355
|
+
for (const row of rows) {
|
|
4356
|
+
if (!row || typeof row !== "object") continue;
|
|
4357
|
+
const typed = row;
|
|
4358
|
+
const title = typeof typed.title === "string" ? typed.title : "";
|
|
4359
|
+
const url = typeof typed.url === "string" ? typed.url : "";
|
|
4360
|
+
const snippet = typeof typed.description === "string" ? typed.description : "";
|
|
4361
|
+
if (!title || !url) continue;
|
|
4362
|
+
results.push({
|
|
4363
|
+
title,
|
|
4364
|
+
url,
|
|
4365
|
+
snippet,
|
|
4366
|
+
source: "brave"
|
|
4367
|
+
});
|
|
4368
|
+
}
|
|
4369
|
+
return results;
|
|
4370
|
+
};
|
|
4371
|
+
var runDdgSearch = async (query, maxResults, allowedDomains) => {
|
|
4372
|
+
const url = new URL("https://api.duckduckgo.com/");
|
|
4373
|
+
url.searchParams.set("q", query);
|
|
4374
|
+
url.searchParams.set("format", "json");
|
|
4375
|
+
url.searchParams.set("no_html", "1");
|
|
4376
|
+
url.searchParams.set("skip_disambig", "1");
|
|
4377
|
+
const response = await fetch(url);
|
|
4378
|
+
if (!response.ok) {
|
|
4379
|
+
throw new Error(`ddg request failed: status=${response.status}`);
|
|
4380
|
+
}
|
|
4381
|
+
const payload = await response.json();
|
|
4382
|
+
const parsed = parseDdg(payload);
|
|
4383
|
+
return normalizeEntries(parsed, allowedDomains, maxResults);
|
|
4384
|
+
};
|
|
4385
|
+
var runBraveSearch = async (query, maxResults, allowedDomains, apiKey) => {
|
|
4386
|
+
const url = new URL("https://api.search.brave.com/res/v1/web/search");
|
|
4387
|
+
url.searchParams.set("q", query);
|
|
4388
|
+
url.searchParams.set("count", String(maxResults));
|
|
4389
|
+
const response = await fetch(url, {
|
|
4390
|
+
headers: {
|
|
4391
|
+
Accept: "application/json",
|
|
4392
|
+
"X-Subscription-Token": apiKey
|
|
4393
|
+
}
|
|
4394
|
+
});
|
|
4395
|
+
if (!response.ok) {
|
|
4396
|
+
throw new Error(`brave request failed: status=${response.status}`);
|
|
4397
|
+
}
|
|
4398
|
+
const payload = await response.json();
|
|
4399
|
+
const parsed = parseBrave(payload);
|
|
4400
|
+
return normalizeEntries(parsed, allowedDomains, maxResults);
|
|
4401
|
+
};
|
|
4402
|
+
var createSearchTool = (options) => defineTool9({
|
|
4403
|
+
name: "search",
|
|
4404
|
+
description: "Search the web and return concise source candidates.",
|
|
4405
|
+
input: z10.object({
|
|
4406
|
+
query: z10.string().min(1).describe("Search query."),
|
|
4407
|
+
max_results: z10.number().int().min(1).max(20).optional().describe("Max results. Default 5."),
|
|
4408
|
+
backend: z10.enum(["ddg", "brave"]).optional().describe("Search backend. Default comes from config."),
|
|
4409
|
+
allowed_domains: z10.array(z10.string().min(1)).optional().describe("Optional allowlist of domains.")
|
|
4410
|
+
}),
|
|
4411
|
+
execute: async (input) => {
|
|
4412
|
+
const backend = input.backend ?? options.defaultBackend;
|
|
4413
|
+
const maxResults = input.max_results ?? 5;
|
|
4414
|
+
const allowedDomains = input.allowed_domains?.map((entry) => entry.trim()).filter((entry) => entry.length > 0) ?? [];
|
|
4415
|
+
try {
|
|
4416
|
+
let results;
|
|
4417
|
+
if (backend === "ddg") {
|
|
4418
|
+
results = await runDdgSearch(input.query, maxResults, allowedDomains);
|
|
4419
|
+
} else {
|
|
4420
|
+
const apiKey = process.env[options.braveApiKeyEnv]?.trim();
|
|
4421
|
+
if (!apiKey) {
|
|
4422
|
+
return `Missing ${options.braveApiKeyEnv} for brave backend.`;
|
|
4423
|
+
}
|
|
4424
|
+
results = await runBraveSearch(
|
|
4425
|
+
input.query,
|
|
4426
|
+
maxResults,
|
|
4427
|
+
allowedDomains,
|
|
4428
|
+
apiKey
|
|
4429
|
+
);
|
|
4430
|
+
}
|
|
4431
|
+
return {
|
|
4432
|
+
query: input.query,
|
|
4433
|
+
backend,
|
|
4434
|
+
count: results.length,
|
|
4435
|
+
results
|
|
4436
|
+
};
|
|
4437
|
+
} catch (error) {
|
|
4438
|
+
return `Error running search: ${String(error)}`;
|
|
4439
|
+
}
|
|
4440
|
+
}
|
|
4441
|
+
});
|
|
4442
|
+
|
|
4443
|
+
// src/tools/skill-load.ts
|
|
4444
|
+
import { defineTool as defineTool10 } from "@codelia/core";
|
|
4445
|
+
import { z as z11 } from "zod";
|
|
4446
|
+
var SkillLoadInputSchema = z11.object({
|
|
4447
|
+
name: z11.string().min(1).optional().describe("Exact skill name to load."),
|
|
4448
|
+
path: z11.string().min(1).optional().describe("Absolute or workspace-relative path to SKILL.md.")
|
|
4199
4449
|
}).refine((value) => !!value.name || !!value.path, {
|
|
4200
4450
|
message: "name or path is required",
|
|
4201
4451
|
path: ["name"]
|
|
4202
4452
|
});
|
|
4203
|
-
var createSkillLoadTool = (skillsResolverKey) =>
|
|
4453
|
+
var createSkillLoadTool = (skillsResolverKey) => defineTool10({
|
|
4204
4454
|
name: "skill_load",
|
|
4205
4455
|
description: "Load full SKILL.md content by exact name or path.",
|
|
4206
4456
|
input: SkillLoadInputSchema,
|
|
@@ -4246,15 +4496,15 @@ var createSkillLoadTool = (skillsResolverKey) => defineTool9({
|
|
|
4246
4496
|
});
|
|
4247
4497
|
|
|
4248
4498
|
// src/tools/skill-search.ts
|
|
4249
|
-
import { defineTool as
|
|
4250
|
-
import { z as
|
|
4251
|
-
var createSkillSearchTool = (skillsResolverKey) =>
|
|
4499
|
+
import { defineTool as defineTool11 } from "@codelia/core";
|
|
4500
|
+
import { z as z12 } from "zod";
|
|
4501
|
+
var createSkillSearchTool = (skillsResolverKey) => defineTool11({
|
|
4252
4502
|
name: "skill_search",
|
|
4253
4503
|
description: "Search installed local skills by name, description, or path.",
|
|
4254
|
-
input:
|
|
4255
|
-
query:
|
|
4256
|
-
limit:
|
|
4257
|
-
scope:
|
|
4504
|
+
input: z12.object({
|
|
4505
|
+
query: z12.string().min(1).describe("Search query text."),
|
|
4506
|
+
limit: z12.number().int().positive().optional().describe("Optional max result count (clamped by config)."),
|
|
4507
|
+
scope: z12.enum(["repo", "user"]).optional().describe("Optional scope filter.")
|
|
4258
4508
|
}),
|
|
4259
4509
|
execute: async (input, ctx) => {
|
|
4260
4510
|
try {
|
|
@@ -4277,17 +4527,17 @@ var createSkillSearchTool = (skillsResolverKey) => defineTool10({
|
|
|
4277
4527
|
});
|
|
4278
4528
|
|
|
4279
4529
|
// src/tools/todo-read.ts
|
|
4280
|
-
import { defineTool as
|
|
4281
|
-
import { z as
|
|
4530
|
+
import { defineTool as defineTool12 } from "@codelia/core";
|
|
4531
|
+
import { z as z13 } from "zod";
|
|
4282
4532
|
|
|
4283
4533
|
// src/tools/todo-store.ts
|
|
4284
4534
|
var todoStore = /* @__PURE__ */ new Map();
|
|
4285
4535
|
|
|
4286
4536
|
// src/tools/todo-read.ts
|
|
4287
|
-
var createTodoReadTool = (sandboxKey) =>
|
|
4537
|
+
var createTodoReadTool = (sandboxKey) => defineTool12({
|
|
4288
4538
|
name: "todo_read",
|
|
4289
4539
|
description: "Read the in-session todo list.",
|
|
4290
|
-
input:
|
|
4540
|
+
input: z13.object({}),
|
|
4291
4541
|
execute: async (_input, ctx) => {
|
|
4292
4542
|
const sandbox = await getSandboxContext(ctx, sandboxKey);
|
|
4293
4543
|
const todos = todoStore.get(sandbox.sessionId) ?? [];
|
|
@@ -4300,17 +4550,17 @@ var createTodoReadTool = (sandboxKey) => defineTool11({
|
|
|
4300
4550
|
});
|
|
4301
4551
|
|
|
4302
4552
|
// src/tools/todo-write.ts
|
|
4303
|
-
import { defineTool as
|
|
4304
|
-
import { z as
|
|
4305
|
-
var createTodoWriteTool = (sandboxKey) =>
|
|
4553
|
+
import { defineTool as defineTool13 } from "@codelia/core";
|
|
4554
|
+
import { z as z14 } from "zod";
|
|
4555
|
+
var createTodoWriteTool = (sandboxKey) => defineTool13({
|
|
4306
4556
|
name: "todo_write",
|
|
4307
4557
|
description: "Replace the in-session todo list.",
|
|
4308
|
-
input:
|
|
4309
|
-
todos:
|
|
4310
|
-
|
|
4311
|
-
content:
|
|
4312
|
-
status:
|
|
4313
|
-
activeForm:
|
|
4558
|
+
input: z14.object({
|
|
4559
|
+
todos: z14.array(
|
|
4560
|
+
z14.object({
|
|
4561
|
+
content: z14.string().describe("Todo item text."),
|
|
4562
|
+
status: z14.enum(["pending", "in_progress", "completed"]).describe("Todo status."),
|
|
4563
|
+
activeForm: z14.string().optional().describe("Optional in-progress phrasing for UI display.")
|
|
4314
4564
|
})
|
|
4315
4565
|
)
|
|
4316
4566
|
}),
|
|
@@ -4327,15 +4577,15 @@ var createTodoWriteTool = (sandboxKey) => defineTool12({
|
|
|
4327
4577
|
});
|
|
4328
4578
|
|
|
4329
4579
|
// src/tools/tool-output-cache.ts
|
|
4330
|
-
import { defineTool as
|
|
4331
|
-
import { z as
|
|
4332
|
-
var createToolOutputCacheTool = (store) =>
|
|
4580
|
+
import { defineTool as defineTool14 } from "@codelia/core";
|
|
4581
|
+
import { z as z15 } from "zod";
|
|
4582
|
+
var createToolOutputCacheTool = (store) => defineTool14({
|
|
4333
4583
|
name: "tool_output_cache",
|
|
4334
4584
|
description: "Read cached tool output by ref_id.",
|
|
4335
|
-
input:
|
|
4336
|
-
ref_id:
|
|
4337
|
-
offset:
|
|
4338
|
-
limit:
|
|
4585
|
+
input: z15.object({
|
|
4586
|
+
ref_id: z15.string().describe("Tool output reference ID."),
|
|
4587
|
+
offset: z15.number().int().nonnegative().optional().describe("Optional 0-based line offset."),
|
|
4588
|
+
limit: z15.number().int().positive().optional().describe("Optional max number of lines to return.")
|
|
4339
4589
|
}),
|
|
4340
4590
|
execute: async (input) => {
|
|
4341
4591
|
if (!store.read) {
|
|
@@ -4351,16 +4601,16 @@ var createToolOutputCacheTool = (store) => defineTool13({
|
|
|
4351
4601
|
}
|
|
4352
4602
|
}
|
|
4353
4603
|
});
|
|
4354
|
-
var createToolOutputCacheGrepTool = (store) =>
|
|
4604
|
+
var createToolOutputCacheGrepTool = (store) => defineTool14({
|
|
4355
4605
|
name: "tool_output_cache_grep",
|
|
4356
4606
|
description: "Search cached tool output by ref_id.",
|
|
4357
|
-
input:
|
|
4358
|
-
ref_id:
|
|
4359
|
-
pattern:
|
|
4360
|
-
regex:
|
|
4361
|
-
before:
|
|
4362
|
-
after:
|
|
4363
|
-
max_matches:
|
|
4607
|
+
input: z15.object({
|
|
4608
|
+
ref_id: z15.string().describe("Tool output reference ID."),
|
|
4609
|
+
pattern: z15.string().describe("Text or regex pattern to search for."),
|
|
4610
|
+
regex: z15.boolean().optional().describe("Interpret pattern as regex when true. Default false."),
|
|
4611
|
+
before: z15.number().int().nonnegative().optional().describe("Context lines before each match. Default 0."),
|
|
4612
|
+
after: z15.number().int().nonnegative().optional().describe("Context lines after each match. Default 0."),
|
|
4613
|
+
max_matches: z15.number().int().positive().optional().describe("Maximum number of matches to return.")
|
|
4364
4614
|
}),
|
|
4365
4615
|
execute: async (input) => {
|
|
4366
4616
|
if (!store.grep) {
|
|
@@ -4383,14 +4633,14 @@ var createToolOutputCacheGrepTool = (store) => defineTool13({
|
|
|
4383
4633
|
// src/tools/write.ts
|
|
4384
4634
|
import { promises as fs13 } from "fs";
|
|
4385
4635
|
import path12 from "path";
|
|
4386
|
-
import { defineTool as
|
|
4387
|
-
import { z as
|
|
4388
|
-
var createWriteTool = (sandboxKey) =>
|
|
4636
|
+
import { defineTool as defineTool15 } from "@codelia/core";
|
|
4637
|
+
import { z as z16 } from "zod";
|
|
4638
|
+
var createWriteTool = (sandboxKey) => defineTool15({
|
|
4389
4639
|
name: "write",
|
|
4390
4640
|
description: "Write text to a file, creating parent directories if needed.",
|
|
4391
|
-
input:
|
|
4392
|
-
file_path:
|
|
4393
|
-
content:
|
|
4641
|
+
input: z16.object({
|
|
4642
|
+
file_path: z16.string().describe("File path under the sandbox root."),
|
|
4643
|
+
content: z16.string().describe("UTF-8 text content to write.")
|
|
4394
4644
|
}),
|
|
4395
4645
|
execute: async (input, ctx) => {
|
|
4396
4646
|
let resolved;
|
|
@@ -4419,6 +4669,7 @@ var createTools = (sandboxKey, agentsResolverKey, skillsResolverKey, options = {
|
|
|
4419
4669
|
createAgentsResolveTool(sandboxKey, agentsResolverKey),
|
|
4420
4670
|
createSkillSearchTool(skillsResolverKey),
|
|
4421
4671
|
createSkillLoadTool(skillsResolverKey),
|
|
4672
|
+
...options.search ? [createSearchTool(options.search)] : [],
|
|
4422
4673
|
createGlobSearchTool(sandboxKey),
|
|
4423
4674
|
createGrepTool(sandboxKey),
|
|
4424
4675
|
...options.toolOutputCacheStore ? [
|
|
@@ -4467,9 +4718,9 @@ var normalizeLanguage = (value) => {
|
|
|
4467
4718
|
};
|
|
4468
4719
|
var languageFromFilePath = (filePath) => {
|
|
4469
4720
|
if (!filePath) return void 0;
|
|
4470
|
-
const
|
|
4471
|
-
if (!
|
|
4472
|
-
const normalizedPath =
|
|
4721
|
+
const path17 = filePath.trim().replace(/^["']|["']$/g, "");
|
|
4722
|
+
if (!path17 || path17 === "/dev/null") return void 0;
|
|
4723
|
+
const normalizedPath = path17.replace(/^a\//, "").replace(/^b\//, "");
|
|
4473
4724
|
const lastSlash = Math.max(
|
|
4474
4725
|
normalizedPath.lastIndexOf("/"),
|
|
4475
4726
|
normalizedPath.lastIndexOf("\\")
|
|
@@ -4540,6 +4791,25 @@ var envTruthy = (value) => {
|
|
|
4540
4791
|
return normalized === "1" || normalized === "true";
|
|
4541
4792
|
};
|
|
4542
4793
|
var OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
|
|
4794
|
+
var isNativeSearchProvider = (provider, allowedProviders) => allowedProviders.includes(provider);
|
|
4795
|
+
var buildHostedSearchToolDefinitions = (provider, options) => {
|
|
4796
|
+
if (options.mode === "local" || !isNativeSearchProvider(provider, options.native.providers)) {
|
|
4797
|
+
return [];
|
|
4798
|
+
}
|
|
4799
|
+
if (provider !== "openai" && provider !== "anthropic") {
|
|
4800
|
+
return [];
|
|
4801
|
+
}
|
|
4802
|
+
return [
|
|
4803
|
+
{
|
|
4804
|
+
type: "hosted_search",
|
|
4805
|
+
name: "web_search",
|
|
4806
|
+
provider,
|
|
4807
|
+
...options.native.searchContextSize ? { search_context_size: options.native.searchContextSize } : {},
|
|
4808
|
+
...options.native.allowedDomains ? { allowed_domains: options.native.allowedDomains } : {},
|
|
4809
|
+
...options.native.userLocation ? { user_location: options.native.userLocation } : {}
|
|
4810
|
+
}
|
|
4811
|
+
];
|
|
4812
|
+
};
|
|
4543
4813
|
var buildOpenAiClientOptions = (authResolver, auth) => {
|
|
4544
4814
|
if (auth.method === "api_key") {
|
|
4545
4815
|
return { apiKey: auth.api_key };
|
|
@@ -4776,7 +5046,7 @@ var createAgentFactory = (state, options = {}) => {
|
|
|
4776
5046
|
const agentsResolverKey = createAgentsResolverKey(agentsResolver);
|
|
4777
5047
|
const skillsResolverKey = createSkillsResolverKey(skillsResolver);
|
|
4778
5048
|
const toolOutputCacheStore = new ToolOutputCacheStoreImpl();
|
|
4779
|
-
const
|
|
5049
|
+
const baseLocalTools = createTools(
|
|
4780
5050
|
sandboxKey,
|
|
4781
5051
|
agentsResolverKey,
|
|
4782
5052
|
skillsResolverKey,
|
|
@@ -4784,7 +5054,7 @@ var createAgentFactory = (state, options = {}) => {
|
|
|
4784
5054
|
toolOutputCacheStore
|
|
4785
5055
|
}
|
|
4786
5056
|
);
|
|
4787
|
-
const editTool =
|
|
5057
|
+
const editTool = baseLocalTools.find(
|
|
4788
5058
|
(tool) => tool.definition.name === "edit"
|
|
4789
5059
|
);
|
|
4790
5060
|
let mcpTools = [];
|
|
@@ -4807,9 +5077,6 @@ var createAgentFactory = (state, options = {}) => {
|
|
|
4807
5077
|
log(`failed to load mcp tools: ${String(error)}`);
|
|
4808
5078
|
}
|
|
4809
5079
|
}
|
|
4810
|
-
const tools = [...localTools, ...mcpTools];
|
|
4811
|
-
state.tools = tools;
|
|
4812
|
-
state.toolDefinitions = tools.map((tool) => tool.definition);
|
|
4813
5080
|
const baseSystemPrompt = await loadSystemPrompt(ctx.workingDir);
|
|
4814
5081
|
const withAgentsContext = appendInitialAgentsContext(
|
|
4815
5082
|
baseSystemPrompt,
|
|
@@ -4845,6 +5112,29 @@ var createAgentFactory = (state, options = {}) => {
|
|
|
4845
5112
|
const authResolver = await AuthResolver.create(state, log);
|
|
4846
5113
|
const provider = await authResolver.resolveProvider(modelConfig.provider);
|
|
4847
5114
|
const providerAuth = await authResolver.resolveProviderAuth(provider);
|
|
5115
|
+
const searchConfig = await resolveSearchConfig(ctx.workingDir);
|
|
5116
|
+
const hostedSearchDefinitions = buildHostedSearchToolDefinitions(
|
|
5117
|
+
provider,
|
|
5118
|
+
searchConfig
|
|
5119
|
+
);
|
|
5120
|
+
if (searchConfig.mode === "native" && hostedSearchDefinitions.length === 0) {
|
|
5121
|
+
throw new Error(
|
|
5122
|
+
`search.mode=native is enabled, but native search is unavailable for provider '${provider}'.`
|
|
5123
|
+
);
|
|
5124
|
+
}
|
|
5125
|
+
const useLocalSearchTool = searchConfig.mode === "local" || searchConfig.mode === "auto" && hostedSearchDefinitions.length === 0;
|
|
5126
|
+
const localSearchTools = useLocalSearchTool ? [
|
|
5127
|
+
createSearchTool({
|
|
5128
|
+
defaultBackend: searchConfig.local.backend,
|
|
5129
|
+
braveApiKeyEnv: searchConfig.local.braveApiKeyEnv
|
|
5130
|
+
})
|
|
5131
|
+
] : [];
|
|
5132
|
+
const tools = [...baseLocalTools, ...localSearchTools, ...mcpTools];
|
|
5133
|
+
state.tools = tools;
|
|
5134
|
+
state.toolDefinitions = [
|
|
5135
|
+
...tools.map((tool) => tool.definition),
|
|
5136
|
+
...hostedSearchDefinitions
|
|
5137
|
+
];
|
|
4848
5138
|
let llm;
|
|
4849
5139
|
switch (provider) {
|
|
4850
5140
|
case "openai": {
|
|
@@ -4884,11 +5174,18 @@ var createAgentFactory = (state, options = {}) => {
|
|
|
4884
5174
|
const modelRegistry = await buildModelRegistry(llm, {
|
|
4885
5175
|
strict: provider !== "openrouter"
|
|
4886
5176
|
});
|
|
5177
|
+
const totalBudgetTrimEnabled = envTruthy(
|
|
5178
|
+
process.env.CODELIA_TOOL_OUTPUT_TOTAL_TRIM
|
|
5179
|
+
);
|
|
4887
5180
|
const agent = new Agent({
|
|
4888
5181
|
llm,
|
|
4889
5182
|
tools,
|
|
5183
|
+
hostedTools: hostedSearchDefinitions,
|
|
4890
5184
|
systemPrompt,
|
|
4891
5185
|
modelRegistry: modelRegistry ?? DEFAULT_MODEL_REGISTRY2,
|
|
5186
|
+
toolOutputCache: {
|
|
5187
|
+
totalBudgetTrim: totalBudgetTrimEnabled
|
|
5188
|
+
},
|
|
4892
5189
|
services: { toolOutputCacheStore },
|
|
4893
5190
|
canExecuteTool: async (call, rawArgs, toolCtx) => {
|
|
4894
5191
|
const decision = permissionService.evaluate(
|
|
@@ -5599,8 +5896,8 @@ var parseAuthorizationServerMetadata = (value) => {
|
|
|
5599
5896
|
var buildAuthorizationServerMetadataUrl = (issuer) => {
|
|
5600
5897
|
try {
|
|
5601
5898
|
const parsed = new URL(issuer);
|
|
5602
|
-
const
|
|
5603
|
-
const basePath =
|
|
5899
|
+
const path17 = parsed.pathname === "/" ? "" : parsed.pathname;
|
|
5900
|
+
const basePath = path17.startsWith("/") ? path17 : `/${path17}`;
|
|
5604
5901
|
const metadataPath = `/.well-known/oauth-authorization-server${basePath}`;
|
|
5605
5902
|
return new URL(metadataPath, `${parsed.origin}/`).toString();
|
|
5606
5903
|
} catch {
|
|
@@ -6257,9 +6554,8 @@ var McpManager = class {
|
|
|
6257
6554
|
};
|
|
6258
6555
|
|
|
6259
6556
|
// src/rpc/handlers.ts
|
|
6260
|
-
import { updateModelConfig as updateModelConfig2 } from "@codelia/config-loader";
|
|
6261
6557
|
import {
|
|
6262
|
-
RPC_ERROR_CODE as
|
|
6558
|
+
RPC_ERROR_CODE as RPC_ERROR_CODE8
|
|
6263
6559
|
} from "@codelia/protocol";
|
|
6264
6560
|
import {
|
|
6265
6561
|
RunEventStoreFactoryImpl,
|
|
@@ -6644,7 +6940,6 @@ var createHistoryHandlers = ({
|
|
|
6644
6940
|
};
|
|
6645
6941
|
|
|
6646
6942
|
// src/rpc/model.ts
|
|
6647
|
-
import { updateModelConfig } from "@codelia/config-loader";
|
|
6648
6943
|
import {
|
|
6649
6944
|
DEFAULT_MODEL_REGISTRY as DEFAULT_MODEL_REGISTRY3,
|
|
6650
6945
|
listModels,
|
|
@@ -6999,12 +7294,12 @@ var createModelHandlers = ({
|
|
|
6999
7294
|
}
|
|
7000
7295
|
}
|
|
7001
7296
|
try {
|
|
7002
|
-
const
|
|
7003
|
-
await
|
|
7297
|
+
const workingDir = state.lastUiContext?.cwd ?? state.runtimeWorkingDir ?? process.cwd();
|
|
7298
|
+
const target = await updateModel(workingDir, { provider, name });
|
|
7004
7299
|
state.agent = null;
|
|
7005
7300
|
const result = { provider, name };
|
|
7006
7301
|
sendResult(id, result);
|
|
7007
|
-
log2(`model.set ${provider}/${name}`);
|
|
7302
|
+
log2(`model.set ${provider}/${name} scope=${target.scope} path=${target.path}`);
|
|
7008
7303
|
} catch (error) {
|
|
7009
7304
|
sendError(id, { code: RPC_ERROR_CODE3.RUNTIME_INTERNAL, message: String(error) });
|
|
7010
7305
|
}
|
|
@@ -7317,6 +7612,28 @@ var buildSessionState = (sessionId, runId, messages, invokeSeq) => ({
|
|
|
7317
7612
|
invoke_seq: invokeSeq,
|
|
7318
7613
|
messages
|
|
7319
7614
|
});
|
|
7615
|
+
var toTimestampMs = (value) => {
|
|
7616
|
+
const ms = Date.parse(value);
|
|
7617
|
+
return Number.isFinite(ms) ? ms : null;
|
|
7618
|
+
};
|
|
7619
|
+
var summarizeProviderMeta = (value) => {
|
|
7620
|
+
if (value === null || value === void 0) {
|
|
7621
|
+
return null;
|
|
7622
|
+
}
|
|
7623
|
+
if (typeof value === "string") {
|
|
7624
|
+
return value.length > 80 ? `${value.slice(0, 77)}...` : value;
|
|
7625
|
+
}
|
|
7626
|
+
if (Array.isArray(value)) {
|
|
7627
|
+
return `array(len=${value.length})`;
|
|
7628
|
+
}
|
|
7629
|
+
if (typeof value === "object") {
|
|
7630
|
+
const keys = Object.keys(value);
|
|
7631
|
+
if (keys.length === 0) return "object";
|
|
7632
|
+
const shown = keys.slice(0, 4).join(",");
|
|
7633
|
+
return keys.length > 4 ? `object(keys=${shown},...)` : `object(keys=${shown})`;
|
|
7634
|
+
}
|
|
7635
|
+
return typeof value;
|
|
7636
|
+
};
|
|
7320
7637
|
var createRunHandlers = ({
|
|
7321
7638
|
state,
|
|
7322
7639
|
getAgent,
|
|
@@ -7450,12 +7767,77 @@ var createRunHandlers = ({
|
|
|
7450
7767
|
const runAbortController = new AbortController();
|
|
7451
7768
|
activeRunAbort = { runId, controller: runAbortController };
|
|
7452
7769
|
const sessionStore = runEventStoreFactory.create({ runId, startedAt });
|
|
7453
|
-
const
|
|
7770
|
+
const sessionAppenderRaw = createSessionAppender(
|
|
7454
7771
|
sessionStore,
|
|
7455
7772
|
(error, record) => {
|
|
7456
7773
|
log2(`session-store error (${record.type}): ${String(error)}`);
|
|
7457
7774
|
}
|
|
7458
7775
|
);
|
|
7776
|
+
const pendingLlmRequests = /* @__PURE__ */ new Map();
|
|
7777
|
+
const emitRunDiagnostics = (params2) => {
|
|
7778
|
+
if (!state.diagnosticsEnabled) return;
|
|
7779
|
+
try {
|
|
7780
|
+
sendRunDiagnostics(params2);
|
|
7781
|
+
} catch (error) {
|
|
7782
|
+
log2(`run diagnostics emit failed: ${String(error)}`);
|
|
7783
|
+
}
|
|
7784
|
+
};
|
|
7785
|
+
const sessionAppend = (record) => {
|
|
7786
|
+
if (state.diagnosticsEnabled) {
|
|
7787
|
+
try {
|
|
7788
|
+
if (record.type === "llm.request") {
|
|
7789
|
+
const modelName = record.model?.name ?? record.input.model ?? "unknown";
|
|
7790
|
+
pendingLlmRequests.set(record.seq, {
|
|
7791
|
+
ts: record.ts,
|
|
7792
|
+
provider: record.model?.provider,
|
|
7793
|
+
model: modelName
|
|
7794
|
+
});
|
|
7795
|
+
}
|
|
7796
|
+
if (record.type === "llm.response") {
|
|
7797
|
+
const request = pendingLlmRequests.get(record.seq);
|
|
7798
|
+
pendingLlmRequests.delete(record.seq);
|
|
7799
|
+
const usage = record.output.usage ?? null;
|
|
7800
|
+
const cacheReadTokens = usage?.input_cached_tokens ?? 0;
|
|
7801
|
+
const cacheCreationTokens = usage?.input_cache_creation_tokens ?? 0;
|
|
7802
|
+
const inputTokens = usage?.input_tokens ?? 0;
|
|
7803
|
+
const hitState = usage ? cacheReadTokens > 0 ? "hit" : "miss" : "unknown";
|
|
7804
|
+
const responseTsMs = toTimestampMs(record.ts);
|
|
7805
|
+
const requestTsMs = request ? toTimestampMs(request.ts) : null;
|
|
7806
|
+
const latencyMs = responseTsMs !== null && requestTsMs !== null ? Math.max(0, responseTsMs - requestTsMs) : 0;
|
|
7807
|
+
const model = usage?.model ?? request?.model ?? "unknown";
|
|
7808
|
+
const diagnostics = {
|
|
7809
|
+
run_id: runId,
|
|
7810
|
+
seq: record.seq,
|
|
7811
|
+
...request?.provider ? { provider: request.provider } : {},
|
|
7812
|
+
model,
|
|
7813
|
+
request_ts: request?.ts ?? record.ts,
|
|
7814
|
+
response_ts: record.ts,
|
|
7815
|
+
latency_ms: latencyMs,
|
|
7816
|
+
stop_reason: record.output.stop_reason ?? null,
|
|
7817
|
+
usage,
|
|
7818
|
+
cache: {
|
|
7819
|
+
hit_state: hitState,
|
|
7820
|
+
cache_read_tokens: cacheReadTokens,
|
|
7821
|
+
cache_creation_tokens: cacheCreationTokens,
|
|
7822
|
+
cache_read_ratio: usage ? cacheReadTokens / Math.max(inputTokens, 1) : null
|
|
7823
|
+
},
|
|
7824
|
+
cost_usd: null,
|
|
7825
|
+
provider_meta_summary: summarizeProviderMeta(
|
|
7826
|
+
record.output.provider_meta
|
|
7827
|
+
)
|
|
7828
|
+
};
|
|
7829
|
+
emitRunDiagnostics({
|
|
7830
|
+
run_id: runId,
|
|
7831
|
+
kind: "llm_call",
|
|
7832
|
+
call: diagnostics
|
|
7833
|
+
});
|
|
7834
|
+
}
|
|
7835
|
+
} catch (error) {
|
|
7836
|
+
log2(`run diagnostics build failed: ${String(error)}`);
|
|
7837
|
+
}
|
|
7838
|
+
}
|
|
7839
|
+
sessionAppenderRaw(record);
|
|
7840
|
+
};
|
|
7459
7841
|
state.sessionAppend = sessionAppend;
|
|
7460
7842
|
const session = {
|
|
7461
7843
|
run_id: runId,
|
|
@@ -7508,6 +7890,13 @@ var createRunHandlers = ({
|
|
|
7508
7890
|
let finalResponse;
|
|
7509
7891
|
let sessionSaveChain = Promise.resolve();
|
|
7510
7892
|
let lastSessionSaveAt = 0;
|
|
7893
|
+
const emitRunSummaryDiagnostics = () => {
|
|
7894
|
+
emitRunDiagnostics({
|
|
7895
|
+
run_id: runId,
|
|
7896
|
+
kind: "run_summary",
|
|
7897
|
+
summary: runtimeAgent.getUsageSummary()
|
|
7898
|
+
});
|
|
7899
|
+
};
|
|
7511
7900
|
const queueSessionSave = async (reason) => {
|
|
7512
7901
|
sessionSaveChain = sessionSaveChain.then(async () => {
|
|
7513
7902
|
if (!sessionId) return;
|
|
@@ -7602,6 +7991,7 @@ var createRunHandlers = ({
|
|
|
7602
7991
|
normalizeRunHistoryAfterCancel(runId, runtimeAgent);
|
|
7603
7992
|
}
|
|
7604
7993
|
await queueSessionSave("terminal");
|
|
7994
|
+
emitRunSummaryDiagnostics();
|
|
7605
7995
|
const status = state.cancelRequested ? "cancelled" : "completed";
|
|
7606
7996
|
emitRunStatus(runId, status);
|
|
7607
7997
|
emitRunEnd(
|
|
@@ -7614,11 +8004,13 @@ var createRunHandlers = ({
|
|
|
7614
8004
|
if (state.cancelRequested || isAbortLikeError(err)) {
|
|
7615
8005
|
normalizeRunHistoryAfterCancel(runId, runtimeAgent);
|
|
7616
8006
|
await queueSessionSave("cancelled");
|
|
8007
|
+
emitRunSummaryDiagnostics();
|
|
7617
8008
|
emitRunStatus(runId, "cancelled", err.message || "cancelled");
|
|
7618
8009
|
emitRunEnd(runId, "cancelled", finalResponse);
|
|
7619
8010
|
return;
|
|
7620
8011
|
}
|
|
7621
8012
|
await queueSessionSave("error");
|
|
8013
|
+
emitRunSummaryDiagnostics();
|
|
7622
8014
|
emitRunStatus(runId, "error", err.message);
|
|
7623
8015
|
appendSession({
|
|
7624
8016
|
type: "run.error",
|
|
@@ -7802,7 +8194,315 @@ var createToolHandlers = ({
|
|
|
7802
8194
|
};
|
|
7803
8195
|
};
|
|
7804
8196
|
|
|
8197
|
+
// src/rpc/shell.ts
|
|
8198
|
+
import crypto6 from "crypto";
|
|
8199
|
+
import path15 from "path";
|
|
8200
|
+
import { spawn as spawn5 } from "child_process";
|
|
8201
|
+
import { ToolOutputCacheStoreImpl as ToolOutputCacheStoreImpl2 } from "@codelia/storage";
|
|
8202
|
+
import {
|
|
8203
|
+
RPC_ERROR_CODE as RPC_ERROR_CODE7
|
|
8204
|
+
} from "@codelia/protocol";
|
|
8205
|
+
var DEFAULT_EXCERPT_LINES = 80;
|
|
8206
|
+
var MAX_INLINE_OUTPUT_BYTES = 64 * 1024;
|
|
8207
|
+
var COMMAND_PREVIEW_CHARS = 400;
|
|
8208
|
+
var truncateCommandPreview = (value) => {
|
|
8209
|
+
const trimmed = value.trim();
|
|
8210
|
+
if (trimmed.length <= COMMAND_PREVIEW_CHARS) return trimmed;
|
|
8211
|
+
return `${trimmed.slice(0, COMMAND_PREVIEW_CHARS)}...[truncated]`;
|
|
8212
|
+
};
|
|
8213
|
+
var utf8ByteLength = (value) => Buffer.byteLength(value, "utf8");
|
|
8214
|
+
var truncateUtf8Prefix = (value, maxBytes) => {
|
|
8215
|
+
if (maxBytes <= 0 || value.length === 0) return "";
|
|
8216
|
+
let bytes = 0;
|
|
8217
|
+
let out = "";
|
|
8218
|
+
for (const ch of value) {
|
|
8219
|
+
const next = utf8ByteLength(ch);
|
|
8220
|
+
if (bytes + next > maxBytes) break;
|
|
8221
|
+
out += ch;
|
|
8222
|
+
bytes += next;
|
|
8223
|
+
}
|
|
8224
|
+
return out;
|
|
8225
|
+
};
|
|
8226
|
+
var truncateUtf8Suffix = (value, maxBytes) => {
|
|
8227
|
+
if (maxBytes <= 0 || value.length === 0) return "";
|
|
8228
|
+
let bytes = 0;
|
|
8229
|
+
const chars = Array.from(value);
|
|
8230
|
+
const out = [];
|
|
8231
|
+
for (let idx = chars.length - 1; idx >= 0; idx -= 1) {
|
|
8232
|
+
const ch = chars[idx];
|
|
8233
|
+
const next = utf8ByteLength(ch);
|
|
8234
|
+
if (bytes + next > maxBytes) break;
|
|
8235
|
+
out.push(ch);
|
|
8236
|
+
bytes += next;
|
|
8237
|
+
}
|
|
8238
|
+
out.reverse();
|
|
8239
|
+
return out.join("");
|
|
8240
|
+
};
|
|
8241
|
+
var excerptByLines = (value) => {
|
|
8242
|
+
const lines = value.split(/\r?\n/);
|
|
8243
|
+
if (lines.length <= DEFAULT_EXCERPT_LINES * 2) {
|
|
8244
|
+
return value;
|
|
8245
|
+
}
|
|
8246
|
+
const head = lines.slice(0, DEFAULT_EXCERPT_LINES);
|
|
8247
|
+
const tail = lines.slice(lines.length - DEFAULT_EXCERPT_LINES);
|
|
8248
|
+
const omitted = lines.length - head.length - tail.length;
|
|
8249
|
+
return [...head, `...[${omitted} lines omitted]...`, ...tail].join("\n");
|
|
8250
|
+
};
|
|
8251
|
+
var excerptByBytes = (value, maxBytes) => {
|
|
8252
|
+
if (utf8ByteLength(value) <= maxBytes) return value;
|
|
8253
|
+
const marker = "\n...[truncated by size]...\n";
|
|
8254
|
+
const markerBytes = utf8ByteLength(marker);
|
|
8255
|
+
if (maxBytes <= markerBytes + 2) {
|
|
8256
|
+
return truncateUtf8Prefix(value, maxBytes);
|
|
8257
|
+
}
|
|
8258
|
+
const budget = maxBytes - markerBytes;
|
|
8259
|
+
const headBytes = Math.floor(budget / 2);
|
|
8260
|
+
const tailBytes = budget - headBytes;
|
|
8261
|
+
const head = truncateUtf8Prefix(value, headBytes);
|
|
8262
|
+
const tail = truncateUtf8Suffix(value, tailBytes);
|
|
8263
|
+
return `${head}${marker}${tail}`;
|
|
8264
|
+
};
|
|
8265
|
+
var needsInlineTruncation = (value) => value.split(/\r?\n/).length > DEFAULT_EXCERPT_LINES * 2 || utf8ByteLength(value) > MAX_INLINE_OUTPUT_BYTES;
|
|
8266
|
+
var excerptText = (value) => excerptByBytes(excerptByLines(value), MAX_INLINE_OUTPUT_BYTES);
|
|
8267
|
+
var isWithin2 = (basePath, candidatePath) => {
|
|
8268
|
+
const relative = path15.relative(basePath, candidatePath);
|
|
8269
|
+
return relative === "" || !relative.startsWith("..") && !path15.isAbsolute(relative);
|
|
8270
|
+
};
|
|
8271
|
+
var resolveShellCwd = (state, requestedCwd) => {
|
|
8272
|
+
const workingDir = state.runtimeWorkingDir ?? process.cwd();
|
|
8273
|
+
const rootDir = state.runtimeSandboxRoot ?? workingDir;
|
|
8274
|
+
if (!requestedCwd) return workingDir;
|
|
8275
|
+
const resolved = path15.resolve(workingDir, requestedCwd);
|
|
8276
|
+
if (!isWithin2(rootDir, resolved)) {
|
|
8277
|
+
return null;
|
|
8278
|
+
}
|
|
8279
|
+
return resolved;
|
|
8280
|
+
};
|
|
8281
|
+
var runShellWithUserShell = async (command, options) => {
|
|
8282
|
+
if (process.platform === "win32") {
|
|
8283
|
+
return runShellCommand(command, options);
|
|
8284
|
+
}
|
|
8285
|
+
const shellPath = process.env.SHELL?.trim() || "";
|
|
8286
|
+
if (!shellPath) {
|
|
8287
|
+
return runShellCommand(command, options);
|
|
8288
|
+
}
|
|
8289
|
+
return new Promise((resolve, reject) => {
|
|
8290
|
+
const child = spawn5(shellPath, ["-lc", command], {
|
|
8291
|
+
cwd: options.cwd,
|
|
8292
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
8293
|
+
signal: options.signal
|
|
8294
|
+
});
|
|
8295
|
+
let stdout = "";
|
|
8296
|
+
let stderr = "";
|
|
8297
|
+
let totalBytes = 0;
|
|
8298
|
+
let settled = false;
|
|
8299
|
+
let timedOut = false;
|
|
8300
|
+
let timeoutHandle;
|
|
8301
|
+
const finish = (handler) => {
|
|
8302
|
+
if (settled) return;
|
|
8303
|
+
settled = true;
|
|
8304
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
8305
|
+
handler();
|
|
8306
|
+
};
|
|
8307
|
+
const consumeChunk = (chunk, stream) => {
|
|
8308
|
+
const text = chunk.toString("utf8");
|
|
8309
|
+
totalBytes += Buffer.byteLength(text, "utf8");
|
|
8310
|
+
if (totalBytes > options.maxOutputBytes) {
|
|
8311
|
+
const error = Object.assign(
|
|
8312
|
+
new Error(
|
|
8313
|
+
`Command output exceeded max buffer of ${options.maxOutputBytes} bytes`
|
|
8314
|
+
),
|
|
8315
|
+
{
|
|
8316
|
+
code: "MAXBUFFER",
|
|
8317
|
+
stdout,
|
|
8318
|
+
stderr,
|
|
8319
|
+
killed: true,
|
|
8320
|
+
signal: "SIGTERM"
|
|
8321
|
+
}
|
|
8322
|
+
);
|
|
8323
|
+
try {
|
|
8324
|
+
child.kill("SIGTERM");
|
|
8325
|
+
} catch {
|
|
8326
|
+
}
|
|
8327
|
+
finish(() => reject(error));
|
|
8328
|
+
return;
|
|
8329
|
+
}
|
|
8330
|
+
if (stream === "stdout") stdout += text;
|
|
8331
|
+
else stderr += text;
|
|
8332
|
+
};
|
|
8333
|
+
child.stdout?.on("data", (chunk) => consumeChunk(chunk, "stdout"));
|
|
8334
|
+
child.stderr?.on("data", (chunk) => consumeChunk(chunk, "stderr"));
|
|
8335
|
+
child.on("error", (error) => {
|
|
8336
|
+
const enriched = Object.assign(error, {
|
|
8337
|
+
stdout,
|
|
8338
|
+
stderr
|
|
8339
|
+
});
|
|
8340
|
+
finish(() => reject(enriched));
|
|
8341
|
+
});
|
|
8342
|
+
child.on("close", (code, signal) => {
|
|
8343
|
+
if (timedOut) {
|
|
8344
|
+
const timeoutError = Object.assign(
|
|
8345
|
+
new Error(
|
|
8346
|
+
`Command timed out after ${Math.trunc(options.timeoutMs / 1e3)}s`
|
|
8347
|
+
),
|
|
8348
|
+
{
|
|
8349
|
+
code: "ETIMEDOUT",
|
|
8350
|
+
stdout,
|
|
8351
|
+
stderr,
|
|
8352
|
+
killed: true,
|
|
8353
|
+
signal: signal ?? "SIGTERM"
|
|
8354
|
+
}
|
|
8355
|
+
);
|
|
8356
|
+
finish(() => reject(timeoutError));
|
|
8357
|
+
return;
|
|
8358
|
+
}
|
|
8359
|
+
if (code === 0) {
|
|
8360
|
+
finish(() => resolve({ stdout, stderr }));
|
|
8361
|
+
return;
|
|
8362
|
+
}
|
|
8363
|
+
const failure = Object.assign(
|
|
8364
|
+
new Error(
|
|
8365
|
+
`Command failed with exit code ${code ?? "unknown"}${signal ? ` signal ${signal}` : ""}`
|
|
8366
|
+
),
|
|
8367
|
+
{ code, stdout, stderr, killed: false, signal }
|
|
8368
|
+
);
|
|
8369
|
+
finish(() => reject(failure));
|
|
8370
|
+
});
|
|
8371
|
+
timeoutHandle = setTimeout(() => {
|
|
8372
|
+
timedOut = true;
|
|
8373
|
+
try {
|
|
8374
|
+
child.kill("SIGTERM");
|
|
8375
|
+
} catch {
|
|
8376
|
+
}
|
|
8377
|
+
setTimeout(() => {
|
|
8378
|
+
try {
|
|
8379
|
+
if (!child.killed) child.kill("SIGKILL");
|
|
8380
|
+
} catch {
|
|
8381
|
+
}
|
|
8382
|
+
}, 2e3).unref();
|
|
8383
|
+
}, options.timeoutMs);
|
|
8384
|
+
});
|
|
8385
|
+
};
|
|
8386
|
+
var createShellHandlers = ({
|
|
8387
|
+
state,
|
|
8388
|
+
log: log2
|
|
8389
|
+
}) => {
|
|
8390
|
+
const outputCache = new ToolOutputCacheStoreImpl2();
|
|
8391
|
+
const handleShellExec = async (id, params) => {
|
|
8392
|
+
const command = params?.command?.trim() ?? "";
|
|
8393
|
+
if (!command) {
|
|
8394
|
+
sendError(id, {
|
|
8395
|
+
code: RPC_ERROR_CODE7.INVALID_PARAMS,
|
|
8396
|
+
message: "command is required"
|
|
8397
|
+
});
|
|
8398
|
+
return;
|
|
8399
|
+
}
|
|
8400
|
+
const requestedTimeout = params?.timeout_seconds ?? DEFAULT_TIMEOUT_SECONDS;
|
|
8401
|
+
if (!Number.isFinite(requestedTimeout) || requestedTimeout <= 0) {
|
|
8402
|
+
sendError(id, {
|
|
8403
|
+
code: RPC_ERROR_CODE7.INVALID_PARAMS,
|
|
8404
|
+
message: "timeout_seconds must be a positive number"
|
|
8405
|
+
});
|
|
8406
|
+
return;
|
|
8407
|
+
}
|
|
8408
|
+
const timeoutSeconds = Math.max(
|
|
8409
|
+
1,
|
|
8410
|
+
Math.min(Math.trunc(requestedTimeout), MAX_TIMEOUT_SECONDS)
|
|
8411
|
+
);
|
|
8412
|
+
const cwd = resolveShellCwd(state, params?.cwd);
|
|
8413
|
+
if (!cwd) {
|
|
8414
|
+
sendError(id, {
|
|
8415
|
+
code: RPC_ERROR_CODE7.INVALID_PARAMS,
|
|
8416
|
+
message: "cwd is outside sandbox root"
|
|
8417
|
+
});
|
|
8418
|
+
return;
|
|
8419
|
+
}
|
|
8420
|
+
const startedAt = Date.now();
|
|
8421
|
+
const commandSummary = summarizeCommand(command);
|
|
8422
|
+
const commandPreview = truncateCommandPreview(command);
|
|
8423
|
+
log2(
|
|
8424
|
+
`shell.exec.start origin=ui_bang cwd=${cwd} timeout_s=${timeoutSeconds} command="${commandSummary}"`
|
|
8425
|
+
);
|
|
8426
|
+
let rawStdout = "";
|
|
8427
|
+
let rawStderr = "";
|
|
8428
|
+
let exitCode = 0;
|
|
8429
|
+
let signal = null;
|
|
8430
|
+
try {
|
|
8431
|
+
const result2 = await runShellWithUserShell(command, {
|
|
8432
|
+
cwd,
|
|
8433
|
+
timeoutMs: timeoutSeconds * 1e3,
|
|
8434
|
+
maxOutputBytes: MAX_OUTPUT_BYTES
|
|
8435
|
+
});
|
|
8436
|
+
rawStdout = result2.stdout;
|
|
8437
|
+
rawStderr = result2.stderr;
|
|
8438
|
+
} catch (error) {
|
|
8439
|
+
const execError = error;
|
|
8440
|
+
rawStdout = execError.stdout ?? "";
|
|
8441
|
+
rawStderr = execError.stderr ?? "";
|
|
8442
|
+
exitCode = typeof execError.code === "number" ? execError.code : null;
|
|
8443
|
+
signal = execError.signal ?? null;
|
|
8444
|
+
}
|
|
8445
|
+
const stdoutTruncated = needsInlineTruncation(rawStdout);
|
|
8446
|
+
const stderrTruncated = needsInlineTruncation(rawStderr);
|
|
8447
|
+
const stdout = stdoutTruncated ? excerptText(rawStdout) : rawStdout;
|
|
8448
|
+
const stderr = stderrTruncated ? excerptText(rawStderr) : rawStderr;
|
|
8449
|
+
const combinedTruncated = stdoutTruncated || stderrTruncated;
|
|
8450
|
+
let stdoutCacheId;
|
|
8451
|
+
let stderrCacheId;
|
|
8452
|
+
if (stdoutTruncated && rawStdout.trim()) {
|
|
8453
|
+
const saved = await outputCache.save({
|
|
8454
|
+
tool_call_id: `shell_exec_stdout_${crypto6.randomUUID()}`,
|
|
8455
|
+
tool_name: "shell.exec",
|
|
8456
|
+
content: rawStdout
|
|
8457
|
+
});
|
|
8458
|
+
stdoutCacheId = saved.id;
|
|
8459
|
+
}
|
|
8460
|
+
if (stderrTruncated && rawStderr.trim()) {
|
|
8461
|
+
const saved = await outputCache.save({
|
|
8462
|
+
tool_call_id: `shell_exec_stderr_${crypto6.randomUUID()}`,
|
|
8463
|
+
tool_name: "shell.exec",
|
|
8464
|
+
content: rawStderr
|
|
8465
|
+
});
|
|
8466
|
+
stderrCacheId = saved.id;
|
|
8467
|
+
}
|
|
8468
|
+
const result = {
|
|
8469
|
+
command_preview: commandPreview,
|
|
8470
|
+
exit_code: exitCode,
|
|
8471
|
+
signal,
|
|
8472
|
+
stdout,
|
|
8473
|
+
stderr,
|
|
8474
|
+
truncated: {
|
|
8475
|
+
stdout: stdoutTruncated,
|
|
8476
|
+
stderr: stderrTruncated,
|
|
8477
|
+
combined: combinedTruncated
|
|
8478
|
+
},
|
|
8479
|
+
duration_ms: Date.now() - startedAt,
|
|
8480
|
+
...stdoutCacheId ? { stdout_cache_id: stdoutCacheId } : {},
|
|
8481
|
+
...stderrCacheId ? { stderr_cache_id: stderrCacheId } : {}
|
|
8482
|
+
};
|
|
8483
|
+
sendResult(id, result);
|
|
8484
|
+
log2(
|
|
8485
|
+
`shell.exec.done origin=ui_bang duration_ms=${result.duration_ms} exit_code=${String(result.exit_code)} signal=${result.signal ?? "-"}`
|
|
8486
|
+
);
|
|
8487
|
+
};
|
|
8488
|
+
return {
|
|
8489
|
+
handleShellExec
|
|
8490
|
+
};
|
|
8491
|
+
};
|
|
8492
|
+
|
|
7805
8493
|
// src/rpc/handlers.ts
|
|
8494
|
+
var SUPPORTED_TUI_THEMES = /* @__PURE__ */ new Set([
|
|
8495
|
+
"codelia",
|
|
8496
|
+
"ocean",
|
|
8497
|
+
"forest",
|
|
8498
|
+
"rose",
|
|
8499
|
+
"sakura",
|
|
8500
|
+
"mauve",
|
|
8501
|
+
"plum",
|
|
8502
|
+
"iris",
|
|
8503
|
+
"crimson",
|
|
8504
|
+
"wine"
|
|
8505
|
+
]);
|
|
7806
8506
|
var createRuntimeHandlers = ({
|
|
7807
8507
|
state,
|
|
7808
8508
|
getAgent,
|
|
@@ -7907,10 +8607,15 @@ var createRuntimeHandlers = ({
|
|
|
7907
8607
|
log2("startup onboarding skipped (model not selected)");
|
|
7908
8608
|
return;
|
|
7909
8609
|
}
|
|
7910
|
-
const
|
|
7911
|
-
await
|
|
8610
|
+
const workingDir = state.lastUiContext?.cwd ?? state.runtimeWorkingDir ?? process.cwd();
|
|
8611
|
+
const modelTarget = await updateModel(workingDir, {
|
|
8612
|
+
provider,
|
|
8613
|
+
name: selectedModel
|
|
8614
|
+
});
|
|
7912
8615
|
state.agent = null;
|
|
7913
|
-
log2(
|
|
8616
|
+
log2(
|
|
8617
|
+
`startup onboarding completed: ${provider}/${selectedModel} scope=${modelTarget.scope} path=${modelTarget.path}`
|
|
8618
|
+
);
|
|
7914
8619
|
};
|
|
7915
8620
|
const launchStartupOnboarding = () => {
|
|
7916
8621
|
if (startupOnboardingStarted) {
|
|
@@ -7956,17 +8661,24 @@ var createRuntimeHandlers = ({
|
|
|
7956
8661
|
state,
|
|
7957
8662
|
getAgent
|
|
7958
8663
|
});
|
|
8664
|
+
const { handleShellExec } = createShellHandlers({
|
|
8665
|
+
state,
|
|
8666
|
+
log: log2
|
|
8667
|
+
});
|
|
7959
8668
|
const handleInitialize = (id, params) => {
|
|
7960
8669
|
const result = {
|
|
7961
8670
|
protocol_version: PROTOCOL_VERSION,
|
|
7962
8671
|
server: { name: SERVER_NAME, version: SERVER_VERSION },
|
|
7963
8672
|
server_capabilities: {
|
|
7964
8673
|
supports_run_cancel: true,
|
|
8674
|
+
supports_run_diagnostics: true,
|
|
8675
|
+
supports_shell_exec: true,
|
|
7965
8676
|
supports_ui_requests: true,
|
|
7966
8677
|
supports_mcp_list: true,
|
|
7967
8678
|
supports_skills_list: true,
|
|
7968
8679
|
supports_context_inspect: true,
|
|
7969
8680
|
supports_tool_call: true,
|
|
8681
|
+
supports_theme_set: true,
|
|
7970
8682
|
supports_permission_preflight_events: true
|
|
7971
8683
|
}
|
|
7972
8684
|
};
|
|
@@ -7982,9 +8694,43 @@ var createRuntimeHandlers = ({
|
|
|
7982
8694
|
`ui.context.update cwd=${params.cwd ?? "-"} file=${params.active_file?.path ?? "-"}`
|
|
7983
8695
|
);
|
|
7984
8696
|
};
|
|
8697
|
+
const handleThemeSet = async (id, params) => {
|
|
8698
|
+
if (state.activeRunId) {
|
|
8699
|
+
sendError(id, { code: RPC_ERROR_CODE8.RUNTIME_BUSY, message: "runtime busy" });
|
|
8700
|
+
return;
|
|
8701
|
+
}
|
|
8702
|
+
const name = params?.name?.trim().toLowerCase();
|
|
8703
|
+
if (!name) {
|
|
8704
|
+
sendError(id, { code: RPC_ERROR_CODE8.INVALID_PARAMS, message: "theme name is required" });
|
|
8705
|
+
return;
|
|
8706
|
+
}
|
|
8707
|
+
if (!SUPPORTED_TUI_THEMES.has(name)) {
|
|
8708
|
+
sendError(id, {
|
|
8709
|
+
code: RPC_ERROR_CODE8.INVALID_PARAMS,
|
|
8710
|
+
message: `unsupported theme: ${name}`
|
|
8711
|
+
});
|
|
8712
|
+
return;
|
|
8713
|
+
}
|
|
8714
|
+
const workingDir = state.lastUiContext?.cwd ?? state.runtimeWorkingDir ?? process.cwd();
|
|
8715
|
+
try {
|
|
8716
|
+
const target = await updateTuiTheme(workingDir, name);
|
|
8717
|
+
const result = {
|
|
8718
|
+
name,
|
|
8719
|
+
scope: target.scope,
|
|
8720
|
+
path: target.path
|
|
8721
|
+
};
|
|
8722
|
+
sendResult(id, result);
|
|
8723
|
+
log2(`theme.set ${name} scope=${target.scope} path=${target.path}`);
|
|
8724
|
+
} catch (error) {
|
|
8725
|
+
sendError(id, { code: RPC_ERROR_CODE8.RUNTIME_INTERNAL, message: String(error) });
|
|
8726
|
+
}
|
|
8727
|
+
};
|
|
7985
8728
|
const handleAuthLogout = async (id, params) => {
|
|
7986
8729
|
if (state.activeRunId) {
|
|
7987
|
-
sendError(id, {
|
|
8730
|
+
sendError(id, {
|
|
8731
|
+
code: RPC_ERROR_CODE8.RUNTIME_BUSY,
|
|
8732
|
+
message: "runtime busy"
|
|
8733
|
+
});
|
|
7988
8734
|
return;
|
|
7989
8735
|
}
|
|
7990
8736
|
const clearSession = params?.clear_session ?? true;
|
|
@@ -7992,7 +8738,7 @@ var createRuntimeHandlers = ({
|
|
|
7992
8738
|
const supportsConfirm = !!state.uiCapabilities?.supports_confirm;
|
|
7993
8739
|
if (!supportsConfirm) {
|
|
7994
8740
|
sendError(id, {
|
|
7995
|
-
code:
|
|
8741
|
+
code: RPC_ERROR_CODE8.RUNTIME_INTERNAL,
|
|
7996
8742
|
message: "UI confirmation is required for logout"
|
|
7997
8743
|
});
|
|
7998
8744
|
return;
|
|
@@ -8034,7 +8780,7 @@ var createRuntimeHandlers = ({
|
|
|
8034
8780
|
log2(`auth.logout session_cleared=${clearSession}`);
|
|
8035
8781
|
} catch (error) {
|
|
8036
8782
|
sendError(id, {
|
|
8037
|
-
code:
|
|
8783
|
+
code: RPC_ERROR_CODE8.RUNTIME_INTERNAL,
|
|
8038
8784
|
message: `auth logout failed: ${String(error)}`
|
|
8039
8785
|
});
|
|
8040
8786
|
}
|
|
@@ -8059,6 +8805,8 @@ var createRuntimeHandlers = ({
|
|
|
8059
8805
|
return handleModelSet(req.id, req.params);
|
|
8060
8806
|
case "tool.call":
|
|
8061
8807
|
return handleToolCall(req.id, req.params);
|
|
8808
|
+
case "shell.exec":
|
|
8809
|
+
return handleShellExec(req.id, req.params);
|
|
8062
8810
|
case "mcp.list":
|
|
8063
8811
|
await mcpManager.start?.();
|
|
8064
8812
|
return sendResult(
|
|
@@ -8069,8 +8817,13 @@ var createRuntimeHandlers = ({
|
|
|
8069
8817
|
return handleSkillsList(req.id, req.params);
|
|
8070
8818
|
case "context.inspect":
|
|
8071
8819
|
return handleContextInspect(req.id, req.params);
|
|
8820
|
+
case "theme.set":
|
|
8821
|
+
return handleThemeSet(req.id, req.params);
|
|
8072
8822
|
default:
|
|
8073
|
-
return sendError(req.id, {
|
|
8823
|
+
return sendError(req.id, {
|
|
8824
|
+
code: RPC_ERROR_CODE8.METHOD_NOT_FOUND,
|
|
8825
|
+
message: "method not found"
|
|
8826
|
+
});
|
|
8074
8827
|
}
|
|
8075
8828
|
};
|
|
8076
8829
|
const handleNotification = (note) => {
|
|
@@ -8097,7 +8850,7 @@ var createRuntimeHandlers = ({
|
|
|
8097
8850
|
};
|
|
8098
8851
|
|
|
8099
8852
|
// src/runtime-state.ts
|
|
8100
|
-
import
|
|
8853
|
+
import crypto7 from "crypto";
|
|
8101
8854
|
var RuntimeState = class {
|
|
8102
8855
|
runSeq = /* @__PURE__ */ new Map();
|
|
8103
8856
|
uiRequestCounter = 0;
|
|
@@ -8120,11 +8873,12 @@ var RuntimeState = class {
|
|
|
8120
8873
|
loadedSkillVersions = /* @__PURE__ */ new Map();
|
|
8121
8874
|
runtimeWorkingDir = null;
|
|
8122
8875
|
runtimeSandboxRoot = null;
|
|
8876
|
+
diagnosticsEnabled = false;
|
|
8123
8877
|
nextRunId() {
|
|
8124
|
-
return
|
|
8878
|
+
return crypto7.randomUUID();
|
|
8125
8879
|
}
|
|
8126
8880
|
nextSessionId() {
|
|
8127
|
-
return
|
|
8881
|
+
return crypto7.randomUUID();
|
|
8128
8882
|
}
|
|
8129
8883
|
beginRun(runId, uiContext) {
|
|
8130
8884
|
this.activeRunId = runId;
|
|
@@ -8213,10 +8967,16 @@ var RuntimeState = class {
|
|
|
8213
8967
|
};
|
|
8214
8968
|
|
|
8215
8969
|
// src/runtime.ts
|
|
8970
|
+
var envTruthy2 = (value) => {
|
|
8971
|
+
if (!value) return false;
|
|
8972
|
+
const normalized = value.trim().toLowerCase();
|
|
8973
|
+
return normalized === "1" || normalized === "true";
|
|
8974
|
+
};
|
|
8216
8975
|
var startRuntime = () => {
|
|
8217
8976
|
void (async () => {
|
|
8218
8977
|
const state = new RuntimeState();
|
|
8219
|
-
|
|
8978
|
+
state.diagnosticsEnabled = envTruthy2(process.env.CODELIA_DIAGNOSTICS);
|
|
8979
|
+
const workingDir = process.env.CODELIA_SANDBOX_ROOT ? path16.resolve(process.env.CODELIA_SANDBOX_ROOT) : process.cwd();
|
|
8220
8980
|
state.runtimeWorkingDir = workingDir;
|
|
8221
8981
|
state.runtimeSandboxRoot = workingDir;
|
|
8222
8982
|
const sessionStateStore = new SessionStateStoreImpl2({
|