@kody-ade/kody-engine 0.4.393 → 0.4.395

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.
Files changed (2) hide show
  1. package/dist/bin/kody.js +111 -10
  2. package/package.json +25 -24
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.392",
18
+ version: "0.4.395",
19
19
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
20
20
  license: "MIT",
21
21
  type: "module",
@@ -3921,6 +3921,25 @@ function createStateBackendFromEnv(env = process.env, client) {
3921
3921
  entry
3922
3922
  });
3923
3923
  },
3924
+ async saveAgencyRun(tenantId, runId, subjectType, subjectId, run, updatedAt) {
3925
+ await transport.mutation(anyApi.agencyRuns.save, {
3926
+ tenantId: requireTenant(tenantId),
3927
+ runId: requireNonEmpty(runId, "runId"),
3928
+ subjectType,
3929
+ subjectId: requireNonEmpty(subjectId, "subjectId"),
3930
+ run,
3931
+ updatedAt
3932
+ });
3933
+ },
3934
+ async appendRunEvent(tenantId, runId, goalId, event, time) {
3935
+ await transport.mutation(anyApi.runEvents.append, {
3936
+ tenantId: requireTenant(tenantId),
3937
+ runId: requireNonEmpty(runId, "runId"),
3938
+ ...goalId ? { goalId: requireNonEmpty(goalId, "goalId") } : {},
3939
+ event,
3940
+ time: requireNonEmpty(time, "time")
3941
+ });
3942
+ },
3924
3943
  async saveReport(tenantId, slug, runId, title, body, meta, updatedAt) {
3925
3944
  await transport.mutation(anyApi.reports.save, {
3926
3945
  tenantId: requireTenant(tenantId),
@@ -3931,6 +3950,32 @@ function createStateBackendFromEnv(env = process.env, client) {
3931
3950
  meta,
3932
3951
  updatedAt
3933
3952
  });
3953
+ },
3954
+ async listIntents(tenantId) {
3955
+ const result = await transport.query(anyApi.intents.list, { tenantId: requireTenant(tenantId) });
3956
+ return Array.isArray(result) ? result : [];
3957
+ },
3958
+ async getIntent(tenantId, intentId) {
3959
+ const result = await transport.query(anyApi.intents.get, {
3960
+ tenantId: requireTenant(tenantId),
3961
+ intentId: requireNonEmpty(intentId, "intentId")
3962
+ });
3963
+ return result ?? null;
3964
+ },
3965
+ async saveIntent(tenantId, intentId, intent, updatedAt) {
3966
+ await transport.mutation(anyApi.intents.save, {
3967
+ tenantId: requireTenant(tenantId),
3968
+ intentId: requireNonEmpty(intentId, "intentId"),
3969
+ intent,
3970
+ updatedAt
3971
+ });
3972
+ },
3973
+ async appendIntentDecision(tenantId, intentId, decision) {
3974
+ await transport.mutation(anyApi.intents.appendDecision, {
3975
+ tenantId: requireTenant(tenantId),
3976
+ intentId: requireNonEmpty(intentId, "intentId"),
3977
+ decision
3978
+ });
3934
3979
  }
3935
3980
  };
3936
3981
  }
@@ -6984,15 +7029,36 @@ function upsertRunIndexRowBestEffort(config, cwd, row) {
6984
7029
  `);
6985
7030
  }
6986
7031
  }
7032
+ async function upsertRunIndexRowBestEffortAsync(config, cwd, row) {
7033
+ if (!row) return;
7034
+ const tenantId = tenantIdForRun(config);
7035
+ const backendConfigured = Boolean(process.env.CONVEX_URL?.trim() && process.env.KODY_SERVICE_KEY?.trim() && tenantId);
7036
+ if (backendConfigured) {
7037
+ const backend = createStateBackendFromEnv();
7038
+ await backend.saveAgencyRun(
7039
+ tenantId,
7040
+ row.id,
7041
+ row.subjectType,
7042
+ row.subjectId,
7043
+ row,
7044
+ row.updatedAt
7045
+ );
7046
+ return;
7047
+ }
7048
+ if (process.env.GITHUB_ACTIONS === "true") {
7049
+ throw new Error("Convex backend is required for the run index in GitHub Actions");
7050
+ }
7051
+ upsertRunIndexRowBestEffort(config, cwd, row);
7052
+ }
6987
7053
  function stageRunIndexFinalization(data, row) {
6988
7054
  if (!row) return;
6989
7055
  const rows = stagedRunIndexRows(data);
6990
7056
  rows[row.id] = row;
6991
7057
  }
6992
- function finalizeStagedRunIndexRows(config, cwd, data, result) {
7058
+ async function finalizeStagedRunIndexRowsAsync(config, cwd, data, result) {
6993
7059
  const rows = stagedRunIndexRows(data);
6994
7060
  for (const row of Object.values(rows)) {
6995
- upsertRunIndexRowBestEffort(config, cwd, finalizedRunIndexRow(row, result));
7061
+ await upsertRunIndexRowBestEffortAsync(config, cwd, finalizedRunIndexRow(row, result));
6996
7062
  }
6997
7063
  data[STAGED_RUN_INDEX_ROWS_KEY] = {};
6998
7064
  }
@@ -7190,6 +7256,10 @@ function isConflict(err) {
7190
7256
  const msg = err instanceof Error ? err.message : String(err);
7191
7257
  return /HTTP 409/i.test(msg) || /HTTP 422/i.test(msg) || /does not match|is at|but expected/i.test(msg);
7192
7258
  }
7259
+ function tenantIdForRun(config) {
7260
+ if (config.github?.owner && config.github.repo) return `${config.github.owner}/${config.github.repo}`;
7261
+ return process.env.GITHUB_REPOSITORY?.trim() || void 0;
7262
+ }
7193
7263
  function recordValue2(value) {
7194
7264
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
7195
7265
  }
@@ -7206,6 +7276,7 @@ var RUN_INDEX_PATH, MAX_RUNS, STAGED_RUN_INDEX_ROWS_KEY;
7206
7276
  var init_runIndex = __esm({
7207
7277
  "src/runIndex.ts"() {
7208
7278
  "use strict";
7279
+ init_state_backend();
7209
7280
  init_stateRepo();
7210
7281
  RUN_INDEX_PATH = "runs/index.json";
7211
7282
  MAX_RUNS = 200;
@@ -8195,9 +8266,14 @@ async function flushGoalRunLogEventsAsync(config, cwd, data) {
8195
8266
  for (const [goalId, log2] of Object.entries(goalRunLogs(data))) {
8196
8267
  if (log2.events.length === 0) continue;
8197
8268
  const enrichedEvents = log2.events.map((event) => enrichGoalRunLogEvent(config, data, log2.path, event));
8269
+ const row = runIndexRowFromGoalEvents(goalId, log2.path, enrichedEvents);
8270
+ if (!row) continue;
8198
8271
  for (const event of enrichedEvents) {
8199
8272
  await backend.appendDailyLog(tenantId, "events", event.time.slice(0, 10), event);
8273
+ await backend.appendRunEvent(tenantId, row.id, goalId, event, event.time);
8200
8274
  }
8275
+ await upsertRunIndexRowBestEffortAsync(config, cwd, row);
8276
+ stageRunIndexFinalization(data, row);
8201
8277
  log2.events = [];
8202
8278
  }
8203
8279
  }
@@ -15010,6 +15086,30 @@ function listCompanyIntents(config, cwd) {
15010
15086
  }
15011
15087
  return records.sort((a, b) => a.intent.priority - b.intent.priority || a.id.localeCompare(b.id));
15012
15088
  }
15089
+ function backendTenant2(config) {
15090
+ const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
15091
+ const repo = config.github?.repo?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[1]?.trim();
15092
+ return owner && repo ? `${owner}/${repo}` : null;
15093
+ }
15094
+ function backendEnabled2(config) {
15095
+ return Boolean(process.env.CONVEX_URL?.trim() && process.env.KODY_SERVICE_KEY?.trim() && backendTenant2(config));
15096
+ }
15097
+ function backendRequired2() {
15098
+ return process.env.GITHUB_ACTIONS === "true";
15099
+ }
15100
+ async function listCompanyIntentsAsync(config, cwd) {
15101
+ const tenantId = backendTenant2(config);
15102
+ if (backendEnabled2(config) && tenantId) {
15103
+ const records = await createStateBackendFromEnv().listIntents(tenantId);
15104
+ return records.filter((record) => isCompanyIntentId(record.intentId)).map((record) => ({
15105
+ id: record.intentId,
15106
+ path: `convex:intents/${record.intentId}`,
15107
+ intent: normalizeCompanyIntent(`convex:intents/${record.intentId}`, record.intent)
15108
+ })).sort((a, b) => a.intent.priority - b.intent.priority || a.id.localeCompare(b.id));
15109
+ }
15110
+ if (backendRequired2()) throw new Error("Convex backend is required for company intents in GitHub Actions");
15111
+ return listCompanyIntents(config, cwd);
15112
+ }
15013
15113
  async function listCompanyPortfolio(config, cwd) {
15014
15114
  const goals = [];
15015
15115
  for (const id of await listGoalStateIdsAsync(config, cwd)) {
@@ -15075,6 +15175,7 @@ var init_companyIntent = __esm({
15075
15175
  "use strict";
15076
15176
  init_state2();
15077
15177
  init_stateStore();
15178
+ init_state_backend();
15078
15179
  init_stateRepo();
15079
15180
  SLUG_RE = /^[a-z][a-z0-9-]{0,63}$/;
15080
15181
  }
@@ -15087,7 +15188,7 @@ var init_loadCompanyIntents = __esm({
15087
15188
  "use strict";
15088
15189
  init_companyIntent();
15089
15190
  loadCompanyIntents = async (ctx) => {
15090
- const intents = listCompanyIntents(ctx.config, ctx.cwd);
15191
+ const intents = await listCompanyIntentsAsync(ctx.config, ctx.cwd);
15091
15192
  const active = intents.filter((record) => record.intent.status === "active");
15092
15193
  ctx.data.companyIntents = intents;
15093
15194
  ctx.data.companyActiveIntents = active;
@@ -21005,8 +21106,8 @@ async function runImplementation(profileName, input) {
21005
21106
  const stageStartedAt = Date.now();
21006
21107
  let finishRunIndex = null;
21007
21108
  emitEvent(input.cwd, { implementation: profileName, kind: "stage_start" });
21008
- const finishAndEnd = (out) => {
21009
- finishRunIndex?.(out);
21109
+ const finishAndEnd = async (out) => {
21110
+ await finishRunIndex?.(out);
21010
21111
  emitEvent(input.cwd, {
21011
21112
  implementation: profileName,
21012
21113
  kind: "stage_end",
@@ -21097,7 +21198,7 @@ async function runImplementation(profileName, input) {
21097
21198
  if (reasoningEffort) ctx.data.jobReasoningEffort = reasoningEffort;
21098
21199
  const runIndexStartedAt = new Date(stageStartedAt).toISOString();
21099
21200
  if (!input.skipConfig) {
21100
- upsertRunIndexRowBestEffort(
21201
+ await upsertRunIndexRowBestEffortAsync(
21101
21202
  config,
21102
21203
  input.cwd,
21103
21204
  runIndexRowFromJobContext({
@@ -21109,10 +21210,10 @@ async function runImplementation(profileName, input) {
21109
21210
  updatedAt: runIndexStartedAt
21110
21211
  })
21111
21212
  );
21112
- finishRunIndex = (out) => {
21213
+ finishRunIndex = async (out) => {
21113
21214
  const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
21114
21215
  const status = statusFromExitCode(out.exitCode);
21115
- upsertRunIndexRowBestEffort(
21216
+ await upsertRunIndexRowBestEffortAsync(
21116
21217
  config,
21117
21218
  input.cwd,
21118
21219
  runIndexRowFromJobContext({
@@ -21125,7 +21226,7 @@ async function runImplementation(profileName, input) {
21125
21226
  reason: out.reason
21126
21227
  })
21127
21228
  );
21128
- finalizeStagedRunIndexRows(config, input.cwd, ctx.data, {
21229
+ await finalizeStagedRunIndexRowsAsync(config, input.cwd, ctx.data, {
21129
21230
  status,
21130
21231
  updatedAt: finishedAt,
21131
21232
  reason: out.reason
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.393",
3
+ "version": "0.4.395",
4
4
  "description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -12,6 +12,28 @@
12
12
  "templates",
13
13
  "kody.config.schema.json"
14
14
  ],
15
+ "scripts": {
16
+ "kody:run": "tsx bin/kody.ts",
17
+ "serve": "tsx bin/kody.ts serve",
18
+ "serve:vscode": "tsx bin/kody.ts serve vscode",
19
+ "serve:claude": "tsx bin/kody.ts serve claude",
20
+ "clean:dist": "node scripts/clean-dist.cjs",
21
+ "build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
22
+ "check:modularity": "tsx scripts/check-script-modularity.ts",
23
+ "pretest": "pnpm check:modularity",
24
+ "test": "vitest run tests/unit tests/int --coverage",
25
+ "posttest": "tsx scripts/check-coverage-floor.ts",
26
+ "test:smoke": "vitest run tests/smoke --no-coverage",
27
+ "test:e2e": "vitest run tests/e2e --no-coverage",
28
+ "test:all": "vitest run tests --no-coverage",
29
+ "typecheck": "tsc --noEmit",
30
+ "lint": "biome check",
31
+ "lint:fix": "biome check --write",
32
+ "format": "biome format --write",
33
+ "verify:package": "node scripts/verify-package-tarball.cjs",
34
+ "brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner",
35
+ "prepublishOnly": "pnpm typecheck && vitest run tests/unit tests/int --no-coverage && pnpm build && pnpm verify:package"
36
+ },
15
37
  "dependencies": {
16
38
  "@actions/cache": "^6.0.0",
17
39
  "@anthropic-ai/claude-agent-sdk": "0.2.119",
@@ -36,26 +58,5 @@
36
58
  "url": "git+https://github.com/aharonyaircohen/kody-engine.git"
37
59
  },
38
60
  "homepage": "https://github.com/aharonyaircohen/kody-engine",
39
- "bugs": "https://github.com/aharonyaircohen/kody-engine/issues",
40
- "scripts": {
41
- "kody:run": "tsx bin/kody.ts",
42
- "serve": "tsx bin/kody.ts serve",
43
- "serve:vscode": "tsx bin/kody.ts serve vscode",
44
- "serve:claude": "tsx bin/kody.ts serve claude",
45
- "clean:dist": "node scripts/clean-dist.cjs",
46
- "build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
47
- "check:modularity": "tsx scripts/check-script-modularity.ts",
48
- "pretest": "pnpm check:modularity",
49
- "test": "vitest run tests/unit tests/int --coverage",
50
- "posttest": "tsx scripts/check-coverage-floor.ts",
51
- "test:smoke": "vitest run tests/smoke --no-coverage",
52
- "test:e2e": "vitest run tests/e2e --no-coverage",
53
- "test:all": "vitest run tests --no-coverage",
54
- "typecheck": "tsc --noEmit",
55
- "lint": "biome check",
56
- "lint:fix": "biome check --write",
57
- "format": "biome format --write",
58
- "verify:package": "node scripts/verify-package-tarball.cjs",
59
- "brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner"
60
- }
61
- }
61
+ "bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
62
+ }