@kody-ade/kody-engine 0.4.158 → 0.4.160
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 +49 -37
- package/dist/executables/types.ts +8 -0
- package/package.json +1 -1
package/dist/bin/kody.js
CHANGED
|
@@ -1061,7 +1061,7 @@ var init_loadPriorArt = __esm({
|
|
|
1061
1061
|
// package.json
|
|
1062
1062
|
var package_default = {
|
|
1063
1063
|
name: "@kody-ade/kody-engine",
|
|
1064
|
-
version: "0.4.
|
|
1064
|
+
version: "0.4.160",
|
|
1065
1065
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
1066
1066
|
license: "MIT",
|
|
1067
1067
|
type: "module",
|
|
@@ -2177,33 +2177,28 @@ function attachmentsDir(cwd, sessionId) {
|
|
|
2177
2177
|
return path10.join(cwd, ".kody", "tmp", "attachments", sessionId);
|
|
2178
2178
|
}
|
|
2179
2179
|
function prepareAttachments(turns, cwd, sessionId) {
|
|
2180
|
-
const lastUserIdx = (() => {
|
|
2181
|
-
for (let i = turns.length - 1; i >= 0; i--) {
|
|
2182
|
-
if (turns[i].role === "user") return i;
|
|
2183
|
-
}
|
|
2184
|
-
return -1;
|
|
2185
|
-
})();
|
|
2186
2180
|
const imagePaths = [];
|
|
2187
2181
|
let imageCounter = 0;
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2182
|
+
let dirEnsured = false;
|
|
2183
|
+
const dir = attachmentsDir(cwd, sessionId);
|
|
2184
|
+
const rewritten = turns.map((turn) => {
|
|
2185
|
+
if (turn.role !== "user" || !turn.content.includes("base64,")) return turn;
|
|
2191
2186
|
const newContent = turn.content.replace(
|
|
2192
2187
|
INLINE_ATTACHMENT_RE,
|
|
2193
2188
|
(_match, label, mime, data) => {
|
|
2194
2189
|
const name = (label ?? "").trim() || "attachment";
|
|
2195
2190
|
const isImage = mime.toLowerCase().startsWith("image/");
|
|
2196
|
-
if (!
|
|
2197
|
-
return `[${isImage ? "Image" : "File"}: ${name}${isLastUser ? "" : " \u2014 omitted from history"}]`;
|
|
2198
|
-
}
|
|
2191
|
+
if (!isImage) return `[File: ${name}]`;
|
|
2199
2192
|
try {
|
|
2200
|
-
|
|
2201
|
-
|
|
2193
|
+
if (!dirEnsured) {
|
|
2194
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
2195
|
+
dirEnsured = true;
|
|
2196
|
+
}
|
|
2202
2197
|
const filePath = path10.join(dir, `${imageCounter}.${extFor(mime)}`);
|
|
2203
2198
|
fs10.writeFileSync(filePath, Buffer.from(data, "base64"));
|
|
2204
2199
|
imageCounter += 1;
|
|
2205
2200
|
imagePaths.push(filePath);
|
|
2206
|
-
return `[Image "${name}" is attached \u2014 saved to ${filePath}. Use the Read tool on that exact path to view it
|
|
2201
|
+
return `[Image "${name}" is attached \u2014 saved to ${filePath}. Use the Read tool on that exact path to view it.]`;
|
|
2207
2202
|
} catch {
|
|
2208
2203
|
return `[Image: ${name} (could not be materialised)]`;
|
|
2209
2204
|
}
|
|
@@ -6936,17 +6931,14 @@ var dispatchClassified = async (ctx) => {
|
|
|
6936
6931
|
if (!classification || !VALID_CLASSES2.has(classification)) return;
|
|
6937
6932
|
const action = ctx.data.action;
|
|
6938
6933
|
if (!action) return;
|
|
6939
|
-
const
|
|
6940
|
-
const dispatchLine = `@kody ${classification}${baseArg}`;
|
|
6934
|
+
const base = typeof ctx.args.base === "string" && ctx.args.base.length > 0 ? ctx.args.base : void 0;
|
|
6941
6935
|
const auditLine = ctx.data.classificationAudit ?? `\u{1F50E} kody classified as \`${classification}\``;
|
|
6942
6936
|
const state = ctx.data.taskState ?? emptyState();
|
|
6943
6937
|
const nextState = reduce(state, "classify", action, void 0);
|
|
6944
6938
|
const stateBody = renderStateComment(nextState);
|
|
6945
6939
|
ctx.data.taskState = nextState;
|
|
6946
6940
|
ctx.data.taskStateRendered = stateBody;
|
|
6947
|
-
const body = `${
|
|
6948
|
-
|
|
6949
|
-
${auditLine}
|
|
6941
|
+
const body = `${auditLine}
|
|
6950
6942
|
|
|
6951
6943
|
${stateBody}`;
|
|
6952
6944
|
try {
|
|
@@ -6957,17 +6949,16 @@ ${stateBody}`;
|
|
|
6957
6949
|
});
|
|
6958
6950
|
} catch (err) {
|
|
6959
6951
|
process.stderr.write(
|
|
6960
|
-
`[kody dispatchClassified] failed to
|
|
6952
|
+
`[kody dispatchClassified] failed to post state comment for #${issueNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
6961
6953
|
`
|
|
6962
6954
|
);
|
|
6963
|
-
ctx.data.action = failedAction3("dispatch post failed");
|
|
6964
|
-
ctx.output.exitCode = 1;
|
|
6965
|
-
ctx.output.reason = "classify: dispatch failed";
|
|
6966
6955
|
}
|
|
6956
|
+
const cliArgs = { issue: issueNumber };
|
|
6957
|
+
if (base && getProfileInputs(classification)?.some((i) => i.name === "base")) {
|
|
6958
|
+
cliArgs.base = base;
|
|
6959
|
+
}
|
|
6960
|
+
ctx.output.nextDispatch = { executable: classification, cliArgs };
|
|
6967
6961
|
};
|
|
6968
|
-
function failedAction3(reason) {
|
|
6969
|
-
return { type: "CLASSIFY_FAILED", payload: { reason }, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
6970
|
-
}
|
|
6971
6962
|
|
|
6972
6963
|
// src/scripts/dispatchJobFileTicks.ts
|
|
6973
6964
|
import * as fs29 from "fs";
|
|
@@ -9577,7 +9568,7 @@ function qaAction2(verdict, payload) {
|
|
|
9577
9568
|
const type = verdict === "PASS" ? "QA_PASS" : verdict === "CONCERNS" ? "QA_CONCERNS" : verdict === "FAIL" ? "QA_FAIL" : "QA_COMPLETED";
|
|
9578
9569
|
return { type, payload: { verdict, ...payload }, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
9579
9570
|
}
|
|
9580
|
-
function
|
|
9571
|
+
function failedAction3(reason) {
|
|
9581
9572
|
return { type: "QA_FAILED", payload: { reason }, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
9582
9573
|
}
|
|
9583
9574
|
function slugifyScope(scope) {
|
|
@@ -9613,7 +9604,7 @@ var openQaIssue = async (ctx, _profile, agentResult) => {
|
|
|
9613
9604
|
`);
|
|
9614
9605
|
ctx.output.exitCode = 1;
|
|
9615
9606
|
ctx.output.reason = reason;
|
|
9616
|
-
ctx.data.action =
|
|
9607
|
+
ctx.data.action = failedAction3(reason);
|
|
9617
9608
|
return;
|
|
9618
9609
|
}
|
|
9619
9610
|
const reportBody = agentResult.finalText.trim();
|
|
@@ -9621,7 +9612,7 @@ var openQaIssue = async (ctx, _profile, agentResult) => {
|
|
|
9621
9612
|
process.stderr.write("qa-engineer: agent produced no report body\n");
|
|
9622
9613
|
ctx.output.exitCode = 1;
|
|
9623
9614
|
ctx.output.reason = "empty report body";
|
|
9624
|
-
ctx.data.action =
|
|
9615
|
+
ctx.data.action = failedAction3("empty report body");
|
|
9625
9616
|
return;
|
|
9626
9617
|
}
|
|
9627
9618
|
const verdict = detectVerdict(reportBody);
|
|
@@ -9635,7 +9626,7 @@ var openQaIssue = async (ctx, _profile, agentResult) => {
|
|
|
9635
9626
|
const msg = err instanceof Error ? err.message : String(err);
|
|
9636
9627
|
ctx.output.exitCode = 4;
|
|
9637
9628
|
ctx.output.reason = `failed to comment on issue #${existingIssue}: ${msg}`;
|
|
9638
|
-
ctx.data.action =
|
|
9629
|
+
ctx.data.action = failedAction3(ctx.output.reason);
|
|
9639
9630
|
return;
|
|
9640
9631
|
}
|
|
9641
9632
|
process.stdout.write(
|
|
@@ -9657,7 +9648,7 @@ QA_REPORT_POSTED=https://github.com/${ctx.config.github.owner}/${ctx.config.gith
|
|
|
9657
9648
|
const msg = err instanceof Error ? err.message : String(err);
|
|
9658
9649
|
ctx.output.exitCode = 4;
|
|
9659
9650
|
ctx.output.reason = `failed to open QA issue: ${truncate2(msg, 1e3)}`;
|
|
9660
|
-
ctx.data.action =
|
|
9651
|
+
ctx.data.action = failedAction3(ctx.output.reason);
|
|
9661
9652
|
return;
|
|
9662
9653
|
}
|
|
9663
9654
|
process.stdout.write(`
|
|
@@ -10969,7 +10960,7 @@ var recordClassification = async (ctx) => {
|
|
|
10969
10960
|
reason = parsed?.reason ?? null;
|
|
10970
10961
|
}
|
|
10971
10962
|
if (!classification) {
|
|
10972
|
-
ctx.data.action =
|
|
10963
|
+
ctx.data.action = failedAction4("classification missing or invalid");
|
|
10973
10964
|
tryAuditComment(
|
|
10974
10965
|
issueNumber,
|
|
10975
10966
|
"\u26A0\uFE0F kody classifier could not decide \u2014 please re-run with an explicit `@kody <type>`.",
|
|
@@ -11010,7 +11001,7 @@ function tryAuditComment(issueNumber, body, cwd) {
|
|
|
11010
11001
|
function makeAction3(type, payload) {
|
|
11011
11002
|
return { type, payload, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
11012
11003
|
}
|
|
11013
|
-
function
|
|
11004
|
+
function failedAction4(reason) {
|
|
11014
11005
|
return { type: "CLASSIFY_FAILED", payload: { reason }, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
11015
11006
|
}
|
|
11016
11007
|
|
|
@@ -13490,7 +13481,8 @@ async function runExecutable(profileName, input) {
|
|
|
13490
13481
|
return finishAndEnd({
|
|
13491
13482
|
exitCode: ctx.output.exitCode ?? 0,
|
|
13492
13483
|
prUrl: ctx.output.prUrl,
|
|
13493
|
-
reason: ctx.output.reason
|
|
13484
|
+
reason: ctx.output.reason,
|
|
13485
|
+
nextDispatch: ctx.output.nextDispatch
|
|
13494
13486
|
});
|
|
13495
13487
|
} finally {
|
|
13496
13488
|
clearStampedLifecycleLabels(profile, ctx);
|
|
@@ -14389,13 +14381,33 @@ ${CI_HELP}`);
|
|
|
14389
14381
|
`);
|
|
14390
14382
|
try {
|
|
14391
14383
|
const config = earlyConfig ?? loadConfig(cwd);
|
|
14392
|
-
|
|
14384
|
+
let result = await runExecutable(dispatch2.executable, {
|
|
14393
14385
|
cliArgs: dispatch2.cliArgs,
|
|
14394
14386
|
cwd,
|
|
14395
14387
|
config,
|
|
14396
14388
|
verbose: args.verbose,
|
|
14397
14389
|
quiet: args.quiet
|
|
14398
14390
|
});
|
|
14391
|
+
const MAX_CHAIN_HOPS = 4;
|
|
14392
|
+
for (let hops = 1; result.nextDispatch && hops <= MAX_CHAIN_HOPS; hops++) {
|
|
14393
|
+
const next = result.nextDispatch;
|
|
14394
|
+
process.stdout.write(`\u2192 kody: in-process hand-off \u2192 ${next.executable} (hop ${hops}/${MAX_CHAIN_HOPS})
|
|
14395
|
+
|
|
14396
|
+
`);
|
|
14397
|
+
result = await runExecutable(next.executable, {
|
|
14398
|
+
cliArgs: next.cliArgs,
|
|
14399
|
+
cwd,
|
|
14400
|
+
config,
|
|
14401
|
+
verbose: args.verbose,
|
|
14402
|
+
quiet: args.quiet
|
|
14403
|
+
});
|
|
14404
|
+
}
|
|
14405
|
+
if (result.nextDispatch) {
|
|
14406
|
+
process.stderr.write(
|
|
14407
|
+
`[kody] in-process hand-off cap (${MAX_CHAIN_HOPS}) reached; not running ${result.nextDispatch.executable}
|
|
14408
|
+
`
|
|
14409
|
+
);
|
|
14410
|
+
}
|
|
14399
14411
|
if (result.exitCode !== 0 && result.exitCode !== 1 && result.exitCode !== 2) {
|
|
14400
14412
|
postFailureTail(issueNumber, cwd, result.reason || `exit ${result.exitCode}`);
|
|
14401
14413
|
}
|
|
@@ -347,6 +347,14 @@ export interface Context {
|
|
|
347
347
|
exitCode: number
|
|
348
348
|
prUrl?: string
|
|
349
349
|
reason?: string
|
|
350
|
+
/**
|
|
351
|
+
* In-process hand-off to the next stage. A stage (e.g. `classify`) sets
|
|
352
|
+
* this so the orchestrator runs the chosen sub-orchestrator
|
|
353
|
+
* (feature/bug/spec/chore) in the same process — instead of posting an
|
|
354
|
+
* `@kody <next>` comment, which is silently ignored when Kody comments as
|
|
355
|
+
* a GitHub App (bot author), stalling the pipeline at classify.
|
|
356
|
+
*/
|
|
357
|
+
nextDispatch?: { executable: string; cliArgs: Record<string, unknown> }
|
|
350
358
|
}
|
|
351
359
|
/**
|
|
352
360
|
* If a preflight script sets this to true, the executor skips the agent
|
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.160",
|
|
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",
|