@kody-ade/kody-engine 0.4.415 → 0.4.417
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 +181 -56
- package/dist/implementations/types.ts +1 -0
- package/package.json +25 -26
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.417",
|
|
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",
|
|
@@ -52,7 +52,7 @@ var init_package = __esm({
|
|
|
52
52
|
dependencies: {
|
|
53
53
|
"@actions/cache": "^6.0.0",
|
|
54
54
|
"@anthropic-ai/claude-agent-sdk": "0.2.119",
|
|
55
|
-
"@kody-ade/agency-domain": "0.
|
|
55
|
+
"@kody-ade/agency-domain": "0.5.0",
|
|
56
56
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
57
57
|
convex: "^1.17.0",
|
|
58
58
|
zod: "^4.0.0"
|
|
@@ -2476,14 +2476,15 @@ function createStateBackendFromEnv(env = process.env, client) {
|
|
|
2476
2476
|
});
|
|
2477
2477
|
return Array.isArray(result) ? result : [];
|
|
2478
2478
|
},
|
|
2479
|
-
async reserveAgencyDispatch(tenantId2,
|
|
2479
|
+
async reserveAgencyDispatch(tenantId2, reservation) {
|
|
2480
2480
|
const result = await transport.mutation(anyApi.agencyModel.reserveDispatch, {
|
|
2481
2481
|
tenantId: requireTenant(tenantId2),
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2482
|
+
...reservation,
|
|
2483
|
+
idempotencyKey: requireNonEmpty(reservation.idempotencyKey, "idempotencyKey"),
|
|
2484
|
+
loopId: requireNonEmpty(reservation.loopId, "loopId"),
|
|
2485
|
+
reservationId: requireNonEmpty(reservation.reservationId, "reservationId"),
|
|
2486
|
+
correlationId: requireNonEmpty(reservation.correlationId, "correlationId"),
|
|
2487
|
+
policyHash: requireNonEmpty(reservation.policyHash, "policyHash")
|
|
2487
2488
|
});
|
|
2488
2489
|
return result;
|
|
2489
2490
|
},
|
|
@@ -2496,10 +2497,11 @@ function createStateBackendFromEnv(env = process.env, client) {
|
|
|
2496
2497
|
now
|
|
2497
2498
|
});
|
|
2498
2499
|
},
|
|
2499
|
-
async finishAgencyDispatch(tenantId2, idempotencyKey, status, now, runId) {
|
|
2500
|
+
async finishAgencyDispatch(tenantId2, idempotencyKey, reservationId, status, now, runId) {
|
|
2500
2501
|
await transport.mutation(anyApi.agencyModel.finishDispatch, {
|
|
2501
2502
|
tenantId: requireTenant(tenantId2),
|
|
2502
2503
|
idempotencyKey: requireNonEmpty(idempotencyKey, "idempotencyKey"),
|
|
2504
|
+
reservationId: requireNonEmpty(reservationId, "reservationId"),
|
|
2503
2505
|
status,
|
|
2504
2506
|
now,
|
|
2505
2507
|
...runId ? { runId: requireNonEmpty(runId, "runId") } : {}
|
|
@@ -3413,6 +3415,7 @@ async function runAgent(opts) {
|
|
|
3413
3415
|
let outcomeKind = "generic_failed";
|
|
3414
3416
|
let errorMessage2;
|
|
3415
3417
|
let tokens = { input: 0, output: 0, cacheRead: 0, cacheCreate: 0 };
|
|
3418
|
+
let costUsd = 0;
|
|
3416
3419
|
let messageCount = 0;
|
|
3417
3420
|
let finalText = "";
|
|
3418
3421
|
let getSubmitted;
|
|
@@ -3429,6 +3432,7 @@ async function runAgent(opts) {
|
|
|
3429
3432
|
outcomeKind = "generic_failed";
|
|
3430
3433
|
errorMessage2 = void 0;
|
|
3431
3434
|
tokens = { input: 0, output: 0, cacheRead: 0, cacheCreate: 0 };
|
|
3435
|
+
costUsd = 0;
|
|
3432
3436
|
messageCount = 0;
|
|
3433
3437
|
let sawMutatingTool = false;
|
|
3434
3438
|
let sawTerminalSuccess = false;
|
|
@@ -3553,6 +3557,7 @@ async function runAgent(opts) {
|
|
|
3553
3557
|
};
|
|
3554
3558
|
}
|
|
3555
3559
|
queryOptions.settingSources = opts.settingSources ?? ["project", "local"];
|
|
3560
|
+
if (opts.abortController) queryOptions.abortController = opts.abortController;
|
|
3556
3561
|
const stableBinary = ensureStableClaudeBinary();
|
|
3557
3562
|
if (stableBinary) {
|
|
3558
3563
|
const sdkBinaryPathOption = ["pathToClaudeCode", "Exec", "utable"].join("");
|
|
@@ -3681,6 +3686,8 @@ async function runAgent(opts) {
|
|
|
3681
3686
|
}
|
|
3682
3687
|
}
|
|
3683
3688
|
if (m.type === "result") {
|
|
3689
|
+
const reportedCost = Number(m.total_cost_usd ?? 0);
|
|
3690
|
+
if (Number.isFinite(reportedCost) && reportedCost >= 0) costUsd = reportedCost;
|
|
3684
3691
|
if (m.subtype === "success") {
|
|
3685
3692
|
outcome = "completed";
|
|
3686
3693
|
outcomeKind = "ok";
|
|
@@ -3758,6 +3765,7 @@ async function runAgent(opts) {
|
|
|
3758
3765
|
ndjsonPath,
|
|
3759
3766
|
durationMs: Date.now() - startedAt,
|
|
3760
3767
|
tokens,
|
|
3768
|
+
costUsd,
|
|
3761
3769
|
messageCount
|
|
3762
3770
|
};
|
|
3763
3771
|
}
|
|
@@ -13036,7 +13044,6 @@ function addDefinition(catalog, document) {
|
|
|
13036
13044
|
}
|
|
13037
13045
|
function add(collection, definition, revision) {
|
|
13038
13046
|
const mutable = collection;
|
|
13039
|
-
if (mutable.has(definition.id)) throw new Error(`Duplicate Agency Definition: ${definition.id}`);
|
|
13040
13047
|
mutable.set(definition.id, { definition, revision });
|
|
13041
13048
|
}
|
|
13042
13049
|
function validateRelationships(catalog) {
|
|
@@ -13096,7 +13103,10 @@ var init_agencyModelRepository = __esm({
|
|
|
13096
13103
|
async loadCatalog() {
|
|
13097
13104
|
const documents = await this.backend.listAgencyDefinitions(this.tenantId);
|
|
13098
13105
|
const catalog = emptyCatalog();
|
|
13099
|
-
|
|
13106
|
+
const ordered = [...documents].sort(
|
|
13107
|
+
(left, right) => left.createdAt.localeCompare(right.createdAt) || left.recordId.localeCompare(right.recordId)
|
|
13108
|
+
);
|
|
13109
|
+
for (const document of ordered) addDefinition(catalog, document);
|
|
13100
13110
|
validateRelationships(catalog);
|
|
13101
13111
|
return catalog;
|
|
13102
13112
|
}
|
|
@@ -13199,7 +13209,7 @@ function resolveDispatchPolicy(input) {
|
|
|
13199
13209
|
});
|
|
13200
13210
|
const policy = mergePolicies(intents.map(({ definition }) => definition.policy));
|
|
13201
13211
|
const constraints = intents.flatMap(({ definition }) => definition.constraints);
|
|
13202
|
-
assertAuthorized(policy, constraints, input.target
|
|
13212
|
+
const requiresApproval = assertAuthorized(policy, constraints, input.target);
|
|
13203
13213
|
const snapshotValue = { policy, constraints };
|
|
13204
13214
|
return {
|
|
13205
13215
|
snapshot: {
|
|
@@ -13211,7 +13221,8 @@ function resolveDispatchPolicy(input) {
|
|
|
13211
13221
|
trace: [
|
|
13212
13222
|
pinned("trigger" in input.owner.definition ? "loop" : "goal", input.owner),
|
|
13213
13223
|
input.target
|
|
13214
|
-
]
|
|
13224
|
+
],
|
|
13225
|
+
requiresApproval
|
|
13215
13226
|
};
|
|
13216
13227
|
}
|
|
13217
13228
|
function mergePolicies(policies) {
|
|
@@ -13235,7 +13246,7 @@ function mergePolicies(policies) {
|
|
|
13235
13246
|
riskyActions: unique(policies.flatMap(({ riskyActions }) => riskyActions))
|
|
13236
13247
|
};
|
|
13237
13248
|
}
|
|
13238
|
-
function assertAuthorized(policy, constraints, target
|
|
13249
|
+
function assertAuthorized(policy, constraints, target) {
|
|
13239
13250
|
const action = `${target.kind}:${target.id}`;
|
|
13240
13251
|
const matches = (patterns) => patterns.some((pattern) => pattern === "*" || pattern === target.id || pattern === action);
|
|
13241
13252
|
if (matches(policy.authority.deny)) throw new Error(`Dispatch blocked: authority denies "${action}"`);
|
|
@@ -13244,7 +13255,7 @@ function assertAuthorized(policy, constraints, target, approved) {
|
|
|
13244
13255
|
const denied = matchingConstraints.find(({ effect }) => effect === "deny");
|
|
13245
13256
|
if (denied) throw new Error(`Dispatch blocked by constraint "${denied.id}": ${denied.rule}`);
|
|
13246
13257
|
const requiresApproval = policy.approval === "all-actions" || policy.approval === "risky-actions" && matches(policy.riskyActions) || matchingConstraints.some(({ effect }) => effect === "require-approval");
|
|
13247
|
-
|
|
13258
|
+
return requiresApproval;
|
|
13248
13259
|
}
|
|
13249
13260
|
function pinned(kind, record2) {
|
|
13250
13261
|
return { kind, id: record2.definition.id, revision: record2.revision };
|
|
@@ -13322,17 +13333,47 @@ async function dispatchAgencyLoopsWith(input) {
|
|
|
13322
13333
|
results.push({ loopId: record2.definition.id, decision: "skipped", reason });
|
|
13323
13334
|
continue;
|
|
13324
13335
|
}
|
|
13325
|
-
const
|
|
13326
|
-
const
|
|
13327
|
-
|
|
13328
|
-
|
|
13329
|
-
|
|
13336
|
+
const failurePolicy = record2.definition.reconciliationPolicy.failure;
|
|
13337
|
+
const budget = policy.snapshot.policy.budget;
|
|
13338
|
+
const maxAttempts = Math.min(failurePolicy.maxAttempts, budget.maxRuns);
|
|
13339
|
+
const timeoutSeconds = Math.min(failurePolicy.timeoutSeconds, budget.maxDurationSeconds);
|
|
13340
|
+
const backoffBudgetSeconds = Array.from(
|
|
13341
|
+
{ length: Math.max(0, maxAttempts - 1) },
|
|
13342
|
+
(_, index) => failurePolicy.backoffSeconds * 2 ** index
|
|
13343
|
+
).reduce((sum, seconds) => sum + seconds, 0);
|
|
13344
|
+
const leaseSeconds = Math.min(
|
|
13345
|
+
budget.maxDurationSeconds,
|
|
13346
|
+
maxAttempts * timeoutSeconds + backoffBudgetSeconds
|
|
13347
|
+
);
|
|
13348
|
+
const leaseUntil = new Date(input.now.getTime() + leaseSeconds * 1e3).toISOString();
|
|
13349
|
+
const reservationId = `reservation-${randomUUID()}`;
|
|
13350
|
+
const correlationId = `corr-${randomUUID()}`;
|
|
13351
|
+
const trace = [policy.trace[0], ...target.intermediate, target.reference];
|
|
13352
|
+
const reservation = await input.backend.reserveAgencyDispatch(input.tenantId, {
|
|
13353
|
+
idempotencyKey: decision.idempotencyKey,
|
|
13354
|
+
loopId: record2.definition.id,
|
|
13330
13355
|
decision,
|
|
13331
13356
|
leaseUntil,
|
|
13357
|
+
reservationId,
|
|
13358
|
+
correlationId,
|
|
13359
|
+
policyHash: policy.snapshot.hash,
|
|
13360
|
+
effectivePolicy: policy.snapshot,
|
|
13361
|
+
definitionRefs: trace,
|
|
13362
|
+
maxConcurrentRuns: policy.snapshot.policy.maxConcurrentRuns,
|
|
13363
|
+
requiresApproval: policy.requiresApproval,
|
|
13364
|
+
approvalScopeKind: "loop",
|
|
13365
|
+
approvalScopeId: record2.definition.id,
|
|
13366
|
+
approvalAction: `${target.reference.kind}:${target.reference.id}`,
|
|
13332
13367
|
now
|
|
13333
|
-
);
|
|
13368
|
+
});
|
|
13334
13369
|
if (!reservation.acquired) {
|
|
13335
|
-
|
|
13370
|
+
const duplicate = reservation.reason === "duplicate";
|
|
13371
|
+
const reason = reservation.reason === "approval-required" ? "dispatch is waiting for approval" : reservation.reason === "concurrency-limit" ? "dispatch is waiting for policy capacity" : "trigger firing already reserved";
|
|
13372
|
+
results.push({
|
|
13373
|
+
loopId: record2.definition.id,
|
|
13374
|
+
decision: duplicate ? "duplicate" : "skipped",
|
|
13375
|
+
reason
|
|
13376
|
+
});
|
|
13336
13377
|
continue;
|
|
13337
13378
|
}
|
|
13338
13379
|
const runningState = createLoopState2({
|
|
@@ -13344,40 +13385,82 @@ async function dispatchAgencyLoopsWith(input) {
|
|
|
13344
13385
|
updatedAt: now
|
|
13345
13386
|
});
|
|
13346
13387
|
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
|
-
});
|
|
13359
13388
|
try {
|
|
13360
|
-
|
|
13361
|
-
|
|
13362
|
-
|
|
13363
|
-
|
|
13364
|
-
|
|
13365
|
-
|
|
13366
|
-
);
|
|
13367
|
-
|
|
13368
|
-
|
|
13389
|
+
let attempts = 0;
|
|
13390
|
+
let tokens = 0;
|
|
13391
|
+
let costUsd = 0;
|
|
13392
|
+
let succeeded = false;
|
|
13393
|
+
let reason = "target failed";
|
|
13394
|
+
let finalRunId;
|
|
13395
|
+
const budgetDeadline = Date.now() + budget.maxDurationSeconds * 1e3;
|
|
13396
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
13397
|
+
const remainingMilliseconds = budgetDeadline - Date.now();
|
|
13398
|
+
if (remainingMilliseconds <= 0) {
|
|
13399
|
+
reason = "policy duration budget exhausted";
|
|
13400
|
+
break;
|
|
13401
|
+
}
|
|
13402
|
+
attempts = attempt;
|
|
13403
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13404
|
+
const runId = `run-${randomUUID()}`;
|
|
13405
|
+
finalRunId = runId;
|
|
13406
|
+
const activeRun = createRun({
|
|
13407
|
+
id: runId,
|
|
13408
|
+
status: "running",
|
|
13409
|
+
origin: { kind: "loop", id: record2.definition.id, revision: record2.revision },
|
|
13410
|
+
target: target.reference,
|
|
13411
|
+
trace,
|
|
13412
|
+
effectivePolicy: policy.snapshot,
|
|
13413
|
+
correlationId,
|
|
13414
|
+
startedAt
|
|
13415
|
+
});
|
|
13416
|
+
await input.backend.createAgencyModelRun(
|
|
13417
|
+
input.tenantId,
|
|
13418
|
+
target.reference.kind,
|
|
13419
|
+
target.reference.id,
|
|
13420
|
+
activeRun,
|
|
13421
|
+
startedAt
|
|
13422
|
+
);
|
|
13423
|
+
const attemptResult = await runAttempt(
|
|
13424
|
+
input.run,
|
|
13425
|
+
target.job,
|
|
13426
|
+
Math.min(timeoutSeconds, remainingMilliseconds / 1e3)
|
|
13427
|
+
);
|
|
13428
|
+
tokens += attemptResult.usage?.tokens ?? 0;
|
|
13429
|
+
costUsd += attemptResult.usage?.costUsd ?? 0;
|
|
13430
|
+
const finishedAt2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
13431
|
+
succeeded = attemptResult.exitCode === 0;
|
|
13432
|
+
reason = attemptResult.reason ?? (succeeded ? "target dispatched" : "target failed");
|
|
13433
|
+
const usage = {
|
|
13434
|
+
tokens: attemptResult.usage?.tokens ?? 0,
|
|
13435
|
+
costUsd: attemptResult.usage?.costUsd ?? 0,
|
|
13436
|
+
durationSeconds: Math.max(0, (Date.parse(finishedAt2) - Date.parse(startedAt)) / 1e3)
|
|
13437
|
+
};
|
|
13438
|
+
if (tokens > budget.maxTokens || costUsd > budget.maxCostUsd) {
|
|
13439
|
+
succeeded = false;
|
|
13440
|
+
reason = tokens > budget.maxTokens ? "policy token budget exhausted" : "policy cost budget exhausted";
|
|
13441
|
+
}
|
|
13442
|
+
await input.backend.finishAgencyModelRun(
|
|
13443
|
+
input.tenantId,
|
|
13444
|
+
terminalRun(activeRun, succeeded ? "succeeded" : "failed", finishedAt2, usage),
|
|
13445
|
+
finishedAt2
|
|
13446
|
+
);
|
|
13447
|
+
if (tokens > budget.maxTokens || costUsd > budget.maxCostUsd) break;
|
|
13448
|
+
if (succeeded || attempt === maxAttempts) break;
|
|
13449
|
+
const backoffMilliseconds = failurePolicy.backoffSeconds * 2 ** (attempt - 1) * 1e3;
|
|
13450
|
+
if (Date.now() + backoffMilliseconds >= budgetDeadline) {
|
|
13451
|
+
reason = "policy duration budget exhausted during retry backoff";
|
|
13452
|
+
break;
|
|
13453
|
+
}
|
|
13454
|
+
await wait(backoffMilliseconds);
|
|
13455
|
+
}
|
|
13369
13456
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13370
|
-
await input.backend.finishAgencyModelRun(
|
|
13371
|
-
input.tenantId,
|
|
13372
|
-
terminalRun(activeRun, succeeded ? "succeeded" : "failed", finishedAt),
|
|
13373
|
-
finishedAt
|
|
13374
|
-
);
|
|
13375
13457
|
await input.backend.finishAgencyDispatch(
|
|
13376
13458
|
input.tenantId,
|
|
13377
13459
|
decision.idempotencyKey,
|
|
13378
|
-
|
|
13460
|
+
reservationId,
|
|
13461
|
+
succeeded ? "dispatched" : "dead-letter",
|
|
13379
13462
|
finishedAt,
|
|
13380
|
-
|
|
13463
|
+
finalRunId
|
|
13381
13464
|
);
|
|
13382
13465
|
await repository.saveState(
|
|
13383
13466
|
createLoopState2({
|
|
@@ -13392,13 +13475,18 @@ async function dispatchAgencyLoopsWith(input) {
|
|
|
13392
13475
|
results.push({
|
|
13393
13476
|
loopId: record2.definition.id,
|
|
13394
13477
|
decision: succeeded ? "dispatched" : "failed",
|
|
13395
|
-
reason:
|
|
13478
|
+
reason: succeeded ? reason : `${reason}; dead-lettered after ${attempts} attempt${attempts === 1 ? "" : "s"}`
|
|
13396
13479
|
});
|
|
13397
13480
|
} catch (error) {
|
|
13398
13481
|
const reason = error instanceof Error ? error.message : String(error);
|
|
13399
13482
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13400
|
-
await input.backend.
|
|
13401
|
-
|
|
13483
|
+
await input.backend.finishAgencyDispatch(
|
|
13484
|
+
input.tenantId,
|
|
13485
|
+
decision.idempotencyKey,
|
|
13486
|
+
reservationId,
|
|
13487
|
+
"dead-letter",
|
|
13488
|
+
finishedAt
|
|
13489
|
+
);
|
|
13402
13490
|
results.push({ loopId: record2.definition.id, decision: "failed", reason });
|
|
13403
13491
|
}
|
|
13404
13492
|
}
|
|
@@ -13421,8 +13509,32 @@ function resolveTarget(loop, catalog) {
|
|
|
13421
13509
|
job: target.kind === "workflow" ? { workflow: target.id, cliArgs: {}, flavor: "scheduled" } : { capability: target.id, cliArgs: {}, flavor: "scheduled" }
|
|
13422
13510
|
};
|
|
13423
13511
|
}
|
|
13424
|
-
function terminalRun(active, status, finishedAt) {
|
|
13425
|
-
return createRun({ ...active, status, finishedAt });
|
|
13512
|
+
function terminalRun(active, status, finishedAt, usage) {
|
|
13513
|
+
return createRun({ ...active, status, finishedAt, usage });
|
|
13514
|
+
}
|
|
13515
|
+
async function runAttempt(run, job, timeoutSeconds) {
|
|
13516
|
+
const abortController = new AbortController();
|
|
13517
|
+
let timer;
|
|
13518
|
+
try {
|
|
13519
|
+
return await Promise.race([
|
|
13520
|
+
run(job, abortController),
|
|
13521
|
+
new Promise((resolve17) => {
|
|
13522
|
+
timer = setTimeout(() => {
|
|
13523
|
+
abortController.abort();
|
|
13524
|
+
resolve17({ exitCode: 124, reason: `target timed out after ${formatSeconds(timeoutSeconds)}s` });
|
|
13525
|
+
}, timeoutSeconds * 1e3);
|
|
13526
|
+
})
|
|
13527
|
+
]);
|
|
13528
|
+
} finally {
|
|
13529
|
+
if (timer) clearTimeout(timer);
|
|
13530
|
+
}
|
|
13531
|
+
}
|
|
13532
|
+
function formatSeconds(seconds) {
|
|
13533
|
+
return Number.isInteger(seconds) ? String(seconds) : seconds.toFixed(3).replace(/0+$/, "").replace(/\.$/, "");
|
|
13534
|
+
}
|
|
13535
|
+
async function wait(milliseconds) {
|
|
13536
|
+
if (milliseconds <= 0) return;
|
|
13537
|
+
await new Promise((resolve17) => setTimeout(resolve17, milliseconds));
|
|
13426
13538
|
}
|
|
13427
13539
|
function repositoryTenant(config) {
|
|
13428
13540
|
const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
|
|
@@ -13446,7 +13558,14 @@ var init_dispatchAgencyLoops = __esm({
|
|
|
13446
13558
|
tenantId: tenantId2,
|
|
13447
13559
|
backend,
|
|
13448
13560
|
now: /* @__PURE__ */ new Date(),
|
|
13449
|
-
run: (job) => runJob(job, {
|
|
13561
|
+
run: (job, abortController) => runJob(job, {
|
|
13562
|
+
cwd: ctx.cwd,
|
|
13563
|
+
config: ctx.config,
|
|
13564
|
+
verbose: ctx.verbose,
|
|
13565
|
+
quiet: ctx.quiet,
|
|
13566
|
+
chain: false,
|
|
13567
|
+
abortController
|
|
13568
|
+
})
|
|
13450
13569
|
});
|
|
13451
13570
|
ctx.data.agencyLoopDispatchResults = results;
|
|
13452
13571
|
};
|
|
@@ -20658,6 +20777,7 @@ async function runImplementation(profileName, input) {
|
|
|
20658
20777
|
isBackendHealthy: lm ? () => lm.isHealthy() : void 0,
|
|
20659
20778
|
verbose: input.verbose,
|
|
20660
20779
|
quiet: input.quiet,
|
|
20780
|
+
abortController: input.abortController,
|
|
20661
20781
|
ndjsonDir,
|
|
20662
20782
|
additionalDirectories: agentTaskArtifacts ? [agentTaskArtifacts.absDir] : void 0,
|
|
20663
20783
|
allowedToolsOverride: profile.claudeCode.tools,
|
|
@@ -20767,6 +20887,10 @@ async function runImplementation(profileName, input) {
|
|
|
20767
20887
|
reason: err instanceof Error ? err.message : String(err)
|
|
20768
20888
|
});
|
|
20769
20889
|
}
|
|
20890
|
+
ctx.output.usage = {
|
|
20891
|
+
tokens: agentResult.tokens ? agentResult.tokens.input + agentResult.tokens.output + agentResult.tokens.cacheRead + agentResult.tokens.cacheCreate : 0,
|
|
20892
|
+
costUsd: agentResult.costUsd ?? 0
|
|
20893
|
+
};
|
|
20770
20894
|
emitEvent(input.cwd, {
|
|
20771
20895
|
implementation: profileName,
|
|
20772
20896
|
kind: "agent_end",
|
|
@@ -21609,6 +21733,7 @@ async function runCapabilityImplementationStep(valid, profileName, capabilityIde
|
|
|
21609
21733
|
skipConfig: base.skipConfig,
|
|
21610
21734
|
verbose: base.verbose,
|
|
21611
21735
|
quiet: base.quiet,
|
|
21736
|
+
abortController: base.abortController,
|
|
21612
21737
|
preloadedData: Object.keys(preloadedData).length > 0 ? preloadedData : void 0
|
|
21613
21738
|
};
|
|
21614
21739
|
const shouldApplyResolvedCapabilityArgs = valid.implementation === void 0 && resolvedCapability && profileName === resolvedCapability.implementation;
|
|
@@ -453,6 +453,7 @@ export interface Context {
|
|
|
453
453
|
exitCode: number
|
|
454
454
|
prUrl?: string
|
|
455
455
|
reason?: string
|
|
456
|
+
usage?: { tokens: number; costUsd: number }
|
|
456
457
|
/**
|
|
457
458
|
* In-process hand-off to the next stage. A stage (e.g. `classify`) sets
|
|
458
459
|
* this so the orchestrator runs the chosen sub-orchestrator
|
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.417",
|
|
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,32 +12,10 @@
|
|
|
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
|
-
},
|
|
37
15
|
"dependencies": {
|
|
38
16
|
"@actions/cache": "^6.0.0",
|
|
39
17
|
"@anthropic-ai/claude-agent-sdk": "0.2.119",
|
|
40
|
-
"@kody-ade/agency-domain": "0.
|
|
18
|
+
"@kody-ade/agency-domain": "0.5.0",
|
|
41
19
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
42
20
|
"convex": "^1.17.0",
|
|
43
21
|
"zod": "^4.0.0"
|
|
@@ -59,5 +37,26 @@
|
|
|
59
37
|
"url": "git+https://github.com/aharonyaircohen/kody-engine.git"
|
|
60
38
|
},
|
|
61
39
|
"homepage": "https://github.com/aharonyaircohen/kody-engine",
|
|
62
|
-
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
63
|
-
|
|
40
|
+
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues",
|
|
41
|
+
"scripts": {
|
|
42
|
+
"kody:run": "tsx bin/kody.ts",
|
|
43
|
+
"serve": "tsx bin/kody.ts serve",
|
|
44
|
+
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
45
|
+
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
46
|
+
"clean:dist": "node scripts/clean-dist.cjs",
|
|
47
|
+
"build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
|
|
48
|
+
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
49
|
+
"pretest": "pnpm check:modularity",
|
|
50
|
+
"test": "vitest run tests/unit tests/int --coverage",
|
|
51
|
+
"posttest": "tsx scripts/check-coverage-floor.ts",
|
|
52
|
+
"test:smoke": "vitest run tests/smoke --no-coverage",
|
|
53
|
+
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
54
|
+
"test:all": "vitest run tests --no-coverage",
|
|
55
|
+
"typecheck": "tsc --noEmit",
|
|
56
|
+
"lint": "biome check",
|
|
57
|
+
"lint:fix": "biome check --write",
|
|
58
|
+
"format": "biome format --write",
|
|
59
|
+
"verify:package": "node scripts/verify-package-tarball.cjs",
|
|
60
|
+
"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"
|
|
61
|
+
}
|
|
62
|
+
}
|