@kody-ade/kody-engine 0.4.559 → 0.4.561
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
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.561",
|
|
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",
|
|
@@ -40,6 +40,7 @@ var init_package = __esm({
|
|
|
40
40
|
posttest: "tsx scripts/check-coverage-floor.ts",
|
|
41
41
|
"test:smoke": "vitest run tests/smoke --no-coverage",
|
|
42
42
|
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
43
|
+
"verify:live-release": "tsx scripts/live-release-gate.ts",
|
|
43
44
|
"test:runtime-services": 'node --test "tests/runtime-services/*.test.mjs"',
|
|
44
45
|
"test:all": "vitest run tests --no-coverage",
|
|
45
46
|
typecheck: "tsc --noEmit",
|
|
@@ -3105,6 +3106,39 @@ function createStateBackendFromEnv(env = process.env, client) {
|
|
|
3105
3106
|
state,
|
|
3106
3107
|
updatedAt
|
|
3107
3108
|
});
|
|
3109
|
+
},
|
|
3110
|
+
async acquireWorkflowRunLease(tenantId2, workflowId, runId, ownerId, nowMs, leaseDurationMs) {
|
|
3111
|
+
const result = await transport.mutation(anyApi.workflowRunLeases.acquire, {
|
|
3112
|
+
tenantId: requireTenant(tenantId2),
|
|
3113
|
+
workflowId: requireNonEmpty(workflowId, "workflowId"),
|
|
3114
|
+
runId: requireNonEmpty(runId, "runId"),
|
|
3115
|
+
ownerId: requireNonEmpty(ownerId, "ownerId"),
|
|
3116
|
+
nowMs,
|
|
3117
|
+
leaseDurationMs
|
|
3118
|
+
});
|
|
3119
|
+
return result;
|
|
3120
|
+
},
|
|
3121
|
+
async renewWorkflowRunLease(tenantId2, workflowId, runId, ownerId, nowMs, leaseDurationMs) {
|
|
3122
|
+
return Boolean(
|
|
3123
|
+
await transport.mutation(anyApi.workflowRunLeases.renew, {
|
|
3124
|
+
tenantId: requireTenant(tenantId2),
|
|
3125
|
+
workflowId: requireNonEmpty(workflowId, "workflowId"),
|
|
3126
|
+
runId: requireNonEmpty(runId, "runId"),
|
|
3127
|
+
ownerId: requireNonEmpty(ownerId, "ownerId"),
|
|
3128
|
+
nowMs,
|
|
3129
|
+
leaseDurationMs
|
|
3130
|
+
})
|
|
3131
|
+
);
|
|
3132
|
+
},
|
|
3133
|
+
async releaseWorkflowRunLease(tenantId2, workflowId, runId, ownerId) {
|
|
3134
|
+
return Boolean(
|
|
3135
|
+
await transport.mutation(anyApi.workflowRunLeases.release, {
|
|
3136
|
+
tenantId: requireTenant(tenantId2),
|
|
3137
|
+
workflowId: requireNonEmpty(workflowId, "workflowId"),
|
|
3138
|
+
runId: requireNonEmpty(runId, "runId"),
|
|
3139
|
+
ownerId: requireNonEmpty(ownerId, "ownerId")
|
|
3140
|
+
})
|
|
3141
|
+
);
|
|
3108
3142
|
}
|
|
3109
3143
|
};
|
|
3110
3144
|
}
|
|
@@ -22711,6 +22745,90 @@ var init_simpleCapabilityRuntime = __esm({
|
|
|
22711
22745
|
}
|
|
22712
22746
|
});
|
|
22713
22747
|
|
|
22748
|
+
// src/workflowDefinitionIdentity.ts
|
|
22749
|
+
import { createHash as createHash8 } from "crypto";
|
|
22750
|
+
function workflowDefinitionHash(workflow) {
|
|
22751
|
+
return createHash8("sha256").update(stableJson(workflow)).digest("hex");
|
|
22752
|
+
}
|
|
22753
|
+
function workflowResumeBlocker(state, workflow) {
|
|
22754
|
+
if (!state || state.status === "done") return null;
|
|
22755
|
+
if (!state.definitionHash) return null;
|
|
22756
|
+
if (state.definitionHash !== workflowDefinitionHash(workflow)) {
|
|
22757
|
+
return "The Workflow definition changed after this run started. Start a new run instead of resuming it.";
|
|
22758
|
+
}
|
|
22759
|
+
return null;
|
|
22760
|
+
}
|
|
22761
|
+
function stableJson(value) {
|
|
22762
|
+
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
|
|
22763
|
+
if (value && typeof value === "object") {
|
|
22764
|
+
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson(item)}`).join(",")}}`;
|
|
22765
|
+
}
|
|
22766
|
+
return JSON.stringify(value) ?? "undefined";
|
|
22767
|
+
}
|
|
22768
|
+
var init_workflowDefinitionIdentity = __esm({
|
|
22769
|
+
"src/workflowDefinitionIdentity.ts"() {
|
|
22770
|
+
"use strict";
|
|
22771
|
+
}
|
|
22772
|
+
});
|
|
22773
|
+
|
|
22774
|
+
// src/workflowRunLease.ts
|
|
22775
|
+
async function acquireWorkflowRunLease(store, input) {
|
|
22776
|
+
const result = await store.acquireWorkflowRunLease(
|
|
22777
|
+
input.tenantId,
|
|
22778
|
+
input.workflowId,
|
|
22779
|
+
input.runId,
|
|
22780
|
+
input.ownerId,
|
|
22781
|
+
input.nowMs,
|
|
22782
|
+
WORKFLOW_RUN_LEASE_MS
|
|
22783
|
+
);
|
|
22784
|
+
if (!result.acquired) return result;
|
|
22785
|
+
return { acquired: true, lease: new WorkflowRunLease(store, input) };
|
|
22786
|
+
}
|
|
22787
|
+
var WORKFLOW_RUN_LEASE_MS, WorkflowRunLeaseLostError, WorkflowRunLease;
|
|
22788
|
+
var init_workflowRunLease = __esm({
|
|
22789
|
+
"src/workflowRunLease.ts"() {
|
|
22790
|
+
"use strict";
|
|
22791
|
+
WORKFLOW_RUN_LEASE_MS = 8 * 60 * 60 * 1e3;
|
|
22792
|
+
WorkflowRunLeaseLostError = class extends Error {
|
|
22793
|
+
constructor() {
|
|
22794
|
+
super("Workflow run ownership was lost; execution stopped to prevent duplicate work.");
|
|
22795
|
+
this.name = "WorkflowRunLeaseLostError";
|
|
22796
|
+
}
|
|
22797
|
+
};
|
|
22798
|
+
WorkflowRunLease = class {
|
|
22799
|
+
constructor(store, identity) {
|
|
22800
|
+
this.store = store;
|
|
22801
|
+
this.identity = identity;
|
|
22802
|
+
}
|
|
22803
|
+
store;
|
|
22804
|
+
identity;
|
|
22805
|
+
released = false;
|
|
22806
|
+
async checkpoint(nowMs = Date.now()) {
|
|
22807
|
+
if (this.released) throw new WorkflowRunLeaseLostError();
|
|
22808
|
+
const renewed = await this.store.renewWorkflowRunLease(
|
|
22809
|
+
this.identity.tenantId,
|
|
22810
|
+
this.identity.workflowId,
|
|
22811
|
+
this.identity.runId,
|
|
22812
|
+
this.identity.ownerId,
|
|
22813
|
+
nowMs,
|
|
22814
|
+
WORKFLOW_RUN_LEASE_MS
|
|
22815
|
+
);
|
|
22816
|
+
if (!renewed) throw new WorkflowRunLeaseLostError();
|
|
22817
|
+
}
|
|
22818
|
+
async release() {
|
|
22819
|
+
if (this.released) return;
|
|
22820
|
+
this.released = true;
|
|
22821
|
+
await this.store.releaseWorkflowRunLease(
|
|
22822
|
+
this.identity.tenantId,
|
|
22823
|
+
this.identity.workflowId,
|
|
22824
|
+
this.identity.runId,
|
|
22825
|
+
this.identity.ownerId
|
|
22826
|
+
);
|
|
22827
|
+
}
|
|
22828
|
+
};
|
|
22829
|
+
}
|
|
22830
|
+
});
|
|
22831
|
+
|
|
22714
22832
|
// src/workflowRunState.ts
|
|
22715
22833
|
function workflowRunStatePath(workflowId, runId) {
|
|
22716
22834
|
if (!SAFE_ID.test(workflowId)) throw new Error(`invalid workflow id ${workflowId}`);
|
|
@@ -22770,21 +22888,21 @@ function parseWorkflowSteps(value) {
|
|
|
22770
22888
|
return Object.keys(steps).length > 0 ? steps : void 0;
|
|
22771
22889
|
}
|
|
22772
22890
|
async function readWorkflowRunState(config, _cwd, workflowId, runId) {
|
|
22773
|
-
const tenantId2 =
|
|
22891
|
+
const tenantId2 = workflowRuntimeTenant(config);
|
|
22774
22892
|
const row = await createStateBackendFromEnv().getWorkflowRun(tenantId2, workflowId, runId);
|
|
22775
22893
|
return row ? parseWorkflowRunState(row.state) : null;
|
|
22776
22894
|
}
|
|
22777
22895
|
async function writeWorkflowRunState(config, _cwd, workflowId, runId, state) {
|
|
22778
22896
|
workflowRunStatePath(workflowId, runId);
|
|
22779
22897
|
await createStateBackendFromEnv().saveWorkflowRun(
|
|
22780
|
-
|
|
22898
|
+
workflowRuntimeTenant(config),
|
|
22781
22899
|
workflowId,
|
|
22782
22900
|
runId,
|
|
22783
22901
|
state,
|
|
22784
22902
|
(/* @__PURE__ */ new Date()).toISOString()
|
|
22785
22903
|
);
|
|
22786
22904
|
}
|
|
22787
|
-
function
|
|
22905
|
+
function workflowRuntimeTenant(config) {
|
|
22788
22906
|
if (config.github?.owner && config.github.repo) return `${config.github.owner}/${config.github.repo}`;
|
|
22789
22907
|
const tenantId2 = process.env.GITHUB_REPOSITORY?.trim();
|
|
22790
22908
|
if (!tenantId2) throw new Error("Repository identity is required for workflow run state");
|
|
@@ -22811,7 +22929,7 @@ __export(job_exports, {
|
|
|
22811
22929
|
stableJobKey: () => stableJobKey,
|
|
22812
22930
|
validateJob: () => validateJob
|
|
22813
22931
|
});
|
|
22814
|
-
import {
|
|
22932
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
22815
22933
|
function newJobId(flavor) {
|
|
22816
22934
|
localJobSeq += 1;
|
|
22817
22935
|
const runId = process.env.GITHUB_RUN_ID;
|
|
@@ -22901,75 +23019,100 @@ async function runJob(job, base) {
|
|
|
22901
23019
|
const capabilitySelectedImplementation = simpleCapabilityRuntime?.implementation ?? resolvedCapability?.implementation ?? capabilityContext?.config.implementation ?? capabilityContext?.config.implementations?.[0] ?? (capabilityContext?.config.role ? capabilityContext.slug : void 0) ?? (capabilityContext?.config.tickScript ? "capability-tick-scripted" : void 0);
|
|
22902
23020
|
const profileName = explicitImplementation ?? capabilitySelectedImplementation;
|
|
22903
23021
|
if (workflow && shouldRunCapabilityWorkflow(valid, workflow, workflowIdentity, capabilitySelectedImplementation, base)) {
|
|
22904
|
-
const
|
|
22905
|
-
|
|
22906
|
-
|
|
22907
|
-
|
|
22908
|
-
|
|
22909
|
-
|
|
22910
|
-
};
|
|
22911
|
-
|
|
22912
|
-
|
|
22913
|
-
|
|
22914
|
-
|
|
22915
|
-
|
|
22916
|
-
id: parentRunId,
|
|
22917
|
-
subjectType: "workflow",
|
|
22918
|
-
subjectId: workflowIdentity,
|
|
22919
|
-
subjectLabel: workflowCapability.title,
|
|
22920
|
-
status: "running",
|
|
22921
|
-
title: workflowCapability.title,
|
|
22922
|
-
startedAt,
|
|
22923
|
-
updatedAt: startedAt,
|
|
22924
|
-
workflow: workflowIdentity,
|
|
22925
|
-
kodyRunId: valid.workflowRunId,
|
|
22926
|
-
parentRunId: typeof base.preloadedData?.parentRunId === "string" ? base.preloadedData.parentRunId : void 0,
|
|
22927
|
-
sourceType: "job"
|
|
22928
|
-
};
|
|
22929
|
-
const persistRun = Boolean(base.config && !base.skipConfig && hasStateBackendConfig());
|
|
22930
|
-
if (base.config && persistRun) {
|
|
22931
|
-
await upsertRunIndexRowBestEffortAsync(base.config, base.cwd, parentRow);
|
|
23022
|
+
const leaseResult = valid.workflowRunId && workflowIdentity && base.config && hasStateBackendConfig() ? await acquireWorkflowRunLease(createStateBackendFromEnv(), {
|
|
23023
|
+
tenantId: workflowRuntimeTenant(base.config),
|
|
23024
|
+
workflowId: workflowIdentity,
|
|
23025
|
+
runId: valid.workflowRunId,
|
|
23026
|
+
ownerId: `${process.env.GITHUB_RUN_ID ?? "local"}:${process.env.GITHUB_RUN_ATTEMPT ?? "1"}:${randomUUID3()}`,
|
|
23027
|
+
nowMs: Date.now()
|
|
23028
|
+
}) : null;
|
|
23029
|
+
if (leaseResult && !leaseResult.acquired) {
|
|
23030
|
+
return {
|
|
23031
|
+
exitCode: 75,
|
|
23032
|
+
reason: `Workflow ${workflowIdentity} run ${valid.workflowRunId} is already running.`
|
|
23033
|
+
};
|
|
22932
23034
|
}
|
|
22933
|
-
const
|
|
22934
|
-
...base,
|
|
22935
|
-
preloadedData: { ...base.preloadedData ?? {}, parentRunId }
|
|
22936
|
-
};
|
|
22937
|
-
let result;
|
|
23035
|
+
const lease = leaseResult?.acquired ? leaseResult.lease : null;
|
|
22938
23036
|
try {
|
|
22939
|
-
|
|
22940
|
-
|
|
23037
|
+
const workflowCapability = capabilityContext ?? workflowContext;
|
|
23038
|
+
const persistedState = valid.workflowRunId && workflowIdentity && base.config ? await readWorkflowRunState(base.config, base.cwd, workflowIdentity, valid.workflowRunId) : null;
|
|
23039
|
+
const workflowJob = {
|
|
23040
|
+
...workflowContext && !valid.why ? { ...valid, why: workflowContext.body } : valid,
|
|
23041
|
+
...workflowCapability.config.agent ? { agent: workflowCapability.config.agent } : {},
|
|
23042
|
+
...valid.workflowState ?? persistedState ? { workflowState: valid.workflowState ?? persistedState ?? void 0 } : {}
|
|
23043
|
+
};
|
|
23044
|
+
const checkpoint = valid.workflowRunId && workflowIdentity && base.config ? async (state) => {
|
|
23045
|
+
await lease?.checkpoint();
|
|
23046
|
+
await writeWorkflowRunState(base.config, base.cwd, workflowIdentity, valid.workflowRunId, state);
|
|
23047
|
+
} : void 0;
|
|
23048
|
+
const parentRunId = `workflow:${workflowIdentity}:${valid.workflowRunId ?? newJobId(valid.flavor)}`;
|
|
23049
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
23050
|
+
const parentRow = {
|
|
23051
|
+
version: 1,
|
|
23052
|
+
id: parentRunId,
|
|
23053
|
+
subjectType: "workflow",
|
|
23054
|
+
subjectId: workflowIdentity,
|
|
23055
|
+
subjectLabel: workflowCapability.title,
|
|
23056
|
+
status: "running",
|
|
23057
|
+
title: workflowCapability.title,
|
|
23058
|
+
startedAt,
|
|
23059
|
+
updatedAt: startedAt,
|
|
23060
|
+
workflow: workflowIdentity,
|
|
23061
|
+
kodyRunId: valid.workflowRunId,
|
|
23062
|
+
parentRunId: typeof base.preloadedData?.parentRunId === "string" ? base.preloadedData.parentRunId : void 0,
|
|
23063
|
+
sourceType: "job"
|
|
23064
|
+
};
|
|
23065
|
+
const persistRun = Boolean(base.config && !base.skipConfig && hasStateBackendConfig());
|
|
23066
|
+
if (base.config && persistRun) {
|
|
23067
|
+
await upsertRunIndexRowBestEffortAsync(base.config, base.cwd, parentRow);
|
|
23068
|
+
}
|
|
23069
|
+
const workflowBase = {
|
|
23070
|
+
...base,
|
|
23071
|
+
preloadedData: { ...base.preloadedData ?? {}, parentRunId }
|
|
23072
|
+
};
|
|
23073
|
+
let result;
|
|
23074
|
+
try {
|
|
23075
|
+
result = await runCapabilityWorkflow(workflowJob, workflow, workflowCapability, workflowBase, checkpoint);
|
|
23076
|
+
} catch (error) {
|
|
23077
|
+
if (base.config && persistRun) {
|
|
23078
|
+
await upsertRunIndexRowBestEffortAsync(base.config, base.cwd, {
|
|
23079
|
+
...parentRow,
|
|
23080
|
+
status: "failed",
|
|
23081
|
+
summary: error instanceof Error ? error.message : String(error),
|
|
23082
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
23083
|
+
});
|
|
23084
|
+
}
|
|
23085
|
+
throw error;
|
|
23086
|
+
}
|
|
22941
23087
|
if (base.config && persistRun) {
|
|
22942
23088
|
await upsertRunIndexRowBestEffortAsync(base.config, base.cwd, {
|
|
22943
23089
|
...parentRow,
|
|
22944
|
-
status: "failed",
|
|
22945
|
-
summary:
|
|
23090
|
+
status: result.exitCode === 0 ? "success" : "failed",
|
|
23091
|
+
summary: result.reason,
|
|
22946
23092
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
22947
23093
|
});
|
|
22948
23094
|
}
|
|
22949
|
-
|
|
22950
|
-
|
|
22951
|
-
|
|
22952
|
-
|
|
22953
|
-
|
|
22954
|
-
|
|
22955
|
-
|
|
22956
|
-
|
|
22957
|
-
|
|
22958
|
-
|
|
22959
|
-
|
|
22960
|
-
|
|
22961
|
-
|
|
22962
|
-
|
|
22963
|
-
|
|
22964
|
-
|
|
22965
|
-
|
|
22966
|
-
|
|
22967
|
-
|
|
22968
|
-
...result.reason ? { summary: result.reason } : {},
|
|
22969
|
-
...Object.keys(facts).length > 0 ? { output: facts } : {}
|
|
23095
|
+
if (valid.workflowRunId && workflowIdentity && base.config && result.workflowState) {
|
|
23096
|
+
await lease?.checkpoint();
|
|
23097
|
+
await writeWorkflowRunState(base.config, base.cwd, workflowIdentity, valid.workflowRunId, result.workflowState);
|
|
23098
|
+
}
|
|
23099
|
+
if (valid.workflowRunId && workflowIdentity && hasGitHubActionsIdentity()) {
|
|
23100
|
+
const facts = result.workflowState?.facts ?? {};
|
|
23101
|
+
await notifyWorkflowCompleted({
|
|
23102
|
+
workflowId: workflowIdentity,
|
|
23103
|
+
runId: valid.workflowRunId,
|
|
23104
|
+
status: result.workflowState?.status === "blocked" ? "blocked" : result.exitCode === 0 ? "success" : "failed",
|
|
23105
|
+
...result.reason ? { summary: result.reason } : {},
|
|
23106
|
+
...Object.keys(facts).length > 0 ? { output: facts } : {}
|
|
23107
|
+
});
|
|
23108
|
+
}
|
|
23109
|
+
return result;
|
|
23110
|
+
} finally {
|
|
23111
|
+
await lease?.release().catch((error) => {
|
|
23112
|
+
process.stderr.write(`warning: failed to release Workflow run ownership: ${String(error)}
|
|
23113
|
+
`);
|
|
22970
23114
|
});
|
|
22971
23115
|
}
|
|
22972
|
-
return result;
|
|
22973
23116
|
}
|
|
22974
23117
|
if (!profileName) {
|
|
22975
23118
|
throw new InvalidJobError(`job capability resolves to no implementation: ${capabilityIdentity ?? action}`);
|
|
@@ -23049,7 +23192,35 @@ async function runCapabilityImplementationStep(valid, profileName, capabilityIde
|
|
|
23049
23192
|
input.cliArgs = simpleCapabilityRuntimeArgs(simpleCapabilityRuntime, capabilityIdentity, capabilityInput);
|
|
23050
23193
|
}
|
|
23051
23194
|
const run = base.chain === false ? runImplementation : runImplementationChain;
|
|
23052
|
-
|
|
23195
|
+
const result = await run(profileName, input);
|
|
23196
|
+
return enforceCapabilityOutputContract(capabilityContext, result);
|
|
23197
|
+
}
|
|
23198
|
+
function enforceCapabilityOutputContract(capability, result) {
|
|
23199
|
+
const schema = capability?.config.outputSchema;
|
|
23200
|
+
if (result.exitCode !== 0 || !schema || !Object.hasOwn(result, "capabilityOutput")) {
|
|
23201
|
+
return result;
|
|
23202
|
+
}
|
|
23203
|
+
try {
|
|
23204
|
+
validateCapabilityContractValue("output", schema, result.capabilityOutput);
|
|
23205
|
+
return result;
|
|
23206
|
+
} catch (error) {
|
|
23207
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
23208
|
+
const blocked = {
|
|
23209
|
+
version: 1,
|
|
23210
|
+
status: "blocked",
|
|
23211
|
+
summary: reason,
|
|
23212
|
+
facts: {},
|
|
23213
|
+
artifacts: [],
|
|
23214
|
+
missingEvidence: [],
|
|
23215
|
+
blockers: [reason]
|
|
23216
|
+
};
|
|
23217
|
+
return {
|
|
23218
|
+
...result,
|
|
23219
|
+
exitCode: 64,
|
|
23220
|
+
reason,
|
|
23221
|
+
capabilityResults: [blocked]
|
|
23222
|
+
};
|
|
23223
|
+
}
|
|
23053
23224
|
}
|
|
23054
23225
|
function shouldRunCapabilityWorkflow(job, workflow, capabilityIdentity, selectedImplementation, base) {
|
|
23055
23226
|
if (workflow.steps.length === 0) return false;
|
|
@@ -23072,6 +23243,14 @@ async function runCapabilityWorkflow(parent, workflow, capability, base, checkpo
|
|
|
23072
23243
|
}
|
|
23073
23244
|
return { exitCode: 64, reason: invalid };
|
|
23074
23245
|
}
|
|
23246
|
+
const resumeBlocker = workflowResumeBlocker(parent.workflowState, workflow);
|
|
23247
|
+
if (resumeBlocker) {
|
|
23248
|
+
const state = initialWorkflowState(parent, workflow);
|
|
23249
|
+
state.status = "blocked";
|
|
23250
|
+
state.blocker = resumeBlocker;
|
|
23251
|
+
await checkpoint?.(state);
|
|
23252
|
+
return { exitCode: 64, reason: resumeBlocker, workflowState: state };
|
|
23253
|
+
}
|
|
23075
23254
|
if (isGraphWorkflow(workflow)) {
|
|
23076
23255
|
const result = await runGraphCapabilityWorkflow(parent, workflow, capability, base, checkpoint);
|
|
23077
23256
|
if (workflow.report && result.workflowState) {
|
|
@@ -23548,16 +23727,6 @@ function capabilityInputNames(folder) {
|
|
|
23548
23727
|
if (!properties || typeof properties !== "object" || Array.isArray(properties)) return /* @__PURE__ */ new Set();
|
|
23549
23728
|
return new Set(Object.keys(properties));
|
|
23550
23729
|
}
|
|
23551
|
-
function workflowDefinitionHash(workflow) {
|
|
23552
|
-
return createHash8("sha256").update(stableJson(workflow)).digest("hex");
|
|
23553
|
-
}
|
|
23554
|
-
function stableJson(value) {
|
|
23555
|
-
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
|
|
23556
|
-
if (value && typeof value === "object") {
|
|
23557
|
-
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson(item)}`).join(",")}}`;
|
|
23558
|
-
}
|
|
23559
|
-
return JSON.stringify(value);
|
|
23560
|
-
}
|
|
23561
23730
|
function cloneWorkflowSteps(steps) {
|
|
23562
23731
|
return Object.fromEntries(Object.entries(steps).map(([id, step]) => [id, { ...step }]));
|
|
23563
23732
|
}
|
|
@@ -23769,6 +23938,7 @@ var init_job = __esm({
|
|
|
23769
23938
|
"src/job.ts"() {
|
|
23770
23939
|
"use strict";
|
|
23771
23940
|
init_agencyBoundaryEval();
|
|
23941
|
+
init_capability_contract_validation();
|
|
23772
23942
|
init_capabilityFolders();
|
|
23773
23943
|
init_config();
|
|
23774
23944
|
init_definition_paths();
|
|
@@ -23779,7 +23949,9 @@ var init_job = __esm({
|
|
|
23779
23949
|
init_publishReport();
|
|
23780
23950
|
init_simpleCapabilityRuntime();
|
|
23781
23951
|
init_state_backend();
|
|
23952
|
+
init_workflowDefinitionIdentity();
|
|
23782
23953
|
init_workflowDefinitions();
|
|
23954
|
+
init_workflowRunLease();
|
|
23783
23955
|
init_workflowRunState();
|
|
23784
23956
|
init_workflowValidation();
|
|
23785
23957
|
init_jobIdentity();
|
|
@@ -27476,7 +27648,7 @@ init_config();
|
|
|
27476
27648
|
init_fetchRepoMcp();
|
|
27477
27649
|
|
|
27478
27650
|
// src/servers/mcpHttpServer.ts
|
|
27479
|
-
import { randomUUID as
|
|
27651
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
27480
27652
|
import { createServer as createServer4 } from "http";
|
|
27481
27653
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
27482
27654
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
@@ -27485,7 +27657,7 @@ function buildMcpHttpServer(opts) {
|
|
|
27485
27657
|
const transports = /* @__PURE__ */ new Map();
|
|
27486
27658
|
for (const route of opts.routes) {
|
|
27487
27659
|
const transport = new StreamableHTTPServerTransport({
|
|
27488
|
-
sessionIdGenerator: () =>
|
|
27660
|
+
sessionIdGenerator: () => randomUUID4()
|
|
27489
27661
|
});
|
|
27490
27662
|
transports.set(route.path, transport);
|
|
27491
27663
|
routes.set(route.path, route.name);
|
|
File without changes
|
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.561",
|
|
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,6 +12,30 @@
|
|
|
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
|
+
"verify:live-release": "tsx scripts/live-release-gate.ts",
|
|
29
|
+
"test:runtime-services": "node --test \"tests/runtime-services/*.test.mjs\"",
|
|
30
|
+
"test:all": "vitest run tests --no-coverage",
|
|
31
|
+
"typecheck": "tsc --noEmit",
|
|
32
|
+
"lint": "biome check",
|
|
33
|
+
"lint:fix": "biome check --write",
|
|
34
|
+
"format": "biome format --write",
|
|
35
|
+
"verify:package": "node scripts/verify-package-tarball.cjs",
|
|
36
|
+
"brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain --build-arg KODY_ENGINE_REF=$(git rev-parse HEAD) -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner",
|
|
37
|
+
"prepublishOnly": "pnpm typecheck && pnpm test:runtime-services && pnpm build && pnpm verify:package"
|
|
38
|
+
},
|
|
15
39
|
"dependencies": {
|
|
16
40
|
"@actions/cache": "^6.0.0",
|
|
17
41
|
"@anthropic-ai/claude-agent-sdk": "0.2.119",
|
|
@@ -38,27 +62,5 @@
|
|
|
38
62
|
"url": "git+https://github.com/aharonyaircohen/kody-engine.git"
|
|
39
63
|
},
|
|
40
64
|
"homepage": "https://github.com/aharonyaircohen/kody-engine",
|
|
41
|
-
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
42
|
-
|
|
43
|
-
"kody:run": "tsx bin/kody.ts",
|
|
44
|
-
"serve": "tsx bin/kody.ts serve",
|
|
45
|
-
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
46
|
-
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
47
|
-
"clean:dist": "node scripts/clean-dist.cjs",
|
|
48
|
-
"build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
|
|
49
|
-
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
50
|
-
"pretest": "pnpm check:modularity",
|
|
51
|
-
"test": "vitest run tests/unit tests/int --coverage",
|
|
52
|
-
"posttest": "tsx scripts/check-coverage-floor.ts",
|
|
53
|
-
"test:smoke": "vitest run tests/smoke --no-coverage",
|
|
54
|
-
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
55
|
-
"test:runtime-services": "node --test \"tests/runtime-services/*.test.mjs\"",
|
|
56
|
-
"test:all": "vitest run tests --no-coverage",
|
|
57
|
-
"typecheck": "tsc --noEmit",
|
|
58
|
-
"lint": "biome check",
|
|
59
|
-
"lint:fix": "biome check --write",
|
|
60
|
-
"format": "biome format --write",
|
|
61
|
-
"verify:package": "node scripts/verify-package-tarball.cjs",
|
|
62
|
-
"brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain --build-arg KODY_ENGINE_REF=$(git rev-parse HEAD) -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner"
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
+
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
66
|
+
}
|