@kody-ade/kody-engine 0.4.292 → 0.4.293
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 +175 -117
- package/dist/executables/types.ts +10 -0
- 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.293",
|
|
19
19
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
20
20
|
license: "MIT",
|
|
21
21
|
type: "module",
|
|
@@ -3490,23 +3490,77 @@ var init_agent = __esm({
|
|
|
3490
3490
|
}
|
|
3491
3491
|
});
|
|
3492
3492
|
|
|
3493
|
+
// src/agents.ts
|
|
3494
|
+
import * as fs9 from "fs";
|
|
3495
|
+
import * as path11 from "path";
|
|
3496
|
+
function stripFrontmatter(raw) {
|
|
3497
|
+
const match = /^---\n[\s\S]*?\n---\n?([\s\S]*)$/.exec(raw);
|
|
3498
|
+
return (match ? match[1] : raw).trim();
|
|
3499
|
+
}
|
|
3500
|
+
function loadAgentIdentity(cwd, slug2, agentsDir = DEFAULT_AGENT_DIR) {
|
|
3501
|
+
const trimmed = slug2.trim();
|
|
3502
|
+
if (!trimmed) throw new Error("loadAgentIdentity: empty agent slug");
|
|
3503
|
+
const agentPath = resolveAgentFile(cwd, trimmed, agentsDir);
|
|
3504
|
+
if (fs9.existsSync(agentPath)) {
|
|
3505
|
+
const body = stripFrontmatter(fs9.readFileSync(agentPath, "utf-8"));
|
|
3506
|
+
if (body) return body;
|
|
3507
|
+
const builtinForEmpty = BUILTIN_AGENTS[trimmed];
|
|
3508
|
+
if (builtinForEmpty) return builtinForEmpty;
|
|
3509
|
+
throw new Error(`loadAgentIdentity: agent '${trimmed}' agent identity body is empty (${agentPath})`);
|
|
3510
|
+
}
|
|
3511
|
+
const builtin = BUILTIN_AGENTS[trimmed];
|
|
3512
|
+
if (builtin) return builtin;
|
|
3513
|
+
throw new Error(`loadAgentIdentity: agent '${trimmed}' declared but ${agentPath} does not exist`);
|
|
3514
|
+
}
|
|
3515
|
+
function resolveAgentFile(cwd, slug2, agentsDir = DEFAULT_AGENT_DIR) {
|
|
3516
|
+
const localPath = path11.join(cwd, agentsDir, `${slug2}.md`);
|
|
3517
|
+
if (fs9.existsSync(localPath)) return localPath;
|
|
3518
|
+
const storeAgentRoot = getCompanyStoreAssetRoot("agents");
|
|
3519
|
+
if (storeAgentRoot) {
|
|
3520
|
+
const storePath = path11.join(storeAgentRoot, `${slug2}.md`);
|
|
3521
|
+
if (fs9.existsSync(storePath)) return storePath;
|
|
3522
|
+
}
|
|
3523
|
+
return localPath;
|
|
3524
|
+
}
|
|
3525
|
+
function frameAgentIdentity(slug2, agent) {
|
|
3526
|
+
return [
|
|
3527
|
+
`## Who you are \u2014 agent identity (authoritative identity)`,
|
|
3528
|
+
``,
|
|
3529
|
+
`You are operating as agent \`${slug2}\`. This identity defines *who* you are:`,
|
|
3530
|
+
`your authority, doctrine, voice, and hard limits. Honour it exactly. Where the`,
|
|
3531
|
+
`this identity's restrictions are stricter than the task, **the agent wins** \u2014 a task`,
|
|
3532
|
+
`can never grant you authority your agent withholds.`,
|
|
3533
|
+
``,
|
|
3534
|
+
agent
|
|
3535
|
+
].join("\n");
|
|
3536
|
+
}
|
|
3537
|
+
var DEFAULT_AGENT_DIR, BUILTIN_AGENTS;
|
|
3538
|
+
var init_agents = __esm({
|
|
3539
|
+
"src/agents.ts"() {
|
|
3540
|
+
"use strict";
|
|
3541
|
+
init_companyStore();
|
|
3542
|
+
DEFAULT_AGENT_DIR = ".kody/agents";
|
|
3543
|
+
BUILTIN_AGENTS = {};
|
|
3544
|
+
}
|
|
3545
|
+
});
|
|
3546
|
+
|
|
3493
3547
|
// src/task-artifacts.ts
|
|
3494
|
-
import
|
|
3495
|
-
import
|
|
3548
|
+
import fs10 from "fs";
|
|
3549
|
+
import path12 from "path";
|
|
3496
3550
|
import posixPath from "path/posix";
|
|
3497
3551
|
function prepareTaskArtifactsDir(cwd, taskId) {
|
|
3498
3552
|
const safeId = String(taskId).replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
3499
3553
|
const absDir = runtimeStatePath(cwd, "task-artifacts", safeId);
|
|
3500
3554
|
const relDir = absDir;
|
|
3501
|
-
|
|
3555
|
+
fs10.mkdirSync(absDir, { recursive: true });
|
|
3502
3556
|
return { taskId: safeId, absDir, relDir };
|
|
3503
3557
|
}
|
|
3504
3558
|
function verifyTaskArtifacts(absDir) {
|
|
3505
3559
|
const missing = [];
|
|
3506
3560
|
for (const name of TASK_ARTIFACT_FILES) {
|
|
3507
|
-
const full =
|
|
3561
|
+
const full = path12.join(absDir, name);
|
|
3508
3562
|
try {
|
|
3509
|
-
const stat =
|
|
3563
|
+
const stat = fs10.statSync(full);
|
|
3510
3564
|
if (!stat.isFile() || stat.size === 0) missing.push(name);
|
|
3511
3565
|
} catch {
|
|
3512
3566
|
missing.push(name);
|
|
@@ -3519,11 +3573,11 @@ function taskArtifactStatePath(taskId, file) {
|
|
|
3519
3573
|
}
|
|
3520
3574
|
function persistTaskArtifactsToState(config, cwd, artifacts) {
|
|
3521
3575
|
for (const file of TASK_ARTIFACT_FILES) {
|
|
3522
|
-
const full =
|
|
3523
|
-
if (!
|
|
3524
|
-
const stat =
|
|
3576
|
+
const full = path12.join(artifacts.absDir, file);
|
|
3577
|
+
if (!fs10.existsSync(full)) continue;
|
|
3578
|
+
const stat = fs10.statSync(full);
|
|
3525
3579
|
if (!stat.isFile() || stat.size === 0) continue;
|
|
3526
|
-
const content =
|
|
3580
|
+
const content = fs10.readFileSync(full, "utf-8");
|
|
3527
3581
|
upsertStateText(
|
|
3528
3582
|
config,
|
|
3529
3583
|
cwd,
|
|
@@ -3603,7 +3657,7 @@ var init_task_artifacts = __esm({
|
|
|
3603
3657
|
|
|
3604
3658
|
// src/gha.ts
|
|
3605
3659
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
3606
|
-
import * as
|
|
3660
|
+
import * as fs16 from "fs";
|
|
3607
3661
|
function getRunUrl() {
|
|
3608
3662
|
const server = process.env.GITHUB_SERVER_URL;
|
|
3609
3663
|
const repo = process.env.GITHUB_REPOSITORY;
|
|
@@ -3614,10 +3668,10 @@ function getRunUrl() {
|
|
|
3614
3668
|
function reactToTriggerComment(cwd) {
|
|
3615
3669
|
if (process.env.GITHUB_EVENT_NAME !== "issue_comment") return;
|
|
3616
3670
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
3617
|
-
if (!eventPath || !
|
|
3671
|
+
if (!eventPath || !fs16.existsSync(eventPath)) return;
|
|
3618
3672
|
let event = null;
|
|
3619
3673
|
try {
|
|
3620
|
-
event = JSON.parse(
|
|
3674
|
+
event = JSON.parse(fs16.readFileSync(eventPath, "utf-8"));
|
|
3621
3675
|
} catch {
|
|
3622
3676
|
return;
|
|
3623
3677
|
}
|
|
@@ -3668,60 +3722,6 @@ var init_gha = __esm({
|
|
|
3668
3722
|
}
|
|
3669
3723
|
});
|
|
3670
3724
|
|
|
3671
|
-
// src/agents.ts
|
|
3672
|
-
import * as fs16 from "fs";
|
|
3673
|
-
import * as path16 from "path";
|
|
3674
|
-
function stripFrontmatter(raw) {
|
|
3675
|
-
const match = /^---\n[\s\S]*?\n---\n?([\s\S]*)$/.exec(raw);
|
|
3676
|
-
return (match ? match[1] : raw).trim();
|
|
3677
|
-
}
|
|
3678
|
-
function loadAgentIdentity(cwd, slug2, agentsDir = DEFAULT_AGENT_DIR) {
|
|
3679
|
-
const trimmed = slug2.trim();
|
|
3680
|
-
if (!trimmed) throw new Error("loadAgentIdentity: empty agent slug");
|
|
3681
|
-
const agentPath = resolveAgentFile(cwd, trimmed, agentsDir);
|
|
3682
|
-
if (fs16.existsSync(agentPath)) {
|
|
3683
|
-
const body = stripFrontmatter(fs16.readFileSync(agentPath, "utf-8"));
|
|
3684
|
-
if (body) return body;
|
|
3685
|
-
const builtinForEmpty = BUILTIN_AGENTS[trimmed];
|
|
3686
|
-
if (builtinForEmpty) return builtinForEmpty;
|
|
3687
|
-
throw new Error(`loadAgentIdentity: agent '${trimmed}' agent identity body is empty (${agentPath})`);
|
|
3688
|
-
}
|
|
3689
|
-
const builtin = BUILTIN_AGENTS[trimmed];
|
|
3690
|
-
if (builtin) return builtin;
|
|
3691
|
-
throw new Error(`loadAgentIdentity: agent '${trimmed}' declared but ${agentPath} does not exist`);
|
|
3692
|
-
}
|
|
3693
|
-
function resolveAgentFile(cwd, slug2, agentsDir = DEFAULT_AGENT_DIR) {
|
|
3694
|
-
const localPath = path16.join(cwd, agentsDir, `${slug2}.md`);
|
|
3695
|
-
if (fs16.existsSync(localPath)) return localPath;
|
|
3696
|
-
const storeAgentRoot = getCompanyStoreAssetRoot("agents");
|
|
3697
|
-
if (storeAgentRoot) {
|
|
3698
|
-
const storePath = path16.join(storeAgentRoot, `${slug2}.md`);
|
|
3699
|
-
if (fs16.existsSync(storePath)) return storePath;
|
|
3700
|
-
}
|
|
3701
|
-
return localPath;
|
|
3702
|
-
}
|
|
3703
|
-
function frameAgentIdentity(slug2, agent) {
|
|
3704
|
-
return [
|
|
3705
|
-
`## Who you are \u2014 agent identity (authoritative identity)`,
|
|
3706
|
-
``,
|
|
3707
|
-
`You are operating as agent \`${slug2}\`. This identity defines *who* you are:`,
|
|
3708
|
-
`your authority, doctrine, voice, and hard limits. Honour it exactly. Where the`,
|
|
3709
|
-
`this identity's restrictions are stricter than the task, **the agent wins** \u2014 a task`,
|
|
3710
|
-
`can never grant you authority your agent withholds.`,
|
|
3711
|
-
``,
|
|
3712
|
-
agent
|
|
3713
|
-
].join("\n");
|
|
3714
|
-
}
|
|
3715
|
-
var DEFAULT_AGENT_DIR, BUILTIN_AGENTS;
|
|
3716
|
-
var init_agents = __esm({
|
|
3717
|
-
"src/agents.ts"() {
|
|
3718
|
-
"use strict";
|
|
3719
|
-
init_companyStore();
|
|
3720
|
-
DEFAULT_AGENT_DIR = ".kody/agents";
|
|
3721
|
-
BUILTIN_AGENTS = {};
|
|
3722
|
-
}
|
|
3723
|
-
});
|
|
3724
|
-
|
|
3725
3725
|
// src/capabilityReport.ts
|
|
3726
3726
|
function parseCapabilityReportsFromText(text) {
|
|
3727
3727
|
const reports = [];
|
|
@@ -7703,8 +7703,7 @@ var init_typeDefinitions = __esm({
|
|
|
7703
7703
|
stage: "publish",
|
|
7704
7704
|
evidence: "productionDeployed",
|
|
7705
7705
|
capability: "vercel-production-deploy",
|
|
7706
|
-
executable: "vercel-production-deploy"
|
|
7707
|
-
args: { goal: { fact: "goalId" } }
|
|
7706
|
+
executable: "vercel-production-deploy"
|
|
7708
7707
|
}
|
|
7709
7708
|
]
|
|
7710
7709
|
},
|
|
@@ -8720,7 +8719,8 @@ var init_advanceManagedGoal = __esm({
|
|
|
8720
8719
|
capability: decision.capability,
|
|
8721
8720
|
cliArgs: decision.cliArgs,
|
|
8722
8721
|
...decision.executable ? { executable: decision.executable } : {},
|
|
8723
|
-
...decision.saveReport === true ? { saveReport: true } : {}
|
|
8722
|
+
...decision.saveReport === true ? { saveReport: true } : {},
|
|
8723
|
+
resultTarget: { type: "goal", id: goal.id, evidence: decision.evidence }
|
|
8724
8724
|
};
|
|
8725
8725
|
ctx.output.reason = `dispatch ${decision.capability} for ${decision.evidence}`;
|
|
8726
8726
|
};
|
|
@@ -9697,6 +9697,18 @@ function collectResults(raw, agentResult) {
|
|
|
9697
9697
|
if (agentResult?.finalText) out.push(...parseCapabilityResultsFromText(agentResult.finalText));
|
|
9698
9698
|
return out;
|
|
9699
9699
|
}
|
|
9700
|
+
function parseResultTarget(raw) {
|
|
9701
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
9702
|
+
const target = raw;
|
|
9703
|
+
if (target.type !== "goal") return null;
|
|
9704
|
+
if (typeof target.id !== "string" || target.id.trim().length === 0) return null;
|
|
9705
|
+
const evidence = typeof target.evidence === "string" && target.evidence.trim().length > 0 ? target.evidence.trim() : void 0;
|
|
9706
|
+
return {
|
|
9707
|
+
type: "goal",
|
|
9708
|
+
id: target.id.trim(),
|
|
9709
|
+
...evidence ? { evidence } : {}
|
|
9710
|
+
};
|
|
9711
|
+
}
|
|
9700
9712
|
function collectGoalCapabilityEvidence(reports, results, fallbackGoalId, explicitEvidence) {
|
|
9701
9713
|
const items = [];
|
|
9702
9714
|
for (const report of reports) {
|
|
@@ -9790,8 +9802,9 @@ var init_applyCapabilityReports = __esm({
|
|
|
9790
9802
|
applyCapabilityReports = async (ctx, _profile, agentResult) => {
|
|
9791
9803
|
const reports = collectReports(ctx.data.capabilityReports, agentResult);
|
|
9792
9804
|
const results = collectResults(ctx.data.capabilityResults ?? ctx.data.dutyResults, agentResult);
|
|
9793
|
-
const
|
|
9794
|
-
const
|
|
9805
|
+
const resultTarget = parseResultTarget(ctx.data.capabilityResultTarget);
|
|
9806
|
+
const resultGoalId = resultTarget?.id ?? (typeof ctx.args.goal === "string" && ctx.args.goal.length > 0 ? ctx.args.goal : null);
|
|
9807
|
+
const explicitEvidence = resultTarget?.evidence ?? (typeof ctx.args.evidence === "string" && ctx.args.evidence.length > 0 ? ctx.args.evidence : void 0);
|
|
9795
9808
|
const evidenceItems = collectGoalCapabilityEvidence(reports, results, resultGoalId, explicitEvidence);
|
|
9796
9809
|
if (evidenceItems.length === 0) return;
|
|
9797
9810
|
const evidenceByGoal = groupGoalEvidence(evidenceItems);
|
|
@@ -18402,7 +18415,8 @@ function handoffToJob(handoff) {
|
|
|
18402
18415
|
executable: handoff.executable,
|
|
18403
18416
|
cliArgs: handoff.cliArgs,
|
|
18404
18417
|
flavor: "instant",
|
|
18405
|
-
saveReport: handoff.saveReport === true
|
|
18418
|
+
saveReport: handoff.saveReport === true,
|
|
18419
|
+
resultTarget: handoff.resultTarget
|
|
18406
18420
|
};
|
|
18407
18421
|
}
|
|
18408
18422
|
function clearStampedLifecycleLabels(profile, ctx) {
|
|
@@ -18817,7 +18831,20 @@ function validateJob(input) {
|
|
|
18817
18831
|
cliArgs: j.cliArgs ?? {},
|
|
18818
18832
|
flavor: j.flavor,
|
|
18819
18833
|
force: j.force === true,
|
|
18820
|
-
saveReport: j.saveReport === true
|
|
18834
|
+
saveReport: j.saveReport === true,
|
|
18835
|
+
resultTarget: parseCapabilityResultTarget(j.resultTarget)
|
|
18836
|
+
};
|
|
18837
|
+
}
|
|
18838
|
+
function parseCapabilityResultTarget(raw) {
|
|
18839
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
18840
|
+
const target = raw;
|
|
18841
|
+
if (target.type !== "goal") return void 0;
|
|
18842
|
+
if (typeof target.id !== "string" || target.id.trim().length === 0) return void 0;
|
|
18843
|
+
const evidence = typeof target.evidence === "string" && target.evidence.trim().length > 0 ? target.evidence.trim() : void 0;
|
|
18844
|
+
return {
|
|
18845
|
+
type: "goal",
|
|
18846
|
+
id: target.id.trim(),
|
|
18847
|
+
...evidence ? { evidence } : {}
|
|
18821
18848
|
};
|
|
18822
18849
|
}
|
|
18823
18850
|
async function runJob(job, base) {
|
|
@@ -18877,6 +18904,7 @@ async function runCapabilityImplementationStep(valid, profileName, capabilityIde
|
|
|
18877
18904
|
preloadedData.jobExecutable = profileName;
|
|
18878
18905
|
if (valid.schedule !== void 0 && valid.schedule.length > 0) preloadedData.jobSchedule = valid.schedule;
|
|
18879
18906
|
if (valid.saveReport === true) preloadedData.jobSaveReport = true;
|
|
18907
|
+
if (valid.resultTarget) preloadedData.capabilityResultTarget = valid.resultTarget;
|
|
18880
18908
|
if (capabilityContext) {
|
|
18881
18909
|
preloadedData.capabilitySlug = capabilityContext.slug;
|
|
18882
18910
|
preloadedData.capabilityTitle = capabilityContext.title;
|
|
@@ -19241,16 +19269,17 @@ import * as path47 from "path";
|
|
|
19241
19269
|
|
|
19242
19270
|
// src/chat/loop.ts
|
|
19243
19271
|
init_agent();
|
|
19272
|
+
init_agents();
|
|
19244
19273
|
init_config();
|
|
19245
19274
|
init_registry();
|
|
19246
19275
|
init_task_artifacts();
|
|
19247
|
-
import * as
|
|
19248
|
-
import * as
|
|
19276
|
+
import * as fs14 from "fs";
|
|
19277
|
+
import * as path16 from "path";
|
|
19249
19278
|
|
|
19250
19279
|
// src/chat/attachments.ts
|
|
19251
19280
|
init_runtimePaths();
|
|
19252
|
-
import * as
|
|
19253
|
-
import * as
|
|
19281
|
+
import * as fs11 from "fs";
|
|
19282
|
+
import * as path13 from "path";
|
|
19254
19283
|
var INLINE_ATTACHMENT_RE = /(?:\[(?:Image|File): ([^\]]*)\]\n)?data:([\w.+-]+\/[\w.+-]+);base64,([A-Za-z0-9+/=]+)/g;
|
|
19255
19284
|
var EXT_BY_MIME = {
|
|
19256
19285
|
"image/png": "png",
|
|
@@ -19283,11 +19312,11 @@ function prepareAttachments(turns, cwd, sessionId) {
|
|
|
19283
19312
|
if (!isImage) return `[File: ${name}]`;
|
|
19284
19313
|
try {
|
|
19285
19314
|
if (!dirEnsured) {
|
|
19286
|
-
|
|
19315
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
19287
19316
|
dirEnsured = true;
|
|
19288
19317
|
}
|
|
19289
|
-
const filePath =
|
|
19290
|
-
|
|
19318
|
+
const filePath = path13.join(dir, `${imageCounter}.${extFor(mime)}`);
|
|
19319
|
+
fs11.writeFileSync(filePath, Buffer.from(data, "base64"));
|
|
19291
19320
|
imageCounter += 1;
|
|
19292
19321
|
imagePaths.push(filePath);
|
|
19293
19322
|
return `[Image "${name}" is attached \u2014 saved to ${filePath}. Use the Read tool on that exact path to view it.]`;
|
|
@@ -19303,11 +19332,11 @@ function prepareAttachments(turns, cwd, sessionId) {
|
|
|
19303
19332
|
}
|
|
19304
19333
|
|
|
19305
19334
|
// src/chat/events.ts
|
|
19306
|
-
import * as
|
|
19307
|
-
import * as
|
|
19335
|
+
import * as fs12 from "fs";
|
|
19336
|
+
import * as path14 from "path";
|
|
19308
19337
|
import posixPath2 from "path/posix";
|
|
19309
19338
|
function eventsFilePath(cwd, sessionId) {
|
|
19310
|
-
return
|
|
19339
|
+
return path14.join(cwd, ".kody", "events", `${sessionId}.jsonl`);
|
|
19311
19340
|
}
|
|
19312
19341
|
function eventsStatePath(sessionId) {
|
|
19313
19342
|
return posixPath2.join("events", `${sessionId}.jsonl`);
|
|
@@ -19318,8 +19347,8 @@ var FileSink = class {
|
|
|
19318
19347
|
}
|
|
19319
19348
|
file;
|
|
19320
19349
|
async emit(event) {
|
|
19321
|
-
|
|
19322
|
-
|
|
19350
|
+
fs12.mkdirSync(path14.dirname(this.file), { recursive: true });
|
|
19351
|
+
fs12.appendFileSync(this.file, `${JSON.stringify(event)}
|
|
19323
19352
|
`);
|
|
19324
19353
|
}
|
|
19325
19354
|
};
|
|
@@ -19373,18 +19402,18 @@ function makeRunId(sessionId, suffix) {
|
|
|
19373
19402
|
}
|
|
19374
19403
|
|
|
19375
19404
|
// src/chat/session.ts
|
|
19376
|
-
import * as
|
|
19377
|
-
import * as
|
|
19405
|
+
import * as fs13 from "fs";
|
|
19406
|
+
import * as path15 from "path";
|
|
19378
19407
|
import posixPath3 from "path/posix";
|
|
19379
19408
|
function sessionFilePath(cwd, sessionId) {
|
|
19380
|
-
return
|
|
19409
|
+
return path15.join(cwd, ".kody", "sessions", `${sessionId}.jsonl`);
|
|
19381
19410
|
}
|
|
19382
19411
|
function sessionStatePath(sessionId) {
|
|
19383
19412
|
return posixPath3.join("sessions", `${sessionId}.jsonl`);
|
|
19384
19413
|
}
|
|
19385
19414
|
function readMeta(file) {
|
|
19386
|
-
if (!
|
|
19387
|
-
const raw =
|
|
19415
|
+
if (!fs13.existsSync(file)) return null;
|
|
19416
|
+
const raw = fs13.readFileSync(file, "utf-8");
|
|
19388
19417
|
const firstLine2 = raw.split("\n", 1)[0]?.trim();
|
|
19389
19418
|
if (!firstLine2) return null;
|
|
19390
19419
|
try {
|
|
@@ -19397,8 +19426,8 @@ function readMeta(file) {
|
|
|
19397
19426
|
}
|
|
19398
19427
|
}
|
|
19399
19428
|
function readSession(file) {
|
|
19400
|
-
if (!
|
|
19401
|
-
const raw =
|
|
19429
|
+
if (!fs13.existsSync(file)) return [];
|
|
19430
|
+
const raw = fs13.readFileSync(file, "utf-8").trim();
|
|
19402
19431
|
if (!raw) return [];
|
|
19403
19432
|
const turns = [];
|
|
19404
19433
|
for (const line of raw.split("\n")) {
|
|
@@ -19414,14 +19443,14 @@ function readSession(file) {
|
|
|
19414
19443
|
return turns;
|
|
19415
19444
|
}
|
|
19416
19445
|
function appendTurn(file, turn) {
|
|
19417
|
-
|
|
19446
|
+
fs13.mkdirSync(path15.dirname(file), { recursive: true });
|
|
19418
19447
|
const line = JSON.stringify({
|
|
19419
19448
|
role: turn.role,
|
|
19420
19449
|
content: turn.content,
|
|
19421
19450
|
timestamp: turn.timestamp,
|
|
19422
19451
|
toolCalls: turn.toolCalls ?? []
|
|
19423
19452
|
});
|
|
19424
|
-
|
|
19453
|
+
fs13.appendFileSync(file, `${line}
|
|
19425
19454
|
`);
|
|
19426
19455
|
}
|
|
19427
19456
|
function seedInitialMessage(file, message) {
|
|
@@ -19556,7 +19585,7 @@ function buildExecutableCatalog() {
|
|
|
19556
19585
|
const entries = [];
|
|
19557
19586
|
for (const { name, profilePath } of discovered) {
|
|
19558
19587
|
try {
|
|
19559
|
-
const raw = JSON.parse(
|
|
19588
|
+
const raw = JSON.parse(fs14.readFileSync(profilePath, "utf-8"));
|
|
19560
19589
|
const describe = typeof raw.describe === "string" ? raw.describe : "";
|
|
19561
19590
|
const firstSentence = describe.split(/(?<=[.!?])\s+/, 1)[0] ?? "";
|
|
19562
19591
|
entries.push({ name, describe: firstSentence.trim() });
|
|
@@ -19593,6 +19622,7 @@ async function runChatTurn(opts) {
|
|
|
19593
19622
|
}
|
|
19594
19623
|
const { turns: promptTurns, imagePaths } = prepareAttachments(turns, opts.cwd, opts.sessionId);
|
|
19595
19624
|
const basePrompt = opts.systemPrompt ?? (opts.model.protocol === "openai" ? OPENAI_CHAT_SYSTEM_PROMPT : CHAT_SYSTEM_PROMPT);
|
|
19625
|
+
const agentIdentityBlock = readAgentIdentityBlock(opts.cwd, opts.agentIdentity);
|
|
19596
19626
|
const catalog = buildExecutableCatalog();
|
|
19597
19627
|
const taskArtifactsPaths = prepareTaskArtifactsDir(opts.cwd, opts.sessionId);
|
|
19598
19628
|
const artifactAddendum = taskArtifactsPromptAddendum({
|
|
@@ -19603,7 +19633,8 @@ async function runChatTurn(opts) {
|
|
|
19603
19633
|
const contextBlock = readContextBlock(opts.cwd);
|
|
19604
19634
|
const memoryBlock = readMemoryIndexBlock(opts.cwd);
|
|
19605
19635
|
const instructionsBlock = readInstructionsBlock(opts.cwd);
|
|
19606
|
-
const
|
|
19636
|
+
const fetchRepoEnabled = Boolean(opts.enableFetchRepoTool && opts.reposRoot);
|
|
19637
|
+
const crossRepoBlock = fetchRepoEnabled ? CROSS_REPO_PROMPT : null;
|
|
19607
19638
|
const dashboardCmsEnabled = Boolean(opts.cmsDashboardUrl && opts.cmsRepoSlug && opts.cmsToken);
|
|
19608
19639
|
const dashboardCmsBlock = dashboardCmsEnabled ? DASHBOARD_CMS_PROMPT : null;
|
|
19609
19640
|
const imageBlock = imagePaths.length > 0 ? [
|
|
@@ -19616,6 +19647,7 @@ async function runChatTurn(opts) {
|
|
|
19616
19647
|
].join("\n") : null;
|
|
19617
19648
|
const systemPrompt = [
|
|
19618
19649
|
basePrompt,
|
|
19650
|
+
agentIdentityBlock,
|
|
19619
19651
|
contextBlock,
|
|
19620
19652
|
memoryBlock,
|
|
19621
19653
|
instructionsBlock,
|
|
@@ -19644,14 +19676,14 @@ async function runChatTurn(opts) {
|
|
|
19644
19676
|
quiet: opts.quiet,
|
|
19645
19677
|
additionalDirectories: [
|
|
19646
19678
|
taskArtifactsPaths.absDir,
|
|
19647
|
-
...Array.from(new Set(imagePaths.map((p2) =>
|
|
19679
|
+
...Array.from(new Set(imagePaths.map((p2) => path16.dirname(p2))))
|
|
19648
19680
|
],
|
|
19649
19681
|
systemPromptAppend: systemPrompt,
|
|
19650
19682
|
...opts.reasoningEffort ? { reasoningEffort: opts.reasoningEffort } : {},
|
|
19651
|
-
//
|
|
19652
|
-
//
|
|
19653
|
-
//
|
|
19654
|
-
...
|
|
19683
|
+
// Cross-repo work is opt-in. Repo Brain's default path remains focused
|
|
19684
|
+
// on the selected repo even though the server stores clones under
|
|
19685
|
+
// reposRoot.
|
|
19686
|
+
...fetchRepoEnabled ? {
|
|
19655
19687
|
enableFetchRepoTool: true,
|
|
19656
19688
|
reposRoot: opts.reposRoot,
|
|
19657
19689
|
repoToken: opts.repoToken
|
|
@@ -19736,6 +19768,12 @@ async function runChatTurn(opts) {
|
|
|
19736
19768
|
}
|
|
19737
19769
|
return { exitCode: 0, reply };
|
|
19738
19770
|
}
|
|
19771
|
+
function readAgentIdentityBlock(cwd, agentIdentity) {
|
|
19772
|
+
const slug2 = agentIdentity?.slug?.trim();
|
|
19773
|
+
if (!slug2) return null;
|
|
19774
|
+
const body = agentIdentity?.body?.trim() || loadAgentIdentity(cwd, slug2);
|
|
19775
|
+
return frameAgentIdentity(slug2, body);
|
|
19776
|
+
}
|
|
19739
19777
|
async function runOpenAIChatTurn(args) {
|
|
19740
19778
|
const { opts, turns, systemPrompt, sessionFile } = args;
|
|
19741
19779
|
const doFetch = opts.fetchImpl ?? fetch;
|
|
@@ -19821,10 +19859,10 @@ async function emit(sink, type, sessionId, suffix, payload) {
|
|
|
19821
19859
|
var MEMORY_INDEX_REL = ".kody/memory/INDEX.md";
|
|
19822
19860
|
var MAX_INDEX_BYTES = 8e3;
|
|
19823
19861
|
function readMemoryIndexBlock(cwd) {
|
|
19824
|
-
const indexPath =
|
|
19862
|
+
const indexPath = path16.join(cwd, MEMORY_INDEX_REL);
|
|
19825
19863
|
let raw;
|
|
19826
19864
|
try {
|
|
19827
|
-
raw =
|
|
19865
|
+
raw = fs14.readFileSync(indexPath, "utf-8");
|
|
19828
19866
|
} catch {
|
|
19829
19867
|
return "";
|
|
19830
19868
|
}
|
|
@@ -19844,17 +19882,17 @@ _\u2026 (memory index truncated; use recall_search to read more)_` : trimmed;
|
|
|
19844
19882
|
var CONTEXT_DIR_REL = ".kody/context";
|
|
19845
19883
|
var MAX_CONTEXT_BYTES = 12e3;
|
|
19846
19884
|
function readContextBlock(cwd) {
|
|
19847
|
-
const dir =
|
|
19885
|
+
const dir = path16.join(cwd, CONTEXT_DIR_REL);
|
|
19848
19886
|
let files;
|
|
19849
19887
|
try {
|
|
19850
|
-
files =
|
|
19888
|
+
files = fs14.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
19851
19889
|
} catch {
|
|
19852
19890
|
return "";
|
|
19853
19891
|
}
|
|
19854
19892
|
const sections = [];
|
|
19855
19893
|
for (const file of files) {
|
|
19856
19894
|
try {
|
|
19857
|
-
const content =
|
|
19895
|
+
const content = fs14.readFileSync(path16.join(dir, file), "utf-8").trim();
|
|
19858
19896
|
if (content) sections.push(`### ${file.replace(/\.md$/, "")}
|
|
19859
19897
|
|
|
19860
19898
|
${content}`);
|
|
@@ -19877,10 +19915,10 @@ _\u2026 (context truncated; use the state repo context files for the full text)_
|
|
|
19877
19915
|
var INSTRUCTIONS_REL = ".kody/instructions.md";
|
|
19878
19916
|
var MAX_INSTRUCTIONS_BYTES = 8e3;
|
|
19879
19917
|
function readInstructionsBlock(cwd) {
|
|
19880
|
-
const instructionsPath =
|
|
19918
|
+
const instructionsPath = path16.join(cwd, INSTRUCTIONS_REL);
|
|
19881
19919
|
let raw;
|
|
19882
19920
|
try {
|
|
19883
|
-
raw =
|
|
19921
|
+
raw = fs14.readFileSync(instructionsPath, "utf-8");
|
|
19884
19922
|
} catch {
|
|
19885
19923
|
return "";
|
|
19886
19924
|
}
|
|
@@ -19981,7 +20019,7 @@ init_config();
|
|
|
19981
20019
|
|
|
19982
20020
|
// src/dispatch.ts
|
|
19983
20021
|
init_config();
|
|
19984
|
-
import * as
|
|
20022
|
+
import * as fs15 from "fs";
|
|
19985
20023
|
|
|
19986
20024
|
// src/cron-match.ts
|
|
19987
20025
|
var FIELD_BOUNDS = [
|
|
@@ -20083,10 +20121,10 @@ function autoDispatch(opts) {
|
|
|
20083
20121
|
}
|
|
20084
20122
|
const eventName = process.env.GITHUB_EVENT_NAME;
|
|
20085
20123
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
20086
|
-
if (!eventName || !eventPath || !
|
|
20124
|
+
if (!eventName || !eventPath || !fs15.existsSync(eventPath)) return null;
|
|
20087
20125
|
let event = {};
|
|
20088
20126
|
try {
|
|
20089
|
-
event = JSON.parse(
|
|
20127
|
+
event = JSON.parse(fs15.readFileSync(eventPath, "utf-8"));
|
|
20090
20128
|
} catch {
|
|
20091
20129
|
return null;
|
|
20092
20130
|
}
|
|
@@ -20197,7 +20235,7 @@ function autoDispatchTyped(opts) {
|
|
|
20197
20235
|
if (legacy) return { kind: "route", ...legacy };
|
|
20198
20236
|
const eventName = process.env.GITHUB_EVENT_NAME;
|
|
20199
20237
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
20200
|
-
if (!eventName || !eventPath || !
|
|
20238
|
+
if (!eventName || !eventPath || !fs15.existsSync(eventPath)) {
|
|
20201
20239
|
return { kind: "silent", reason: "no GHA event context" };
|
|
20202
20240
|
}
|
|
20203
20241
|
if (eventName !== "issue_comment") {
|
|
@@ -20205,7 +20243,7 @@ function autoDispatchTyped(opts) {
|
|
|
20205
20243
|
}
|
|
20206
20244
|
let event = {};
|
|
20207
20245
|
try {
|
|
20208
|
-
event = JSON.parse(
|
|
20246
|
+
event = JSON.parse(fs15.readFileSync(eventPath, "utf-8"));
|
|
20209
20247
|
} catch {
|
|
20210
20248
|
return { kind: "silent", reason: "GHA event payload unreadable" };
|
|
20211
20249
|
}
|
|
@@ -20249,7 +20287,7 @@ function dispatchScheduledWatches(opts) {
|
|
|
20249
20287
|
for (const exe of listExecutables()) {
|
|
20250
20288
|
let raw;
|
|
20251
20289
|
try {
|
|
20252
|
-
raw =
|
|
20290
|
+
raw = fs15.readFileSync(exe.profilePath, "utf-8");
|
|
20253
20291
|
} catch {
|
|
20254
20292
|
continue;
|
|
20255
20293
|
}
|
|
@@ -21332,6 +21370,19 @@ function strField(body, key) {
|
|
|
21332
21370
|
}
|
|
21333
21371
|
return void 0;
|
|
21334
21372
|
}
|
|
21373
|
+
function boolField(body, key) {
|
|
21374
|
+
return typeof body === "object" && body !== null && body[key] === true;
|
|
21375
|
+
}
|
|
21376
|
+
function agentIdentityField(body) {
|
|
21377
|
+
if (typeof body !== "object" || body === null || !("agentIdentity" in body)) return void 0;
|
|
21378
|
+
const value = body.agentIdentity;
|
|
21379
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
21380
|
+
const record2 = value;
|
|
21381
|
+
const slug2 = typeof record2.slug === "string" ? record2.slug.trim() : "";
|
|
21382
|
+
const bodyText = typeof record2.body === "string" ? record2.body.trim() : "";
|
|
21383
|
+
if (!slug2 || !bodyText) return void 0;
|
|
21384
|
+
return { slug: slug2, body: bodyText };
|
|
21385
|
+
}
|
|
21335
21386
|
function sendJson(res, status, body) {
|
|
21336
21387
|
res.writeHead(status, { "content-type": "application/json" });
|
|
21337
21388
|
res.end(JSON.stringify(body));
|
|
@@ -21466,6 +21517,8 @@ async function handleChatTurn(req, res, chatId, opts) {
|
|
|
21466
21517
|
const dashboardUrl = strField(body, "dashboardUrl");
|
|
21467
21518
|
const storeRepoUrl = strField(body, "storeRepoUrl");
|
|
21468
21519
|
const storeRef = strField(body, "storeRef");
|
|
21520
|
+
const allowCrossRepo = boolField(body, "allowCrossRepo");
|
|
21521
|
+
const agentIdentity = agentIdentityField(body);
|
|
21469
21522
|
let agentCwd;
|
|
21470
21523
|
try {
|
|
21471
21524
|
agentCwd = await ensureRepoCwd({
|
|
@@ -21540,9 +21593,12 @@ async function handleChatTurn(req, res, chatId, opts) {
|
|
|
21540
21593
|
model: opts.model,
|
|
21541
21594
|
litellmUrl: opts.litellmUrl,
|
|
21542
21595
|
sink,
|
|
21543
|
-
// Let the agent clone + work on OTHER repos via the fetch_repo tool.
|
|
21544
21596
|
reposRoot: opts.reposRoot,
|
|
21597
|
+
// Repo Brain is selected-repo focused by default. Higher-level
|
|
21598
|
+
// coordinator flows can opt into fetch_repo explicitly.
|
|
21599
|
+
...allowCrossRepo ? { enableFetchRepoTool: true } : {},
|
|
21545
21600
|
repoToken,
|
|
21601
|
+
...agentIdentity ? { agentIdentity } : {},
|
|
21546
21602
|
...dashboardUrl && repo && stateToken ? {
|
|
21547
21603
|
cmsDashboardUrl: dashboardUrl,
|
|
21548
21604
|
cmsRepoSlug: repo,
|
|
@@ -21812,7 +21868,9 @@ async function proxyToBrainServe(args) {
|
|
|
21812
21868
|
...args.body.repoToken ? { repoToken: args.body.repoToken } : {},
|
|
21813
21869
|
...args.body.dashboardUrl ? { dashboardUrl: args.body.dashboardUrl } : {},
|
|
21814
21870
|
...args.body.storeRepoUrl ? { storeRepoUrl: args.body.storeRepoUrl } : {},
|
|
21815
|
-
...args.body.storeRef ? { storeRef: args.body.storeRef } : {}
|
|
21871
|
+
...args.body.storeRef ? { storeRef: args.body.storeRef } : {},
|
|
21872
|
+
...args.body.allowCrossRepo === true ? { allowCrossRepo: true } : {},
|
|
21873
|
+
...args.body.agentIdentity ? { agentIdentity: args.body.agentIdentity } : {}
|
|
21816
21874
|
})
|
|
21817
21875
|
});
|
|
21818
21876
|
if (!upstream.ok || !upstream.body) {
|
|
@@ -394,6 +394,12 @@ export interface OutputContract {
|
|
|
394
394
|
}
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
+
export interface CapabilityResultTarget {
|
|
398
|
+
type: "goal"
|
|
399
|
+
id: string
|
|
400
|
+
evidence?: string
|
|
401
|
+
}
|
|
402
|
+
|
|
397
403
|
// ────────────────────────────────────────────────────────────────────────────
|
|
398
404
|
// Run-time context passed to every script.
|
|
399
405
|
// ────────────────────────────────────────────────────────────────────────────
|
|
@@ -429,6 +435,7 @@ export interface Context {
|
|
|
429
435
|
executable?: string
|
|
430
436
|
cliArgs: Record<string, unknown>
|
|
431
437
|
saveReport?: boolean
|
|
438
|
+
resultTarget?: CapabilityResultTarget
|
|
432
439
|
}
|
|
433
440
|
/** In-process hand-off to a full Job, preserving job identity in task state. */
|
|
434
441
|
nextJob?: Job
|
|
@@ -440,6 +447,7 @@ export interface Context {
|
|
|
440
447
|
executable?: string
|
|
441
448
|
cliArgs: Record<string, unknown>
|
|
442
449
|
saveReport?: boolean
|
|
450
|
+
resultTarget?: CapabilityResultTarget
|
|
443
451
|
}
|
|
444
452
|
}
|
|
445
453
|
/**
|
|
@@ -512,4 +520,6 @@ export interface Job {
|
|
|
512
520
|
force?: boolean
|
|
513
521
|
/** Ask the owning goal/loop to write a report run after its persisted decision. */
|
|
514
522
|
saveReport?: boolean
|
|
523
|
+
/** Internal parent context used by postflights to attach neutral capability output. */
|
|
524
|
+
resultTarget?: CapabilityResultTarget
|
|
515
525
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.293",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|