@kody-ade/kody-engine 0.4.532 → 0.4.533
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 +70 -9
- package/package.json +1 -1
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.533",
|
|
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",
|
|
@@ -2816,6 +2816,15 @@ function createStateBackendFromEnv(env = process.env, client) {
|
|
|
2816
2816
|
});
|
|
2817
2817
|
return result;
|
|
2818
2818
|
},
|
|
2819
|
+
async renewLoopDispatch(tenantId2, idempotencyKey, reservationId, leaseUntil, now) {
|
|
2820
|
+
await transport.mutation(anyApi.agencyModel.renewDispatch, {
|
|
2821
|
+
tenantId: requireTenant(tenantId2),
|
|
2822
|
+
idempotencyKey: requireNonEmpty(idempotencyKey, "idempotencyKey"),
|
|
2823
|
+
reservationId: requireNonEmpty(reservationId, "reservationId"),
|
|
2824
|
+
leaseUntil: requireNonEmpty(leaseUntil, "leaseUntil"),
|
|
2825
|
+
now: requireNonEmpty(now, "now")
|
|
2826
|
+
});
|
|
2827
|
+
},
|
|
2819
2828
|
async finishLoopDispatch(tenantId2, idempotencyKey, reservationId, status, now, runId) {
|
|
2820
2829
|
await transport.mutation(anyApi.agencyModel.finishDispatch, {
|
|
2821
2830
|
tenantId: requireTenant(tenantId2),
|
|
@@ -13659,9 +13668,11 @@ var init_loopDefinitions = __esm({
|
|
|
13659
13668
|
// src/scripts/dispatchLoops.ts
|
|
13660
13669
|
import { randomUUID } from "crypto";
|
|
13661
13670
|
function assertLoopDispatchesSucceeded(results) {
|
|
13662
|
-
const
|
|
13663
|
-
if (
|
|
13664
|
-
throw new Error(
|
|
13671
|
+
const didNotRun = results.filter((result) => result.status === "failed" || result.status === "blocked");
|
|
13672
|
+
if (didNotRun.length === 0) return;
|
|
13673
|
+
throw new Error(
|
|
13674
|
+
`Loop dispatch did not run: ${didNotRun.map((result) => `${result.loopId}: ${result.reason}`).join("; ")}`
|
|
13675
|
+
);
|
|
13665
13676
|
}
|
|
13666
13677
|
async function dispatchLoopsWith(input) {
|
|
13667
13678
|
const results = [];
|
|
@@ -13692,7 +13703,9 @@ async function dispatchLoopsWith(input) {
|
|
|
13692
13703
|
now: input.now.toISOString()
|
|
13693
13704
|
});
|
|
13694
13705
|
if (!claimed.acquired) {
|
|
13695
|
-
|
|
13706
|
+
const reason2 = claimed.reason ?? "already claimed";
|
|
13707
|
+
const status2 = reason2 === "duplicate" ? "skipped" : "blocked";
|
|
13708
|
+
results.push({ loopId: loop.id, status: status2, reason: reason2 });
|
|
13696
13709
|
continue;
|
|
13697
13710
|
}
|
|
13698
13711
|
const runId = `loop-${loop.id}-${input.nonce()}`;
|
|
@@ -13705,15 +13718,32 @@ async function dispatchLoopsWith(input) {
|
|
|
13705
13718
|
startedAt
|
|
13706
13719
|
};
|
|
13707
13720
|
await input.backend.createAgencyRun(input.tenantId, "loop", loop.id, running, startedAt);
|
|
13708
|
-
|
|
13709
|
-
|
|
13721
|
+
const stopLeaseRenewal = startLoopLeaseRenewal({
|
|
13722
|
+
backend: input.backend,
|
|
13723
|
+
tenantId: input.tenantId,
|
|
13724
|
+
idempotencyKey,
|
|
13725
|
+
reservationId
|
|
13726
|
+
});
|
|
13727
|
+
let exitCode = 1;
|
|
13728
|
+
let reason = "target did not complete";
|
|
13729
|
+
let runFailed = false;
|
|
13710
13730
|
try {
|
|
13711
13731
|
const result = await input.run(loopJob(loop), runId);
|
|
13712
13732
|
exitCode = result.exitCode;
|
|
13713
13733
|
reason = result.reason ?? (exitCode === 0 ? "dispatched" : "target failed");
|
|
13714
13734
|
} catch (error) {
|
|
13735
|
+
runFailed = true;
|
|
13715
13736
|
exitCode = 1;
|
|
13716
13737
|
reason = error instanceof Error ? error.message : String(error);
|
|
13738
|
+
} finally {
|
|
13739
|
+
try {
|
|
13740
|
+
await stopLeaseRenewal();
|
|
13741
|
+
} catch (error) {
|
|
13742
|
+
if (!runFailed && exitCode === 0) {
|
|
13743
|
+
exitCode = 1;
|
|
13744
|
+
reason = `Loop reservation renewal failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
13745
|
+
}
|
|
13746
|
+
}
|
|
13717
13747
|
}
|
|
13718
13748
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13719
13749
|
const succeeded = exitCode === 0;
|
|
@@ -13733,6 +13763,36 @@ async function dispatchLoopsWith(input) {
|
|
|
13733
13763
|
}
|
|
13734
13764
|
return results;
|
|
13735
13765
|
}
|
|
13766
|
+
function startLoopLeaseRenewal(input) {
|
|
13767
|
+
let stopped = false;
|
|
13768
|
+
let renewalError;
|
|
13769
|
+
let pending = Promise.resolve();
|
|
13770
|
+
const timer = setInterval(() => {
|
|
13771
|
+
pending = pending.then(async () => {
|
|
13772
|
+
const now = /* @__PURE__ */ new Date();
|
|
13773
|
+
try {
|
|
13774
|
+
await input.backend.renewLoopDispatch(
|
|
13775
|
+
input.tenantId,
|
|
13776
|
+
input.idempotencyKey,
|
|
13777
|
+
input.reservationId,
|
|
13778
|
+
new Date(now.getTime() + LOOP_DISPATCH_LEASE_MS).toISOString(),
|
|
13779
|
+
now.toISOString()
|
|
13780
|
+
);
|
|
13781
|
+
} catch (error) {
|
|
13782
|
+
renewalError ??= error;
|
|
13783
|
+
}
|
|
13784
|
+
});
|
|
13785
|
+
}, LOOP_DISPATCH_RENEW_INTERVAL_MS);
|
|
13786
|
+
timer.unref?.();
|
|
13787
|
+
return async () => {
|
|
13788
|
+
if (!stopped) {
|
|
13789
|
+
stopped = true;
|
|
13790
|
+
clearInterval(timer);
|
|
13791
|
+
}
|
|
13792
|
+
await pending;
|
|
13793
|
+
if (renewalError) throw renewalError;
|
|
13794
|
+
};
|
|
13795
|
+
}
|
|
13736
13796
|
function selectRunnableLoops(loops, now, options) {
|
|
13737
13797
|
return loops.filter(
|
|
13738
13798
|
(loop) => loop.enabled && (!options.loopId || loop.id === options.loopId) && (options.force || loop.trigger.type === "schedule" && dueSlot(loop, now) !== null)
|
|
@@ -13781,14 +13841,15 @@ function repositoryTenant(config) {
|
|
|
13781
13841
|
const repo = config.github?.repo?.trim() || envRepo?.trim();
|
|
13782
13842
|
return owner && repo ? `${owner}/${repo}` : null;
|
|
13783
13843
|
}
|
|
13784
|
-
var LOOP_DISPATCH_LEASE_MS, dispatchLoops;
|
|
13844
|
+
var LOOP_DISPATCH_LEASE_MS, LOOP_DISPATCH_RENEW_INTERVAL_MS, dispatchLoops;
|
|
13785
13845
|
var init_dispatchLoops = __esm({
|
|
13786
13846
|
"src/scripts/dispatchLoops.ts"() {
|
|
13787
13847
|
"use strict";
|
|
13788
13848
|
init_job();
|
|
13789
13849
|
init_loopDefinitions();
|
|
13790
13850
|
init_state_backend();
|
|
13791
|
-
LOOP_DISPATCH_LEASE_MS =
|
|
13851
|
+
LOOP_DISPATCH_LEASE_MS = 10 * 60 * 1e3;
|
|
13852
|
+
LOOP_DISPATCH_RENEW_INTERVAL_MS = 60 * 1e3;
|
|
13792
13853
|
dispatchLoops = async (ctx) => {
|
|
13793
13854
|
const tenantId2 = repositoryTenant(ctx.config);
|
|
13794
13855
|
if (!tenantId2) throw new Error("Repository identity is required for Loop dispatch");
|
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.533",
|
|
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",
|