@kody-ade/kody-engine 0.4.414 → 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 +281 -65
- 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,18 +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
|
-
|
|
13127
|
-
|
|
13128
|
-
).map((record2) => [record2.definition.id, record2.definition])
|
|
13129
|
-
);
|
|
13130
|
-
const loops = records.filter(
|
|
13131
|
-
(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 }] : []
|
|
13132
13286
|
);
|
|
13133
13287
|
const results = [];
|
|
13134
13288
|
for (const record2 of loops) {
|
|
@@ -13147,6 +13301,27 @@ async function dispatchAgencyLoopsWith(input) {
|
|
|
13147
13301
|
results.push({ loopId: record2.definition.id, decision: "skipped", reason: decision.reason });
|
|
13148
13302
|
continue;
|
|
13149
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
|
+
}
|
|
13150
13325
|
const leaseUntil = new Date(input.now.getTime() + 15 * 6e4).toISOString();
|
|
13151
13326
|
const reservation = await input.backend.reserveAgencyDispatch(
|
|
13152
13327
|
input.tenantId,
|
|
@@ -13169,14 +13344,40 @@ async function dispatchAgencyLoopsWith(input) {
|
|
|
13169
13344
|
updatedAt: now
|
|
13170
13345
|
});
|
|
13171
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
|
+
});
|
|
13172
13359
|
try {
|
|
13173
|
-
|
|
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);
|
|
13174
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
|
+
);
|
|
13175
13375
|
await input.backend.finishAgencyDispatch(
|
|
13176
13376
|
input.tenantId,
|
|
13177
13377
|
decision.idempotencyKey,
|
|
13178
13378
|
succeeded ? "dispatched" : "failed",
|
|
13179
|
-
|
|
13379
|
+
finishedAt,
|
|
13380
|
+
runId
|
|
13180
13381
|
);
|
|
13181
13382
|
await repository.saveState(
|
|
13182
13383
|
createLoopState2({
|
|
@@ -13195,19 +13396,33 @@ async function dispatchAgencyLoopsWith(input) {
|
|
|
13195
13396
|
});
|
|
13196
13397
|
} catch (error) {
|
|
13197
13398
|
const reason = error instanceof Error ? error.message : String(error);
|
|
13198
|
-
|
|
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);
|
|
13199
13402
|
results.push({ loopId: record2.definition.id, decision: "failed", reason });
|
|
13200
13403
|
}
|
|
13201
13404
|
}
|
|
13202
13405
|
return results;
|
|
13203
13406
|
}
|
|
13204
|
-
function
|
|
13205
|
-
const
|
|
13206
|
-
if (!
|
|
13207
|
-
if (
|
|
13208
|
-
|
|
13209
|
-
}
|
|
13210
|
-
|
|
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 };
|
|
13418
|
+
return {
|
|
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" }
|
|
13422
|
+
};
|
|
13423
|
+
}
|
|
13424
|
+
function terminalRun(active, status, finishedAt) {
|
|
13425
|
+
return createRun({ ...active, status, finishedAt });
|
|
13211
13426
|
}
|
|
13212
13427
|
function repositoryTenant(config) {
|
|
13213
13428
|
const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
|
|
@@ -13220,6 +13435,7 @@ var init_dispatchAgencyLoops = __esm({
|
|
|
13220
13435
|
"use strict";
|
|
13221
13436
|
init_agencyModelRepository();
|
|
13222
13437
|
init_triggerDispatcher();
|
|
13438
|
+
init_policyResolver();
|
|
13223
13439
|
init_job();
|
|
13224
13440
|
init_state_backend();
|
|
13225
13441
|
dispatchAgencyLoops = async (ctx) => {
|
|
@@ -15078,9 +15294,9 @@ var init_kodyVariables = __esm({
|
|
|
15078
15294
|
});
|
|
15079
15295
|
|
|
15080
15296
|
// src/backendVault.ts
|
|
15081
|
-
import { createDecipheriv, createHash as
|
|
15297
|
+
import { createDecipheriv, createHash as createHash3 } from "crypto";
|
|
15082
15298
|
function cacheKey(owner, repo, masterKey) {
|
|
15083
|
-
const keyHash =
|
|
15299
|
+
const keyHash = createHash3("sha256").update(masterKey).digest("hex").slice(0, 16);
|
|
15084
15300
|
return `${owner}/${repo}:${keyHash}`.toLowerCase();
|
|
15085
15301
|
}
|
|
15086
15302
|
function decryptVault(payload, masterKey) {
|
|
@@ -15729,7 +15945,7 @@ var init_notifyTerminal = __esm({
|
|
|
15729
15945
|
});
|
|
15730
15946
|
|
|
15731
15947
|
// src/scripts/openAgencyModelReviewPr.ts
|
|
15732
|
-
import { createHash as
|
|
15948
|
+
import { createHash as createHash4 } from "crypto";
|
|
15733
15949
|
function parseAgencyModelProposal(raw) {
|
|
15734
15950
|
const text2 = raw.trim();
|
|
15735
15951
|
const jsonText = (text2.match(/^```(?:json)?\s*\n([\s\S]*?)\n```$/i)?.[1] ?? text2).trim();
|
|
@@ -15781,7 +15997,7 @@ function normalizeBundleFiles(bundle) {
|
|
|
15781
15997
|
});
|
|
15782
15998
|
}
|
|
15783
15999
|
function buildProposalId(issueNumber, bundle, sourceLabel) {
|
|
15784
|
-
const digest =
|
|
16000
|
+
const digest = createHash4("sha256").update(JSON.stringify({ issueNumber, sourceLabel, title: bundle.title, files: normalizeBundleFiles(bundle) })).digest("hex").slice(0, 16);
|
|
15785
16001
|
return `issue-${issueNumber}-${digest}`;
|
|
15786
16002
|
}
|
|
15787
16003
|
function isDryRun(ctx) {
|
|
@@ -17853,9 +18069,9 @@ var init_runFlow = __esm({
|
|
|
17853
18069
|
});
|
|
17854
18070
|
|
|
17855
18071
|
// src/scripts/previewBuildHelpers.ts
|
|
17856
|
-
import { createDecipheriv as createDecipheriv2, createHash as
|
|
18072
|
+
import { createDecipheriv as createDecipheriv2, createHash as createHash5, hkdfSync as hkdfSync2 } from "crypto";
|
|
17857
18073
|
function shortHash(s) {
|
|
17858
|
-
return
|
|
18074
|
+
return createHash5("sha256").update(s).digest("hex").slice(0, 6);
|
|
17859
18075
|
}
|
|
17860
18076
|
function previewAppName(repo, pr) {
|
|
17861
18077
|
const [owner, name] = repo.split("/");
|
|
@@ -17888,7 +18104,7 @@ function formatPreviewComment(args) {
|
|
|
17888
18104
|
].join("\n");
|
|
17889
18105
|
}
|
|
17890
18106
|
function defaultImageTag(repo, ref) {
|
|
17891
|
-
return
|
|
18107
|
+
return createHash5("sha256").update(`${repo}@${ref}`).digest("hex").slice(0, 12);
|
|
17892
18108
|
}
|
|
17893
18109
|
var init_previewBuildHelpers = __esm({
|
|
17894
18110
|
"src/scripts/previewBuildHelpers.ts"() {
|
|
@@ -25313,7 +25529,7 @@ init_config();
|
|
|
25313
25529
|
init_fetchRepoMcp();
|
|
25314
25530
|
|
|
25315
25531
|
// src/servers/mcpHttpServer.ts
|
|
25316
|
-
import { randomUUID } from "crypto";
|
|
25532
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
25317
25533
|
import { createServer as createServer4 } from "http";
|
|
25318
25534
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
25319
25535
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
@@ -25322,7 +25538,7 @@ function buildMcpHttpServer(opts) {
|
|
|
25322
25538
|
const transports = /* @__PURE__ */ new Map();
|
|
25323
25539
|
for (const route of opts.routes) {
|
|
25324
25540
|
const transport = new StreamableHTTPServerTransport({
|
|
25325
|
-
sessionIdGenerator: () =>
|
|
25541
|
+
sessionIdGenerator: () => randomUUID2()
|
|
25326
25542
|
});
|
|
25327
25543
|
transports.set(route.path, transport);
|
|
25328
25544
|
routes.set(route.path, route.name);
|
|
@@ -25894,7 +26110,7 @@ init_config();
|
|
|
25894
26110
|
|
|
25895
26111
|
// src/definition-hydration.ts
|
|
25896
26112
|
init_state_backend();
|
|
25897
|
-
import { createHash as
|
|
26113
|
+
import { createHash as createHash6 } from "crypto";
|
|
25898
26114
|
import * as fs50 from "fs";
|
|
25899
26115
|
import * as path51 from "path";
|
|
25900
26116
|
var SLUG_RE2 = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
@@ -25915,7 +26131,7 @@ function normalizeDefinitionBundle(bundle) {
|
|
|
25915
26131
|
return { schemaVersion: 1, files };
|
|
25916
26132
|
}
|
|
25917
26133
|
function definitionVersion(bundle) {
|
|
25918
|
-
return `sha256:${
|
|
26134
|
+
return `sha256:${createHash6("sha256").update(JSON.stringify(normalizeDefinitionBundle(bundle))).digest("hex")}`;
|
|
25919
26135
|
}
|
|
25920
26136
|
function verifyDefinition(definition) {
|
|
25921
26137
|
if (!SLUG_RE2.test(definition.slug)) throw new Error(`invalid definition slug: ${definition.slug}`);
|
|
@@ -26016,12 +26232,12 @@ import { createServer as createServer5 } from "http";
|
|
|
26016
26232
|
|
|
26017
26233
|
// src/pool/agency-loop-tick.ts
|
|
26018
26234
|
function normalizeRepositories(repositories) {
|
|
26019
|
-
const
|
|
26235
|
+
const unique2 = /* @__PURE__ */ new Set();
|
|
26020
26236
|
for (const raw of repositories) {
|
|
26021
26237
|
const repo = raw.trim().toLowerCase();
|
|
26022
|
-
if (/^[^/\s]+\/[^/\s]+$/.test(repo))
|
|
26238
|
+
if (/^[^/\s]+\/[^/\s]+$/.test(repo)) unique2.add(repo);
|
|
26023
26239
|
}
|
|
26024
|
-
return [...
|
|
26240
|
+
return [...unique2].sort();
|
|
26025
26241
|
}
|
|
26026
26242
|
async function runAgencyLoopTick(deps) {
|
|
26027
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"
|