@kody-ade/kody-engine 0.4.400 → 0.4.402
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/bin/kody.js +750 -416
- package/package.json +1 -1
package/dist/bin/kody.js
CHANGED
|
@@ -15,7 +15,7 @@ var init_package = __esm({
|
|
|
15
15
|
"package.json"() {
|
|
16
16
|
package_default = {
|
|
17
17
|
name: "@kody-ade/kody-engine",
|
|
18
|
-
version: "0.4.
|
|
18
|
+
version: "0.4.402",
|
|
19
19
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
|
|
20
20
|
license: "MIT",
|
|
21
21
|
type: "module",
|
|
@@ -1088,7 +1088,7 @@ function cmsHeaders(opts) {
|
|
|
1088
1088
|
}
|
|
1089
1089
|
};
|
|
1090
1090
|
}
|
|
1091
|
-
async function callDashboardCms(opts,
|
|
1091
|
+
async function callDashboardCms(opts, path51, init = {}) {
|
|
1092
1092
|
const baseUrl = dashboardBaseUrl(opts);
|
|
1093
1093
|
if (!baseUrl) {
|
|
1094
1094
|
return {
|
|
@@ -1100,7 +1100,7 @@ async function callDashboardCms(opts, path50, init = {}) {
|
|
|
1100
1100
|
const headerResult = cmsHeaders(opts);
|
|
1101
1101
|
if (!headerResult.ok) return headerResult;
|
|
1102
1102
|
try {
|
|
1103
|
-
const res = await fetch(`${baseUrl}${
|
|
1103
|
+
const res = await fetch(`${baseUrl}${path51}`, {
|
|
1104
1104
|
...init,
|
|
1105
1105
|
headers: {
|
|
1106
1106
|
...headerResult.headers,
|
|
@@ -1172,8 +1172,8 @@ function documentArg(value) {
|
|
|
1172
1172
|
function normalizeCmsDocumentIdInput(input) {
|
|
1173
1173
|
const trimmed = stripWrappingQuotes(input.trim());
|
|
1174
1174
|
const withoutQuery = trimmed.split(/[?#]/, 1)[0] ?? trimmed;
|
|
1175
|
-
const
|
|
1176
|
-
return
|
|
1175
|
+
const path51 = parseDocumentPath(withoutQuery);
|
|
1176
|
+
return path51 ?? parseDocumentIdSegment(withoutQuery) ?? withoutQuery;
|
|
1177
1177
|
}
|
|
1178
1178
|
function stripWrappingQuotes(value) {
|
|
1179
1179
|
let current = value;
|
|
@@ -1184,9 +1184,9 @@ function stripWrappingQuotes(value) {
|
|
|
1184
1184
|
}
|
|
1185
1185
|
}
|
|
1186
1186
|
function parseDocumentPath(value) {
|
|
1187
|
-
const
|
|
1188
|
-
if (!
|
|
1189
|
-
const parts =
|
|
1187
|
+
const path51 = value.startsWith("http://") || value.startsWith("https://") ? urlPathname(value) : value;
|
|
1188
|
+
if (!path51?.includes("/content/entries/")) return null;
|
|
1189
|
+
const parts = path51.split("/").filter(Boolean).map(decodePathPart);
|
|
1190
1190
|
const entriesIndex = parts.findIndex((part, index) => part === "content" && parts[index + 1] === "entries");
|
|
1191
1191
|
const idPart = parts[entriesIndex + 3];
|
|
1192
1192
|
if (!idPart || idPart === "new") return null;
|
|
@@ -3604,7 +3604,14 @@ var init_agents = __esm({
|
|
|
3604
3604
|
"src/agents.ts"() {
|
|
3605
3605
|
"use strict";
|
|
3606
3606
|
init_definition_paths();
|
|
3607
|
-
BUILTIN_AGENTS = {
|
|
3607
|
+
BUILTIN_AGENTS = {
|
|
3608
|
+
kody: [
|
|
3609
|
+
"# Kody",
|
|
3610
|
+
"",
|
|
3611
|
+
"You are Kody, the autonomous development engine running this task.",
|
|
3612
|
+
"Stay concise, make the smallest correct change, verify the real path, and report blockers honestly."
|
|
3613
|
+
].join("\n")
|
|
3614
|
+
};
|
|
3608
3615
|
}
|
|
3609
3616
|
});
|
|
3610
3617
|
|
|
@@ -3763,7 +3770,7 @@ var init_task_artifacts = __esm({
|
|
|
3763
3770
|
|
|
3764
3771
|
// src/gha.ts
|
|
3765
3772
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
3766
|
-
import * as
|
|
3773
|
+
import * as fs17 from "fs";
|
|
3767
3774
|
function getRunUrl() {
|
|
3768
3775
|
const server = process.env.GITHUB_SERVER_URL;
|
|
3769
3776
|
const repo = process.env.GITHUB_REPOSITORY;
|
|
@@ -3774,10 +3781,10 @@ function getRunUrl() {
|
|
|
3774
3781
|
function reactToTriggerComment(cwd) {
|
|
3775
3782
|
if (process.env.GITHUB_EVENT_NAME !== "issue_comment") return;
|
|
3776
3783
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
3777
|
-
if (!eventPath || !
|
|
3784
|
+
if (!eventPath || !fs17.existsSync(eventPath)) return;
|
|
3778
3785
|
let event = null;
|
|
3779
3786
|
try {
|
|
3780
|
-
event = JSON.parse(
|
|
3787
|
+
event = JSON.parse(fs17.readFileSync(eventPath, "utf-8"));
|
|
3781
3788
|
} catch {
|
|
3782
3789
|
return;
|
|
3783
3790
|
}
|
|
@@ -4306,31 +4313,31 @@ var init_lifecycles = __esm({
|
|
|
4306
4313
|
});
|
|
4307
4314
|
|
|
4308
4315
|
// src/scripts/buildSyntheticPlugin.ts
|
|
4309
|
-
import * as
|
|
4316
|
+
import * as fs18 from "fs";
|
|
4310
4317
|
import * as os3 from "os";
|
|
4311
|
-
import * as
|
|
4318
|
+
import * as path17 from "path";
|
|
4312
4319
|
function getPluginsCatalogRoot() {
|
|
4313
|
-
const here =
|
|
4320
|
+
const here = path17.dirname(new URL(import.meta.url).pathname);
|
|
4314
4321
|
const candidates = [
|
|
4315
|
-
|
|
4322
|
+
path17.join(here, "..", "plugins"),
|
|
4316
4323
|
// dev: src/scripts → src/plugins
|
|
4317
|
-
|
|
4324
|
+
path17.join(here, "..", "..", "plugins"),
|
|
4318
4325
|
// built: dist/scripts → dist/plugins
|
|
4319
|
-
|
|
4326
|
+
path17.join(here, "..", "..", "src", "plugins")
|
|
4320
4327
|
// fallback
|
|
4321
4328
|
];
|
|
4322
4329
|
for (const c of candidates) {
|
|
4323
|
-
if (
|
|
4330
|
+
if (fs18.existsSync(c) && fs18.statSync(c).isDirectory()) return c;
|
|
4324
4331
|
}
|
|
4325
4332
|
return candidates[0];
|
|
4326
4333
|
}
|
|
4327
4334
|
function copyDir(src, dst) {
|
|
4328
|
-
|
|
4329
|
-
for (const ent of
|
|
4330
|
-
const s =
|
|
4331
|
-
const d =
|
|
4335
|
+
fs18.mkdirSync(dst, { recursive: true });
|
|
4336
|
+
for (const ent of fs18.readdirSync(src, { withFileTypes: true })) {
|
|
4337
|
+
const s = path17.join(src, ent.name);
|
|
4338
|
+
const d = path17.join(dst, ent.name);
|
|
4332
4339
|
if (ent.isDirectory()) copyDir(s, d);
|
|
4333
|
-
else if (ent.isFile())
|
|
4340
|
+
else if (ent.isFile()) fs18.copyFileSync(s, d);
|
|
4334
4341
|
}
|
|
4335
4342
|
}
|
|
4336
4343
|
var buildSyntheticPlugin;
|
|
@@ -4343,45 +4350,45 @@ var init_buildSyntheticPlugin = __esm({
|
|
|
4343
4350
|
if (!needsSynthetic) return;
|
|
4344
4351
|
const catalog = getPluginsCatalogRoot();
|
|
4345
4352
|
const runId = `${profile.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
4346
|
-
const root =
|
|
4347
|
-
|
|
4353
|
+
const root = path17.join(os3.tmpdir(), `kody-synth-${runId}`);
|
|
4354
|
+
fs18.mkdirSync(path17.join(root, ".claude-plugin"), { recursive: true });
|
|
4348
4355
|
const resolvePart = (bucket, entry) => {
|
|
4349
|
-
const local =
|
|
4350
|
-
if (
|
|
4351
|
-
const central =
|
|
4352
|
-
if (
|
|
4356
|
+
const local = path17.join(profile.dir, bucket, entry);
|
|
4357
|
+
if (fs18.existsSync(local)) return local;
|
|
4358
|
+
const central = path17.join(catalog, bucket, entry);
|
|
4359
|
+
if (fs18.existsSync(central)) return central;
|
|
4353
4360
|
throw new Error(
|
|
4354
4361
|
`buildSyntheticPlugin: ${bucket} entry '${entry}' not found in implementation dir (${profile.dir}/${bucket}/) or catalog (${catalog}/${bucket}/)`
|
|
4355
4362
|
);
|
|
4356
4363
|
};
|
|
4357
4364
|
if (cc.skills.length > 0) {
|
|
4358
|
-
const dst =
|
|
4359
|
-
|
|
4365
|
+
const dst = path17.join(root, "skills");
|
|
4366
|
+
fs18.mkdirSync(dst, { recursive: true });
|
|
4360
4367
|
for (const name of cc.skills) {
|
|
4361
|
-
copyDir(resolvePart("skills", name),
|
|
4368
|
+
copyDir(resolvePart("skills", name), path17.join(dst, name));
|
|
4362
4369
|
}
|
|
4363
4370
|
}
|
|
4364
4371
|
if (cc.commands.length > 0) {
|
|
4365
|
-
const dst =
|
|
4366
|
-
|
|
4372
|
+
const dst = path17.join(root, "commands");
|
|
4373
|
+
fs18.mkdirSync(dst, { recursive: true });
|
|
4367
4374
|
for (const name of cc.commands) {
|
|
4368
|
-
|
|
4375
|
+
fs18.copyFileSync(resolvePart("commands", `${name}.md`), path17.join(dst, `${name}.md`));
|
|
4369
4376
|
}
|
|
4370
4377
|
}
|
|
4371
4378
|
if (cc.hooks.length > 0) {
|
|
4372
|
-
const dst =
|
|
4373
|
-
|
|
4379
|
+
const dst = path17.join(root, "hooks");
|
|
4380
|
+
fs18.mkdirSync(dst, { recursive: true });
|
|
4374
4381
|
const merged = { hooks: {} };
|
|
4375
4382
|
for (const name of cc.hooks) {
|
|
4376
4383
|
const src = resolvePart("hooks", `${name}.json`);
|
|
4377
|
-
const parsed = JSON.parse(
|
|
4384
|
+
const parsed = JSON.parse(fs18.readFileSync(src, "utf-8"));
|
|
4378
4385
|
for (const [event, entries] of Object.entries(parsed.hooks ?? {})) {
|
|
4379
4386
|
if (!Array.isArray(entries)) continue;
|
|
4380
4387
|
if (!merged.hooks[event]) merged.hooks[event] = [];
|
|
4381
4388
|
merged.hooks[event].push(...entries);
|
|
4382
4389
|
}
|
|
4383
4390
|
}
|
|
4384
|
-
|
|
4391
|
+
fs18.writeFileSync(path17.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
|
|
4385
4392
|
`);
|
|
4386
4393
|
}
|
|
4387
4394
|
const manifest = {
|
|
@@ -4391,7 +4398,7 @@ var init_buildSyntheticPlugin = __esm({
|
|
|
4391
4398
|
};
|
|
4392
4399
|
if (cc.skills.length > 0) manifest.skills = ["./skills/"];
|
|
4393
4400
|
if (cc.commands.length > 0) manifest.commands = ["./commands/"];
|
|
4394
|
-
|
|
4401
|
+
fs18.writeFileSync(path17.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
|
|
4395
4402
|
`);
|
|
4396
4403
|
ctx.data.syntheticPluginPath = root;
|
|
4397
4404
|
};
|
|
@@ -4399,8 +4406,8 @@ var init_buildSyntheticPlugin = __esm({
|
|
|
4399
4406
|
});
|
|
4400
4407
|
|
|
4401
4408
|
// src/subagents.ts
|
|
4402
|
-
import * as
|
|
4403
|
-
import * as
|
|
4409
|
+
import * as fs19 from "fs";
|
|
4410
|
+
import * as path18 from "path";
|
|
4404
4411
|
function splitFrontmatter(raw) {
|
|
4405
4412
|
const match = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/.exec(raw);
|
|
4406
4413
|
if (!match) return { fm: {}, body: raw.trim() };
|
|
@@ -4413,10 +4420,10 @@ function splitFrontmatter(raw) {
|
|
|
4413
4420
|
return { fm, body: (match[2] ?? "").trim() };
|
|
4414
4421
|
}
|
|
4415
4422
|
function resolveAgentFile2(profileDir, name) {
|
|
4416
|
-
const local =
|
|
4417
|
-
if (
|
|
4418
|
-
const central =
|
|
4419
|
-
if (
|
|
4423
|
+
const local = path18.join(profileDir, "agents", `${name}.md`);
|
|
4424
|
+
if (fs19.existsSync(local)) return local;
|
|
4425
|
+
const central = path18.join(getPluginsCatalogRoot(), "agents", `${name}.md`);
|
|
4426
|
+
if (fs19.existsSync(central)) return central;
|
|
4420
4427
|
throw new Error(`loadSubagents: agent '${name}' not found in ${profileDir}/agents/ or shared catalog`);
|
|
4421
4428
|
}
|
|
4422
4429
|
function captureSubagentTemplates(profile) {
|
|
@@ -4425,7 +4432,7 @@ function captureSubagentTemplates(profile) {
|
|
|
4425
4432
|
const out = {};
|
|
4426
4433
|
for (const name of names) {
|
|
4427
4434
|
try {
|
|
4428
|
-
out[name] =
|
|
4435
|
+
out[name] = fs19.readFileSync(resolveAgentFile2(profile.dir, name), "utf-8");
|
|
4429
4436
|
} catch {
|
|
4430
4437
|
}
|
|
4431
4438
|
}
|
|
@@ -4436,7 +4443,7 @@ function loadSubagents(profile) {
|
|
|
4436
4443
|
if (!names || names.length === 0) return void 0;
|
|
4437
4444
|
const agents = {};
|
|
4438
4445
|
for (const name of names) {
|
|
4439
|
-
const raw = profile.subagentTemplates?.[name] ??
|
|
4446
|
+
const raw = profile.subagentTemplates?.[name] ?? fs19.readFileSync(resolveAgentFile2(profile.dir, name), "utf-8");
|
|
4440
4447
|
const { fm, body } = splitFrontmatter(raw);
|
|
4441
4448
|
if (!body) throw new Error(`loadSubagents: agent '${name}' has an empty prompt body`);
|
|
4442
4449
|
const def = {
|
|
@@ -4460,15 +4467,15 @@ var init_subagents = __esm({
|
|
|
4460
4467
|
});
|
|
4461
4468
|
|
|
4462
4469
|
// src/profile.ts
|
|
4463
|
-
import * as
|
|
4464
|
-
import * as
|
|
4470
|
+
import * as fs20 from "fs";
|
|
4471
|
+
import * as path19 from "path";
|
|
4465
4472
|
function loadProfile(profilePath) {
|
|
4466
|
-
if (!
|
|
4473
|
+
if (!fs20.existsSync(profilePath)) {
|
|
4467
4474
|
throw new ProfileError(profilePath, "file not found");
|
|
4468
4475
|
}
|
|
4469
4476
|
let raw;
|
|
4470
4477
|
try {
|
|
4471
|
-
raw = JSON.parse(
|
|
4478
|
+
raw = JSON.parse(fs20.readFileSync(profilePath, "utf-8"));
|
|
4472
4479
|
} catch (err) {
|
|
4473
4480
|
throw new ProfileError(profilePath, `invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
4474
4481
|
}
|
|
@@ -4479,7 +4486,7 @@ function loadProfile(profilePath) {
|
|
|
4479
4486
|
const unknownKeys = Object.keys(r).filter((k) => !KNOWN_PROFILE_KEYS.has(k));
|
|
4480
4487
|
if (unknownKeys.length > 0) {
|
|
4481
4488
|
process.stderr.write(
|
|
4482
|
-
`[kody profile] ${
|
|
4489
|
+
`[kody profile] ${path19.basename(path19.dirname(profilePath))}: unknown top-level keys ignored: ${unknownKeys.join(", ")}
|
|
4483
4490
|
`
|
|
4484
4491
|
);
|
|
4485
4492
|
}
|
|
@@ -4489,7 +4496,7 @@ function loadProfile(profilePath) {
|
|
|
4489
4496
|
if (!refPath) {
|
|
4490
4497
|
throw new ProfileError(profilePath, `capability references unknown implementation '${execRef}'`);
|
|
4491
4498
|
}
|
|
4492
|
-
if (
|
|
4499
|
+
if (path19.resolve(refPath) === path19.resolve(profilePath)) {
|
|
4493
4500
|
} else {
|
|
4494
4501
|
const base = loadProfile(refPath);
|
|
4495
4502
|
return {
|
|
@@ -4587,8 +4594,8 @@ function loadProfile(profilePath) {
|
|
|
4587
4594
|
// Phase 5 in-process handoff opt-in. Default false; containers
|
|
4588
4595
|
// flip to true after end-to-end verification.
|
|
4589
4596
|
preloadContext: r.preloadContext === true,
|
|
4590
|
-
dir:
|
|
4591
|
-
promptTemplates: readPromptTemplates(
|
|
4597
|
+
dir: path19.dirname(profilePath),
|
|
4598
|
+
promptTemplates: readPromptTemplates(path19.dirname(profilePath))
|
|
4592
4599
|
};
|
|
4593
4600
|
if (lifecycle) {
|
|
4594
4601
|
applyLifecycle(profile, profilePath);
|
|
@@ -4631,17 +4638,17 @@ function readPromptTemplates(dir) {
|
|
|
4631
4638
|
const out = {};
|
|
4632
4639
|
const read = (p) => {
|
|
4633
4640
|
try {
|
|
4634
|
-
out[p] =
|
|
4641
|
+
out[p] = fs20.readFileSync(p, "utf-8");
|
|
4635
4642
|
} catch {
|
|
4636
4643
|
}
|
|
4637
4644
|
};
|
|
4638
|
-
read(
|
|
4639
|
-
read(
|
|
4640
|
-
read(
|
|
4645
|
+
read(path19.join(dir, "prompt.md"));
|
|
4646
|
+
read(path19.join(dir, "capability.md"));
|
|
4647
|
+
read(path19.join(dir, "capability.md"));
|
|
4641
4648
|
try {
|
|
4642
|
-
const promptsDir =
|
|
4643
|
-
for (const ent of
|
|
4644
|
-
if (ent.endsWith(".md")) read(
|
|
4649
|
+
const promptsDir = path19.join(dir, "prompts");
|
|
4650
|
+
for (const ent of fs20.readdirSync(promptsDir)) {
|
|
4651
|
+
if (ent.endsWith(".md")) read(path19.join(promptsDir, ent));
|
|
4645
4652
|
}
|
|
4646
4653
|
} catch {
|
|
4647
4654
|
}
|
|
@@ -5415,16 +5422,16 @@ var init_state = __esm({
|
|
|
5415
5422
|
});
|
|
5416
5423
|
|
|
5417
5424
|
// src/prompt.ts
|
|
5418
|
-
import * as
|
|
5419
|
-
import * as
|
|
5425
|
+
import * as fs21 from "fs";
|
|
5426
|
+
import * as path20 from "path";
|
|
5420
5427
|
function loadProjectConventions(projectDir) {
|
|
5421
5428
|
const out = [];
|
|
5422
5429
|
for (const rel of CONVENTION_FILES) {
|
|
5423
|
-
const abs =
|
|
5424
|
-
if (!
|
|
5430
|
+
const abs = path20.join(projectDir, rel);
|
|
5431
|
+
if (!fs21.existsSync(abs)) continue;
|
|
5425
5432
|
let content;
|
|
5426
5433
|
try {
|
|
5427
|
-
content =
|
|
5434
|
+
content = fs21.readFileSync(abs, "utf-8");
|
|
5428
5435
|
} catch {
|
|
5429
5436
|
continue;
|
|
5430
5437
|
}
|
|
@@ -5659,8 +5666,8 @@ var loadMemoryContext_exports = {};
|
|
|
5659
5666
|
__export(loadMemoryContext_exports, {
|
|
5660
5667
|
loadMemoryContext: () => loadMemoryContext
|
|
5661
5668
|
});
|
|
5662
|
-
import * as
|
|
5663
|
-
import * as
|
|
5669
|
+
import * as fs22 from "fs";
|
|
5670
|
+
import * as path21 from "path";
|
|
5664
5671
|
function formatBlockFromBackend(docs) {
|
|
5665
5672
|
const pages = docs.flatMap((record2) => {
|
|
5666
5673
|
if (!record2.doc || typeof record2.doc !== "object") return [];
|
|
@@ -5683,21 +5690,21 @@ function collectPages(memoryAbs) {
|
|
|
5683
5690
|
walkMd(memoryAbs, (file) => {
|
|
5684
5691
|
let stat;
|
|
5685
5692
|
try {
|
|
5686
|
-
stat =
|
|
5693
|
+
stat = fs22.statSync(file);
|
|
5687
5694
|
} catch {
|
|
5688
5695
|
return;
|
|
5689
5696
|
}
|
|
5690
5697
|
let raw;
|
|
5691
5698
|
try {
|
|
5692
|
-
raw =
|
|
5699
|
+
raw = fs22.readFileSync(file, "utf-8");
|
|
5693
5700
|
} catch {
|
|
5694
5701
|
return;
|
|
5695
5702
|
}
|
|
5696
5703
|
const fm = raw.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
5697
|
-
const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ??
|
|
5704
|
+
const title = fm?.[1]?.match(/^title:\s*(.+)$/m)?.[1]?.trim() ?? path21.basename(file, ".md");
|
|
5698
5705
|
const updated = fm?.[1]?.match(/^updated:\s*([0-9T:.+\-Z]+)/m)?.[1]?.trim() ?? "";
|
|
5699
5706
|
out.push({
|
|
5700
|
-
relPath:
|
|
5707
|
+
relPath: path21.relative(memoryAbs, file),
|
|
5701
5708
|
title,
|
|
5702
5709
|
updated,
|
|
5703
5710
|
content: raw.length > PER_PAGE_MAX_BYTES ? raw.slice(0, PER_PAGE_MAX_BYTES) + TRUNCATED_SUFFIX2 : raw,
|
|
@@ -5765,16 +5772,16 @@ function walkMd(root, visit) {
|
|
|
5765
5772
|
const dir = stack.pop();
|
|
5766
5773
|
let names;
|
|
5767
5774
|
try {
|
|
5768
|
-
names =
|
|
5775
|
+
names = fs22.readdirSync(dir);
|
|
5769
5776
|
} catch {
|
|
5770
5777
|
continue;
|
|
5771
5778
|
}
|
|
5772
5779
|
for (const name of names) {
|
|
5773
5780
|
if (name.startsWith(".")) continue;
|
|
5774
|
-
const full =
|
|
5781
|
+
const full = path21.join(dir, name);
|
|
5775
5782
|
let stat;
|
|
5776
5783
|
try {
|
|
5777
|
-
stat =
|
|
5784
|
+
stat = fs22.statSync(full);
|
|
5778
5785
|
} catch {
|
|
5779
5786
|
continue;
|
|
5780
5787
|
}
|
|
@@ -5809,8 +5816,8 @@ var init_loadMemoryContext = __esm({
|
|
|
5809
5816
|
}
|
|
5810
5817
|
return;
|
|
5811
5818
|
}
|
|
5812
|
-
const memoryAbs =
|
|
5813
|
-
if (!
|
|
5819
|
+
const memoryAbs = path21.join(ctx.cwd, MEMORY_DIR_RELATIVE);
|
|
5820
|
+
if (!fs22.existsSync(memoryAbs)) {
|
|
5814
5821
|
ctx.data.memoryContext = "";
|
|
5815
5822
|
return;
|
|
5816
5823
|
}
|
|
@@ -5854,11 +5861,11 @@ var init_loadCoverageRules = __esm({
|
|
|
5854
5861
|
|
|
5855
5862
|
// src/container.ts
|
|
5856
5863
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
5857
|
-
import * as
|
|
5864
|
+
import * as fs23 from "fs";
|
|
5858
5865
|
function getProfileInputsForChild(profileName, _cwd) {
|
|
5859
5866
|
try {
|
|
5860
5867
|
const profilePath = resolveProfilePath(profileName);
|
|
5861
|
-
if (!
|
|
5868
|
+
if (!fs23.existsSync(profilePath)) return null;
|
|
5862
5869
|
return loadProfile(profilePath).inputs;
|
|
5863
5870
|
} catch {
|
|
5864
5871
|
return null;
|
|
@@ -6321,11 +6328,11 @@ var init_lifecycleLabels = __esm({
|
|
|
6321
6328
|
});
|
|
6322
6329
|
|
|
6323
6330
|
// src/litellm.ts
|
|
6324
|
-
import { execFileSync as execFileSync4, spawn as
|
|
6325
|
-
import * as
|
|
6331
|
+
import { execFileSync as execFileSync4, spawn as spawn4 } from "child_process";
|
|
6332
|
+
import * as fs24 from "fs";
|
|
6326
6333
|
import * as net from "net";
|
|
6327
6334
|
import * as os4 from "os";
|
|
6328
|
-
import * as
|
|
6335
|
+
import * as path22 from "path";
|
|
6329
6336
|
async function checkLitellmHealth(url) {
|
|
6330
6337
|
try {
|
|
6331
6338
|
const response = await fetch(`${url}/health`, { signal: AbortSignal.timeout(3e3) });
|
|
@@ -6394,6 +6401,8 @@ function locateLitellmScript() {
|
|
|
6394
6401
|
}
|
|
6395
6402
|
}
|
|
6396
6403
|
function resolveLitellmCommand() {
|
|
6404
|
+
const imageScript = "/opt/venv/bin/litellm";
|
|
6405
|
+
if (fs24.existsSync(imageScript)) return imageScript;
|
|
6397
6406
|
try {
|
|
6398
6407
|
execFileSync4("which", ["litellm"], { timeout: 3e3, stdio: "pipe" });
|
|
6399
6408
|
return "litellm";
|
|
@@ -6429,13 +6438,13 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
|
|
|
6429
6438
|
const spawnProxy = () => {
|
|
6430
6439
|
const portMatch = activeUrl.match(/:(\d+)/);
|
|
6431
6440
|
const port = portMatch ? portMatch[1] : "4000";
|
|
6432
|
-
const configPath =
|
|
6433
|
-
|
|
6441
|
+
const configPath = path22.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.yaml`);
|
|
6442
|
+
fs24.writeFileSync(configPath, generateLitellmConfigYaml(model));
|
|
6434
6443
|
const args = ["--config", configPath, "--port", port];
|
|
6435
|
-
const nextLogPath =
|
|
6436
|
-
const outFd =
|
|
6437
|
-
child =
|
|
6438
|
-
|
|
6444
|
+
const nextLogPath = path22.join(os4.tmpdir(), `kody-local-litellm-${Date.now()}.log`);
|
|
6445
|
+
const outFd = fs24.openSync(nextLogPath, "w");
|
|
6446
|
+
child = spawn4(cmd, args, { stdio: ["ignore", outFd, outFd], detached: true, env: childEnv });
|
|
6447
|
+
fs24.closeSync(outFd);
|
|
6439
6448
|
logPath = nextLogPath;
|
|
6440
6449
|
};
|
|
6441
6450
|
const waitForHealth = async () => {
|
|
@@ -6449,7 +6458,7 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
|
|
|
6449
6458
|
const readLogTail = () => {
|
|
6450
6459
|
if (!logPath) return "";
|
|
6451
6460
|
try {
|
|
6452
|
-
return
|
|
6461
|
+
return fs24.readFileSync(logPath, "utf-8").slice(-2e3);
|
|
6453
6462
|
} catch {
|
|
6454
6463
|
return "";
|
|
6455
6464
|
}
|
|
@@ -6532,10 +6541,10 @@ function canListen(port, host) {
|
|
|
6532
6541
|
});
|
|
6533
6542
|
}
|
|
6534
6543
|
function readDotenvApiKeys(projectDir) {
|
|
6535
|
-
const dotenvPath =
|
|
6536
|
-
if (!
|
|
6544
|
+
const dotenvPath = path22.join(projectDir, ".env");
|
|
6545
|
+
if (!fs24.existsSync(dotenvPath)) return {};
|
|
6537
6546
|
const result = {};
|
|
6538
|
-
for (const rawLine of
|
|
6547
|
+
for (const rawLine of fs24.readFileSync(dotenvPath, "utf-8").split("\n")) {
|
|
6539
6548
|
const line = rawLine.trim();
|
|
6540
6549
|
if (!line || line.startsWith("#")) continue;
|
|
6541
6550
|
const match = line.match(/^([A-Z_][A-Z0-9_]*_API_KEY)=(.*)$/);
|
|
@@ -6932,8 +6941,8 @@ var init_pushWithRetry = __esm({
|
|
|
6932
6941
|
|
|
6933
6942
|
// src/commit.ts
|
|
6934
6943
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
6935
|
-
import * as
|
|
6936
|
-
import * as
|
|
6944
|
+
import * as fs25 from "fs";
|
|
6945
|
+
import * as path23 from "path";
|
|
6937
6946
|
function isGitHubYamlPath(filePath) {
|
|
6938
6947
|
const normalized = filePath.replace(/^\.\/+/, "");
|
|
6939
6948
|
return normalized.startsWith(".github/") && /\.ya?ml$/i.test(normalized);
|
|
@@ -6975,18 +6984,18 @@ function ensureGitIdentity(cwd) {
|
|
|
6975
6984
|
}
|
|
6976
6985
|
function abortUnfinishedGitOps(cwd) {
|
|
6977
6986
|
const aborted = [];
|
|
6978
|
-
const gitDir =
|
|
6979
|
-
if (!
|
|
6980
|
-
if (
|
|
6987
|
+
const gitDir = path23.join(cwd ?? process.cwd(), ".git");
|
|
6988
|
+
if (!fs25.existsSync(gitDir)) return aborted;
|
|
6989
|
+
if (fs25.existsSync(path23.join(gitDir, "MERGE_HEAD"))) {
|
|
6981
6990
|
if (tryGit(["merge", "--abort"], cwd)) aborted.push("merge");
|
|
6982
6991
|
}
|
|
6983
|
-
if (
|
|
6992
|
+
if (fs25.existsSync(path23.join(gitDir, "CHERRY_PICK_HEAD"))) {
|
|
6984
6993
|
if (tryGit(["cherry-pick", "--abort"], cwd)) aborted.push("cherry-pick");
|
|
6985
6994
|
}
|
|
6986
|
-
if (
|
|
6995
|
+
if (fs25.existsSync(path23.join(gitDir, "REVERT_HEAD"))) {
|
|
6987
6996
|
if (tryGit(["revert", "--abort"], cwd)) aborted.push("revert");
|
|
6988
6997
|
}
|
|
6989
|
-
if (
|
|
6998
|
+
if (fs25.existsSync(path23.join(gitDir, "rebase-merge")) || fs25.existsSync(path23.join(gitDir, "rebase-apply"))) {
|
|
6990
6999
|
if (tryGit(["rebase", "--abort"], cwd)) aborted.push("rebase");
|
|
6991
7000
|
}
|
|
6992
7001
|
try {
|
|
@@ -7043,7 +7052,7 @@ function normalizeCommitMessage(raw) {
|
|
|
7043
7052
|
function commitAndPush(branch, agentMessage, cwd) {
|
|
7044
7053
|
const allChanged = listChangedFiles(cwd);
|
|
7045
7054
|
const allowedFiles = allChanged.filter((f) => !isForbiddenPath(f));
|
|
7046
|
-
const mergeHeadExists =
|
|
7055
|
+
const mergeHeadExists = fs25.existsSync(path23.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
|
|
7047
7056
|
if (allowedFiles.length === 0 && !mergeHeadExists) {
|
|
7048
7057
|
return { committed: false, pushed: false, sha: "", message: "" };
|
|
7049
7058
|
}
|
|
@@ -7683,13 +7692,13 @@ var init_state2 = __esm({
|
|
|
7683
7692
|
});
|
|
7684
7693
|
|
|
7685
7694
|
// src/goal/runLog.ts
|
|
7686
|
-
import * as
|
|
7695
|
+
import * as fs26 from "fs";
|
|
7687
7696
|
function stageGoalRunLogEvent(data, goalId, event, at = nowIso()) {
|
|
7688
7697
|
const logs = goalRunLogs(data);
|
|
7689
7698
|
const existing = logs[goalId];
|
|
7690
|
-
const
|
|
7699
|
+
const path51 = existing?.path ?? goalRunLogPath(goalId, data);
|
|
7691
7700
|
logs[goalId] = {
|
|
7692
|
-
path:
|
|
7701
|
+
path: path51,
|
|
7693
7702
|
events: [...existing?.events ?? [], buildGoalRunLogEvent(data, goalId, event, at)]
|
|
7694
7703
|
};
|
|
7695
7704
|
}
|
|
@@ -8025,8 +8034,8 @@ function readGithubEvent() {
|
|
|
8025
8034
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
8026
8035
|
if (!eventPath) return null;
|
|
8027
8036
|
try {
|
|
8028
|
-
if (!
|
|
8029
|
-
const parsed = JSON.parse(
|
|
8037
|
+
if (!fs26.existsSync(eventPath)) return null;
|
|
8038
|
+
const parsed = JSON.parse(fs26.readFileSync(eventPath, "utf-8"));
|
|
8030
8039
|
return recordValue3(parsed);
|
|
8031
8040
|
} catch {
|
|
8032
8041
|
return null;
|
|
@@ -8136,8 +8145,8 @@ var init_stateStore = __esm({
|
|
|
8136
8145
|
});
|
|
8137
8146
|
|
|
8138
8147
|
// src/goal/targetLoopResolution.ts
|
|
8139
|
-
import * as
|
|
8140
|
-
import * as
|
|
8148
|
+
import * as fs27 from "fs";
|
|
8149
|
+
import * as path24 from "path";
|
|
8141
8150
|
async function resolveActiveGoalLoopTarget(config, cwd, loopGoalId, loopGoal) {
|
|
8142
8151
|
const targetId = loopGoal.loopTarget?.id.trim() ?? "";
|
|
8143
8152
|
assertSafeGoalId(targetId, "loop target");
|
|
@@ -8215,11 +8224,11 @@ function goalInstanceTime(state) {
|
|
|
8215
8224
|
return Number.isNaN(parsed) ? 0 : parsed;
|
|
8216
8225
|
}
|
|
8217
8226
|
function loadGoalTemplate(cwd, targetId) {
|
|
8218
|
-
return readJsonObject(
|
|
8227
|
+
return readJsonObject(path24.join(cwd, ".kody-engine", "definitions", "goals", targetId, "state.json"));
|
|
8219
8228
|
}
|
|
8220
8229
|
function readJsonObject(filePath) {
|
|
8221
|
-
if (!
|
|
8222
|
-
const parsed = JSON.parse(
|
|
8230
|
+
if (!fs27.existsSync(filePath)) return null;
|
|
8231
|
+
const parsed = JSON.parse(fs27.readFileSync(filePath, "utf8"));
|
|
8223
8232
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
8224
8233
|
throw new Error(`goal template ${filePath} must be a JSON object`);
|
|
8225
8234
|
}
|
|
@@ -8662,11 +8671,11 @@ function validateWorkflow(value, options = {}) {
|
|
|
8662
8671
|
function formatWorkflowValidationIssues(issues) {
|
|
8663
8672
|
return issues.map((entry) => `${entry.path}: ${entry.message}`);
|
|
8664
8673
|
}
|
|
8665
|
-
function validateDataMatch(value,
|
|
8674
|
+
function validateDataMatch(value, path51, issues, capabilityOutputs) {
|
|
8666
8675
|
if (value === void 0) return;
|
|
8667
8676
|
const match = asRecord2(value);
|
|
8668
8677
|
if (!match || Object.keys(match).length === 0) {
|
|
8669
|
-
issue(issues, "invalid_condition",
|
|
8678
|
+
issue(issues, "invalid_condition", path51, "workflow condition must contain at least one match");
|
|
8670
8679
|
return;
|
|
8671
8680
|
}
|
|
8672
8681
|
for (const [field, expected] of Object.entries(match)) {
|
|
@@ -8674,7 +8683,7 @@ function validateDataMatch(value, path50, issues, capabilityOutputs) {
|
|
|
8674
8683
|
issue(
|
|
8675
8684
|
issues,
|
|
8676
8685
|
"invalid_data_path",
|
|
8677
|
-
`${
|
|
8686
|
+
`${path51}.${field}`,
|
|
8678
8687
|
`workflow condition must read from facts, evidence, artifacts, result, workflow, or lastOutcome`
|
|
8679
8688
|
);
|
|
8680
8689
|
}
|
|
@@ -8682,12 +8691,12 @@ function validateDataMatch(value, path50, issues, capabilityOutputs) {
|
|
|
8682
8691
|
issue(
|
|
8683
8692
|
issues,
|
|
8684
8693
|
"undeclared_result_path",
|
|
8685
|
-
`${
|
|
8694
|
+
`${path51}.${field}`,
|
|
8686
8695
|
`workflow condition reads ${field}, but the source capability does not declare it`
|
|
8687
8696
|
);
|
|
8688
8697
|
}
|
|
8689
8698
|
if (!isComparable(expected)) {
|
|
8690
|
-
issue(issues, "invalid_condition_value", `${
|
|
8699
|
+
issue(issues, "invalid_condition_value", `${path51}.${field}`, "workflow condition value must be a JSON scalar");
|
|
8691
8700
|
}
|
|
8692
8701
|
}
|
|
8693
8702
|
}
|
|
@@ -8705,8 +8714,8 @@ function isComparable(value) {
|
|
|
8705
8714
|
if (value === null || ["string", "number", "boolean"].includes(typeof value)) return true;
|
|
8706
8715
|
return Array.isArray(value) && value.length > 0 && value.every((item) => isComparable(item) && !Array.isArray(item));
|
|
8707
8716
|
}
|
|
8708
|
-
function issue(issues, code,
|
|
8709
|
-
issues.push({ code, path:
|
|
8717
|
+
function issue(issues, code, path51, message) {
|
|
8718
|
+
issues.push({ code, path: path51, message });
|
|
8710
8719
|
}
|
|
8711
8720
|
var SAFE_NAME, SAFE_STEP_ID, SAFE_DATA_PATH, SUPPORTED_STEP_FIELDS, SUPPORTED_TRANSITION_FIELDS;
|
|
8712
8721
|
var init_workflowValidation = __esm({
|
|
@@ -8738,8 +8747,8 @@ var init_workflowValidation = __esm({
|
|
|
8738
8747
|
});
|
|
8739
8748
|
|
|
8740
8749
|
// src/workflowDefinitions.ts
|
|
8741
|
-
import * as
|
|
8742
|
-
import * as
|
|
8750
|
+
import * as fs28 from "fs";
|
|
8751
|
+
import * as path25 from "path";
|
|
8743
8752
|
function isWorkflowDefinitionId(value) {
|
|
8744
8753
|
return WORKFLOW_ID_PATTERN.test(value);
|
|
8745
8754
|
}
|
|
@@ -8780,14 +8789,14 @@ function normalizeWorkflowDefinition(value) {
|
|
|
8780
8789
|
};
|
|
8781
8790
|
}
|
|
8782
8791
|
function readWorkflowDefinition(_config, cwd, id) {
|
|
8783
|
-
const filePath =
|
|
8784
|
-
if (!
|
|
8785
|
-
return parseWorkflowDefinition(
|
|
8792
|
+
const filePath = path25.join(cwd ?? process.cwd(), ".kody-engine", "runtime", workflowDefinitionPath(id));
|
|
8793
|
+
if (!fs28.existsSync(filePath)) return null;
|
|
8794
|
+
return parseWorkflowDefinition(fs28.readFileSync(filePath, "utf8"));
|
|
8786
8795
|
}
|
|
8787
8796
|
function workflowDefinitionToCapabilityFolder(id, workflow, source = workflowDefinitionPath(id)) {
|
|
8788
8797
|
return {
|
|
8789
8798
|
slug: id,
|
|
8790
|
-
dir:
|
|
8799
|
+
dir: path25.dirname(source),
|
|
8791
8800
|
profilePath: source,
|
|
8792
8801
|
bodyPath: source,
|
|
8793
8802
|
title: workflow.name,
|
|
@@ -8964,15 +8973,15 @@ var init_backendStateBackend = __esm({
|
|
|
8964
8973
|
this.jobsDir = opts.jobsDir.replace(/\/+$/, "");
|
|
8965
8974
|
}
|
|
8966
8975
|
async load(slug) {
|
|
8967
|
-
const
|
|
8976
|
+
const path51 = stateFilePath(this.jobsDir, slug);
|
|
8968
8977
|
const loaded = await createStateBackendFromEnv().get(this.tenantId, `capabilities/${slug}`, "job-state");
|
|
8969
8978
|
if (!loaded) {
|
|
8970
|
-
return { path:
|
|
8979
|
+
return { path: path51, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
8971
8980
|
}
|
|
8972
8981
|
if (!isStateEnvelope(loaded.doc)) {
|
|
8973
8982
|
throw new Error(`BackendStateBackend: capabilities/${slug} is not a StateEnvelope`);
|
|
8974
8983
|
}
|
|
8975
|
-
return { path:
|
|
8984
|
+
return { path: path51, handle: loaded.updatedAt, state: loaded.doc, created: false };
|
|
8976
8985
|
}
|
|
8977
8986
|
async save(loaded, next) {
|
|
8978
8987
|
if (!loaded.created && isStateUnchanged(loaded.state, next)) return false;
|
|
@@ -8992,8 +9001,8 @@ var init_backendStateBackend = __esm({
|
|
|
8992
9001
|
});
|
|
8993
9002
|
|
|
8994
9003
|
// src/scripts/jobState/localFileBackend.ts
|
|
8995
|
-
import * as
|
|
8996
|
-
import * as
|
|
9004
|
+
import * as fs29 from "fs";
|
|
9005
|
+
import * as path26 from "path";
|
|
8997
9006
|
function sanitizeKey(s) {
|
|
8998
9007
|
return s.replace(/[^A-Za-z0-9._-]/g, "-");
|
|
8999
9008
|
}
|
|
@@ -9049,7 +9058,7 @@ var init_localFileBackend = __esm({
|
|
|
9049
9058
|
if (!opts.owner || !opts.repo) throw new Error("LocalFileBackend: owner and repo are required");
|
|
9050
9059
|
this.cwd = opts.cwd;
|
|
9051
9060
|
this.jobsDir = opts.jobsDir;
|
|
9052
|
-
this.absDir =
|
|
9061
|
+
this.absDir = path26.resolve(opts.cwd, opts.jobsDir);
|
|
9053
9062
|
this.owner = opts.owner;
|
|
9054
9063
|
this.repo = opts.repo;
|
|
9055
9064
|
this.cache = opts.cache ?? defaultCacheAdapter();
|
|
@@ -9064,7 +9073,7 @@ var init_localFileBackend = __esm({
|
|
|
9064
9073
|
`);
|
|
9065
9074
|
return;
|
|
9066
9075
|
}
|
|
9067
|
-
|
|
9076
|
+
fs29.mkdirSync(this.absDir, { recursive: true });
|
|
9068
9077
|
const prefix = this.cacheKeyPrefix();
|
|
9069
9078
|
const probeKey = `${prefix}probe-${Date.now()}`;
|
|
9070
9079
|
try {
|
|
@@ -9093,7 +9102,7 @@ var init_localFileBackend = __esm({
|
|
|
9093
9102
|
`);
|
|
9094
9103
|
return;
|
|
9095
9104
|
}
|
|
9096
|
-
if (!
|
|
9105
|
+
if (!fs29.existsSync(this.absDir)) {
|
|
9097
9106
|
return;
|
|
9098
9107
|
}
|
|
9099
9108
|
const key = `${this.cacheKeyPrefix()}${process.env.GITHUB_RUN_ID ?? "norunid"}-${Date.now()}`;
|
|
@@ -9109,11 +9118,11 @@ var init_localFileBackend = __esm({
|
|
|
9109
9118
|
}
|
|
9110
9119
|
load(slug) {
|
|
9111
9120
|
const relPath = stateFilePath(this.jobsDir, slug);
|
|
9112
|
-
const absPath =
|
|
9113
|
-
if (!
|
|
9121
|
+
const absPath = path26.resolve(this.cwd, relPath);
|
|
9122
|
+
if (!fs29.existsSync(absPath)) {
|
|
9114
9123
|
return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
|
|
9115
9124
|
}
|
|
9116
|
-
const raw =
|
|
9125
|
+
const raw = fs29.readFileSync(absPath, "utf-8");
|
|
9117
9126
|
let parsed;
|
|
9118
9127
|
try {
|
|
9119
9128
|
parsed = JSON.parse(raw);
|
|
@@ -9130,13 +9139,13 @@ var init_localFileBackend = __esm({
|
|
|
9130
9139
|
if (!loaded.created && isStateUnchanged(loaded.state, next)) {
|
|
9131
9140
|
return false;
|
|
9132
9141
|
}
|
|
9133
|
-
const absPath =
|
|
9134
|
-
|
|
9142
|
+
const absPath = path26.resolve(this.cwd, loaded.path);
|
|
9143
|
+
fs29.mkdirSync(path26.dirname(absPath), { recursive: true });
|
|
9135
9144
|
const body = `${JSON.stringify(next, null, 2)}
|
|
9136
9145
|
`;
|
|
9137
9146
|
const tmpPath = `${absPath}.${process.pid}.tmp`;
|
|
9138
|
-
|
|
9139
|
-
|
|
9147
|
+
fs29.writeFileSync(tmpPath, body, "utf-8");
|
|
9148
|
+
fs29.renameSync(tmpPath, absPath);
|
|
9140
9149
|
return true;
|
|
9141
9150
|
}
|
|
9142
9151
|
cacheKeyPrefix() {
|
|
@@ -9168,7 +9177,7 @@ var init_jobState = __esm({
|
|
|
9168
9177
|
});
|
|
9169
9178
|
|
|
9170
9179
|
// src/scripts/goalCapabilityScheduling.ts
|
|
9171
|
-
import * as
|
|
9180
|
+
import * as path27 from "path";
|
|
9172
9181
|
function isCapabilityCadenceGoal(goal, extra) {
|
|
9173
9182
|
return extra.scheduleMode === "agentLoop" || extra.scheduler === "agentLoop" || goal.type === "standing" && goal.capabilities.length > 0;
|
|
9174
9183
|
}
|
|
@@ -9224,7 +9233,7 @@ function planTargetLoopSchedule(opts) {
|
|
|
9224
9233
|
}
|
|
9225
9234
|
async function planGoalCapabilitySchedule(opts) {
|
|
9226
9235
|
const jobsDir = opts.jobsDir ?? capabilitiesRoot(opts.cwd);
|
|
9227
|
-
const jobsRoot =
|
|
9236
|
+
const jobsRoot = path27.resolve(opts.cwd, jobsDir);
|
|
9228
9237
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
9229
9238
|
const at = now.toISOString();
|
|
9230
9239
|
const backend = resolveBackend({ config: opts.config, cwd: opts.cwd, jobsDir });
|
|
@@ -11039,8 +11048,8 @@ var init_classifyByLabel = __esm({
|
|
|
11039
11048
|
});
|
|
11040
11049
|
|
|
11041
11050
|
// src/scripts/commitAndPush.ts
|
|
11042
|
-
import * as
|
|
11043
|
-
import * as
|
|
11051
|
+
import * as fs30 from "fs";
|
|
11052
|
+
import * as path28 from "path";
|
|
11044
11053
|
function sentinelPathForStage(cwd, profileName) {
|
|
11045
11054
|
const runId = resolveRunId();
|
|
11046
11055
|
return runtimeStatePath(cwd, "agent-runs", runId, `commit-${profileName}.lock`);
|
|
@@ -11061,9 +11070,9 @@ var init_commitAndPush = __esm({
|
|
|
11061
11070
|
}
|
|
11062
11071
|
const idempotencyEnabled = process.env.KODY_COMMIT_IDEMPOTENCY !== "0";
|
|
11063
11072
|
const sentinel = idempotencyEnabled ? sentinelPathForStage(ctx.cwd, profile.name) : null;
|
|
11064
|
-
if (sentinel &&
|
|
11073
|
+
if (sentinel && fs30.existsSync(sentinel)) {
|
|
11065
11074
|
try {
|
|
11066
|
-
const replay = JSON.parse(
|
|
11075
|
+
const replay = JSON.parse(fs30.readFileSync(sentinel, "utf-8"));
|
|
11067
11076
|
ctx.data.commitResult = replay.commitResult ?? { committed: false, pushed: false };
|
|
11068
11077
|
if (Array.isArray(replay.changedFiles)) ctx.data.changedFiles = replay.changedFiles;
|
|
11069
11078
|
if (typeof replay.hasCommitsAhead === "boolean") ctx.data.hasCommitsAhead = replay.hasCommitsAhead;
|
|
@@ -11123,8 +11132,8 @@ var init_commitAndPush = __esm({
|
|
|
11123
11132
|
const result = ctx.data.commitResult;
|
|
11124
11133
|
if (sentinel && result?.committed) {
|
|
11125
11134
|
try {
|
|
11126
|
-
|
|
11127
|
-
|
|
11135
|
+
fs30.mkdirSync(path28.dirname(sentinel), { recursive: true });
|
|
11136
|
+
fs30.writeFileSync(
|
|
11128
11137
|
sentinel,
|
|
11129
11138
|
JSON.stringify(
|
|
11130
11139
|
{
|
|
@@ -11218,8 +11227,8 @@ var init_commitGoalState = __esm({
|
|
|
11218
11227
|
});
|
|
11219
11228
|
|
|
11220
11229
|
// src/scripts/composePrompt.ts
|
|
11221
|
-
import * as
|
|
11222
|
-
import * as
|
|
11230
|
+
import * as fs31 from "fs";
|
|
11231
|
+
import * as path29 from "path";
|
|
11223
11232
|
function fenceUntrusted(value) {
|
|
11224
11233
|
if (value.trim().length === 0) return value;
|
|
11225
11234
|
const safe = value.replace(/-{3,}\s*END UNTRUSTED INPUT\s*-{3,}/gi, "[END UNTRUSTED INPUT]");
|
|
@@ -11343,10 +11352,10 @@ var init_composePrompt = __esm({
|
|
|
11343
11352
|
const explicit = ctx.data.promptTemplate;
|
|
11344
11353
|
const mode = ctx.args.mode;
|
|
11345
11354
|
const candidates = [
|
|
11346
|
-
explicit ?
|
|
11347
|
-
mode ?
|
|
11348
|
-
|
|
11349
|
-
|
|
11355
|
+
explicit ? path29.join(profile.dir, explicit) : null,
|
|
11356
|
+
mode ? path29.join(profile.dir, "prompts", `${mode}.md`) : null,
|
|
11357
|
+
path29.join(profile.dir, "prompt.md"),
|
|
11358
|
+
path29.join(profile.dir, "capability.md")
|
|
11350
11359
|
].filter(Boolean);
|
|
11351
11360
|
let templatePath = "";
|
|
11352
11361
|
let template = "";
|
|
@@ -11359,7 +11368,7 @@ var init_composePrompt = __esm({
|
|
|
11359
11368
|
break;
|
|
11360
11369
|
}
|
|
11361
11370
|
try {
|
|
11362
|
-
template =
|
|
11371
|
+
template = fs31.readFileSync(c, "utf-8");
|
|
11363
11372
|
templatePath = c;
|
|
11364
11373
|
break;
|
|
11365
11374
|
} catch (err) {
|
|
@@ -11370,7 +11379,7 @@ var init_composePrompt = __esm({
|
|
|
11370
11379
|
if (!templatePath) {
|
|
11371
11380
|
let dirState;
|
|
11372
11381
|
try {
|
|
11373
|
-
dirState = `dir contents: [${
|
|
11382
|
+
dirState = `dir contents: [${fs31.readdirSync(profile.dir).join(", ")}]`;
|
|
11374
11383
|
} catch (err) {
|
|
11375
11384
|
dirState = `readdir(${profile.dir}) failed: ${err?.code ?? String(err)}`;
|
|
11376
11385
|
}
|
|
@@ -12059,19 +12068,19 @@ var init_deriveQaScopeFromIssue = __esm({
|
|
|
12059
12068
|
|
|
12060
12069
|
// src/scripts/diagMcp.ts
|
|
12061
12070
|
import { execFileSync as execFileSync9 } from "child_process";
|
|
12062
|
-
import * as
|
|
12071
|
+
import * as fs32 from "fs";
|
|
12063
12072
|
import * as os5 from "os";
|
|
12064
|
-
import * as
|
|
12073
|
+
import * as path30 from "path";
|
|
12065
12074
|
var diagMcp;
|
|
12066
12075
|
var init_diagMcp = __esm({
|
|
12067
12076
|
"src/scripts/diagMcp.ts"() {
|
|
12068
12077
|
"use strict";
|
|
12069
12078
|
diagMcp = async (_ctx) => {
|
|
12070
12079
|
const home = os5.homedir();
|
|
12071
|
-
const cacheDir =
|
|
12080
|
+
const cacheDir = path30.join(home, ".cache", "ms-playwright");
|
|
12072
12081
|
let entries = [];
|
|
12073
12082
|
try {
|
|
12074
|
-
entries =
|
|
12083
|
+
entries = fs32.readdirSync(cacheDir);
|
|
12075
12084
|
} catch {
|
|
12076
12085
|
}
|
|
12077
12086
|
const hasChromium = entries.some((e) => e.startsWith("chromium"));
|
|
@@ -12099,13 +12108,13 @@ var init_diagMcp = __esm({
|
|
|
12099
12108
|
});
|
|
12100
12109
|
|
|
12101
12110
|
// src/scripts/frameworkDetectors.ts
|
|
12102
|
-
import * as
|
|
12103
|
-
import * as
|
|
12111
|
+
import * as fs33 from "fs";
|
|
12112
|
+
import * as path31 from "path";
|
|
12104
12113
|
function detectFrameworks(cwd) {
|
|
12105
12114
|
const out = [];
|
|
12106
12115
|
let deps = {};
|
|
12107
12116
|
try {
|
|
12108
|
-
const pkg = JSON.parse(
|
|
12117
|
+
const pkg = JSON.parse(fs33.readFileSync(path31.join(cwd, "package.json"), "utf-8"));
|
|
12109
12118
|
deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
12110
12119
|
} catch {
|
|
12111
12120
|
return out;
|
|
@@ -12142,25 +12151,25 @@ function detectFrameworks(cwd) {
|
|
|
12142
12151
|
}
|
|
12143
12152
|
function findFile(cwd, candidates) {
|
|
12144
12153
|
for (const c of candidates) {
|
|
12145
|
-
if (
|
|
12154
|
+
if (fs33.existsSync(path31.join(cwd, c))) return c;
|
|
12146
12155
|
}
|
|
12147
12156
|
return null;
|
|
12148
12157
|
}
|
|
12149
12158
|
function discoverPayloadCollections(cwd) {
|
|
12150
12159
|
const out = [];
|
|
12151
12160
|
for (const dir of COLLECTION_DIRS) {
|
|
12152
|
-
const full =
|
|
12153
|
-
if (!
|
|
12161
|
+
const full = path31.join(cwd, dir);
|
|
12162
|
+
if (!fs33.existsSync(full)) continue;
|
|
12154
12163
|
let files;
|
|
12155
12164
|
try {
|
|
12156
|
-
files =
|
|
12165
|
+
files = fs33.readdirSync(full).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
12157
12166
|
} catch {
|
|
12158
12167
|
continue;
|
|
12159
12168
|
}
|
|
12160
12169
|
for (const file of files) {
|
|
12161
12170
|
try {
|
|
12162
|
-
const filePath =
|
|
12163
|
-
const content =
|
|
12171
|
+
const filePath = path31.join(full, file);
|
|
12172
|
+
const content = fs33.readFileSync(filePath, "utf-8").slice(0, 1e4);
|
|
12164
12173
|
const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
|
|
12165
12174
|
if (!slugMatch) continue;
|
|
12166
12175
|
const slug = slugMatch[1];
|
|
@@ -12174,7 +12183,7 @@ function discoverPayloadCollections(cwd) {
|
|
|
12174
12183
|
out.push({
|
|
12175
12184
|
name,
|
|
12176
12185
|
slug,
|
|
12177
|
-
filePath:
|
|
12186
|
+
filePath: path31.relative(cwd, filePath),
|
|
12178
12187
|
fields: fields.slice(0, 20),
|
|
12179
12188
|
hasAdmin
|
|
12180
12189
|
});
|
|
@@ -12187,28 +12196,28 @@ function discoverPayloadCollections(cwd) {
|
|
|
12187
12196
|
function discoverAdminComponents(cwd, collections) {
|
|
12188
12197
|
const out = [];
|
|
12189
12198
|
for (const dir of ADMIN_COMPONENT_DIRS) {
|
|
12190
|
-
const full =
|
|
12191
|
-
if (!
|
|
12199
|
+
const full = path31.join(cwd, dir);
|
|
12200
|
+
if (!fs33.existsSync(full)) continue;
|
|
12192
12201
|
let entries;
|
|
12193
12202
|
try {
|
|
12194
|
-
entries =
|
|
12203
|
+
entries = fs33.readdirSync(full, { withFileTypes: true });
|
|
12195
12204
|
} catch {
|
|
12196
12205
|
continue;
|
|
12197
12206
|
}
|
|
12198
12207
|
for (const entry of entries) {
|
|
12199
|
-
const entryPath =
|
|
12208
|
+
const entryPath = path31.join(full, entry.name);
|
|
12200
12209
|
let name;
|
|
12201
12210
|
let filePath;
|
|
12202
12211
|
if (entry.isDirectory()) {
|
|
12203
12212
|
const indexFile = ["index.tsx", "index.ts", "index.jsx", "index.js"].find(
|
|
12204
|
-
(f) =>
|
|
12213
|
+
(f) => fs33.existsSync(path31.join(entryPath, f))
|
|
12205
12214
|
);
|
|
12206
12215
|
if (!indexFile) continue;
|
|
12207
12216
|
name = entry.name;
|
|
12208
|
-
filePath =
|
|
12217
|
+
filePath = path31.relative(cwd, path31.join(entryPath, indexFile));
|
|
12209
12218
|
} else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
|
|
12210
12219
|
name = entry.name.replace(/\.(tsx?|jsx?)$/, "");
|
|
12211
|
-
filePath =
|
|
12220
|
+
filePath = path31.relative(cwd, entryPath);
|
|
12212
12221
|
} else {
|
|
12213
12222
|
continue;
|
|
12214
12223
|
}
|
|
@@ -12216,7 +12225,7 @@ function discoverAdminComponents(cwd, collections) {
|
|
|
12216
12225
|
if (collections) {
|
|
12217
12226
|
for (const col of collections) {
|
|
12218
12227
|
try {
|
|
12219
|
-
const colContent =
|
|
12228
|
+
const colContent = fs33.readFileSync(path31.join(cwd, col.filePath), "utf-8");
|
|
12220
12229
|
if (colContent.includes(name)) {
|
|
12221
12230
|
usedInCollection = col.slug;
|
|
12222
12231
|
break;
|
|
@@ -12234,8 +12243,8 @@ function scanApiRoutes(cwd) {
|
|
|
12234
12243
|
const out = [];
|
|
12235
12244
|
const appDirs = ["src/app", "app"];
|
|
12236
12245
|
for (const appDir of appDirs) {
|
|
12237
|
-
const apiDir =
|
|
12238
|
-
if (!
|
|
12246
|
+
const apiDir = path31.join(cwd, appDir, "api");
|
|
12247
|
+
if (!fs33.existsSync(apiDir)) continue;
|
|
12239
12248
|
walkApiRoutes(apiDir, "/api", cwd, out);
|
|
12240
12249
|
break;
|
|
12241
12250
|
}
|
|
@@ -12244,14 +12253,14 @@ function scanApiRoutes(cwd) {
|
|
|
12244
12253
|
function walkApiRoutes(dir, prefix, cwd, out) {
|
|
12245
12254
|
let entries;
|
|
12246
12255
|
try {
|
|
12247
|
-
entries =
|
|
12256
|
+
entries = fs33.readdirSync(dir, { withFileTypes: true });
|
|
12248
12257
|
} catch {
|
|
12249
12258
|
return;
|
|
12250
12259
|
}
|
|
12251
12260
|
const routeFile = entries.find((e) => e.isFile() && /^route\.(ts|js|tsx|jsx)$/.test(e.name));
|
|
12252
12261
|
if (routeFile) {
|
|
12253
12262
|
try {
|
|
12254
|
-
const content =
|
|
12263
|
+
const content = fs33.readFileSync(path31.join(dir, routeFile.name), "utf-8").slice(0, 5e3);
|
|
12255
12264
|
const methods = HTTP_METHODS.filter(
|
|
12256
12265
|
(m) => new RegExp(`export\\s+(?:async\\s+)?function\\s+${m}\\b`).test(content)
|
|
12257
12266
|
);
|
|
@@ -12259,7 +12268,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
12259
12268
|
out.push({
|
|
12260
12269
|
path: prefix,
|
|
12261
12270
|
methods,
|
|
12262
|
-
filePath:
|
|
12271
|
+
filePath: path31.relative(cwd, path31.join(dir, routeFile.name))
|
|
12263
12272
|
});
|
|
12264
12273
|
}
|
|
12265
12274
|
} catch {
|
|
@@ -12270,7 +12279,7 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
12270
12279
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
12271
12280
|
let segment = entry.name;
|
|
12272
12281
|
if (segment.startsWith("(") && segment.endsWith(")")) {
|
|
12273
|
-
walkApiRoutes(
|
|
12282
|
+
walkApiRoutes(path31.join(dir, entry.name), prefix, cwd, out);
|
|
12274
12283
|
continue;
|
|
12275
12284
|
}
|
|
12276
12285
|
if (segment.startsWith("[[") && segment.endsWith("]]")) {
|
|
@@ -12278,16 +12287,16 @@ function walkApiRoutes(dir, prefix, cwd, out) {
|
|
|
12278
12287
|
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
12279
12288
|
segment = `:${segment.slice(1, -1)}`;
|
|
12280
12289
|
}
|
|
12281
|
-
walkApiRoutes(
|
|
12290
|
+
walkApiRoutes(path31.join(dir, entry.name), `${prefix}/${segment}`, cwd, out);
|
|
12282
12291
|
}
|
|
12283
12292
|
}
|
|
12284
12293
|
function scanEnvVars(cwd) {
|
|
12285
12294
|
const candidates = [".env.example", ".env.local.example", ".env.template"];
|
|
12286
12295
|
for (const envFile of candidates) {
|
|
12287
|
-
const envPath =
|
|
12288
|
-
if (!
|
|
12296
|
+
const envPath = path31.join(cwd, envFile);
|
|
12297
|
+
if (!fs33.existsSync(envPath)) continue;
|
|
12289
12298
|
try {
|
|
12290
|
-
const content =
|
|
12299
|
+
const content = fs33.readFileSync(envPath, "utf-8");
|
|
12291
12300
|
const vars = [];
|
|
12292
12301
|
for (const line of content.split("\n")) {
|
|
12293
12302
|
const trimmed = line.trim();
|
|
@@ -12332,8 +12341,8 @@ var init_frameworkDetectors = __esm({
|
|
|
12332
12341
|
});
|
|
12333
12342
|
|
|
12334
12343
|
// src/scripts/discoverQaContext.ts
|
|
12335
|
-
import * as
|
|
12336
|
-
import * as
|
|
12344
|
+
import * as fs34 from "fs";
|
|
12345
|
+
import * as path32 from "path";
|
|
12337
12346
|
function runQaDiscovery(cwd) {
|
|
12338
12347
|
const out = {
|
|
12339
12348
|
routes: [],
|
|
@@ -12364,9 +12373,9 @@ function runQaDiscovery(cwd) {
|
|
|
12364
12373
|
}
|
|
12365
12374
|
function detectDevServer(cwd, out) {
|
|
12366
12375
|
try {
|
|
12367
|
-
const pkg = JSON.parse(
|
|
12376
|
+
const pkg = JSON.parse(fs34.readFileSync(path32.join(cwd, "package.json"), "utf-8"));
|
|
12368
12377
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
12369
|
-
const pm =
|
|
12378
|
+
const pm = fs34.existsSync(path32.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs34.existsSync(path32.join(cwd, "yarn.lock")) ? "yarn" : fs34.existsSync(path32.join(cwd, "bun.lockb")) ? "bun" : "npm";
|
|
12370
12379
|
if (pkg.scripts?.dev) out.devCommand = `${pm} dev`;
|
|
12371
12380
|
if (allDeps.next || allDeps.nuxt) out.devPort = 3e3;
|
|
12372
12381
|
else if (allDeps.vite) out.devPort = 5173;
|
|
@@ -12376,8 +12385,8 @@ function detectDevServer(cwd, out) {
|
|
|
12376
12385
|
function scanFrontendRoutes(cwd, out) {
|
|
12377
12386
|
const appDirs = ["src/app", "app"];
|
|
12378
12387
|
for (const appDir of appDirs) {
|
|
12379
|
-
const full =
|
|
12380
|
-
if (!
|
|
12388
|
+
const full = path32.join(cwd, appDir);
|
|
12389
|
+
if (!fs34.existsSync(full)) continue;
|
|
12381
12390
|
walkFrontendRoutes(full, "", out);
|
|
12382
12391
|
break;
|
|
12383
12392
|
}
|
|
@@ -12385,7 +12394,7 @@ function scanFrontendRoutes(cwd, out) {
|
|
|
12385
12394
|
function walkFrontendRoutes(dir, prefix, out) {
|
|
12386
12395
|
let entries;
|
|
12387
12396
|
try {
|
|
12388
|
-
entries =
|
|
12397
|
+
entries = fs34.readdirSync(dir, { withFileTypes: true });
|
|
12389
12398
|
} catch {
|
|
12390
12399
|
return;
|
|
12391
12400
|
}
|
|
@@ -12402,7 +12411,7 @@ function walkFrontendRoutes(dir, prefix, out) {
|
|
|
12402
12411
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
12403
12412
|
let segment = entry.name;
|
|
12404
12413
|
if (segment.startsWith("(") && segment.endsWith(")")) {
|
|
12405
|
-
walkFrontendRoutes(
|
|
12414
|
+
walkFrontendRoutes(path32.join(dir, entry.name), prefix, out);
|
|
12406
12415
|
continue;
|
|
12407
12416
|
}
|
|
12408
12417
|
if (segment.startsWith("[[") && segment.endsWith("]]")) {
|
|
@@ -12410,7 +12419,7 @@ function walkFrontendRoutes(dir, prefix, out) {
|
|
|
12410
12419
|
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
12411
12420
|
segment = `:${segment.slice(1, -1)}`;
|
|
12412
12421
|
}
|
|
12413
|
-
walkFrontendRoutes(
|
|
12422
|
+
walkFrontendRoutes(path32.join(dir, entry.name), `${prefix}/${segment}`, out);
|
|
12414
12423
|
}
|
|
12415
12424
|
}
|
|
12416
12425
|
function detectAuthFiles(cwd, out) {
|
|
@@ -12427,23 +12436,23 @@ function detectAuthFiles(cwd, out) {
|
|
|
12427
12436
|
"src/app/api/oauth"
|
|
12428
12437
|
];
|
|
12429
12438
|
for (const c of candidates) {
|
|
12430
|
-
if (
|
|
12439
|
+
if (fs34.existsSync(path32.join(cwd, c))) out.authFiles.push(c);
|
|
12431
12440
|
}
|
|
12432
12441
|
}
|
|
12433
12442
|
function detectRoles(cwd, out) {
|
|
12434
12443
|
const rolePaths = ["src/types", "src/lib", "src/utils", "src/constants", "src/access", "src/collections"];
|
|
12435
12444
|
for (const rp of rolePaths) {
|
|
12436
|
-
const dir =
|
|
12437
|
-
if (!
|
|
12445
|
+
const dir = path32.join(cwd, rp);
|
|
12446
|
+
if (!fs34.existsSync(dir)) continue;
|
|
12438
12447
|
let files;
|
|
12439
12448
|
try {
|
|
12440
|
-
files =
|
|
12449
|
+
files = fs34.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
|
|
12441
12450
|
} catch {
|
|
12442
12451
|
continue;
|
|
12443
12452
|
}
|
|
12444
12453
|
for (const f of files) {
|
|
12445
12454
|
try {
|
|
12446
|
-
const content =
|
|
12455
|
+
const content = fs34.readFileSync(path32.join(dir, f), "utf-8").slice(0, 5e3);
|
|
12447
12456
|
const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
|
|
12448
12457
|
if (roleMatches) {
|
|
12449
12458
|
for (const m of roleMatches) {
|
|
@@ -13724,12 +13733,12 @@ var init_fixFlow = __esm({
|
|
|
13724
13733
|
|
|
13725
13734
|
// src/scripts/initFlow.ts
|
|
13726
13735
|
import { execFileSync as execFileSync14 } from "child_process";
|
|
13727
|
-
import * as
|
|
13728
|
-
import * as
|
|
13736
|
+
import * as fs35 from "fs";
|
|
13737
|
+
import * as path33 from "path";
|
|
13729
13738
|
function detectPackageManager(cwd) {
|
|
13730
|
-
if (
|
|
13731
|
-
if (
|
|
13732
|
-
if (
|
|
13739
|
+
if (fs35.existsSync(path33.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
13740
|
+
if (fs35.existsSync(path33.join(cwd, "yarn.lock"))) return "yarn";
|
|
13741
|
+
if (fs35.existsSync(path33.join(cwd, "bun.lockb"))) return "bun";
|
|
13733
13742
|
return "npm";
|
|
13734
13743
|
}
|
|
13735
13744
|
function qualityCommandsFor(pm) {
|
|
@@ -13801,22 +13810,22 @@ function performInit(cwd, force) {
|
|
|
13801
13810
|
const pm = detectPackageManager(cwd);
|
|
13802
13811
|
const ownerRepo = detectOwnerRepo(cwd);
|
|
13803
13812
|
const defaultBranch = defaultBranchFromGit(cwd);
|
|
13804
|
-
const configPath =
|
|
13805
|
-
if (
|
|
13813
|
+
const configPath = path33.join(cwd, "kody.config.json");
|
|
13814
|
+
if (fs35.existsSync(configPath) && !force) {
|
|
13806
13815
|
skipped.push("kody.config.json");
|
|
13807
13816
|
} else {
|
|
13808
13817
|
const cfg = makeConfig(pm, ownerRepo, defaultBranch);
|
|
13809
|
-
|
|
13818
|
+
fs35.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
13810
13819
|
`);
|
|
13811
13820
|
wrote.push("kody.config.json");
|
|
13812
13821
|
}
|
|
13813
|
-
const workflowDir =
|
|
13814
|
-
const workflowPath =
|
|
13815
|
-
if (
|
|
13822
|
+
const workflowDir = path33.join(cwd, ".github", "workflows");
|
|
13823
|
+
const workflowPath = path33.join(workflowDir, "kody.yml");
|
|
13824
|
+
if (fs35.existsSync(workflowPath) && !force) {
|
|
13816
13825
|
skipped.push(".github/workflows/kody.yml");
|
|
13817
13826
|
} else {
|
|
13818
|
-
|
|
13819
|
-
|
|
13827
|
+
fs35.mkdirSync(workflowDir, { recursive: true });
|
|
13828
|
+
fs35.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
|
|
13820
13829
|
wrote.push(".github/workflows/kody.yml");
|
|
13821
13830
|
}
|
|
13822
13831
|
for (const exe of listImplementations()) {
|
|
@@ -13827,12 +13836,12 @@ function performInit(cwd, force) {
|
|
|
13827
13836
|
continue;
|
|
13828
13837
|
}
|
|
13829
13838
|
if (profile.kind !== "scheduled" || !profile.schedule) continue;
|
|
13830
|
-
const target =
|
|
13831
|
-
if (
|
|
13839
|
+
const target = path33.join(workflowDir, `kody-${exe.name}.yml`);
|
|
13840
|
+
if (fs35.existsSync(target) && !force) {
|
|
13832
13841
|
skipped.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
13833
13842
|
continue;
|
|
13834
13843
|
}
|
|
13835
|
-
|
|
13844
|
+
fs35.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
|
|
13836
13845
|
wrote.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
13837
13846
|
}
|
|
13838
13847
|
let labels;
|
|
@@ -13980,7 +13989,7 @@ Nothing to do. All files already present. (Use --force to overwrite.)
|
|
|
13980
13989
|
});
|
|
13981
13990
|
|
|
13982
13991
|
// src/scripts/loadAgentAdhoc.ts
|
|
13983
|
-
import * as
|
|
13992
|
+
import * as fs36 from "fs";
|
|
13984
13993
|
function resolveMessage(messageArg) {
|
|
13985
13994
|
const fromComment = readCommentBody();
|
|
13986
13995
|
if (fromComment) return stripDirective(fromComment);
|
|
@@ -13988,9 +13997,9 @@ function resolveMessage(messageArg) {
|
|
|
13988
13997
|
}
|
|
13989
13998
|
function readCommentBody() {
|
|
13990
13999
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
13991
|
-
if (!eventPath || !
|
|
14000
|
+
if (!eventPath || !fs36.existsSync(eventPath)) return "";
|
|
13992
14001
|
try {
|
|
13993
|
-
const event = JSON.parse(
|
|
14002
|
+
const event = JSON.parse(fs36.readFileSync(eventPath, "utf-8"));
|
|
13994
14003
|
return String(event.comment?.body ?? "");
|
|
13995
14004
|
} catch {
|
|
13996
14005
|
return "";
|
|
@@ -14044,10 +14053,10 @@ var init_loadAgentAdhoc = __esm({
|
|
|
14044
14053
|
throw new Error("loadAgentAdhoc: ctx.args.agent must be a non-empty slug");
|
|
14045
14054
|
}
|
|
14046
14055
|
const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
|
|
14047
|
-
if (!
|
|
14056
|
+
if (!fs36.existsSync(agentPath)) {
|
|
14048
14057
|
throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
|
|
14049
14058
|
}
|
|
14050
|
-
const { title, body } = parseAgentFile(
|
|
14059
|
+
const { title, body } = parseAgentFile(fs36.readFileSync(agentPath, "utf-8"), agentSlug);
|
|
14051
14060
|
const message = resolveMessage(ctx.args.message);
|
|
14052
14061
|
if (!message) {
|
|
14053
14062
|
throw new Error(
|
|
@@ -14119,13 +14128,13 @@ var init_loadCapabilityState = __esm({
|
|
|
14119
14128
|
function isCompanyIntentId(value) {
|
|
14120
14129
|
return SLUG_RE.test(value);
|
|
14121
14130
|
}
|
|
14122
|
-
function normalizeCompanyIntent(
|
|
14131
|
+
function normalizeCompanyIntent(path51, raw) {
|
|
14123
14132
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
14124
|
-
throw new Error(`${
|
|
14133
|
+
throw new Error(`${path51}: intent must be JSON object`);
|
|
14125
14134
|
}
|
|
14126
14135
|
const input = raw;
|
|
14127
14136
|
const id = stringField4(input.id);
|
|
14128
|
-
if (!id || !isCompanyIntentId(id)) throw new Error(`${
|
|
14137
|
+
if (!id || !isCompanyIntentId(id)) throw new Error(`${path51}: invalid intent id`);
|
|
14129
14138
|
const createdAt = stringField4(input.createdAt) || nowIso();
|
|
14130
14139
|
const updatedAt = stringField4(input.updatedAt) || createdAt;
|
|
14131
14140
|
const description = stringField4(input.description);
|
|
@@ -14416,8 +14425,8 @@ var init_loadIssueStateComment = __esm({
|
|
|
14416
14425
|
});
|
|
14417
14426
|
|
|
14418
14427
|
// src/scripts/loadJobFromFile.ts
|
|
14419
|
-
import * as
|
|
14420
|
-
import * as
|
|
14428
|
+
import * as fs37 from "fs";
|
|
14429
|
+
import * as path34 from "path";
|
|
14421
14430
|
function parseJobFile(raw, slug) {
|
|
14422
14431
|
let stripped = raw;
|
|
14423
14432
|
if (stripped.startsWith("---\n")) {
|
|
@@ -14456,10 +14465,10 @@ var init_loadJobFromFile = __esm({
|
|
|
14456
14465
|
if (!slug) {
|
|
14457
14466
|
throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
|
|
14458
14467
|
}
|
|
14459
|
-
const capability = resolveCapabilityFolder(slug,
|
|
14468
|
+
const capability = resolveCapabilityFolder(slug, path34.resolve(ctx.cwd, jobsDir));
|
|
14460
14469
|
if (!capability) {
|
|
14461
14470
|
throw new Error(
|
|
14462
|
-
`loadJobFromFile: capability folder not found or incomplete: ${
|
|
14471
|
+
`loadJobFromFile: capability folder not found or incomplete: ${path34.resolve(ctx.cwd, jobsDir, slug)}`
|
|
14463
14472
|
);
|
|
14464
14473
|
}
|
|
14465
14474
|
const { title, body, config } = capability;
|
|
@@ -14469,12 +14478,12 @@ var init_loadJobFromFile = __esm({
|
|
|
14469
14478
|
let agentIdentity = "";
|
|
14470
14479
|
if (agentSlug) {
|
|
14471
14480
|
const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
|
|
14472
|
-
if (!
|
|
14481
|
+
if (!fs37.existsSync(agentPath)) {
|
|
14473
14482
|
throw new Error(
|
|
14474
14483
|
`loadJobFromFile: capability '${slug}' declares agent '${agentSlug}' but ${agentPath} does not exist`
|
|
14475
14484
|
);
|
|
14476
14485
|
}
|
|
14477
|
-
const agentRaw =
|
|
14486
|
+
const agentRaw = fs37.readFileSync(agentPath, "utf-8");
|
|
14478
14487
|
const parsed = parseJobFile(agentRaw, agentSlug);
|
|
14479
14488
|
agentTitle = parsed.title;
|
|
14480
14489
|
agentIdentity = parsed.body;
|
|
@@ -14554,13 +14563,13 @@ ${truncate2(issue2.body, FINDING_BODY_MAX_BYTES)}`;
|
|
|
14554
14563
|
});
|
|
14555
14564
|
|
|
14556
14565
|
// src/scripts/kodyVariables.ts
|
|
14557
|
-
import * as
|
|
14558
|
-
import * as
|
|
14566
|
+
import * as fs38 from "fs";
|
|
14567
|
+
import * as path35 from "path";
|
|
14559
14568
|
function readKodyVariables(cwd) {
|
|
14560
|
-
const full =
|
|
14569
|
+
const full = path35.join(cwd, KODY_VARIABLES_REL_PATH);
|
|
14561
14570
|
let raw;
|
|
14562
14571
|
try {
|
|
14563
|
-
raw =
|
|
14572
|
+
raw = fs38.readFileSync(full, "utf-8");
|
|
14564
14573
|
} catch {
|
|
14565
14574
|
return {};
|
|
14566
14575
|
}
|
|
@@ -14723,8 +14732,8 @@ var init_runtimeSecrets = __esm({
|
|
|
14723
14732
|
});
|
|
14724
14733
|
|
|
14725
14734
|
// src/scripts/loadQaContext.ts
|
|
14726
|
-
import * as
|
|
14727
|
-
import * as
|
|
14735
|
+
import * as fs39 from "fs";
|
|
14736
|
+
import * as path36 from "path";
|
|
14728
14737
|
function parseSlugList(value) {
|
|
14729
14738
|
const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
14730
14739
|
return inner.split(",").map(
|
|
@@ -14753,18 +14762,18 @@ function readProfileAgents(raw) {
|
|
|
14753
14762
|
return { agent: agent ?? legacy ?? ["kody"], body };
|
|
14754
14763
|
}
|
|
14755
14764
|
function readProfile(cwd) {
|
|
14756
|
-
const dir =
|
|
14757
|
-
if (!
|
|
14765
|
+
const dir = path36.join(cwd, CONTEXT_DIR_REL_PATH);
|
|
14766
|
+
if (!fs39.existsSync(dir)) return "";
|
|
14758
14767
|
let entries;
|
|
14759
14768
|
try {
|
|
14760
|
-
entries =
|
|
14769
|
+
entries = fs39.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
14761
14770
|
} catch {
|
|
14762
14771
|
return "";
|
|
14763
14772
|
}
|
|
14764
14773
|
const blocks = [];
|
|
14765
14774
|
for (const file of entries) {
|
|
14766
14775
|
try {
|
|
14767
|
-
const raw =
|
|
14776
|
+
const raw = fs39.readFileSync(path36.join(dir, file), "utf-8");
|
|
14768
14777
|
const { agent, body } = readProfileAgents(raw);
|
|
14769
14778
|
if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
|
|
14770
14779
|
blocks.push(`## ${file}
|
|
@@ -14813,8 +14822,8 @@ var init_loadQaContext = __esm({
|
|
|
14813
14822
|
});
|
|
14814
14823
|
|
|
14815
14824
|
// src/taskContext.ts
|
|
14816
|
-
import * as
|
|
14817
|
-
import * as
|
|
14825
|
+
import * as fs40 from "fs";
|
|
14826
|
+
import * as path37 from "path";
|
|
14818
14827
|
function buildTaskContext(args) {
|
|
14819
14828
|
return {
|
|
14820
14829
|
schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
|
|
@@ -14830,9 +14839,9 @@ function buildTaskContext(args) {
|
|
|
14830
14839
|
function persistTaskContext(cwd, ctx) {
|
|
14831
14840
|
try {
|
|
14832
14841
|
const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
|
|
14833
|
-
|
|
14834
|
-
const file =
|
|
14835
|
-
|
|
14842
|
+
fs40.mkdirSync(dir, { recursive: true });
|
|
14843
|
+
const file = path37.join(dir, "task-context.json");
|
|
14844
|
+
fs40.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
|
|
14836
14845
|
`);
|
|
14837
14846
|
return file;
|
|
14838
14847
|
} catch (err) {
|
|
@@ -15259,19 +15268,19 @@ function parseAgencyModelProposal(raw) {
|
|
|
15259
15268
|
function normalizeBundleFiles(bundle) {
|
|
15260
15269
|
const seen = /* @__PURE__ */ new Set();
|
|
15261
15270
|
return bundle.files.map((file, index) => {
|
|
15262
|
-
const
|
|
15263
|
-
const parts =
|
|
15264
|
-
if (!
|
|
15271
|
+
const path51 = file.path.replace(/^\/+/, "");
|
|
15272
|
+
const parts = path51.split("/");
|
|
15273
|
+
if (!path51 || file.path.startsWith("/") || file.path.includes("\\") || parts.some((part) => !part || part === "." || part === "..")) {
|
|
15265
15274
|
throw new Error(`openAgencyModelReviewPr: files[${index}].path is unsafe`);
|
|
15266
15275
|
}
|
|
15267
15276
|
if (!/^(agents\/[^/]+\.md|capabilities\/[^/]+\/.+|goals\/(?:templates\/)?[^/]+\/.+|workflows\/[^/]+\.json)$/.test(
|
|
15268
|
-
|
|
15277
|
+
path51
|
|
15269
15278
|
)) {
|
|
15270
15279
|
throw new Error(`openAgencyModelReviewPr: files[${index}].path is not a supported definition path`);
|
|
15271
15280
|
}
|
|
15272
|
-
if (seen.has(
|
|
15273
|
-
seen.add(
|
|
15274
|
-
return { path:
|
|
15281
|
+
if (seen.has(path51)) throw new Error(`openAgencyModelReviewPr: duplicate generated file path: ${path51}`);
|
|
15282
|
+
seen.add(path51);
|
|
15283
|
+
return { path: path51, content: file.content.replace(/\r\n?/g, "\n") };
|
|
15275
15284
|
});
|
|
15276
15285
|
}
|
|
15277
15286
|
function buildProposalId(issueNumber, bundle, sourceLabel) {
|
|
@@ -16215,9 +16224,9 @@ var init_postResearchComment = __esm({
|
|
|
16215
16224
|
});
|
|
16216
16225
|
|
|
16217
16226
|
// src/scripts/prepareBrowserAuth.ts
|
|
16218
|
-
import * as
|
|
16227
|
+
import * as fs41 from "fs";
|
|
16219
16228
|
import * as os6 from "os";
|
|
16220
|
-
import * as
|
|
16229
|
+
import * as path38 from "path";
|
|
16221
16230
|
function appendAuthMessage(ctx, message) {
|
|
16222
16231
|
const current = typeof ctx.data.qaAuthBlock === "string" ? ctx.data.qaAuthBlock.trim() : "";
|
|
16223
16232
|
ctx.data.qaAuthBlock = current ? `${current}
|
|
@@ -16256,9 +16265,9 @@ async function githubJson(url, token) {
|
|
|
16256
16265
|
return await response.json();
|
|
16257
16266
|
}
|
|
16258
16267
|
function writeKodyStorageState(input) {
|
|
16259
|
-
const directory =
|
|
16260
|
-
|
|
16261
|
-
const file =
|
|
16268
|
+
const directory = fs41.mkdtempSync(path38.join(os6.tmpdir(), "kody-browser-auth-"));
|
|
16269
|
+
fs41.chmodSync(directory, 448);
|
|
16270
|
+
const file = path38.join(directory, "storage-state.json");
|
|
16262
16271
|
const now = Date.now();
|
|
16263
16272
|
const repoEntry = {
|
|
16264
16273
|
repoUrl: input.repoUrl,
|
|
@@ -16288,7 +16297,7 @@ function writeKodyStorageState(input) {
|
|
|
16288
16297
|
}
|
|
16289
16298
|
]
|
|
16290
16299
|
};
|
|
16291
|
-
|
|
16300
|
+
fs41.writeFileSync(file, JSON.stringify(storageState), { mode: 384 });
|
|
16292
16301
|
return { directory, file };
|
|
16293
16302
|
}
|
|
16294
16303
|
function configurePlaywright(profile, storageStatePath) {
|
|
@@ -16370,7 +16379,7 @@ async function prepareMethod(ctx, profile, method) {
|
|
|
16370
16379
|
configurePlaywright(profile, state.file);
|
|
16371
16380
|
const authDirectory = state.directory;
|
|
16372
16381
|
registerRuntimeCleanup(ctx, () => {
|
|
16373
|
-
|
|
16382
|
+
fs41.rmSync(authDirectory, { recursive: true, force: true });
|
|
16374
16383
|
});
|
|
16375
16384
|
appendAuthMessage(
|
|
16376
16385
|
ctx,
|
|
@@ -16378,7 +16387,7 @@ async function prepareMethod(ctx, profile, method) {
|
|
|
16378
16387
|
);
|
|
16379
16388
|
return true;
|
|
16380
16389
|
} catch (error) {
|
|
16381
|
-
if (state)
|
|
16390
|
+
if (state) fs41.rmSync(state.directory, { recursive: true, force: true });
|
|
16382
16391
|
const reason = error instanceof Error ? error.message : String(error);
|
|
16383
16392
|
appendAuthMessage(
|
|
16384
16393
|
ctx,
|
|
@@ -16491,9 +16500,9 @@ function latestResult(raw, agentResult) {
|
|
|
16491
16500
|
function recordField4(value) {
|
|
16492
16501
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
16493
16502
|
}
|
|
16494
|
-
function resolveDotted(root,
|
|
16495
|
-
if (!
|
|
16496
|
-
return
|
|
16503
|
+
function resolveDotted(root, path51) {
|
|
16504
|
+
if (!path51) return void 0;
|
|
16505
|
+
return path51.split(".").reduce((value, key) => recordField4(value)?.[key], root);
|
|
16497
16506
|
}
|
|
16498
16507
|
function stringValue4(value) {
|
|
16499
16508
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
@@ -17444,10 +17453,10 @@ var init_previewBuildHelpers = __esm({
|
|
|
17444
17453
|
});
|
|
17445
17454
|
|
|
17446
17455
|
// src/scripts/previewBuildRun.ts
|
|
17447
|
-
import { spawn as
|
|
17456
|
+
import { spawn as spawn5 } from "child_process";
|
|
17448
17457
|
async function runCmd(cmd, args, opts = {}) {
|
|
17449
17458
|
await new Promise((resolve16, reject) => {
|
|
17450
|
-
const child =
|
|
17459
|
+
const child = spawn5(cmd, args, {
|
|
17451
17460
|
cwd: opts.cwd,
|
|
17452
17461
|
env: { ...process.env, ...opts.env ?? {} },
|
|
17453
17462
|
stdio: opts.input ? ["pipe", "inherit", "inherit"] : "inherit"
|
|
@@ -17530,12 +17539,12 @@ fi
|
|
|
17530
17539
|
|
|
17531
17540
|
// src/scripts/runPreviewBuild.ts
|
|
17532
17541
|
import { copyFile, writeFile } from "fs/promises";
|
|
17533
|
-
import * as
|
|
17542
|
+
import * as path39 from "path";
|
|
17534
17543
|
import { fileURLToPath } from "url";
|
|
17535
17544
|
function bundledDockerfilePath(mode) {
|
|
17536
|
-
const here =
|
|
17545
|
+
const here = path39.dirname(fileURLToPath(import.meta.url));
|
|
17537
17546
|
const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
|
|
17538
|
-
return
|
|
17547
|
+
return path39.join(here, "preview-build-templates", file);
|
|
17539
17548
|
}
|
|
17540
17549
|
function required(name) {
|
|
17541
17550
|
const v = (process.env[name] ?? "").trim();
|
|
@@ -17782,10 +17791,10 @@ var init_runPreviewBuild = __esm({
|
|
|
17782
17791
|
console.log(`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`);
|
|
17783
17792
|
if (Object.keys(buildEnv).length > 0) {
|
|
17784
17793
|
const lines = Object.entries(buildEnv).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
|
|
17785
|
-
await writeFile(
|
|
17794
|
+
await writeFile(path39.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
|
|
17786
17795
|
`, "utf8");
|
|
17787
17796
|
}
|
|
17788
|
-
const consumerDockerfile =
|
|
17797
|
+
const consumerDockerfile = path39.join(ctx.cwd, "Dockerfile.preview");
|
|
17789
17798
|
const { stat } = await import("fs/promises");
|
|
17790
17799
|
let hasConsumerDockerfile = false;
|
|
17791
17800
|
try {
|
|
@@ -17969,8 +17978,8 @@ var init_tickShellRunner = __esm({
|
|
|
17969
17978
|
});
|
|
17970
17979
|
|
|
17971
17980
|
// src/scripts/runScheduledImplementationTick.ts
|
|
17972
|
-
import * as
|
|
17973
|
-
import * as
|
|
17981
|
+
import * as fs42 from "fs";
|
|
17982
|
+
import * as path40 from "path";
|
|
17974
17983
|
var runScheduledImplementationTick;
|
|
17975
17984
|
var init_runScheduledImplementationTick = __esm({
|
|
17976
17985
|
"src/scripts/runScheduledImplementationTick.ts"() {
|
|
@@ -17991,14 +18000,14 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
17991
18000
|
ctx.output.reason = `runScheduledImplementationTick: args.slug or ctx.args.${slugArg} must be non-empty capability slug`;
|
|
17992
18001
|
return;
|
|
17993
18002
|
}
|
|
17994
|
-
const capability = resolveCapabilityFolder(slug,
|
|
18003
|
+
const capability = resolveCapabilityFolder(slug, path40.resolve(ctx.cwd, jobsDir));
|
|
17995
18004
|
if (!capability) {
|
|
17996
18005
|
ctx.output.exitCode = 99;
|
|
17997
18006
|
ctx.output.reason = `runScheduledImplementationTick: capability folder not found or incomplete: ${slug} (searched ${jobsDir} and company store)`;
|
|
17998
18007
|
return;
|
|
17999
18008
|
}
|
|
18000
|
-
const shellPath =
|
|
18001
|
-
if (!
|
|
18009
|
+
const shellPath = path40.join(profile.dir, shell);
|
|
18010
|
+
if (!fs42.existsSync(shellPath)) {
|
|
18002
18011
|
ctx.output.exitCode = 99;
|
|
18003
18012
|
ctx.output.reason = `runScheduledImplementationTick: shell not found: ${shell} (looked in ${profile.dir})`;
|
|
18004
18013
|
return;
|
|
@@ -18029,8 +18038,8 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
18029
18038
|
});
|
|
18030
18039
|
|
|
18031
18040
|
// src/scripts/runTickScript.ts
|
|
18032
|
-
import * as
|
|
18033
|
-
import * as
|
|
18041
|
+
import * as fs43 from "fs";
|
|
18042
|
+
import * as path41 from "path";
|
|
18034
18043
|
var runTickScript;
|
|
18035
18044
|
var init_runTickScript = __esm({
|
|
18036
18045
|
"src/scripts/runTickScript.ts"() {
|
|
@@ -18050,10 +18059,10 @@ var init_runTickScript = __esm({
|
|
|
18050
18059
|
ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
|
|
18051
18060
|
return;
|
|
18052
18061
|
}
|
|
18053
|
-
const capability = readCapabilityFolder(
|
|
18062
|
+
const capability = readCapabilityFolder(path41.resolve(ctx.cwd, jobsDir), slug);
|
|
18054
18063
|
if (!capability) {
|
|
18055
18064
|
ctx.output.exitCode = 99;
|
|
18056
|
-
ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${
|
|
18065
|
+
ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${path41.resolve(ctx.cwd, jobsDir, slug)}`;
|
|
18057
18066
|
return;
|
|
18058
18067
|
}
|
|
18059
18068
|
const tickScript = capability.config.tickScript;
|
|
@@ -18062,8 +18071,8 @@ var init_runTickScript = __esm({
|
|
|
18062
18071
|
ctx.output.reason = `runTickScript: capability ${slug} has no \`tickScript\` in profile.json \u2014 route via capability-tick instead`;
|
|
18063
18072
|
return;
|
|
18064
18073
|
}
|
|
18065
|
-
const scriptPath =
|
|
18066
|
-
if (!
|
|
18074
|
+
const scriptPath = path41.isAbsolute(tickScript) ? tickScript : path41.join(ctx.cwd, tickScript);
|
|
18075
|
+
if (!fs43.existsSync(scriptPath)) {
|
|
18067
18076
|
ctx.output.exitCode = 99;
|
|
18068
18077
|
ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
|
|
18069
18078
|
return;
|
|
@@ -18345,7 +18354,7 @@ var init_syncFlow = __esm({
|
|
|
18345
18354
|
});
|
|
18346
18355
|
|
|
18347
18356
|
// src/scripts/validateAgencyModelProposal.ts
|
|
18348
|
-
import * as
|
|
18357
|
+
import * as path42 from "path";
|
|
18349
18358
|
function validateModelBundle(bundle, expectedKind, options = {}) {
|
|
18350
18359
|
const failures = [];
|
|
18351
18360
|
validateOneModel(bundle.model, bundle.files, "model", true, failures, expectedKind, options);
|
|
@@ -18671,7 +18680,7 @@ var init_validateAgencyModelProposal = __esm({
|
|
|
18671
18680
|
const bundle = parseAgencyModelProposal(raw);
|
|
18672
18681
|
const expectedKind = readExpectedModelKind(args);
|
|
18673
18682
|
const failures = validateModelBundle(bundle, expectedKind, {
|
|
18674
|
-
capabilityRoot:
|
|
18683
|
+
capabilityRoot: path42.join(ctx.cwd, ".kody", "capabilities")
|
|
18675
18684
|
});
|
|
18676
18685
|
if (failures.length > 0) {
|
|
18677
18686
|
throw new Error(`validateAgencyModelProposal: ${failures.join("; ")}`);
|
|
@@ -18716,7 +18725,7 @@ var init_verify2 = __esm({
|
|
|
18716
18725
|
});
|
|
18717
18726
|
|
|
18718
18727
|
// src/scripts/verifyReproFails.ts
|
|
18719
|
-
import { spawn as
|
|
18728
|
+
import { spawn as spawn6 } from "child_process";
|
|
18720
18729
|
function composeTestCommand(baseCmd, testPath) {
|
|
18721
18730
|
const trimmed = baseCmd.trim();
|
|
18722
18731
|
const lower = trimmed.toLowerCase();
|
|
@@ -18735,7 +18744,7 @@ function stripAnsi2(s) {
|
|
|
18735
18744
|
}
|
|
18736
18745
|
function runCommand2(command, cwd) {
|
|
18737
18746
|
return new Promise((resolve16) => {
|
|
18738
|
-
const child =
|
|
18747
|
+
const child = spawn6(command, {
|
|
18739
18748
|
cwd,
|
|
18740
18749
|
shell: true,
|
|
18741
18750
|
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1", CI: process.env.CI ?? "1" },
|
|
@@ -19065,9 +19074,9 @@ var init_waitForCi = __esm({
|
|
|
19065
19074
|
});
|
|
19066
19075
|
|
|
19067
19076
|
// src/scripts/warmupMcp.ts
|
|
19068
|
-
import { spawn as
|
|
19077
|
+
import { spawn as spawn7 } from "child_process";
|
|
19069
19078
|
async function warmupOne(command, args, env) {
|
|
19070
|
-
const child =
|
|
19079
|
+
const child = spawn7(command, args, {
|
|
19071
19080
|
stdio: ["pipe", "pipe", "pipe"],
|
|
19072
19081
|
env: env ? { ...process.env, ...env } : process.env
|
|
19073
19082
|
});
|
|
@@ -19222,7 +19231,7 @@ var init_warmupMcp = __esm({
|
|
|
19222
19231
|
});
|
|
19223
19232
|
|
|
19224
19233
|
// src/scripts/writeAgentRunSummary.ts
|
|
19225
|
-
import * as
|
|
19234
|
+
import * as fs44 from "fs";
|
|
19226
19235
|
var writeAgentRunSummary;
|
|
19227
19236
|
var init_writeAgentRunSummary = __esm({
|
|
19228
19237
|
"src/scripts/writeAgentRunSummary.ts"() {
|
|
@@ -19248,7 +19257,7 @@ var init_writeAgentRunSummary = __esm({
|
|
|
19248
19257
|
if (reason) lines.push(`- **Reason:** ${reason}`);
|
|
19249
19258
|
lines.push("");
|
|
19250
19259
|
try {
|
|
19251
|
-
|
|
19260
|
+
fs44.appendFileSync(summaryPath, `${lines.join("\n")}
|
|
19252
19261
|
`);
|
|
19253
19262
|
} catch {
|
|
19254
19263
|
}
|
|
@@ -19574,17 +19583,17 @@ var init_scripts = __esm({
|
|
|
19574
19583
|
});
|
|
19575
19584
|
|
|
19576
19585
|
// src/stateWorkspace.ts
|
|
19577
|
-
import * as
|
|
19578
|
-
import * as
|
|
19586
|
+
import * as fs45 from "fs";
|
|
19587
|
+
import * as path43 from "path";
|
|
19579
19588
|
function tenantId(config) {
|
|
19580
19589
|
const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
|
|
19581
19590
|
const repo = config.github?.repo?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[1]?.trim();
|
|
19582
19591
|
return owner && repo ? `${owner}/${repo}` : null;
|
|
19583
19592
|
}
|
|
19584
19593
|
function writeRuntimeFile(cwd, relativePath, content) {
|
|
19585
|
-
const target =
|
|
19586
|
-
|
|
19587
|
-
|
|
19594
|
+
const target = path43.join(cwd, RUNTIME_ROOT, relativePath);
|
|
19595
|
+
fs45.mkdirSync(path43.dirname(target), { recursive: true });
|
|
19596
|
+
fs45.writeFileSync(target, content, "utf8");
|
|
19588
19597
|
}
|
|
19589
19598
|
function record(value) {
|
|
19590
19599
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -19649,11 +19658,11 @@ async function hydrateStateWorkspace(config, cwd, backendOverride) {
|
|
|
19649
19658
|
throw new Error("Convex backend is required for runtime workspace documents");
|
|
19650
19659
|
return;
|
|
19651
19660
|
}
|
|
19652
|
-
const key = `${
|
|
19661
|
+
const key = `${path43.resolve(cwd)}|${tenant}`;
|
|
19653
19662
|
if (hydratedWorkspaces.has(key)) return;
|
|
19654
19663
|
const backend = backendOverride ?? createStateBackendFromEnv();
|
|
19655
|
-
const root =
|
|
19656
|
-
|
|
19664
|
+
const root = path43.join(cwd, RUNTIME_ROOT);
|
|
19665
|
+
fs45.rmSync(root, { recursive: true, force: true });
|
|
19657
19666
|
await Promise.all([
|
|
19658
19667
|
hydratePrefix(backend, tenant, cwd, "context:"),
|
|
19659
19668
|
hydratePrefix(backend, tenant, cwd, "memory:"),
|
|
@@ -19669,7 +19678,7 @@ var init_stateWorkspace = __esm({
|
|
|
19669
19678
|
"src/stateWorkspace.ts"() {
|
|
19670
19679
|
"use strict";
|
|
19671
19680
|
init_state_backend();
|
|
19672
|
-
RUNTIME_ROOT =
|
|
19681
|
+
RUNTIME_ROOT = path43.join(".kody-engine", "runtime");
|
|
19673
19682
|
hydratedWorkspaces = /* @__PURE__ */ new Set();
|
|
19674
19683
|
}
|
|
19675
19684
|
});
|
|
@@ -19739,10 +19748,10 @@ var init_tools = __esm({
|
|
|
19739
19748
|
});
|
|
19740
19749
|
|
|
19741
19750
|
// src/executor.ts
|
|
19742
|
-
import { spawn as
|
|
19743
|
-
import * as
|
|
19751
|
+
import { spawn as spawn8 } from "child_process";
|
|
19752
|
+
import * as fs46 from "fs";
|
|
19744
19753
|
import * as os7 from "os";
|
|
19745
|
-
import * as
|
|
19754
|
+
import * as path44 from "path";
|
|
19746
19755
|
function isMutatingPostflight(scriptName) {
|
|
19747
19756
|
return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
|
|
19748
19757
|
}
|
|
@@ -19970,7 +19979,7 @@ async function runImplementation(profileName, input) {
|
|
|
19970
19979
|
const jobWhyBlock = typeof ctx.data.jobWhy === "string" ? operatorRequestBlock(ctx.data.jobWhy) : null;
|
|
19971
19980
|
const jobRefBlock = jobReferenceBlock(profileName, profile, ctx.data);
|
|
19972
19981
|
const invokeAgent = async (prompt) => {
|
|
19973
|
-
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) =>
|
|
19982
|
+
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path44.isAbsolute(p) ? p : path44.resolve(profile.dir, p)).filter((p) => p.length > 0);
|
|
19974
19983
|
const syntheticPath = ctx.data.syntheticPluginPath;
|
|
19975
19984
|
const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
|
|
19976
19985
|
const agents = loadSubagents(profile);
|
|
@@ -20408,17 +20417,17 @@ function clearStampedLifecycleLabels(profile, ctx) {
|
|
|
20408
20417
|
function resolveProfilePath(profileName) {
|
|
20409
20418
|
const found = resolveImplementation(profileName);
|
|
20410
20419
|
if (found) return found;
|
|
20411
|
-
const here =
|
|
20420
|
+
const here = path44.dirname(new URL(import.meta.url).pathname);
|
|
20412
20421
|
const candidates = [
|
|
20413
|
-
|
|
20422
|
+
path44.join(here, "implementations", profileName, "profile.json"),
|
|
20414
20423
|
// same-dir sibling (dev)
|
|
20415
|
-
|
|
20424
|
+
path44.join(here, "..", "implementations", profileName, "profile.json"),
|
|
20416
20425
|
// up one (prod: dist/bin → dist/implementations)
|
|
20417
|
-
|
|
20426
|
+
path44.join(here, "..", "src", "implementations", profileName, "profile.json")
|
|
20418
20427
|
// fallback
|
|
20419
20428
|
];
|
|
20420
20429
|
for (const c of candidates) {
|
|
20421
|
-
if (
|
|
20430
|
+
if (fs46.existsSync(c)) return c;
|
|
20422
20431
|
}
|
|
20423
20432
|
return candidates[0];
|
|
20424
20433
|
}
|
|
@@ -20533,15 +20542,15 @@ function resolveShellTimeoutMs(entry) {
|
|
|
20533
20542
|
}
|
|
20534
20543
|
async function runShellEntry(entry, ctx, profile) {
|
|
20535
20544
|
const shellName = entry.shell;
|
|
20536
|
-
const shellPath =
|
|
20537
|
-
if (!
|
|
20545
|
+
const shellPath = path44.join(profile.dir, shellName);
|
|
20546
|
+
if (!fs46.existsSync(shellPath)) {
|
|
20538
20547
|
ctx.skipAgent = true;
|
|
20539
20548
|
ctx.output.exitCode = 99;
|
|
20540
20549
|
ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
|
|
20541
20550
|
return;
|
|
20542
20551
|
}
|
|
20543
20552
|
const positional = entry.with ? Object.values(entry.with).map((v) => String(v)) : [];
|
|
20544
|
-
const outputFile =
|
|
20553
|
+
const outputFile = path44.join(
|
|
20545
20554
|
os7.tmpdir(),
|
|
20546
20555
|
`kody-shell-output-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
|
20547
20556
|
);
|
|
@@ -20554,7 +20563,7 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
20554
20563
|
env[`KODY_CFG_${k}`] = v;
|
|
20555
20564
|
}
|
|
20556
20565
|
const timeoutMs = resolveShellTimeoutMs(entry);
|
|
20557
|
-
const child =
|
|
20566
|
+
const child = spawn8("bash", [shellPath, ...positional], {
|
|
20558
20567
|
cwd: ctx.cwd,
|
|
20559
20568
|
env,
|
|
20560
20569
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -20613,9 +20622,9 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
20613
20622
|
}
|
|
20614
20623
|
let sideChannelText = "";
|
|
20615
20624
|
try {
|
|
20616
|
-
if (
|
|
20617
|
-
sideChannelText =
|
|
20618
|
-
|
|
20625
|
+
if (fs46.existsSync(outputFile)) {
|
|
20626
|
+
sideChannelText = fs46.readFileSync(outputFile, "utf-8");
|
|
20627
|
+
fs46.rmSync(outputFile, { force: true });
|
|
20619
20628
|
}
|
|
20620
20629
|
} catch {
|
|
20621
20630
|
}
|
|
@@ -20785,7 +20794,7 @@ __export(job_exports, {
|
|
|
20785
20794
|
stableJobKey: () => stableJobKey,
|
|
20786
20795
|
validateJob: () => validateJob
|
|
20787
20796
|
});
|
|
20788
|
-
import * as
|
|
20797
|
+
import * as path45 from "path";
|
|
20789
20798
|
function newJobId(flavor) {
|
|
20790
20799
|
localJobSeq += 1;
|
|
20791
20800
|
const runId = process.env.GITHUB_RUN_ID;
|
|
@@ -21248,11 +21257,11 @@ function selectWorkflowTransition(step, data, counts) {
|
|
|
21248
21257
|
}
|
|
21249
21258
|
function workflowResultConditionPaths(transitions) {
|
|
21250
21259
|
return transitions.flatMap(
|
|
21251
|
-
(transition) => Object.keys(transition.when ?? {}).filter((
|
|
21260
|
+
(transition) => Object.keys(transition.when ?? {}).filter((path51) => path51.startsWith("result."))
|
|
21252
21261
|
);
|
|
21253
21262
|
}
|
|
21254
21263
|
function conditionMatches(condition, context) {
|
|
21255
|
-
return Object.entries(condition).every(([
|
|
21264
|
+
return Object.entries(condition).every(([path51, expected]) => valueMatches(resolveDottedPath2(context, path51), expected));
|
|
21256
21265
|
}
|
|
21257
21266
|
function withWorkflowBoundaryEval(capability, result) {
|
|
21258
21267
|
const capabilityKind = capability.config.capabilityKind;
|
|
@@ -21410,7 +21419,7 @@ function loadCapabilityContext(slug, cwd) {
|
|
|
21410
21419
|
return resolveCapabilityFolder(slug, hydratedCapabilitiesRoot(cwd));
|
|
21411
21420
|
}
|
|
21412
21421
|
function hydratedCapabilitiesRoot(cwd) {
|
|
21413
|
-
return
|
|
21422
|
+
return path45.join(cwd, ".kody-engine", "definitions", "capabilities");
|
|
21414
21423
|
}
|
|
21415
21424
|
function loadWorkflowContext(slug, base) {
|
|
21416
21425
|
if (!slug || !base.config || !isWorkflowDefinitionId(slug)) return null;
|
|
@@ -21573,7 +21582,7 @@ function translateOpenAISseToBrain(opts) {
|
|
|
21573
21582
|
|
|
21574
21583
|
// src/servers/brain-serve.ts
|
|
21575
21584
|
import { createServer as createServer2 } from "http";
|
|
21576
|
-
import * as
|
|
21585
|
+
import * as path48 from "path";
|
|
21577
21586
|
|
|
21578
21587
|
// src/chat/loop.ts
|
|
21579
21588
|
init_agent();
|
|
@@ -21581,8 +21590,8 @@ init_agents();
|
|
|
21581
21590
|
init_config();
|
|
21582
21591
|
init_registry();
|
|
21583
21592
|
init_task_artifacts();
|
|
21584
|
-
import * as
|
|
21585
|
-
import * as
|
|
21593
|
+
import * as fs15 from "fs";
|
|
21594
|
+
import * as path16 from "path";
|
|
21586
21595
|
|
|
21587
21596
|
// src/chat/attachments.ts
|
|
21588
21597
|
init_runtimePaths();
|
|
@@ -21639,12 +21648,293 @@ function prepareAttachments(turns, cwd, sessionId) {
|
|
|
21639
21648
|
return { turns: rewritten, imagePaths };
|
|
21640
21649
|
}
|
|
21641
21650
|
|
|
21642
|
-
// src/chat/
|
|
21651
|
+
// src/chat/codex-app-server.ts
|
|
21652
|
+
import { spawn as spawn3 } from "child_process";
|
|
21643
21653
|
import * as fs12 from "fs";
|
|
21644
21654
|
import * as path13 from "path";
|
|
21655
|
+
import { createInterface } from "readline";
|
|
21656
|
+
function codexThreadStartParams(args) {
|
|
21657
|
+
return {
|
|
21658
|
+
cwd: args.cwd,
|
|
21659
|
+
developerInstructions: args.developerInstructions
|
|
21660
|
+
};
|
|
21661
|
+
}
|
|
21662
|
+
function codexTurnStartParams(args) {
|
|
21663
|
+
return {
|
|
21664
|
+
threadId: args.threadId,
|
|
21665
|
+
input: [{ type: "text", text: args.message }]
|
|
21666
|
+
};
|
|
21667
|
+
}
|
|
21668
|
+
function translateCodexNotification(notification, chatId) {
|
|
21669
|
+
const params = notification.params ?? {};
|
|
21670
|
+
if (notification.method === "item/agentMessage/delta") {
|
|
21671
|
+
const delta = params.delta;
|
|
21672
|
+
return typeof delta === "string" && delta.length > 0 ? [{ type: "text", text: delta, chatId }] : [];
|
|
21673
|
+
}
|
|
21674
|
+
if (notification.method === "turn/completed") {
|
|
21675
|
+
return [{ type: "done", chatId }];
|
|
21676
|
+
}
|
|
21677
|
+
if (notification.method === "error") {
|
|
21678
|
+
const message = params.message;
|
|
21679
|
+
return [
|
|
21680
|
+
{
|
|
21681
|
+
type: "error",
|
|
21682
|
+
error: typeof message === "string" ? message : "Codex app-server error",
|
|
21683
|
+
chatId
|
|
21684
|
+
}
|
|
21685
|
+
];
|
|
21686
|
+
}
|
|
21687
|
+
if (notification.method === "item/started") {
|
|
21688
|
+
const item = params.item;
|
|
21689
|
+
if (!item || typeof item !== "object") return [];
|
|
21690
|
+
const record2 = item;
|
|
21691
|
+
return [
|
|
21692
|
+
{
|
|
21693
|
+
type: "tool_use",
|
|
21694
|
+
name: typeof record2.type === "string" ? record2.type : "tool",
|
|
21695
|
+
input: record2,
|
|
21696
|
+
chatId
|
|
21697
|
+
}
|
|
21698
|
+
];
|
|
21699
|
+
}
|
|
21700
|
+
return [];
|
|
21701
|
+
}
|
|
21702
|
+
var CodexAppServerClient = class {
|
|
21703
|
+
process;
|
|
21704
|
+
initialized = false;
|
|
21705
|
+
constructor(options) {
|
|
21706
|
+
const child = (options.spawnImpl ?? spawn3)("codex", ["app-server", "--stdio"], {
|
|
21707
|
+
cwd: options.cwd,
|
|
21708
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
21709
|
+
});
|
|
21710
|
+
this.process = {
|
|
21711
|
+
child,
|
|
21712
|
+
nextId: 1,
|
|
21713
|
+
pending: /* @__PURE__ */ new Map(),
|
|
21714
|
+
turnWaiters: /* @__PURE__ */ new Map()
|
|
21715
|
+
};
|
|
21716
|
+
const lines = createInterface({ input: child.stdout });
|
|
21717
|
+
lines.on("line", (line) => this.handleLine(line));
|
|
21718
|
+
child.on("error", (error) => this.fail(error));
|
|
21719
|
+
child.on("exit", (code, signal) => {
|
|
21720
|
+
this.fail(new Error(`codex app-server exited (${code ?? `signal ${signal}`})`));
|
|
21721
|
+
});
|
|
21722
|
+
}
|
|
21723
|
+
async startThread(args) {
|
|
21724
|
+
await this.ensureInitialized();
|
|
21725
|
+
const result = await this.request("thread/start", codexThreadStartParams(args));
|
|
21726
|
+
const thread = result.thread;
|
|
21727
|
+
if (!thread || typeof thread !== "object") {
|
|
21728
|
+
throw new Error("Codex app-server returned no thread");
|
|
21729
|
+
}
|
|
21730
|
+
const id = thread.id;
|
|
21731
|
+
if (typeof id !== "string" || !id) throw new Error("Codex app-server returned an invalid thread id");
|
|
21732
|
+
return id;
|
|
21733
|
+
}
|
|
21734
|
+
async resumeThread(threadId) {
|
|
21735
|
+
await this.ensureInitialized();
|
|
21736
|
+
await this.request("thread/resume", { threadId });
|
|
21737
|
+
}
|
|
21738
|
+
async runTurn(args) {
|
|
21739
|
+
await new Promise((resolve16, reject) => {
|
|
21740
|
+
this.process.turnWaiters.set(args.threadId, {
|
|
21741
|
+
resolve: resolve16,
|
|
21742
|
+
reject,
|
|
21743
|
+
onNotification: args.onNotification,
|
|
21744
|
+
queue: Promise.resolve()
|
|
21745
|
+
});
|
|
21746
|
+
void this.request("turn/start", codexTurnStartParams(args)).catch((error) => {
|
|
21747
|
+
this.process.turnWaiters.delete(args.threadId);
|
|
21748
|
+
reject(error);
|
|
21749
|
+
});
|
|
21750
|
+
});
|
|
21751
|
+
}
|
|
21752
|
+
close() {
|
|
21753
|
+
this.process.child.kill();
|
|
21754
|
+
this.fail(new Error("Codex app-server client closed"));
|
|
21755
|
+
}
|
|
21756
|
+
request(method, params) {
|
|
21757
|
+
const id = this.process.nextId++;
|
|
21758
|
+
return new Promise((resolve16, reject) => {
|
|
21759
|
+
this.process.pending.set(id, { resolve: resolve16, reject });
|
|
21760
|
+
this.process.child.stdin.write(`${JSON.stringify({ method, id, params })}
|
|
21761
|
+
`);
|
|
21762
|
+
});
|
|
21763
|
+
}
|
|
21764
|
+
notify(method, params) {
|
|
21765
|
+
this.process.child.stdin.write(`${JSON.stringify({ method, params })}
|
|
21766
|
+
`);
|
|
21767
|
+
}
|
|
21768
|
+
async ensureInitialized() {
|
|
21769
|
+
if (this.initialized) return;
|
|
21770
|
+
await this.request("initialize", {
|
|
21771
|
+
clientInfo: { name: "kody-brain", version: "0.1.0" }
|
|
21772
|
+
});
|
|
21773
|
+
this.notify("initialized", {});
|
|
21774
|
+
this.initialized = true;
|
|
21775
|
+
}
|
|
21776
|
+
handleLine(line) {
|
|
21777
|
+
let message;
|
|
21778
|
+
try {
|
|
21779
|
+
message = JSON.parse(line);
|
|
21780
|
+
} catch {
|
|
21781
|
+
return;
|
|
21782
|
+
}
|
|
21783
|
+
if (typeof message.id === "number") {
|
|
21784
|
+
const pending = this.process.pending.get(message.id);
|
|
21785
|
+
if (!pending) return;
|
|
21786
|
+
this.process.pending.delete(message.id);
|
|
21787
|
+
if (message.error && typeof message.error === "object") {
|
|
21788
|
+
const error = message.error;
|
|
21789
|
+
pending.reject(new Error(typeof error.message === "string" ? error.message : "Codex request failed"));
|
|
21790
|
+
} else {
|
|
21791
|
+
pending.resolve(message.result ?? {});
|
|
21792
|
+
}
|
|
21793
|
+
return;
|
|
21794
|
+
}
|
|
21795
|
+
if (typeof message.method !== "string") return;
|
|
21796
|
+
const notification = {
|
|
21797
|
+
method: message.method,
|
|
21798
|
+
params: typeof message.params === "object" && message.params !== null ? message.params : {}
|
|
21799
|
+
};
|
|
21800
|
+
const threadId = notification.params?.threadId;
|
|
21801
|
+
if (typeof threadId !== "string") return;
|
|
21802
|
+
const waiter = this.process.turnWaiters.get(threadId);
|
|
21803
|
+
if (!waiter) return;
|
|
21804
|
+
waiter.queue = waiter.queue.then(() => waiter.onNotification(notification));
|
|
21805
|
+
if (notification.method === "turn/completed" || notification.method === "error") {
|
|
21806
|
+
this.process.turnWaiters.delete(threadId);
|
|
21807
|
+
void waiter.queue.then(() => {
|
|
21808
|
+
if (notification.method === "error") {
|
|
21809
|
+
waiter.reject(new Error(String(notification.params?.message ?? "Codex turn failed")));
|
|
21810
|
+
} else {
|
|
21811
|
+
waiter.resolve();
|
|
21812
|
+
}
|
|
21813
|
+
}, waiter.reject);
|
|
21814
|
+
}
|
|
21815
|
+
}
|
|
21816
|
+
fail(error) {
|
|
21817
|
+
for (const pending of this.process.pending.values()) pending.reject(error);
|
|
21818
|
+
this.process.pending.clear();
|
|
21819
|
+
for (const waiter of this.process.turnWaiters.values()) waiter.reject(error);
|
|
21820
|
+
this.process.turnWaiters.clear();
|
|
21821
|
+
}
|
|
21822
|
+
};
|
|
21823
|
+
var clients = /* @__PURE__ */ new Map();
|
|
21824
|
+
function threadMapPath(cwd) {
|
|
21825
|
+
return path13.join(cwd, ".kody-engine", "runtime", "codex-threads.json");
|
|
21826
|
+
}
|
|
21827
|
+
function readThreadMap(cwd) {
|
|
21828
|
+
try {
|
|
21829
|
+
const value = JSON.parse(fs12.readFileSync(threadMapPath(cwd), "utf8"));
|
|
21830
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
21831
|
+
return Object.fromEntries(
|
|
21832
|
+
Object.entries(value).filter(
|
|
21833
|
+
(entry) => typeof entry[1] === "string"
|
|
21834
|
+
)
|
|
21835
|
+
);
|
|
21836
|
+
} catch {
|
|
21837
|
+
return {};
|
|
21838
|
+
}
|
|
21839
|
+
}
|
|
21840
|
+
function writeThreadMap(cwd, map) {
|
|
21841
|
+
const file = threadMapPath(cwd);
|
|
21842
|
+
fs12.mkdirSync(path13.dirname(file), { recursive: true });
|
|
21843
|
+
fs12.writeFileSync(file, `${JSON.stringify(map, null, 2)}
|
|
21844
|
+
`);
|
|
21845
|
+
}
|
|
21846
|
+
async function runCodexChatTurn(args) {
|
|
21847
|
+
const { opts, turns, systemPrompt, store } = args;
|
|
21848
|
+
const last = turns.at(-1);
|
|
21849
|
+
if (!last || last.role !== "user") {
|
|
21850
|
+
const error = "last turn is not a user message";
|
|
21851
|
+
await opts.sink.emit({
|
|
21852
|
+
event: "chat.error",
|
|
21853
|
+
payload: { error },
|
|
21854
|
+
runId: opts.sessionId,
|
|
21855
|
+
emittedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
21856
|
+
});
|
|
21857
|
+
return { exitCode: 64, error };
|
|
21858
|
+
}
|
|
21859
|
+
const client = clients.get(opts.cwd) ?? new CodexAppServerClient({ cwd: opts.cwd });
|
|
21860
|
+
clients.set(opts.cwd, client);
|
|
21861
|
+
const map = readThreadMap(opts.cwd);
|
|
21862
|
+
let threadId = map[opts.sessionId];
|
|
21863
|
+
if (threadId) {
|
|
21864
|
+
try {
|
|
21865
|
+
await client.resumeThread(threadId);
|
|
21866
|
+
} catch {
|
|
21867
|
+
threadId = void 0;
|
|
21868
|
+
}
|
|
21869
|
+
}
|
|
21870
|
+
threadId ??= await client.startThread({ cwd: opts.cwd, developerInstructions: systemPrompt });
|
|
21871
|
+
if (!map[opts.sessionId]) {
|
|
21872
|
+
map[opts.sessionId] = threadId;
|
|
21873
|
+
writeThreadMap(opts.cwd, map);
|
|
21874
|
+
}
|
|
21875
|
+
const replyParts = [];
|
|
21876
|
+
try {
|
|
21877
|
+
await client.runTurn({
|
|
21878
|
+
threadId,
|
|
21879
|
+
message: last.content,
|
|
21880
|
+
onNotification: async (notification) => {
|
|
21881
|
+
for (const event of translateCodexNotification(notification, opts.sessionId)) {
|
|
21882
|
+
if (event.type === "text" && event.text) {
|
|
21883
|
+
replyParts.push(event.text);
|
|
21884
|
+
await opts.sink.emit({
|
|
21885
|
+
event: "chat.message",
|
|
21886
|
+
payload: { sessionId: opts.sessionId, role: "assistant", content: event.text },
|
|
21887
|
+
runId: opts.sessionId,
|
|
21888
|
+
emittedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
21889
|
+
});
|
|
21890
|
+
} else if (event.type === "tool_use") {
|
|
21891
|
+
await opts.sink.emit({
|
|
21892
|
+
event: "chat.tool",
|
|
21893
|
+
payload: { phase: "use", name: event.name, input: event.input },
|
|
21894
|
+
runId: opts.sessionId,
|
|
21895
|
+
emittedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
21896
|
+
});
|
|
21897
|
+
}
|
|
21898
|
+
}
|
|
21899
|
+
}
|
|
21900
|
+
});
|
|
21901
|
+
} catch (error) {
|
|
21902
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
21903
|
+
await opts.sink.emit({
|
|
21904
|
+
event: "chat.error",
|
|
21905
|
+
payload: { error: message },
|
|
21906
|
+
runId: opts.sessionId,
|
|
21907
|
+
emittedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
21908
|
+
});
|
|
21909
|
+
return { exitCode: 99, error: message };
|
|
21910
|
+
}
|
|
21911
|
+
const reply = replyParts.join("").trim();
|
|
21912
|
+
if (!reply) {
|
|
21913
|
+
const error = "Codex completed without producing a reply";
|
|
21914
|
+
await opts.sink.emit({
|
|
21915
|
+
event: "chat.error",
|
|
21916
|
+
payload: { error },
|
|
21917
|
+
runId: opts.sessionId,
|
|
21918
|
+
emittedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
21919
|
+
});
|
|
21920
|
+
return { exitCode: 99, error };
|
|
21921
|
+
}
|
|
21922
|
+
await store.appendTurn({ role: "assistant", content: reply, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
21923
|
+
await opts.sink.emit({
|
|
21924
|
+
event: "chat.done",
|
|
21925
|
+
payload: { sessionId: opts.sessionId },
|
|
21926
|
+
runId: opts.sessionId,
|
|
21927
|
+
emittedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
21928
|
+
});
|
|
21929
|
+
return { exitCode: 0, reply };
|
|
21930
|
+
}
|
|
21931
|
+
|
|
21932
|
+
// src/chat/events.ts
|
|
21933
|
+
import * as fs13 from "fs";
|
|
21934
|
+
import * as path14 from "path";
|
|
21645
21935
|
import posixPath2 from "path/posix";
|
|
21646
21936
|
function eventsFilePath(cwd, sessionId) {
|
|
21647
|
-
return
|
|
21937
|
+
return path14.join(cwd, ".kody-engine", "runtime", "events", `${sessionId}.jsonl`);
|
|
21648
21938
|
}
|
|
21649
21939
|
var FileSink = class {
|
|
21650
21940
|
constructor(file) {
|
|
@@ -21652,8 +21942,8 @@ var FileSink = class {
|
|
|
21652
21942
|
}
|
|
21653
21943
|
file;
|
|
21654
21944
|
async emit(event) {
|
|
21655
|
-
|
|
21656
|
-
|
|
21945
|
+
fs13.mkdirSync(path14.dirname(this.file), { recursive: true });
|
|
21946
|
+
fs13.appendFileSync(this.file, `${JSON.stringify(event)}
|
|
21657
21947
|
`);
|
|
21658
21948
|
}
|
|
21659
21949
|
};
|
|
@@ -21711,15 +22001,15 @@ init_convex_client();
|
|
|
21711
22001
|
import { anyApi as anyApi2 } from "convex/server";
|
|
21712
22002
|
|
|
21713
22003
|
// src/chat/session.ts
|
|
21714
|
-
import * as
|
|
21715
|
-
import * as
|
|
22004
|
+
import * as fs14 from "fs";
|
|
22005
|
+
import * as path15 from "path";
|
|
21716
22006
|
import posixPath3 from "path/posix";
|
|
21717
22007
|
function sessionFilePath(cwd, sessionId) {
|
|
21718
|
-
return
|
|
22008
|
+
return path15.join(cwd, ".kody-engine", "runtime", "sessions", `${sessionId}.jsonl`);
|
|
21719
22009
|
}
|
|
21720
22010
|
function readMeta(file) {
|
|
21721
|
-
if (!
|
|
21722
|
-
const raw =
|
|
22011
|
+
if (!fs14.existsSync(file)) return null;
|
|
22012
|
+
const raw = fs14.readFileSync(file, "utf-8");
|
|
21723
22013
|
const firstLine2 = raw.split("\n", 1)[0]?.trim();
|
|
21724
22014
|
if (!firstLine2) return null;
|
|
21725
22015
|
try {
|
|
@@ -21732,8 +22022,8 @@ function readMeta(file) {
|
|
|
21732
22022
|
}
|
|
21733
22023
|
}
|
|
21734
22024
|
function readSession(file) {
|
|
21735
|
-
if (!
|
|
21736
|
-
const raw =
|
|
22025
|
+
if (!fs14.existsSync(file)) return [];
|
|
22026
|
+
const raw = fs14.readFileSync(file, "utf-8").trim();
|
|
21737
22027
|
if (!raw) return [];
|
|
21738
22028
|
const turns = [];
|
|
21739
22029
|
for (const line of raw.split("\n")) {
|
|
@@ -21749,14 +22039,14 @@ function readSession(file) {
|
|
|
21749
22039
|
return turns;
|
|
21750
22040
|
}
|
|
21751
22041
|
function appendTurn(file, turn) {
|
|
21752
|
-
|
|
22042
|
+
fs14.mkdirSync(path15.dirname(file), { recursive: true });
|
|
21753
22043
|
const line = JSON.stringify({
|
|
21754
22044
|
role: turn.role,
|
|
21755
22045
|
content: turn.content,
|
|
21756
22046
|
timestamp: turn.timestamp,
|
|
21757
22047
|
toolCalls: turn.toolCalls ?? []
|
|
21758
22048
|
});
|
|
21759
|
-
|
|
22049
|
+
fs14.appendFileSync(file, `${line}
|
|
21760
22050
|
`);
|
|
21761
22051
|
}
|
|
21762
22052
|
function seedInitialMessage(file, message) {
|
|
@@ -21989,7 +22279,7 @@ function buildImplementationCatalog() {
|
|
|
21989
22279
|
const entries = [];
|
|
21990
22280
|
for (const { name, profilePath } of discovered) {
|
|
21991
22281
|
try {
|
|
21992
|
-
const raw = JSON.parse(
|
|
22282
|
+
const raw = JSON.parse(fs15.readFileSync(profilePath, "utf-8"));
|
|
21993
22283
|
const describe = typeof raw.describe === "string" ? raw.describe : "";
|
|
21994
22284
|
const firstSentence = describe.split(/(?<=[.!?])\s+/, 1)[0] ?? "";
|
|
21995
22285
|
entries.push({ name, describe: firstSentence.trim() });
|
|
@@ -22011,6 +22301,9 @@ function buildImplementationCatalog() {
|
|
|
22011
22301
|
}
|
|
22012
22302
|
return lines.join("\n");
|
|
22013
22303
|
}
|
|
22304
|
+
function shouldWriteTaskArtifacts(driver) {
|
|
22305
|
+
return driver !== "codex-app-server";
|
|
22306
|
+
}
|
|
22014
22307
|
async function runChatTurn(opts) {
|
|
22015
22308
|
const store = opts.store ?? createSessionStore({ sessionId: opts.sessionId, sessionFile: opts.sessionFile });
|
|
22016
22309
|
const turns = await store.readTurns();
|
|
@@ -22034,11 +22327,11 @@ async function runChatTurn(opts) {
|
|
|
22034
22327
|
taskKey: `sessions/${opts.sessionId}`
|
|
22035
22328
|
};
|
|
22036
22329
|
initializeTaskArtifacts(taskArtifactsPaths, { taskType: "chat", target: opts.sessionId });
|
|
22037
|
-
const artifactAddendum = taskArtifactsPromptAddendum({
|
|
22330
|
+
const artifactAddendum = shouldWriteTaskArtifacts(opts.driver) ? taskArtifactsPromptAddendum({
|
|
22038
22331
|
taskId: taskArtifactsPaths.taskId,
|
|
22039
22332
|
taskType: "chat",
|
|
22040
22333
|
relDir: taskArtifactsPaths.relDir
|
|
22041
|
-
});
|
|
22334
|
+
}) : null;
|
|
22042
22335
|
const contextBlock = readContextBlock(opts.cwd);
|
|
22043
22336
|
const memoryBlock = readMemoryIndexBlock(opts.cwd);
|
|
22044
22337
|
const instructionsBlock = readInstructionsBlock(opts.cwd);
|
|
@@ -22067,6 +22360,14 @@ async function runChatTurn(opts) {
|
|
|
22067
22360
|
artifactAddendum
|
|
22068
22361
|
].filter((s) => typeof s === "string" && s.length > 0).join("\n\n");
|
|
22069
22362
|
const prompt = buildPrompt(promptTurns);
|
|
22363
|
+
if (opts.driver === "codex-app-server") {
|
|
22364
|
+
return runCodexChatTurn({
|
|
22365
|
+
opts,
|
|
22366
|
+
turns: promptTurns,
|
|
22367
|
+
systemPrompt,
|
|
22368
|
+
store
|
|
22369
|
+
});
|
|
22370
|
+
}
|
|
22070
22371
|
if (opts.model.protocol === "openai" && opts.litellmUrl) {
|
|
22071
22372
|
return runOpenAIChatTurn({
|
|
22072
22373
|
opts,
|
|
@@ -22085,7 +22386,7 @@ async function runChatTurn(opts) {
|
|
|
22085
22386
|
quiet: opts.quiet,
|
|
22086
22387
|
additionalDirectories: [
|
|
22087
22388
|
taskArtifactsPaths.absDir,
|
|
22088
|
-
...Array.from(new Set(imagePaths.map((p2) =>
|
|
22389
|
+
...Array.from(new Set(imagePaths.map((p2) => path16.dirname(p2))))
|
|
22089
22390
|
],
|
|
22090
22391
|
systemPromptAppend: systemPrompt,
|
|
22091
22392
|
...opts.reasoningEffort ? { reasoningEffort: opts.reasoningEffort } : {},
|
|
@@ -22268,10 +22569,10 @@ async function emit(sink, type, sessionId, suffix, payload) {
|
|
|
22268
22569
|
var MEMORY_INDEX_REL = ".kody-engine/runtime/memory/INDEX.md";
|
|
22269
22570
|
var MAX_INDEX_BYTES = 8e3;
|
|
22270
22571
|
function readMemoryIndexBlock(cwd) {
|
|
22271
|
-
const indexPath =
|
|
22572
|
+
const indexPath = path16.join(cwd, MEMORY_INDEX_REL);
|
|
22272
22573
|
let raw;
|
|
22273
22574
|
try {
|
|
22274
|
-
raw =
|
|
22575
|
+
raw = fs15.readFileSync(indexPath, "utf-8");
|
|
22275
22576
|
} catch {
|
|
22276
22577
|
return "";
|
|
22277
22578
|
}
|
|
@@ -22291,17 +22592,17 @@ _\u2026 (memory index truncated; use recall_search to read more)_` : trimmed;
|
|
|
22291
22592
|
var CONTEXT_DIR_REL = ".kody-engine/runtime/context";
|
|
22292
22593
|
var MAX_CONTEXT_BYTES = 12e3;
|
|
22293
22594
|
function readContextBlock(cwd) {
|
|
22294
|
-
const dir =
|
|
22595
|
+
const dir = path16.join(cwd, CONTEXT_DIR_REL);
|
|
22295
22596
|
let files;
|
|
22296
22597
|
try {
|
|
22297
|
-
files =
|
|
22598
|
+
files = fs15.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
22298
22599
|
} catch {
|
|
22299
22600
|
return "";
|
|
22300
22601
|
}
|
|
22301
22602
|
const sections = [];
|
|
22302
22603
|
for (const file of files) {
|
|
22303
22604
|
try {
|
|
22304
|
-
const content =
|
|
22605
|
+
const content = fs15.readFileSync(path16.join(dir, file), "utf-8").trim();
|
|
22305
22606
|
if (content) sections.push(`### ${file.replace(/\.md$/, "")}
|
|
22306
22607
|
|
|
22307
22608
|
${content}`);
|
|
@@ -22327,7 +22628,7 @@ var SYSTEM_PROMPT_OVERRIDE_REL = ".kody-engine/runtime/system-prompt.md";
|
|
|
22327
22628
|
function readSystemPromptOverride(cwd) {
|
|
22328
22629
|
let raw;
|
|
22329
22630
|
try {
|
|
22330
|
-
raw =
|
|
22631
|
+
raw = fs15.readFileSync(path16.join(cwd, SYSTEM_PROMPT_OVERRIDE_REL), "utf-8");
|
|
22331
22632
|
} catch {
|
|
22332
22633
|
return null;
|
|
22333
22634
|
}
|
|
@@ -22335,10 +22636,10 @@ function readSystemPromptOverride(cwd) {
|
|
|
22335
22636
|
return trimmed.length > 0 ? trimmed : null;
|
|
22336
22637
|
}
|
|
22337
22638
|
function readInstructionsBlock(cwd) {
|
|
22338
|
-
const instructionsPath =
|
|
22639
|
+
const instructionsPath = path16.join(cwd, INSTRUCTIONS_REL);
|
|
22339
22640
|
let raw;
|
|
22340
22641
|
try {
|
|
22341
|
-
raw =
|
|
22642
|
+
raw = fs15.readFileSync(instructionsPath, "utf-8");
|
|
22342
22643
|
} catch {
|
|
22343
22644
|
return "";
|
|
22344
22645
|
}
|
|
@@ -22356,13 +22657,28 @@ _\u2026 (instructions truncated)_` : trimmed;
|
|
|
22356
22657
|
].join("\n");
|
|
22357
22658
|
}
|
|
22358
22659
|
|
|
22660
|
+
// src/chat/runtime-drivers.ts
|
|
22661
|
+
var RUNTIME_DRIVERS = {
|
|
22662
|
+
native: "native",
|
|
22663
|
+
"codex app-server": "codex-app-server",
|
|
22664
|
+
"codex-app-server": "codex-app-server"
|
|
22665
|
+
};
|
|
22666
|
+
function resolveBrainDriver(runtime) {
|
|
22667
|
+
const normalized = runtime.trim().toLowerCase();
|
|
22668
|
+
const driver = RUNTIME_DRIVERS[normalized];
|
|
22669
|
+
if (!driver) {
|
|
22670
|
+
throw new Error(`Unsupported Brain runtime: ${runtime}`);
|
|
22671
|
+
}
|
|
22672
|
+
return driver;
|
|
22673
|
+
}
|
|
22674
|
+
|
|
22359
22675
|
// src/servers/brain-serve.ts
|
|
22360
22676
|
init_config();
|
|
22361
22677
|
|
|
22362
22678
|
// src/kody-cli.ts
|
|
22363
22679
|
import { execFileSync as execFileSync24 } from "child_process";
|
|
22364
|
-
import * as
|
|
22365
|
-
import * as
|
|
22680
|
+
import * as fs47 from "fs";
|
|
22681
|
+
import * as path46 from "path";
|
|
22366
22682
|
|
|
22367
22683
|
// src/app-auth.ts
|
|
22368
22684
|
import { createSign } from "crypto";
|
|
@@ -22489,7 +22805,7 @@ init_config();
|
|
|
22489
22805
|
|
|
22490
22806
|
// src/dispatch.ts
|
|
22491
22807
|
init_config();
|
|
22492
|
-
import * as
|
|
22808
|
+
import * as fs16 from "fs";
|
|
22493
22809
|
|
|
22494
22810
|
// src/cron-match.ts
|
|
22495
22811
|
var FIELD_BOUNDS = [
|
|
@@ -22591,10 +22907,10 @@ function autoDispatch(opts) {
|
|
|
22591
22907
|
}
|
|
22592
22908
|
const eventName = process.env.GITHUB_EVENT_NAME;
|
|
22593
22909
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
22594
|
-
if (!eventName || !eventPath || !
|
|
22910
|
+
if (!eventName || !eventPath || !fs16.existsSync(eventPath)) return null;
|
|
22595
22911
|
let event = {};
|
|
22596
22912
|
try {
|
|
22597
|
-
event = JSON.parse(
|
|
22913
|
+
event = JSON.parse(fs16.readFileSync(eventPath, "utf-8"));
|
|
22598
22914
|
} catch {
|
|
22599
22915
|
return null;
|
|
22600
22916
|
}
|
|
@@ -22718,7 +23034,7 @@ function autoDispatchTyped(opts) {
|
|
|
22718
23034
|
if (legacy) return { kind: "route", ...legacy };
|
|
22719
23035
|
const eventName = process.env.GITHUB_EVENT_NAME;
|
|
22720
23036
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
22721
|
-
if (!eventName || !eventPath || !
|
|
23037
|
+
if (!eventName || !eventPath || !fs16.existsSync(eventPath)) {
|
|
22722
23038
|
return { kind: "silent", reason: "no GHA event context" };
|
|
22723
23039
|
}
|
|
22724
23040
|
if (eventName !== "issue_comment") {
|
|
@@ -22726,7 +23042,7 @@ function autoDispatchTyped(opts) {
|
|
|
22726
23042
|
}
|
|
22727
23043
|
let event = {};
|
|
22728
23044
|
try {
|
|
22729
|
-
event = JSON.parse(
|
|
23045
|
+
event = JSON.parse(fs16.readFileSync(eventPath, "utf-8"));
|
|
22730
23046
|
} catch {
|
|
22731
23047
|
return { kind: "silent", reason: "GHA event payload unreadable" };
|
|
22732
23048
|
}
|
|
@@ -22780,7 +23096,7 @@ function dispatchScheduledWatches(opts) {
|
|
|
22780
23096
|
for (const exe of listImplementations()) {
|
|
22781
23097
|
let raw;
|
|
22782
23098
|
try {
|
|
22783
|
-
raw =
|
|
23099
|
+
raw = fs16.readFileSync(exe.profilePath, "utf-8");
|
|
22784
23100
|
} catch {
|
|
22785
23101
|
continue;
|
|
22786
23102
|
}
|
|
@@ -23164,9 +23480,9 @@ async function resolveAuthToken(env = process.env) {
|
|
|
23164
23480
|
return void 0;
|
|
23165
23481
|
}
|
|
23166
23482
|
function detectPackageManager2(cwd) {
|
|
23167
|
-
if (
|
|
23168
|
-
if (
|
|
23169
|
-
if (
|
|
23483
|
+
if (fs47.existsSync(path46.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
23484
|
+
if (fs47.existsSync(path46.join(cwd, "yarn.lock"))) return "yarn";
|
|
23485
|
+
if (fs47.existsSync(path46.join(cwd, "bun.lockb"))) return "bun";
|
|
23170
23486
|
return "npm";
|
|
23171
23487
|
}
|
|
23172
23488
|
function shouldChainScheduledWatch(match) {
|
|
@@ -23259,8 +23575,8 @@ function postFailureTail(issueNumber, cwd, reason) {
|
|
|
23259
23575
|
const logPath = lastRunLogPath(cwd);
|
|
23260
23576
|
let tail = "";
|
|
23261
23577
|
try {
|
|
23262
|
-
if (
|
|
23263
|
-
const content =
|
|
23578
|
+
if (fs47.existsSync(logPath)) {
|
|
23579
|
+
const content = fs47.readFileSync(logPath, "utf-8");
|
|
23264
23580
|
tail = content.slice(-3e3);
|
|
23265
23581
|
}
|
|
23266
23582
|
} catch {
|
|
@@ -23289,7 +23605,7 @@ async function runCi(argv) {
|
|
|
23289
23605
|
return 0;
|
|
23290
23606
|
}
|
|
23291
23607
|
const args = parseCiArgs(argv);
|
|
23292
|
-
const cwd = args.cwd ?
|
|
23608
|
+
const cwd = args.cwd ? path46.resolve(args.cwd) : process.cwd();
|
|
23293
23609
|
try {
|
|
23294
23610
|
const n = unpackAllSecrets();
|
|
23295
23611
|
if (n > 0) process.stdout.write(`\u2192 kody: unpacked ${n} secret(s) from ALL_SECRETS
|
|
@@ -23348,9 +23664,9 @@ async function runCi(argv) {
|
|
|
23348
23664
|
forceRunCliArgs = { goal: envForceMessage };
|
|
23349
23665
|
}
|
|
23350
23666
|
}
|
|
23351
|
-
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath &&
|
|
23667
|
+
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath && fs47.existsSync(dispatchEventPath)) {
|
|
23352
23668
|
try {
|
|
23353
|
-
const evt = JSON.parse(
|
|
23669
|
+
const evt = JSON.parse(fs47.readFileSync(dispatchEventPath, "utf-8"));
|
|
23354
23670
|
const inputs = objectValue2(evt.inputs);
|
|
23355
23671
|
const issueInput = parseInt(String(inputs?.issue_number ?? ""), 10);
|
|
23356
23672
|
const sessionInput = String(inputs?.sessionId ?? "");
|
|
@@ -23723,8 +24039,8 @@ init_repoWorkspace();
|
|
|
23723
24039
|
|
|
23724
24040
|
// src/scripts/brainTurnLog.ts
|
|
23725
24041
|
init_runtimePaths();
|
|
23726
|
-
import * as
|
|
23727
|
-
import * as
|
|
24042
|
+
import * as fs48 from "fs";
|
|
24043
|
+
import * as path47 from "path";
|
|
23728
24044
|
import posixPath4 from "path/posix";
|
|
23729
24045
|
var live = /* @__PURE__ */ new Map();
|
|
23730
24046
|
function brainEventsFilePath(dir, chatId) {
|
|
@@ -23732,8 +24048,8 @@ function brainEventsFilePath(dir, chatId) {
|
|
|
23732
24048
|
}
|
|
23733
24049
|
function lastPersistedSeq(dir, chatId) {
|
|
23734
24050
|
const p = brainEventsFilePath(dir, chatId);
|
|
23735
|
-
if (!
|
|
23736
|
-
const lines =
|
|
24051
|
+
if (!fs48.existsSync(p)) return 0;
|
|
24052
|
+
const lines = fs48.readFileSync(p, "utf-8").split("\n").filter(Boolean);
|
|
23737
24053
|
if (lines.length === 0) return 0;
|
|
23738
24054
|
try {
|
|
23739
24055
|
return JSON.parse(lines[lines.length - 1]).seq || 0;
|
|
@@ -23743,9 +24059,9 @@ function lastPersistedSeq(dir, chatId) {
|
|
|
23743
24059
|
}
|
|
23744
24060
|
function readSince(dir, chatId, since) {
|
|
23745
24061
|
const p = brainEventsFilePath(dir, chatId);
|
|
23746
|
-
if (!
|
|
24062
|
+
if (!fs48.existsSync(p)) return [];
|
|
23747
24063
|
const out = [];
|
|
23748
|
-
for (const line of
|
|
24064
|
+
for (const line of fs48.readFileSync(p, "utf-8").split("\n")) {
|
|
23749
24065
|
if (!line) continue;
|
|
23750
24066
|
try {
|
|
23751
24067
|
const rec = JSON.parse(line);
|
|
@@ -23771,12 +24087,12 @@ function beginTurn(dir, chatId) {
|
|
|
23771
24087
|
};
|
|
23772
24088
|
live.set(chatId, state);
|
|
23773
24089
|
const p = brainEventsFilePath(dir, chatId);
|
|
23774
|
-
|
|
24090
|
+
fs48.mkdirSync(path47.dirname(p), { recursive: true });
|
|
23775
24091
|
return (event) => {
|
|
23776
24092
|
state.seq += 1;
|
|
23777
24093
|
const rec = { seq: state.seq, turn, ts: Date.now(), event };
|
|
23778
24094
|
try {
|
|
23779
|
-
|
|
24095
|
+
fs48.appendFileSync(p, `${JSON.stringify(rec)}
|
|
23780
24096
|
`);
|
|
23781
24097
|
} catch (err) {
|
|
23782
24098
|
process.stderr.write(
|
|
@@ -23815,7 +24131,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
|
|
|
23815
24131
|
event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
|
|
23816
24132
|
};
|
|
23817
24133
|
try {
|
|
23818
|
-
|
|
24134
|
+
fs48.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
|
|
23819
24135
|
`);
|
|
23820
24136
|
} catch {
|
|
23821
24137
|
}
|
|
@@ -24012,9 +24328,14 @@ var BrokerSink = class {
|
|
|
24012
24328
|
const be = translateChatEvent(event, this.chatId);
|
|
24013
24329
|
if (!be) return;
|
|
24014
24330
|
this.emitToLog(be);
|
|
24015
|
-
if (this.tenantId
|
|
24331
|
+
if (this.tenantId && hasStateBackendConfig()) {
|
|
24332
|
+
await createStateBackendFromEnv().appendChatEvent(this.tenantId, this.chatId, be);
|
|
24333
|
+
}
|
|
24016
24334
|
}
|
|
24017
24335
|
};
|
|
24336
|
+
function hasStateBackendConfig(env = process.env) {
|
|
24337
|
+
return Boolean(env.CONVEX_URL?.trim() && env.KODY_SERVICE_KEY?.trim());
|
|
24338
|
+
}
|
|
24018
24339
|
var chatQueues = /* @__PURE__ */ new Map();
|
|
24019
24340
|
function enqueue(chatId, fn) {
|
|
24020
24341
|
const prev = chatQueues.get(chatId) ?? Promise.resolve();
|
|
@@ -24074,8 +24395,18 @@ async function handleChatTurn(req, res, chatId, opts) {
|
|
|
24074
24395
|
const dashboardUrl = strField(body, "dashboardUrl");
|
|
24075
24396
|
const storeRepoUrl = strField(body, "storeRepoUrl");
|
|
24076
24397
|
const storeRef = strField(body, "storeRef");
|
|
24398
|
+
const runtime = strField(body, "runtime");
|
|
24077
24399
|
const allowCrossRepo = boolField(body, "allowCrossRepo");
|
|
24078
24400
|
const agentIdentity = agentIdentityField(body);
|
|
24401
|
+
let turnDriver = opts.driver;
|
|
24402
|
+
if (runtime) {
|
|
24403
|
+
try {
|
|
24404
|
+
turnDriver = resolveBrainDriver(runtime);
|
|
24405
|
+
} catch (err) {
|
|
24406
|
+
sendJson(res, 400, { error: err instanceof Error ? err.message : String(err) });
|
|
24407
|
+
return;
|
|
24408
|
+
}
|
|
24409
|
+
}
|
|
24079
24410
|
openSseStream(res, chatId);
|
|
24080
24411
|
if (repo) {
|
|
24081
24412
|
emitSse(res, {
|
|
@@ -24105,7 +24436,6 @@ async function handleChatTurn(req, res, chatId, opts) {
|
|
|
24105
24436
|
}
|
|
24106
24437
|
const stateToken = repoToken || envGithubToken();
|
|
24107
24438
|
const sessionFile = sessionFilePath(agentCwd, chatId);
|
|
24108
|
-
const brainEventsFile = brainEventsFilePath(agentCwd, chatId);
|
|
24109
24439
|
const sessionStore = createSessionStore({
|
|
24110
24440
|
sessionId: chatId,
|
|
24111
24441
|
sessionFile,
|
|
@@ -24135,6 +24465,7 @@ async function handleChatTurn(req, res, chatId, opts) {
|
|
|
24135
24465
|
...allowCrossRepo ? { enableFetchRepoTool: true } : {},
|
|
24136
24466
|
repoToken,
|
|
24137
24467
|
...agentIdentity ? { agentIdentity } : {},
|
|
24468
|
+
...turnDriver ? { driver: turnDriver } : {},
|
|
24138
24469
|
...dashboardUrl && repo && stateToken ? {
|
|
24139
24470
|
cmsDashboardUrl: dashboardUrl,
|
|
24140
24471
|
cmsRepoSlug: repo,
|
|
@@ -24161,7 +24492,7 @@ async function handleChatTurn(req, res, chatId, opts) {
|
|
|
24161
24492
|
function buildServer(opts) {
|
|
24162
24493
|
const runTurn = opts.runTurn ?? runChatTurn;
|
|
24163
24494
|
const cloneRepo = opts.cloneRepo ?? defaultCloneRepo;
|
|
24164
|
-
const reposRoot = opts.reposRoot ??
|
|
24495
|
+
const reposRoot = opts.reposRoot ?? path48.join(path48.dirname(path48.resolve(opts.cwd)), "repos");
|
|
24165
24496
|
return createServer2(async (req, res) => {
|
|
24166
24497
|
if (!req.method || !req.url) {
|
|
24167
24498
|
sendJson(res, 400, { error: "bad request" });
|
|
@@ -24189,7 +24520,8 @@ function buildServer(opts) {
|
|
|
24189
24520
|
cloneRepo,
|
|
24190
24521
|
model: opts.model,
|
|
24191
24522
|
litellmUrl: opts.litellmUrl,
|
|
24192
|
-
runTurn
|
|
24523
|
+
runTurn,
|
|
24524
|
+
driver: opts.driver
|
|
24193
24525
|
});
|
|
24194
24526
|
return;
|
|
24195
24527
|
}
|
|
@@ -24216,11 +24548,12 @@ async function brainServe(opts) {
|
|
|
24216
24548
|
}
|
|
24217
24549
|
const apiKey = getApiKey();
|
|
24218
24550
|
const port = Number(process.env.PORT ?? DEFAULT_PORT);
|
|
24551
|
+
const driver = process.env.BRAIN_DRIVER?.trim() === "codex-app-server" ? "codex-app-server" : "native";
|
|
24219
24552
|
const model = parseModelRuntimeConfig(
|
|
24220
24553
|
process.env.MODEL?.trim() || "claude/claude-haiku-4-5-20251001",
|
|
24221
24554
|
process.env.KODY_MODEL_CONFIG
|
|
24222
24555
|
);
|
|
24223
|
-
const usesProxy = needsLitellmProxy(model);
|
|
24556
|
+
const usesProxy = driver === "native" && needsLitellmProxy(model);
|
|
24224
24557
|
let handle = null;
|
|
24225
24558
|
if (usesProxy) {
|
|
24226
24559
|
process.stdout.write(`[brain-serve] starting LiteLLM proxy for ${model.provider}/${model.model}...
|
|
@@ -24236,7 +24569,8 @@ async function brainServe(opts) {
|
|
|
24236
24569
|
// Per-repo clones live here; defaults to a `repos` sibling of cwd.
|
|
24237
24570
|
reposRoot: process.env.BRAIN_REPOS_ROOT?.trim() || void 0,
|
|
24238
24571
|
model,
|
|
24239
|
-
litellmUrl
|
|
24572
|
+
litellmUrl,
|
|
24573
|
+
driver
|
|
24240
24574
|
});
|
|
24241
24575
|
await new Promise((resolve16) => {
|
|
24242
24576
|
server.listen(port, "0.0.0.0", () => {
|
|
@@ -24761,8 +25095,8 @@ async function loadConfigSafe() {
|
|
|
24761
25095
|
}
|
|
24762
25096
|
|
|
24763
25097
|
// src/chat-cli.ts
|
|
24764
|
-
import * as
|
|
24765
|
-
import * as
|
|
25098
|
+
import * as fs49 from "fs";
|
|
25099
|
+
import * as path49 from "path";
|
|
24766
25100
|
|
|
24767
25101
|
// src/chat/inbox.ts
|
|
24768
25102
|
import { execFileSync as execFileSync25 } from "child_process";
|
|
@@ -25034,7 +25368,7 @@ async function runChat(argv) {
|
|
|
25034
25368
|
${CHAT_HELP}`);
|
|
25035
25369
|
return 64;
|
|
25036
25370
|
}
|
|
25037
|
-
const cwd = args.cwd ?
|
|
25371
|
+
const cwd = args.cwd ? path49.resolve(args.cwd) : process.cwd();
|
|
25038
25372
|
const sessionId = args.sessionId;
|
|
25039
25373
|
const runRequest = readRunRequestFromEnv();
|
|
25040
25374
|
if (runRequest && "request" in runRequest) {
|
|
@@ -25095,7 +25429,7 @@ ${CHAT_HELP}`);
|
|
|
25095
25429
|
const sink = buildSink(cwd, sessionId, args.dashboardUrl);
|
|
25096
25430
|
const meta = readMeta(sessionFile);
|
|
25097
25431
|
process.stdout.write(
|
|
25098
|
-
`\u2192 kody:chat: session file=${sessionFile} exists=${
|
|
25432
|
+
`\u2192 kody:chat: session file=${sessionFile} exists=${fs49.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
|
|
25099
25433
|
`
|
|
25100
25434
|
);
|
|
25101
25435
|
try {
|
|
@@ -25141,8 +25475,8 @@ init_config();
|
|
|
25141
25475
|
// src/definition-hydration.ts
|
|
25142
25476
|
init_state_backend();
|
|
25143
25477
|
import { createHash as createHash5 } from "crypto";
|
|
25144
|
-
import * as
|
|
25145
|
-
import * as
|
|
25478
|
+
import * as fs50 from "fs";
|
|
25479
|
+
import * as path50 from "path";
|
|
25146
25480
|
var SLUG_RE2 = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
25147
25481
|
function assertSafeDefinitionPath(filePath) {
|
|
25148
25482
|
const segments = filePath.split("/");
|
|
@@ -25176,32 +25510,32 @@ function writeDefinition(root, kind, definition) {
|
|
|
25176
25510
|
if (kind === "agent") {
|
|
25177
25511
|
const raw = bundle.files["agent.md"];
|
|
25178
25512
|
if (typeof raw !== "string") throw new Error(`agent definition ${definition.slug} is missing agent.md`);
|
|
25179
|
-
|
|
25513
|
+
fs50.writeFileSync(path50.join(root, "agents", `${definition.slug}.md`), raw, "utf8");
|
|
25180
25514
|
return;
|
|
25181
25515
|
}
|
|
25182
25516
|
if (kind === "goal") {
|
|
25183
|
-
const goalRoot =
|
|
25517
|
+
const goalRoot = path50.join(root, "goals", definition.slug);
|
|
25184
25518
|
for (const [filePath, contents] of Object.entries(bundle.files)) {
|
|
25185
|
-
const target =
|
|
25186
|
-
|
|
25187
|
-
|
|
25519
|
+
const target = path50.join(goalRoot, filePath);
|
|
25520
|
+
fs50.mkdirSync(path50.dirname(target), { recursive: true });
|
|
25521
|
+
fs50.writeFileSync(target, contents, "utf8");
|
|
25188
25522
|
}
|
|
25189
25523
|
return;
|
|
25190
25524
|
}
|
|
25191
|
-
const capabilityRoot =
|
|
25525
|
+
const capabilityRoot = path50.join(root, "capabilities", definition.slug);
|
|
25192
25526
|
for (const [filePath, contents] of Object.entries(bundle.files)) {
|
|
25193
|
-
const target =
|
|
25194
|
-
|
|
25195
|
-
|
|
25527
|
+
const target = path50.join(capabilityRoot, filePath);
|
|
25528
|
+
fs50.mkdirSync(path50.dirname(target), { recursive: true });
|
|
25529
|
+
fs50.writeFileSync(target, contents, "utf8");
|
|
25196
25530
|
}
|
|
25197
25531
|
}
|
|
25198
25532
|
async function hydrateDefinitions(options) {
|
|
25199
|
-
const root =
|
|
25533
|
+
const root = path50.join(options.cwd, ".kody-engine", "definitions");
|
|
25200
25534
|
const staging = `${root}.tmp-${process.pid}-${Date.now()}`;
|
|
25201
|
-
|
|
25202
|
-
|
|
25203
|
-
|
|
25204
|
-
|
|
25535
|
+
fs50.rmSync(staging, { recursive: true, force: true });
|
|
25536
|
+
fs50.mkdirSync(path50.join(staging, "agents"), { recursive: true });
|
|
25537
|
+
fs50.mkdirSync(path50.join(staging, "capabilities"), { recursive: true });
|
|
25538
|
+
fs50.mkdirSync(path50.join(staging, "goals"), { recursive: true });
|
|
25205
25539
|
try {
|
|
25206
25540
|
const [capabilities, agents, goals] = await Promise.all([
|
|
25207
25541
|
options.backend.listDefinitions(options.tenantId, "capability"),
|
|
@@ -25227,13 +25561,13 @@ async function hydrateDefinitions(options) {
|
|
|
25227
25561
|
hydratedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25228
25562
|
versions: Object.fromEntries(Object.entries(versions).sort(([left], [right]) => left.localeCompare(right)))
|
|
25229
25563
|
};
|
|
25230
|
-
|
|
25564
|
+
fs50.writeFileSync(path50.join(staging, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
25231
25565
|
`, "utf8");
|
|
25232
|
-
|
|
25233
|
-
|
|
25566
|
+
fs50.rmSync(root, { recursive: true, force: true });
|
|
25567
|
+
fs50.renameSync(staging, root);
|
|
25234
25568
|
return { root, tenantId: options.tenantId, versions: manifest.versions };
|
|
25235
25569
|
} catch (error) {
|
|
25236
|
-
|
|
25570
|
+
fs50.rmSync(staging, { recursive: true, force: true });
|
|
25237
25571
|
throw error;
|
|
25238
25572
|
}
|
|
25239
25573
|
}
|
|
@@ -25327,8 +25661,8 @@ var FlyClient = class {
|
|
|
25327
25661
|
get fetch() {
|
|
25328
25662
|
return this.opts.fetchImpl ?? fetch;
|
|
25329
25663
|
}
|
|
25330
|
-
async call(
|
|
25331
|
-
const res = await this.fetch(`${FLY_API_BASE}${
|
|
25664
|
+
async call(path51, init = {}) {
|
|
25665
|
+
const res = await this.fetch(`${FLY_API_BASE}${path51}`, {
|
|
25332
25666
|
method: init.method ?? "GET",
|
|
25333
25667
|
headers: {
|
|
25334
25668
|
Authorization: `Bearer ${this.opts.token}`,
|
|
@@ -25339,7 +25673,7 @@ var FlyClient = class {
|
|
|
25339
25673
|
if (res.status === 404 && init.allow404) return null;
|
|
25340
25674
|
if (!res.ok) {
|
|
25341
25675
|
const text2 = await res.text().catch(() => "");
|
|
25342
|
-
throw new Error(`Fly API ${res.status} on ${
|
|
25676
|
+
throw new Error(`Fly API ${res.status} on ${path51}: ${text2.slice(0, 200) || res.statusText}`);
|
|
25343
25677
|
}
|
|
25344
25678
|
if (res.status === 204) return null;
|
|
25345
25679
|
const raw = await res.text();
|
|
@@ -26091,8 +26425,8 @@ async function poolServe() {
|
|
|
26091
26425
|
}
|
|
26092
26426
|
|
|
26093
26427
|
// src/servers/runner-serve.ts
|
|
26094
|
-
import { spawn as
|
|
26095
|
-
import * as
|
|
26428
|
+
import { spawn as spawn9 } from "child_process";
|
|
26429
|
+
import * as fs51 from "fs";
|
|
26096
26430
|
import { createServer as createServer6 } from "http";
|
|
26097
26431
|
var DEFAULT_PORT2 = 8080;
|
|
26098
26432
|
var DEFAULT_WORKDIR = "/workspace/repo";
|
|
@@ -26227,8 +26561,8 @@ async function defaultRunJob(job) {
|
|
|
26227
26561
|
const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
|
|
26228
26562
|
const branch = job.ref ?? "main";
|
|
26229
26563
|
const authUrl = `https://x-access-token:${job.githubToken}@github.com/${job.repo}.git`;
|
|
26230
|
-
|
|
26231
|
-
|
|
26564
|
+
fs51.rmSync(workdir, { recursive: true, force: true });
|
|
26565
|
+
fs51.mkdirSync(workdir, { recursive: true });
|
|
26232
26566
|
const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
|
|
26233
26567
|
const target = job.runRequest.target;
|
|
26234
26568
|
const interactive = target.type === "chat";
|
|
@@ -26258,7 +26592,7 @@ async function defaultRunJob(job) {
|
|
|
26258
26592
|
...interactive && job.hardCapMs ? { KODY_HARD_CAP_MS: String(job.hardCapMs) } : {}
|
|
26259
26593
|
};
|
|
26260
26594
|
const run = (cmd, args, cwd) => new Promise((resolve16) => {
|
|
26261
|
-
const child =
|
|
26595
|
+
const child = spawn9(cmd, args, { stdio: "inherit", env: childEnv, cwd });
|
|
26262
26596
|
child.on("exit", (code) => resolve16(code ?? 0));
|
|
26263
26597
|
child.on("error", (err) => {
|
|
26264
26598
|
process.stderr.write(`[runner-serve] ${cmd} failed: ${err.message}
|
|
@@ -26361,7 +26695,7 @@ async function runnerServe() {
|
|
|
26361
26695
|
// src/servers/serve.ts
|
|
26362
26696
|
init_config();
|
|
26363
26697
|
init_litellm();
|
|
26364
|
-
import { spawn as
|
|
26698
|
+
import { spawn as spawn10 } from "child_process";
|
|
26365
26699
|
function parseTarget2(positional) {
|
|
26366
26700
|
if (!Array.isArray(positional) || positional.length === 0) return "none";
|
|
26367
26701
|
const first = String(positional[0]).toLowerCase();
|
|
@@ -26411,7 +26745,7 @@ async function serve(opts) {
|
|
|
26411
26745
|
if (usesProxy) process.stdout.write(` ANTHROPIC_BASE_URL=${url}
|
|
26412
26746
|
`);
|
|
26413
26747
|
const args = ["--dangerously-skip-permissions", "--model", model.model];
|
|
26414
|
-
const child =
|
|
26748
|
+
const child = spawn10("claude", args, { stdio: "inherit", env: editorEnv, cwd: opts.cwd });
|
|
26415
26749
|
const exitCode = await new Promise((resolve16) => {
|
|
26416
26750
|
child.on("exit", (code) => resolve16(code ?? 0));
|
|
26417
26751
|
child.on("error", (err) => {
|
|
@@ -26431,7 +26765,7 @@ async function serve(opts) {
|
|
|
26431
26765
|
if (usesProxy) process.stdout.write(` ANTHROPIC_BASE_URL=${url}
|
|
26432
26766
|
`);
|
|
26433
26767
|
try {
|
|
26434
|
-
const code =
|
|
26768
|
+
const code = spawn10("code", [opts.cwd], { stdio: "inherit", env: editorEnv, detached: true });
|
|
26435
26769
|
code.on("error", (err) => {
|
|
26436
26770
|
process.stderr.write(`[kody serve] failed to launch VS Code: ${err.message}
|
|
26437
26771
|
`);
|