@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.
- package/dist/bin/kody.js +279 -64
- 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.
|
|
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
|
|
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"))
|
|
2000
|
-
for (const action of listBuiltinCapabilityActions(getBuiltinCapabilitiesRoot()))
|
|
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
|
|
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 !==
|
|
13008
|
-
throw new Error(`Agency State does not match Definition: ${definition.
|
|
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
|
|
13025
|
-
|
|
13026
|
-
|
|
13027
|
-
(
|
|
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 (
|
|
13031
|
-
definition:
|
|
13032
|
-
|
|
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 {
|
|
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
|
|
13125
|
-
const
|
|
13126
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
13200
|
-
|
|
13201
|
-
|
|
13202
|
-
|
|
13203
|
-
|
|
13204
|
-
|
|
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
|
-
|
|
13208
|
-
|
|
13209
|
-
cliArgs: {
|
|
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
|
|
15297
|
+
import { createDecipheriv, createHash as createHash3 } from "crypto";
|
|
15083
15298
|
function cacheKey(owner, repo, masterKey) {
|
|
15084
|
-
const keyHash =
|
|
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
|
|
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 =
|
|
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
|
|
18072
|
+
import { createDecipheriv as createDecipheriv2, createHash as createHash5, hkdfSync as hkdfSync2 } from "crypto";
|
|
17858
18073
|
function shortHash(s) {
|
|
17859
|
-
return
|
|
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
|
|
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: () =>
|
|
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
|
|
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:${
|
|
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
|
|
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))
|
|
26238
|
+
if (/^[^/\s]+\/[^/\s]+$/.test(repo)) unique2.add(repo);
|
|
26024
26239
|
}
|
|
26025
|
-
return [...
|
|
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.
|
|
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"
|