@kody-ade/kody-engine 0.4.292 → 0.4.294
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 +186 -118
- package/dist/executables/types.ts +10 -0
- package/package.json +2 -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.294",
|
|
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",
|
|
@@ -45,8 +45,9 @@ var init_package = __esm({
|
|
|
45
45
|
lint: "biome check",
|
|
46
46
|
"lint:fix": "biome check --write",
|
|
47
47
|
format: "biome format --write",
|
|
48
|
+
"verify:package": "node scripts/verify-package-tarball.cjs",
|
|
48
49
|
"brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner",
|
|
49
|
-
prepublishOnly: "pnpm typecheck && vitest run tests/unit tests/int --no-coverage && pnpm build"
|
|
50
|
+
prepublishOnly: "pnpm typecheck && vitest run tests/unit tests/int --no-coverage && pnpm build && pnpm verify:package"
|
|
50
51
|
},
|
|
51
52
|
dependencies: {
|
|
52
53
|
"@actions/cache": "^6.0.0",
|
|
@@ -2306,6 +2307,7 @@ function listFolderCapabilityActions(root, source) {
|
|
|
2306
2307
|
if (capability.config.internal === true || capability.config.public === false) continue;
|
|
2307
2308
|
const action = capability.config.action ?? slug2;
|
|
2308
2309
|
const { executable, cliArgs } = resolveCapabilityExecution(capability);
|
|
2310
|
+
if (hasUnresolvedExplicitImplementation(capability, executable)) continue;
|
|
2309
2311
|
out.push({
|
|
2310
2312
|
action,
|
|
2311
2313
|
capability: slug2,
|
|
@@ -2319,6 +2321,14 @@ function listFolderCapabilityActions(root, source) {
|
|
|
2319
2321
|
}
|
|
2320
2322
|
return out.sort((a, b) => a.action.localeCompare(b.action));
|
|
2321
2323
|
}
|
|
2324
|
+
function hasUnresolvedExplicitImplementation(capability, executable) {
|
|
2325
|
+
const config = capability.config;
|
|
2326
|
+
const hasExplicitImplementation = Boolean(config.implementation || config.executable) || (config.implementations?.length ?? 0) > 0 || (config.executables?.length ?? 0) > 0;
|
|
2327
|
+
if (!hasExplicitImplementation) return false;
|
|
2328
|
+
if (config.workflow?.steps.length) return false;
|
|
2329
|
+
if (config.role && PUBLIC_EXECUTABLE_ROLES.has(config.role)) return false;
|
|
2330
|
+
return resolveExecutable(executable) === null;
|
|
2331
|
+
}
|
|
2322
2332
|
function listBuiltinCapabilityActions(root = getBuiltinCapabilitiesRoot()) {
|
|
2323
2333
|
if (!fs6.existsSync(root) || !fs6.statSync(root).isDirectory()) return [];
|
|
2324
2334
|
const out = [];
|
|
@@ -3490,23 +3500,77 @@ var init_agent = __esm({
|
|
|
3490
3500
|
}
|
|
3491
3501
|
});
|
|
3492
3502
|
|
|
3503
|
+
// src/agents.ts
|
|
3504
|
+
import * as fs9 from "fs";
|
|
3505
|
+
import * as path11 from "path";
|
|
3506
|
+
function stripFrontmatter(raw) {
|
|
3507
|
+
const match = /^---\n[\s\S]*?\n---\n?([\s\S]*)$/.exec(raw);
|
|
3508
|
+
return (match ? match[1] : raw).trim();
|
|
3509
|
+
}
|
|
3510
|
+
function loadAgentIdentity(cwd, slug2, agentsDir = DEFAULT_AGENT_DIR) {
|
|
3511
|
+
const trimmed = slug2.trim();
|
|
3512
|
+
if (!trimmed) throw new Error("loadAgentIdentity: empty agent slug");
|
|
3513
|
+
const agentPath = resolveAgentFile(cwd, trimmed, agentsDir);
|
|
3514
|
+
if (fs9.existsSync(agentPath)) {
|
|
3515
|
+
const body = stripFrontmatter(fs9.readFileSync(agentPath, "utf-8"));
|
|
3516
|
+
if (body) return body;
|
|
3517
|
+
const builtinForEmpty = BUILTIN_AGENTS[trimmed];
|
|
3518
|
+
if (builtinForEmpty) return builtinForEmpty;
|
|
3519
|
+
throw new Error(`loadAgentIdentity: agent '${trimmed}' agent identity body is empty (${agentPath})`);
|
|
3520
|
+
}
|
|
3521
|
+
const builtin = BUILTIN_AGENTS[trimmed];
|
|
3522
|
+
if (builtin) return builtin;
|
|
3523
|
+
throw new Error(`loadAgentIdentity: agent '${trimmed}' declared but ${agentPath} does not exist`);
|
|
3524
|
+
}
|
|
3525
|
+
function resolveAgentFile(cwd, slug2, agentsDir = DEFAULT_AGENT_DIR) {
|
|
3526
|
+
const localPath = path11.join(cwd, agentsDir, `${slug2}.md`);
|
|
3527
|
+
if (fs9.existsSync(localPath)) return localPath;
|
|
3528
|
+
const storeAgentRoot = getCompanyStoreAssetRoot("agents");
|
|
3529
|
+
if (storeAgentRoot) {
|
|
3530
|
+
const storePath = path11.join(storeAgentRoot, `${slug2}.md`);
|
|
3531
|
+
if (fs9.existsSync(storePath)) return storePath;
|
|
3532
|
+
}
|
|
3533
|
+
return localPath;
|
|
3534
|
+
}
|
|
3535
|
+
function frameAgentIdentity(slug2, agent) {
|
|
3536
|
+
return [
|
|
3537
|
+
`## Who you are \u2014 agent identity (authoritative identity)`,
|
|
3538
|
+
``,
|
|
3539
|
+
`You are operating as agent \`${slug2}\`. This identity defines *who* you are:`,
|
|
3540
|
+
`your authority, doctrine, voice, and hard limits. Honour it exactly. Where the`,
|
|
3541
|
+
`this identity's restrictions are stricter than the task, **the agent wins** \u2014 a task`,
|
|
3542
|
+
`can never grant you authority your agent withholds.`,
|
|
3543
|
+
``,
|
|
3544
|
+
agent
|
|
3545
|
+
].join("\n");
|
|
3546
|
+
}
|
|
3547
|
+
var DEFAULT_AGENT_DIR, BUILTIN_AGENTS;
|
|
3548
|
+
var init_agents = __esm({
|
|
3549
|
+
"src/agents.ts"() {
|
|
3550
|
+
"use strict";
|
|
3551
|
+
init_companyStore();
|
|
3552
|
+
DEFAULT_AGENT_DIR = ".kody/agents";
|
|
3553
|
+
BUILTIN_AGENTS = {};
|
|
3554
|
+
}
|
|
3555
|
+
});
|
|
3556
|
+
|
|
3493
3557
|
// src/task-artifacts.ts
|
|
3494
|
-
import
|
|
3495
|
-
import
|
|
3558
|
+
import fs10 from "fs";
|
|
3559
|
+
import path12 from "path";
|
|
3496
3560
|
import posixPath from "path/posix";
|
|
3497
3561
|
function prepareTaskArtifactsDir(cwd, taskId) {
|
|
3498
3562
|
const safeId = String(taskId).replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
3499
3563
|
const absDir = runtimeStatePath(cwd, "task-artifacts", safeId);
|
|
3500
3564
|
const relDir = absDir;
|
|
3501
|
-
|
|
3565
|
+
fs10.mkdirSync(absDir, { recursive: true });
|
|
3502
3566
|
return { taskId: safeId, absDir, relDir };
|
|
3503
3567
|
}
|
|
3504
3568
|
function verifyTaskArtifacts(absDir) {
|
|
3505
3569
|
const missing = [];
|
|
3506
3570
|
for (const name of TASK_ARTIFACT_FILES) {
|
|
3507
|
-
const full =
|
|
3571
|
+
const full = path12.join(absDir, name);
|
|
3508
3572
|
try {
|
|
3509
|
-
const stat =
|
|
3573
|
+
const stat = fs10.statSync(full);
|
|
3510
3574
|
if (!stat.isFile() || stat.size === 0) missing.push(name);
|
|
3511
3575
|
} catch {
|
|
3512
3576
|
missing.push(name);
|
|
@@ -3519,11 +3583,11 @@ function taskArtifactStatePath(taskId, file) {
|
|
|
3519
3583
|
}
|
|
3520
3584
|
function persistTaskArtifactsToState(config, cwd, artifacts) {
|
|
3521
3585
|
for (const file of TASK_ARTIFACT_FILES) {
|
|
3522
|
-
const full =
|
|
3523
|
-
if (!
|
|
3524
|
-
const stat =
|
|
3586
|
+
const full = path12.join(artifacts.absDir, file);
|
|
3587
|
+
if (!fs10.existsSync(full)) continue;
|
|
3588
|
+
const stat = fs10.statSync(full);
|
|
3525
3589
|
if (!stat.isFile() || stat.size === 0) continue;
|
|
3526
|
-
const content =
|
|
3590
|
+
const content = fs10.readFileSync(full, "utf-8");
|
|
3527
3591
|
upsertStateText(
|
|
3528
3592
|
config,
|
|
3529
3593
|
cwd,
|
|
@@ -3603,7 +3667,7 @@ var init_task_artifacts = __esm({
|
|
|
3603
3667
|
|
|
3604
3668
|
// src/gha.ts
|
|
3605
3669
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
3606
|
-
import * as
|
|
3670
|
+
import * as fs16 from "fs";
|
|
3607
3671
|
function getRunUrl() {
|
|
3608
3672
|
const server = process.env.GITHUB_SERVER_URL;
|
|
3609
3673
|
const repo = process.env.GITHUB_REPOSITORY;
|
|
@@ -3614,10 +3678,10 @@ function getRunUrl() {
|
|
|
3614
3678
|
function reactToTriggerComment(cwd) {
|
|
3615
3679
|
if (process.env.GITHUB_EVENT_NAME !== "issue_comment") return;
|
|
3616
3680
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
3617
|
-
if (!eventPath || !
|
|
3681
|
+
if (!eventPath || !fs16.existsSync(eventPath)) return;
|
|
3618
3682
|
let event = null;
|
|
3619
3683
|
try {
|
|
3620
|
-
event = JSON.parse(
|
|
3684
|
+
event = JSON.parse(fs16.readFileSync(eventPath, "utf-8"));
|
|
3621
3685
|
} catch {
|
|
3622
3686
|
return;
|
|
3623
3687
|
}
|
|
@@ -3668,60 +3732,6 @@ var init_gha = __esm({
|
|
|
3668
3732
|
}
|
|
3669
3733
|
});
|
|
3670
3734
|
|
|
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
3735
|
// src/capabilityReport.ts
|
|
3726
3736
|
function parseCapabilityReportsFromText(text) {
|
|
3727
3737
|
const reports = [];
|
|
@@ -7703,8 +7713,7 @@ var init_typeDefinitions = __esm({
|
|
|
7703
7713
|
stage: "publish",
|
|
7704
7714
|
evidence: "productionDeployed",
|
|
7705
7715
|
capability: "vercel-production-deploy",
|
|
7706
|
-
executable: "vercel-production-deploy"
|
|
7707
|
-
args: { goal: { fact: "goalId" } }
|
|
7716
|
+
executable: "vercel-production-deploy"
|
|
7708
7717
|
}
|
|
7709
7718
|
]
|
|
7710
7719
|
},
|
|
@@ -8720,7 +8729,8 @@ var init_advanceManagedGoal = __esm({
|
|
|
8720
8729
|
capability: decision.capability,
|
|
8721
8730
|
cliArgs: decision.cliArgs,
|
|
8722
8731
|
...decision.executable ? { executable: decision.executable } : {},
|
|
8723
|
-
...decision.saveReport === true ? { saveReport: true } : {}
|
|
8732
|
+
...decision.saveReport === true ? { saveReport: true } : {},
|
|
8733
|
+
resultTarget: { type: "goal", id: goal.id, evidence: decision.evidence }
|
|
8724
8734
|
};
|
|
8725
8735
|
ctx.output.reason = `dispatch ${decision.capability} for ${decision.evidence}`;
|
|
8726
8736
|
};
|
|
@@ -9697,6 +9707,18 @@ function collectResults(raw, agentResult) {
|
|
|
9697
9707
|
if (agentResult?.finalText) out.push(...parseCapabilityResultsFromText(agentResult.finalText));
|
|
9698
9708
|
return out;
|
|
9699
9709
|
}
|
|
9710
|
+
function parseResultTarget(raw) {
|
|
9711
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
9712
|
+
const target = raw;
|
|
9713
|
+
if (target.type !== "goal") return null;
|
|
9714
|
+
if (typeof target.id !== "string" || target.id.trim().length === 0) return null;
|
|
9715
|
+
const evidence = typeof target.evidence === "string" && target.evidence.trim().length > 0 ? target.evidence.trim() : void 0;
|
|
9716
|
+
return {
|
|
9717
|
+
type: "goal",
|
|
9718
|
+
id: target.id.trim(),
|
|
9719
|
+
...evidence ? { evidence } : {}
|
|
9720
|
+
};
|
|
9721
|
+
}
|
|
9700
9722
|
function collectGoalCapabilityEvidence(reports, results, fallbackGoalId, explicitEvidence) {
|
|
9701
9723
|
const items = [];
|
|
9702
9724
|
for (const report of reports) {
|
|
@@ -9790,8 +9812,9 @@ var init_applyCapabilityReports = __esm({
|
|
|
9790
9812
|
applyCapabilityReports = async (ctx, _profile, agentResult) => {
|
|
9791
9813
|
const reports = collectReports(ctx.data.capabilityReports, agentResult);
|
|
9792
9814
|
const results = collectResults(ctx.data.capabilityResults ?? ctx.data.dutyResults, agentResult);
|
|
9793
|
-
const
|
|
9794
|
-
const
|
|
9815
|
+
const resultTarget = parseResultTarget(ctx.data.capabilityResultTarget);
|
|
9816
|
+
const resultGoalId = resultTarget?.id ?? (typeof ctx.args.goal === "string" && ctx.args.goal.length > 0 ? ctx.args.goal : null);
|
|
9817
|
+
const explicitEvidence = resultTarget?.evidence ?? (typeof ctx.args.evidence === "string" && ctx.args.evidence.length > 0 ? ctx.args.evidence : void 0);
|
|
9795
9818
|
const evidenceItems = collectGoalCapabilityEvidence(reports, results, resultGoalId, explicitEvidence);
|
|
9796
9819
|
if (evidenceItems.length === 0) return;
|
|
9797
9820
|
const evidenceByGoal = groupGoalEvidence(evidenceItems);
|
|
@@ -18402,7 +18425,8 @@ function handoffToJob(handoff) {
|
|
|
18402
18425
|
executable: handoff.executable,
|
|
18403
18426
|
cliArgs: handoff.cliArgs,
|
|
18404
18427
|
flavor: "instant",
|
|
18405
|
-
saveReport: handoff.saveReport === true
|
|
18428
|
+
saveReport: handoff.saveReport === true,
|
|
18429
|
+
resultTarget: handoff.resultTarget
|
|
18406
18430
|
};
|
|
18407
18431
|
}
|
|
18408
18432
|
function clearStampedLifecycleLabels(profile, ctx) {
|
|
@@ -18817,7 +18841,20 @@ function validateJob(input) {
|
|
|
18817
18841
|
cliArgs: j.cliArgs ?? {},
|
|
18818
18842
|
flavor: j.flavor,
|
|
18819
18843
|
force: j.force === true,
|
|
18820
|
-
saveReport: j.saveReport === true
|
|
18844
|
+
saveReport: j.saveReport === true,
|
|
18845
|
+
resultTarget: parseCapabilityResultTarget(j.resultTarget)
|
|
18846
|
+
};
|
|
18847
|
+
}
|
|
18848
|
+
function parseCapabilityResultTarget(raw) {
|
|
18849
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
18850
|
+
const target = raw;
|
|
18851
|
+
if (target.type !== "goal") return void 0;
|
|
18852
|
+
if (typeof target.id !== "string" || target.id.trim().length === 0) return void 0;
|
|
18853
|
+
const evidence = typeof target.evidence === "string" && target.evidence.trim().length > 0 ? target.evidence.trim() : void 0;
|
|
18854
|
+
return {
|
|
18855
|
+
type: "goal",
|
|
18856
|
+
id: target.id.trim(),
|
|
18857
|
+
...evidence ? { evidence } : {}
|
|
18821
18858
|
};
|
|
18822
18859
|
}
|
|
18823
18860
|
async function runJob(job, base) {
|
|
@@ -18877,6 +18914,7 @@ async function runCapabilityImplementationStep(valid, profileName, capabilityIde
|
|
|
18877
18914
|
preloadedData.jobExecutable = profileName;
|
|
18878
18915
|
if (valid.schedule !== void 0 && valid.schedule.length > 0) preloadedData.jobSchedule = valid.schedule;
|
|
18879
18916
|
if (valid.saveReport === true) preloadedData.jobSaveReport = true;
|
|
18917
|
+
if (valid.resultTarget) preloadedData.capabilityResultTarget = valid.resultTarget;
|
|
18880
18918
|
if (capabilityContext) {
|
|
18881
18919
|
preloadedData.capabilitySlug = capabilityContext.slug;
|
|
18882
18920
|
preloadedData.capabilityTitle = capabilityContext.title;
|
|
@@ -19241,16 +19279,17 @@ import * as path47 from "path";
|
|
|
19241
19279
|
|
|
19242
19280
|
// src/chat/loop.ts
|
|
19243
19281
|
init_agent();
|
|
19282
|
+
init_agents();
|
|
19244
19283
|
init_config();
|
|
19245
19284
|
init_registry();
|
|
19246
19285
|
init_task_artifacts();
|
|
19247
|
-
import * as
|
|
19248
|
-
import * as
|
|
19286
|
+
import * as fs14 from "fs";
|
|
19287
|
+
import * as path16 from "path";
|
|
19249
19288
|
|
|
19250
19289
|
// src/chat/attachments.ts
|
|
19251
19290
|
init_runtimePaths();
|
|
19252
|
-
import * as
|
|
19253
|
-
import * as
|
|
19291
|
+
import * as fs11 from "fs";
|
|
19292
|
+
import * as path13 from "path";
|
|
19254
19293
|
var INLINE_ATTACHMENT_RE = /(?:\[(?:Image|File): ([^\]]*)\]\n)?data:([\w.+-]+\/[\w.+-]+);base64,([A-Za-z0-9+/=]+)/g;
|
|
19255
19294
|
var EXT_BY_MIME = {
|
|
19256
19295
|
"image/png": "png",
|
|
@@ -19283,11 +19322,11 @@ function prepareAttachments(turns, cwd, sessionId) {
|
|
|
19283
19322
|
if (!isImage) return `[File: ${name}]`;
|
|
19284
19323
|
try {
|
|
19285
19324
|
if (!dirEnsured) {
|
|
19286
|
-
|
|
19325
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
19287
19326
|
dirEnsured = true;
|
|
19288
19327
|
}
|
|
19289
|
-
const filePath =
|
|
19290
|
-
|
|
19328
|
+
const filePath = path13.join(dir, `${imageCounter}.${extFor(mime)}`);
|
|
19329
|
+
fs11.writeFileSync(filePath, Buffer.from(data, "base64"));
|
|
19291
19330
|
imageCounter += 1;
|
|
19292
19331
|
imagePaths.push(filePath);
|
|
19293
19332
|
return `[Image "${name}" is attached \u2014 saved to ${filePath}. Use the Read tool on that exact path to view it.]`;
|
|
@@ -19303,11 +19342,11 @@ function prepareAttachments(turns, cwd, sessionId) {
|
|
|
19303
19342
|
}
|
|
19304
19343
|
|
|
19305
19344
|
// src/chat/events.ts
|
|
19306
|
-
import * as
|
|
19307
|
-
import * as
|
|
19345
|
+
import * as fs12 from "fs";
|
|
19346
|
+
import * as path14 from "path";
|
|
19308
19347
|
import posixPath2 from "path/posix";
|
|
19309
19348
|
function eventsFilePath(cwd, sessionId) {
|
|
19310
|
-
return
|
|
19349
|
+
return path14.join(cwd, ".kody", "events", `${sessionId}.jsonl`);
|
|
19311
19350
|
}
|
|
19312
19351
|
function eventsStatePath(sessionId) {
|
|
19313
19352
|
return posixPath2.join("events", `${sessionId}.jsonl`);
|
|
@@ -19318,8 +19357,8 @@ var FileSink = class {
|
|
|
19318
19357
|
}
|
|
19319
19358
|
file;
|
|
19320
19359
|
async emit(event) {
|
|
19321
|
-
|
|
19322
|
-
|
|
19360
|
+
fs12.mkdirSync(path14.dirname(this.file), { recursive: true });
|
|
19361
|
+
fs12.appendFileSync(this.file, `${JSON.stringify(event)}
|
|
19323
19362
|
`);
|
|
19324
19363
|
}
|
|
19325
19364
|
};
|
|
@@ -19373,18 +19412,18 @@ function makeRunId(sessionId, suffix) {
|
|
|
19373
19412
|
}
|
|
19374
19413
|
|
|
19375
19414
|
// src/chat/session.ts
|
|
19376
|
-
import * as
|
|
19377
|
-
import * as
|
|
19415
|
+
import * as fs13 from "fs";
|
|
19416
|
+
import * as path15 from "path";
|
|
19378
19417
|
import posixPath3 from "path/posix";
|
|
19379
19418
|
function sessionFilePath(cwd, sessionId) {
|
|
19380
|
-
return
|
|
19419
|
+
return path15.join(cwd, ".kody", "sessions", `${sessionId}.jsonl`);
|
|
19381
19420
|
}
|
|
19382
19421
|
function sessionStatePath(sessionId) {
|
|
19383
19422
|
return posixPath3.join("sessions", `${sessionId}.jsonl`);
|
|
19384
19423
|
}
|
|
19385
19424
|
function readMeta(file) {
|
|
19386
|
-
if (!
|
|
19387
|
-
const raw =
|
|
19425
|
+
if (!fs13.existsSync(file)) return null;
|
|
19426
|
+
const raw = fs13.readFileSync(file, "utf-8");
|
|
19388
19427
|
const firstLine2 = raw.split("\n", 1)[0]?.trim();
|
|
19389
19428
|
if (!firstLine2) return null;
|
|
19390
19429
|
try {
|
|
@@ -19397,8 +19436,8 @@ function readMeta(file) {
|
|
|
19397
19436
|
}
|
|
19398
19437
|
}
|
|
19399
19438
|
function readSession(file) {
|
|
19400
|
-
if (!
|
|
19401
|
-
const raw =
|
|
19439
|
+
if (!fs13.existsSync(file)) return [];
|
|
19440
|
+
const raw = fs13.readFileSync(file, "utf-8").trim();
|
|
19402
19441
|
if (!raw) return [];
|
|
19403
19442
|
const turns = [];
|
|
19404
19443
|
for (const line of raw.split("\n")) {
|
|
@@ -19414,14 +19453,14 @@ function readSession(file) {
|
|
|
19414
19453
|
return turns;
|
|
19415
19454
|
}
|
|
19416
19455
|
function appendTurn(file, turn) {
|
|
19417
|
-
|
|
19456
|
+
fs13.mkdirSync(path15.dirname(file), { recursive: true });
|
|
19418
19457
|
const line = JSON.stringify({
|
|
19419
19458
|
role: turn.role,
|
|
19420
19459
|
content: turn.content,
|
|
19421
19460
|
timestamp: turn.timestamp,
|
|
19422
19461
|
toolCalls: turn.toolCalls ?? []
|
|
19423
19462
|
});
|
|
19424
|
-
|
|
19463
|
+
fs13.appendFileSync(file, `${line}
|
|
19425
19464
|
`);
|
|
19426
19465
|
}
|
|
19427
19466
|
function seedInitialMessage(file, message) {
|
|
@@ -19556,7 +19595,7 @@ function buildExecutableCatalog() {
|
|
|
19556
19595
|
const entries = [];
|
|
19557
19596
|
for (const { name, profilePath } of discovered) {
|
|
19558
19597
|
try {
|
|
19559
|
-
const raw = JSON.parse(
|
|
19598
|
+
const raw = JSON.parse(fs14.readFileSync(profilePath, "utf-8"));
|
|
19560
19599
|
const describe = typeof raw.describe === "string" ? raw.describe : "";
|
|
19561
19600
|
const firstSentence = describe.split(/(?<=[.!?])\s+/, 1)[0] ?? "";
|
|
19562
19601
|
entries.push({ name, describe: firstSentence.trim() });
|
|
@@ -19593,6 +19632,7 @@ async function runChatTurn(opts) {
|
|
|
19593
19632
|
}
|
|
19594
19633
|
const { turns: promptTurns, imagePaths } = prepareAttachments(turns, opts.cwd, opts.sessionId);
|
|
19595
19634
|
const basePrompt = opts.systemPrompt ?? (opts.model.protocol === "openai" ? OPENAI_CHAT_SYSTEM_PROMPT : CHAT_SYSTEM_PROMPT);
|
|
19635
|
+
const agentIdentityBlock = readAgentIdentityBlock(opts.cwd, opts.agentIdentity);
|
|
19596
19636
|
const catalog = buildExecutableCatalog();
|
|
19597
19637
|
const taskArtifactsPaths = prepareTaskArtifactsDir(opts.cwd, opts.sessionId);
|
|
19598
19638
|
const artifactAddendum = taskArtifactsPromptAddendum({
|
|
@@ -19603,7 +19643,8 @@ async function runChatTurn(opts) {
|
|
|
19603
19643
|
const contextBlock = readContextBlock(opts.cwd);
|
|
19604
19644
|
const memoryBlock = readMemoryIndexBlock(opts.cwd);
|
|
19605
19645
|
const instructionsBlock = readInstructionsBlock(opts.cwd);
|
|
19606
|
-
const
|
|
19646
|
+
const fetchRepoEnabled = Boolean(opts.enableFetchRepoTool && opts.reposRoot);
|
|
19647
|
+
const crossRepoBlock = fetchRepoEnabled ? CROSS_REPO_PROMPT : null;
|
|
19607
19648
|
const dashboardCmsEnabled = Boolean(opts.cmsDashboardUrl && opts.cmsRepoSlug && opts.cmsToken);
|
|
19608
19649
|
const dashboardCmsBlock = dashboardCmsEnabled ? DASHBOARD_CMS_PROMPT : null;
|
|
19609
19650
|
const imageBlock = imagePaths.length > 0 ? [
|
|
@@ -19616,6 +19657,7 @@ async function runChatTurn(opts) {
|
|
|
19616
19657
|
].join("\n") : null;
|
|
19617
19658
|
const systemPrompt = [
|
|
19618
19659
|
basePrompt,
|
|
19660
|
+
agentIdentityBlock,
|
|
19619
19661
|
contextBlock,
|
|
19620
19662
|
memoryBlock,
|
|
19621
19663
|
instructionsBlock,
|
|
@@ -19644,14 +19686,14 @@ async function runChatTurn(opts) {
|
|
|
19644
19686
|
quiet: opts.quiet,
|
|
19645
19687
|
additionalDirectories: [
|
|
19646
19688
|
taskArtifactsPaths.absDir,
|
|
19647
|
-
...Array.from(new Set(imagePaths.map((p2) =>
|
|
19689
|
+
...Array.from(new Set(imagePaths.map((p2) => path16.dirname(p2))))
|
|
19648
19690
|
],
|
|
19649
19691
|
systemPromptAppend: systemPrompt,
|
|
19650
19692
|
...opts.reasoningEffort ? { reasoningEffort: opts.reasoningEffort } : {},
|
|
19651
|
-
//
|
|
19652
|
-
//
|
|
19653
|
-
//
|
|
19654
|
-
...
|
|
19693
|
+
// Cross-repo work is opt-in. Repo Brain's default path remains focused
|
|
19694
|
+
// on the selected repo even though the server stores clones under
|
|
19695
|
+
// reposRoot.
|
|
19696
|
+
...fetchRepoEnabled ? {
|
|
19655
19697
|
enableFetchRepoTool: true,
|
|
19656
19698
|
reposRoot: opts.reposRoot,
|
|
19657
19699
|
repoToken: opts.repoToken
|
|
@@ -19736,6 +19778,12 @@ async function runChatTurn(opts) {
|
|
|
19736
19778
|
}
|
|
19737
19779
|
return { exitCode: 0, reply };
|
|
19738
19780
|
}
|
|
19781
|
+
function readAgentIdentityBlock(cwd, agentIdentity) {
|
|
19782
|
+
const slug2 = agentIdentity?.slug?.trim();
|
|
19783
|
+
if (!slug2) return null;
|
|
19784
|
+
const body = agentIdentity?.body?.trim() || loadAgentIdentity(cwd, slug2);
|
|
19785
|
+
return frameAgentIdentity(slug2, body);
|
|
19786
|
+
}
|
|
19739
19787
|
async function runOpenAIChatTurn(args) {
|
|
19740
19788
|
const { opts, turns, systemPrompt, sessionFile } = args;
|
|
19741
19789
|
const doFetch = opts.fetchImpl ?? fetch;
|
|
@@ -19821,10 +19869,10 @@ async function emit(sink, type, sessionId, suffix, payload) {
|
|
|
19821
19869
|
var MEMORY_INDEX_REL = ".kody/memory/INDEX.md";
|
|
19822
19870
|
var MAX_INDEX_BYTES = 8e3;
|
|
19823
19871
|
function readMemoryIndexBlock(cwd) {
|
|
19824
|
-
const indexPath =
|
|
19872
|
+
const indexPath = path16.join(cwd, MEMORY_INDEX_REL);
|
|
19825
19873
|
let raw;
|
|
19826
19874
|
try {
|
|
19827
|
-
raw =
|
|
19875
|
+
raw = fs14.readFileSync(indexPath, "utf-8");
|
|
19828
19876
|
} catch {
|
|
19829
19877
|
return "";
|
|
19830
19878
|
}
|
|
@@ -19844,17 +19892,17 @@ _\u2026 (memory index truncated; use recall_search to read more)_` : trimmed;
|
|
|
19844
19892
|
var CONTEXT_DIR_REL = ".kody/context";
|
|
19845
19893
|
var MAX_CONTEXT_BYTES = 12e3;
|
|
19846
19894
|
function readContextBlock(cwd) {
|
|
19847
|
-
const dir =
|
|
19895
|
+
const dir = path16.join(cwd, CONTEXT_DIR_REL);
|
|
19848
19896
|
let files;
|
|
19849
19897
|
try {
|
|
19850
|
-
files =
|
|
19898
|
+
files = fs14.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
19851
19899
|
} catch {
|
|
19852
19900
|
return "";
|
|
19853
19901
|
}
|
|
19854
19902
|
const sections = [];
|
|
19855
19903
|
for (const file of files) {
|
|
19856
19904
|
try {
|
|
19857
|
-
const content =
|
|
19905
|
+
const content = fs14.readFileSync(path16.join(dir, file), "utf-8").trim();
|
|
19858
19906
|
if (content) sections.push(`### ${file.replace(/\.md$/, "")}
|
|
19859
19907
|
|
|
19860
19908
|
${content}`);
|
|
@@ -19877,10 +19925,10 @@ _\u2026 (context truncated; use the state repo context files for the full text)_
|
|
|
19877
19925
|
var INSTRUCTIONS_REL = ".kody/instructions.md";
|
|
19878
19926
|
var MAX_INSTRUCTIONS_BYTES = 8e3;
|
|
19879
19927
|
function readInstructionsBlock(cwd) {
|
|
19880
|
-
const instructionsPath =
|
|
19928
|
+
const instructionsPath = path16.join(cwd, INSTRUCTIONS_REL);
|
|
19881
19929
|
let raw;
|
|
19882
19930
|
try {
|
|
19883
|
-
raw =
|
|
19931
|
+
raw = fs14.readFileSync(instructionsPath, "utf-8");
|
|
19884
19932
|
} catch {
|
|
19885
19933
|
return "";
|
|
19886
19934
|
}
|
|
@@ -19981,7 +20029,7 @@ init_config();
|
|
|
19981
20029
|
|
|
19982
20030
|
// src/dispatch.ts
|
|
19983
20031
|
init_config();
|
|
19984
|
-
import * as
|
|
20032
|
+
import * as fs15 from "fs";
|
|
19985
20033
|
|
|
19986
20034
|
// src/cron-match.ts
|
|
19987
20035
|
var FIELD_BOUNDS = [
|
|
@@ -20083,10 +20131,10 @@ function autoDispatch(opts) {
|
|
|
20083
20131
|
}
|
|
20084
20132
|
const eventName = process.env.GITHUB_EVENT_NAME;
|
|
20085
20133
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
20086
|
-
if (!eventName || !eventPath || !
|
|
20134
|
+
if (!eventName || !eventPath || !fs15.existsSync(eventPath)) return null;
|
|
20087
20135
|
let event = {};
|
|
20088
20136
|
try {
|
|
20089
|
-
event = JSON.parse(
|
|
20137
|
+
event = JSON.parse(fs15.readFileSync(eventPath, "utf-8"));
|
|
20090
20138
|
} catch {
|
|
20091
20139
|
return null;
|
|
20092
20140
|
}
|
|
@@ -20197,7 +20245,7 @@ function autoDispatchTyped(opts) {
|
|
|
20197
20245
|
if (legacy) return { kind: "route", ...legacy };
|
|
20198
20246
|
const eventName = process.env.GITHUB_EVENT_NAME;
|
|
20199
20247
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
20200
|
-
if (!eventName || !eventPath || !
|
|
20248
|
+
if (!eventName || !eventPath || !fs15.existsSync(eventPath)) {
|
|
20201
20249
|
return { kind: "silent", reason: "no GHA event context" };
|
|
20202
20250
|
}
|
|
20203
20251
|
if (eventName !== "issue_comment") {
|
|
@@ -20205,7 +20253,7 @@ function autoDispatchTyped(opts) {
|
|
|
20205
20253
|
}
|
|
20206
20254
|
let event = {};
|
|
20207
20255
|
try {
|
|
20208
|
-
event = JSON.parse(
|
|
20256
|
+
event = JSON.parse(fs15.readFileSync(eventPath, "utf-8"));
|
|
20209
20257
|
} catch {
|
|
20210
20258
|
return { kind: "silent", reason: "GHA event payload unreadable" };
|
|
20211
20259
|
}
|
|
@@ -20249,7 +20297,7 @@ function dispatchScheduledWatches(opts) {
|
|
|
20249
20297
|
for (const exe of listExecutables()) {
|
|
20250
20298
|
let raw;
|
|
20251
20299
|
try {
|
|
20252
|
-
raw =
|
|
20300
|
+
raw = fs15.readFileSync(exe.profilePath, "utf-8");
|
|
20253
20301
|
} catch {
|
|
20254
20302
|
continue;
|
|
20255
20303
|
}
|
|
@@ -21332,6 +21380,19 @@ function strField(body, key) {
|
|
|
21332
21380
|
}
|
|
21333
21381
|
return void 0;
|
|
21334
21382
|
}
|
|
21383
|
+
function boolField(body, key) {
|
|
21384
|
+
return typeof body === "object" && body !== null && body[key] === true;
|
|
21385
|
+
}
|
|
21386
|
+
function agentIdentityField(body) {
|
|
21387
|
+
if (typeof body !== "object" || body === null || !("agentIdentity" in body)) return void 0;
|
|
21388
|
+
const value = body.agentIdentity;
|
|
21389
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
21390
|
+
const record2 = value;
|
|
21391
|
+
const slug2 = typeof record2.slug === "string" ? record2.slug.trim() : "";
|
|
21392
|
+
const bodyText = typeof record2.body === "string" ? record2.body.trim() : "";
|
|
21393
|
+
if (!slug2 || !bodyText) return void 0;
|
|
21394
|
+
return { slug: slug2, body: bodyText };
|
|
21395
|
+
}
|
|
21335
21396
|
function sendJson(res, status, body) {
|
|
21336
21397
|
res.writeHead(status, { "content-type": "application/json" });
|
|
21337
21398
|
res.end(JSON.stringify(body));
|
|
@@ -21466,6 +21527,8 @@ async function handleChatTurn(req, res, chatId, opts) {
|
|
|
21466
21527
|
const dashboardUrl = strField(body, "dashboardUrl");
|
|
21467
21528
|
const storeRepoUrl = strField(body, "storeRepoUrl");
|
|
21468
21529
|
const storeRef = strField(body, "storeRef");
|
|
21530
|
+
const allowCrossRepo = boolField(body, "allowCrossRepo");
|
|
21531
|
+
const agentIdentity = agentIdentityField(body);
|
|
21469
21532
|
let agentCwd;
|
|
21470
21533
|
try {
|
|
21471
21534
|
agentCwd = await ensureRepoCwd({
|
|
@@ -21540,9 +21603,12 @@ async function handleChatTurn(req, res, chatId, opts) {
|
|
|
21540
21603
|
model: opts.model,
|
|
21541
21604
|
litellmUrl: opts.litellmUrl,
|
|
21542
21605
|
sink,
|
|
21543
|
-
// Let the agent clone + work on OTHER repos via the fetch_repo tool.
|
|
21544
21606
|
reposRoot: opts.reposRoot,
|
|
21607
|
+
// Repo Brain is selected-repo focused by default. Higher-level
|
|
21608
|
+
// coordinator flows can opt into fetch_repo explicitly.
|
|
21609
|
+
...allowCrossRepo ? { enableFetchRepoTool: true } : {},
|
|
21545
21610
|
repoToken,
|
|
21611
|
+
...agentIdentity ? { agentIdentity } : {},
|
|
21546
21612
|
...dashboardUrl && repo && stateToken ? {
|
|
21547
21613
|
cmsDashboardUrl: dashboardUrl,
|
|
21548
21614
|
cmsRepoSlug: repo,
|
|
@@ -21812,7 +21878,9 @@ async function proxyToBrainServe(args) {
|
|
|
21812
21878
|
...args.body.repoToken ? { repoToken: args.body.repoToken } : {},
|
|
21813
21879
|
...args.body.dashboardUrl ? { dashboardUrl: args.body.dashboardUrl } : {},
|
|
21814
21880
|
...args.body.storeRepoUrl ? { storeRepoUrl: args.body.storeRepoUrl } : {},
|
|
21815
|
-
...args.body.storeRef ? { storeRef: args.body.storeRef } : {}
|
|
21881
|
+
...args.body.storeRef ? { storeRef: args.body.storeRef } : {},
|
|
21882
|
+
...args.body.allowCrossRepo === true ? { allowCrossRepo: true } : {},
|
|
21883
|
+
...args.body.agentIdentity ? { agentIdentity: args.body.agentIdentity } : {}
|
|
21816
21884
|
})
|
|
21817
21885
|
});
|
|
21818
21886
|
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.294",
|
|
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",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
"lint": "biome check",
|
|
55
55
|
"lint:fix": "biome check --write",
|
|
56
56
|
"format": "biome format --write",
|
|
57
|
+
"verify:package": "node scripts/verify-package-tarball.cjs",
|
|
57
58
|
"brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner"
|
|
58
59
|
}
|
|
59
60
|
}
|