@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 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.292",
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 fs9 from "fs";
3495
- import path11 from "path";
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
- fs9.mkdirSync(absDir, { recursive: true });
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 = path11.join(absDir, name);
3561
+ const full = path12.join(absDir, name);
3508
3562
  try {
3509
- const stat = fs9.statSync(full);
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 = path11.join(artifacts.absDir, file);
3523
- if (!fs9.existsSync(full)) continue;
3524
- const stat = fs9.statSync(full);
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 = fs9.readFileSync(full, "utf-8");
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 fs15 from "fs";
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 || !fs15.existsSync(eventPath)) return;
3671
+ if (!eventPath || !fs16.existsSync(eventPath)) return;
3618
3672
  let event = null;
3619
3673
  try {
3620
- event = JSON.parse(fs15.readFileSync(eventPath, "utf-8"));
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 resultGoalId = typeof ctx.args.goal === "string" && ctx.args.goal.length > 0 ? ctx.args.goal : null;
9794
- const explicitEvidence = typeof ctx.args.evidence === "string" && ctx.args.evidence.length > 0 ? ctx.args.evidence : void 0;
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 fs13 from "fs";
19248
- import * as path15 from "path";
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 fs10 from "fs";
19253
- import * as path12 from "path";
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
- fs10.mkdirSync(dir, { recursive: true });
19315
+ fs11.mkdirSync(dir, { recursive: true });
19287
19316
  dirEnsured = true;
19288
19317
  }
19289
- const filePath = path12.join(dir, `${imageCounter}.${extFor(mime)}`);
19290
- fs10.writeFileSync(filePath, Buffer.from(data, "base64"));
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 fs11 from "fs";
19307
- import * as path13 from "path";
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 path13.join(cwd, ".kody", "events", `${sessionId}.jsonl`);
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
- fs11.mkdirSync(path13.dirname(this.file), { recursive: true });
19322
- fs11.appendFileSync(this.file, `${JSON.stringify(event)}
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 fs12 from "fs";
19377
- import * as path14 from "path";
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 path14.join(cwd, ".kody", "sessions", `${sessionId}.jsonl`);
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 (!fs12.existsSync(file)) return null;
19387
- const raw = fs12.readFileSync(file, "utf-8");
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 (!fs12.existsSync(file)) return [];
19401
- const raw = fs12.readFileSync(file, "utf-8").trim();
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
- fs12.mkdirSync(path14.dirname(file), { recursive: true });
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
- fs12.appendFileSync(file, `${line}
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(fs13.readFileSync(profilePath, "utf-8"));
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 crossRepoBlock = opts.reposRoot ? CROSS_REPO_PROMPT : null;
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) => path15.dirname(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
- // Let the agent clone + work on OTHER repos mid-conversation (a
19652
- // repo-less Brain serves many). Enabled whenever we know where repos
19653
- // live; grants read access to that root via additionalDirectories.
19654
- ...opts.reposRoot ? {
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 = path15.join(cwd, MEMORY_INDEX_REL);
19862
+ const indexPath = path16.join(cwd, MEMORY_INDEX_REL);
19825
19863
  let raw;
19826
19864
  try {
19827
- raw = fs13.readFileSync(indexPath, "utf-8");
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 = path15.join(cwd, CONTEXT_DIR_REL);
19885
+ const dir = path16.join(cwd, CONTEXT_DIR_REL);
19848
19886
  let files;
19849
19887
  try {
19850
- files = fs13.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
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 = fs13.readFileSync(path15.join(dir, file), "utf-8").trim();
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 = path15.join(cwd, INSTRUCTIONS_REL);
19918
+ const instructionsPath = path16.join(cwd, INSTRUCTIONS_REL);
19881
19919
  let raw;
19882
19920
  try {
19883
- raw = fs13.readFileSync(instructionsPath, "utf-8");
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 fs14 from "fs";
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 || !fs14.existsSync(eventPath)) return null;
20124
+ if (!eventName || !eventPath || !fs15.existsSync(eventPath)) return null;
20087
20125
  let event = {};
20088
20126
  try {
20089
- event = JSON.parse(fs14.readFileSync(eventPath, "utf-8"));
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 || !fs14.existsSync(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(fs14.readFileSync(eventPath, "utf-8"));
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 = fs14.readFileSync(exe.profilePath, "utf-8");
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.292",
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",