@kody-ade/kody-engine 0.4.413 → 0.4.415

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 +279 -64
  2. package/package.json +2 -2
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.413",
18
+ version: "0.4.415",
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",
@@ -50,9 +50,9 @@ var init_package = __esm({
50
50
  prepublishOnly: "pnpm typecheck && vitest run tests/unit tests/int --no-coverage && pnpm build && pnpm verify:package"
51
51
  },
52
52
  dependencies: {
53
- "@kody-ade/agency-domain": "0.1.1",
54
53
  "@actions/cache": "^6.0.0",
55
54
  "@anthropic-ai/claude-agent-sdk": "0.2.119",
55
+ "@kody-ade/agency-domain": "0.4.0",
56
56
  "@modelcontextprotocol/sdk": "^1.29.0",
57
57
  convex: "^1.17.0",
58
58
  zod: "^4.0.0"
@@ -1990,14 +1990,14 @@ function resolveImplementationCandidates(name, roots = getImplementationRoots())
1990
1990
  function listCapabilityActions(projectCapabilitiesRoot = getProjectCapabilitiesRoot()) {
1991
1991
  const seen = /* @__PURE__ */ new Set();
1992
1992
  const out = [];
1993
- const add = (action) => {
1993
+ const add2 = (action) => {
1994
1994
  if (!isSafeName(action.action) || !isSafeName(action.capability) || !isSafeName(action.implementation)) return;
1995
1995
  if (seen.has(action.action)) return;
1996
1996
  seen.add(action.action);
1997
1997
  out.push(action);
1998
1998
  };
1999
- for (const action of listFolderCapabilityActions(projectCapabilitiesRoot, "project-folder")) add(action);
2000
- for (const action of listBuiltinCapabilityActions(getBuiltinCapabilitiesRoot())) add(action);
1999
+ for (const action of listFolderCapabilityActions(projectCapabilitiesRoot, "project-folder")) add2(action);
2000
+ for (const action of listBuiltinCapabilityActions(getBuiltinCapabilitiesRoot())) add2(action);
2001
2001
  return out.sort((a, b) => a.action.localeCompare(b.action));
2002
2002
  }
2003
2003
  function resolveCapabilityAction(action, projectCapabilitiesRoot = getProjectCapabilitiesRoot()) {
@@ -2505,6 +2505,22 @@ function createStateBackendFromEnv(env = process.env, client) {
2505
2505
  ...runId ? { runId: requireNonEmpty(runId, "runId") } : {}
2506
2506
  });
2507
2507
  },
2508
+ async createAgencyModelRun(tenantId2, subjectType, subjectId, run, now) {
2509
+ await transport.mutation(anyApi.agencyModel.createRunRecord, {
2510
+ tenantId: requireTenant(tenantId2),
2511
+ subjectType,
2512
+ subjectId: requireNonEmpty(subjectId, "subjectId"),
2513
+ run,
2514
+ now
2515
+ });
2516
+ },
2517
+ async finishAgencyModelRun(tenantId2, run, now) {
2518
+ await transport.mutation(anyApi.agencyModel.finishRunRecord, {
2519
+ tenantId: requireTenant(tenantId2),
2520
+ run,
2521
+ now
2522
+ });
2523
+ },
2508
2524
  async appendRunEvent(tenantId2, runId, goalId, event, time) {
2509
2525
  await transport.mutation(anyApi.runEvents.append, {
2510
2526
  tenantId: requireTenant(tenantId2),
@@ -12969,6 +12985,7 @@ var init_dispatchClassified = __esm({
12969
12985
 
12970
12986
  // src/goal/agencyModelRepository.ts
12971
12987
  import {
12988
+ createAgentDefinition,
12972
12989
  createCapabilityDefinition,
12973
12990
  createGoalDefinition,
12974
12991
  createGoalState,
@@ -12977,7 +12994,8 @@ import {
12977
12994
  createLoopState,
12978
12995
  createOperationDefinition,
12979
12996
  createRunOutput,
12980
- createWorkflowDefinition
12997
+ createWorkflowDefinition,
12998
+ relationshipIssues
12981
12999
  } from "@kody-ade/agency-domain";
12982
13000
  function goalProgressFromOutputs(definition, outputs) {
12983
13001
  const required2 = definition.objective.requiredEvidence;
@@ -12987,28 +13005,65 @@ function goalProgressFromOutputs(definition, outputs) {
12987
13005
  );
12988
13006
  return required2.filter((key) => satisfied.has(key)).length / required2.length;
12989
13007
  }
12990
- function validateAllDefinitions(documents) {
12991
- for (const document of documents) {
12992
- if (document.schemaVersion !== 1) throw new Error(`Unsupported Agency Definition schema: ${document.schemaVersion}`);
12993
- if (document.kind === "intent") createIntentDefinition(document.data);
12994
- else if (document.kind === "operation") createOperationDefinition(document.data);
12995
- else if (document.kind === "goal") createGoalDefinition(document.data);
12996
- else if (document.kind === "loop") createLoopDefinition(document.data);
12997
- else if (document.kind === "workflow") createWorkflowDefinition(document.data);
12998
- else createCapabilityDefinition(document.data);
12999
- }
13000
- }
13001
- function parseManagedDefinition(document) {
13002
- return document.kind === "goal" ? createGoalDefinition(document.data) : createLoopDefinition(document.data);
13003
- }
13004
- function parseState(document, definition) {
13008
+ function parseState(document, definition, kind) {
13005
13009
  if (!document) return null;
13006
13010
  if (document.schemaVersion !== 1) throw new Error(`Unsupported Agency State schema: ${document.schemaVersion}`);
13007
- if (document.kind !== definition.kind || document.definitionId !== definition.recordId) {
13008
- throw new Error(`Agency State does not match Definition: ${definition.recordId}`);
13011
+ if (document.kind !== kind || document.definitionId !== definition.id) {
13012
+ throw new Error(`Agency State does not match Definition: ${definition.id}`);
13009
13013
  }
13010
13014
  return document.kind === "goal" ? createGoalState(document.data) : createLoopState(document.data);
13011
13015
  }
13016
+ function emptyCatalog() {
13017
+ return {
13018
+ intents: /* @__PURE__ */ new Map(),
13019
+ operations: /* @__PURE__ */ new Map(),
13020
+ goals: /* @__PURE__ */ new Map(),
13021
+ loops: /* @__PURE__ */ new Map(),
13022
+ workflows: /* @__PURE__ */ new Map(),
13023
+ capabilities: /* @__PURE__ */ new Map(),
13024
+ agents: /* @__PURE__ */ new Map()
13025
+ };
13026
+ }
13027
+ function addDefinition(catalog, document) {
13028
+ if (document.schemaVersion !== 1) throw new Error(`Unsupported Agency Definition schema: ${document.schemaVersion}`);
13029
+ if (document.kind === "intent") add(catalog.intents, createIntentDefinition(document.data), document.recordId);
13030
+ else if (document.kind === "operation") add(catalog.operations, createOperationDefinition(document.data), document.recordId);
13031
+ else if (document.kind === "goal") add(catalog.goals, createGoalDefinition(document.data), document.recordId);
13032
+ else if (document.kind === "loop") add(catalog.loops, createLoopDefinition(document.data), document.recordId);
13033
+ else if (document.kind === "workflow") add(catalog.workflows, createWorkflowDefinition(document.data), document.recordId);
13034
+ else if (document.kind === "capability") add(catalog.capabilities, createCapabilityDefinition(document.data), document.recordId);
13035
+ else add(catalog.agents, createAgentDefinition(document.data), document.recordId);
13036
+ }
13037
+ function add(collection, definition, revision) {
13038
+ const mutable = collection;
13039
+ if (mutable.has(definition.id)) throw new Error(`Duplicate Agency Definition: ${definition.id}`);
13040
+ mutable.set(definition.id, { definition, revision });
13041
+ }
13042
+ function validateRelationships(catalog) {
13043
+ const relationshipCatalog = {
13044
+ operations: [...catalog.operations.keys()],
13045
+ goals: [...catalog.goals.keys()],
13046
+ workflows: [...catalog.workflows.keys()],
13047
+ capabilities: [...catalog.capabilities.keys()]
13048
+ };
13049
+ const issues = [...catalog.goals.values(), ...catalog.loops.values()].flatMap(
13050
+ ({ definition }) => relationshipIssues(definition, relationshipCatalog).map((issue2) => `${definition.id}: ${issue2}`)
13051
+ );
13052
+ for (const { definition } of catalog.operations.values()) {
13053
+ for (const intentId of definition.intentIds) {
13054
+ if (!catalog.intents.has(intentId)) issues.push(`${definition.id}: Missing Intent "${intentId}"`);
13055
+ }
13056
+ }
13057
+ for (const { definition } of catalog.workflows.values()) {
13058
+ for (const step of definition.steps) {
13059
+ if (!catalog.capabilities.has(step.capabilityRef.id)) {
13060
+ issues.push(`${definition.id}: Missing Capability "${step.capabilityRef.id}"`);
13061
+ }
13062
+ }
13063
+ }
13064
+ if (issues.length > 0) throw new Error(`Invalid Agency relationships:
13065
+ ${issues.join("\n")}`);
13066
+ }
13012
13067
  var AgencyModelRepository;
13013
13068
  var init_agencyModelRepository = __esm({
13014
13069
  "src/goal/agencyModelRepository.ts"() {
@@ -13020,19 +13075,31 @@ var init_agencyModelRepository = __esm({
13020
13075
  }
13021
13076
  backend;
13022
13077
  tenantId;
13023
- async listManagedWork() {
13024
- const documents = await this.backend.listAgencyDefinitions(this.tenantId);
13025
- validateAllDefinitions(documents);
13026
- const managed = documents.filter(
13027
- (document) => document.kind === "goal" || document.kind === "loop"
13028
- );
13078
+ async listManagedWork(catalog) {
13079
+ const definitions = catalog ?? await this.loadCatalog();
13080
+ const managed = [
13081
+ ...Array.from(definitions.goals.values(), ({ definition, revision }) => ({ definition, revision, kind: "goal" })),
13082
+ ...Array.from(definitions.loops.values(), ({ definition, revision }) => ({ definition, revision, kind: "loop" }))
13083
+ ];
13029
13084
  return Promise.all(
13030
- managed.map(async (document) => ({
13031
- definition: parseManagedDefinition(document),
13032
- state: parseState(await this.backend.getAgencyState(this.tenantId, document.recordId), document)
13085
+ managed.map(async (record2) => ({
13086
+ definition: record2.definition,
13087
+ revision: record2.revision,
13088
+ state: parseState(
13089
+ await this.backend.getAgencyState(this.tenantId, record2.definition.id),
13090
+ record2.definition,
13091
+ record2.kind
13092
+ )
13033
13093
  }))
13034
13094
  );
13035
13095
  }
13096
+ async loadCatalog() {
13097
+ const documents = await this.backend.listAgencyDefinitions(this.tenantId);
13098
+ const catalog = emptyCatalog();
13099
+ for (const document of documents) addDefinition(catalog, document);
13100
+ validateRelationships(catalog);
13101
+ return catalog;
13102
+ }
13036
13103
  async saveState(state, kind, updatedAt) {
13037
13104
  const data = kind === "goal" ? createGoalState(state) : createLoopState(state);
13038
13105
  await this.backend.putAgencyState(this.tenantId, state.definitionId, kind, 1, data, updatedAt);
@@ -13117,13 +13184,105 @@ var init_triggerDispatcher = __esm({
13117
13184
  }
13118
13185
  });
13119
13186
 
13187
+ // src/goal/policyResolver.ts
13188
+ import { createHash as createHash2 } from "crypto";
13189
+ function resolveDispatchPolicy(input) {
13190
+ const operation = input.catalog.operations.get(input.owner.definition.operationId);
13191
+ if (!operation) throw new Error(`Dispatch blocked: Operation "${input.owner.definition.operationId}" is unresolved`);
13192
+ if (operation.definition.intentIds.length === 0) {
13193
+ throw new Error(`Dispatch blocked: Operation "${operation.definition.id}" has no Intent`);
13194
+ }
13195
+ const intents = operation.definition.intentIds.map((intentId) => {
13196
+ const intent = input.catalog.intents.get(intentId);
13197
+ if (!intent) throw new Error(`Dispatch blocked: Intent "${intentId}" is unresolved`);
13198
+ return intent;
13199
+ });
13200
+ const policy = mergePolicies(intents.map(({ definition }) => definition.policy));
13201
+ const constraints = intents.flatMap(({ definition }) => definition.constraints);
13202
+ assertAuthorized(policy, constraints, input.target, input.approved === true);
13203
+ const snapshotValue = { policy, constraints };
13204
+ return {
13205
+ snapshot: {
13206
+ hash: createHash2("sha256").update(stableJson(snapshotValue)).digest("hex"),
13207
+ ...snapshotValue
13208
+ },
13209
+ operation,
13210
+ intents,
13211
+ trace: [
13212
+ pinned("trigger" in input.owner.definition ? "loop" : "goal", input.owner),
13213
+ input.target
13214
+ ]
13215
+ };
13216
+ }
13217
+ function mergePolicies(policies) {
13218
+ const approvalOrder = ["none", "risky-actions", "all-actions"];
13219
+ return {
13220
+ approval: policies.reduce(
13221
+ (strictest, policy) => approvalOrder.indexOf(policy.approval) > approvalOrder.indexOf(strictest) ? policy.approval : strictest,
13222
+ "none"
13223
+ ),
13224
+ authority: {
13225
+ allow: intersect(policies.map(({ authority }) => authority.allow)),
13226
+ deny: unique(policies.flatMap(({ authority }) => authority.deny))
13227
+ },
13228
+ budget: {
13229
+ maxRuns: Math.min(...policies.map(({ budget }) => budget.maxRuns)),
13230
+ maxTokens: Math.min(...policies.map(({ budget }) => budget.maxTokens)),
13231
+ maxCostUsd: Math.min(...policies.map(({ budget }) => budget.maxCostUsd)),
13232
+ maxDurationSeconds: Math.min(...policies.map(({ budget }) => budget.maxDurationSeconds))
13233
+ },
13234
+ maxConcurrentRuns: Math.min(...policies.map(({ maxConcurrentRuns }) => maxConcurrentRuns)),
13235
+ riskyActions: unique(policies.flatMap(({ riskyActions }) => riskyActions))
13236
+ };
13237
+ }
13238
+ function assertAuthorized(policy, constraints, target, approved) {
13239
+ const action = `${target.kind}:${target.id}`;
13240
+ const matches = (patterns) => patterns.some((pattern) => pattern === "*" || pattern === target.id || pattern === action);
13241
+ if (matches(policy.authority.deny)) throw new Error(`Dispatch blocked: authority denies "${action}"`);
13242
+ if (!matches(policy.authority.allow)) throw new Error(`Dispatch blocked: authority does not allow "${action}"`);
13243
+ const matchingConstraints = constraints.filter(({ actions }) => matches(actions));
13244
+ const denied = matchingConstraints.find(({ effect }) => effect === "deny");
13245
+ if (denied) throw new Error(`Dispatch blocked by constraint "${denied.id}": ${denied.rule}`);
13246
+ const requiresApproval = policy.approval === "all-actions" || policy.approval === "risky-actions" && matches(policy.riskyActions) || matchingConstraints.some(({ effect }) => effect === "require-approval");
13247
+ if (requiresApproval && !approved) throw new Error(`Dispatch blocked: approval is required for "${action}"`);
13248
+ }
13249
+ function pinned(kind, record2) {
13250
+ return { kind, id: record2.definition.id, revision: record2.revision };
13251
+ }
13252
+ function intersect(groups) {
13253
+ if (groups.length === 0) return [];
13254
+ if (groups.every((group) => group.includes("*"))) return ["*"];
13255
+ const candidates = unique(groups.flatMap((group) => group.filter((item) => item !== "*")));
13256
+ return candidates.filter((candidate) => groups.every((group) => group.includes("*") || group.includes(candidate)));
13257
+ }
13258
+ function unique(values) {
13259
+ return [...new Set(values)].sort();
13260
+ }
13261
+ function stableJson(value) {
13262
+ if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
13263
+ if (value && typeof value === "object") {
13264
+ return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson(item)}`).join(",")}}`;
13265
+ }
13266
+ return JSON.stringify(value);
13267
+ }
13268
+ var init_policyResolver = __esm({
13269
+ "src/goal/policyResolver.ts"() {
13270
+ "use strict";
13271
+ }
13272
+ });
13273
+
13120
13274
  // src/scripts/dispatchAgencyLoops.ts
13121
- import { createLoopState as createLoopState2 } from "@kody-ade/agency-domain";
13275
+ import { randomUUID } from "crypto";
13276
+ import {
13277
+ createLoopState as createLoopState2,
13278
+ createRun
13279
+ } from "@kody-ade/agency-domain";
13122
13280
  async function dispatchAgencyLoopsWith(input) {
13123
13281
  const repository = new AgencyModelRepository(input.backend, input.tenantId);
13124
- const records = await repository.listManagedWork();
13125
- const loops = records.filter(
13126
- (record2) => "trigger" in record2.definition
13282
+ const catalog = await repository.loadCatalog();
13283
+ const records = await repository.listManagedWork(catalog);
13284
+ const loops = records.flatMap(
13285
+ (record2) => "trigger" in record2.definition ? [{ ...record2, definition: record2.definition, state: record2.state }] : []
13127
13286
  );
13128
13287
  const results = [];
13129
13288
  for (const record2 of loops) {
@@ -13142,6 +13301,27 @@ async function dispatchAgencyLoopsWith(input) {
13142
13301
  results.push({ loopId: record2.definition.id, decision: "skipped", reason: decision.reason });
13143
13302
  continue;
13144
13303
  }
13304
+ let target;
13305
+ let policy;
13306
+ try {
13307
+ target = resolveTarget(record2.definition, catalog);
13308
+ policy = resolveDispatchPolicy({
13309
+ catalog,
13310
+ owner: { definition: record2.definition, revision: record2.revision },
13311
+ target: target.reference
13312
+ });
13313
+ } catch (error) {
13314
+ const reason = error instanceof Error ? error.message : String(error);
13315
+ await input.backend.recordSkippedAgencyDispatch(
13316
+ input.tenantId,
13317
+ decision.idempotencyKey,
13318
+ record2.definition.id,
13319
+ { kind: "skip", reason, scheduledAt: decision.scheduledAt },
13320
+ now
13321
+ );
13322
+ results.push({ loopId: record2.definition.id, decision: "skipped", reason });
13323
+ continue;
13324
+ }
13145
13325
  const leaseUntil = new Date(input.now.getTime() + 15 * 6e4).toISOString();
13146
13326
  const reservation = await input.backend.reserveAgencyDispatch(
13147
13327
  input.tenantId,
@@ -13164,14 +13344,40 @@ async function dispatchAgencyLoopsWith(input) {
13164
13344
  updatedAt: now
13165
13345
  });
13166
13346
  await repository.saveState(runningState, "loop", now);
13347
+ const runId = `run-${randomUUID()}`;
13348
+ const correlationId = `corr-${randomUUID()}`;
13349
+ const activeRun = createRun({
13350
+ id: runId,
13351
+ status: "running",
13352
+ origin: { kind: "loop", id: record2.definition.id, revision: record2.revision },
13353
+ target: target.reference,
13354
+ trace: [policy.trace[0], ...target.intermediate, target.reference],
13355
+ effectivePolicy: policy.snapshot,
13356
+ correlationId,
13357
+ startedAt: now
13358
+ });
13167
13359
  try {
13168
- const output = await input.run(jobForTarget(record2.definition));
13360
+ await input.backend.createAgencyModelRun(
13361
+ input.tenantId,
13362
+ target.reference.kind,
13363
+ target.reference.id,
13364
+ activeRun,
13365
+ now
13366
+ );
13367
+ const output = await input.run(target.job);
13169
13368
  const succeeded = output.exitCode === 0;
13369
+ const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
13370
+ await input.backend.finishAgencyModelRun(
13371
+ input.tenantId,
13372
+ terminalRun(activeRun, succeeded ? "succeeded" : "failed", finishedAt),
13373
+ finishedAt
13374
+ );
13170
13375
  await input.backend.finishAgencyDispatch(
13171
13376
  input.tenantId,
13172
13377
  decision.idempotencyKey,
13173
13378
  succeeded ? "dispatched" : "failed",
13174
- (/* @__PURE__ */ new Date()).toISOString()
13379
+ finishedAt,
13380
+ runId
13175
13381
  );
13176
13382
  await repository.saveState(
13177
13383
  createLoopState2({
@@ -13190,26 +13396,34 @@ async function dispatchAgencyLoopsWith(input) {
13190
13396
  });
13191
13397
  } catch (error) {
13192
13398
  const reason = error instanceof Error ? error.message : String(error);
13193
- await input.backend.finishAgencyDispatch(input.tenantId, decision.idempotencyKey, "failed", (/* @__PURE__ */ new Date()).toISOString());
13399
+ const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
13400
+ await input.backend.finishAgencyModelRun(input.tenantId, terminalRun(activeRun, "failed", finishedAt), finishedAt).catch(() => void 0);
13401
+ await input.backend.finishAgencyDispatch(input.tenantId, decision.idempotencyKey, "failed", finishedAt, runId);
13194
13402
  results.push({ loopId: record2.definition.id, decision: "failed", reason });
13195
13403
  }
13196
13404
  }
13197
13405
  return results;
13198
13406
  }
13199
- function jobForTarget(loop) {
13200
- if (loop.targetRef.kind === "workflow") {
13201
- return { workflow: loop.targetRef.id, cliArgs: {}, flavor: "scheduled" };
13202
- }
13203
- if (loop.targetRef.kind === "capability") {
13204
- return { capability: loop.targetRef.id, cliArgs: {}, flavor: "scheduled" };
13205
- }
13407
+ function resolveTarget(loop, catalog) {
13408
+ const goal = loop.targetRef.kind === "goal" ? catalog.goals.get(loop.targetRef.id) : void 0;
13409
+ if (loop.targetRef.kind === "goal" && !goal) throw new Error(`Loop target Goal is missing: ${loop.targetRef.id}`);
13410
+ if (goal && goal.definition.operationId !== loop.operationId) {
13411
+ throw new Error(`Loop and target Goal must belong to the same Operation`);
13412
+ }
13413
+ const target = goal?.definition.executionRef ?? loop.targetRef;
13414
+ if (target.kind === "goal") throw new Error("Nested Goal target is invalid");
13415
+ const record2 = target.kind === "workflow" ? catalog.workflows.get(target.id) : catalog.capabilities.get(target.id);
13416
+ if (!record2) throw new Error(`Loop execution target is missing: ${target.kind}:${target.id}`);
13417
+ const reference = { kind: target.kind, id: target.id, revision: record2.revision };
13206
13418
  return {
13207
- capability: "goal-manager",
13208
- implementation: "goal-manager",
13209
- cliArgs: { goal: loop.targetRef.id },
13210
- flavor: "scheduled"
13419
+ reference,
13420
+ intermediate: goal ? [{ kind: "goal", id: goal.definition.id, revision: goal.revision }] : [],
13421
+ job: target.kind === "workflow" ? { workflow: target.id, cliArgs: {}, flavor: "scheduled" } : { capability: target.id, cliArgs: {}, flavor: "scheduled" }
13211
13422
  };
13212
13423
  }
13424
+ function terminalRun(active, status, finishedAt) {
13425
+ return createRun({ ...active, status, finishedAt });
13426
+ }
13213
13427
  function repositoryTenant(config) {
13214
13428
  const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
13215
13429
  const repo = config.github?.repo?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[1]?.trim();
@@ -13221,6 +13435,7 @@ var init_dispatchAgencyLoops = __esm({
13221
13435
  "use strict";
13222
13436
  init_agencyModelRepository();
13223
13437
  init_triggerDispatcher();
13438
+ init_policyResolver();
13224
13439
  init_job();
13225
13440
  init_state_backend();
13226
13441
  dispatchAgencyLoops = async (ctx) => {
@@ -15079,9 +15294,9 @@ var init_kodyVariables = __esm({
15079
15294
  });
15080
15295
 
15081
15296
  // src/backendVault.ts
15082
- import { createDecipheriv, createHash as createHash2 } from "crypto";
15297
+ import { createDecipheriv, createHash as createHash3 } from "crypto";
15083
15298
  function cacheKey(owner, repo, masterKey) {
15084
- const keyHash = createHash2("sha256").update(masterKey).digest("hex").slice(0, 16);
15299
+ const keyHash = createHash3("sha256").update(masterKey).digest("hex").slice(0, 16);
15085
15300
  return `${owner}/${repo}:${keyHash}`.toLowerCase();
15086
15301
  }
15087
15302
  function decryptVault(payload, masterKey) {
@@ -15730,7 +15945,7 @@ var init_notifyTerminal = __esm({
15730
15945
  });
15731
15946
 
15732
15947
  // src/scripts/openAgencyModelReviewPr.ts
15733
- import { createHash as createHash3 } from "crypto";
15948
+ import { createHash as createHash4 } from "crypto";
15734
15949
  function parseAgencyModelProposal(raw) {
15735
15950
  const text2 = raw.trim();
15736
15951
  const jsonText = (text2.match(/^```(?:json)?\s*\n([\s\S]*?)\n```$/i)?.[1] ?? text2).trim();
@@ -15782,7 +15997,7 @@ function normalizeBundleFiles(bundle) {
15782
15997
  });
15783
15998
  }
15784
15999
  function buildProposalId(issueNumber, bundle, sourceLabel) {
15785
- const digest = createHash3("sha256").update(JSON.stringify({ issueNumber, sourceLabel, title: bundle.title, files: normalizeBundleFiles(bundle) })).digest("hex").slice(0, 16);
16000
+ const digest = createHash4("sha256").update(JSON.stringify({ issueNumber, sourceLabel, title: bundle.title, files: normalizeBundleFiles(bundle) })).digest("hex").slice(0, 16);
15786
16001
  return `issue-${issueNumber}-${digest}`;
15787
16002
  }
15788
16003
  function isDryRun(ctx) {
@@ -17854,9 +18069,9 @@ var init_runFlow = __esm({
17854
18069
  });
17855
18070
 
17856
18071
  // src/scripts/previewBuildHelpers.ts
17857
- import { createDecipheriv as createDecipheriv2, createHash as createHash4, hkdfSync as hkdfSync2 } from "crypto";
18072
+ import { createDecipheriv as createDecipheriv2, createHash as createHash5, hkdfSync as hkdfSync2 } from "crypto";
17858
18073
  function shortHash(s) {
17859
- return createHash4("sha256").update(s).digest("hex").slice(0, 6);
18074
+ return createHash5("sha256").update(s).digest("hex").slice(0, 6);
17860
18075
  }
17861
18076
  function previewAppName(repo, pr) {
17862
18077
  const [owner, name] = repo.split("/");
@@ -17889,7 +18104,7 @@ function formatPreviewComment(args) {
17889
18104
  ].join("\n");
17890
18105
  }
17891
18106
  function defaultImageTag(repo, ref) {
17892
- return createHash4("sha256").update(`${repo}@${ref}`).digest("hex").slice(0, 12);
18107
+ return createHash5("sha256").update(`${repo}@${ref}`).digest("hex").slice(0, 12);
17893
18108
  }
17894
18109
  var init_previewBuildHelpers = __esm({
17895
18110
  "src/scripts/previewBuildHelpers.ts"() {
@@ -25314,7 +25529,7 @@ init_config();
25314
25529
  init_fetchRepoMcp();
25315
25530
 
25316
25531
  // src/servers/mcpHttpServer.ts
25317
- import { randomUUID } from "crypto";
25532
+ import { randomUUID as randomUUID2 } from "crypto";
25318
25533
  import { createServer as createServer4 } from "http";
25319
25534
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
25320
25535
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
@@ -25323,7 +25538,7 @@ function buildMcpHttpServer(opts) {
25323
25538
  const transports = /* @__PURE__ */ new Map();
25324
25539
  for (const route of opts.routes) {
25325
25540
  const transport = new StreamableHTTPServerTransport({
25326
- sessionIdGenerator: () => randomUUID()
25541
+ sessionIdGenerator: () => randomUUID2()
25327
25542
  });
25328
25543
  transports.set(route.path, transport);
25329
25544
  routes.set(route.path, route.name);
@@ -25895,7 +26110,7 @@ init_config();
25895
26110
 
25896
26111
  // src/definition-hydration.ts
25897
26112
  init_state_backend();
25898
- import { createHash as createHash5 } from "crypto";
26113
+ import { createHash as createHash6 } from "crypto";
25899
26114
  import * as fs50 from "fs";
25900
26115
  import * as path51 from "path";
25901
26116
  var SLUG_RE2 = /^[a-z0-9][a-z0-9_-]{0,63}$/;
@@ -25916,7 +26131,7 @@ function normalizeDefinitionBundle(bundle) {
25916
26131
  return { schemaVersion: 1, files };
25917
26132
  }
25918
26133
  function definitionVersion(bundle) {
25919
- return `sha256:${createHash5("sha256").update(JSON.stringify(normalizeDefinitionBundle(bundle))).digest("hex")}`;
26134
+ return `sha256:${createHash6("sha256").update(JSON.stringify(normalizeDefinitionBundle(bundle))).digest("hex")}`;
25920
26135
  }
25921
26136
  function verifyDefinition(definition) {
25922
26137
  if (!SLUG_RE2.test(definition.slug)) throw new Error(`invalid definition slug: ${definition.slug}`);
@@ -26017,12 +26232,12 @@ import { createServer as createServer5 } from "http";
26017
26232
 
26018
26233
  // src/pool/agency-loop-tick.ts
26019
26234
  function normalizeRepositories(repositories) {
26020
- const unique = /* @__PURE__ */ new Set();
26235
+ const unique2 = /* @__PURE__ */ new Set();
26021
26236
  for (const raw of repositories) {
26022
26237
  const repo = raw.trim().toLowerCase();
26023
- if (/^[^/\s]+\/[^/\s]+$/.test(repo)) unique.add(repo);
26238
+ if (/^[^/\s]+\/[^/\s]+$/.test(repo)) unique2.add(repo);
26024
26239
  }
26025
- return [...unique].sort();
26240
+ return [...unique2].sort();
26026
26241
  }
26027
26242
  async function runAgencyLoopTick(deps) {
26028
26243
  const repositories = normalizeRepositories(await deps.discover());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.413",
3
+ "version": "0.4.415",
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",
@@ -35,9 +35,9 @@
35
35
  "prepublishOnly": "pnpm typecheck && vitest run tests/unit tests/int --no-coverage && pnpm build && pnpm verify:package"
36
36
  },
37
37
  "dependencies": {
38
- "@kody-ade/agency-domain": "0.1.1",
39
38
  "@actions/cache": "^6.0.0",
40
39
  "@anthropic-ai/claude-agent-sdk": "0.2.119",
40
+ "@kody-ade/agency-domain": "0.4.0",
41
41
  "@modelcontextprotocol/sdk": "^1.29.0",
42
42
  "convex": "^1.17.0",
43
43
  "zod": "^4.0.0"