@kody-ade/kody-engine 0.4.445 → 0.4.447
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.447",
|
|
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",
|
|
@@ -1795,11 +1795,11 @@ function parseWorkflowTransitions(value) {
|
|
|
1795
1795
|
const transitions = rawTransitions.map((raw) => {
|
|
1796
1796
|
if (typeof raw === "string") {
|
|
1797
1797
|
const to2 = raw.trim();
|
|
1798
|
-
return isSafeStepId(to2) ? { to: to2 } : null;
|
|
1798
|
+
return to2 === "$end" || isSafeStepId(to2) ? { to: to2 } : null;
|
|
1799
1799
|
}
|
|
1800
1800
|
if (!isPlainObject(raw)) return null;
|
|
1801
1801
|
const to = stringField(raw.to);
|
|
1802
|
-
if (!to || !isSafeStepId(to)) return null;
|
|
1802
|
+
if (!to || to !== "$end" && !isSafeStepId(to)) return null;
|
|
1803
1803
|
const maxIterations = typeof raw.maxIterations === "number" && Number.isInteger(raw.maxIterations) && raw.maxIterations > 0 ? raw.maxIterations : void 0;
|
|
1804
1804
|
return {
|
|
1805
1805
|
to,
|
|
@@ -1862,11 +1862,11 @@ function definitionsRoot(cwd = process.cwd()) {
|
|
|
1862
1862
|
const override = process.env.KODY_DEFINITIONS_ROOT?.trim();
|
|
1863
1863
|
const overrideCwd = process.env.KODY_DEFINITIONS_ROOT_CWD?.trim();
|
|
1864
1864
|
if (override && overrideCwd && path6.resolve(cwd) === path6.resolve(overrideCwd)) {
|
|
1865
|
-
return path6.resolve(override);
|
|
1865
|
+
return storeCatalogRoot(path6.resolve(override));
|
|
1866
1866
|
}
|
|
1867
1867
|
const hydrated = path6.join(cwd, ".kody-engine", "definitions");
|
|
1868
1868
|
if (fs5.existsSync(hydrated)) return hydrated;
|
|
1869
|
-
return override ? path6.resolve(override) : hydrated;
|
|
1869
|
+
return override ? storeCatalogRoot(path6.resolve(override)) : hydrated;
|
|
1870
1870
|
}
|
|
1871
1871
|
function hasExplicitDefinitionsRoot(cwd = process.cwd(), env = process.env) {
|
|
1872
1872
|
const root = env.KODY_DEFINITIONS_ROOT?.trim();
|
|
@@ -1874,13 +1874,36 @@ function hasExplicitDefinitionsRoot(cwd = process.cwd(), env = process.env) {
|
|
|
1874
1874
|
return Boolean(root && rootCwd && path6.resolve(cwd) === path6.resolve(rootCwd));
|
|
1875
1875
|
}
|
|
1876
1876
|
function capabilitiesRoot(cwd = process.cwd()) {
|
|
1877
|
-
return path6.join(definitionsRoot(cwd), "capabilities");
|
|
1877
|
+
return storeAssetRoot(cwd, "capabilities") ?? path6.join(definitionsRoot(cwd), "capabilities");
|
|
1878
1878
|
}
|
|
1879
1879
|
function implementationsRoot(cwd = process.cwd()) {
|
|
1880
1880
|
return path6.join(definitionsRoot(cwd), "implementations");
|
|
1881
1881
|
}
|
|
1882
1882
|
function agentsRoot(cwd = process.cwd()) {
|
|
1883
|
-
return path6.join(definitionsRoot(cwd), "agents");
|
|
1883
|
+
return storeAssetRoot(cwd, "agent") ?? path6.join(definitionsRoot(cwd), "agents");
|
|
1884
|
+
}
|
|
1885
|
+
function storeCatalogRoot(root) {
|
|
1886
|
+
const manifest = readStoreManifest(root);
|
|
1887
|
+
const roots = ["capabilities", "workflows", "loops"].map((kind) => manifest?.assetRoots?.[kind]).filter((value) => typeof value === "string" && Boolean(value.trim())).map((value) => path6.dirname(value));
|
|
1888
|
+
return roots.length === 3 && new Set(roots).size === 1 ? path6.join(root, roots[0]) : root;
|
|
1889
|
+
}
|
|
1890
|
+
function storeAssetRoot(cwd, kind) {
|
|
1891
|
+
const override = process.env.KODY_DEFINITIONS_ROOT?.trim();
|
|
1892
|
+
if (!override) return null;
|
|
1893
|
+
const overrideCwd = process.env.KODY_DEFINITIONS_ROOT_CWD?.trim();
|
|
1894
|
+
if (overrideCwd && path6.resolve(cwd) !== path6.resolve(overrideCwd)) return null;
|
|
1895
|
+
const root = path6.resolve(override);
|
|
1896
|
+
const configured = readStoreManifest(root)?.assetRoots?.[kind];
|
|
1897
|
+
return typeof configured === "string" && configured.trim() ? path6.join(root, configured) : null;
|
|
1898
|
+
}
|
|
1899
|
+
function readStoreManifest(root) {
|
|
1900
|
+
const file = path6.join(root, "kody-store.json");
|
|
1901
|
+
if (!fs5.existsSync(file)) return null;
|
|
1902
|
+
try {
|
|
1903
|
+
return JSON.parse(fs5.readFileSync(file, "utf8"));
|
|
1904
|
+
} catch {
|
|
1905
|
+
return null;
|
|
1906
|
+
}
|
|
1884
1907
|
}
|
|
1885
1908
|
var init_definition_paths = __esm({
|
|
1886
1909
|
"src/definition-paths.ts"() {
|
|
@@ -8959,10 +8982,13 @@ function validateWorkflow(value, options = {}) {
|
|
|
8959
8982
|
}
|
|
8960
8983
|
}
|
|
8961
8984
|
const target = text(raw.to);
|
|
8962
|
-
if (!target || !SAFE_STEP_ID.test(target)) {
|
|
8985
|
+
if (!target || target !== "$end" && !SAFE_STEP_ID.test(target)) {
|
|
8963
8986
|
issue(issues, "invalid_transition_target", `${base}.to`, "workflow connection must name a valid target step");
|
|
8964
8987
|
return;
|
|
8965
8988
|
}
|
|
8989
|
+
if (target === "$end") {
|
|
8990
|
+
return;
|
|
8991
|
+
}
|
|
8966
8992
|
if (!seen.has(target)) {
|
|
8967
8993
|
issue(
|
|
8968
8994
|
issues,
|
|
@@ -13798,6 +13824,204 @@ var init_dispatchAgencyLoops = __esm({
|
|
|
13798
13824
|
}
|
|
13799
13825
|
});
|
|
13800
13826
|
|
|
13827
|
+
// src/loopDefinitions.ts
|
|
13828
|
+
import * as fs36 from "fs";
|
|
13829
|
+
import * as path34 from "path";
|
|
13830
|
+
function normalizeLoopDefinition(value) {
|
|
13831
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
13832
|
+
const raw = value;
|
|
13833
|
+
if (Object.keys(raw).some((key) => !["id", "trigger", "target", "input", "enabled"].includes(key))) return null;
|
|
13834
|
+
if (typeof raw.id !== "string" || !ID.test(raw.id)) return null;
|
|
13835
|
+
if (typeof raw.enabled !== "boolean") return null;
|
|
13836
|
+
if (!isObject(raw.input) || !isObject(raw.trigger) || !isObject(raw.target)) return null;
|
|
13837
|
+
const targetKind = raw.target.kind;
|
|
13838
|
+
const targetId = raw.target.id;
|
|
13839
|
+
if (targetKind !== "workflow" && targetKind !== "capability" || typeof targetId !== "string" || !ID.test(targetId)) {
|
|
13840
|
+
return null;
|
|
13841
|
+
}
|
|
13842
|
+
const trigger = normalizeTrigger(raw.trigger);
|
|
13843
|
+
if (!trigger) return null;
|
|
13844
|
+
return {
|
|
13845
|
+
id: raw.id,
|
|
13846
|
+
trigger,
|
|
13847
|
+
target: { kind: targetKind, id: targetId },
|
|
13848
|
+
input: raw.input,
|
|
13849
|
+
enabled: raw.enabled
|
|
13850
|
+
};
|
|
13851
|
+
}
|
|
13852
|
+
function readLoopDefinition(cwd, id) {
|
|
13853
|
+
if (!ID.test(id)) return null;
|
|
13854
|
+
const roots = [path34.join(cwd, ".kody-engine", "runtime"), definitionsRoot(cwd)];
|
|
13855
|
+
for (const root of roots) {
|
|
13856
|
+
const filePath = path34.join(root, "loops", id, "loop.json");
|
|
13857
|
+
if (!fs36.existsSync(filePath)) continue;
|
|
13858
|
+
try {
|
|
13859
|
+
const loop = normalizeLoopDefinition(JSON.parse(fs36.readFileSync(filePath, "utf8")));
|
|
13860
|
+
if (loop?.id === id) return loop;
|
|
13861
|
+
process.stderr.write(`[kody] invalid simple Loop definition: ${filePath}
|
|
13862
|
+
`);
|
|
13863
|
+
} catch {
|
|
13864
|
+
process.stderr.write(`[kody] unreadable simple Loop definition: ${filePath}
|
|
13865
|
+
`);
|
|
13866
|
+
}
|
|
13867
|
+
}
|
|
13868
|
+
process.stderr.write(
|
|
13869
|
+
`[kody] simple Loop not found: ${id} (${roots.map((root) => path34.join(root, "loops", id, "loop.json")).join(", ")})
|
|
13870
|
+
`
|
|
13871
|
+
);
|
|
13872
|
+
return null;
|
|
13873
|
+
}
|
|
13874
|
+
function listLoopDefinitions(cwd) {
|
|
13875
|
+
const roots = [path34.join(cwd, ".kody-engine", "runtime"), definitionsRoot(cwd)];
|
|
13876
|
+
const byId = /* @__PURE__ */ new Map();
|
|
13877
|
+
for (const root of roots.reverse()) {
|
|
13878
|
+
const loopsDir = path34.join(root, "loops");
|
|
13879
|
+
if (!fs36.existsSync(loopsDir)) continue;
|
|
13880
|
+
for (const id of fs36.readdirSync(loopsDir).sort()) {
|
|
13881
|
+
if (!ID.test(id)) continue;
|
|
13882
|
+
const filePath = path34.join(loopsDir, id, "loop.json");
|
|
13883
|
+
if (!fs36.existsSync(filePath)) continue;
|
|
13884
|
+
try {
|
|
13885
|
+
const loop = normalizeLoopDefinition(JSON.parse(fs36.readFileSync(filePath, "utf8")));
|
|
13886
|
+
if (loop?.id === id) byId.set(id, loop);
|
|
13887
|
+
} catch {
|
|
13888
|
+
process.stderr.write(`[kody] unreadable simple Loop definition: ${filePath}
|
|
13889
|
+
`);
|
|
13890
|
+
}
|
|
13891
|
+
}
|
|
13892
|
+
}
|
|
13893
|
+
return [...byId.values()].sort((left, right) => left.id.localeCompare(right.id));
|
|
13894
|
+
}
|
|
13895
|
+
function normalizeTrigger(raw) {
|
|
13896
|
+
if (raw.type === "manual" && Object.keys(raw).length === 1) return { type: "manual" };
|
|
13897
|
+
if (raw.type === "schedule" && typeof raw.every === "string" && /^\d+[mhd]$/.test(raw.every)) {
|
|
13898
|
+
if (raw.at === void 0 && Object.keys(raw).every((key) => key === "type" || key === "every")) {
|
|
13899
|
+
return { type: "schedule", every: raw.every };
|
|
13900
|
+
}
|
|
13901
|
+
if (isObject(raw.at) && typeof raw.at.time === "string" && typeof raw.at.timezone === "string" && Object.keys(raw.at).every((key) => key === "time" || key === "timezone") && Object.keys(raw).every((key) => key === "type" || key === "every" || key === "at")) {
|
|
13902
|
+
return { type: "schedule", every: raw.every, at: { time: raw.at.time, timezone: raw.at.timezone } };
|
|
13903
|
+
}
|
|
13904
|
+
}
|
|
13905
|
+
if ((raw.type === "event" || raw.type === "webhook") && typeof raw.event === "string" && raw.event.trim() && Object.keys(raw).every((key) => key === "type" || key === "event")) {
|
|
13906
|
+
return { type: raw.type, event: raw.event.trim() };
|
|
13907
|
+
}
|
|
13908
|
+
if (raw.type === "condition" && typeof raw.expression === "string" && raw.expression.trim() && Object.keys(raw).every((key) => key === "type" || key === "expression")) {
|
|
13909
|
+
return { type: "condition", expression: raw.expression.trim() };
|
|
13910
|
+
}
|
|
13911
|
+
return null;
|
|
13912
|
+
}
|
|
13913
|
+
function isObject(value) {
|
|
13914
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
13915
|
+
}
|
|
13916
|
+
var ID;
|
|
13917
|
+
var init_loopDefinitions = __esm({
|
|
13918
|
+
"src/loopDefinitions.ts"() {
|
|
13919
|
+
"use strict";
|
|
13920
|
+
init_definition_paths();
|
|
13921
|
+
ID = /^[a-z0-9][a-z0-9_-]{0,79}$/;
|
|
13922
|
+
}
|
|
13923
|
+
});
|
|
13924
|
+
|
|
13925
|
+
// src/scripts/dispatchSimpleLoops.ts
|
|
13926
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
13927
|
+
function dueSlot(loop, now) {
|
|
13928
|
+
if (!loop.enabled || loop.trigger.type !== "schedule") return null;
|
|
13929
|
+
const match = /^(\d+)([mhd])$/.exec(loop.trigger.every);
|
|
13930
|
+
if (!match) return null;
|
|
13931
|
+
const amount = Number(match[1]);
|
|
13932
|
+
const unit = match[2];
|
|
13933
|
+
const milliseconds = amount * (unit === "m" ? 6e4 : unit === "h" ? 36e5 : 864e5);
|
|
13934
|
+
const slot = Math.floor(now.getTime() / milliseconds) * milliseconds;
|
|
13935
|
+
if (!loop.trigger.at) return new Date(slot).toISOString();
|
|
13936
|
+
const parts = new Intl.DateTimeFormat("en-CA", {
|
|
13937
|
+
timeZone: loop.trigger.at.timezone,
|
|
13938
|
+
year: "numeric",
|
|
13939
|
+
month: "2-digit",
|
|
13940
|
+
day: "2-digit",
|
|
13941
|
+
hour: "2-digit",
|
|
13942
|
+
minute: "2-digit",
|
|
13943
|
+
hourCycle: "h23"
|
|
13944
|
+
}).formatToParts(now);
|
|
13945
|
+
const hour = parts.find((part) => part.type === "hour")?.value;
|
|
13946
|
+
const minute = parts.find((part) => part.type === "minute")?.value;
|
|
13947
|
+
const [targetHour, targetMinute] = loop.trigger.at.time.split(":").map(Number);
|
|
13948
|
+
const localMinute = Number(hour) * 60 + Number(minute);
|
|
13949
|
+
const targetLocalMinute = Number(targetHour) * 60 + Number(targetMinute);
|
|
13950
|
+
const windowMinutes = Math.max(1, Math.ceil(Number(process.env.KODY_SCHEDULE_WINDOW_SEC || 300) / 60));
|
|
13951
|
+
if (localMinute < targetLocalMinute || localMinute >= targetLocalMinute + windowMinutes) return null;
|
|
13952
|
+
const year = parts.find((part) => part.type === "year")?.value;
|
|
13953
|
+
const month = parts.find((part) => part.type === "month")?.value;
|
|
13954
|
+
const day = parts.find((part) => part.type === "day")?.value;
|
|
13955
|
+
return `${year}-${month}-${day}T${loop.trigger.at.time}[${loop.trigger.at.timezone}]`;
|
|
13956
|
+
}
|
|
13957
|
+
function loopJob(loop) {
|
|
13958
|
+
const cliArgs = Object.fromEntries(
|
|
13959
|
+
Object.entries(loop.input).map(([key, value]) => [key, typeof value === "string" ? value : JSON.stringify(value)])
|
|
13960
|
+
);
|
|
13961
|
+
return loop.target.kind === "workflow" ? { workflow: loop.target.id, cliArgs, flavor: "scheduled" } : { capability: loop.target.id, cliArgs, flavor: "scheduled" };
|
|
13962
|
+
}
|
|
13963
|
+
function repositoryTenant2(config) {
|
|
13964
|
+
const [envOwner, envRepo] = (process.env.GITHUB_REPOSITORY ?? "").split("/");
|
|
13965
|
+
const owner = config.github?.owner?.trim() || envOwner?.trim();
|
|
13966
|
+
const repo = config.github?.repo?.trim() || envRepo?.trim();
|
|
13967
|
+
return owner && repo ? `${owner}/${repo}` : null;
|
|
13968
|
+
}
|
|
13969
|
+
var dispatchSimpleLoops;
|
|
13970
|
+
var init_dispatchSimpleLoops = __esm({
|
|
13971
|
+
"src/scripts/dispatchSimpleLoops.ts"() {
|
|
13972
|
+
"use strict";
|
|
13973
|
+
init_loopDefinitions();
|
|
13974
|
+
init_job();
|
|
13975
|
+
init_state_backend();
|
|
13976
|
+
dispatchSimpleLoops = async (ctx) => {
|
|
13977
|
+
const tenantId2 = repositoryTenant2(ctx.config);
|
|
13978
|
+
if (!tenantId2) throw new Error("Repository identity is required for Loop dispatch");
|
|
13979
|
+
const now = /* @__PURE__ */ new Date();
|
|
13980
|
+
const due = listLoopDefinitions(ctx.cwd).filter((loop) => dueSlot(loop, now) !== null);
|
|
13981
|
+
const backend = createStateBackendFromEnv();
|
|
13982
|
+
const results = [];
|
|
13983
|
+
for (const loop of due) {
|
|
13984
|
+
const slot = dueSlot(loop, now);
|
|
13985
|
+
if (!slot) continue;
|
|
13986
|
+
const reservationId = `reservation-${randomUUID2()}`;
|
|
13987
|
+
const idempotencyKey = `${loop.id}:${slot}`;
|
|
13988
|
+
const claimed = await backend.reserveAgencyDispatch(tenantId2, {
|
|
13989
|
+
idempotencyKey,
|
|
13990
|
+
loopId: loop.id,
|
|
13991
|
+
decision: { kind: "fire", reason: "local Loop schedule is due", scheduledAt: slot },
|
|
13992
|
+
leaseUntil: new Date(now.getTime() + 6 * 60 * 60 * 1e3).toISOString(),
|
|
13993
|
+
reservationId,
|
|
13994
|
+
correlationId: `corr-${randomUUID2()}`,
|
|
13995
|
+
policyHash: `loop:${loop.id}`,
|
|
13996
|
+
effectivePolicy: { source: "repository" },
|
|
13997
|
+
definitionRefs: [{ kind: "loop", id: loop.id }],
|
|
13998
|
+
maxConcurrentRuns: 1,
|
|
13999
|
+
requiresApproval: false,
|
|
14000
|
+
approvalScopeKind: "loop",
|
|
14001
|
+
approvalScopeId: loop.id,
|
|
14002
|
+
approvalAction: `${loop.target.kind}:${loop.target.id}`,
|
|
14003
|
+
now: now.toISOString()
|
|
14004
|
+
});
|
|
14005
|
+
if (!claimed.acquired) {
|
|
14006
|
+
results.push({ loopId: loop.id, status: "skipped", reason: claimed.reason ?? "already claimed" });
|
|
14007
|
+
continue;
|
|
14008
|
+
}
|
|
14009
|
+
const result = await runJob(loopJob(loop), {
|
|
14010
|
+
cwd: ctx.cwd,
|
|
14011
|
+
config: ctx.config,
|
|
14012
|
+
verbose: ctx.verbose,
|
|
14013
|
+
quiet: ctx.quiet,
|
|
14014
|
+
chain: false
|
|
14015
|
+
});
|
|
14016
|
+
const status = result.exitCode === 0 ? "dispatched" : "failed";
|
|
14017
|
+
await backend.finishAgencyDispatch(tenantId2, idempotencyKey, reservationId, status, (/* @__PURE__ */ new Date()).toISOString());
|
|
14018
|
+
results.push({ loopId: loop.id, status, reason: result.reason ?? status });
|
|
14019
|
+
}
|
|
14020
|
+
ctx.data.simpleLoopDispatchResults = results;
|
|
14021
|
+
};
|
|
14022
|
+
}
|
|
14023
|
+
});
|
|
14024
|
+
|
|
13801
14025
|
// src/jobIdentity.ts
|
|
13802
14026
|
function stableJobKey(job) {
|
|
13803
14027
|
const capability = job.workflow ?? job.capability ?? job.action;
|
|
@@ -14818,15 +15042,15 @@ var init_fixFlow = __esm({
|
|
|
14818
15042
|
});
|
|
14819
15043
|
|
|
14820
15044
|
// src/workflow-template.ts
|
|
14821
|
-
import * as
|
|
14822
|
-
import * as
|
|
15045
|
+
import * as fs37 from "fs";
|
|
15046
|
+
import * as path35 from "path";
|
|
14823
15047
|
import { fileURLToPath } from "url";
|
|
14824
15048
|
function loadKodyWorkflowTemplate() {
|
|
14825
|
-
const here =
|
|
14826
|
-
const candidates = [
|
|
14827
|
-
const source = candidates.find((candidate) =>
|
|
15049
|
+
const here = path35.dirname(fileURLToPath(import.meta.url));
|
|
15050
|
+
const candidates = [path35.resolve(here, "../templates/kody.yml"), path35.resolve(here, "../../templates/kody.yml")];
|
|
15051
|
+
const source = candidates.find((candidate) => fs37.existsSync(candidate));
|
|
14828
15052
|
if (!source) throw new Error(`Kody workflow template is missing: ${KODY_WORKFLOW_TEMPLATE_PATH}`);
|
|
14829
|
-
return
|
|
15053
|
+
return fs37.readFileSync(source, "utf8");
|
|
14830
15054
|
}
|
|
14831
15055
|
var KODY_WORKFLOW_TEMPLATE_PATH;
|
|
14832
15056
|
var init_workflow_template = __esm({
|
|
@@ -14838,12 +15062,12 @@ var init_workflow_template = __esm({
|
|
|
14838
15062
|
|
|
14839
15063
|
// src/scripts/initFlow.ts
|
|
14840
15064
|
import { execFileSync as execFileSync14 } from "child_process";
|
|
14841
|
-
import * as
|
|
14842
|
-
import * as
|
|
15065
|
+
import * as fs38 from "fs";
|
|
15066
|
+
import * as path36 from "path";
|
|
14843
15067
|
function detectPackageManager(cwd) {
|
|
14844
|
-
if (
|
|
14845
|
-
if (
|
|
14846
|
-
if (
|
|
15068
|
+
if (fs38.existsSync(path36.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
15069
|
+
if (fs38.existsSync(path36.join(cwd, "yarn.lock"))) return "yarn";
|
|
15070
|
+
if (fs38.existsSync(path36.join(cwd, "bun.lockb"))) return "bun";
|
|
14847
15071
|
return "npm";
|
|
14848
15072
|
}
|
|
14849
15073
|
function qualityCommandsFor(pm) {
|
|
@@ -14915,22 +15139,22 @@ function performInit(cwd, force) {
|
|
|
14915
15139
|
const pm = detectPackageManager(cwd);
|
|
14916
15140
|
const ownerRepo = detectOwnerRepo(cwd);
|
|
14917
15141
|
const defaultBranch = defaultBranchFromGit(cwd);
|
|
14918
|
-
const configPath =
|
|
14919
|
-
if (
|
|
15142
|
+
const configPath = path36.join(cwd, "kody.config.json");
|
|
15143
|
+
if (fs38.existsSync(configPath) && !force) {
|
|
14920
15144
|
skipped.push("kody.config.json");
|
|
14921
15145
|
} else {
|
|
14922
15146
|
const cfg = makeConfig(pm, ownerRepo, defaultBranch);
|
|
14923
|
-
|
|
15147
|
+
fs38.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
14924
15148
|
`);
|
|
14925
15149
|
wrote.push("kody.config.json");
|
|
14926
15150
|
}
|
|
14927
|
-
const workflowDir =
|
|
14928
|
-
const workflowPath =
|
|
14929
|
-
if (
|
|
15151
|
+
const workflowDir = path36.join(cwd, ".github", "workflows");
|
|
15152
|
+
const workflowPath = path36.join(workflowDir, "kody.yml");
|
|
15153
|
+
if (fs38.existsSync(workflowPath) && !force) {
|
|
14930
15154
|
skipped.push(".github/workflows/kody.yml");
|
|
14931
15155
|
} else {
|
|
14932
|
-
|
|
14933
|
-
|
|
15156
|
+
fs38.mkdirSync(workflowDir, { recursive: true });
|
|
15157
|
+
fs38.writeFileSync(workflowPath, loadKodyWorkflowTemplate());
|
|
14934
15158
|
wrote.push(".github/workflows/kody.yml");
|
|
14935
15159
|
}
|
|
14936
15160
|
for (const exe of listRuntimeProfilesForCwd(cwd)) {
|
|
@@ -14941,12 +15165,12 @@ function performInit(cwd, force) {
|
|
|
14941
15165
|
continue;
|
|
14942
15166
|
}
|
|
14943
15167
|
if (profile.kind !== "scheduled" || !profile.schedule) continue;
|
|
14944
|
-
const target =
|
|
14945
|
-
if (
|
|
15168
|
+
const target = path36.join(workflowDir, `kody-${exe.name}.yml`);
|
|
15169
|
+
if (fs38.existsSync(target) && !force) {
|
|
14946
15170
|
skipped.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
14947
15171
|
continue;
|
|
14948
15172
|
}
|
|
14949
|
-
|
|
15173
|
+
fs38.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
|
|
14950
15174
|
wrote.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
14951
15175
|
}
|
|
14952
15176
|
let labels;
|
|
@@ -15034,7 +15258,7 @@ Nothing to do. All files already present. (Use --force to overwrite.)
|
|
|
15034
15258
|
});
|
|
15035
15259
|
|
|
15036
15260
|
// src/scripts/loadAgentAdhoc.ts
|
|
15037
|
-
import * as
|
|
15261
|
+
import * as fs39 from "fs";
|
|
15038
15262
|
function resolveMessage(messageArg) {
|
|
15039
15263
|
const fromComment = readCommentBody();
|
|
15040
15264
|
if (fromComment) return stripDirective(fromComment);
|
|
@@ -15042,9 +15266,9 @@ function resolveMessage(messageArg) {
|
|
|
15042
15266
|
}
|
|
15043
15267
|
function readCommentBody() {
|
|
15044
15268
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
15045
|
-
if (!eventPath || !
|
|
15269
|
+
if (!eventPath || !fs39.existsSync(eventPath)) return "";
|
|
15046
15270
|
try {
|
|
15047
|
-
const event = JSON.parse(
|
|
15271
|
+
const event = JSON.parse(fs39.readFileSync(eventPath, "utf-8"));
|
|
15048
15272
|
return String(event.comment?.body ?? "");
|
|
15049
15273
|
} catch {
|
|
15050
15274
|
return "";
|
|
@@ -15098,10 +15322,10 @@ var init_loadAgentAdhoc = __esm({
|
|
|
15098
15322
|
throw new Error("loadAgentAdhoc: ctx.args.agent must be a non-empty slug");
|
|
15099
15323
|
}
|
|
15100
15324
|
const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
|
|
15101
|
-
if (!
|
|
15325
|
+
if (!fs39.existsSync(agentPath)) {
|
|
15102
15326
|
throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
|
|
15103
15327
|
}
|
|
15104
|
-
const { title, body } = parseAgentFile(
|
|
15328
|
+
const { title, body } = parseAgentFile(fs39.readFileSync(agentPath, "utf-8"), agentSlug);
|
|
15105
15329
|
const message = resolveMessage(ctx.args.message);
|
|
15106
15330
|
if (!message) {
|
|
15107
15331
|
throw new Error(
|
|
@@ -15170,8 +15394,8 @@ var init_loadCapabilityState = __esm({
|
|
|
15170
15394
|
});
|
|
15171
15395
|
|
|
15172
15396
|
// src/scripts/loadSimpleCapability.ts
|
|
15173
|
-
import * as
|
|
15174
|
-
import * as
|
|
15397
|
+
import * as fs40 from "fs";
|
|
15398
|
+
import * as path37 from "path";
|
|
15175
15399
|
function parseInput(supplied) {
|
|
15176
15400
|
if (typeof supplied !== "string") return supplied;
|
|
15177
15401
|
try {
|
|
@@ -15218,14 +15442,14 @@ function capabilityEnvironment(input) {
|
|
|
15218
15442
|
return environment;
|
|
15219
15443
|
}
|
|
15220
15444
|
function listFiles(root) {
|
|
15221
|
-
if (!
|
|
15445
|
+
if (!fs40.existsSync(root)) return [];
|
|
15222
15446
|
const files = [];
|
|
15223
15447
|
const visit = (dir) => {
|
|
15224
|
-
for (const entry of
|
|
15225
|
-
const absolute =
|
|
15448
|
+
for (const entry of fs40.readdirSync(dir, { withFileTypes: true })) {
|
|
15449
|
+
const absolute = path37.join(dir, entry.name);
|
|
15226
15450
|
if (entry.isSymbolicLink()) continue;
|
|
15227
15451
|
if (entry.isDirectory()) visit(absolute);
|
|
15228
|
-
else if (entry.isFile()) files.push(
|
|
15452
|
+
else if (entry.isFile()) files.push(path37.relative(root, absolute));
|
|
15229
15453
|
}
|
|
15230
15454
|
};
|
|
15231
15455
|
visit(root);
|
|
@@ -15246,8 +15470,8 @@ var init_loadSimpleCapability = __esm({
|
|
|
15246
15470
|
if (!capability) {
|
|
15247
15471
|
throw new Error(`Capability "${slug}" is not a valid simple capability folder`);
|
|
15248
15472
|
}
|
|
15249
|
-
const toolRoot =
|
|
15250
|
-
const skillRoot =
|
|
15473
|
+
const toolRoot = path37.join(capability.dir, "tools");
|
|
15474
|
+
const skillRoot = path37.join(capability.dir, "skills");
|
|
15251
15475
|
const toolFiles = listFiles(toolRoot);
|
|
15252
15476
|
const skillFiles = listFiles(skillRoot);
|
|
15253
15477
|
const input = parseInput(ctx.args.input);
|
|
@@ -15271,7 +15495,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
15271
15495
|
...skillFiles.flatMap((file) => [
|
|
15272
15496
|
`### ${file}`,
|
|
15273
15497
|
"",
|
|
15274
|
-
|
|
15498
|
+
fs40.readFileSync(path37.join(skillRoot, file), "utf-8"),
|
|
15275
15499
|
""
|
|
15276
15500
|
])
|
|
15277
15501
|
] : [],
|
|
@@ -15280,7 +15504,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
15280
15504
|
"## Tools",
|
|
15281
15505
|
"",
|
|
15282
15506
|
"Inspect or run these capability-owned files when needed:",
|
|
15283
|
-
...toolFiles.map((file) => `- ${
|
|
15507
|
+
...toolFiles.map((file) => `- ${path37.join(toolRoot, file)}`)
|
|
15284
15508
|
] : []
|
|
15285
15509
|
].join("\n");
|
|
15286
15510
|
};
|
|
@@ -15588,8 +15812,8 @@ var init_loadIssueStateComment = __esm({
|
|
|
15588
15812
|
});
|
|
15589
15813
|
|
|
15590
15814
|
// src/scripts/loadJobFromFile.ts
|
|
15591
|
-
import * as
|
|
15592
|
-
import * as
|
|
15815
|
+
import * as fs41 from "fs";
|
|
15816
|
+
import * as path38 from "path";
|
|
15593
15817
|
function parseJobFile(raw, slug) {
|
|
15594
15818
|
let stripped = raw;
|
|
15595
15819
|
if (stripped.startsWith("---\n")) {
|
|
@@ -15628,10 +15852,10 @@ var init_loadJobFromFile = __esm({
|
|
|
15628
15852
|
if (!slug) {
|
|
15629
15853
|
throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
|
|
15630
15854
|
}
|
|
15631
|
-
const capability = resolveCapabilityFolder(slug,
|
|
15855
|
+
const capability = resolveCapabilityFolder(slug, path38.resolve(ctx.cwd, jobsDir));
|
|
15632
15856
|
if (!capability) {
|
|
15633
15857
|
throw new Error(
|
|
15634
|
-
`loadJobFromFile: capability folder not found or incomplete: ${
|
|
15858
|
+
`loadJobFromFile: capability folder not found or incomplete: ${path38.resolve(ctx.cwd, jobsDir, slug)}`
|
|
15635
15859
|
);
|
|
15636
15860
|
}
|
|
15637
15861
|
const { title, body, config } = capability;
|
|
@@ -15641,12 +15865,12 @@ var init_loadJobFromFile = __esm({
|
|
|
15641
15865
|
let agentIdentity = "";
|
|
15642
15866
|
if (agentSlug) {
|
|
15643
15867
|
const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
|
|
15644
|
-
if (!
|
|
15868
|
+
if (!fs41.existsSync(agentPath)) {
|
|
15645
15869
|
throw new Error(
|
|
15646
15870
|
`loadJobFromFile: capability '${slug}' declares agent '${agentSlug}' but ${agentPath} does not exist`
|
|
15647
15871
|
);
|
|
15648
15872
|
}
|
|
15649
|
-
const agentRaw =
|
|
15873
|
+
const agentRaw = fs41.readFileSync(agentPath, "utf-8");
|
|
15650
15874
|
const parsed = parseJobFile(agentRaw, agentSlug);
|
|
15651
15875
|
agentTitle = parsed.title;
|
|
15652
15876
|
agentIdentity = parsed.body;
|
|
@@ -15726,13 +15950,13 @@ ${truncate2(issue2.body, FINDING_BODY_MAX_BYTES)}`;
|
|
|
15726
15950
|
});
|
|
15727
15951
|
|
|
15728
15952
|
// src/scripts/kodyVariables.ts
|
|
15729
|
-
import * as
|
|
15730
|
-
import * as
|
|
15953
|
+
import * as fs42 from "fs";
|
|
15954
|
+
import * as path39 from "path";
|
|
15731
15955
|
function readKodyVariables(cwd) {
|
|
15732
|
-
const full =
|
|
15956
|
+
const full = path39.join(cwd, KODY_VARIABLES_REL_PATH);
|
|
15733
15957
|
let raw;
|
|
15734
15958
|
try {
|
|
15735
|
-
raw =
|
|
15959
|
+
raw = fs42.readFileSync(full, "utf-8");
|
|
15736
15960
|
} catch {
|
|
15737
15961
|
return {};
|
|
15738
15962
|
}
|
|
@@ -15908,8 +16132,8 @@ var init_runtimeSecrets = __esm({
|
|
|
15908
16132
|
});
|
|
15909
16133
|
|
|
15910
16134
|
// src/scripts/loadQaContext.ts
|
|
15911
|
-
import * as
|
|
15912
|
-
import * as
|
|
16135
|
+
import * as fs43 from "fs";
|
|
16136
|
+
import * as path40 from "path";
|
|
15913
16137
|
function parseSlugList(value) {
|
|
15914
16138
|
const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
15915
16139
|
return inner.split(",").map(
|
|
@@ -15938,18 +16162,18 @@ function readProfileAgents(raw) {
|
|
|
15938
16162
|
return { agent: agent ?? legacy ?? ["kody"], body };
|
|
15939
16163
|
}
|
|
15940
16164
|
function readProfile(cwd) {
|
|
15941
|
-
const dir =
|
|
15942
|
-
if (!
|
|
16165
|
+
const dir = path40.join(cwd, CONTEXT_DIR_REL_PATH);
|
|
16166
|
+
if (!fs43.existsSync(dir)) return "";
|
|
15943
16167
|
let entries;
|
|
15944
16168
|
try {
|
|
15945
|
-
entries =
|
|
16169
|
+
entries = fs43.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
15946
16170
|
} catch {
|
|
15947
16171
|
return "";
|
|
15948
16172
|
}
|
|
15949
16173
|
const blocks = [];
|
|
15950
16174
|
for (const file of entries) {
|
|
15951
16175
|
try {
|
|
15952
|
-
const raw =
|
|
16176
|
+
const raw = fs43.readFileSync(path40.join(dir, file), "utf-8");
|
|
15953
16177
|
const { agent, body } = readProfileAgents(raw);
|
|
15954
16178
|
if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
|
|
15955
16179
|
blocks.push(`## ${file}
|
|
@@ -15998,8 +16222,8 @@ var init_loadQaContext = __esm({
|
|
|
15998
16222
|
});
|
|
15999
16223
|
|
|
16000
16224
|
// src/taskContext.ts
|
|
16001
|
-
import * as
|
|
16002
|
-
import * as
|
|
16225
|
+
import * as fs44 from "fs";
|
|
16226
|
+
import * as path41 from "path";
|
|
16003
16227
|
function buildTaskContext(args) {
|
|
16004
16228
|
return {
|
|
16005
16229
|
schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
|
|
@@ -16015,9 +16239,9 @@ function buildTaskContext(args) {
|
|
|
16015
16239
|
function persistTaskContext(cwd, ctx) {
|
|
16016
16240
|
try {
|
|
16017
16241
|
const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
|
|
16018
|
-
|
|
16019
|
-
const file =
|
|
16020
|
-
|
|
16242
|
+
fs44.mkdirSync(dir, { recursive: true });
|
|
16243
|
+
const file = path41.join(dir, "task-context.json");
|
|
16244
|
+
fs44.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
|
|
16021
16245
|
`);
|
|
16022
16246
|
return file;
|
|
16023
16247
|
} catch (err) {
|
|
@@ -16857,7 +17081,7 @@ function parseSingleJsonCandidate(candidates) {
|
|
|
16857
17081
|
}
|
|
16858
17082
|
return parsed.length === 1 ? { found: true, value: parsed[0] } : { found: false };
|
|
16859
17083
|
}
|
|
16860
|
-
function
|
|
17084
|
+
function isObject2(value) {
|
|
16861
17085
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
16862
17086
|
}
|
|
16863
17087
|
function stringValue4(value) {
|
|
@@ -16875,8 +17099,8 @@ var init_parseSimpleCapabilityOutput = __esm({
|
|
|
16875
17099
|
return;
|
|
16876
17100
|
}
|
|
16877
17101
|
ctx.data.capabilityOutput = output;
|
|
16878
|
-
const result =
|
|
16879
|
-
const data =
|
|
17102
|
+
const result = isObject2(output) ? output : {};
|
|
17103
|
+
const data = isObject2(result.data) ? result.data : isObject2(output) ? output : { output };
|
|
16880
17104
|
const summary = typeof result.summary === "string" ? result.summary : "Capability completed";
|
|
16881
17105
|
const reason = typeof result.reason === "string" ? result.reason : summary;
|
|
16882
17106
|
const prUrl = stringValue4(data.pullRequestUrl) ?? stringValue4(data.prUrl) ?? stringValue4(result.pullRequestUrl) ?? stringValue4(result.prUrl);
|
|
@@ -17467,9 +17691,9 @@ var init_postResearchComment = __esm({
|
|
|
17467
17691
|
});
|
|
17468
17692
|
|
|
17469
17693
|
// src/scripts/prepareBrowserAuth.ts
|
|
17470
|
-
import * as
|
|
17694
|
+
import * as fs45 from "fs";
|
|
17471
17695
|
import * as os6 from "os";
|
|
17472
|
-
import * as
|
|
17696
|
+
import * as path42 from "path";
|
|
17473
17697
|
function appendAuthMessage(ctx, message) {
|
|
17474
17698
|
const current = typeof ctx.data.qaAuthBlock === "string" ? ctx.data.qaAuthBlock.trim() : "";
|
|
17475
17699
|
ctx.data.qaAuthBlock = current ? `${current}
|
|
@@ -17508,9 +17732,9 @@ async function githubJson(url, token) {
|
|
|
17508
17732
|
return await response.json();
|
|
17509
17733
|
}
|
|
17510
17734
|
function writeKodyStorageState(input) {
|
|
17511
|
-
const directory =
|
|
17512
|
-
|
|
17513
|
-
const file =
|
|
17735
|
+
const directory = fs45.mkdtempSync(path42.join(os6.tmpdir(), "kody-browser-auth-"));
|
|
17736
|
+
fs45.chmodSync(directory, 448);
|
|
17737
|
+
const file = path42.join(directory, "storage-state.json");
|
|
17514
17738
|
const now = Date.now();
|
|
17515
17739
|
const repoEntry = {
|
|
17516
17740
|
repoUrl: input.repoUrl,
|
|
@@ -17540,7 +17764,7 @@ function writeKodyStorageState(input) {
|
|
|
17540
17764
|
}
|
|
17541
17765
|
]
|
|
17542
17766
|
};
|
|
17543
|
-
|
|
17767
|
+
fs45.writeFileSync(file, JSON.stringify(storageState), { mode: 384 });
|
|
17544
17768
|
return { directory, file };
|
|
17545
17769
|
}
|
|
17546
17770
|
function configurePlaywright(profile, storageStatePath) {
|
|
@@ -17622,7 +17846,7 @@ async function prepareMethod(ctx, profile, method) {
|
|
|
17622
17846
|
configurePlaywright(profile, state.file);
|
|
17623
17847
|
const authDirectory = state.directory;
|
|
17624
17848
|
registerRuntimeCleanup(ctx, () => {
|
|
17625
|
-
|
|
17849
|
+
fs45.rmSync(authDirectory, { recursive: true, force: true });
|
|
17626
17850
|
});
|
|
17627
17851
|
appendAuthMessage(
|
|
17628
17852
|
ctx,
|
|
@@ -17630,7 +17854,7 @@ async function prepareMethod(ctx, profile, method) {
|
|
|
17630
17854
|
);
|
|
17631
17855
|
return true;
|
|
17632
17856
|
} catch (error) {
|
|
17633
|
-
if (state)
|
|
17857
|
+
if (state) fs45.rmSync(state.directory, { recursive: true, force: true });
|
|
17634
17858
|
const reason = error instanceof Error ? error.message : String(error);
|
|
17635
17859
|
appendAuthMessage(
|
|
17636
17860
|
ctx,
|
|
@@ -18729,12 +18953,12 @@ fi
|
|
|
18729
18953
|
|
|
18730
18954
|
// src/scripts/runPreviewBuild.ts
|
|
18731
18955
|
import { copyFile, writeFile } from "fs/promises";
|
|
18732
|
-
import * as
|
|
18956
|
+
import * as path43 from "path";
|
|
18733
18957
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
18734
18958
|
function bundledDockerfilePath(mode) {
|
|
18735
|
-
const here =
|
|
18959
|
+
const here = path43.dirname(fileURLToPath2(import.meta.url));
|
|
18736
18960
|
const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
|
|
18737
|
-
return
|
|
18961
|
+
return path43.join(here, "preview-build-templates", file);
|
|
18738
18962
|
}
|
|
18739
18963
|
function required(name) {
|
|
18740
18964
|
const v = (process.env[name] ?? "").trim();
|
|
@@ -18969,10 +19193,10 @@ var init_runPreviewBuild = __esm({
|
|
|
18969
19193
|
console.log(`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`);
|
|
18970
19194
|
if (Object.keys(buildEnv).length > 0) {
|
|
18971
19195
|
const lines = Object.entries(buildEnv).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
|
|
18972
|
-
await writeFile(
|
|
19196
|
+
await writeFile(path43.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
|
|
18973
19197
|
`, "utf8");
|
|
18974
19198
|
}
|
|
18975
|
-
const consumerDockerfile =
|
|
19199
|
+
const consumerDockerfile = path43.join(ctx.cwd, "Dockerfile.preview");
|
|
18976
19200
|
const { stat } = await import("fs/promises");
|
|
18977
19201
|
let hasConsumerDockerfile = false;
|
|
18978
19202
|
try {
|
|
@@ -19156,8 +19380,8 @@ var init_tickShellRunner = __esm({
|
|
|
19156
19380
|
});
|
|
19157
19381
|
|
|
19158
19382
|
// src/scripts/runScheduledImplementationTick.ts
|
|
19159
|
-
import * as
|
|
19160
|
-
import * as
|
|
19383
|
+
import * as fs46 from "fs";
|
|
19384
|
+
import * as path44 from "path";
|
|
19161
19385
|
var runScheduledImplementationTick;
|
|
19162
19386
|
var init_runScheduledImplementationTick = __esm({
|
|
19163
19387
|
"src/scripts/runScheduledImplementationTick.ts"() {
|
|
@@ -19178,14 +19402,14 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
19178
19402
|
ctx.output.reason = `runScheduledImplementationTick: args.slug or ctx.args.${slugArg} must be non-empty capability slug`;
|
|
19179
19403
|
return;
|
|
19180
19404
|
}
|
|
19181
|
-
const capability = resolveCapabilityFolder(slug,
|
|
19405
|
+
const capability = resolveCapabilityFolder(slug, path44.resolve(ctx.cwd, jobsDir));
|
|
19182
19406
|
if (!capability) {
|
|
19183
19407
|
ctx.output.exitCode = 99;
|
|
19184
19408
|
ctx.output.reason = `runScheduledImplementationTick: capability folder not found or incomplete: ${slug} (searched ${jobsDir} and company store)`;
|
|
19185
19409
|
return;
|
|
19186
19410
|
}
|
|
19187
|
-
const shellPath =
|
|
19188
|
-
if (!
|
|
19411
|
+
const shellPath = path44.join(profile.dir, shell);
|
|
19412
|
+
if (!fs46.existsSync(shellPath)) {
|
|
19189
19413
|
ctx.output.exitCode = 99;
|
|
19190
19414
|
ctx.output.reason = `runScheduledImplementationTick: shell not found: ${shell} (looked in ${profile.dir})`;
|
|
19191
19415
|
return;
|
|
@@ -19216,8 +19440,8 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
19216
19440
|
});
|
|
19217
19441
|
|
|
19218
19442
|
// src/scripts/runTickScript.ts
|
|
19219
|
-
import * as
|
|
19220
|
-
import * as
|
|
19443
|
+
import * as fs47 from "fs";
|
|
19444
|
+
import * as path45 from "path";
|
|
19221
19445
|
var runTickScript;
|
|
19222
19446
|
var init_runTickScript = __esm({
|
|
19223
19447
|
"src/scripts/runTickScript.ts"() {
|
|
@@ -19237,10 +19461,10 @@ var init_runTickScript = __esm({
|
|
|
19237
19461
|
ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
|
|
19238
19462
|
return;
|
|
19239
19463
|
}
|
|
19240
|
-
const capability = readCapabilityFolder(
|
|
19464
|
+
const capability = readCapabilityFolder(path45.resolve(ctx.cwd, jobsDir), slug);
|
|
19241
19465
|
if (!capability) {
|
|
19242
19466
|
ctx.output.exitCode = 99;
|
|
19243
|
-
ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${
|
|
19467
|
+
ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${path45.resolve(ctx.cwd, jobsDir, slug)}`;
|
|
19244
19468
|
return;
|
|
19245
19469
|
}
|
|
19246
19470
|
const tickScript = capability.config.tickScript;
|
|
@@ -19249,8 +19473,8 @@ var init_runTickScript = __esm({
|
|
|
19249
19473
|
ctx.output.reason = `runTickScript: capability ${slug} has no \`tickScript\` in profile.json \u2014 route via capability-tick instead`;
|
|
19250
19474
|
return;
|
|
19251
19475
|
}
|
|
19252
|
-
const scriptPath =
|
|
19253
|
-
if (!
|
|
19476
|
+
const scriptPath = path45.isAbsolute(tickScript) ? tickScript : path45.join(ctx.cwd, tickScript);
|
|
19477
|
+
if (!fs47.existsSync(scriptPath)) {
|
|
19254
19478
|
ctx.output.exitCode = 99;
|
|
19255
19479
|
ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
|
|
19256
19480
|
return;
|
|
@@ -19532,7 +19756,7 @@ var init_syncFlow = __esm({
|
|
|
19532
19756
|
});
|
|
19533
19757
|
|
|
19534
19758
|
// src/scripts/validateAgencyModelProposal.ts
|
|
19535
|
-
import * as
|
|
19759
|
+
import * as path46 from "path";
|
|
19536
19760
|
function validateModelBundle(bundle, expectedKind, options = {}) {
|
|
19537
19761
|
const failures = [];
|
|
19538
19762
|
validateOneModel(bundle.model, bundle.files, "model", true, failures, expectedKind, options);
|
|
@@ -19850,7 +20074,7 @@ var init_validateAgencyModelProposal = __esm({
|
|
|
19850
20074
|
const bundle = parseAgencyModelProposal(raw);
|
|
19851
20075
|
const expectedKind = readExpectedModelKind(args);
|
|
19852
20076
|
const failures = validateModelBundle(bundle, expectedKind, {
|
|
19853
|
-
capabilityRoot:
|
|
20077
|
+
capabilityRoot: path46.join(ctx.cwd, ".kody", "capabilities")
|
|
19854
20078
|
});
|
|
19855
20079
|
if (failures.length > 0) {
|
|
19856
20080
|
throw new Error(`validateAgencyModelProposal: ${failures.join("; ")}`);
|
|
@@ -20401,7 +20625,7 @@ var init_warmupMcp = __esm({
|
|
|
20401
20625
|
});
|
|
20402
20626
|
|
|
20403
20627
|
// src/scripts/writeAgentRunSummary.ts
|
|
20404
|
-
import * as
|
|
20628
|
+
import * as fs48 from "fs";
|
|
20405
20629
|
var writeAgentRunSummary;
|
|
20406
20630
|
var init_writeAgentRunSummary = __esm({
|
|
20407
20631
|
"src/scripts/writeAgentRunSummary.ts"() {
|
|
@@ -20427,7 +20651,7 @@ var init_writeAgentRunSummary = __esm({
|
|
|
20427
20651
|
if (reason) lines.push(`- **Reason:** ${reason}`);
|
|
20428
20652
|
lines.push("");
|
|
20429
20653
|
try {
|
|
20430
|
-
|
|
20654
|
+
fs48.appendFileSync(summaryPath, `${lines.join("\n")}
|
|
20431
20655
|
`);
|
|
20432
20656
|
} catch {
|
|
20433
20657
|
}
|
|
@@ -20564,6 +20788,7 @@ var init_scripts = __esm({
|
|
|
20564
20788
|
init_dispatchCapabilityTicks();
|
|
20565
20789
|
init_dispatchClassified();
|
|
20566
20790
|
init_dispatchAgencyLoops();
|
|
20791
|
+
init_dispatchSimpleLoops();
|
|
20567
20792
|
init_dispatchNextTaskJob();
|
|
20568
20793
|
init_ensurePr();
|
|
20569
20794
|
init_evaluateAgencyBoundaries();
|
|
@@ -20688,6 +20913,7 @@ var init_scripts = __esm({
|
|
|
20688
20913
|
warmupMcp,
|
|
20689
20914
|
dispatchCapabilityTicks,
|
|
20690
20915
|
dispatchAgencyLoops,
|
|
20916
|
+
dispatchSimpleLoops,
|
|
20691
20917
|
dispatchCapabilityFileTicks,
|
|
20692
20918
|
planTaskJobs,
|
|
20693
20919
|
dispatchNextTaskJob,
|
|
@@ -20759,17 +20985,17 @@ var init_scripts = __esm({
|
|
|
20759
20985
|
});
|
|
20760
20986
|
|
|
20761
20987
|
// src/stateWorkspace.ts
|
|
20762
|
-
import * as
|
|
20763
|
-
import * as
|
|
20988
|
+
import * as fs49 from "fs";
|
|
20989
|
+
import * as path47 from "path";
|
|
20764
20990
|
function tenantId(config) {
|
|
20765
20991
|
const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
|
|
20766
20992
|
const repo = config.github?.repo?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[1]?.trim();
|
|
20767
20993
|
return owner && repo ? `${owner}/${repo}` : null;
|
|
20768
20994
|
}
|
|
20769
20995
|
function writeRuntimeFile(cwd, relativePath, content) {
|
|
20770
|
-
const target =
|
|
20771
|
-
|
|
20772
|
-
|
|
20996
|
+
const target = path47.join(cwd, RUNTIME_ROOT, relativePath);
|
|
20997
|
+
fs49.mkdirSync(path47.dirname(target), { recursive: true });
|
|
20998
|
+
fs49.writeFileSync(target, content, "utf8");
|
|
20773
20999
|
}
|
|
20774
21000
|
function record(value) {
|
|
20775
21001
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -20834,11 +21060,11 @@ async function hydrateStateWorkspace(config, cwd, backendOverride) {
|
|
|
20834
21060
|
throw new Error("Kody backend access is required for runtime workspace documents");
|
|
20835
21061
|
return;
|
|
20836
21062
|
}
|
|
20837
|
-
const key = `${
|
|
21063
|
+
const key = `${path47.resolve(cwd)}|${tenant}`;
|
|
20838
21064
|
if (hydratedWorkspaces.has(key)) return;
|
|
20839
21065
|
const backend = backendOverride ?? createStateBackendFromEnv();
|
|
20840
|
-
const root =
|
|
20841
|
-
|
|
21066
|
+
const root = path47.join(cwd, RUNTIME_ROOT);
|
|
21067
|
+
fs49.rmSync(root, { recursive: true, force: true });
|
|
20842
21068
|
await Promise.all([
|
|
20843
21069
|
hydratePrefix(backend, tenant, cwd, "context:"),
|
|
20844
21070
|
hydratePrefix(backend, tenant, cwd, "memory:"),
|
|
@@ -20854,7 +21080,7 @@ var init_stateWorkspace = __esm({
|
|
|
20854
21080
|
"src/stateWorkspace.ts"() {
|
|
20855
21081
|
"use strict";
|
|
20856
21082
|
init_state_backend();
|
|
20857
|
-
RUNTIME_ROOT =
|
|
21083
|
+
RUNTIME_ROOT = path47.join(".kody-engine", "runtime");
|
|
20858
21084
|
hydratedWorkspaces = /* @__PURE__ */ new Set();
|
|
20859
21085
|
}
|
|
20860
21086
|
});
|
|
@@ -20925,9 +21151,9 @@ var init_tools = __esm({
|
|
|
20925
21151
|
|
|
20926
21152
|
// src/executor.ts
|
|
20927
21153
|
import { spawn as spawn8 } from "child_process";
|
|
20928
|
-
import * as
|
|
21154
|
+
import * as fs50 from "fs";
|
|
20929
21155
|
import * as os7 from "os";
|
|
20930
|
-
import * as
|
|
21156
|
+
import * as path48 from "path";
|
|
20931
21157
|
function isMutatingPostflight(scriptName) {
|
|
20932
21158
|
return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
|
|
20933
21159
|
}
|
|
@@ -21168,7 +21394,7 @@ async function runImplementation(profileName, input) {
|
|
|
21168
21394
|
const jobWhyBlock = typeof ctx.data.jobWhy === "string" ? operatorRequestBlock(ctx.data.jobWhy) : null;
|
|
21169
21395
|
const jobRefBlock = jobReferenceBlock(profileName, profile, ctx.data);
|
|
21170
21396
|
const invokeAgent = async (prompt) => {
|
|
21171
|
-
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) =>
|
|
21397
|
+
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path48.isAbsolute(p) ? p : path48.resolve(profile.dir, p)).filter((p) => p.length > 0);
|
|
21172
21398
|
const syntheticPath = ctx.data.syntheticPluginPath;
|
|
21173
21399
|
const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
|
|
21174
21400
|
const agents = loadSubagents(profile);
|
|
@@ -21632,17 +21858,17 @@ function clearStampedLifecycleLabels(profile, ctx) {
|
|
|
21632
21858
|
function resolveProfilePath(profileName, cwd = process.cwd()) {
|
|
21633
21859
|
const found = resolveImplementation(profileName, getRuntimeProfileRootsForCwd(cwd));
|
|
21634
21860
|
if (found) return found;
|
|
21635
|
-
const here =
|
|
21861
|
+
const here = path48.dirname(new URL(import.meta.url).pathname);
|
|
21636
21862
|
const candidates = [
|
|
21637
|
-
|
|
21863
|
+
path48.join(here, "implementations", profileName, "profile.json"),
|
|
21638
21864
|
// same-dir sibling (dev)
|
|
21639
|
-
|
|
21865
|
+
path48.join(here, "..", "implementations", profileName, "profile.json"),
|
|
21640
21866
|
// up one (prod: dist/bin → dist/implementations)
|
|
21641
|
-
|
|
21867
|
+
path48.join(here, "..", "src", "implementations", profileName, "profile.json")
|
|
21642
21868
|
// fallback
|
|
21643
21869
|
];
|
|
21644
21870
|
for (const c of candidates) {
|
|
21645
|
-
if (
|
|
21871
|
+
if (fs50.existsSync(c)) return c;
|
|
21646
21872
|
}
|
|
21647
21873
|
return candidates[0];
|
|
21648
21874
|
}
|
|
@@ -21757,15 +21983,15 @@ function resolveShellTimeoutMs(entry) {
|
|
|
21757
21983
|
}
|
|
21758
21984
|
async function runShellEntry(entry, ctx, profile) {
|
|
21759
21985
|
const shellName = entry.shell;
|
|
21760
|
-
const shellPath =
|
|
21761
|
-
if (!
|
|
21986
|
+
const shellPath = path48.join(profile.dir, shellName);
|
|
21987
|
+
if (!fs50.existsSync(shellPath)) {
|
|
21762
21988
|
ctx.skipAgent = true;
|
|
21763
21989
|
ctx.output.exitCode = 99;
|
|
21764
21990
|
ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
|
|
21765
21991
|
return;
|
|
21766
21992
|
}
|
|
21767
21993
|
const positional = entry.with ? Object.values(entry.with).map((v) => String(v)) : [];
|
|
21768
|
-
const outputFile =
|
|
21994
|
+
const outputFile = path48.join(
|
|
21769
21995
|
os7.tmpdir(),
|
|
21770
21996
|
`kody-shell-output-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
|
21771
21997
|
);
|
|
@@ -21837,9 +22063,9 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
21837
22063
|
}
|
|
21838
22064
|
let sideChannelText = "";
|
|
21839
22065
|
try {
|
|
21840
|
-
if (
|
|
21841
|
-
sideChannelText =
|
|
21842
|
-
|
|
22066
|
+
if (fs50.existsSync(outputFile)) {
|
|
22067
|
+
sideChannelText = fs50.readFileSync(outputFile, "utf-8");
|
|
22068
|
+
fs50.rmSync(outputFile, { force: true });
|
|
21843
22069
|
}
|
|
21844
22070
|
} catch {
|
|
21845
22071
|
}
|
|
@@ -22011,7 +22237,7 @@ __export(job_exports, {
|
|
|
22011
22237
|
stableJobKey: () => stableJobKey,
|
|
22012
22238
|
validateJob: () => validateJob
|
|
22013
22239
|
});
|
|
22014
|
-
import * as
|
|
22240
|
+
import * as path49 from "path";
|
|
22015
22241
|
function newJobId(flavor) {
|
|
22016
22242
|
localJobSeq += 1;
|
|
22017
22243
|
const runId = process.env.GITHUB_RUN_ID;
|
|
@@ -22487,6 +22713,13 @@ async function runGraphCapabilityWorkflow(parent, workflow, capability, base, ch
|
|
|
22487
22713
|
const key = `${step.id}->${transition.to}`;
|
|
22488
22714
|
state.transitionCounts[key] = (state.transitionCounts[key] ?? 0) + 1;
|
|
22489
22715
|
}
|
|
22716
|
+
if (transition.to === "$end") {
|
|
22717
|
+
state.status = "done";
|
|
22718
|
+
delete state.currentStepId;
|
|
22719
|
+
delete state.blocker;
|
|
22720
|
+
await checkpoint?.(state);
|
|
22721
|
+
return withWorkflowBoundaryEval(capability, { ...result, workflowState: state });
|
|
22722
|
+
}
|
|
22490
22723
|
state.currentStepId = transition.to;
|
|
22491
22724
|
state.status = "running";
|
|
22492
22725
|
delete state.blocker;
|
|
@@ -22662,7 +22895,7 @@ function valueMatches(actual, expected) {
|
|
|
22662
22895
|
}
|
|
22663
22896
|
function workflowStepTargetNumber(step, parent, chainData) {
|
|
22664
22897
|
if (step.target === "pr") return workflowPrNumber(chainData) ?? workflowTargetFactNumber(step, chainData);
|
|
22665
|
-
if (step.target === "issue") return workflowIssueNumber(parent);
|
|
22898
|
+
if (step.target === "issue") return workflowIssueNumber(parent) ?? workflowTargetFactNumber(step, chainData);
|
|
22666
22899
|
return typeof parent.target === "number" ? parent.target : targetFromCliArgs(parent.cliArgs);
|
|
22667
22900
|
}
|
|
22668
22901
|
function workflowResumeStartIndex(steps, evidence) {
|
|
@@ -22712,7 +22945,7 @@ function loadCapabilityContext(slug, cwd) {
|
|
|
22712
22945
|
return resolveCapabilityFolder(slug, hydratedCapabilitiesRoot(cwd));
|
|
22713
22946
|
}
|
|
22714
22947
|
function hydratedCapabilitiesRoot(cwd) {
|
|
22715
|
-
return
|
|
22948
|
+
return path49.join(cwd, ".kody-engine", "definitions", "capabilities");
|
|
22716
22949
|
}
|
|
22717
22950
|
function loadWorkflowContext(slug, base) {
|
|
22718
22951
|
if (!slug || !isWorkflowDefinitionId(slug)) return null;
|
|
@@ -24688,82 +24921,7 @@ function readRunRequestFromEnv(env = process.env) {
|
|
|
24688
24921
|
|
|
24689
24922
|
// src/kody-cli.ts
|
|
24690
24923
|
init_runtimePaths();
|
|
24691
|
-
|
|
24692
|
-
// src/loopDefinitions.ts
|
|
24693
|
-
init_definition_paths();
|
|
24694
|
-
import * as fs50 from "fs";
|
|
24695
|
-
import * as path49 from "path";
|
|
24696
|
-
var ID = /^[a-z0-9][a-z0-9_-]{0,79}$/;
|
|
24697
|
-
function normalizeLoopDefinition(value) {
|
|
24698
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
24699
|
-
const raw = value;
|
|
24700
|
-
if (Object.keys(raw).some((key) => !["id", "trigger", "target", "input", "enabled"].includes(key))) return null;
|
|
24701
|
-
if (typeof raw.id !== "string" || !ID.test(raw.id)) return null;
|
|
24702
|
-
if (typeof raw.enabled !== "boolean") return null;
|
|
24703
|
-
if (!isObject2(raw.input) || !isObject2(raw.trigger) || !isObject2(raw.target)) return null;
|
|
24704
|
-
const targetKind = raw.target.kind;
|
|
24705
|
-
const targetId = raw.target.id;
|
|
24706
|
-
if (targetKind !== "workflow" && targetKind !== "capability" || typeof targetId !== "string" || !ID.test(targetId)) {
|
|
24707
|
-
return null;
|
|
24708
|
-
}
|
|
24709
|
-
const trigger = normalizeTrigger(raw.trigger);
|
|
24710
|
-
if (!trigger) return null;
|
|
24711
|
-
return {
|
|
24712
|
-
id: raw.id,
|
|
24713
|
-
trigger,
|
|
24714
|
-
target: { kind: targetKind, id: targetId },
|
|
24715
|
-
input: raw.input,
|
|
24716
|
-
enabled: raw.enabled
|
|
24717
|
-
};
|
|
24718
|
-
}
|
|
24719
|
-
function readLoopDefinition(cwd, id) {
|
|
24720
|
-
if (!ID.test(id)) return null;
|
|
24721
|
-
const roots = [
|
|
24722
|
-
path49.join(cwd, ".kody-engine", "runtime"),
|
|
24723
|
-
definitionsRoot(cwd)
|
|
24724
|
-
];
|
|
24725
|
-
for (const root of roots) {
|
|
24726
|
-
const filePath = path49.join(root, "loops", id, "loop.json");
|
|
24727
|
-
if (!fs50.existsSync(filePath)) continue;
|
|
24728
|
-
try {
|
|
24729
|
-
const loop = normalizeLoopDefinition(JSON.parse(fs50.readFileSync(filePath, "utf8")));
|
|
24730
|
-
if (loop?.id === id) return loop;
|
|
24731
|
-
process.stderr.write(`[kody] invalid simple Loop definition: ${filePath}
|
|
24732
|
-
`);
|
|
24733
|
-
} catch {
|
|
24734
|
-
process.stderr.write(`[kody] unreadable simple Loop definition: ${filePath}
|
|
24735
|
-
`);
|
|
24736
|
-
}
|
|
24737
|
-
}
|
|
24738
|
-
process.stderr.write(
|
|
24739
|
-
`[kody] simple Loop not found: ${id} (${roots.map((root) => path49.join(root, "loops", id, "loop.json")).join(", ")})
|
|
24740
|
-
`
|
|
24741
|
-
);
|
|
24742
|
-
return null;
|
|
24743
|
-
}
|
|
24744
|
-
function normalizeTrigger(raw) {
|
|
24745
|
-
if (raw.type === "manual" && Object.keys(raw).length === 1) return { type: "manual" };
|
|
24746
|
-
if (raw.type === "schedule" && typeof raw.every === "string" && /^\d+[mhd]$/.test(raw.every)) {
|
|
24747
|
-
if (raw.at === void 0 && Object.keys(raw).every((key) => key === "type" || key === "every")) {
|
|
24748
|
-
return { type: "schedule", every: raw.every };
|
|
24749
|
-
}
|
|
24750
|
-
if (isObject2(raw.at) && typeof raw.at.time === "string" && typeof raw.at.timezone === "string" && Object.keys(raw.at).every((key) => key === "time" || key === "timezone") && Object.keys(raw).every((key) => key === "type" || key === "every" || key === "at")) {
|
|
24751
|
-
return { type: "schedule", every: raw.every, at: { time: raw.at.time, timezone: raw.at.timezone } };
|
|
24752
|
-
}
|
|
24753
|
-
}
|
|
24754
|
-
if ((raw.type === "event" || raw.type === "webhook") && typeof raw.event === "string" && raw.event.trim() && Object.keys(raw).every((key) => key === "type" || key === "event")) {
|
|
24755
|
-
return { type: raw.type, event: raw.event.trim() };
|
|
24756
|
-
}
|
|
24757
|
-
if (raw.type === "condition" && typeof raw.expression === "string" && raw.expression.trim() && Object.keys(raw).every((key) => key === "type" || key === "expression")) {
|
|
24758
|
-
return { type: "condition", expression: raw.expression.trim() };
|
|
24759
|
-
}
|
|
24760
|
-
return null;
|
|
24761
|
-
}
|
|
24762
|
-
function isObject2(value) {
|
|
24763
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
24764
|
-
}
|
|
24765
|
-
|
|
24766
|
-
// src/kody-cli.ts
|
|
24924
|
+
init_loopDefinitions();
|
|
24767
24925
|
init_stateWorkspace();
|
|
24768
24926
|
init_workflowDefinitions();
|
|
24769
24927
|
var FAILED_DISPATCH_LABEL = {
|
|
@@ -26445,7 +26603,7 @@ init_config();
|
|
|
26445
26603
|
init_fetchRepoMcp();
|
|
26446
26604
|
|
|
26447
26605
|
// src/servers/mcpHttpServer.ts
|
|
26448
|
-
import { randomUUID as
|
|
26606
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
26449
26607
|
import { createServer as createServer4 } from "http";
|
|
26450
26608
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
26451
26609
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
@@ -26454,7 +26612,7 @@ function buildMcpHttpServer(opts) {
|
|
|
26454
26612
|
const transports = /* @__PURE__ */ new Map();
|
|
26455
26613
|
for (const route of opts.routes) {
|
|
26456
26614
|
const transport = new StreamableHTTPServerTransport({
|
|
26457
|
-
sessionIdGenerator: () =>
|
|
26615
|
+
sessionIdGenerator: () => randomUUID3()
|
|
26458
26616
|
});
|
|
26459
26617
|
transports.set(route.path, transport);
|
|
26460
26618
|
routes.set(route.path, route.name);
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
{
|
|
2
2
|
"internal": true,
|
|
3
|
-
"role": "watch",
|
|
4
|
-
"kind": "scheduled",
|
|
5
|
-
"schedule": "*/5 * * * *",
|
|
6
3
|
"claudeCode": {
|
|
7
4
|
"model": "inherit",
|
|
8
5
|
"permissionMode": "default",
|
|
@@ -33,9 +30,6 @@
|
|
|
33
30
|
"outputArtifacts": [],
|
|
34
31
|
"scripts": {
|
|
35
32
|
"preflight": [
|
|
36
|
-
{
|
|
37
|
-
"script": "dispatchAgencyLoops"
|
|
38
|
-
},
|
|
39
33
|
{
|
|
40
34
|
"shell": "scheduler.sh",
|
|
41
35
|
"timeoutSec": 1800
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"internal": true,
|
|
3
|
+
"role": "watch",
|
|
4
|
+
"kind": "scheduled",
|
|
5
|
+
"schedule": "*/5 * * * *",
|
|
6
|
+
"claudeCode": {
|
|
7
|
+
"model": "inherit",
|
|
8
|
+
"permissionMode": "default",
|
|
9
|
+
"maxTurns": 0,
|
|
10
|
+
"maxThinkingTokens": null,
|
|
11
|
+
"systemPromptAppend": null,
|
|
12
|
+
"tools": [],
|
|
13
|
+
"hooks": [],
|
|
14
|
+
"skills": [],
|
|
15
|
+
"commands": [],
|
|
16
|
+
"subagents": [],
|
|
17
|
+
"plugins": [],
|
|
18
|
+
"mcpServers": []
|
|
19
|
+
},
|
|
20
|
+
"cliTools": [],
|
|
21
|
+
"inputArtifacts": [],
|
|
22
|
+
"outputArtifacts": [],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"preflight": [
|
|
25
|
+
{ "script": "dispatchSimpleLoops" },
|
|
26
|
+
{ "script": "skipAgent" }
|
|
27
|
+
],
|
|
28
|
+
"postflight": []
|
|
29
|
+
},
|
|
30
|
+
"inputs": [],
|
|
31
|
+
"name": "loop-scheduler"
|
|
32
|
+
}
|
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.447",
|
|
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",
|