@kody-ade/kody-engine 0.4.68 → 0.4.70

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
@@ -864,7 +864,7 @@ var init_loadPriorArt = __esm({
864
864
  // package.json
865
865
  var package_default = {
866
866
  name: "@kody-ade/kody-engine",
867
- version: "0.4.68",
867
+ version: "0.4.70",
868
868
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
869
869
  license: "MIT",
870
870
  type: "module",
@@ -878,7 +878,10 @@ var package_default = {
878
878
  ],
879
879
  scripts: {
880
880
  kody: "tsx bin/kody.ts",
881
+ serve: "tsx bin/kody.ts serve",
881
882
  build: "tsup && node scripts/copy-assets.cjs",
883
+ "check:modularity": "tsx scripts/check-script-modularity.ts",
884
+ pretest: "pnpm check:modularity",
882
885
  test: "vitest run tests/unit tests/int --no-coverage",
883
886
  "test:e2e": "vitest run tests/e2e --no-coverage",
884
887
  "test:all": "vitest run tests --no-coverage",
@@ -1410,6 +1413,48 @@ async function runAgent(opts) {
1410
1413
  if (line) process.stdout.write(`${line}
1411
1414
  `);
1412
1415
  const m = msg;
1416
+ if (opts.onProgress) {
1417
+ const blocks = m.message?.content ?? [];
1418
+ for (const block of blocks) {
1419
+ try {
1420
+ if (block.type === "thinking") {
1421
+ const t = block.thinking;
1422
+ if (typeof t === "string" && t.length > 0) {
1423
+ await opts.onProgress({ kind: "thinking", thinking: t });
1424
+ }
1425
+ } else if (block.type === "tool_use") {
1426
+ const b = block;
1427
+ await opts.onProgress({
1428
+ kind: "tool_use",
1429
+ name: b.name ?? "tool",
1430
+ input: b.input,
1431
+ id: b.id
1432
+ });
1433
+ } else if (block.type === "tool_result") {
1434
+ const b = block;
1435
+ const content = typeof b.content === "string" ? b.content : (() => {
1436
+ try {
1437
+ return JSON.stringify(b.content);
1438
+ } catch {
1439
+ return "";
1440
+ }
1441
+ })();
1442
+ await opts.onProgress({
1443
+ kind: "tool_result",
1444
+ toolUseId: b.tool_use_id,
1445
+ content,
1446
+ isError: b.is_error
1447
+ });
1448
+ } else if (block.type === "text") {
1449
+ const b = block;
1450
+ if (typeof b.text === "string" && b.text.length > 0) {
1451
+ await opts.onProgress({ kind: "text", text: b.text });
1452
+ }
1453
+ }
1454
+ } catch {
1455
+ }
1456
+ }
1457
+ }
1413
1458
  const usage = m.usage;
1414
1459
  if (usage && typeof usage === "object") {
1415
1460
  const i = Number(usage.input_tokens ?? 0);
@@ -1596,6 +1641,7 @@ async function runChatTurn(opts) {
1596
1641
  }
1597
1642
  const systemPrompt = opts.systemPrompt ?? CHAT_SYSTEM_PROMPT;
1598
1643
  const prompt = buildPrompt(turns);
1644
+ let progressSeq = 0;
1599
1645
  const invoke = opts.invokeAgent ?? ((p) => runAgent({
1600
1646
  prompt: p,
1601
1647
  model: opts.model,
@@ -1603,7 +1649,29 @@ async function runChatTurn(opts) {
1603
1649
  litellmUrl: opts.litellmUrl,
1604
1650
  verbose: opts.verbose,
1605
1651
  quiet: opts.quiet,
1606
- systemPromptAppend: systemPrompt
1652
+ systemPromptAppend: systemPrompt,
1653
+ onProgress: async (ev) => {
1654
+ progressSeq += 1;
1655
+ if (ev.kind === "thinking") {
1656
+ await emit(opts.sink, "chat.thinking", opts.sessionId, `think-${progressSeq}`, {
1657
+ text: ev.thinking
1658
+ });
1659
+ } else if (ev.kind === "tool_use") {
1660
+ await emit(opts.sink, "chat.tool", opts.sessionId, `tool-${progressSeq}`, {
1661
+ phase: "use",
1662
+ id: ev.id,
1663
+ name: ev.name,
1664
+ input: ev.input ?? {}
1665
+ });
1666
+ } else if (ev.kind === "tool_result") {
1667
+ await emit(opts.sink, "chat.tool", opts.sessionId, `tool-${progressSeq}`, {
1668
+ phase: "result",
1669
+ toolUseId: ev.toolUseId,
1670
+ content: ev.content,
1671
+ isError: ev.isError === true
1672
+ });
1673
+ }
1674
+ }
1607
1675
  }));
1608
1676
  let result;
1609
1677
  try {
@@ -2328,7 +2396,7 @@ function coerceBare(spec, value) {
2328
2396
  init_issue();
2329
2397
 
2330
2398
  // src/executor.ts
2331
- import { execFileSync as execFileSync29, spawn as spawn5 } from "child_process";
2399
+ import { execFileSync as execFileSync29, spawn as spawn6 } from "child_process";
2332
2400
  import * as fs31 from "fs";
2333
2401
  import * as path29 from "path";
2334
2402
  init_events();
@@ -8884,6 +8952,72 @@ function buildChildEnv(parent, force) {
8884
8952
  return out;
8885
8953
  }
8886
8954
 
8955
+ // src/scripts/serveFlow.ts
8956
+ import { spawn as spawn3 } from "child_process";
8957
+ var serveFlow = async (ctx) => {
8958
+ ctx.skipAgent = true;
8959
+ const model = parseProviderModel(ctx.config.agent.model);
8960
+ const usesProxy = needsLitellmProxy(model);
8961
+ let handle = null;
8962
+ if (usesProxy) {
8963
+ process.stdout.write(`[kody serve] starting LiteLLM proxy for ${model.provider}/${model.model}...
8964
+ `);
8965
+ handle = await startLitellmIfNeeded(model, ctx.cwd);
8966
+ process.stdout.write(`[kody serve] LiteLLM ready at ${handle?.url ?? LITELLM_DEFAULT_URL}
8967
+ `);
8968
+ } else {
8969
+ process.stdout.write(`[kody serve] model ${model.provider}/${model.model} routes to Anthropic directly \u2014 no proxy needed
8970
+ `);
8971
+ }
8972
+ const url = handle?.url ?? LITELLM_DEFAULT_URL;
8973
+ const noEditor = ctx.args.noEditor === true;
8974
+ if (!noEditor) {
8975
+ const env = { ...process.env };
8976
+ if (usesProxy) {
8977
+ env.ANTHROPIC_BASE_URL = url;
8978
+ env.ANTHROPIC_API_KEY = getAnthropicApiKeyOrDummy();
8979
+ }
8980
+ process.stdout.write(`[kody serve] launching VS Code at ${ctx.cwd}
8981
+ `);
8982
+ if (usesProxy) process.stdout.write(` ANTHROPIC_BASE_URL=${url}
8983
+ `);
8984
+ try {
8985
+ const code = spawn3("code", [ctx.cwd], { stdio: "inherit", env, detached: true });
8986
+ code.on("error", (err) => {
8987
+ process.stderr.write(`[kody serve] failed to launch VS Code: ${err.message}
8988
+ `);
8989
+ process.stderr.write(` Install the 'code' CLI: VS Code \u2192 Command Palette \u2192 "Shell Command: Install 'code' command in PATH"
8990
+ `);
8991
+ });
8992
+ code.unref();
8993
+ } catch (err) {
8994
+ const msg = err instanceof Error ? err.message : String(err);
8995
+ process.stderr.write(`[kody serve] failed to spawn VS Code: ${msg}
8996
+ `);
8997
+ }
8998
+ }
8999
+ process.stdout.write(`[kody serve] running. Press Ctrl+C to stop.
9000
+ `);
9001
+ const keepAlive = setInterval(() => {
9002
+ }, 6e4);
9003
+ const cleanup = (signal, exitCode) => {
9004
+ clearInterval(keepAlive);
9005
+ if (handle) {
9006
+ process.stdout.write(`[kody serve] received ${signal}, stopping LiteLLM proxy...
9007
+ `);
9008
+ try {
9009
+ handle.kill();
9010
+ } catch {
9011
+ }
9012
+ }
9013
+ process.exit(exitCode);
9014
+ };
9015
+ process.on("SIGINT", () => cleanup("SIGINT", 130));
9016
+ process.on("SIGTERM", () => cleanup("SIGTERM", 143));
9017
+ await new Promise(() => {
9018
+ });
9019
+ };
9020
+
8887
9021
  // src/scripts/saveGoalState.ts
8888
9022
  var saveGoalState = async (ctx) => {
8889
9023
  const goal = ctx.data.goal;
@@ -9168,7 +9302,7 @@ var verify = async (ctx) => {
9168
9302
  };
9169
9303
 
9170
9304
  // src/scripts/verifyReproFails.ts
9171
- import { spawn as spawn3 } from "child_process";
9305
+ import { spawn as spawn4 } from "child_process";
9172
9306
  var TEST_TIMEOUT_MS = 10 * 60 * 1e3;
9173
9307
  var TAIL_CHARS2 = 8e3;
9174
9308
  var ANSI_RE2 = /\x1B\[[0-?]*[ -/]*[@-~]/g;
@@ -9237,7 +9371,7 @@ function stripAnsi2(s) {
9237
9371
  }
9238
9372
  function runCommand2(command, cwd) {
9239
9373
  return new Promise((resolve4) => {
9240
- const child = spawn3(command, {
9374
+ const child = spawn4(command, {
9241
9375
  cwd,
9242
9376
  shell: true,
9243
9377
  env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1", CI: process.env.CI ?? "1" },
@@ -9410,7 +9544,7 @@ function sleep2(ms) {
9410
9544
  }
9411
9545
 
9412
9546
  // src/scripts/warmupMcp.ts
9413
- import { spawn as spawn4 } from "child_process";
9547
+ import { spawn as spawn5 } from "child_process";
9414
9548
  var PER_SERVER_TIMEOUT_MS = 6e4;
9415
9549
  var PER_REQUEST_TIMEOUT_MS = 2e4;
9416
9550
  var warmupMcp = async (_ctx, profile) => {
@@ -9432,7 +9566,7 @@ var warmupMcp = async (_ctx, profile) => {
9432
9566
  }
9433
9567
  };
9434
9568
  async function warmupOne(command, args, env) {
9435
- const child = spawn4(command, args, {
9569
+ const child = spawn5(command, args, {
9436
9570
  stdio: ["pipe", "pipe", "pipe"],
9437
9571
  env: env ? { ...process.env, ...env } : process.env
9438
9572
  });
@@ -9684,6 +9818,7 @@ var preflightScripts = {
9684
9818
  dispatchJobTicks,
9685
9819
  dispatchJobFileTicks,
9686
9820
  runTickScript,
9821
+ serveFlow,
9687
9822
  loadGoalState,
9688
9823
  handleAbandonedGoal,
9689
9824
  deriveGoalPhase,
@@ -10194,7 +10329,7 @@ async function runShellEntry(entry, ctx, profile) {
10194
10329
  env[`KODY_CFG_${k}`] = v;
10195
10330
  }
10196
10331
  const timeoutMs = resolveShellTimeoutMs(entry);
10197
- const child = spawn5("bash", [shellPath, ...positional], {
10332
+ const child = spawn6("bash", [shellPath, ...positional], {
10198
10333
  cwd: ctx.cwd,
10199
10334
  env,
10200
10335
  stdio: ["pipe", "pipe", "pipe"],
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "serve",
3
+ "role": "utility",
4
+ "describe": "Start a LiteLLM proxy and launch VS Code with ANTHROPIC_BASE_URL pointed at it. Long-lived — Ctrl+C to stop.",
5
+ "inputs": [
6
+ {
7
+ "name": "noEditor",
8
+ "flag": "--no-editor",
9
+ "type": "bool",
10
+ "required": false,
11
+ "describe": "Run the LiteLLM proxy only; do not launch VS Code."
12
+ }
13
+ ],
14
+ "claudeCode": {
15
+ "model": "inherit",
16
+ "permissionMode": "acceptEdits",
17
+ "maxTurns": null,
18
+ "systemPromptAppend": null,
19
+ "tools": [],
20
+ "hooks": [],
21
+ "skills": [],
22
+ "commands": [],
23
+ "subagents": [],
24
+ "plugins": [],
25
+ "mcpServers": []
26
+ },
27
+ "cliTools": [],
28
+ "scripts": {
29
+ "preflight": [
30
+ {
31
+ "script": "serveFlow"
32
+ }
33
+ ],
34
+ "postflight": []
35
+ }
36
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.68",
3
+ "version": "0.4.70",
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",
@@ -12,18 +12,6 @@
12
12
  "templates",
13
13
  "kody.config.schema.json"
14
14
  ],
15
- "scripts": {
16
- "kody": "tsx bin/kody.ts",
17
- "build": "tsup && node scripts/copy-assets.cjs",
18
- "test": "vitest run tests/unit tests/int --no-coverage",
19
- "test:e2e": "vitest run tests/e2e --no-coverage",
20
- "test:all": "vitest run tests --no-coverage",
21
- "typecheck": "tsc --noEmit",
22
- "lint": "biome check",
23
- "lint:fix": "biome check --write",
24
- "format": "biome format --write",
25
- "prepublishOnly": "pnpm build"
26
- },
27
15
  "dependencies": {
28
16
  "@actions/cache": "^6.0.0",
29
17
  "@anthropic-ai/claude-agent-sdk": "0.2.119",
@@ -45,5 +33,19 @@
45
33
  "url": "git+https://github.com/aharonyaircohen/kody-engine.git"
46
34
  },
47
35
  "homepage": "https://github.com/aharonyaircohen/kody-engine",
48
- "bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
49
- }
36
+ "bugs": "https://github.com/aharonyaircohen/kody-engine/issues",
37
+ "scripts": {
38
+ "kody": "tsx bin/kody.ts",
39
+ "serve": "tsx bin/kody.ts serve",
40
+ "build": "tsup && node scripts/copy-assets.cjs",
41
+ "check:modularity": "tsx scripts/check-script-modularity.ts",
42
+ "pretest": "pnpm check:modularity",
43
+ "test": "vitest run tests/unit tests/int --no-coverage",
44
+ "test:e2e": "vitest run tests/e2e --no-coverage",
45
+ "test:all": "vitest run tests --no-coverage",
46
+ "typecheck": "tsc --noEmit",
47
+ "lint": "biome check",
48
+ "lint:fix": "biome check --write",
49
+ "format": "biome format --write"
50
+ }
51
+ }