@kody-ade/kody-engine 0.4.445 → 0.4.446
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.446",
|
|
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",
|
|
@@ -13798,6 +13798,204 @@ var init_dispatchAgencyLoops = __esm({
|
|
|
13798
13798
|
}
|
|
13799
13799
|
});
|
|
13800
13800
|
|
|
13801
|
+
// src/loopDefinitions.ts
|
|
13802
|
+
import * as fs36 from "fs";
|
|
13803
|
+
import * as path34 from "path";
|
|
13804
|
+
function normalizeLoopDefinition(value) {
|
|
13805
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
13806
|
+
const raw = value;
|
|
13807
|
+
if (Object.keys(raw).some((key) => !["id", "trigger", "target", "input", "enabled"].includes(key))) return null;
|
|
13808
|
+
if (typeof raw.id !== "string" || !ID.test(raw.id)) return null;
|
|
13809
|
+
if (typeof raw.enabled !== "boolean") return null;
|
|
13810
|
+
if (!isObject(raw.input) || !isObject(raw.trigger) || !isObject(raw.target)) return null;
|
|
13811
|
+
const targetKind = raw.target.kind;
|
|
13812
|
+
const targetId = raw.target.id;
|
|
13813
|
+
if (targetKind !== "workflow" && targetKind !== "capability" || typeof targetId !== "string" || !ID.test(targetId)) {
|
|
13814
|
+
return null;
|
|
13815
|
+
}
|
|
13816
|
+
const trigger = normalizeTrigger(raw.trigger);
|
|
13817
|
+
if (!trigger) return null;
|
|
13818
|
+
return {
|
|
13819
|
+
id: raw.id,
|
|
13820
|
+
trigger,
|
|
13821
|
+
target: { kind: targetKind, id: targetId },
|
|
13822
|
+
input: raw.input,
|
|
13823
|
+
enabled: raw.enabled
|
|
13824
|
+
};
|
|
13825
|
+
}
|
|
13826
|
+
function readLoopDefinition(cwd, id) {
|
|
13827
|
+
if (!ID.test(id)) return null;
|
|
13828
|
+
const roots = [path34.join(cwd, ".kody-engine", "runtime"), definitionsRoot(cwd)];
|
|
13829
|
+
for (const root of roots) {
|
|
13830
|
+
const filePath = path34.join(root, "loops", id, "loop.json");
|
|
13831
|
+
if (!fs36.existsSync(filePath)) continue;
|
|
13832
|
+
try {
|
|
13833
|
+
const loop = normalizeLoopDefinition(JSON.parse(fs36.readFileSync(filePath, "utf8")));
|
|
13834
|
+
if (loop?.id === id) return loop;
|
|
13835
|
+
process.stderr.write(`[kody] invalid simple Loop definition: ${filePath}
|
|
13836
|
+
`);
|
|
13837
|
+
} catch {
|
|
13838
|
+
process.stderr.write(`[kody] unreadable simple Loop definition: ${filePath}
|
|
13839
|
+
`);
|
|
13840
|
+
}
|
|
13841
|
+
}
|
|
13842
|
+
process.stderr.write(
|
|
13843
|
+
`[kody] simple Loop not found: ${id} (${roots.map((root) => path34.join(root, "loops", id, "loop.json")).join(", ")})
|
|
13844
|
+
`
|
|
13845
|
+
);
|
|
13846
|
+
return null;
|
|
13847
|
+
}
|
|
13848
|
+
function listLoopDefinitions(cwd) {
|
|
13849
|
+
const roots = [path34.join(cwd, ".kody-engine", "runtime"), definitionsRoot(cwd)];
|
|
13850
|
+
const byId = /* @__PURE__ */ new Map();
|
|
13851
|
+
for (const root of roots.reverse()) {
|
|
13852
|
+
const loopsDir = path34.join(root, "loops");
|
|
13853
|
+
if (!fs36.existsSync(loopsDir)) continue;
|
|
13854
|
+
for (const id of fs36.readdirSync(loopsDir).sort()) {
|
|
13855
|
+
if (!ID.test(id)) continue;
|
|
13856
|
+
const filePath = path34.join(loopsDir, 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) byId.set(id, loop);
|
|
13861
|
+
} catch {
|
|
13862
|
+
process.stderr.write(`[kody] unreadable simple Loop definition: ${filePath}
|
|
13863
|
+
`);
|
|
13864
|
+
}
|
|
13865
|
+
}
|
|
13866
|
+
}
|
|
13867
|
+
return [...byId.values()].sort((left, right) => left.id.localeCompare(right.id));
|
|
13868
|
+
}
|
|
13869
|
+
function normalizeTrigger(raw) {
|
|
13870
|
+
if (raw.type === "manual" && Object.keys(raw).length === 1) return { type: "manual" };
|
|
13871
|
+
if (raw.type === "schedule" && typeof raw.every === "string" && /^\d+[mhd]$/.test(raw.every)) {
|
|
13872
|
+
if (raw.at === void 0 && Object.keys(raw).every((key) => key === "type" || key === "every")) {
|
|
13873
|
+
return { type: "schedule", every: raw.every };
|
|
13874
|
+
}
|
|
13875
|
+
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")) {
|
|
13876
|
+
return { type: "schedule", every: raw.every, at: { time: raw.at.time, timezone: raw.at.timezone } };
|
|
13877
|
+
}
|
|
13878
|
+
}
|
|
13879
|
+
if ((raw.type === "event" || raw.type === "webhook") && typeof raw.event === "string" && raw.event.trim() && Object.keys(raw).every((key) => key === "type" || key === "event")) {
|
|
13880
|
+
return { type: raw.type, event: raw.event.trim() };
|
|
13881
|
+
}
|
|
13882
|
+
if (raw.type === "condition" && typeof raw.expression === "string" && raw.expression.trim() && Object.keys(raw).every((key) => key === "type" || key === "expression")) {
|
|
13883
|
+
return { type: "condition", expression: raw.expression.trim() };
|
|
13884
|
+
}
|
|
13885
|
+
return null;
|
|
13886
|
+
}
|
|
13887
|
+
function isObject(value) {
|
|
13888
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
13889
|
+
}
|
|
13890
|
+
var ID;
|
|
13891
|
+
var init_loopDefinitions = __esm({
|
|
13892
|
+
"src/loopDefinitions.ts"() {
|
|
13893
|
+
"use strict";
|
|
13894
|
+
init_definition_paths();
|
|
13895
|
+
ID = /^[a-z0-9][a-z0-9_-]{0,79}$/;
|
|
13896
|
+
}
|
|
13897
|
+
});
|
|
13898
|
+
|
|
13899
|
+
// src/scripts/dispatchSimpleLoops.ts
|
|
13900
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
13901
|
+
function dueSlot(loop, now) {
|
|
13902
|
+
if (!loop.enabled || loop.trigger.type !== "schedule") return null;
|
|
13903
|
+
const match = /^(\d+)([mhd])$/.exec(loop.trigger.every);
|
|
13904
|
+
if (!match) return null;
|
|
13905
|
+
const amount = Number(match[1]);
|
|
13906
|
+
const unit = match[2];
|
|
13907
|
+
const milliseconds = amount * (unit === "m" ? 6e4 : unit === "h" ? 36e5 : 864e5);
|
|
13908
|
+
const slot = Math.floor(now.getTime() / milliseconds) * milliseconds;
|
|
13909
|
+
if (!loop.trigger.at) return new Date(slot).toISOString();
|
|
13910
|
+
const parts = new Intl.DateTimeFormat("en-CA", {
|
|
13911
|
+
timeZone: loop.trigger.at.timezone,
|
|
13912
|
+
year: "numeric",
|
|
13913
|
+
month: "2-digit",
|
|
13914
|
+
day: "2-digit",
|
|
13915
|
+
hour: "2-digit",
|
|
13916
|
+
minute: "2-digit",
|
|
13917
|
+
hourCycle: "h23"
|
|
13918
|
+
}).formatToParts(now);
|
|
13919
|
+
const hour = parts.find((part) => part.type === "hour")?.value;
|
|
13920
|
+
const minute = parts.find((part) => part.type === "minute")?.value;
|
|
13921
|
+
const [targetHour, targetMinute] = loop.trigger.at.time.split(":").map(Number);
|
|
13922
|
+
const localMinute = Number(hour) * 60 + Number(minute);
|
|
13923
|
+
const targetLocalMinute = Number(targetHour) * 60 + Number(targetMinute);
|
|
13924
|
+
const windowMinutes = Math.max(1, Math.ceil(Number(process.env.KODY_SCHEDULE_WINDOW_SEC || 300) / 60));
|
|
13925
|
+
if (localMinute < targetLocalMinute || localMinute >= targetLocalMinute + windowMinutes) return null;
|
|
13926
|
+
const year = parts.find((part) => part.type === "year")?.value;
|
|
13927
|
+
const month = parts.find((part) => part.type === "month")?.value;
|
|
13928
|
+
const day = parts.find((part) => part.type === "day")?.value;
|
|
13929
|
+
return `${year}-${month}-${day}T${loop.trigger.at.time}[${loop.trigger.at.timezone}]`;
|
|
13930
|
+
}
|
|
13931
|
+
function loopJob(loop) {
|
|
13932
|
+
const cliArgs = Object.fromEntries(
|
|
13933
|
+
Object.entries(loop.input).map(([key, value]) => [key, typeof value === "string" ? value : JSON.stringify(value)])
|
|
13934
|
+
);
|
|
13935
|
+
return loop.target.kind === "workflow" ? { workflow: loop.target.id, cliArgs, flavor: "scheduled" } : { capability: loop.target.id, cliArgs, flavor: "scheduled" };
|
|
13936
|
+
}
|
|
13937
|
+
function repositoryTenant2(config) {
|
|
13938
|
+
const [envOwner, envRepo] = (process.env.GITHUB_REPOSITORY ?? "").split("/");
|
|
13939
|
+
const owner = config.github?.owner?.trim() || envOwner?.trim();
|
|
13940
|
+
const repo = config.github?.repo?.trim() || envRepo?.trim();
|
|
13941
|
+
return owner && repo ? `${owner}/${repo}` : null;
|
|
13942
|
+
}
|
|
13943
|
+
var dispatchSimpleLoops;
|
|
13944
|
+
var init_dispatchSimpleLoops = __esm({
|
|
13945
|
+
"src/scripts/dispatchSimpleLoops.ts"() {
|
|
13946
|
+
"use strict";
|
|
13947
|
+
init_loopDefinitions();
|
|
13948
|
+
init_job();
|
|
13949
|
+
init_state_backend();
|
|
13950
|
+
dispatchSimpleLoops = async (ctx) => {
|
|
13951
|
+
const tenantId2 = repositoryTenant2(ctx.config);
|
|
13952
|
+
if (!tenantId2) throw new Error("Repository identity is required for Loop dispatch");
|
|
13953
|
+
const now = /* @__PURE__ */ new Date();
|
|
13954
|
+
const due = listLoopDefinitions(ctx.cwd).filter((loop) => dueSlot(loop, now) !== null);
|
|
13955
|
+
const backend = createStateBackendFromEnv();
|
|
13956
|
+
const results = [];
|
|
13957
|
+
for (const loop of due) {
|
|
13958
|
+
const slot = dueSlot(loop, now);
|
|
13959
|
+
if (!slot) continue;
|
|
13960
|
+
const reservationId = `reservation-${randomUUID2()}`;
|
|
13961
|
+
const idempotencyKey = `${loop.id}:${slot}`;
|
|
13962
|
+
const claimed = await backend.reserveAgencyDispatch(tenantId2, {
|
|
13963
|
+
idempotencyKey,
|
|
13964
|
+
loopId: loop.id,
|
|
13965
|
+
decision: { kind: "fire", reason: "local Loop schedule is due", scheduledAt: slot },
|
|
13966
|
+
leaseUntil: new Date(now.getTime() + 6 * 60 * 60 * 1e3).toISOString(),
|
|
13967
|
+
reservationId,
|
|
13968
|
+
correlationId: `corr-${randomUUID2()}`,
|
|
13969
|
+
policyHash: `loop:${loop.id}`,
|
|
13970
|
+
effectivePolicy: { source: "repository" },
|
|
13971
|
+
definitionRefs: [{ kind: "loop", id: loop.id }],
|
|
13972
|
+
maxConcurrentRuns: 1,
|
|
13973
|
+
requiresApproval: false,
|
|
13974
|
+
approvalScopeKind: "loop",
|
|
13975
|
+
approvalScopeId: loop.id,
|
|
13976
|
+
approvalAction: `${loop.target.kind}:${loop.target.id}`,
|
|
13977
|
+
now: now.toISOString()
|
|
13978
|
+
});
|
|
13979
|
+
if (!claimed.acquired) {
|
|
13980
|
+
results.push({ loopId: loop.id, status: "skipped", reason: claimed.reason ?? "already claimed" });
|
|
13981
|
+
continue;
|
|
13982
|
+
}
|
|
13983
|
+
const result = await runJob(loopJob(loop), {
|
|
13984
|
+
cwd: ctx.cwd,
|
|
13985
|
+
config: ctx.config,
|
|
13986
|
+
verbose: ctx.verbose,
|
|
13987
|
+
quiet: ctx.quiet,
|
|
13988
|
+
chain: false
|
|
13989
|
+
});
|
|
13990
|
+
const status = result.exitCode === 0 ? "dispatched" : "failed";
|
|
13991
|
+
await backend.finishAgencyDispatch(tenantId2, idempotencyKey, reservationId, status, (/* @__PURE__ */ new Date()).toISOString());
|
|
13992
|
+
results.push({ loopId: loop.id, status, reason: result.reason ?? status });
|
|
13993
|
+
}
|
|
13994
|
+
ctx.data.simpleLoopDispatchResults = results;
|
|
13995
|
+
};
|
|
13996
|
+
}
|
|
13997
|
+
});
|
|
13998
|
+
|
|
13801
13999
|
// src/jobIdentity.ts
|
|
13802
14000
|
function stableJobKey(job) {
|
|
13803
14001
|
const capability = job.workflow ?? job.capability ?? job.action;
|
|
@@ -14818,15 +15016,15 @@ var init_fixFlow = __esm({
|
|
|
14818
15016
|
});
|
|
14819
15017
|
|
|
14820
15018
|
// src/workflow-template.ts
|
|
14821
|
-
import * as
|
|
14822
|
-
import * as
|
|
15019
|
+
import * as fs37 from "fs";
|
|
15020
|
+
import * as path35 from "path";
|
|
14823
15021
|
import { fileURLToPath } from "url";
|
|
14824
15022
|
function loadKodyWorkflowTemplate() {
|
|
14825
|
-
const here =
|
|
14826
|
-
const candidates = [
|
|
14827
|
-
const source = candidates.find((candidate) =>
|
|
15023
|
+
const here = path35.dirname(fileURLToPath(import.meta.url));
|
|
15024
|
+
const candidates = [path35.resolve(here, "../templates/kody.yml"), path35.resolve(here, "../../templates/kody.yml")];
|
|
15025
|
+
const source = candidates.find((candidate) => fs37.existsSync(candidate));
|
|
14828
15026
|
if (!source) throw new Error(`Kody workflow template is missing: ${KODY_WORKFLOW_TEMPLATE_PATH}`);
|
|
14829
|
-
return
|
|
15027
|
+
return fs37.readFileSync(source, "utf8");
|
|
14830
15028
|
}
|
|
14831
15029
|
var KODY_WORKFLOW_TEMPLATE_PATH;
|
|
14832
15030
|
var init_workflow_template = __esm({
|
|
@@ -14838,12 +15036,12 @@ var init_workflow_template = __esm({
|
|
|
14838
15036
|
|
|
14839
15037
|
// src/scripts/initFlow.ts
|
|
14840
15038
|
import { execFileSync as execFileSync14 } from "child_process";
|
|
14841
|
-
import * as
|
|
14842
|
-
import * as
|
|
15039
|
+
import * as fs38 from "fs";
|
|
15040
|
+
import * as path36 from "path";
|
|
14843
15041
|
function detectPackageManager(cwd) {
|
|
14844
|
-
if (
|
|
14845
|
-
if (
|
|
14846
|
-
if (
|
|
15042
|
+
if (fs38.existsSync(path36.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
15043
|
+
if (fs38.existsSync(path36.join(cwd, "yarn.lock"))) return "yarn";
|
|
15044
|
+
if (fs38.existsSync(path36.join(cwd, "bun.lockb"))) return "bun";
|
|
14847
15045
|
return "npm";
|
|
14848
15046
|
}
|
|
14849
15047
|
function qualityCommandsFor(pm) {
|
|
@@ -14915,22 +15113,22 @@ function performInit(cwd, force) {
|
|
|
14915
15113
|
const pm = detectPackageManager(cwd);
|
|
14916
15114
|
const ownerRepo = detectOwnerRepo(cwd);
|
|
14917
15115
|
const defaultBranch = defaultBranchFromGit(cwd);
|
|
14918
|
-
const configPath =
|
|
14919
|
-
if (
|
|
15116
|
+
const configPath = path36.join(cwd, "kody.config.json");
|
|
15117
|
+
if (fs38.existsSync(configPath) && !force) {
|
|
14920
15118
|
skipped.push("kody.config.json");
|
|
14921
15119
|
} else {
|
|
14922
15120
|
const cfg = makeConfig(pm, ownerRepo, defaultBranch);
|
|
14923
|
-
|
|
15121
|
+
fs38.writeFileSync(configPath, `${JSON.stringify(cfg, null, 2)}
|
|
14924
15122
|
`);
|
|
14925
15123
|
wrote.push("kody.config.json");
|
|
14926
15124
|
}
|
|
14927
|
-
const workflowDir =
|
|
14928
|
-
const workflowPath =
|
|
14929
|
-
if (
|
|
15125
|
+
const workflowDir = path36.join(cwd, ".github", "workflows");
|
|
15126
|
+
const workflowPath = path36.join(workflowDir, "kody.yml");
|
|
15127
|
+
if (fs38.existsSync(workflowPath) && !force) {
|
|
14930
15128
|
skipped.push(".github/workflows/kody.yml");
|
|
14931
15129
|
} else {
|
|
14932
|
-
|
|
14933
|
-
|
|
15130
|
+
fs38.mkdirSync(workflowDir, { recursive: true });
|
|
15131
|
+
fs38.writeFileSync(workflowPath, loadKodyWorkflowTemplate());
|
|
14934
15132
|
wrote.push(".github/workflows/kody.yml");
|
|
14935
15133
|
}
|
|
14936
15134
|
for (const exe of listRuntimeProfilesForCwd(cwd)) {
|
|
@@ -14941,12 +15139,12 @@ function performInit(cwd, force) {
|
|
|
14941
15139
|
continue;
|
|
14942
15140
|
}
|
|
14943
15141
|
if (profile.kind !== "scheduled" || !profile.schedule) continue;
|
|
14944
|
-
const target =
|
|
14945
|
-
if (
|
|
15142
|
+
const target = path36.join(workflowDir, `kody-${exe.name}.yml`);
|
|
15143
|
+
if (fs38.existsSync(target) && !force) {
|
|
14946
15144
|
skipped.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
14947
15145
|
continue;
|
|
14948
15146
|
}
|
|
14949
|
-
|
|
15147
|
+
fs38.writeFileSync(target, renderScheduledWorkflow(exe.name, profile.schedule));
|
|
14950
15148
|
wrote.push(`.github/workflows/kody-${exe.name}.yml`);
|
|
14951
15149
|
}
|
|
14952
15150
|
let labels;
|
|
@@ -15034,7 +15232,7 @@ Nothing to do. All files already present. (Use --force to overwrite.)
|
|
|
15034
15232
|
});
|
|
15035
15233
|
|
|
15036
15234
|
// src/scripts/loadAgentAdhoc.ts
|
|
15037
|
-
import * as
|
|
15235
|
+
import * as fs39 from "fs";
|
|
15038
15236
|
function resolveMessage(messageArg) {
|
|
15039
15237
|
const fromComment = readCommentBody();
|
|
15040
15238
|
if (fromComment) return stripDirective(fromComment);
|
|
@@ -15042,9 +15240,9 @@ function resolveMessage(messageArg) {
|
|
|
15042
15240
|
}
|
|
15043
15241
|
function readCommentBody() {
|
|
15044
15242
|
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
15045
|
-
if (!eventPath || !
|
|
15243
|
+
if (!eventPath || !fs39.existsSync(eventPath)) return "";
|
|
15046
15244
|
try {
|
|
15047
|
-
const event = JSON.parse(
|
|
15245
|
+
const event = JSON.parse(fs39.readFileSync(eventPath, "utf-8"));
|
|
15048
15246
|
return String(event.comment?.body ?? "");
|
|
15049
15247
|
} catch {
|
|
15050
15248
|
return "";
|
|
@@ -15098,10 +15296,10 @@ var init_loadAgentAdhoc = __esm({
|
|
|
15098
15296
|
throw new Error("loadAgentAdhoc: ctx.args.agent must be a non-empty slug");
|
|
15099
15297
|
}
|
|
15100
15298
|
const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
|
|
15101
|
-
if (!
|
|
15299
|
+
if (!fs39.existsSync(agentPath)) {
|
|
15102
15300
|
throw new Error(`loadAgentAdhoc: agent identity not found: ${agentPath}`);
|
|
15103
15301
|
}
|
|
15104
|
-
const { title, body } = parseAgentFile(
|
|
15302
|
+
const { title, body } = parseAgentFile(fs39.readFileSync(agentPath, "utf-8"), agentSlug);
|
|
15105
15303
|
const message = resolveMessage(ctx.args.message);
|
|
15106
15304
|
if (!message) {
|
|
15107
15305
|
throw new Error(
|
|
@@ -15170,8 +15368,8 @@ var init_loadCapabilityState = __esm({
|
|
|
15170
15368
|
});
|
|
15171
15369
|
|
|
15172
15370
|
// src/scripts/loadSimpleCapability.ts
|
|
15173
|
-
import * as
|
|
15174
|
-
import * as
|
|
15371
|
+
import * as fs40 from "fs";
|
|
15372
|
+
import * as path37 from "path";
|
|
15175
15373
|
function parseInput(supplied) {
|
|
15176
15374
|
if (typeof supplied !== "string") return supplied;
|
|
15177
15375
|
try {
|
|
@@ -15218,14 +15416,14 @@ function capabilityEnvironment(input) {
|
|
|
15218
15416
|
return environment;
|
|
15219
15417
|
}
|
|
15220
15418
|
function listFiles(root) {
|
|
15221
|
-
if (!
|
|
15419
|
+
if (!fs40.existsSync(root)) return [];
|
|
15222
15420
|
const files = [];
|
|
15223
15421
|
const visit = (dir) => {
|
|
15224
|
-
for (const entry of
|
|
15225
|
-
const absolute =
|
|
15422
|
+
for (const entry of fs40.readdirSync(dir, { withFileTypes: true })) {
|
|
15423
|
+
const absolute = path37.join(dir, entry.name);
|
|
15226
15424
|
if (entry.isSymbolicLink()) continue;
|
|
15227
15425
|
if (entry.isDirectory()) visit(absolute);
|
|
15228
|
-
else if (entry.isFile()) files.push(
|
|
15426
|
+
else if (entry.isFile()) files.push(path37.relative(root, absolute));
|
|
15229
15427
|
}
|
|
15230
15428
|
};
|
|
15231
15429
|
visit(root);
|
|
@@ -15246,8 +15444,8 @@ var init_loadSimpleCapability = __esm({
|
|
|
15246
15444
|
if (!capability) {
|
|
15247
15445
|
throw new Error(`Capability "${slug}" is not a valid simple capability folder`);
|
|
15248
15446
|
}
|
|
15249
|
-
const toolRoot =
|
|
15250
|
-
const skillRoot =
|
|
15447
|
+
const toolRoot = path37.join(capability.dir, "tools");
|
|
15448
|
+
const skillRoot = path37.join(capability.dir, "skills");
|
|
15251
15449
|
const toolFiles = listFiles(toolRoot);
|
|
15252
15450
|
const skillFiles = listFiles(skillRoot);
|
|
15253
15451
|
const input = parseInput(ctx.args.input);
|
|
@@ -15271,7 +15469,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
15271
15469
|
...skillFiles.flatMap((file) => [
|
|
15272
15470
|
`### ${file}`,
|
|
15273
15471
|
"",
|
|
15274
|
-
|
|
15472
|
+
fs40.readFileSync(path37.join(skillRoot, file), "utf-8"),
|
|
15275
15473
|
""
|
|
15276
15474
|
])
|
|
15277
15475
|
] : [],
|
|
@@ -15280,7 +15478,7 @@ var init_loadSimpleCapability = __esm({
|
|
|
15280
15478
|
"## Tools",
|
|
15281
15479
|
"",
|
|
15282
15480
|
"Inspect or run these capability-owned files when needed:",
|
|
15283
|
-
...toolFiles.map((file) => `- ${
|
|
15481
|
+
...toolFiles.map((file) => `- ${path37.join(toolRoot, file)}`)
|
|
15284
15482
|
] : []
|
|
15285
15483
|
].join("\n");
|
|
15286
15484
|
};
|
|
@@ -15588,8 +15786,8 @@ var init_loadIssueStateComment = __esm({
|
|
|
15588
15786
|
});
|
|
15589
15787
|
|
|
15590
15788
|
// src/scripts/loadJobFromFile.ts
|
|
15591
|
-
import * as
|
|
15592
|
-
import * as
|
|
15789
|
+
import * as fs41 from "fs";
|
|
15790
|
+
import * as path38 from "path";
|
|
15593
15791
|
function parseJobFile(raw, slug) {
|
|
15594
15792
|
let stripped = raw;
|
|
15595
15793
|
if (stripped.startsWith("---\n")) {
|
|
@@ -15628,10 +15826,10 @@ var init_loadJobFromFile = __esm({
|
|
|
15628
15826
|
if (!slug) {
|
|
15629
15827
|
throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
|
|
15630
15828
|
}
|
|
15631
|
-
const capability = resolveCapabilityFolder(slug,
|
|
15829
|
+
const capability = resolveCapabilityFolder(slug, path38.resolve(ctx.cwd, jobsDir));
|
|
15632
15830
|
if (!capability) {
|
|
15633
15831
|
throw new Error(
|
|
15634
|
-
`loadJobFromFile: capability folder not found or incomplete: ${
|
|
15832
|
+
`loadJobFromFile: capability folder not found or incomplete: ${path38.resolve(ctx.cwd, jobsDir, slug)}`
|
|
15635
15833
|
);
|
|
15636
15834
|
}
|
|
15637
15835
|
const { title, body, config } = capability;
|
|
@@ -15641,12 +15839,12 @@ var init_loadJobFromFile = __esm({
|
|
|
15641
15839
|
let agentIdentity = "";
|
|
15642
15840
|
if (agentSlug) {
|
|
15643
15841
|
const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
|
|
15644
|
-
if (!
|
|
15842
|
+
if (!fs41.existsSync(agentPath)) {
|
|
15645
15843
|
throw new Error(
|
|
15646
15844
|
`loadJobFromFile: capability '${slug}' declares agent '${agentSlug}' but ${agentPath} does not exist`
|
|
15647
15845
|
);
|
|
15648
15846
|
}
|
|
15649
|
-
const agentRaw =
|
|
15847
|
+
const agentRaw = fs41.readFileSync(agentPath, "utf-8");
|
|
15650
15848
|
const parsed = parseJobFile(agentRaw, agentSlug);
|
|
15651
15849
|
agentTitle = parsed.title;
|
|
15652
15850
|
agentIdentity = parsed.body;
|
|
@@ -15726,13 +15924,13 @@ ${truncate2(issue2.body, FINDING_BODY_MAX_BYTES)}`;
|
|
|
15726
15924
|
});
|
|
15727
15925
|
|
|
15728
15926
|
// src/scripts/kodyVariables.ts
|
|
15729
|
-
import * as
|
|
15730
|
-
import * as
|
|
15927
|
+
import * as fs42 from "fs";
|
|
15928
|
+
import * as path39 from "path";
|
|
15731
15929
|
function readKodyVariables(cwd) {
|
|
15732
|
-
const full =
|
|
15930
|
+
const full = path39.join(cwd, KODY_VARIABLES_REL_PATH);
|
|
15733
15931
|
let raw;
|
|
15734
15932
|
try {
|
|
15735
|
-
raw =
|
|
15933
|
+
raw = fs42.readFileSync(full, "utf-8");
|
|
15736
15934
|
} catch {
|
|
15737
15935
|
return {};
|
|
15738
15936
|
}
|
|
@@ -15908,8 +16106,8 @@ var init_runtimeSecrets = __esm({
|
|
|
15908
16106
|
});
|
|
15909
16107
|
|
|
15910
16108
|
// src/scripts/loadQaContext.ts
|
|
15911
|
-
import * as
|
|
15912
|
-
import * as
|
|
16109
|
+
import * as fs43 from "fs";
|
|
16110
|
+
import * as path40 from "path";
|
|
15913
16111
|
function parseSlugList(value) {
|
|
15914
16112
|
const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
15915
16113
|
return inner.split(",").map(
|
|
@@ -15938,18 +16136,18 @@ function readProfileAgents(raw) {
|
|
|
15938
16136
|
return { agent: agent ?? legacy ?? ["kody"], body };
|
|
15939
16137
|
}
|
|
15940
16138
|
function readProfile(cwd) {
|
|
15941
|
-
const dir =
|
|
15942
|
-
if (!
|
|
16139
|
+
const dir = path40.join(cwd, CONTEXT_DIR_REL_PATH);
|
|
16140
|
+
if (!fs43.existsSync(dir)) return "";
|
|
15943
16141
|
let entries;
|
|
15944
16142
|
try {
|
|
15945
|
-
entries =
|
|
16143
|
+
entries = fs43.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
15946
16144
|
} catch {
|
|
15947
16145
|
return "";
|
|
15948
16146
|
}
|
|
15949
16147
|
const blocks = [];
|
|
15950
16148
|
for (const file of entries) {
|
|
15951
16149
|
try {
|
|
15952
|
-
const raw =
|
|
16150
|
+
const raw = fs43.readFileSync(path40.join(dir, file), "utf-8");
|
|
15953
16151
|
const { agent, body } = readProfileAgents(raw);
|
|
15954
16152
|
if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
|
|
15955
16153
|
blocks.push(`## ${file}
|
|
@@ -15998,8 +16196,8 @@ var init_loadQaContext = __esm({
|
|
|
15998
16196
|
});
|
|
15999
16197
|
|
|
16000
16198
|
// src/taskContext.ts
|
|
16001
|
-
import * as
|
|
16002
|
-
import * as
|
|
16199
|
+
import * as fs44 from "fs";
|
|
16200
|
+
import * as path41 from "path";
|
|
16003
16201
|
function buildTaskContext(args) {
|
|
16004
16202
|
return {
|
|
16005
16203
|
schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
|
|
@@ -16015,9 +16213,9 @@ function buildTaskContext(args) {
|
|
|
16015
16213
|
function persistTaskContext(cwd, ctx) {
|
|
16016
16214
|
try {
|
|
16017
16215
|
const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
|
|
16018
|
-
|
|
16019
|
-
const file =
|
|
16020
|
-
|
|
16216
|
+
fs44.mkdirSync(dir, { recursive: true });
|
|
16217
|
+
const file = path41.join(dir, "task-context.json");
|
|
16218
|
+
fs44.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
|
|
16021
16219
|
`);
|
|
16022
16220
|
return file;
|
|
16023
16221
|
} catch (err) {
|
|
@@ -16857,7 +17055,7 @@ function parseSingleJsonCandidate(candidates) {
|
|
|
16857
17055
|
}
|
|
16858
17056
|
return parsed.length === 1 ? { found: true, value: parsed[0] } : { found: false };
|
|
16859
17057
|
}
|
|
16860
|
-
function
|
|
17058
|
+
function isObject2(value) {
|
|
16861
17059
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
16862
17060
|
}
|
|
16863
17061
|
function stringValue4(value) {
|
|
@@ -16875,8 +17073,8 @@ var init_parseSimpleCapabilityOutput = __esm({
|
|
|
16875
17073
|
return;
|
|
16876
17074
|
}
|
|
16877
17075
|
ctx.data.capabilityOutput = output;
|
|
16878
|
-
const result =
|
|
16879
|
-
const data =
|
|
17076
|
+
const result = isObject2(output) ? output : {};
|
|
17077
|
+
const data = isObject2(result.data) ? result.data : isObject2(output) ? output : { output };
|
|
16880
17078
|
const summary = typeof result.summary === "string" ? result.summary : "Capability completed";
|
|
16881
17079
|
const reason = typeof result.reason === "string" ? result.reason : summary;
|
|
16882
17080
|
const prUrl = stringValue4(data.pullRequestUrl) ?? stringValue4(data.prUrl) ?? stringValue4(result.pullRequestUrl) ?? stringValue4(result.prUrl);
|
|
@@ -17467,9 +17665,9 @@ var init_postResearchComment = __esm({
|
|
|
17467
17665
|
});
|
|
17468
17666
|
|
|
17469
17667
|
// src/scripts/prepareBrowserAuth.ts
|
|
17470
|
-
import * as
|
|
17668
|
+
import * as fs45 from "fs";
|
|
17471
17669
|
import * as os6 from "os";
|
|
17472
|
-
import * as
|
|
17670
|
+
import * as path42 from "path";
|
|
17473
17671
|
function appendAuthMessage(ctx, message) {
|
|
17474
17672
|
const current = typeof ctx.data.qaAuthBlock === "string" ? ctx.data.qaAuthBlock.trim() : "";
|
|
17475
17673
|
ctx.data.qaAuthBlock = current ? `${current}
|
|
@@ -17508,9 +17706,9 @@ async function githubJson(url, token) {
|
|
|
17508
17706
|
return await response.json();
|
|
17509
17707
|
}
|
|
17510
17708
|
function writeKodyStorageState(input) {
|
|
17511
|
-
const directory =
|
|
17512
|
-
|
|
17513
|
-
const file =
|
|
17709
|
+
const directory = fs45.mkdtempSync(path42.join(os6.tmpdir(), "kody-browser-auth-"));
|
|
17710
|
+
fs45.chmodSync(directory, 448);
|
|
17711
|
+
const file = path42.join(directory, "storage-state.json");
|
|
17514
17712
|
const now = Date.now();
|
|
17515
17713
|
const repoEntry = {
|
|
17516
17714
|
repoUrl: input.repoUrl,
|
|
@@ -17540,7 +17738,7 @@ function writeKodyStorageState(input) {
|
|
|
17540
17738
|
}
|
|
17541
17739
|
]
|
|
17542
17740
|
};
|
|
17543
|
-
|
|
17741
|
+
fs45.writeFileSync(file, JSON.stringify(storageState), { mode: 384 });
|
|
17544
17742
|
return { directory, file };
|
|
17545
17743
|
}
|
|
17546
17744
|
function configurePlaywright(profile, storageStatePath) {
|
|
@@ -17622,7 +17820,7 @@ async function prepareMethod(ctx, profile, method) {
|
|
|
17622
17820
|
configurePlaywright(profile, state.file);
|
|
17623
17821
|
const authDirectory = state.directory;
|
|
17624
17822
|
registerRuntimeCleanup(ctx, () => {
|
|
17625
|
-
|
|
17823
|
+
fs45.rmSync(authDirectory, { recursive: true, force: true });
|
|
17626
17824
|
});
|
|
17627
17825
|
appendAuthMessage(
|
|
17628
17826
|
ctx,
|
|
@@ -17630,7 +17828,7 @@ async function prepareMethod(ctx, profile, method) {
|
|
|
17630
17828
|
);
|
|
17631
17829
|
return true;
|
|
17632
17830
|
} catch (error) {
|
|
17633
|
-
if (state)
|
|
17831
|
+
if (state) fs45.rmSync(state.directory, { recursive: true, force: true });
|
|
17634
17832
|
const reason = error instanceof Error ? error.message : String(error);
|
|
17635
17833
|
appendAuthMessage(
|
|
17636
17834
|
ctx,
|
|
@@ -18729,12 +18927,12 @@ fi
|
|
|
18729
18927
|
|
|
18730
18928
|
// src/scripts/runPreviewBuild.ts
|
|
18731
18929
|
import { copyFile, writeFile } from "fs/promises";
|
|
18732
|
-
import * as
|
|
18930
|
+
import * as path43 from "path";
|
|
18733
18931
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
18734
18932
|
function bundledDockerfilePath(mode) {
|
|
18735
|
-
const here =
|
|
18933
|
+
const here = path43.dirname(fileURLToPath2(import.meta.url));
|
|
18736
18934
|
const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
|
|
18737
|
-
return
|
|
18935
|
+
return path43.join(here, "preview-build-templates", file);
|
|
18738
18936
|
}
|
|
18739
18937
|
function required(name) {
|
|
18740
18938
|
const v = (process.env[name] ?? "").trim();
|
|
@@ -18969,10 +19167,10 @@ var init_runPreviewBuild = __esm({
|
|
|
18969
19167
|
console.log(`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`);
|
|
18970
19168
|
if (Object.keys(buildEnv).length > 0) {
|
|
18971
19169
|
const lines = Object.entries(buildEnv).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
|
|
18972
|
-
await writeFile(
|
|
19170
|
+
await writeFile(path43.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
|
|
18973
19171
|
`, "utf8");
|
|
18974
19172
|
}
|
|
18975
|
-
const consumerDockerfile =
|
|
19173
|
+
const consumerDockerfile = path43.join(ctx.cwd, "Dockerfile.preview");
|
|
18976
19174
|
const { stat } = await import("fs/promises");
|
|
18977
19175
|
let hasConsumerDockerfile = false;
|
|
18978
19176
|
try {
|
|
@@ -19156,8 +19354,8 @@ var init_tickShellRunner = __esm({
|
|
|
19156
19354
|
});
|
|
19157
19355
|
|
|
19158
19356
|
// src/scripts/runScheduledImplementationTick.ts
|
|
19159
|
-
import * as
|
|
19160
|
-
import * as
|
|
19357
|
+
import * as fs46 from "fs";
|
|
19358
|
+
import * as path44 from "path";
|
|
19161
19359
|
var runScheduledImplementationTick;
|
|
19162
19360
|
var init_runScheduledImplementationTick = __esm({
|
|
19163
19361
|
"src/scripts/runScheduledImplementationTick.ts"() {
|
|
@@ -19178,14 +19376,14 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
19178
19376
|
ctx.output.reason = `runScheduledImplementationTick: args.slug or ctx.args.${slugArg} must be non-empty capability slug`;
|
|
19179
19377
|
return;
|
|
19180
19378
|
}
|
|
19181
|
-
const capability = resolveCapabilityFolder(slug,
|
|
19379
|
+
const capability = resolveCapabilityFolder(slug, path44.resolve(ctx.cwd, jobsDir));
|
|
19182
19380
|
if (!capability) {
|
|
19183
19381
|
ctx.output.exitCode = 99;
|
|
19184
19382
|
ctx.output.reason = `runScheduledImplementationTick: capability folder not found or incomplete: ${slug} (searched ${jobsDir} and company store)`;
|
|
19185
19383
|
return;
|
|
19186
19384
|
}
|
|
19187
|
-
const shellPath =
|
|
19188
|
-
if (!
|
|
19385
|
+
const shellPath = path44.join(profile.dir, shell);
|
|
19386
|
+
if (!fs46.existsSync(shellPath)) {
|
|
19189
19387
|
ctx.output.exitCode = 99;
|
|
19190
19388
|
ctx.output.reason = `runScheduledImplementationTick: shell not found: ${shell} (looked in ${profile.dir})`;
|
|
19191
19389
|
return;
|
|
@@ -19216,8 +19414,8 @@ var init_runScheduledImplementationTick = __esm({
|
|
|
19216
19414
|
});
|
|
19217
19415
|
|
|
19218
19416
|
// src/scripts/runTickScript.ts
|
|
19219
|
-
import * as
|
|
19220
|
-
import * as
|
|
19417
|
+
import * as fs47 from "fs";
|
|
19418
|
+
import * as path45 from "path";
|
|
19221
19419
|
var runTickScript;
|
|
19222
19420
|
var init_runTickScript = __esm({
|
|
19223
19421
|
"src/scripts/runTickScript.ts"() {
|
|
@@ -19237,10 +19435,10 @@ var init_runTickScript = __esm({
|
|
|
19237
19435
|
ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
|
|
19238
19436
|
return;
|
|
19239
19437
|
}
|
|
19240
|
-
const capability = readCapabilityFolder(
|
|
19438
|
+
const capability = readCapabilityFolder(path45.resolve(ctx.cwd, jobsDir), slug);
|
|
19241
19439
|
if (!capability) {
|
|
19242
19440
|
ctx.output.exitCode = 99;
|
|
19243
|
-
ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${
|
|
19441
|
+
ctx.output.reason = `runTickScript: capability folder not found or incomplete: ${path45.resolve(ctx.cwd, jobsDir, slug)}`;
|
|
19244
19442
|
return;
|
|
19245
19443
|
}
|
|
19246
19444
|
const tickScript = capability.config.tickScript;
|
|
@@ -19249,8 +19447,8 @@ var init_runTickScript = __esm({
|
|
|
19249
19447
|
ctx.output.reason = `runTickScript: capability ${slug} has no \`tickScript\` in profile.json \u2014 route via capability-tick instead`;
|
|
19250
19448
|
return;
|
|
19251
19449
|
}
|
|
19252
|
-
const scriptPath =
|
|
19253
|
-
if (!
|
|
19450
|
+
const scriptPath = path45.isAbsolute(tickScript) ? tickScript : path45.join(ctx.cwd, tickScript);
|
|
19451
|
+
if (!fs47.existsSync(scriptPath)) {
|
|
19254
19452
|
ctx.output.exitCode = 99;
|
|
19255
19453
|
ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
|
|
19256
19454
|
return;
|
|
@@ -19532,7 +19730,7 @@ var init_syncFlow = __esm({
|
|
|
19532
19730
|
});
|
|
19533
19731
|
|
|
19534
19732
|
// src/scripts/validateAgencyModelProposal.ts
|
|
19535
|
-
import * as
|
|
19733
|
+
import * as path46 from "path";
|
|
19536
19734
|
function validateModelBundle(bundle, expectedKind, options = {}) {
|
|
19537
19735
|
const failures = [];
|
|
19538
19736
|
validateOneModel(bundle.model, bundle.files, "model", true, failures, expectedKind, options);
|
|
@@ -19850,7 +20048,7 @@ var init_validateAgencyModelProposal = __esm({
|
|
|
19850
20048
|
const bundle = parseAgencyModelProposal(raw);
|
|
19851
20049
|
const expectedKind = readExpectedModelKind(args);
|
|
19852
20050
|
const failures = validateModelBundle(bundle, expectedKind, {
|
|
19853
|
-
capabilityRoot:
|
|
20051
|
+
capabilityRoot: path46.join(ctx.cwd, ".kody", "capabilities")
|
|
19854
20052
|
});
|
|
19855
20053
|
if (failures.length > 0) {
|
|
19856
20054
|
throw new Error(`validateAgencyModelProposal: ${failures.join("; ")}`);
|
|
@@ -20401,7 +20599,7 @@ var init_warmupMcp = __esm({
|
|
|
20401
20599
|
});
|
|
20402
20600
|
|
|
20403
20601
|
// src/scripts/writeAgentRunSummary.ts
|
|
20404
|
-
import * as
|
|
20602
|
+
import * as fs48 from "fs";
|
|
20405
20603
|
var writeAgentRunSummary;
|
|
20406
20604
|
var init_writeAgentRunSummary = __esm({
|
|
20407
20605
|
"src/scripts/writeAgentRunSummary.ts"() {
|
|
@@ -20427,7 +20625,7 @@ var init_writeAgentRunSummary = __esm({
|
|
|
20427
20625
|
if (reason) lines.push(`- **Reason:** ${reason}`);
|
|
20428
20626
|
lines.push("");
|
|
20429
20627
|
try {
|
|
20430
|
-
|
|
20628
|
+
fs48.appendFileSync(summaryPath, `${lines.join("\n")}
|
|
20431
20629
|
`);
|
|
20432
20630
|
} catch {
|
|
20433
20631
|
}
|
|
@@ -20564,6 +20762,7 @@ var init_scripts = __esm({
|
|
|
20564
20762
|
init_dispatchCapabilityTicks();
|
|
20565
20763
|
init_dispatchClassified();
|
|
20566
20764
|
init_dispatchAgencyLoops();
|
|
20765
|
+
init_dispatchSimpleLoops();
|
|
20567
20766
|
init_dispatchNextTaskJob();
|
|
20568
20767
|
init_ensurePr();
|
|
20569
20768
|
init_evaluateAgencyBoundaries();
|
|
@@ -20688,6 +20887,7 @@ var init_scripts = __esm({
|
|
|
20688
20887
|
warmupMcp,
|
|
20689
20888
|
dispatchCapabilityTicks,
|
|
20690
20889
|
dispatchAgencyLoops,
|
|
20890
|
+
dispatchSimpleLoops,
|
|
20691
20891
|
dispatchCapabilityFileTicks,
|
|
20692
20892
|
planTaskJobs,
|
|
20693
20893
|
dispatchNextTaskJob,
|
|
@@ -20759,17 +20959,17 @@ var init_scripts = __esm({
|
|
|
20759
20959
|
});
|
|
20760
20960
|
|
|
20761
20961
|
// src/stateWorkspace.ts
|
|
20762
|
-
import * as
|
|
20763
|
-
import * as
|
|
20962
|
+
import * as fs49 from "fs";
|
|
20963
|
+
import * as path47 from "path";
|
|
20764
20964
|
function tenantId(config) {
|
|
20765
20965
|
const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
|
|
20766
20966
|
const repo = config.github?.repo?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[1]?.trim();
|
|
20767
20967
|
return owner && repo ? `${owner}/${repo}` : null;
|
|
20768
20968
|
}
|
|
20769
20969
|
function writeRuntimeFile(cwd, relativePath, content) {
|
|
20770
|
-
const target =
|
|
20771
|
-
|
|
20772
|
-
|
|
20970
|
+
const target = path47.join(cwd, RUNTIME_ROOT, relativePath);
|
|
20971
|
+
fs49.mkdirSync(path47.dirname(target), { recursive: true });
|
|
20972
|
+
fs49.writeFileSync(target, content, "utf8");
|
|
20773
20973
|
}
|
|
20774
20974
|
function record(value) {
|
|
20775
20975
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -20834,11 +21034,11 @@ async function hydrateStateWorkspace(config, cwd, backendOverride) {
|
|
|
20834
21034
|
throw new Error("Kody backend access is required for runtime workspace documents");
|
|
20835
21035
|
return;
|
|
20836
21036
|
}
|
|
20837
|
-
const key = `${
|
|
21037
|
+
const key = `${path47.resolve(cwd)}|${tenant}`;
|
|
20838
21038
|
if (hydratedWorkspaces.has(key)) return;
|
|
20839
21039
|
const backend = backendOverride ?? createStateBackendFromEnv();
|
|
20840
|
-
const root =
|
|
20841
|
-
|
|
21040
|
+
const root = path47.join(cwd, RUNTIME_ROOT);
|
|
21041
|
+
fs49.rmSync(root, { recursive: true, force: true });
|
|
20842
21042
|
await Promise.all([
|
|
20843
21043
|
hydratePrefix(backend, tenant, cwd, "context:"),
|
|
20844
21044
|
hydratePrefix(backend, tenant, cwd, "memory:"),
|
|
@@ -20854,7 +21054,7 @@ var init_stateWorkspace = __esm({
|
|
|
20854
21054
|
"src/stateWorkspace.ts"() {
|
|
20855
21055
|
"use strict";
|
|
20856
21056
|
init_state_backend();
|
|
20857
|
-
RUNTIME_ROOT =
|
|
21057
|
+
RUNTIME_ROOT = path47.join(".kody-engine", "runtime");
|
|
20858
21058
|
hydratedWorkspaces = /* @__PURE__ */ new Set();
|
|
20859
21059
|
}
|
|
20860
21060
|
});
|
|
@@ -20925,9 +21125,9 @@ var init_tools = __esm({
|
|
|
20925
21125
|
|
|
20926
21126
|
// src/executor.ts
|
|
20927
21127
|
import { spawn as spawn8 } from "child_process";
|
|
20928
|
-
import * as
|
|
21128
|
+
import * as fs50 from "fs";
|
|
20929
21129
|
import * as os7 from "os";
|
|
20930
|
-
import * as
|
|
21130
|
+
import * as path48 from "path";
|
|
20931
21131
|
function isMutatingPostflight(scriptName) {
|
|
20932
21132
|
return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
|
|
20933
21133
|
}
|
|
@@ -21168,7 +21368,7 @@ async function runImplementation(profileName, input) {
|
|
|
21168
21368
|
const jobWhyBlock = typeof ctx.data.jobWhy === "string" ? operatorRequestBlock(ctx.data.jobWhy) : null;
|
|
21169
21369
|
const jobRefBlock = jobReferenceBlock(profileName, profile, ctx.data);
|
|
21170
21370
|
const invokeAgent = async (prompt) => {
|
|
21171
|
-
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) =>
|
|
21371
|
+
const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path48.isAbsolute(p) ? p : path48.resolve(profile.dir, p)).filter((p) => p.length > 0);
|
|
21172
21372
|
const syntheticPath = ctx.data.syntheticPluginPath;
|
|
21173
21373
|
const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
|
|
21174
21374
|
const agents = loadSubagents(profile);
|
|
@@ -21632,17 +21832,17 @@ function clearStampedLifecycleLabels(profile, ctx) {
|
|
|
21632
21832
|
function resolveProfilePath(profileName, cwd = process.cwd()) {
|
|
21633
21833
|
const found = resolveImplementation(profileName, getRuntimeProfileRootsForCwd(cwd));
|
|
21634
21834
|
if (found) return found;
|
|
21635
|
-
const here =
|
|
21835
|
+
const here = path48.dirname(new URL(import.meta.url).pathname);
|
|
21636
21836
|
const candidates = [
|
|
21637
|
-
|
|
21837
|
+
path48.join(here, "implementations", profileName, "profile.json"),
|
|
21638
21838
|
// same-dir sibling (dev)
|
|
21639
|
-
|
|
21839
|
+
path48.join(here, "..", "implementations", profileName, "profile.json"),
|
|
21640
21840
|
// up one (prod: dist/bin → dist/implementations)
|
|
21641
|
-
|
|
21841
|
+
path48.join(here, "..", "src", "implementations", profileName, "profile.json")
|
|
21642
21842
|
// fallback
|
|
21643
21843
|
];
|
|
21644
21844
|
for (const c of candidates) {
|
|
21645
|
-
if (
|
|
21845
|
+
if (fs50.existsSync(c)) return c;
|
|
21646
21846
|
}
|
|
21647
21847
|
return candidates[0];
|
|
21648
21848
|
}
|
|
@@ -21757,15 +21957,15 @@ function resolveShellTimeoutMs(entry) {
|
|
|
21757
21957
|
}
|
|
21758
21958
|
async function runShellEntry(entry, ctx, profile) {
|
|
21759
21959
|
const shellName = entry.shell;
|
|
21760
|
-
const shellPath =
|
|
21761
|
-
if (!
|
|
21960
|
+
const shellPath = path48.join(profile.dir, shellName);
|
|
21961
|
+
if (!fs50.existsSync(shellPath)) {
|
|
21762
21962
|
ctx.skipAgent = true;
|
|
21763
21963
|
ctx.output.exitCode = 99;
|
|
21764
21964
|
ctx.output.reason = `shell script not found: ${shellName} (looked in ${profile.dir})`;
|
|
21765
21965
|
return;
|
|
21766
21966
|
}
|
|
21767
21967
|
const positional = entry.with ? Object.values(entry.with).map((v) => String(v)) : [];
|
|
21768
|
-
const outputFile =
|
|
21968
|
+
const outputFile = path48.join(
|
|
21769
21969
|
os7.tmpdir(),
|
|
21770
21970
|
`kody-shell-output-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
|
21771
21971
|
);
|
|
@@ -21837,9 +22037,9 @@ async function runShellEntry(entry, ctx, profile) {
|
|
|
21837
22037
|
}
|
|
21838
22038
|
let sideChannelText = "";
|
|
21839
22039
|
try {
|
|
21840
|
-
if (
|
|
21841
|
-
sideChannelText =
|
|
21842
|
-
|
|
22040
|
+
if (fs50.existsSync(outputFile)) {
|
|
22041
|
+
sideChannelText = fs50.readFileSync(outputFile, "utf-8");
|
|
22042
|
+
fs50.rmSync(outputFile, { force: true });
|
|
21843
22043
|
}
|
|
21844
22044
|
} catch {
|
|
21845
22045
|
}
|
|
@@ -22011,7 +22211,7 @@ __export(job_exports, {
|
|
|
22011
22211
|
stableJobKey: () => stableJobKey,
|
|
22012
22212
|
validateJob: () => validateJob
|
|
22013
22213
|
});
|
|
22014
|
-
import * as
|
|
22214
|
+
import * as path49 from "path";
|
|
22015
22215
|
function newJobId(flavor) {
|
|
22016
22216
|
localJobSeq += 1;
|
|
22017
22217
|
const runId = process.env.GITHUB_RUN_ID;
|
|
@@ -22712,7 +22912,7 @@ function loadCapabilityContext(slug, cwd) {
|
|
|
22712
22912
|
return resolveCapabilityFolder(slug, hydratedCapabilitiesRoot(cwd));
|
|
22713
22913
|
}
|
|
22714
22914
|
function hydratedCapabilitiesRoot(cwd) {
|
|
22715
|
-
return
|
|
22915
|
+
return path49.join(cwd, ".kody-engine", "definitions", "capabilities");
|
|
22716
22916
|
}
|
|
22717
22917
|
function loadWorkflowContext(slug, base) {
|
|
22718
22918
|
if (!slug || !isWorkflowDefinitionId(slug)) return null;
|
|
@@ -24688,82 +24888,7 @@ function readRunRequestFromEnv(env = process.env) {
|
|
|
24688
24888
|
|
|
24689
24889
|
// src/kody-cli.ts
|
|
24690
24890
|
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
|
|
24891
|
+
init_loopDefinitions();
|
|
24767
24892
|
init_stateWorkspace();
|
|
24768
24893
|
init_workflowDefinitions();
|
|
24769
24894
|
var FAILED_DISPATCH_LABEL = {
|
|
@@ -26445,7 +26570,7 @@ init_config();
|
|
|
26445
26570
|
init_fetchRepoMcp();
|
|
26446
26571
|
|
|
26447
26572
|
// src/servers/mcpHttpServer.ts
|
|
26448
|
-
import { randomUUID as
|
|
26573
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
26449
26574
|
import { createServer as createServer4 } from "http";
|
|
26450
26575
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
26451
26576
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
@@ -26454,7 +26579,7 @@ function buildMcpHttpServer(opts) {
|
|
|
26454
26579
|
const transports = /* @__PURE__ */ new Map();
|
|
26455
26580
|
for (const route of opts.routes) {
|
|
26456
26581
|
const transport = new StreamableHTTPServerTransport({
|
|
26457
|
-
sessionIdGenerator: () =>
|
|
26582
|
+
sessionIdGenerator: () => randomUUID3()
|
|
26458
26583
|
});
|
|
26459
26584
|
transports.set(route.path, transport);
|
|
26460
26585
|
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.446",
|
|
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",
|