@kody-ade/kody-engine 0.4.274 → 0.4.276
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 +285 -53
- package/dist/executables/types.ts +1 -1
- package/package.json +1 -1
package/dist/bin/kody.js
CHANGED
|
@@ -15,7 +15,7 @@ var init_package = __esm({
|
|
|
15
15
|
"package.json"() {
|
|
16
16
|
package_default = {
|
|
17
17
|
name: "@kody-ade/kody-engine",
|
|
18
|
-
version: "0.4.
|
|
18
|
+
version: "0.4.276",
|
|
19
19
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
20
20
|
license: "MIT",
|
|
21
21
|
type: "module",
|
|
@@ -8808,7 +8808,7 @@ function refreshGoalDashboardReport(input) {
|
|
|
8808
8808
|
if (!REPORT_SLUG_RE.test(input.goalId)) {
|
|
8809
8809
|
throw new Error(`goal report: invalid goal id "${input.goalId}"`);
|
|
8810
8810
|
}
|
|
8811
|
-
const filePath =
|
|
8811
|
+
const filePath = goalDashboardReportRunPath(input.goalId);
|
|
8812
8812
|
const body = goalReportBody(
|
|
8813
8813
|
input.goalId,
|
|
8814
8814
|
input.state,
|
|
@@ -8816,17 +8816,15 @@ function refreshGoalDashboardReport(input) {
|
|
|
8816
8816
|
latestGoalRunLogEvent(input.data, input.goalId),
|
|
8817
8817
|
evidenceItems
|
|
8818
8818
|
);
|
|
8819
|
-
|
|
8820
|
-
if (current?.content === body) {
|
|
8821
|
-
const report2 = { slug: input.goalId, path: current.path, changed: false };
|
|
8822
|
-
recordGoalReport(input.data, report2);
|
|
8823
|
-
return report2;
|
|
8824
|
-
}
|
|
8825
|
-
upsertStateText(input.config, input.cwd, filePath, body, `chore(reports): refresh ${input.goalId}`);
|
|
8819
|
+
writeStateText(input.config, input.cwd, filePath, body, `chore(reports): add ${input.goalId} run`);
|
|
8826
8820
|
const report = { slug: input.goalId, path: filePath, changed: true };
|
|
8827
8821
|
recordGoalReport(input.data, report);
|
|
8828
8822
|
return report;
|
|
8829
8823
|
}
|
|
8824
|
+
function goalDashboardReportRunPath(goalId, now = /* @__PURE__ */ new Date()) {
|
|
8825
|
+
const runId = now.toISOString().replace(/\.\d{3}Z$/, "Z").replace(/:/g, "-");
|
|
8826
|
+
return `reports/${goalId}/runs/${runId}.md`;
|
|
8827
|
+
}
|
|
8830
8828
|
function capabilityEvidenceOutput(evidence) {
|
|
8831
8829
|
return {
|
|
8832
8830
|
kind: "capability-evidence",
|
|
@@ -19581,6 +19579,68 @@ init_job();
|
|
|
19581
19579
|
init_registry();
|
|
19582
19580
|
init_runtimePaths();
|
|
19583
19581
|
init_stateWorkspace();
|
|
19582
|
+
|
|
19583
|
+
// src/run-request.ts
|
|
19584
|
+
var RUN_REQUEST_ENV = "KODY_RUN_REQUEST_JSON";
|
|
19585
|
+
var INTENTS = /* @__PURE__ */ new Set(["continue", "manage", "run", "tick"]);
|
|
19586
|
+
var SOURCES = /* @__PURE__ */ new Set(["dashboard", "github", "schedule"]);
|
|
19587
|
+
var TARGET_TYPES = /* @__PURE__ */ new Set(["chat", "goal", "issue", "workflow"]);
|
|
19588
|
+
function isRecord(value) {
|
|
19589
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19590
|
+
}
|
|
19591
|
+
function readString(value) {
|
|
19592
|
+
return typeof value === "string" ? value.trim() : "";
|
|
19593
|
+
}
|
|
19594
|
+
function parseTarget(input) {
|
|
19595
|
+
if (!isRecord(input)) return { error: "runRequest.target must be an object" };
|
|
19596
|
+
const type = readString(input.type);
|
|
19597
|
+
if (!TARGET_TYPES.has(type)) return { error: "runRequest.target.type is invalid" };
|
|
19598
|
+
if (type === "issue") {
|
|
19599
|
+
const id2 = Number(input.id);
|
|
19600
|
+
if (!Number.isInteger(id2) || id2 <= 0) return { error: "runRequest.target.id must be a positive issue number" };
|
|
19601
|
+
return { target: { type, id: id2 } };
|
|
19602
|
+
}
|
|
19603
|
+
const id = readString(input.id);
|
|
19604
|
+
if (!id) return { error: "runRequest.target.id is required" };
|
|
19605
|
+
return { target: { type, id } };
|
|
19606
|
+
}
|
|
19607
|
+
function parseRunRequest(input) {
|
|
19608
|
+
let body = input;
|
|
19609
|
+
if (typeof input === "string") {
|
|
19610
|
+
const raw = input.trim();
|
|
19611
|
+
if (!raw) return { error: `${RUN_REQUEST_ENV} is empty` };
|
|
19612
|
+
try {
|
|
19613
|
+
body = JSON.parse(raw);
|
|
19614
|
+
} catch {
|
|
19615
|
+
return { error: `${RUN_REQUEST_ENV} must be valid JSON` };
|
|
19616
|
+
}
|
|
19617
|
+
}
|
|
19618
|
+
if (!isRecord(body)) return { error: "runRequest must be an object" };
|
|
19619
|
+
const parsedTarget = parseTarget(body.target);
|
|
19620
|
+
if ("error" in parsedTarget) return parsedTarget;
|
|
19621
|
+
const intent = readString(body.intent);
|
|
19622
|
+
if (!INTENTS.has(intent)) return { error: "runRequest.intent is invalid" };
|
|
19623
|
+
const source = readString(body.source);
|
|
19624
|
+
if (!SOURCES.has(source)) return { error: "runRequest.source is invalid" };
|
|
19625
|
+
if (body.input !== void 0 && !isRecord(body.input)) {
|
|
19626
|
+
return { error: "runRequest.input must be an object when provided" };
|
|
19627
|
+
}
|
|
19628
|
+
return {
|
|
19629
|
+
request: {
|
|
19630
|
+
target: parsedTarget.target,
|
|
19631
|
+
intent,
|
|
19632
|
+
source,
|
|
19633
|
+
...body.input !== void 0 ? { input: body.input } : {}
|
|
19634
|
+
}
|
|
19635
|
+
};
|
|
19636
|
+
}
|
|
19637
|
+
function readRunRequestFromEnv(env = process.env) {
|
|
19638
|
+
const raw = env[RUN_REQUEST_ENV];
|
|
19639
|
+
if (raw == null || raw.trim() === "") return null;
|
|
19640
|
+
return parseRunRequest(raw);
|
|
19641
|
+
}
|
|
19642
|
+
|
|
19643
|
+
// src/kody-cli.ts
|
|
19584
19644
|
var CI_HELP = `kody ci \u2014 minimal-YAML autonomous engineer (CI preflight + run)
|
|
19585
19645
|
|
|
19586
19646
|
Usage:
|
|
@@ -19639,6 +19699,30 @@ function parseCiArgs(argv) {
|
|
|
19639
19699
|
}
|
|
19640
19700
|
return result;
|
|
19641
19701
|
}
|
|
19702
|
+
function routeRunRequest(request) {
|
|
19703
|
+
const { target, intent } = request;
|
|
19704
|
+
if (target.type === "chat" || target.type === "issue") return { kind: "ignore" };
|
|
19705
|
+
if (target.type === "goal") {
|
|
19706
|
+
if (intent !== "manage" && intent !== "run" && intent !== "tick") {
|
|
19707
|
+
return { kind: "error", error: `goal target does not support intent '${intent}'` };
|
|
19708
|
+
}
|
|
19709
|
+
return {
|
|
19710
|
+
kind: "action",
|
|
19711
|
+
action: "goal-manager",
|
|
19712
|
+
cliArgs: { goal: target.id }
|
|
19713
|
+
};
|
|
19714
|
+
}
|
|
19715
|
+
if (target.type === "workflow") {
|
|
19716
|
+
if (target.id === "scheduled-fanout") {
|
|
19717
|
+
return { kind: "fanout", force: intent === "run" };
|
|
19718
|
+
}
|
|
19719
|
+
if (intent !== "run" && intent !== "tick") {
|
|
19720
|
+
return { kind: "error", error: `workflow target does not support intent '${intent}'` };
|
|
19721
|
+
}
|
|
19722
|
+
return { kind: "action", action: target.id, cliArgs: {} };
|
|
19723
|
+
}
|
|
19724
|
+
return { kind: "error", error: "unsupported run request target" };
|
|
19725
|
+
}
|
|
19642
19726
|
function unpackAllSecrets(env = process.env) {
|
|
19643
19727
|
const raw = env.ALL_SECRETS;
|
|
19644
19728
|
if (!raw) return 0;
|
|
@@ -19850,15 +19934,38 @@ async function runCi(argv) {
|
|
|
19850
19934
|
let manualWorkflowDispatch = false;
|
|
19851
19935
|
let forceRunAction = null;
|
|
19852
19936
|
let forceRunCliArgs = {};
|
|
19937
|
+
let runRequestFanOut = false;
|
|
19938
|
+
let runRequestFanOutForce = false;
|
|
19939
|
+
const parsedRunRequest = readRunRequestFromEnv();
|
|
19940
|
+
if (parsedRunRequest && "error" in parsedRunRequest) {
|
|
19941
|
+
process.stderr.write(`[kody] ${parsedRunRequest.error}
|
|
19942
|
+
`);
|
|
19943
|
+
return 64;
|
|
19944
|
+
}
|
|
19945
|
+
if (!args.issueNumber && !autoFallback && parsedRunRequest && "request" in parsedRunRequest) {
|
|
19946
|
+
const route = routeRunRequest(parsedRunRequest.request);
|
|
19947
|
+
if (route.kind === "error") {
|
|
19948
|
+
process.stderr.write(`[kody] ${route.error}
|
|
19949
|
+
`);
|
|
19950
|
+
return 64;
|
|
19951
|
+
}
|
|
19952
|
+
if (route.kind === "fanout") {
|
|
19953
|
+
runRequestFanOut = true;
|
|
19954
|
+
runRequestFanOutForce = route.force;
|
|
19955
|
+
} else if (route.kind === "action") {
|
|
19956
|
+
forceRunAction = route.action;
|
|
19957
|
+
forceRunCliArgs = route.cliArgs;
|
|
19958
|
+
}
|
|
19959
|
+
}
|
|
19853
19960
|
const envForceAction = (process.env.KODY_FORCE_ACTION ?? "").trim();
|
|
19854
19961
|
const envForceMessage = (process.env.KODY_FORCE_MESSAGE ?? "").trim();
|
|
19855
|
-
if (!args.issueNumber && !autoFallback && envForceAction) {
|
|
19962
|
+
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && envForceAction) {
|
|
19856
19963
|
forceRunAction = envForceAction;
|
|
19857
19964
|
if (envForceAction === "goal-manager" && envForceMessage) {
|
|
19858
19965
|
forceRunCliArgs = { goal: envForceMessage };
|
|
19859
19966
|
}
|
|
19860
19967
|
}
|
|
19861
|
-
if (!args.issueNumber && !autoFallback && !forceRunAction && eventName === "workflow_dispatch" && dispatchEventPath && fs46.existsSync(dispatchEventPath)) {
|
|
19968
|
+
if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath && fs46.existsSync(dispatchEventPath)) {
|
|
19862
19969
|
try {
|
|
19863
19970
|
const evt = JSON.parse(fs46.readFileSync(dispatchEventPath, "utf-8"));
|
|
19864
19971
|
const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
|
|
@@ -19950,6 +20057,9 @@ async function runCi(argv) {
|
|
|
19950
20057
|
const ec = result.exitCode;
|
|
19951
20058
|
return ec === 0 || ec === 1 || ec === 2 ? ec : 99;
|
|
19952
20059
|
}
|
|
20060
|
+
if (!args.issueNumber && !autoFallback && runRequestFanOut) {
|
|
20061
|
+
return runScheduledFanOut(cwd, args, { force: runRequestFanOutForce });
|
|
20062
|
+
}
|
|
19953
20063
|
if (!args.issueNumber && !autoFallback && (eventName === "schedule" || manualWorkflowDispatch)) {
|
|
19954
20064
|
return runScheduledFanOut(cwd, args, { force: manualWorkflowDispatch });
|
|
19955
20065
|
}
|
|
@@ -21573,6 +21683,10 @@ function parseChatArgs(argv, env = process.env) {
|
|
|
21573
21683
|
else if (arg?.startsWith("--")) result.errors.push(`unknown arg: ${arg}`);
|
|
21574
21684
|
else if (arg) result.errors.push(`unexpected positional: ${arg}`);
|
|
21575
21685
|
}
|
|
21686
|
+
const runRequest = readRunRequestFromEnv(env);
|
|
21687
|
+
if (runRequest && "error" in runRequest) result.errors.push(runRequest.error);
|
|
21688
|
+
const chatTarget = runRequest && "request" in runRequest && runRequest.request.target.type === "chat" ? runRequest.request.target.id : void 0;
|
|
21689
|
+
result.sessionId = result.sessionId ?? chatTarget;
|
|
21576
21690
|
result.sessionId = result.sessionId ?? env.SESSION_ID ?? void 0;
|
|
21577
21691
|
result.initMessage = result.initMessage ?? env.INIT_MESSAGE ?? void 0;
|
|
21578
21692
|
result.model = result.model ?? env.MODEL ?? void 0;
|
|
@@ -21766,7 +21880,11 @@ async function runCapabilityFallbackTick(deps) {
|
|
|
21766
21880
|
const res = await deps.claim(owner, repo, {
|
|
21767
21881
|
jobId: `sched-${owner}-${repo}-${clock()}`,
|
|
21768
21882
|
repo: tag,
|
|
21769
|
-
|
|
21883
|
+
runRequest: {
|
|
21884
|
+
target: { type: "workflow", id: "scheduled-fanout" },
|
|
21885
|
+
intent: "tick",
|
|
21886
|
+
source: "schedule"
|
|
21887
|
+
}
|
|
21770
21888
|
});
|
|
21771
21889
|
if (res.ok) {
|
|
21772
21890
|
claimed++;
|
|
@@ -22341,7 +22459,7 @@ var PoolRegistry = class {
|
|
|
22341
22459
|
jobId: req.jobId,
|
|
22342
22460
|
repo: `${owner}/${repo}`,
|
|
22343
22461
|
githubToken: this.cfg.githubToken,
|
|
22344
|
-
|
|
22462
|
+
runRequest: req.runRequest,
|
|
22345
22463
|
issueNumber: req.issueNumber,
|
|
22346
22464
|
sessionId: req.sessionId,
|
|
22347
22465
|
idleExitMs: req.idleExitMs,
|
|
@@ -22427,24 +22545,78 @@ function parseClaimRequest(body) {
|
|
|
22427
22545
|
const repo = typeof b.repo === "string" ? b.repo.trim() : "";
|
|
22428
22546
|
if (!/^[^/\s]+\/[^/\s]+$/.test(repo)) return { error: "repo must be 'owner/name'" };
|
|
22429
22547
|
const mode = b.mode === "interactive" ? "interactive" : b.mode === "scheduled" ? "scheduled" : "issue";
|
|
22430
|
-
const
|
|
22431
|
-
|
|
22432
|
-
|
|
22433
|
-
|
|
22434
|
-
|
|
22435
|
-
|
|
22436
|
-
|
|
22437
|
-
|
|
22438
|
-
|
|
22548
|
+
const action = typeof b.action === "string" && b.action.trim() ? b.action.trim() : void 0;
|
|
22549
|
+
const message = typeof b.message === "string" && b.message.trim() ? b.message.trim() : void 0;
|
|
22550
|
+
const runRequest = b.runRequest !== void 0 ? parseRunRequest(b.runRequest) : synthesizeLegacyClaimRequest({
|
|
22551
|
+
mode,
|
|
22552
|
+
issueNumber: b.issueNumber,
|
|
22553
|
+
sessionId: b.sessionId,
|
|
22554
|
+
action,
|
|
22555
|
+
message
|
|
22556
|
+
});
|
|
22557
|
+
if ("error" in runRequest) return { error: runRequest.error };
|
|
22558
|
+
const req = { jobId, repo, runRequest: runRequest.request };
|
|
22559
|
+
if (req.runRequest.target.type === "issue") {
|
|
22560
|
+
req.issueNumber = req.runRequest.target.id;
|
|
22561
|
+
} else if (req.runRequest.target.type === "chat") {
|
|
22562
|
+
req.sessionId = req.runRequest.target.id;
|
|
22439
22563
|
if (Number.isFinite(Number(b.idleExitMs))) req.idleExitMs = Number(b.idleExitMs);
|
|
22440
22564
|
if (Number.isFinite(Number(b.hardCapMs))) req.hardCapMs = Number(b.hardCapMs);
|
|
22441
22565
|
}
|
|
22442
22566
|
if (typeof b.ref === "string" && b.ref.trim()) req.ref = b.ref.trim();
|
|
22443
22567
|
if (typeof b.model === "string" && b.model.trim()) req.model = b.model.trim();
|
|
22444
|
-
if (typeof b.sessionId === "string" && b.sessionId.trim()) req.sessionId = b.sessionId.trim();
|
|
22445
22568
|
if (typeof b.dashboardUrl === "string" && b.dashboardUrl.trim()) req.dashboardUrl = b.dashboardUrl.trim();
|
|
22446
22569
|
return { req };
|
|
22447
22570
|
}
|
|
22571
|
+
function synthesizeLegacyClaimRequest(input) {
|
|
22572
|
+
if (input.mode === "issue") {
|
|
22573
|
+
const issueNumber = Number(input.issueNumber);
|
|
22574
|
+
if (!Number.isInteger(issueNumber) || issueNumber <= 0) return { error: "issueNumber required for issue mode" };
|
|
22575
|
+
return {
|
|
22576
|
+
request: {
|
|
22577
|
+
target: { type: "issue", id: issueNumber },
|
|
22578
|
+
intent: "run",
|
|
22579
|
+
source: "dashboard"
|
|
22580
|
+
}
|
|
22581
|
+
};
|
|
22582
|
+
}
|
|
22583
|
+
if (input.mode === "interactive") {
|
|
22584
|
+
const sessionId = typeof input.sessionId === "string" ? input.sessionId.trim() : "";
|
|
22585
|
+
if (!sessionId) return { error: "sessionId required for interactive mode" };
|
|
22586
|
+
return {
|
|
22587
|
+
request: {
|
|
22588
|
+
target: { type: "chat", id: sessionId },
|
|
22589
|
+
intent: "continue",
|
|
22590
|
+
source: "dashboard"
|
|
22591
|
+
}
|
|
22592
|
+
};
|
|
22593
|
+
}
|
|
22594
|
+
if (input.action === "goal-manager" && input.message) {
|
|
22595
|
+
return {
|
|
22596
|
+
request: {
|
|
22597
|
+
target: { type: "goal", id: input.message },
|
|
22598
|
+
intent: "manage",
|
|
22599
|
+
source: "dashboard"
|
|
22600
|
+
}
|
|
22601
|
+
};
|
|
22602
|
+
}
|
|
22603
|
+
if (input.action) {
|
|
22604
|
+
return {
|
|
22605
|
+
request: {
|
|
22606
|
+
target: { type: "workflow", id: input.action },
|
|
22607
|
+
intent: "run",
|
|
22608
|
+
source: "dashboard"
|
|
22609
|
+
}
|
|
22610
|
+
};
|
|
22611
|
+
}
|
|
22612
|
+
return {
|
|
22613
|
+
request: {
|
|
22614
|
+
target: { type: "workflow", id: "scheduled-fanout" },
|
|
22615
|
+
intent: "tick",
|
|
22616
|
+
source: "schedule"
|
|
22617
|
+
}
|
|
22618
|
+
};
|
|
22619
|
+
}
|
|
22448
22620
|
async function poolServe() {
|
|
22449
22621
|
const masterRaw = process.env.KODY_MASTER_KEY?.trim();
|
|
22450
22622
|
if (!masterRaw) throw new Error("KODY_MASTER_KEY required for pool-serve");
|
|
@@ -22612,33 +22784,85 @@ function parseJob(body) {
|
|
|
22612
22784
|
if (!/^[^/\s]+\/[^/\s]+$/.test(repo)) return { error: "repo must be 'owner/name'" };
|
|
22613
22785
|
const githubToken = typeof b.githubToken === "string" ? b.githubToken.trim() : "";
|
|
22614
22786
|
if (!githubToken) return { error: "githubToken required" };
|
|
22787
|
+
const action = typeof b.action === "string" && b.action.trim() ? b.action.trim() : void 0;
|
|
22788
|
+
const message = typeof b.message === "string" && b.message.trim() ? b.message.trim() : void 0;
|
|
22615
22789
|
const mode = b.mode === "interactive" ? "interactive" : b.mode === "scheduled" ? "scheduled" : "issue";
|
|
22616
|
-
const
|
|
22617
|
-
|
|
22618
|
-
|
|
22619
|
-
|
|
22620
|
-
|
|
22621
|
-
|
|
22622
|
-
|
|
22623
|
-
|
|
22624
|
-
|
|
22625
|
-
|
|
22626
|
-
job.
|
|
22790
|
+
const runRequest = b.runRequest !== void 0 ? parseRunRequest(b.runRequest) : synthesizeLegacyRunRequest({
|
|
22791
|
+
mode,
|
|
22792
|
+
issueNumber: b.issueNumber,
|
|
22793
|
+
sessionId: b.sessionId,
|
|
22794
|
+
action,
|
|
22795
|
+
message
|
|
22796
|
+
});
|
|
22797
|
+
if ("error" in runRequest) return { error: runRequest.error };
|
|
22798
|
+
const job = { jobId, repo, githubToken, runRequest: runRequest.request };
|
|
22799
|
+
if (job.runRequest.target.type === "issue") {
|
|
22800
|
+
job.issueNumber = job.runRequest.target.id;
|
|
22801
|
+
} else if (job.runRequest.target.type === "chat") {
|
|
22802
|
+
job.sessionId = job.runRequest.target.id;
|
|
22627
22803
|
if (Number.isFinite(Number(b.idleExitMs))) job.idleExitMs = Number(b.idleExitMs);
|
|
22628
22804
|
if (Number.isFinite(Number(b.hardCapMs))) job.hardCapMs = Number(b.hardCapMs);
|
|
22629
22805
|
}
|
|
22630
22806
|
if (typeof b.ref === "string" && b.ref.trim()) job.ref = b.ref.trim();
|
|
22631
22807
|
if (typeof b.model === "string" && b.model.trim()) job.model = b.model.trim();
|
|
22632
22808
|
if (typeof b.reasoningEffort === "string" && b.reasoningEffort.trim()) job.reasoningEffort = b.reasoningEffort.trim();
|
|
22633
|
-
if (typeof b.action === "string" && b.action.trim()) job.action = b.action.trim();
|
|
22634
|
-
if (typeof b.message === "string" && b.message.trim()) job.message = b.message.trim();
|
|
22635
|
-
if (typeof b.sessionId === "string" && b.sessionId.trim()) job.sessionId = b.sessionId.trim();
|
|
22636
22809
|
if (typeof b.dashboardUrl === "string" && b.dashboardUrl.trim()) job.dashboardUrl = b.dashboardUrl.trim();
|
|
22637
22810
|
if (b.allSecrets && (typeof b.allSecrets === "object" || typeof b.allSecrets === "string")) {
|
|
22638
22811
|
job.allSecrets = b.allSecrets;
|
|
22639
22812
|
}
|
|
22640
22813
|
return { job };
|
|
22641
22814
|
}
|
|
22815
|
+
function synthesizeLegacyRunRequest(input) {
|
|
22816
|
+
if (input.mode === "issue") {
|
|
22817
|
+
const issueNumber = Number(input.issueNumber);
|
|
22818
|
+
if (!Number.isInteger(issueNumber) || issueNumber <= 0) {
|
|
22819
|
+
return { error: "issueNumber (positive integer) required for issue mode" };
|
|
22820
|
+
}
|
|
22821
|
+
return {
|
|
22822
|
+
request: {
|
|
22823
|
+
target: { type: "issue", id: issueNumber },
|
|
22824
|
+
intent: "run",
|
|
22825
|
+
source: "dashboard"
|
|
22826
|
+
}
|
|
22827
|
+
};
|
|
22828
|
+
}
|
|
22829
|
+
if (input.mode === "interactive") {
|
|
22830
|
+
const sessionId = typeof input.sessionId === "string" ? input.sessionId.trim() : "";
|
|
22831
|
+
if (!sessionId) return { error: "sessionId required for interactive mode" };
|
|
22832
|
+
return {
|
|
22833
|
+
request: {
|
|
22834
|
+
target: { type: "chat", id: sessionId },
|
|
22835
|
+
intent: "continue",
|
|
22836
|
+
source: "dashboard"
|
|
22837
|
+
}
|
|
22838
|
+
};
|
|
22839
|
+
}
|
|
22840
|
+
if (input.action === "goal-manager" && input.message) {
|
|
22841
|
+
return {
|
|
22842
|
+
request: {
|
|
22843
|
+
target: { type: "goal", id: input.message },
|
|
22844
|
+
intent: "manage",
|
|
22845
|
+
source: "dashboard"
|
|
22846
|
+
}
|
|
22847
|
+
};
|
|
22848
|
+
}
|
|
22849
|
+
if (input.action) {
|
|
22850
|
+
return {
|
|
22851
|
+
request: {
|
|
22852
|
+
target: { type: "workflow", id: input.action },
|
|
22853
|
+
intent: "run",
|
|
22854
|
+
source: "dashboard"
|
|
22855
|
+
}
|
|
22856
|
+
};
|
|
22857
|
+
}
|
|
22858
|
+
return {
|
|
22859
|
+
request: {
|
|
22860
|
+
target: { type: "workflow", id: "scheduled-fanout" },
|
|
22861
|
+
intent: "tick",
|
|
22862
|
+
source: "schedule"
|
|
22863
|
+
}
|
|
22864
|
+
};
|
|
22865
|
+
}
|
|
22642
22866
|
async function defaultRunJob(job) {
|
|
22643
22867
|
const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
|
|
22644
22868
|
const branch = job.ref ?? "main";
|
|
@@ -22646,20 +22870,17 @@ async function defaultRunJob(job) {
|
|
|
22646
22870
|
fs51.rmSync(workdir, { recursive: true, force: true });
|
|
22647
22871
|
fs51.mkdirSync(workdir, { recursive: true });
|
|
22648
22872
|
const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
|
|
22649
|
-
const
|
|
22650
|
-
const
|
|
22651
|
-
const
|
|
22873
|
+
const target = job.runRequest.target;
|
|
22874
|
+
const interactive = target.type === "chat";
|
|
22875
|
+
const scheduled = target.type === "goal" || target.type === "workflow";
|
|
22876
|
+
const issueNumber = target.type === "issue" ? target.id : void 0;
|
|
22877
|
+
const sessionId = target.type === "chat" ? target.id : void 0;
|
|
22652
22878
|
const childEnv = {
|
|
22653
22879
|
...process.env,
|
|
22654
22880
|
REPO: job.repo,
|
|
22655
22881
|
REF: branch,
|
|
22656
22882
|
GITHUB_TOKEN: job.githubToken,
|
|
22657
|
-
|
|
22658
|
-
// Scheduled mode drives the engine down the same path GitHub Actions' cron
|
|
22659
|
-
// takes (runScheduledFanOut → due capabilities/goals). Bare `kody` routes on this.
|
|
22660
|
-
...scheduled ? { GITHUB_EVENT_NAME: "schedule" } : {},
|
|
22661
|
-
...job.action ? { KODY_FORCE_ACTION: job.action } : {},
|
|
22662
|
-
...job.message ? { KODY_FORCE_MESSAGE: job.message } : {},
|
|
22883
|
+
[RUN_REQUEST_ENV]: JSON.stringify(job.runRequest),
|
|
22663
22884
|
// GITHUB_REPOSITORY + GH_TOKEN are normally injected by GitHub Actions.
|
|
22664
22885
|
// The engine's interactive mode needs GITHUB_REPOSITORY to resolve the
|
|
22665
22886
|
// configured state repo and persist chat.ready / events (the durable signal
|
|
@@ -22667,11 +22888,9 @@ async function defaultRunJob(job) {
|
|
|
22667
22888
|
// and the session never appears "ready". GH_TOKEN auths the `gh` CLI.
|
|
22668
22889
|
GITHUB_REPOSITORY: job.repo,
|
|
22669
22890
|
GH_TOKEN: job.githubToken,
|
|
22670
|
-
|
|
22671
|
-
// sets SESSION_ID so the engine boots a chat session.
|
|
22672
|
-
ISSUE_NUMBER: interactive || scheduled ? "" : String(job.issueNumber),
|
|
22891
|
+
ISSUE_NUMBER: issueNumber ? String(issueNumber) : "",
|
|
22673
22892
|
ALL_SECRETS: allSecrets,
|
|
22674
|
-
SESSION_ID:
|
|
22893
|
+
SESSION_ID: sessionId ?? "",
|
|
22675
22894
|
DASHBOARD_URL: job.dashboardUrl ?? "",
|
|
22676
22895
|
MODEL: job.model ?? "",
|
|
22677
22896
|
REASONING_EFFORT: job.reasoningEffort ?? "",
|
|
@@ -22700,7 +22919,7 @@ async function defaultRunJob(job) {
|
|
|
22700
22919
|
const authorEmail = process.env.GIT_AUTHOR_EMAIL ?? "kody-bot@users.noreply.github.com";
|
|
22701
22920
|
await run("git", ["config", "user.name", authorName], workdir);
|
|
22702
22921
|
await run("git", ["config", "user.email", authorEmail], workdir);
|
|
22703
|
-
const jobDesc = interactive ? `
|
|
22922
|
+
const jobDesc = interactive ? `chat session ${sessionId}` : scheduled ? `${target.type} ${target.id}` : `issue #${issueNumber}`;
|
|
22704
22923
|
process.stdout.write(`[runner-serve] job ${job.jobId}: ${jobDesc}
|
|
22705
22924
|
`);
|
|
22706
22925
|
const runCode = await run("kody", [], workdir);
|
|
@@ -22783,7 +23002,7 @@ async function runnerServe() {
|
|
|
22783
23002
|
init_config();
|
|
22784
23003
|
init_litellm();
|
|
22785
23004
|
import { spawn as spawn9 } from "child_process";
|
|
22786
|
-
function
|
|
23005
|
+
function parseTarget2(positional) {
|
|
22787
23006
|
if (!Array.isArray(positional) || positional.length === 0) return "none";
|
|
22788
23007
|
const first = String(positional[0]).toLowerCase();
|
|
22789
23008
|
if (first === "vscode" || first === "code") return "vscode";
|
|
@@ -22798,7 +23017,7 @@ function buildProxyEnv(url) {
|
|
|
22798
23017
|
};
|
|
22799
23018
|
}
|
|
22800
23019
|
async function serve(opts) {
|
|
22801
|
-
const target =
|
|
23020
|
+
const target = parseTarget2(opts.args);
|
|
22802
23021
|
const model = parseProviderModel(opts.config.agent.model);
|
|
22803
23022
|
const usesProxy = needsLitellmProxy(model);
|
|
22804
23023
|
let handle = null;
|
|
@@ -23112,6 +23331,17 @@ function envRunMode(env = process.env) {
|
|
|
23112
23331
|
}
|
|
23113
23332
|
return { ...result, errors: [`unknown KODY_RUN_MODE: ${mode}`] };
|
|
23114
23333
|
}
|
|
23334
|
+
function envRunRequest(env = process.env) {
|
|
23335
|
+
const result = { command: "help", errors: [] };
|
|
23336
|
+
const parsed = readRunRequestFromEnv(env);
|
|
23337
|
+
if (!parsed) return null;
|
|
23338
|
+
if ("error" in parsed) return { ...result, errors: [parsed.error] };
|
|
23339
|
+
const { target } = parsed.request;
|
|
23340
|
+
if (target.type === "chat") return { ...result, command: "chat", chatArgv: [] };
|
|
23341
|
+
if (target.type === "issue") return { ...result, command: "ci", ciArgv: ["--issue", String(target.id)] };
|
|
23342
|
+
if (target.type === "goal" || target.type === "workflow") return { ...result, command: "ci", ciArgv: [] };
|
|
23343
|
+
return { ...result, errors: [`unsupported runRequest target: ${target.type ?? "unknown"}`] };
|
|
23344
|
+
}
|
|
23115
23345
|
var HELP_TEXT = `kody-engine \u2014 single-session autonomous engineer
|
|
23116
23346
|
|
|
23117
23347
|
Usage:
|
|
@@ -23148,6 +23378,8 @@ Exit codes:
|
|
|
23148
23378
|
function parseArgs(argv) {
|
|
23149
23379
|
const result = { command: "help", errors: [] };
|
|
23150
23380
|
if (argv.length === 0) {
|
|
23381
|
+
const runRequest = envRunRequest();
|
|
23382
|
+
if (runRequest) return runRequest;
|
|
23151
23383
|
const mode = envRunMode();
|
|
23152
23384
|
if (mode) return mode;
|
|
23153
23385
|
if (process.env.SESSION_ID) return { ...result, command: "chat", chatArgv: [] };
|
|
@@ -498,6 +498,6 @@ export interface Job {
|
|
|
498
498
|
flavor: JobFlavor
|
|
499
499
|
/** Manual force-run (bypass cadence) for a scheduled job. */
|
|
500
500
|
force?: boolean
|
|
501
|
-
/** Ask the owning goal/loop to
|
|
501
|
+
/** Ask the owning goal/loop to write a report run after its persisted decision. */
|
|
502
502
|
saveReport?: boolean
|
|
503
503
|
}
|
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.276",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|