@kody-ade/kody-engine 0.2.53 → 0.2.55
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/kody2.js +203 -51
- package/dist/executables/bug/profile.json +9 -0
- package/dist/executables/chore/profile.json +9 -0
- package/dist/executables/classify/profile.json +64 -0
- package/dist/executables/classify/prompt.md +49 -0
- package/dist/executables/feature/profile.json +9 -0
- package/dist/executables/fix/profile.json +1 -0
- package/dist/executables/fix-ci/profile.json +1 -0
- package/dist/executables/init/profile.json +1 -0
- package/dist/executables/plan/profile.json +1 -0
- package/dist/executables/plan-verify/profile.json +1 -0
- package/dist/executables/release/profile.json +1 -0
- package/dist/executables/research/profile.json +4 -0
- package/dist/executables/resolve/profile.json +1 -0
- package/dist/executables/review/profile.json +1 -0
- package/dist/executables/run/profile.json +1 -0
- package/dist/executables/spec/profile.json +9 -0
- package/dist/executables/sync/profile.json +1 -0
- package/dist/executables/types.ts +13 -1
- package/dist/executables/ui-review/profile.json +1 -0
- package/dist/executables/watch-stale-prs/profile.json +1 -0
- package/package.json +1 -1
package/dist/bin/kody2.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.2.
|
|
6
|
+
version: "0.2.55",
|
|
7
7
|
description: "kody2 \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
8
8
|
license: "MIT",
|
|
9
9
|
type: "module",
|
|
@@ -50,7 +50,7 @@ var package_default = {
|
|
|
50
50
|
};
|
|
51
51
|
|
|
52
52
|
// src/chat-cli.ts
|
|
53
|
-
import { execFileSync as
|
|
53
|
+
import { execFileSync as execFileSync21 } from "child_process";
|
|
54
54
|
import * as fs22 from "fs";
|
|
55
55
|
import * as path19 from "path";
|
|
56
56
|
|
|
@@ -182,9 +182,24 @@ function loadConfig(projectDir = process.cwd()) {
|
|
|
182
182
|
issueContext: parseIssueContext(raw.issueContext),
|
|
183
183
|
testRequirements: parseTestRequirements(raw.testRequirements),
|
|
184
184
|
defaultExecutable: typeof raw.defaultExecutable === "string" && raw.defaultExecutable.length > 0 ? raw.defaultExecutable : void 0,
|
|
185
|
+
classify: parseClassifyConfig(raw.classify),
|
|
185
186
|
release: parseReleaseConfig(raw.release)
|
|
186
187
|
};
|
|
187
188
|
}
|
|
189
|
+
function parseClassifyConfig(raw) {
|
|
190
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
191
|
+
const r = raw;
|
|
192
|
+
const out = {};
|
|
193
|
+
if (r.labelMap && typeof r.labelMap === "object") {
|
|
194
|
+
const entries = Object.entries(r.labelMap).filter(
|
|
195
|
+
([, v]) => typeof v === "string" && v.length > 0
|
|
196
|
+
);
|
|
197
|
+
if (entries.length > 0) {
|
|
198
|
+
out.labelMap = Object.fromEntries(entries.map(([k, v]) => [k.toLowerCase(), String(v)]));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
202
|
+
}
|
|
188
203
|
function parseReleaseConfig(raw) {
|
|
189
204
|
if (!raw || typeof raw !== "object") return void 0;
|
|
190
205
|
const r = raw;
|
|
@@ -528,7 +543,7 @@ async function emit(sink, type, sessionId, suffix, payload) {
|
|
|
528
543
|
}
|
|
529
544
|
|
|
530
545
|
// src/kody2-cli.ts
|
|
531
|
-
import { execFileSync as
|
|
546
|
+
import { execFileSync as execFileSync20 } from "child_process";
|
|
532
547
|
import * as fs21 from "fs";
|
|
533
548
|
import * as path18 from "path";
|
|
534
549
|
|
|
@@ -738,6 +753,7 @@ import * as fs7 from "fs";
|
|
|
738
753
|
import * as path6 from "path";
|
|
739
754
|
var VALID_INPUT_TYPES = /* @__PURE__ */ new Set(["int", "string", "bool", "enum"]);
|
|
740
755
|
var VALID_PERMISSION_MODES = /* @__PURE__ */ new Set(["default", "acceptEdits", "plan", "bypassPermissions"]);
|
|
756
|
+
var VALID_ROLES = /* @__PURE__ */ new Set(["primitive", "orchestrator", "watch", "utility"]);
|
|
741
757
|
var ProfileError = class extends Error {
|
|
742
758
|
constructor(profilePath, message) {
|
|
743
759
|
super(`Invalid profile at ${profilePath}:
|
|
@@ -765,9 +781,17 @@ function loadProfile(profilePath) {
|
|
|
765
781
|
if (kind === "scheduled" && typeof r.schedule !== "string") {
|
|
766
782
|
throw new ProfileError(profilePath, `kind: "scheduled" requires a "schedule" cron string`);
|
|
767
783
|
}
|
|
784
|
+
if (typeof r.role !== "string" || !VALID_ROLES.has(r.role)) {
|
|
785
|
+
throw new ProfileError(
|
|
786
|
+
profilePath,
|
|
787
|
+
`"role" is required and must be one of: ${[...VALID_ROLES].join(" | ")}`
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
const role = r.role;
|
|
768
791
|
const profile = {
|
|
769
792
|
name: requireString(profilePath, r, "name"),
|
|
770
793
|
describe: typeof r.describe === "string" ? r.describe : "",
|
|
794
|
+
role,
|
|
771
795
|
kind,
|
|
772
796
|
schedule: typeof r.schedule === "string" ? r.schedule : void 0,
|
|
773
797
|
inputs: parseInputs(profilePath, r.inputs),
|
|
@@ -1490,6 +1514,41 @@ ${formatMissesForFeedback(misses)}`;
|
|
|
1490
1514
|
ctx.data.coverageMisses = finalMisses;
|
|
1491
1515
|
};
|
|
1492
1516
|
|
|
1517
|
+
// src/scripts/classifyByLabel.ts
|
|
1518
|
+
var VALID_CLASSES = /* @__PURE__ */ new Set(["feature", "bug", "spec", "chore"]);
|
|
1519
|
+
var classifyByLabel = async (ctx) => {
|
|
1520
|
+
const issue = ctx.data.issue;
|
|
1521
|
+
const labels = issue?.labels;
|
|
1522
|
+
if (!labels || labels.length === 0) return;
|
|
1523
|
+
const cfgMap = ctx.config.classify?.labelMap;
|
|
1524
|
+
const map = cfgMap ?? defaultLabelMap();
|
|
1525
|
+
for (const label of labels) {
|
|
1526
|
+
const candidate = map[label.toLowerCase()];
|
|
1527
|
+
if (candidate && VALID_CLASSES.has(candidate)) {
|
|
1528
|
+
ctx.data.classification = candidate;
|
|
1529
|
+
ctx.data.classificationSource = "label";
|
|
1530
|
+
ctx.data.classificationReason = `label \`${label}\` \u2192 ${candidate}`;
|
|
1531
|
+
ctx.skipAgent = true;
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
};
|
|
1536
|
+
function defaultLabelMap() {
|
|
1537
|
+
return {
|
|
1538
|
+
bug: "bug",
|
|
1539
|
+
enhancement: "bug",
|
|
1540
|
+
refactor: "feature",
|
|
1541
|
+
feature: "feature",
|
|
1542
|
+
performance: "feature",
|
|
1543
|
+
rfc: "spec",
|
|
1544
|
+
design: "spec",
|
|
1545
|
+
spec: "spec",
|
|
1546
|
+
docs: "chore",
|
|
1547
|
+
chore: "chore",
|
|
1548
|
+
dependencies: "chore"
|
|
1549
|
+
};
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1493
1552
|
// src/scripts/commitAndPush.ts
|
|
1494
1553
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
1495
1554
|
|
|
@@ -2357,7 +2416,7 @@ function gh2(args, options) {
|
|
|
2357
2416
|
}).trim();
|
|
2358
2417
|
}
|
|
2359
2418
|
function getIssue(issueNumber, cwd) {
|
|
2360
|
-
const output = gh2(["issue", "view", String(issueNumber), "--json", "number,title,body,comments"], { cwd });
|
|
2419
|
+
const output = gh2(["issue", "view", String(issueNumber), "--json", "number,title,body,comments,labels"], { cwd });
|
|
2361
2420
|
const parsed = JSON.parse(output);
|
|
2362
2421
|
if (typeof parsed?.title !== "string") {
|
|
2363
2422
|
throw new Error(`Issue #${issueNumber}: unexpected response shape`);
|
|
@@ -2370,12 +2429,16 @@ function getIssue(issueNumber, cwd) {
|
|
|
2370
2429
|
body: c.body ?? "",
|
|
2371
2430
|
author: c.author?.login ?? "unknown",
|
|
2372
2431
|
createdAt: c.createdAt ?? ""
|
|
2373
|
-
}))
|
|
2432
|
+
})),
|
|
2433
|
+
labels: Array.isArray(parsed.labels) ? parsed.labels.map((l) => l.name ?? "").filter((n) => n.length > 0) : []
|
|
2374
2434
|
};
|
|
2375
2435
|
}
|
|
2436
|
+
function stripKody2Mentions(body) {
|
|
2437
|
+
return body.replace(/(@)(kody2)/gi, "$1\u200B$2");
|
|
2438
|
+
}
|
|
2376
2439
|
function postIssueComment(issueNumber, body, cwd) {
|
|
2377
2440
|
try {
|
|
2378
|
-
gh2(["issue", "comment", String(issueNumber), "--body-file", "-"], { input: body, cwd });
|
|
2441
|
+
gh2(["issue", "comment", String(issueNumber), "--body-file", "-"], { input: stripKody2Mentions(body), cwd });
|
|
2379
2442
|
} catch (err) {
|
|
2380
2443
|
process.stderr.write(
|
|
2381
2444
|
`[kody2] failed to post comment on #${issueNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -2460,7 +2523,7 @@ function getPrLatestReviewBody(prNumber, cwd) {
|
|
|
2460
2523
|
}
|
|
2461
2524
|
function postPrReviewComment(prNumber, body, cwd) {
|
|
2462
2525
|
try {
|
|
2463
|
-
gh2(["pr", "comment", String(prNumber), "--body-file", "-"], { input: body, cwd });
|
|
2526
|
+
gh2(["pr", "comment", String(prNumber), "--body-file", "-"], { input: stripKody2Mentions(body), cwd });
|
|
2464
2527
|
} catch (err) {
|
|
2465
2528
|
process.stderr.write(
|
|
2466
2529
|
`[kody2] failed to post review comment on PR #${prNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -2698,7 +2761,11 @@ function parseGenericFlags(argv) {
|
|
|
2698
2761
|
}
|
|
2699
2762
|
|
|
2700
2763
|
// src/lifecycleLabels.ts
|
|
2701
|
-
var
|
|
2764
|
+
var KODY_NAMESPACE = "kody";
|
|
2765
|
+
function groupOf(label) {
|
|
2766
|
+
const idx = label.indexOf(":");
|
|
2767
|
+
return idx === -1 ? label : label.slice(0, idx + 1);
|
|
2768
|
+
}
|
|
2702
2769
|
function collectProfileLabels() {
|
|
2703
2770
|
const byLabel = /* @__PURE__ */ new Map();
|
|
2704
2771
|
for (const exe of listExecutables()) {
|
|
@@ -2719,7 +2786,7 @@ function extractLabelSpec(entry) {
|
|
|
2719
2786
|
const w = entry.with;
|
|
2720
2787
|
if (!w) return null;
|
|
2721
2788
|
const label = typeof w.label === "string" ? w.label : null;
|
|
2722
|
-
if (!label || !label.startsWith(
|
|
2789
|
+
if (!label || !label.startsWith(KODY_NAMESPACE)) return null;
|
|
2723
2790
|
return {
|
|
2724
2791
|
label,
|
|
2725
2792
|
color: typeof w.color === "string" ? w.color : void 0,
|
|
@@ -2766,16 +2833,17 @@ function createLabelInRepo(spec, cwd) {
|
|
|
2766
2833
|
}
|
|
2767
2834
|
function setKodyLabel(issueNumber, spec, cwd) {
|
|
2768
2835
|
const target = spec.label;
|
|
2769
|
-
if (!target.startsWith(
|
|
2836
|
+
if (!target.startsWith(KODY_NAMESPACE)) {
|
|
2770
2837
|
process.stderr.write(
|
|
2771
2838
|
`[kody2] setKodyLabel: refusing to set non-kody label "${target}"
|
|
2772
2839
|
`
|
|
2773
2840
|
);
|
|
2774
2841
|
return;
|
|
2775
2842
|
}
|
|
2843
|
+
const targetGroup = groupOf(target);
|
|
2776
2844
|
const present = getIssueLabels(issueNumber, cwd);
|
|
2777
2845
|
for (const label of present) {
|
|
2778
|
-
if (label !== target && label.startsWith(
|
|
2846
|
+
if (label !== target && label.startsWith(KODY_NAMESPACE) && groupOf(label) === targetGroup) {
|
|
2779
2847
|
removeLabel(issueNumber, label, cwd);
|
|
2780
2848
|
}
|
|
2781
2849
|
}
|
|
@@ -2832,7 +2900,7 @@ var finishFlow = async (ctx, _profile, _agentResult, args) => {
|
|
|
2832
2900
|
if (state) state.flow = void 0;
|
|
2833
2901
|
if (!issueNumber) return;
|
|
2834
2902
|
const label = typeof args?.label === "string" ? args.label : void 0;
|
|
2835
|
-
if (label && label.startsWith(
|
|
2903
|
+
if (label && label.startsWith(KODY_NAMESPACE)) {
|
|
2836
2904
|
setKodyLabel(
|
|
2837
2905
|
issueNumber,
|
|
2838
2906
|
{
|
|
@@ -3517,7 +3585,9 @@ var loadIssueContext = async (ctx) => {
|
|
|
3517
3585
|
const kept = sorted.slice(0, limit);
|
|
3518
3586
|
const commentsFormatted = kept.length === 0 ? "(no comments yet)" : kept.map((c) => `- **${c.author}** (${c.createdAt}):
|
|
3519
3587
|
${truncate2(c.body, maxBytes).replace(/\n/g, "\n ")}`).join("\n\n");
|
|
3520
|
-
|
|
3588
|
+
const labels = issue.labels ?? [];
|
|
3589
|
+
const labelsFormatted = labels.length === 0 ? "(no labels)" : labels.map((l) => `\`${l}\``).join(", ");
|
|
3590
|
+
ctx.data.issue = { ...issue, commentsFormatted, labelsFormatted };
|
|
3521
3591
|
ctx.data.commentTargetType = "issue";
|
|
3522
3592
|
ctx.data.commentTargetNumber = issueNumber;
|
|
3523
3593
|
};
|
|
@@ -3642,6 +3712,86 @@ var persistFlowState = async (ctx) => {
|
|
|
3642
3712
|
}
|
|
3643
3713
|
};
|
|
3644
3714
|
|
|
3715
|
+
// src/scripts/postClassification.ts
|
|
3716
|
+
import { execFileSync as execFileSync14 } from "child_process";
|
|
3717
|
+
var API_TIMEOUT_MS6 = 3e4;
|
|
3718
|
+
var VALID_CLASSES2 = /* @__PURE__ */ new Set(["feature", "bug", "spec", "chore"]);
|
|
3719
|
+
var postClassification = async (ctx) => {
|
|
3720
|
+
const issueNumber = ctx.args.issue;
|
|
3721
|
+
if (!issueNumber) return;
|
|
3722
|
+
const presetClassification = ctx.data.classification;
|
|
3723
|
+
let classification = null;
|
|
3724
|
+
let reason = null;
|
|
3725
|
+
if (presetClassification && VALID_CLASSES2.has(presetClassification)) {
|
|
3726
|
+
classification = presetClassification;
|
|
3727
|
+
reason = ctx.data.classificationReason ?? "label-based match";
|
|
3728
|
+
} else {
|
|
3729
|
+
const parsed = parseClassification(ctx.data.prSummary ?? "");
|
|
3730
|
+
classification = parsed?.classification ?? null;
|
|
3731
|
+
reason = parsed?.reason ?? null;
|
|
3732
|
+
}
|
|
3733
|
+
if (!classification) {
|
|
3734
|
+
ctx.data.action = failedAction("classification missing or invalid");
|
|
3735
|
+
tryAuditComment(issueNumber, "\u26A0\uFE0F kody2 classifier could not decide \u2014 please re-run with an explicit `@kody2 <type>`.", ctx.cwd);
|
|
3736
|
+
ctx.output.exitCode = 1;
|
|
3737
|
+
ctx.output.reason = "classify: no decision";
|
|
3738
|
+
return;
|
|
3739
|
+
}
|
|
3740
|
+
tryAuditComment(
|
|
3741
|
+
issueNumber,
|
|
3742
|
+
`\u{1F50E} kody2 classified as \`${classification}\`${reason ? ` \u2014 ${reason}` : ""}`,
|
|
3743
|
+
ctx.cwd
|
|
3744
|
+
);
|
|
3745
|
+
try {
|
|
3746
|
+
execFileSync14("gh", ["issue", "comment", String(issueNumber), "--body", `@kody2 ${classification}`], {
|
|
3747
|
+
cwd: ctx.cwd,
|
|
3748
|
+
timeout: API_TIMEOUT_MS6,
|
|
3749
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3750
|
+
});
|
|
3751
|
+
} catch (err) {
|
|
3752
|
+
process.stderr.write(
|
|
3753
|
+
`[kody2 postClassification] failed to dispatch @kody2 ${classification}: ${err instanceof Error ? err.message : String(err)}
|
|
3754
|
+
`
|
|
3755
|
+
);
|
|
3756
|
+
ctx.data.action = failedAction("dispatch post failed");
|
|
3757
|
+
ctx.output.exitCode = 1;
|
|
3758
|
+
ctx.output.reason = "classify: dispatch failed";
|
|
3759
|
+
return;
|
|
3760
|
+
}
|
|
3761
|
+
ctx.data.action = makeAction2(`CLASSIFIED_AS_${classification.toUpperCase()}`, {
|
|
3762
|
+
classification,
|
|
3763
|
+
reason: reason ?? "",
|
|
3764
|
+
source: ctx.data.classificationSource ?? "agent"
|
|
3765
|
+
});
|
|
3766
|
+
ctx.data.classification = classification;
|
|
3767
|
+
ctx.data.classificationReason = reason ?? "";
|
|
3768
|
+
};
|
|
3769
|
+
function parseClassification(prSummary) {
|
|
3770
|
+
if (!prSummary) return null;
|
|
3771
|
+
const classMatch = prSummary.match(/classification:\s*(feature|bug|spec|chore)\b/i);
|
|
3772
|
+
if (!classMatch) return null;
|
|
3773
|
+
const classification = classMatch[1].toLowerCase();
|
|
3774
|
+
const reasonMatch = prSummary.match(/reason:\s*(.+)$/im);
|
|
3775
|
+
const reason = reasonMatch ? reasonMatch[1].trim() : "";
|
|
3776
|
+
return { classification, reason };
|
|
3777
|
+
}
|
|
3778
|
+
function tryAuditComment(issueNumber, body, cwd) {
|
|
3779
|
+
try {
|
|
3780
|
+
execFileSync14("gh", ["issue", "comment", String(issueNumber), "--body", body], {
|
|
3781
|
+
cwd,
|
|
3782
|
+
timeout: API_TIMEOUT_MS6,
|
|
3783
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3784
|
+
});
|
|
3785
|
+
} catch {
|
|
3786
|
+
}
|
|
3787
|
+
}
|
|
3788
|
+
function makeAction2(type, payload) {
|
|
3789
|
+
return { type, payload, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
3790
|
+
}
|
|
3791
|
+
function failedAction(reason) {
|
|
3792
|
+
return { type: "CLASSIFY_FAILED", payload: { reason }, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
3793
|
+
}
|
|
3794
|
+
|
|
3645
3795
|
// src/scripts/postIssueComment.ts
|
|
3646
3796
|
var postIssueComment2 = async (ctx) => {
|
|
3647
3797
|
if (ctx.skipAgent && ctx.output.exitCode !== void 0) return;
|
|
@@ -3756,7 +3906,7 @@ function reviewAction(verdict, payload) {
|
|
|
3756
3906
|
const type = verdict === "PASS" ? "REVIEW_PASS" : verdict === "CONCERNS" ? "REVIEW_CONCERNS" : verdict === "FAIL" ? "REVIEW_FAIL" : "REVIEW_COMPLETED";
|
|
3757
3907
|
return { type, payload: { verdict, ...payload }, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
3758
3908
|
}
|
|
3759
|
-
function
|
|
3909
|
+
function failedAction2(reason) {
|
|
3760
3910
|
return { type: "REVIEW_FAILED", payload: { reason }, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
3761
3911
|
}
|
|
3762
3912
|
var postReviewResult = async (ctx, _profile, agentResult) => {
|
|
@@ -3764,7 +3914,7 @@ var postReviewResult = async (ctx, _profile, agentResult) => {
|
|
|
3764
3914
|
if (!prNumber) {
|
|
3765
3915
|
ctx.output.exitCode = 99;
|
|
3766
3916
|
ctx.output.reason = "review postflight: no PR number in context";
|
|
3767
|
-
ctx.data.action =
|
|
3917
|
+
ctx.data.action = failedAction2(ctx.output.reason);
|
|
3768
3918
|
return;
|
|
3769
3919
|
}
|
|
3770
3920
|
if (!agentResult || agentResult.outcome !== "completed") {
|
|
@@ -3775,7 +3925,7 @@ var postReviewResult = async (ctx, _profile, agentResult) => {
|
|
|
3775
3925
|
}
|
|
3776
3926
|
ctx.output.exitCode = 1;
|
|
3777
3927
|
ctx.output.reason = reason;
|
|
3778
|
-
ctx.data.action =
|
|
3928
|
+
ctx.data.action = failedAction2(reason);
|
|
3779
3929
|
return;
|
|
3780
3930
|
}
|
|
3781
3931
|
const reviewBody = agentResult.finalText.trim();
|
|
@@ -3786,7 +3936,7 @@ var postReviewResult = async (ctx, _profile, agentResult) => {
|
|
|
3786
3936
|
}
|
|
3787
3937
|
ctx.output.exitCode = 1;
|
|
3788
3938
|
ctx.output.reason = "empty review body";
|
|
3789
|
-
ctx.data.action =
|
|
3939
|
+
ctx.data.action = failedAction2("empty review body");
|
|
3790
3940
|
return;
|
|
3791
3941
|
}
|
|
3792
3942
|
try {
|
|
@@ -3795,7 +3945,7 @@ var postReviewResult = async (ctx, _profile, agentResult) => {
|
|
|
3795
3945
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3796
3946
|
ctx.output.exitCode = 4;
|
|
3797
3947
|
ctx.output.reason = `failed to post review comment: ${msg}`;
|
|
3798
|
-
ctx.data.action =
|
|
3948
|
+
ctx.data.action = failedAction2(ctx.output.reason);
|
|
3799
3949
|
return;
|
|
3800
3950
|
}
|
|
3801
3951
|
const verdict = detectVerdict(reviewBody);
|
|
@@ -3811,7 +3961,7 @@ REVIEW_POSTED=https://github.com/${ctx.config.github.owner}/${ctx.config.github.
|
|
|
3811
3961
|
};
|
|
3812
3962
|
|
|
3813
3963
|
// src/scripts/releaseFlow.ts
|
|
3814
|
-
import { execFileSync as
|
|
3964
|
+
import { execFileSync as execFileSync15, spawnSync } from "child_process";
|
|
3815
3965
|
import * as fs18 from "fs";
|
|
3816
3966
|
import * as path16 from "path";
|
|
3817
3967
|
function bumpVersion(current, bump) {
|
|
@@ -3841,7 +3991,7 @@ function generateChangelog(cwd, newVersion, lastTag) {
|
|
|
3841
3991
|
const range = lastTag ? `${lastTag}..HEAD` : "HEAD";
|
|
3842
3992
|
let log = "";
|
|
3843
3993
|
try {
|
|
3844
|
-
log =
|
|
3994
|
+
log = execFileSync15("git", ["log", range, "--pretty=format:%s||%h", "--no-merges"], {
|
|
3845
3995
|
cwd,
|
|
3846
3996
|
encoding: "utf-8",
|
|
3847
3997
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -3898,7 +4048,7 @@ ${entry}${prior.slice(idx + 1)}`);
|
|
|
3898
4048
|
}
|
|
3899
4049
|
}
|
|
3900
4050
|
function git3(args, cwd, timeout = 6e4) {
|
|
3901
|
-
return
|
|
4051
|
+
return execFileSync15("git", args, {
|
|
3902
4052
|
encoding: "utf-8",
|
|
3903
4053
|
timeout,
|
|
3904
4054
|
cwd,
|
|
@@ -4125,12 +4275,12 @@ function fail(ctx, profile, reason) {
|
|
|
4125
4275
|
ctx.data.agentDone = false;
|
|
4126
4276
|
ctx.data.agentFailureReason = reason;
|
|
4127
4277
|
const modeSeg = profile.name.replace(/-/g, "_").toUpperCase();
|
|
4128
|
-
const
|
|
4278
|
+
const failedAction3 = {
|
|
4129
4279
|
type: `${modeSeg}_FAILED`,
|
|
4130
4280
|
payload: { reason },
|
|
4131
4281
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
4132
4282
|
};
|
|
4133
|
-
ctx.data.action =
|
|
4283
|
+
ctx.data.action = failedAction3;
|
|
4134
4284
|
}
|
|
4135
4285
|
function countActionItems(block) {
|
|
4136
4286
|
if (!block.trim()) return 0;
|
|
@@ -4169,12 +4319,12 @@ function fail2(ctx, profile, reason) {
|
|
|
4169
4319
|
ctx.data.agentDone = false;
|
|
4170
4320
|
ctx.data.agentFailureReason = reason;
|
|
4171
4321
|
const modeSeg = profile.name.replace(/-/g, "_").toUpperCase();
|
|
4172
|
-
const
|
|
4322
|
+
const failedAction3 = {
|
|
4173
4323
|
type: `${modeSeg}_FAILED`,
|
|
4174
4324
|
payload: { reason },
|
|
4175
4325
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
4176
4326
|
};
|
|
4177
|
-
ctx.data.action =
|
|
4327
|
+
ctx.data.action = failedAction3;
|
|
4178
4328
|
}
|
|
4179
4329
|
|
|
4180
4330
|
// src/scripts/resolveArtifacts.ts
|
|
@@ -4201,7 +4351,7 @@ var resolveArtifacts = async (ctx, profile) => {
|
|
|
4201
4351
|
};
|
|
4202
4352
|
|
|
4203
4353
|
// src/scripts/resolveFlow.ts
|
|
4204
|
-
import { execFileSync as
|
|
4354
|
+
import { execFileSync as execFileSync16 } from "child_process";
|
|
4205
4355
|
var CONFLICT_DIFF_MAX_BYTES = 4e4;
|
|
4206
4356
|
var resolveFlow = async (ctx) => {
|
|
4207
4357
|
const prNumber = ctx.args.pr;
|
|
@@ -4253,7 +4403,7 @@ var resolveFlow = async (ctx) => {
|
|
|
4253
4403
|
};
|
|
4254
4404
|
function getConflictedFiles(cwd) {
|
|
4255
4405
|
try {
|
|
4256
|
-
const out =
|
|
4406
|
+
const out = execFileSync16("git", ["diff", "--name-only", "--diff-filter=U"], {
|
|
4257
4407
|
encoding: "utf-8",
|
|
4258
4408
|
cwd,
|
|
4259
4409
|
env: { ...process.env, HUSKY: "0" }
|
|
@@ -4268,7 +4418,7 @@ function getConflictMarkersPreview(files, cwd, maxBytes = CONFLICT_DIFF_MAX_BYTE
|
|
|
4268
4418
|
let total = 0;
|
|
4269
4419
|
for (const f of files) {
|
|
4270
4420
|
try {
|
|
4271
|
-
const content =
|
|
4421
|
+
const content = execFileSync16("cat", [f], { encoding: "utf-8", cwd }).toString();
|
|
4272
4422
|
const snippet = `### ${f}
|
|
4273
4423
|
|
|
4274
4424
|
\`\`\`
|
|
@@ -4399,9 +4549,9 @@ function synthesizeAction(ctx) {
|
|
|
4399
4549
|
// src/scripts/setLifecycleLabel.ts
|
|
4400
4550
|
var setLifecycleLabel = async (ctx, _profile, args) => {
|
|
4401
4551
|
const label = args?.label;
|
|
4402
|
-
if (typeof label !== "string" || !label.startsWith(
|
|
4552
|
+
if (typeof label !== "string" || !label.startsWith(KODY_NAMESPACE)) {
|
|
4403
4553
|
process.stderr.write(
|
|
4404
|
-
`[kody2] setLifecycleLabel: missing or invalid "label" arg (must start with "${
|
|
4554
|
+
`[kody2] setLifecycleLabel: missing or invalid "label" arg (must start with "${KODY_NAMESPACE}"): ${String(label)}
|
|
4405
4555
|
`
|
|
4406
4556
|
);
|
|
4407
4557
|
return;
|
|
@@ -4432,8 +4582,8 @@ var skipAgent = async (ctx) => {
|
|
|
4432
4582
|
};
|
|
4433
4583
|
|
|
4434
4584
|
// src/scripts/startFlow.ts
|
|
4435
|
-
import { execFileSync as
|
|
4436
|
-
var
|
|
4585
|
+
import { execFileSync as execFileSync17 } from "child_process";
|
|
4586
|
+
var API_TIMEOUT_MS7 = 3e4;
|
|
4437
4587
|
var startFlow = async (ctx, profile, _agentResult, args) => {
|
|
4438
4588
|
const entry = args?.entry;
|
|
4439
4589
|
if (!entry) {
|
|
@@ -4466,8 +4616,8 @@ function postKody2Comment(target, issueNumber, state, next, cwd) {
|
|
|
4466
4616
|
const sub = target === "pr" && state?.core.prUrl ? "pr" : "issue";
|
|
4467
4617
|
const body = `@kody2 ${next}`;
|
|
4468
4618
|
try {
|
|
4469
|
-
|
|
4470
|
-
timeout:
|
|
4619
|
+
execFileSync17("gh", [sub, "comment", String(targetNumber), "--body", body], {
|
|
4620
|
+
timeout: API_TIMEOUT_MS7,
|
|
4471
4621
|
cwd,
|
|
4472
4622
|
stdio: ["ignore", "pipe", "pipe"]
|
|
4473
4623
|
});
|
|
@@ -4486,7 +4636,7 @@ function parsePr2(url) {
|
|
|
4486
4636
|
}
|
|
4487
4637
|
|
|
4488
4638
|
// src/scripts/syncFlow.ts
|
|
4489
|
-
import { execFileSync as
|
|
4639
|
+
import { execFileSync as execFileSync18 } from "child_process";
|
|
4490
4640
|
var syncFlow = async (ctx) => {
|
|
4491
4641
|
ctx.skipAgent = true;
|
|
4492
4642
|
const prNumber = ctx.args.pr;
|
|
@@ -4545,7 +4695,7 @@ function bail2(ctx, prNumber, reason) {
|
|
|
4545
4695
|
}
|
|
4546
4696
|
function revParseHead(cwd) {
|
|
4547
4697
|
try {
|
|
4548
|
-
return
|
|
4698
|
+
return execFileSync18("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
|
|
4549
4699
|
} catch {
|
|
4550
4700
|
return "";
|
|
4551
4701
|
}
|
|
@@ -4553,9 +4703,9 @@ function revParseHead(cwd) {
|
|
|
4553
4703
|
function pushBranch(branch, cwd) {
|
|
4554
4704
|
const env = { ...process.env, HUSKY: "0", SKIP_HOOKS: "1" };
|
|
4555
4705
|
try {
|
|
4556
|
-
|
|
4706
|
+
execFileSync18("git", ["push", "-u", "origin", branch], { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
|
|
4557
4707
|
} catch {
|
|
4558
|
-
|
|
4708
|
+
execFileSync18("git", ["push", "--force-with-lease", "-u", "origin", branch], {
|
|
4559
4709
|
cwd,
|
|
4560
4710
|
env,
|
|
4561
4711
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -4773,7 +4923,8 @@ var preflightScripts = {
|
|
|
4773
4923
|
resolvePreviewUrl,
|
|
4774
4924
|
composePrompt,
|
|
4775
4925
|
setLifecycleLabel,
|
|
4776
|
-
skipAgent
|
|
4926
|
+
skipAgent,
|
|
4927
|
+
classifyByLabel
|
|
4777
4928
|
};
|
|
4778
4929
|
var postflightScripts = {
|
|
4779
4930
|
parseAgentResult: parseAgentResult2,
|
|
@@ -4795,7 +4946,8 @@ var postflightScripts = {
|
|
|
4795
4946
|
dispatch,
|
|
4796
4947
|
finishFlow,
|
|
4797
4948
|
advanceFlow,
|
|
4798
|
-
persistFlowState
|
|
4949
|
+
persistFlowState,
|
|
4950
|
+
postClassification
|
|
4799
4951
|
};
|
|
4800
4952
|
var allScriptNames = /* @__PURE__ */ new Set([
|
|
4801
4953
|
...Object.keys(preflightScripts),
|
|
@@ -4803,7 +4955,7 @@ var allScriptNames = /* @__PURE__ */ new Set([
|
|
|
4803
4955
|
]);
|
|
4804
4956
|
|
|
4805
4957
|
// src/tools.ts
|
|
4806
|
-
import { execFileSync as
|
|
4958
|
+
import { execFileSync as execFileSync19 } from "child_process";
|
|
4807
4959
|
function verifyCliTools(tools, cwd) {
|
|
4808
4960
|
const out = [];
|
|
4809
4961
|
for (const t of tools) out.push(verifyOne(t, cwd));
|
|
@@ -4836,7 +4988,7 @@ function verifyOne(tool, cwd) {
|
|
|
4836
4988
|
}
|
|
4837
4989
|
function runShell2(cmd, cwd, timeoutMs = 3e4) {
|
|
4838
4990
|
try {
|
|
4839
|
-
|
|
4991
|
+
execFileSync19("sh", ["-c", cmd], { cwd, stdio: "pipe", timeout: timeoutMs });
|
|
4840
4992
|
return true;
|
|
4841
4993
|
} catch {
|
|
4842
4994
|
return false;
|
|
@@ -5166,7 +5318,7 @@ function detectPackageManager2(cwd) {
|
|
|
5166
5318
|
}
|
|
5167
5319
|
function shellOut(cmd, args, cwd, stream = true) {
|
|
5168
5320
|
try {
|
|
5169
|
-
|
|
5321
|
+
execFileSync20(cmd, args, {
|
|
5170
5322
|
cwd,
|
|
5171
5323
|
stdio: stream ? "inherit" : "pipe",
|
|
5172
5324
|
env: { ...process.env, HUSKY: "0", SKIP_HOOKS: "1", CI: process.env.CI ?? "1" }
|
|
@@ -5179,7 +5331,7 @@ function shellOut(cmd, args, cwd, stream = true) {
|
|
|
5179
5331
|
}
|
|
5180
5332
|
function isOnPath(bin) {
|
|
5181
5333
|
try {
|
|
5182
|
-
|
|
5334
|
+
execFileSync20("which", [bin], { stdio: "pipe" });
|
|
5183
5335
|
return true;
|
|
5184
5336
|
} catch {
|
|
5185
5337
|
return false;
|
|
@@ -5213,7 +5365,7 @@ function installLitellmIfNeeded(cwd) {
|
|
|
5213
5365
|
} catch {
|
|
5214
5366
|
}
|
|
5215
5367
|
try {
|
|
5216
|
-
|
|
5368
|
+
execFileSync20("python3", ["-c", "import litellm"], { stdio: "pipe" });
|
|
5217
5369
|
process.stdout.write("\u2192 kody2: litellm already installed\n");
|
|
5218
5370
|
return 0;
|
|
5219
5371
|
} catch {
|
|
@@ -5223,16 +5375,16 @@ function installLitellmIfNeeded(cwd) {
|
|
|
5223
5375
|
}
|
|
5224
5376
|
function configureGitIdentity(cwd) {
|
|
5225
5377
|
try {
|
|
5226
|
-
const name =
|
|
5378
|
+
const name = execFileSync20("git", ["config", "user.name"], { cwd, stdio: "pipe", encoding: "utf-8" }).trim();
|
|
5227
5379
|
if (name) return;
|
|
5228
5380
|
} catch {
|
|
5229
5381
|
}
|
|
5230
5382
|
try {
|
|
5231
|
-
|
|
5383
|
+
execFileSync20("git", ["config", "user.name", "github-actions[bot]"], { cwd, stdio: "pipe" });
|
|
5232
5384
|
} catch {
|
|
5233
5385
|
}
|
|
5234
5386
|
try {
|
|
5235
|
-
|
|
5387
|
+
execFileSync20("git", ["config", "user.email", "41898282+github-actions[bot]@users.noreply.github.com"], {
|
|
5236
5388
|
cwd,
|
|
5237
5389
|
stdio: "pipe"
|
|
5238
5390
|
});
|
|
@@ -5409,9 +5561,9 @@ function commitChatFiles(cwd, sessionId, verbose) {
|
|
|
5409
5561
|
if (paths.length === 0) return;
|
|
5410
5562
|
const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
|
|
5411
5563
|
try {
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5564
|
+
execFileSync21("git", ["add", ...paths], opts);
|
|
5565
|
+
execFileSync21("git", ["commit", "--quiet", "-m", `chat: reply for ${sessionId}`], opts);
|
|
5566
|
+
execFileSync21("git", ["push", "--quiet", "origin", "HEAD"], opts);
|
|
5415
5567
|
} catch (err) {
|
|
5416
5568
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5417
5569
|
process.stderr.write(`[kody2:chat] commit/push skipped: ${msg}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bug",
|
|
3
|
+
"role": "orchestrator",
|
|
3
4
|
"describe": "Sub-orchestrator for bug / enhancement issues — plan → run → review (→ fix on concerns/fail). No agent — the postflight entries ARE the transition table, evaluated top-to-bottom via runWhen.",
|
|
4
5
|
"inputs": [
|
|
5
6
|
{
|
|
@@ -27,6 +28,14 @@
|
|
|
27
28
|
"cliTools": [],
|
|
28
29
|
"scripts": {
|
|
29
30
|
"preflight": [
|
|
31
|
+
{
|
|
32
|
+
"script": "setLifecycleLabel",
|
|
33
|
+
"with": {
|
|
34
|
+
"label": "kody-flow:bug",
|
|
35
|
+
"color": "d73a4a",
|
|
36
|
+
"description": "kody2 flow: bug / enhancement"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
30
39
|
{
|
|
31
40
|
"script": "setLifecycleLabel",
|
|
32
41
|
"with": {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chore",
|
|
3
|
+
"role": "orchestrator",
|
|
3
4
|
"describe": "Sub-orchestrator for chore / docs / dep-bump issues — run → review (→ fix on concerns/fail). Skips planning entirely. No agent.",
|
|
4
5
|
"inputs": [
|
|
5
6
|
{
|
|
@@ -27,6 +28,14 @@
|
|
|
27
28
|
"cliTools": [],
|
|
28
29
|
"scripts": {
|
|
29
30
|
"preflight": [
|
|
31
|
+
{
|
|
32
|
+
"script": "setLifecycleLabel",
|
|
33
|
+
"with": {
|
|
34
|
+
"label": "kody-flow:chore",
|
|
35
|
+
"color": "c5def5",
|
|
36
|
+
"description": "kody2 flow: chore / docs / dep-bump"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
30
39
|
{
|
|
31
40
|
"script": "setLifecycleLabel",
|
|
32
41
|
"with": {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "classify",
|
|
3
|
+
"role": "primitive",
|
|
4
|
+
"describe": "Classify an issue into one of {feature, bug, spec, chore} and dispatch the matching sub-orchestrator. Label-first fast path; LLM fallback when labels don't decide.",
|
|
5
|
+
"inputs": [
|
|
6
|
+
{
|
|
7
|
+
"name": "issue",
|
|
8
|
+
"flag": "--issue",
|
|
9
|
+
"type": "int",
|
|
10
|
+
"required": true,
|
|
11
|
+
"describe": "GitHub issue number to classify."
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"claudeCode": {
|
|
15
|
+
"model": "inherit",
|
|
16
|
+
"permissionMode": "default",
|
|
17
|
+
"maxTurns": null,
|
|
18
|
+
"maxThinkingTokens": null,
|
|
19
|
+
"systemPromptAppend": null,
|
|
20
|
+
"tools": [
|
|
21
|
+
"Read",
|
|
22
|
+
"Bash"
|
|
23
|
+
],
|
|
24
|
+
"hooks": [],
|
|
25
|
+
"skills": [],
|
|
26
|
+
"commands": [],
|
|
27
|
+
"subagents": [],
|
|
28
|
+
"plugins": [],
|
|
29
|
+
"mcpServers": []
|
|
30
|
+
},
|
|
31
|
+
"cliTools": [],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"preflight": [
|
|
34
|
+
{
|
|
35
|
+
"script": "setLifecycleLabel",
|
|
36
|
+
"with": {
|
|
37
|
+
"label": "kody:classifying",
|
|
38
|
+
"color": "0e8a16",
|
|
39
|
+
"description": "kody2: classifying the issue"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{ "script": "loadIssueContext" },
|
|
43
|
+
{ "script": "loadTaskState" },
|
|
44
|
+
{ "script": "classifyByLabel" },
|
|
45
|
+
{ "script": "loadConventions" },
|
|
46
|
+
{ "script": "composePrompt" }
|
|
47
|
+
],
|
|
48
|
+
"postflight": [
|
|
49
|
+
{ "script": "parseAgentResult" },
|
|
50
|
+
{ "script": "postClassification" },
|
|
51
|
+
{ "script": "writeRunSummary" },
|
|
52
|
+
{ "script": "saveTaskState" }
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
"output": {
|
|
56
|
+
"actionTypes": [
|
|
57
|
+
"CLASSIFIED_AS_FEATURE",
|
|
58
|
+
"CLASSIFIED_AS_BUG",
|
|
59
|
+
"CLASSIFIED_AS_SPEC",
|
|
60
|
+
"CLASSIFIED_AS_CHORE",
|
|
61
|
+
"CLASSIFY_FAILED"
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
You are Kody's issue-triage classifier. Your only job: read the issue below and pick ONE of the four flow types.
|
|
2
|
+
|
|
3
|
+
# Repo
|
|
4
|
+
{{repoOwner}}/{{repoName}}, default branch `{{defaultBranch}}`
|
|
5
|
+
|
|
6
|
+
# Issue #{{issue.number}}: {{issue.title}}
|
|
7
|
+
|
|
8
|
+
Labels: {{issue.labelsFormatted}}
|
|
9
|
+
|
|
10
|
+
{{issue.body}}
|
|
11
|
+
|
|
12
|
+
Recent comments (most recent first, truncated):
|
|
13
|
+
{{issue.commentsFormatted}}
|
|
14
|
+
|
|
15
|
+
{{conventionsBlock}}
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Classification rubric
|
|
20
|
+
|
|
21
|
+
Pick **exactly one** of:
|
|
22
|
+
|
|
23
|
+
- **feature** — new user-facing capability, refactor, performance work, or anything where scope is not fully known up front. Multi-file change likely. Use when the issue opens a design space (even if small).
|
|
24
|
+
- **bug** — fix broken behavior, enhancement to existing feature, or any targeted change where the scope is localized and well understood. Skip research; go straight to plan.
|
|
25
|
+
- **spec** — produce a design doc, RFC, architecture proposal, or exploration artifact. No code changes. Terminates at the plan artifact.
|
|
26
|
+
- **chore** — trivial maintenance: docs tweak, dep bump, lint fix, README update. No planning needed.
|
|
27
|
+
|
|
28
|
+
**If the issue ASKS for an RFC / design doc / spec / analysis with no implementation → `spec`.** Beats everything else.
|
|
29
|
+
**If the issue is plainly "fix X" or "add tiny Y to existing Z" with clear boundaries → `bug`.**
|
|
30
|
+
**If the issue is "tweak config / bump dep / fix typo" with no real design choice → `chore`.**
|
|
31
|
+
**Otherwise → `feature`.**
|
|
32
|
+
|
|
33
|
+
# Required output
|
|
34
|
+
|
|
35
|
+
Your FINAL message must be exactly this shape (no extra text before or after):
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
DONE
|
|
39
|
+
COMMIT_MSG: classify: <classification>
|
|
40
|
+
PR_SUMMARY:
|
|
41
|
+
classification: <feature|bug|spec|chore>
|
|
42
|
+
reason: <one sentence explaining the pick, grounded in the issue text>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
# Rules
|
|
46
|
+
|
|
47
|
+
- Read-only. Do NOT modify any file. Do NOT run git or gh.
|
|
48
|
+
- Output `FAILED: <reason>` if the issue is incoherent or ambiguous beyond the rubric.
|
|
49
|
+
- Do not over-think. This is triage, not analysis.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "feature",
|
|
3
|
+
"role": "orchestrator",
|
|
3
4
|
"describe": "Sub-orchestrator for feature / refactor issues — research → plan → run → review (→ fix on concerns/fail). No agent — the postflight entries ARE the transition table, evaluated top-to-bottom via runWhen.",
|
|
4
5
|
"inputs": [
|
|
5
6
|
{
|
|
@@ -27,6 +28,14 @@
|
|
|
27
28
|
"cliTools": [],
|
|
28
29
|
"scripts": {
|
|
29
30
|
"preflight": [
|
|
31
|
+
{
|
|
32
|
+
"script": "setLifecycleLabel",
|
|
33
|
+
"with": {
|
|
34
|
+
"label": "kody-flow:feature",
|
|
35
|
+
"color": "a2eeef",
|
|
36
|
+
"description": "kody2 flow: feature / refactor"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
30
39
|
{
|
|
31
40
|
"script": "setLifecycleLabel",
|
|
32
41
|
"with": {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plan-verify",
|
|
3
|
+
"role": "utility",
|
|
3
4
|
"describe": "Live-test executable. Loads kody-live-marker skill, /kody-live-probe command, kody-live-trace hook, and the bundled test-plugin. Asks the agent to emit confirmation tokens for each feature so Kody2 can validate plugin wiring end-to-end.",
|
|
4
5
|
"inputs": [
|
|
5
6
|
{ "name": "issue", "flag": "--issue", "type": "int", "required": true, "describe": "GitHub issue number to verify against." }
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "research",
|
|
3
|
+
"role": "primitive",
|
|
3
4
|
"describe": "Research an issue: understand the ask, map relevant repo context, and surface clarifying questions + gaps. Read-only — no branches, no commits, no prescribed next steps.",
|
|
4
5
|
"inputs": [
|
|
5
6
|
{
|
|
@@ -67,6 +68,9 @@
|
|
|
67
68
|
},
|
|
68
69
|
{
|
|
69
70
|
"script": "saveTaskState"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"script": "advanceFlow"
|
|
70
74
|
}
|
|
71
75
|
]
|
|
72
76
|
},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spec",
|
|
3
|
+
"role": "orchestrator",
|
|
3
4
|
"describe": "Sub-orchestrator for spec / RFC / design-doc issues — research → plan (stop). Terminates at the plan artifact; no run, no PR. No agent.",
|
|
4
5
|
"inputs": [
|
|
5
6
|
{
|
|
@@ -27,6 +28,14 @@
|
|
|
27
28
|
"cliTools": [],
|
|
28
29
|
"scripts": {
|
|
29
30
|
"preflight": [
|
|
31
|
+
{
|
|
32
|
+
"script": "setLifecycleLabel",
|
|
33
|
+
"with": {
|
|
34
|
+
"label": "kody-flow:spec",
|
|
35
|
+
"color": "7057ff",
|
|
36
|
+
"description": "kody2 flow: spec / RFC / design-doc"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
30
39
|
{
|
|
31
40
|
"script": "setLifecycleLabel",
|
|
32
41
|
"with": {
|
|
@@ -18,7 +18,19 @@ export interface Profile {
|
|
|
18
18
|
name: string
|
|
19
19
|
describe: string
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* Semantic role — what this executable IS, not when it runs.
|
|
22
|
+
* - primitive: single-step agent executor (flow → agent → verify → commit → PR).
|
|
23
|
+
* - orchestrator: no-agent, drives primitives via a postflight transition table.
|
|
24
|
+
* - watch: scheduled observer that inspects repo state and may trigger other executables.
|
|
25
|
+
* - utility: no-agent, one-off administrative work (scaffolding, release, etc.).
|
|
26
|
+
*
|
|
27
|
+
* Roles enforce shape at profile-load time and let help/dispatch treat
|
|
28
|
+
* executables differently by category.
|
|
29
|
+
*/
|
|
30
|
+
role: "primitive" | "orchestrator" | "watch" | "utility"
|
|
31
|
+
/**
|
|
32
|
+
* Execution model — orthogonal to `role`.
|
|
33
|
+
* `oneshot` (default): single invocation on demand.
|
|
22
34
|
* `scheduled`: fires periodically via an external cron (typically GHA
|
|
23
35
|
* `schedule:`). Scheduled profiles must declare a `schedule` cron string.
|
|
24
36
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ui-review",
|
|
3
|
+
"role": "primitive",
|
|
3
4
|
"describe": "UI/UX review of an open PR: browses the running preview with Playwright, compares behavior to diff intent, posts one structured review comment. Read-only on the repo (no commits); writes a throwaway Playwright spec under .kody2/.",
|
|
4
5
|
"kind": "oneshot",
|
|
5
6
|
"inputs": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.55",
|
|
4
4
|
"description": "kody2 — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|