@kody-ade/kody-engine 0.4.29 → 0.4.30
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 +155 -199
- package/package.json +1 -1
package/dist/bin/kody.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// package.json
|
|
4
4
|
var package_default = {
|
|
5
5
|
name: "@kody-ade/kody-engine",
|
|
6
|
-
version: "0.4.
|
|
6
|
+
version: "0.4.30",
|
|
7
7
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
8
8
|
license: "MIT",
|
|
9
9
|
type: "module",
|
|
@@ -1977,153 +1977,10 @@ function stripBlockingEnv(env) {
|
|
|
1977
1977
|
return out;
|
|
1978
1978
|
}
|
|
1979
1979
|
|
|
1980
|
-
// src/prompt.ts
|
|
1981
|
-
import * as fs10 from "fs";
|
|
1982
|
-
import * as path9 from "path";
|
|
1983
|
-
var CONVENTIONS_PER_FILE_MAX_BYTES = 3e4;
|
|
1984
|
-
var CONVENTION_FILES = ["CLAUDE.md", "AGENTS.md"];
|
|
1985
|
-
function loadProjectConventions(projectDir) {
|
|
1986
|
-
const out = [];
|
|
1987
|
-
for (const rel of CONVENTION_FILES) {
|
|
1988
|
-
const abs = path9.join(projectDir, rel);
|
|
1989
|
-
if (!fs10.existsSync(abs)) continue;
|
|
1990
|
-
let content;
|
|
1991
|
-
try {
|
|
1992
|
-
content = fs10.readFileSync(abs, "utf-8");
|
|
1993
|
-
} catch {
|
|
1994
|
-
continue;
|
|
1995
|
-
}
|
|
1996
|
-
const truncated = content.length > CONVENTIONS_PER_FILE_MAX_BYTES;
|
|
1997
|
-
if (truncated) content = `${content.slice(0, CONVENTIONS_PER_FILE_MAX_BYTES)}
|
|
1998
|
-
|
|
1999
|
-
\u2026 (truncated)`;
|
|
2000
|
-
out.push({ path: rel, content, truncated });
|
|
2001
|
-
}
|
|
2002
|
-
return out;
|
|
2003
|
-
}
|
|
2004
|
-
function parseAgentResult(finalText) {
|
|
2005
|
-
const text = (finalText || "").trim();
|
|
2006
|
-
if (!text)
|
|
2007
|
-
return {
|
|
2008
|
-
done: false,
|
|
2009
|
-
commitMessage: "",
|
|
2010
|
-
prSummary: "",
|
|
2011
|
-
feedbackActions: "",
|
|
2012
|
-
planDeviations: "",
|
|
2013
|
-
priorArt: "",
|
|
2014
|
-
failureReason: "agent produced no final message",
|
|
2015
|
-
markerMissing: false
|
|
2016
|
-
};
|
|
2017
|
-
const MARKDOWN_PREFIX = "[\\s>*_#`~\\-]*";
|
|
2018
|
-
const FAILED_RE = new RegExp(`(?:^|\\n)${MARKDOWN_PREFIX}FAILED${MARKDOWN_PREFIX}\\s*:\\s*(.+?)\\s*$`, "is");
|
|
2019
|
-
const DONE_RE = new RegExp(`(?:^|\\n)${MARKDOWN_PREFIX}DONE\\b`, "i");
|
|
2020
|
-
const failedMatch = text.match(FAILED_RE);
|
|
2021
|
-
if (failedMatch) {
|
|
2022
|
-
return {
|
|
2023
|
-
done: false,
|
|
2024
|
-
commitMessage: "",
|
|
2025
|
-
prSummary: "",
|
|
2026
|
-
feedbackActions: "",
|
|
2027
|
-
planDeviations: "",
|
|
2028
|
-
priorArt: "",
|
|
2029
|
-
failureReason: stripMarkdownEmphasis(failedMatch[1]),
|
|
2030
|
-
markerMissing: false
|
|
2031
|
-
};
|
|
2032
|
-
}
|
|
2033
|
-
const hasDoneMarker = DONE_RE.test(text);
|
|
2034
|
-
const hasCommitMsg = /^[\s>*_#`~-]*COMMIT_MSG\s*:/im.test(text);
|
|
2035
|
-
const hasPrSummary = /^[\s>*_#`~-]*PR_SUMMARY\s*:/im.test(text);
|
|
2036
|
-
if (!hasDoneMarker && !hasCommitMsg && !hasPrSummary) {
|
|
2037
|
-
const tail = text.length > 400 ? `\u2026${text.slice(-400)}` : text;
|
|
2038
|
-
return {
|
|
2039
|
-
done: false,
|
|
2040
|
-
commitMessage: "",
|
|
2041
|
-
prSummary: "",
|
|
2042
|
-
feedbackActions: "",
|
|
2043
|
-
planDeviations: "",
|
|
2044
|
-
priorArt: "",
|
|
2045
|
-
failureReason: `no DONE or FAILED marker in agent output \u2014 agent tail: ${tail}`,
|
|
2046
|
-
markerMissing: true
|
|
2047
|
-
};
|
|
2048
|
-
}
|
|
2049
|
-
const commitMatch = text.match(/^[\s>*_#`~-]*COMMIT_MSG[\s>*_#`~-]*\s*:\s*(.+)$/im);
|
|
2050
|
-
const commitMessage = commitMatch ? stripMarkdownEmphasis(commitMatch[1]) : "";
|
|
2051
|
-
const feedbackActions = extractBlock(
|
|
2052
|
-
text,
|
|
2053
|
-
/(?:^|\n)[ \t]*FEEDBACK_ACTIONS\s*:[ \t]*\n/i,
|
|
2054
|
-
/(?:^|\n)[ \t]*(?:PLAN_DEVIATIONS|COMMIT_MSG|PR_SUMMARY|PRIOR_ART)\s*:/i
|
|
2055
|
-
);
|
|
2056
|
-
let planDeviations = extractBlock(
|
|
2057
|
-
text,
|
|
2058
|
-
/(?:^|\n)[ \t]*PLAN_DEVIATIONS\s*:[ \t]*\n/i,
|
|
2059
|
-
/(?:^|\n)[ \t]*(?:COMMIT_MSG|PR_SUMMARY|FEEDBACK_ACTIONS|PRIOR_ART)\s*:/i
|
|
2060
|
-
);
|
|
2061
|
-
if (!planDeviations) {
|
|
2062
|
-
const inline = text.match(/(?:^|\n)[ \t]*PLAN_DEVIATIONS\s*:[ \t]*(.+?)[ \t]*(?:\n|$)/i);
|
|
2063
|
-
if (inline) planDeviations = inline[1].trim();
|
|
2064
|
-
}
|
|
2065
|
-
let priorArt = "";
|
|
2066
|
-
const priorArtInline = text.match(/(?:^|\n)[ \t]*PRIOR_ART\s*:[ \t]*(.+?)[ \t]*(?:\n|$)/i);
|
|
2067
|
-
if (priorArtInline) priorArt = priorArtInline[1].trim();
|
|
2068
|
-
const summaryStart = text.search(/(^|\n)[ \t]*PR_SUMMARY\s*:[ \t]*\n/i);
|
|
2069
|
-
let prSummary = "";
|
|
2070
|
-
if (summaryStart !== -1) {
|
|
2071
|
-
const afterMarker = text.slice(summaryStart).replace(/^[\s\S]*?PR_SUMMARY\s*:[ \t]*\n/i, "");
|
|
2072
|
-
prSummary = afterMarker.replace(/\n\s*```\s*$/g, "").replace(/```\s*$/g, "").trim();
|
|
2073
|
-
}
|
|
2074
|
-
return {
|
|
2075
|
-
done: true,
|
|
2076
|
-
commitMessage,
|
|
2077
|
-
prSummary,
|
|
2078
|
-
feedbackActions,
|
|
2079
|
-
planDeviations,
|
|
2080
|
-
priorArt,
|
|
2081
|
-
failureReason: "",
|
|
2082
|
-
markerMissing: false
|
|
2083
|
-
};
|
|
2084
|
-
}
|
|
2085
|
-
function stripMarkdownEmphasis(s) {
|
|
2086
|
-
return s.trim().replace(/^[*_`~]+|[*_`~]+$/g, "").trim();
|
|
2087
|
-
}
|
|
2088
|
-
function extractBlock(text, startMarker, endMarker) {
|
|
2089
|
-
const startIdx = text.search(startMarker);
|
|
2090
|
-
if (startIdx === -1) return "";
|
|
2091
|
-
const afterStart = text.slice(startIdx).replace(startMarker, "");
|
|
2092
|
-
const endIdx = afterStart.search(endMarker);
|
|
2093
|
-
const body = endIdx === -1 ? afterStart : afterStart.slice(0, endIdx);
|
|
2094
|
-
return body.replace(/\n\s*```\s*$/g, "").trim();
|
|
2095
|
-
}
|
|
2096
|
-
|
|
2097
|
-
// src/rescueMissingMarker.ts
|
|
2098
|
-
var NUDGE_PROMPT = "Your previous message did not contain the required terminator. Reply with EXACTLY one of:\n DONE\n COMMIT_MSG: <one-line commit message>\nor, if the work failed:\n FAILED: <one-line reason>\nDo not repeat any earlier content \u2014 emit only the marker line(s).";
|
|
2099
|
-
async function rescueMissingMarker(result, invoke) {
|
|
2100
|
-
if (result.outcome !== "completed") return result;
|
|
2101
|
-
const parsed = parseAgentResult(result.finalText);
|
|
2102
|
-
if (!parsed.markerMissing) return result;
|
|
2103
|
-
try {
|
|
2104
|
-
const rescue = await invoke(NUDGE_PROMPT);
|
|
2105
|
-
if (!rescue.finalText || !rescue.finalText.trim()) return result;
|
|
2106
|
-
return {
|
|
2107
|
-
...result,
|
|
2108
|
-
finalText: `${result.finalText}
|
|
2109
|
-
|
|
2110
|
-
---
|
|
2111
|
-
|
|
2112
|
-
${rescue.finalText}`,
|
|
2113
|
-
outcome: rescue.outcome === "failed" ? result.outcome : rescue.outcome
|
|
2114
|
-
};
|
|
2115
|
-
} catch (err) {
|
|
2116
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2117
|
-
process.stderr.write(`[kody] marker-rescue turn failed: ${msg}
|
|
2118
|
-
`);
|
|
2119
|
-
return result;
|
|
2120
|
-
}
|
|
2121
|
-
}
|
|
2122
|
-
|
|
2123
1980
|
// src/commit.ts
|
|
2124
1981
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
2125
|
-
import * as
|
|
2126
|
-
import * as
|
|
1982
|
+
import * as fs10 from "fs";
|
|
1983
|
+
import * as path9 from "path";
|
|
2127
1984
|
var FORBIDDEN_PATH_PREFIXES = [
|
|
2128
1985
|
".kody/",
|
|
2129
1986
|
".kody-engine/",
|
|
@@ -2179,18 +2036,18 @@ function tryGit(args, cwd) {
|
|
|
2179
2036
|
}
|
|
2180
2037
|
function abortUnfinishedGitOps(cwd) {
|
|
2181
2038
|
const aborted = [];
|
|
2182
|
-
const gitDir =
|
|
2183
|
-
if (!
|
|
2184
|
-
if (
|
|
2039
|
+
const gitDir = path9.join(cwd ?? process.cwd(), ".git");
|
|
2040
|
+
if (!fs10.existsSync(gitDir)) return aborted;
|
|
2041
|
+
if (fs10.existsSync(path9.join(gitDir, "MERGE_HEAD"))) {
|
|
2185
2042
|
if (tryGit(["merge", "--abort"], cwd)) aborted.push("merge");
|
|
2186
2043
|
}
|
|
2187
|
-
if (
|
|
2044
|
+
if (fs10.existsSync(path9.join(gitDir, "CHERRY_PICK_HEAD"))) {
|
|
2188
2045
|
if (tryGit(["cherry-pick", "--abort"], cwd)) aborted.push("cherry-pick");
|
|
2189
2046
|
}
|
|
2190
|
-
if (
|
|
2047
|
+
if (fs10.existsSync(path9.join(gitDir, "REVERT_HEAD"))) {
|
|
2191
2048
|
if (tryGit(["revert", "--abort"], cwd)) aborted.push("revert");
|
|
2192
2049
|
}
|
|
2193
|
-
if (
|
|
2050
|
+
if (fs10.existsSync(path9.join(gitDir, "rebase-merge")) || fs10.existsSync(path9.join(gitDir, "rebase-apply"))) {
|
|
2194
2051
|
if (tryGit(["rebase", "--abort"], cwd)) aborted.push("rebase");
|
|
2195
2052
|
}
|
|
2196
2053
|
try {
|
|
@@ -2246,7 +2103,7 @@ function normalizeCommitMessage(raw) {
|
|
|
2246
2103
|
function commitAndPush(branch, agentMessage, cwd) {
|
|
2247
2104
|
const allChanged = listChangedFiles(cwd);
|
|
2248
2105
|
const allowedFiles = allChanged.filter((f) => !isForbiddenPath(f));
|
|
2249
|
-
const mergeHeadExists =
|
|
2106
|
+
const mergeHeadExists = fs10.existsSync(path9.join(cwd ?? process.cwd(), ".git", "MERGE_HEAD"));
|
|
2250
2107
|
if (allowedFiles.length === 0 && !mergeHeadExists) {
|
|
2251
2108
|
return { committed: false, pushed: false, sha: "", message: "" };
|
|
2252
2109
|
}
|
|
@@ -2558,21 +2415,21 @@ var advanceFlow = async (ctx, profile) => {
|
|
|
2558
2415
|
};
|
|
2559
2416
|
|
|
2560
2417
|
// src/scripts/buildSyntheticPlugin.ts
|
|
2561
|
-
import * as
|
|
2418
|
+
import * as fs11 from "fs";
|
|
2562
2419
|
import * as os2 from "os";
|
|
2563
|
-
import * as
|
|
2420
|
+
import * as path10 from "path";
|
|
2564
2421
|
function getPluginsCatalogRoot() {
|
|
2565
|
-
const here =
|
|
2422
|
+
const here = path10.dirname(new URL(import.meta.url).pathname);
|
|
2566
2423
|
const candidates = [
|
|
2567
|
-
|
|
2424
|
+
path10.join(here, "..", "plugins"),
|
|
2568
2425
|
// dev: src/scripts → src/plugins
|
|
2569
|
-
|
|
2426
|
+
path10.join(here, "..", "..", "plugins"),
|
|
2570
2427
|
// built: dist/scripts → dist/plugins
|
|
2571
|
-
|
|
2428
|
+
path10.join(here, "..", "..", "src", "plugins")
|
|
2572
2429
|
// fallback
|
|
2573
2430
|
];
|
|
2574
2431
|
for (const c of candidates) {
|
|
2575
|
-
if (
|
|
2432
|
+
if (fs11.existsSync(c) && fs11.statSync(c).isDirectory()) return c;
|
|
2576
2433
|
}
|
|
2577
2434
|
return candidates[0];
|
|
2578
2435
|
}
|
|
@@ -2582,52 +2439,52 @@ var buildSyntheticPlugin = async (ctx, profile) => {
|
|
|
2582
2439
|
if (!needsSynthetic) return;
|
|
2583
2440
|
const catalog = getPluginsCatalogRoot();
|
|
2584
2441
|
const runId = `${profile.name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
2585
|
-
const root =
|
|
2586
|
-
|
|
2442
|
+
const root = path10.join(os2.tmpdir(), `kody-synth-${runId}`);
|
|
2443
|
+
fs11.mkdirSync(path10.join(root, ".claude-plugin"), { recursive: true });
|
|
2587
2444
|
const resolvePart = (bucket, entry) => {
|
|
2588
|
-
const local =
|
|
2589
|
-
if (
|
|
2590
|
-
const central =
|
|
2591
|
-
if (
|
|
2445
|
+
const local = path10.join(profile.dir, bucket, entry);
|
|
2446
|
+
if (fs11.existsSync(local)) return local;
|
|
2447
|
+
const central = path10.join(catalog, bucket, entry);
|
|
2448
|
+
if (fs11.existsSync(central)) return central;
|
|
2592
2449
|
throw new Error(
|
|
2593
2450
|
`buildSyntheticPlugin: ${bucket} entry '${entry}' not found in executable dir (${profile.dir}/${bucket}/) or catalog (${catalog}/${bucket}/)`
|
|
2594
2451
|
);
|
|
2595
2452
|
};
|
|
2596
2453
|
if (cc.skills.length > 0) {
|
|
2597
|
-
const dst =
|
|
2598
|
-
|
|
2454
|
+
const dst = path10.join(root, "skills");
|
|
2455
|
+
fs11.mkdirSync(dst, { recursive: true });
|
|
2599
2456
|
for (const name of cc.skills) {
|
|
2600
|
-
copyDir(resolvePart("skills", name),
|
|
2457
|
+
copyDir(resolvePart("skills", name), path10.join(dst, name));
|
|
2601
2458
|
}
|
|
2602
2459
|
}
|
|
2603
2460
|
if (cc.commands.length > 0) {
|
|
2604
|
-
const dst =
|
|
2605
|
-
|
|
2461
|
+
const dst = path10.join(root, "commands");
|
|
2462
|
+
fs11.mkdirSync(dst, { recursive: true });
|
|
2606
2463
|
for (const name of cc.commands) {
|
|
2607
|
-
|
|
2464
|
+
fs11.copyFileSync(resolvePart("commands", `${name}.md`), path10.join(dst, `${name}.md`));
|
|
2608
2465
|
}
|
|
2609
2466
|
}
|
|
2610
2467
|
if (cc.subagents.length > 0) {
|
|
2611
|
-
const dst =
|
|
2612
|
-
|
|
2468
|
+
const dst = path10.join(root, "agents");
|
|
2469
|
+
fs11.mkdirSync(dst, { recursive: true });
|
|
2613
2470
|
for (const name of cc.subagents) {
|
|
2614
|
-
|
|
2471
|
+
fs11.copyFileSync(resolvePart("agents", `${name}.md`), path10.join(dst, `${name}.md`));
|
|
2615
2472
|
}
|
|
2616
2473
|
}
|
|
2617
2474
|
if (cc.hooks.length > 0) {
|
|
2618
|
-
const dst =
|
|
2619
|
-
|
|
2475
|
+
const dst = path10.join(root, "hooks");
|
|
2476
|
+
fs11.mkdirSync(dst, { recursive: true });
|
|
2620
2477
|
const merged = { hooks: {} };
|
|
2621
2478
|
for (const name of cc.hooks) {
|
|
2622
2479
|
const src = resolvePart("hooks", `${name}.json`);
|
|
2623
|
-
const parsed = JSON.parse(
|
|
2480
|
+
const parsed = JSON.parse(fs11.readFileSync(src, "utf-8"));
|
|
2624
2481
|
for (const [event, entries] of Object.entries(parsed.hooks ?? {})) {
|
|
2625
2482
|
if (!Array.isArray(entries)) continue;
|
|
2626
2483
|
if (!merged.hooks[event]) merged.hooks[event] = [];
|
|
2627
2484
|
merged.hooks[event].push(...entries);
|
|
2628
2485
|
}
|
|
2629
2486
|
}
|
|
2630
|
-
|
|
2487
|
+
fs11.writeFileSync(path10.join(dst, "hooks.json"), `${JSON.stringify(merged, null, 2)}
|
|
2631
2488
|
`);
|
|
2632
2489
|
}
|
|
2633
2490
|
const manifest = {
|
|
@@ -2638,17 +2495,17 @@ var buildSyntheticPlugin = async (ctx, profile) => {
|
|
|
2638
2495
|
if (cc.skills.length > 0) manifest.skills = ["./skills/"];
|
|
2639
2496
|
if (cc.commands.length > 0) manifest.commands = ["./commands/"];
|
|
2640
2497
|
if (cc.subagents.length > 0) manifest.agents = cc.subagents.map((n) => `./agents/${n}.md`);
|
|
2641
|
-
|
|
2498
|
+
fs11.writeFileSync(path10.join(root, ".claude-plugin", "plugin.json"), `${JSON.stringify(manifest, null, 2)}
|
|
2642
2499
|
`);
|
|
2643
2500
|
ctx.data.syntheticPluginPath = root;
|
|
2644
2501
|
};
|
|
2645
2502
|
function copyDir(src, dst) {
|
|
2646
|
-
|
|
2647
|
-
for (const ent of
|
|
2648
|
-
const s =
|
|
2649
|
-
const d =
|
|
2503
|
+
fs11.mkdirSync(dst, { recursive: true });
|
|
2504
|
+
for (const ent of fs11.readdirSync(src, { withFileTypes: true })) {
|
|
2505
|
+
const s = path10.join(src, ent.name);
|
|
2506
|
+
const d = path10.join(dst, ent.name);
|
|
2650
2507
|
if (ent.isDirectory()) copyDir(s, d);
|
|
2651
|
-
else if (ent.isFile())
|
|
2508
|
+
else if (ent.isFile()) fs11.copyFileSync(s, d);
|
|
2652
2509
|
}
|
|
2653
2510
|
}
|
|
2654
2511
|
|
|
@@ -2713,6 +2570,111 @@ function formatMissesForFeedback(misses) {
|
|
|
2713
2570
|
return lines.join("\n");
|
|
2714
2571
|
}
|
|
2715
2572
|
|
|
2573
|
+
// src/prompt.ts
|
|
2574
|
+
import * as fs12 from "fs";
|
|
2575
|
+
import * as path11 from "path";
|
|
2576
|
+
var CONVENTIONS_PER_FILE_MAX_BYTES = 3e4;
|
|
2577
|
+
var CONVENTION_FILES = ["CLAUDE.md", "AGENTS.md"];
|
|
2578
|
+
function loadProjectConventions(projectDir) {
|
|
2579
|
+
const out = [];
|
|
2580
|
+
for (const rel of CONVENTION_FILES) {
|
|
2581
|
+
const abs = path11.join(projectDir, rel);
|
|
2582
|
+
if (!fs12.existsSync(abs)) continue;
|
|
2583
|
+
let content;
|
|
2584
|
+
try {
|
|
2585
|
+
content = fs12.readFileSync(abs, "utf-8");
|
|
2586
|
+
} catch {
|
|
2587
|
+
continue;
|
|
2588
|
+
}
|
|
2589
|
+
const truncated = content.length > CONVENTIONS_PER_FILE_MAX_BYTES;
|
|
2590
|
+
if (truncated) content = `${content.slice(0, CONVENTIONS_PER_FILE_MAX_BYTES)}
|
|
2591
|
+
|
|
2592
|
+
\u2026 (truncated)`;
|
|
2593
|
+
out.push({ path: rel, content, truncated });
|
|
2594
|
+
}
|
|
2595
|
+
return out;
|
|
2596
|
+
}
|
|
2597
|
+
function parseAgentResult(finalText) {
|
|
2598
|
+
const text = (finalText || "").trim();
|
|
2599
|
+
if (!text)
|
|
2600
|
+
return {
|
|
2601
|
+
done: false,
|
|
2602
|
+
commitMessage: "",
|
|
2603
|
+
prSummary: "",
|
|
2604
|
+
feedbackActions: "",
|
|
2605
|
+
planDeviations: "",
|
|
2606
|
+
priorArt: "",
|
|
2607
|
+
failureReason: "agent produced no final message",
|
|
2608
|
+
markerMissing: false
|
|
2609
|
+
};
|
|
2610
|
+
const MARKDOWN_PREFIX = "[\\s>*_#`~\\-]*";
|
|
2611
|
+
const FAILED_RE = new RegExp(`(?:^|\\n)${MARKDOWN_PREFIX}FAILED${MARKDOWN_PREFIX}\\s*:\\s*(.+?)\\s*$`, "is");
|
|
2612
|
+
const DONE_RE = new RegExp(`(?:^|\\n)${MARKDOWN_PREFIX}DONE\\b`, "i");
|
|
2613
|
+
const failedMatch = text.match(FAILED_RE);
|
|
2614
|
+
if (failedMatch) {
|
|
2615
|
+
return {
|
|
2616
|
+
done: false,
|
|
2617
|
+
commitMessage: "",
|
|
2618
|
+
prSummary: "",
|
|
2619
|
+
feedbackActions: "",
|
|
2620
|
+
planDeviations: "",
|
|
2621
|
+
priorArt: "",
|
|
2622
|
+
failureReason: stripMarkdownEmphasis(failedMatch[1]),
|
|
2623
|
+
markerMissing: false
|
|
2624
|
+
};
|
|
2625
|
+
}
|
|
2626
|
+
const hasDoneMarker = DONE_RE.test(text);
|
|
2627
|
+
const hasCommitMsg = /^[\s>*_#`~-]*COMMIT_MSG\s*:/im.test(text);
|
|
2628
|
+
const hasPrSummary = /^[\s>*_#`~-]*PR_SUMMARY\s*:/im.test(text);
|
|
2629
|
+
const markerMissing = !hasDoneMarker && !hasCommitMsg && !hasPrSummary;
|
|
2630
|
+
const commitMatch = text.match(/^[\s>*_#`~-]*COMMIT_MSG[\s>*_#`~-]*\s*:\s*(.+)$/im);
|
|
2631
|
+
const commitMessage = commitMatch ? stripMarkdownEmphasis(commitMatch[1]) : "";
|
|
2632
|
+
const feedbackActions = extractBlock(
|
|
2633
|
+
text,
|
|
2634
|
+
/(?:^|\n)[ \t]*FEEDBACK_ACTIONS\s*:[ \t]*\n/i,
|
|
2635
|
+
/(?:^|\n)[ \t]*(?:PLAN_DEVIATIONS|COMMIT_MSG|PR_SUMMARY|PRIOR_ART)\s*:/i
|
|
2636
|
+
);
|
|
2637
|
+
let planDeviations = extractBlock(
|
|
2638
|
+
text,
|
|
2639
|
+
/(?:^|\n)[ \t]*PLAN_DEVIATIONS\s*:[ \t]*\n/i,
|
|
2640
|
+
/(?:^|\n)[ \t]*(?:COMMIT_MSG|PR_SUMMARY|FEEDBACK_ACTIONS|PRIOR_ART)\s*:/i
|
|
2641
|
+
);
|
|
2642
|
+
if (!planDeviations) {
|
|
2643
|
+
const inline = text.match(/(?:^|\n)[ \t]*PLAN_DEVIATIONS\s*:[ \t]*(.+?)[ \t]*(?:\n|$)/i);
|
|
2644
|
+
if (inline) planDeviations = inline[1].trim();
|
|
2645
|
+
}
|
|
2646
|
+
let priorArt = "";
|
|
2647
|
+
const priorArtInline = text.match(/(?:^|\n)[ \t]*PRIOR_ART\s*:[ \t]*(.+?)[ \t]*(?:\n|$)/i);
|
|
2648
|
+
if (priorArtInline) priorArt = priorArtInline[1].trim();
|
|
2649
|
+
const summaryStart = text.search(/(^|\n)[ \t]*PR_SUMMARY\s*:[ \t]*\n/i);
|
|
2650
|
+
let prSummary = "";
|
|
2651
|
+
if (summaryStart !== -1) {
|
|
2652
|
+
const afterMarker = text.slice(summaryStart).replace(/^[\s\S]*?PR_SUMMARY\s*:[ \t]*\n/i, "");
|
|
2653
|
+
prSummary = afterMarker.replace(/\n\s*```\s*$/g, "").replace(/```\s*$/g, "").trim();
|
|
2654
|
+
}
|
|
2655
|
+
return {
|
|
2656
|
+
done: true,
|
|
2657
|
+
commitMessage,
|
|
2658
|
+
prSummary,
|
|
2659
|
+
feedbackActions,
|
|
2660
|
+
planDeviations,
|
|
2661
|
+
priorArt,
|
|
2662
|
+
failureReason: "",
|
|
2663
|
+
markerMissing
|
|
2664
|
+
};
|
|
2665
|
+
}
|
|
2666
|
+
function stripMarkdownEmphasis(s) {
|
|
2667
|
+
return s.trim().replace(/^[*_`~]+|[*_`~]+$/g, "").trim();
|
|
2668
|
+
}
|
|
2669
|
+
function extractBlock(text, startMarker, endMarker) {
|
|
2670
|
+
const startIdx = text.search(startMarker);
|
|
2671
|
+
if (startIdx === -1) return "";
|
|
2672
|
+
const afterStart = text.slice(startIdx).replace(startMarker, "");
|
|
2673
|
+
const endIdx = afterStart.search(endMarker);
|
|
2674
|
+
const body = endIdx === -1 ? afterStart : afterStart.slice(0, endIdx);
|
|
2675
|
+
return body.replace(/\n\s*```\s*$/g, "").trim();
|
|
2676
|
+
}
|
|
2677
|
+
|
|
2716
2678
|
// src/scripts/checkCoverageWithRetry.ts
|
|
2717
2679
|
var checkCoverageWithRetry = async (ctx) => {
|
|
2718
2680
|
const reqs = ctx.data.coverageRules ?? [];
|
|
@@ -6717,13 +6679,19 @@ var requirePlanDeviations = async (ctx, profile) => {
|
|
|
6717
6679
|
if (!planContent) return;
|
|
6718
6680
|
const raw = String(ctx.data.planDeviations ?? "").trim();
|
|
6719
6681
|
if (raw.length === 0) {
|
|
6720
|
-
|
|
6682
|
+
process.stderr.write(
|
|
6683
|
+
"[kody requirePlanDeviations] warning: agent omitted PLAN_DEVIATIONS block \u2014 proceeding anyway (verify/tests are the real gate)\n"
|
|
6684
|
+
);
|
|
6685
|
+
ctx.data.planDeviationsOmitted = true;
|
|
6721
6686
|
return;
|
|
6722
6687
|
}
|
|
6723
6688
|
if (isNoneSentinel(raw)) return;
|
|
6724
6689
|
const bullets = raw.split("\n").filter((l) => /^\s*[-*]\s+/.test(l));
|
|
6725
6690
|
if (bullets.length === 0) {
|
|
6726
|
-
|
|
6691
|
+
process.stderr.write(
|
|
6692
|
+
"[kody requirePlanDeviations] warning: PLAN_DEVIATIONS block is not 'none' and lists no bullet items \u2014 proceeding anyway\n"
|
|
6693
|
+
);
|
|
6694
|
+
ctx.data.planDeviationsMalformed = true;
|
|
6727
6695
|
return;
|
|
6728
6696
|
}
|
|
6729
6697
|
ctx.data.planDeviationCount = bullets.length;
|
|
@@ -6735,17 +6703,6 @@ function isNoneSentinel(block) {
|
|
|
6735
6703
|
if (stripped.length !== 1) return false;
|
|
6736
6704
|
return stripped[0] === "none";
|
|
6737
6705
|
}
|
|
6738
|
-
function fail2(ctx, profile, reason) {
|
|
6739
|
-
ctx.data.agentDone = false;
|
|
6740
|
-
ctx.data.agentFailureReason = reason;
|
|
6741
|
-
const modeSeg = profile.name.replace(/-/g, "_").toUpperCase();
|
|
6742
|
-
const failedAction6 = {
|
|
6743
|
-
type: `${modeSeg}_FAILED`,
|
|
6744
|
-
payload: { reason },
|
|
6745
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6746
|
-
};
|
|
6747
|
-
ctx.data.action = failedAction6;
|
|
6748
|
-
}
|
|
6749
6706
|
|
|
6750
6707
|
// src/scripts/resolveArtifacts.ts
|
|
6751
6708
|
var resolveArtifacts = async (ctx, profile) => {
|
|
@@ -8396,7 +8353,6 @@ async function runExecutable(profileName, input) {
|
|
|
8396
8353
|
return finish({ exitCode: 99, reason: "composePrompt did not produce a prompt (ctx.data.prompt missing)" });
|
|
8397
8354
|
}
|
|
8398
8355
|
agentResult = await invokeAgent(prompt);
|
|
8399
|
-
agentResult = await rescueMissingMarker(agentResult, invokeAgent);
|
|
8400
8356
|
}
|
|
8401
8357
|
for (const entry of profile.scripts.postflight) {
|
|
8402
8358
|
const entryLabel = entry.script ?? entry.shell ?? "<unknown>";
|
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.30",
|
|
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",
|