@kody-ade/kody-engine 0.4.288 → 0.4.290

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/README.md CHANGED
@@ -78,10 +78,6 @@ See [SECURITY.md](SECURITY.md) to report a vulnerability.
78
78
  │ src/executor.ts — runs capability implementations │
79
79
  │ .kody/capabilities/<slug>/ │
80
80
  │ profile.json · capability.md · optional skills/scripts │
81
- │ .kody/capabilities/<slug>/ │
82
- │ legacy fallback: profile.json · capability.md │
83
- │ .kody/executables/<name>/ │
84
- │ legacy fallback: profile.json · prompt.md · *.sh │
85
81
  │ src/scripts/*.ts — cross-cutting catalog │
86
82
  └─────────────────────────────────────────────┘
87
83
  ```
@@ -91,10 +87,10 @@ Every top-level command is an auto-discovered capability action. The router has
91
87
  after `@kody` through `config.aliases`, then falls back to the legacy-named
92
88
  `config.defaultExecutable` / `config.defaultPrExecutable` fields as default
93
89
  capability actions. Drop a new `.kody/capabilities/<slug>/` directory with
94
- `profile.json` + `capability.md`; legacy `.kody/capabilities/` and
95
- `.kody/executables/` roots still load while repos migrate.
90
+ `profile.json` + `capability.md`. Project/store `.kody/executables/` folders
91
+ are obsolete and are not resolver sources.
96
92
 
97
- Legacy Executable directories are private implementation units and contain
93
+ Capability implementation profiles are private implementation units and contain
98
94
  **only** three kinds of files: `profile.json` (declaration), `prompt.md` (agent
99
95
  instructions), and `.sh` scripts (mechanical side-effect work). Cross-cutting
100
96
  TypeScript lives in [src/scripts/](src/scripts/); it can't import from
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.288",
18
+ version: "0.4.290",
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",
@@ -1266,7 +1266,7 @@ var init_events = __esm({
1266
1266
  // src/verify.ts
1267
1267
  import { spawn } from "child_process";
1268
1268
  function runCommand(command, cwd) {
1269
- return new Promise((resolve9) => {
1269
+ return new Promise((resolve10) => {
1270
1270
  const start = Date.now();
1271
1271
  const child = spawn(command, {
1272
1272
  cwd,
@@ -1295,11 +1295,11 @@ function runCommand(command, cwd) {
1295
1295
  child.on("exit", (code) => {
1296
1296
  clearTimeout(timer);
1297
1297
  const tail = Buffer.concat(buffers).toString("utf-8").slice(-TAIL_CHARS);
1298
- resolve9({ exitCode: code ?? -1, durationMs: Date.now() - start, tail });
1298
+ resolve10({ exitCode: code ?? -1, durationMs: Date.now() - start, tail });
1299
1299
  });
1300
1300
  child.on("error", (err) => {
1301
1301
  clearTimeout(timer);
1302
- resolve9({ exitCode: -1, durationMs: Date.now() - start, tail: err.message });
1302
+ resolve10({ exitCode: -1, durationMs: Date.now() - start, tail: err.message });
1303
1303
  });
1304
1304
  });
1305
1305
  }
@@ -1907,6 +1907,8 @@ function parseCapabilityConfig(raw) {
1907
1907
  executable: stringField(raw.executable),
1908
1908
  tickScript: stringField(raw.tickScript),
1909
1909
  disabled: typeof raw.disabled === "boolean" ? raw.disabled : void 0,
1910
+ internal: typeof raw.internal === "boolean" ? raw.internal : void 0,
1911
+ public: typeof raw.public === "boolean" ? raw.public : void 0,
1910
1912
  agent: stringField(raw.agent),
1911
1913
  mentions: stringList(raw.mentions).map((m) => m.replace(/^@/, "")),
1912
1914
  tools,
@@ -2022,7 +2024,6 @@ function getCompanyStoreAssetRoot(kind) {
2022
2024
  if (!root) return null;
2023
2025
  const folderByKind = {
2024
2026
  capabilities: "capabilities",
2025
- executables: "executables",
2026
2027
  goals: "goals",
2027
2028
  agents: "agents",
2028
2029
  workflows: "workflows"
@@ -2128,15 +2129,9 @@ function getExecutablesRoot() {
2128
2129
  }
2129
2130
  return candidates[0];
2130
2131
  }
2131
- function getProjectExecutablesRoot() {
2132
- return path8.join(process.cwd(), ".kody", "executables");
2133
- }
2134
2132
  function getProjectCapabilitiesRoot() {
2135
2133
  return path8.join(process.cwd(), ".kody", "capabilities");
2136
2134
  }
2137
- function getCompanyStoreExecutablesRoot() {
2138
- return getCompanyStoreAssetRoot("executables");
2139
- }
2140
2135
  function getCompanyStoreCapabilitiesRoot() {
2141
2136
  return getCompanyStoreAssetRoot("capabilities");
2142
2137
  }
@@ -2157,14 +2152,10 @@ function getBuiltinCapabilitiesRoot() {
2157
2152
  }
2158
2153
  function getExecutableRoots() {
2159
2154
  const projectCapabilitiesRoot = getProjectCapabilitiesRoot();
2160
- const projectExecutablesRoot = getProjectExecutablesRoot();
2161
2155
  const storeCapabilitiesRoot = getCompanyStoreCapabilitiesRoot();
2162
- const storeExecutablesRoot = getCompanyStoreExecutablesRoot();
2163
2156
  return [
2164
2157
  projectCapabilitiesRoot,
2165
- projectExecutablesRoot,
2166
2158
  ...storeCapabilitiesRoot ? [storeCapabilitiesRoot] : [],
2167
- ...storeExecutablesRoot ? [storeExecutablesRoot] : [],
2168
2159
  getExecutablesRoot()
2169
2160
  ];
2170
2161
  }
@@ -2216,21 +2207,12 @@ function listCapabilityActions(projectCapabilitiesRoot = getProjectCapabilitiesR
2216
2207
  seen.add(action.action);
2217
2208
  out.push(action);
2218
2209
  };
2219
- const storeCapabilitiesRoot = getCompanyStoreCapabilitiesRoot();
2220
- const projectExecutableRoots = [getProjectExecutablesRoot()];
2221
- const storeExecutableRoot = getCompanyStoreExecutablesRoot();
2222
- const storeExecutableRoots = storeExecutableRoot ? [storeExecutableRoot] : [];
2223
2210
  for (const action of listFolderCapabilityActions(projectCapabilitiesRoot, "project-folder"))
2224
2211
  add(action);
2225
- for (const root of projectExecutableRoots) {
2226
- for (const action of listExecutableCapabilityActions(root, "project-executable")) add(action);
2227
- }
2212
+ const storeCapabilitiesRoot = getCompanyStoreCapabilitiesRoot();
2228
2213
  if (storeCapabilitiesRoot) {
2229
2214
  for (const action of listFolderCapabilityActions(storeCapabilitiesRoot, "company-store")) add(action);
2230
2215
  }
2231
- for (const root of storeExecutableRoots) {
2232
- for (const action of listExecutableCapabilityActions(root, "company-store-executable")) add(action);
2233
- }
2234
2216
  for (const action of listBuiltinCapabilityActions(getBuiltinCapabilitiesRoot())) add(action);
2235
2217
  return out.sort((a, b) => a.action.localeCompare(b.action));
2236
2218
  }
@@ -2294,34 +2276,6 @@ function isImplementationProfile(profilePath, requireImplementationProfile) {
2294
2276
  return false;
2295
2277
  }
2296
2278
  }
2297
- function listExecutableCapabilityActions(root, source) {
2298
- if (!fs6.existsSync(root) || !fs6.statSync(root).isDirectory()) return [];
2299
- const out = [];
2300
- for (const ent of fs6.readdirSync(root, { withFileTypes: true })) {
2301
- if (!ent.isDirectory() || !isSafeName(ent.name)) continue;
2302
- const profilePath = path8.join(root, ent.name, CAPABILITY_PROFILE_FILE);
2303
- if (!fs6.existsSync(profilePath) || !fs6.statSync(profilePath).isFile()) continue;
2304
- try {
2305
- const raw = JSON.parse(fs6.readFileSync(profilePath, "utf-8"));
2306
- const action = typeof raw.action === "string" && raw.action.trim() ? raw.action.trim() : "";
2307
- if (!action) continue;
2308
- if (!PUBLIC_EXECUTABLE_ROLES.has(String(raw.role))) continue;
2309
- if (typeof raw.kind !== "string" || !raw.kind.trim()) continue;
2310
- if (!Array.isArray(raw.inputs)) continue;
2311
- out.push({
2312
- action,
2313
- capability: ent.name,
2314
- executable: ent.name,
2315
- cliArgs: {},
2316
- source,
2317
- describe: typeof raw.describe === "string" ? raw.describe : void 0,
2318
- profilePath
2319
- });
2320
- } catch {
2321
- }
2322
- }
2323
- return out.sort((a, b) => a.action.localeCompare(b.action));
2324
- }
2325
2279
  function listFolderCapabilityActions(root, source) {
2326
2280
  if (!fs6.existsSync(root) || !fs6.statSync(root).isDirectory()) return [];
2327
2281
  const out = [];
@@ -2329,6 +2283,7 @@ function listFolderCapabilityActions(root, source) {
2329
2283
  if (!isSafeName(slug2)) continue;
2330
2284
  const capability = readCapabilityFolder(root, slug2);
2331
2285
  if (!capability) continue;
2286
+ if (capability.config.internal === true || capability.config.public === false) continue;
2332
2287
  const action = capability.config.action ?? slug2;
2333
2288
  const { executable, cliArgs } = resolveCapabilityExecution(capability);
2334
2289
  out.push({
@@ -2978,7 +2933,7 @@ var init_repoWorkspace = __esm({
2978
2933
  defaultCloneRepo = (repo, token, dir) => {
2979
2934
  fs7.mkdirSync(path9.dirname(dir), { recursive: true });
2980
2935
  const authUrl = token ? `https://x-access-token:${token}@github.com/${repo}.git` : `https://github.com/${repo}.git`;
2981
- return new Promise((resolve9, reject) => {
2936
+ return new Promise((resolve10, reject) => {
2982
2937
  const child = spawn2("git", ["clone", "--depth=1", authUrl, dir], {
2983
2938
  stdio: "inherit"
2984
2939
  });
@@ -2994,7 +2949,7 @@ var init_repoWorkspace = __esm({
2994
2949
  spawnSync("git", ["-C", dir, "config", "user.email", email]);
2995
2950
  } catch {
2996
2951
  }
2997
- resolve9();
2952
+ resolve10();
2998
2953
  });
2999
2954
  child.on("error", reject);
3000
2955
  });
@@ -3302,10 +3257,10 @@ async function runAgent(opts) {
3302
3257
  let timer;
3303
3258
  let next;
3304
3259
  if (turnTimeoutMs > 0) {
3305
- const timeoutPromise = new Promise((resolve9) => {
3260
+ const timeoutPromise = new Promise((resolve10) => {
3306
3261
  timer = setTimeout(() => {
3307
3262
  timedOut = true;
3308
- resolve9({ done: true, value: void 0 });
3263
+ resolve10({ done: true, value: void 0 });
3309
3264
  }, turnTimeoutMs);
3310
3265
  });
3311
3266
  next = await Promise.race([nextPromise, timeoutPromise]);
@@ -4255,18 +4210,29 @@ function loadProfile(profilePath) {
4255
4210
  if (!refPath) {
4256
4211
  throw new ProfileError(profilePath, `capability references unknown executable '${execRef}'`);
4257
4212
  }
4258
- const base = loadProfile(refPath);
4259
- return {
4260
- ...base,
4261
- name: requireString(profilePath, r, "name"),
4262
- action: typeof r.action === "string" && r.action.trim() ? r.action.trim() : void 0,
4263
- implementation: execRef,
4264
- executable: execRef,
4265
- describe: typeof r.describe === "string" ? r.describe : base.describe,
4266
- agent: typeof r.agent === "string" && r.agent.trim() ? r.agent.trim() : base.agent,
4267
- capabilityTools: parseStringArray2(r.capabilityTools ?? r.capabilityTools ?? r.tools) ?? base.capabilityTools,
4268
- mentions: Array.isArray(r.mentions) ? r.mentions.map((m) => String(m).trim()).filter(Boolean) : base.mentions
4269
- };
4213
+ if (path19.resolve(refPath) === path19.resolve(profilePath)) {
4214
+ } else {
4215
+ const base = loadProfile(refPath);
4216
+ return {
4217
+ ...base,
4218
+ name: requireString(profilePath, r, "name"),
4219
+ action: typeof r.action === "string" && r.action.trim() ? r.action.trim() : void 0,
4220
+ implementation: execRef,
4221
+ executable: execRef,
4222
+ internal: typeof r.internal === "boolean" ? r.internal : base.internal,
4223
+ public: typeof r.public === "boolean" ? r.public : base.public,
4224
+ capabilityKind: parseCapabilityKind(r.capabilityKind) ?? base.capabilityKind,
4225
+ slug: typeof r.slug === "string" && r.slug.trim() ? r.slug.trim() : base.slug,
4226
+ title: typeof r.title === "string" && r.title.trim() ? r.title.trim() : base.title,
4227
+ skills: parseStringArray2(r.skills) ?? base.skills,
4228
+ prompt: typeof r.prompt === "string" && r.prompt.trim() ? r.prompt.trim() : base.prompt,
4229
+ chatTools: parseStringArray2(r.chatTools) ?? base.chatTools,
4230
+ describe: typeof r.describe === "string" ? r.describe : base.describe,
4231
+ agent: typeof r.agent === "string" && r.agent.trim() ? r.agent.trim() : base.agent,
4232
+ capabilityTools: parseStringArray2(r.capabilityTools ?? r.capabilityTools ?? r.tools) ?? base.capabilityTools,
4233
+ mentions: Array.isArray(r.mentions) ? r.mentions.map((m) => String(m).trim()).filter(Boolean) : base.mentions
4234
+ };
4235
+ }
4270
4236
  }
4271
4237
  const kind = r.kind === "scheduled" ? "scheduled" : "oneshot";
4272
4238
  if (kind === "scheduled" && typeof r.schedule !== "string") {
@@ -4306,6 +4272,14 @@ function loadProfile(profilePath) {
4306
4272
  action: typeof r.action === "string" && r.action.trim() ? r.action.trim() : void 0,
4307
4273
  implementation: void 0,
4308
4274
  executable: void 0,
4275
+ internal: typeof r.internal === "boolean" ? r.internal : void 0,
4276
+ public: typeof r.public === "boolean" ? r.public : void 0,
4277
+ capabilityKind: parseCapabilityKind(r.capabilityKind),
4278
+ slug: typeof r.slug === "string" && r.slug.trim() ? r.slug.trim() : void 0,
4279
+ title: typeof r.title === "string" && r.title.trim() ? r.title.trim() : void 0,
4280
+ skills: parseStringArray2(r.skills),
4281
+ prompt: typeof r.prompt === "string" && r.prompt.trim() ? r.prompt.trim() : void 0,
4282
+ chatTools: parseStringArray2(r.chatTools),
4309
4283
  describe: typeof r.describe === "string" ? r.describe : "",
4310
4284
  // Optional agent to run as. Empty/blank string → undefined (no agent).
4311
4285
  agent: typeof r.agent === "string" && r.agent.trim() ? r.agent.trim() : void 0,
@@ -4406,6 +4380,9 @@ function parseStringArray2(raw) {
4406
4380
  const values = raw.map((t) => String(t).trim()).filter(Boolean);
4407
4381
  return values.length > 0 ? values : void 0;
4408
4382
  }
4383
+ function parseCapabilityKind(raw) {
4384
+ return raw === "observe" || raw === "act" || raw === "verify" ? raw : void 0;
4385
+ }
4409
4386
  function parseInputs(p, raw) {
4410
4387
  if (!Array.isArray(raw)) throw new ProfileError(p, `"inputs" must be an array`);
4411
4388
  const out = [];
@@ -4670,6 +4647,14 @@ var init_profile = __esm({
4670
4647
  "implementations",
4671
4648
  "executable",
4672
4649
  "executables",
4650
+ "internal",
4651
+ "public",
4652
+ "capabilityKind",
4653
+ "slug",
4654
+ "title",
4655
+ "skills",
4656
+ "prompt",
4657
+ "chatTools",
4673
4658
  "agent",
4674
4659
  "every",
4675
4660
  "capabilityTools",
@@ -12961,7 +12946,7 @@ function retryDelaysMs() {
12961
12946
  }
12962
12947
  function sleep(ms) {
12963
12948
  if (ms <= 0) return Promise.resolve();
12964
- return new Promise((resolve9) => setTimeout(resolve9, ms));
12949
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
12965
12950
  }
12966
12951
  async function fetchGoalStateWithRetry(config, goalId, cwd) {
12967
12952
  let state = fetchGoalState(config, goalId, cwd);
@@ -13798,6 +13783,11 @@ function normalizeBundleFiles(ctx, bundle) {
13798
13783
  if (!relativePath) {
13799
13784
  throw new Error(`openAgentFactoryStatePr: files[${index}].path must point to a state repo file`);
13800
13785
  }
13786
+ if (relativePath === "executables" || relativePath.startsWith("executables/")) {
13787
+ throw new Error(
13788
+ `openAgentFactoryStatePr: files[${index}].path uses obsolete executables storage; use capabilities/<slug>/ instead`
13789
+ );
13790
+ }
13801
13791
  if (seen.has(relativePath)) {
13802
13792
  throw new Error(`openAgentFactoryStatePr: duplicate generated file path: ${relativePath}`);
13803
13793
  }
@@ -15637,7 +15627,7 @@ var init_previewBuildHelpers = __esm({
15637
15627
  // src/scripts/previewBuildRun.ts
15638
15628
  import { spawn as spawn4 } from "child_process";
15639
15629
  async function runCmd(cmd, args, opts = {}) {
15640
- await new Promise((resolve9, reject) => {
15630
+ await new Promise((resolve10, reject) => {
15641
15631
  const child = spawn4(cmd, args, {
15642
15632
  cwd: opts.cwd,
15643
15633
  env: { ...process.env, ...opts.env ?? {} },
@@ -15649,7 +15639,7 @@ async function runCmd(cmd, args, opts = {}) {
15649
15639
  }
15650
15640
  child.on("error", reject);
15651
15641
  child.on("close", (code) => {
15652
- if (code === 0) resolve9();
15642
+ if (code === 0) resolve10();
15653
15643
  else reject(new Error(`${cmd} ${args.join(" ")} exited ${code}`));
15654
15644
  });
15655
15645
  });
@@ -16773,7 +16763,7 @@ function stripAnsi2(s) {
16773
16763
  return s.replace(ANSI_RE2, "");
16774
16764
  }
16775
16765
  function runCommand2(command, cwd) {
16776
- return new Promise((resolve9) => {
16766
+ return new Promise((resolve10) => {
16777
16767
  const child = spawn5(command, {
16778
16768
  cwd,
16779
16769
  shell: true,
@@ -16800,11 +16790,11 @@ function runCommand2(command, cwd) {
16800
16790
  }, TEST_TIMEOUT_MS);
16801
16791
  child.on("exit", (code) => {
16802
16792
  clearTimeout(timer);
16803
- resolve9({ exitCode: code ?? -1, output: Buffer.concat(buffers).toString("utf-8") });
16793
+ resolve10({ exitCode: code ?? -1, output: Buffer.concat(buffers).toString("utf-8") });
16804
16794
  });
16805
16795
  child.on("error", (err) => {
16806
16796
  clearTimeout(timer);
16807
- resolve9({ exitCode: -1, output: err.message });
16797
+ resolve10({ exitCode: -1, output: err.message });
16808
16798
  });
16809
16799
  });
16810
16800
  }
@@ -17209,21 +17199,21 @@ function lineStream(stream) {
17209
17199
  tryDeliver();
17210
17200
  });
17211
17201
  return {
17212
- next: (timeoutMs) => new Promise((resolve9) => {
17202
+ next: (timeoutMs) => new Promise((resolve10) => {
17213
17203
  if (queue.length > 0) {
17214
- resolve9(queue.shift());
17204
+ resolve10(queue.shift());
17215
17205
  return;
17216
17206
  }
17217
17207
  if (ended) {
17218
- resolve9(null);
17208
+ resolve10(null);
17219
17209
  return;
17220
17210
  }
17221
- waiter = resolve9;
17211
+ waiter = resolve10;
17222
17212
  const t = setTimeout(
17223
17213
  () => {
17224
- if (waiter === resolve9) {
17214
+ if (waiter === resolve10) {
17225
17215
  waiter = null;
17226
- resolve9(null);
17216
+ resolve10(null);
17227
17217
  }
17228
17218
  },
17229
17219
  Math.max(0, timeoutMs)
@@ -17712,7 +17702,6 @@ var init_stateWorkspace = __esm({
17712
17702
  "use strict";
17713
17703
  init_stateRepo();
17714
17704
  DIR_MAPPINGS = [
17715
- { stateDir: "executables", localDir: path41.join(".kody", "executables") },
17716
17705
  { stateDir: "capabilities", localDir: path41.join(".kody", "capabilities") },
17717
17706
  { stateDir: "agents", localDir: path41.join(".kody", "agents") },
17718
17707
  { stateDir: "context", localDir: path41.join(".kody", "context") },
@@ -18513,14 +18502,14 @@ async function runShellEntry(entry, ctx, profile) {
18513
18502
  let killTimer;
18514
18503
  let escalateTimer;
18515
18504
  const result = await new Promise(
18516
- (resolve9) => {
18505
+ (resolve10) => {
18517
18506
  let settled = false;
18518
18507
  const settle = (code, signal, spawnErr) => {
18519
18508
  if (settled) return;
18520
18509
  settled = true;
18521
18510
  if (killTimer) clearTimeout(killTimer);
18522
18511
  if (escalateTimer) clearTimeout(escalateTimer);
18523
- resolve9({ code, signal, spawnErr });
18512
+ resolve10({ code, signal, spawnErr });
18524
18513
  };
18525
18514
  child.on("error", (err) => settle(null, null, err));
18526
18515
  child.on("close", (code, signal) => settle(code, signal));
@@ -18781,7 +18770,7 @@ async function runJob(job, base) {
18781
18770
  }
18782
18771
  const workflow = capabilityContext?.config.workflow ?? workflowContext?.config.workflow;
18783
18772
  const workflowIdentity = valid.workflow ?? capabilityIdentity ?? workflowContext?.slug;
18784
- const capabilitySelectedExecutable = resolvedCapability?.executable ?? capabilityContext?.config.executable ?? capabilityContext?.config.executables?.[0] ?? (capabilityContext?.config.tickScript ? "capability-tick-scripted" : void 0);
18773
+ const capabilitySelectedExecutable = resolvedCapability?.executable ?? capabilityContext?.config.executable ?? capabilityContext?.config.executables?.[0] ?? (capabilityContext?.config.role ? capabilityContext.slug : void 0) ?? (capabilityContext?.config.tickScript ? "capability-tick-scripted" : void 0);
18785
18774
  const profileName = valid.executable ?? capabilitySelectedExecutable;
18786
18775
  if (workflow && shouldRunCapabilityWorkflow(valid, workflow, workflowIdentity, capabilitySelectedExecutable, base)) {
18787
18776
  const workflowCapability = capabilityContext ?? workflowContext;
@@ -20860,6 +20849,10 @@ async function runCi(argv) {
20860
20849
  `);
20861
20850
  return 64;
20862
20851
  }
20852
+ if (process.env.GITHUB_EVENT_NAME === "issue_comment") {
20853
+ process.stdout.write("\u2192 kody: no action for event issue_comment \u2014 exiting cleanly\n");
20854
+ return 0;
20855
+ }
20863
20856
  process.stdout.write(`\u2192 kody: no action for event ${process.env.GITHUB_EVENT_NAME} \u2014 checking scheduled watches
20864
20857
  `);
20865
20858
  return runScheduledFanOut(cwd, args, { force: false });
@@ -21246,17 +21239,17 @@ function authOk(req, expected) {
21246
21239
  return false;
21247
21240
  }
21248
21241
  function readJsonBody(req) {
21249
- return new Promise((resolve9, reject) => {
21242
+ return new Promise((resolve10, reject) => {
21250
21243
  const chunks = [];
21251
21244
  req.on("data", (c) => chunks.push(c));
21252
21245
  req.on("end", () => {
21253
21246
  const raw = Buffer.concat(chunks).toString("utf-8");
21254
21247
  if (!raw.trim()) {
21255
- resolve9({});
21248
+ resolve10({});
21256
21249
  return;
21257
21250
  }
21258
21251
  try {
21259
- resolve9(JSON.parse(raw));
21252
+ resolve10(JSON.parse(raw));
21260
21253
  } catch (err) {
21261
21254
  reject(err instanceof Error ? err : new Error(String(err)));
21262
21255
  }
@@ -21611,11 +21604,11 @@ async function brainServe(opts) {
21611
21604
  model,
21612
21605
  litellmUrl
21613
21606
  });
21614
- await new Promise((resolve9) => {
21607
+ await new Promise((resolve10) => {
21615
21608
  server.listen(port, "0.0.0.0", () => {
21616
21609
  process.stdout.write(`[brain-serve] listening on 0.0.0.0:${port} (cwd=${opts.cwd})
21617
21610
  `);
21618
- resolve9();
21611
+ resolve10();
21619
21612
  });
21620
21613
  });
21621
21614
  const shutdown = (signal) => {
@@ -21868,14 +21861,14 @@ async function startBrainProxy(opts) {
21868
21861
  const { httpServer, handler } = buildBrainProxy(opts);
21869
21862
  const port = opts.port ?? 0;
21870
21863
  const host = opts.host ?? "127.0.0.1";
21871
- await new Promise((resolve9) => httpServer.listen(port, host, () => resolve9()));
21864
+ await new Promise((resolve10) => httpServer.listen(port, host, () => resolve10()));
21872
21865
  const addr = httpServer.address();
21873
21866
  return {
21874
21867
  httpServer,
21875
21868
  port: addr.port,
21876
21869
  url: `http://${host}:${addr.port}`,
21877
- stop: () => new Promise((resolve9) => {
21878
- httpServer.close(() => resolve9());
21870
+ stop: () => new Promise((resolve10) => {
21871
+ httpServer.close(() => resolve10());
21879
21872
  }),
21880
21873
  handler
21881
21874
  };
@@ -22025,23 +22018,23 @@ function buildMcpHttpServer(opts) {
22025
22018
  httpServer,
22026
22019
  routes,
22027
22020
  port,
22028
- stop: () => new Promise((resolve9) => {
22021
+ stop: () => new Promise((resolve10) => {
22029
22022
  let pending = transports.size;
22030
22023
  if (pending === 0) {
22031
- httpServer.close(() => resolve9());
22024
+ httpServer.close(() => resolve10());
22032
22025
  return;
22033
22026
  }
22034
22027
  for (const transport of transports.values()) {
22035
22028
  void transport.close().finally(() => {
22036
22029
  pending--;
22037
- if (pending === 0) httpServer.close(() => resolve9());
22030
+ if (pending === 0) httpServer.close(() => resolve10());
22038
22031
  });
22039
22032
  }
22040
22033
  })
22041
22034
  };
22042
22035
  }
22043
22036
  function listenMcpHttpServer(server, host = "127.0.0.1") {
22044
- return new Promise((resolve9, reject) => {
22037
+ return new Promise((resolve10, reject) => {
22045
22038
  server.httpServer.once("error", reject);
22046
22039
  server.httpServer.listen(server.port, host, () => {
22047
22040
  server.httpServer.off("error", reject);
@@ -22049,7 +22042,7 @@ function listenMcpHttpServer(server, host = "127.0.0.1") {
22049
22042
  if (addr && typeof addr === "object") {
22050
22043
  server.port = addr.port;
22051
22044
  }
22052
- resolve9();
22045
+ resolve10();
22053
22046
  });
22054
22047
  });
22055
22048
  }
@@ -22190,7 +22183,7 @@ async function waitForNextUserMessage(opts) {
22190
22183
  }
22191
22184
  }
22192
22185
  function sleep3(ms) {
22193
- return new Promise((resolve9) => setTimeout(resolve9, ms));
22186
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
22194
22187
  }
22195
22188
  function currentBranch(cwd) {
22196
22189
  try {
@@ -23293,14 +23286,14 @@ function sendJson2(res, status, body) {
23293
23286
  res.end(JSON.stringify(body));
23294
23287
  }
23295
23288
  function readJsonBody2(req) {
23296
- return new Promise((resolve9, reject) => {
23289
+ return new Promise((resolve10, reject) => {
23297
23290
  const chunks = [];
23298
23291
  req.on("data", (c) => chunks.push(c));
23299
23292
  req.on("end", () => {
23300
23293
  const raw = Buffer.concat(chunks).toString("utf-8");
23301
- if (!raw.trim()) return resolve9({});
23294
+ if (!raw.trim()) return resolve10({});
23302
23295
  try {
23303
- resolve9(JSON.parse(raw));
23296
+ resolve10(JSON.parse(raw));
23304
23297
  } catch (err) {
23305
23298
  reject(err instanceof Error ? err : new Error(String(err)));
23306
23299
  }
@@ -23482,10 +23475,10 @@ async function poolServe() {
23482
23475
  }
23483
23476
  });
23484
23477
  const apiHost = process.env.POOL_API_HOST ?? "::";
23485
- await new Promise((resolve9) => {
23478
+ await new Promise((resolve10) => {
23486
23479
  server.listen(apiPort, apiHost, () => {
23487
23480
  log(`listening on ${apiHost}:${apiPort} (min=${min}, app=${app}, region=${region})`);
23488
- resolve9();
23481
+ resolve10();
23489
23482
  });
23490
23483
  });
23491
23484
  const shutdown = (signal) => {
@@ -23524,17 +23517,17 @@ function authOk2(req, expected) {
23524
23517
  return false;
23525
23518
  }
23526
23519
  function readJsonBody3(req) {
23527
- return new Promise((resolve9, reject) => {
23520
+ return new Promise((resolve10, reject) => {
23528
23521
  const chunks = [];
23529
23522
  req.on("data", (c) => chunks.push(c));
23530
23523
  req.on("end", () => {
23531
23524
  const raw = Buffer.concat(chunks).toString("utf-8");
23532
23525
  if (!raw.trim()) {
23533
- resolve9({});
23526
+ resolve10({});
23534
23527
  return;
23535
23528
  }
23536
23529
  try {
23537
- resolve9(JSON.parse(raw));
23530
+ resolve10(JSON.parse(raw));
23538
23531
  } catch (err) {
23539
23532
  reject(err instanceof Error ? err : new Error(String(err)));
23540
23533
  }
@@ -23668,13 +23661,13 @@ async function defaultRunJob(job) {
23668
23661
  ...interactive && job.idleExitMs ? { KODY_IDLE_EXIT_MS: String(job.idleExitMs) } : {},
23669
23662
  ...interactive && job.hardCapMs ? { KODY_HARD_CAP_MS: String(job.hardCapMs) } : {}
23670
23663
  };
23671
- const run = (cmd, args, cwd) => new Promise((resolve9) => {
23664
+ const run = (cmd, args, cwd) => new Promise((resolve10) => {
23672
23665
  const child = spawn8(cmd, args, { stdio: "inherit", env: childEnv, cwd });
23673
- child.on("exit", (code) => resolve9(code ?? 0));
23666
+ child.on("exit", (code) => resolve10(code ?? 0));
23674
23667
  child.on("error", (err) => {
23675
23668
  process.stderr.write(`[runner-serve] ${cmd} failed: ${err.message}
23676
23669
  `);
23677
- resolve9(1);
23670
+ resolve10(1);
23678
23671
  });
23679
23672
  });
23680
23673
  process.stdout.write(`[runner-serve] job ${job.jobId}: cloning ${job.repo}@${branch}
@@ -23750,11 +23743,11 @@ async function runnerServe() {
23750
23743
  const port = Number(process.env.PORT ?? DEFAULT_PORT2);
23751
23744
  const server = buildServer2({ apiKey });
23752
23745
  const host = process.env.RUNNER_HOST ?? "::";
23753
- await new Promise((resolve9) => {
23746
+ await new Promise((resolve10) => {
23754
23747
  server.listen(port, host, () => {
23755
23748
  process.stdout.write(`[runner-serve] listening on ${host}:${port} (idle, awaiting job)
23756
23749
  `);
23757
- resolve9();
23750
+ resolve10();
23758
23751
  });
23759
23752
  });
23760
23753
  const shutdown = (signal) => {
@@ -23823,14 +23816,14 @@ async function serve(opts) {
23823
23816
  `);
23824
23817
  const args = ["--dangerously-skip-permissions", "--model", model.model];
23825
23818
  const child = spawn9("claude", args, { stdio: "inherit", env: editorEnv, cwd: opts.cwd });
23826
- const exitCode = await new Promise((resolve9) => {
23827
- child.on("exit", (code) => resolve9(code ?? 0));
23819
+ const exitCode = await new Promise((resolve10) => {
23820
+ child.on("exit", (code) => resolve10(code ?? 0));
23828
23821
  child.on("error", (err) => {
23829
23822
  process.stderr.write(`[kody serve] failed to launch Claude Code: ${err.message}
23830
23823
  `);
23831
23824
  process.stderr.write(` Install: https://docs.anthropic.com/claude/docs/claude-code
23832
23825
  `);
23833
- resolve9(1);
23826
+ resolve10(1);
23834
23827
  });
23835
23828
  });
23836
23829
  killProxy();
@@ -18,7 +18,7 @@ You are Kody's agent factory. Convert the operator request into review-ready Kod
18
18
 
19
19
  # Task
20
20
 
21
- Design the smallest Kody model structure that satisfies the request. You may create or assemble simple executables, capabilities, loops, goals, and agents.
21
+ Design the smallest Kody model structure that satisfies the request. You may create or assemble simple capability implementation profiles, capabilities, loops, goals, and agents.
22
22
 
23
23
  Use the current Kody vocabulary:
24
24
 
@@ -31,7 +31,7 @@ Use the current Kody vocabulary:
31
31
  Use current storage names when producing files:
32
32
 
33
33
  - capability: capability contract, public action ownership, kind, agent, cadence, and output contract
34
- - executable: capability implementation
34
+ - implementation profile: capability implementation stored under `capabilities/<slug>/`
35
35
 
36
36
  # Boundaries
37
37
 
@@ -40,7 +40,8 @@ Use current storage names when producing files:
40
40
  - Do not activate generated definitions yourself.
41
41
  - Do not create a consumer-repo PR.
42
42
  - The deterministic postflight will open a review PR in the configured state repo under the configured state path.
43
- - Put generated file paths relative to the configured state path, for example `executables/...`, `capabilities/...`, `agents/...`, `goals/...`, or `memory/...`.
43
+ - Put generated file paths relative to the configured state path, for example `capabilities/...`, `agents/...`, `goals/...`, or `memory/...`.
44
+ - Do not create `executables/...` paths. External executables are obsolete; implementation profiles live in capability folders.
44
45
  - Produce complete file contents. Do not describe patches.
45
46
  - Prefer a small bundle over a broad framework. Include assumptions in the summary.
46
47
 
@@ -59,7 +60,7 @@ PR_SUMMARY:
59
60
  "summary": "human explanation and assumptions",
60
61
  "files": [
61
62
  {
62
- "path": "executables/example/profile.json",
63
+ "path": "capabilities/example/profile.json",
63
64
  "content": "{\n \"name\": \"example\"\n}\n"
64
65
  }
65
66
  ]
@@ -56,6 +56,18 @@ export interface Profile {
56
56
  executable?: string
57
57
  implementations?: string[]
58
58
  executables?: string[]
59
+ /** Hide a capability implementation profile from public action discovery. */
60
+ internal?: boolean
61
+ /** Explicit public-action flag for capability profiles. */
62
+ public?: boolean
63
+ /** Public capability output class when the profile also serves as a capability contract. */
64
+ capabilityKind?: "observe" | "act" | "verify"
65
+ /** Optional dashboard-facing capability metadata. The executor does not act on these fields. */
66
+ slug?: string
67
+ title?: string
68
+ skills?: string[]
69
+ prompt?: string
70
+ chatTools?: string[]
59
71
  /**
60
72
  * Execution model — orthogonal to `role`.
61
73
  * `oneshot` (default): single invocation on demand.
@@ -160,7 +172,7 @@ export interface Profile {
160
172
  * preflight runs. composePrompt prefers these over a fresh disk read so the
161
173
  * template survives working-tree churn from runFlow's branch setup — on the CI
162
174
  * runner a branch checkout can drop the tracked-but-ignore-negated
163
- * `.kody/executables/<name>/` dir, and reading prompt.md afterwards fails with
175
+ * `.kody/capabilities/<name>/` dir, and reading prompt.md afterwards fails with
164
176
  * ENOENT even though profile.json (read here, earlier) loaded fine.
165
177
  */
166
178
  promptTemplates?: Record<string, string>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.288",
3
+ "version": "0.4.290",
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",