@kody-ade/kody-engine 0.4.289 → 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.289",
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;
@@ -21250,17 +21239,17 @@ function authOk(req, expected) {
21250
21239
  return false;
21251
21240
  }
21252
21241
  function readJsonBody(req) {
21253
- return new Promise((resolve9, reject) => {
21242
+ return new Promise((resolve10, reject) => {
21254
21243
  const chunks = [];
21255
21244
  req.on("data", (c) => chunks.push(c));
21256
21245
  req.on("end", () => {
21257
21246
  const raw = Buffer.concat(chunks).toString("utf-8");
21258
21247
  if (!raw.trim()) {
21259
- resolve9({});
21248
+ resolve10({});
21260
21249
  return;
21261
21250
  }
21262
21251
  try {
21263
- resolve9(JSON.parse(raw));
21252
+ resolve10(JSON.parse(raw));
21264
21253
  } catch (err) {
21265
21254
  reject(err instanceof Error ? err : new Error(String(err)));
21266
21255
  }
@@ -21615,11 +21604,11 @@ async function brainServe(opts) {
21615
21604
  model,
21616
21605
  litellmUrl
21617
21606
  });
21618
- await new Promise((resolve9) => {
21607
+ await new Promise((resolve10) => {
21619
21608
  server.listen(port, "0.0.0.0", () => {
21620
21609
  process.stdout.write(`[brain-serve] listening on 0.0.0.0:${port} (cwd=${opts.cwd})
21621
21610
  `);
21622
- resolve9();
21611
+ resolve10();
21623
21612
  });
21624
21613
  });
21625
21614
  const shutdown = (signal) => {
@@ -21872,14 +21861,14 @@ async function startBrainProxy(opts) {
21872
21861
  const { httpServer, handler } = buildBrainProxy(opts);
21873
21862
  const port = opts.port ?? 0;
21874
21863
  const host = opts.host ?? "127.0.0.1";
21875
- await new Promise((resolve9) => httpServer.listen(port, host, () => resolve9()));
21864
+ await new Promise((resolve10) => httpServer.listen(port, host, () => resolve10()));
21876
21865
  const addr = httpServer.address();
21877
21866
  return {
21878
21867
  httpServer,
21879
21868
  port: addr.port,
21880
21869
  url: `http://${host}:${addr.port}`,
21881
- stop: () => new Promise((resolve9) => {
21882
- httpServer.close(() => resolve9());
21870
+ stop: () => new Promise((resolve10) => {
21871
+ httpServer.close(() => resolve10());
21883
21872
  }),
21884
21873
  handler
21885
21874
  };
@@ -22029,23 +22018,23 @@ function buildMcpHttpServer(opts) {
22029
22018
  httpServer,
22030
22019
  routes,
22031
22020
  port,
22032
- stop: () => new Promise((resolve9) => {
22021
+ stop: () => new Promise((resolve10) => {
22033
22022
  let pending = transports.size;
22034
22023
  if (pending === 0) {
22035
- httpServer.close(() => resolve9());
22024
+ httpServer.close(() => resolve10());
22036
22025
  return;
22037
22026
  }
22038
22027
  for (const transport of transports.values()) {
22039
22028
  void transport.close().finally(() => {
22040
22029
  pending--;
22041
- if (pending === 0) httpServer.close(() => resolve9());
22030
+ if (pending === 0) httpServer.close(() => resolve10());
22042
22031
  });
22043
22032
  }
22044
22033
  })
22045
22034
  };
22046
22035
  }
22047
22036
  function listenMcpHttpServer(server, host = "127.0.0.1") {
22048
- return new Promise((resolve9, reject) => {
22037
+ return new Promise((resolve10, reject) => {
22049
22038
  server.httpServer.once("error", reject);
22050
22039
  server.httpServer.listen(server.port, host, () => {
22051
22040
  server.httpServer.off("error", reject);
@@ -22053,7 +22042,7 @@ function listenMcpHttpServer(server, host = "127.0.0.1") {
22053
22042
  if (addr && typeof addr === "object") {
22054
22043
  server.port = addr.port;
22055
22044
  }
22056
- resolve9();
22045
+ resolve10();
22057
22046
  });
22058
22047
  });
22059
22048
  }
@@ -22194,7 +22183,7 @@ async function waitForNextUserMessage(opts) {
22194
22183
  }
22195
22184
  }
22196
22185
  function sleep3(ms) {
22197
- return new Promise((resolve9) => setTimeout(resolve9, ms));
22186
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
22198
22187
  }
22199
22188
  function currentBranch(cwd) {
22200
22189
  try {
@@ -23297,14 +23286,14 @@ function sendJson2(res, status, body) {
23297
23286
  res.end(JSON.stringify(body));
23298
23287
  }
23299
23288
  function readJsonBody2(req) {
23300
- return new Promise((resolve9, reject) => {
23289
+ return new Promise((resolve10, reject) => {
23301
23290
  const chunks = [];
23302
23291
  req.on("data", (c) => chunks.push(c));
23303
23292
  req.on("end", () => {
23304
23293
  const raw = Buffer.concat(chunks).toString("utf-8");
23305
- if (!raw.trim()) return resolve9({});
23294
+ if (!raw.trim()) return resolve10({});
23306
23295
  try {
23307
- resolve9(JSON.parse(raw));
23296
+ resolve10(JSON.parse(raw));
23308
23297
  } catch (err) {
23309
23298
  reject(err instanceof Error ? err : new Error(String(err)));
23310
23299
  }
@@ -23486,10 +23475,10 @@ async function poolServe() {
23486
23475
  }
23487
23476
  });
23488
23477
  const apiHost = process.env.POOL_API_HOST ?? "::";
23489
- await new Promise((resolve9) => {
23478
+ await new Promise((resolve10) => {
23490
23479
  server.listen(apiPort, apiHost, () => {
23491
23480
  log(`listening on ${apiHost}:${apiPort} (min=${min}, app=${app}, region=${region})`);
23492
- resolve9();
23481
+ resolve10();
23493
23482
  });
23494
23483
  });
23495
23484
  const shutdown = (signal) => {
@@ -23528,17 +23517,17 @@ function authOk2(req, expected) {
23528
23517
  return false;
23529
23518
  }
23530
23519
  function readJsonBody3(req) {
23531
- return new Promise((resolve9, reject) => {
23520
+ return new Promise((resolve10, reject) => {
23532
23521
  const chunks = [];
23533
23522
  req.on("data", (c) => chunks.push(c));
23534
23523
  req.on("end", () => {
23535
23524
  const raw = Buffer.concat(chunks).toString("utf-8");
23536
23525
  if (!raw.trim()) {
23537
- resolve9({});
23526
+ resolve10({});
23538
23527
  return;
23539
23528
  }
23540
23529
  try {
23541
- resolve9(JSON.parse(raw));
23530
+ resolve10(JSON.parse(raw));
23542
23531
  } catch (err) {
23543
23532
  reject(err instanceof Error ? err : new Error(String(err)));
23544
23533
  }
@@ -23672,13 +23661,13 @@ async function defaultRunJob(job) {
23672
23661
  ...interactive && job.idleExitMs ? { KODY_IDLE_EXIT_MS: String(job.idleExitMs) } : {},
23673
23662
  ...interactive && job.hardCapMs ? { KODY_HARD_CAP_MS: String(job.hardCapMs) } : {}
23674
23663
  };
23675
- const run = (cmd, args, cwd) => new Promise((resolve9) => {
23664
+ const run = (cmd, args, cwd) => new Promise((resolve10) => {
23676
23665
  const child = spawn8(cmd, args, { stdio: "inherit", env: childEnv, cwd });
23677
- child.on("exit", (code) => resolve9(code ?? 0));
23666
+ child.on("exit", (code) => resolve10(code ?? 0));
23678
23667
  child.on("error", (err) => {
23679
23668
  process.stderr.write(`[runner-serve] ${cmd} failed: ${err.message}
23680
23669
  `);
23681
- resolve9(1);
23670
+ resolve10(1);
23682
23671
  });
23683
23672
  });
23684
23673
  process.stdout.write(`[runner-serve] job ${job.jobId}: cloning ${job.repo}@${branch}
@@ -23754,11 +23743,11 @@ async function runnerServe() {
23754
23743
  const port = Number(process.env.PORT ?? DEFAULT_PORT2);
23755
23744
  const server = buildServer2({ apiKey });
23756
23745
  const host = process.env.RUNNER_HOST ?? "::";
23757
- await new Promise((resolve9) => {
23746
+ await new Promise((resolve10) => {
23758
23747
  server.listen(port, host, () => {
23759
23748
  process.stdout.write(`[runner-serve] listening on ${host}:${port} (idle, awaiting job)
23760
23749
  `);
23761
- resolve9();
23750
+ resolve10();
23762
23751
  });
23763
23752
  });
23764
23753
  const shutdown = (signal) => {
@@ -23827,14 +23816,14 @@ async function serve(opts) {
23827
23816
  `);
23828
23817
  const args = ["--dangerously-skip-permissions", "--model", model.model];
23829
23818
  const child = spawn9("claude", args, { stdio: "inherit", env: editorEnv, cwd: opts.cwd });
23830
- const exitCode = await new Promise((resolve9) => {
23831
- child.on("exit", (code) => resolve9(code ?? 0));
23819
+ const exitCode = await new Promise((resolve10) => {
23820
+ child.on("exit", (code) => resolve10(code ?? 0));
23832
23821
  child.on("error", (err) => {
23833
23822
  process.stderr.write(`[kody serve] failed to launch Claude Code: ${err.message}
23834
23823
  `);
23835
23824
  process.stderr.write(` Install: https://docs.anthropic.com/claude/docs/claude-code
23836
23825
  `);
23837
- resolve9(1);
23826
+ resolve10(1);
23838
23827
  });
23839
23828
  });
23840
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.289",
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",