@kody-ade/kody-engine 0.4.456 → 0.4.458
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/kody.js
CHANGED
|
@@ -15,7 +15,7 @@ var init_package = __esm({
|
|
|
15
15
|
"package.json"() {
|
|
16
16
|
package_default = {
|
|
17
17
|
name: "@kody-ade/kody-engine",
|
|
18
|
-
version: "0.4.
|
|
18
|
+
version: "0.4.458",
|
|
19
19
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
|
|
20
20
|
license: "MIT",
|
|
21
21
|
type: "module",
|
|
@@ -8925,12 +8925,7 @@ function validateWorkflow(value, options = {}) {
|
|
|
8925
8925
|
}
|
|
8926
8926
|
validateDataMatch(step.runWhen, `${base}.runWhen`, issues);
|
|
8927
8927
|
if (step.delivery !== void 0 && step.delivery !== "pull-request") {
|
|
8928
|
-
issue(
|
|
8929
|
-
issues,
|
|
8930
|
-
"invalid_delivery",
|
|
8931
|
-
`${base}.delivery`,
|
|
8932
|
-
"workflow step delivery must be pull-request"
|
|
8933
|
-
);
|
|
8928
|
+
issue(issues, "invalid_delivery", `${base}.delivery`, "workflow step delivery must be pull-request");
|
|
8934
8929
|
}
|
|
8935
8930
|
if (step.input !== void 0 && !isJsonValue(step.input)) {
|
|
8936
8931
|
issue(issues, "invalid_input", `${base}.input`, "workflow step input must be one JSON value");
|
|
@@ -13062,124 +13057,6 @@ var init_dispatch = __esm({
|
|
|
13062
13057
|
}
|
|
13063
13058
|
});
|
|
13064
13059
|
|
|
13065
|
-
// src/scripts/dispatchCapabilityFileTicks.ts
|
|
13066
|
-
var dispatchCapabilityFileTicks;
|
|
13067
|
-
var init_dispatchCapabilityFileTicks = __esm({
|
|
13068
|
-
"src/scripts/dispatchCapabilityFileTicks.ts"() {
|
|
13069
|
-
"use strict";
|
|
13070
|
-
dispatchCapabilityFileTicks = async (ctx) => {
|
|
13071
|
-
ctx.skipAgent = true;
|
|
13072
|
-
ctx.data.jobTickResults = [];
|
|
13073
|
-
ctx.output.exitCode = 0;
|
|
13074
|
-
ctx.output.reason = "capability scheduling is owned by goals and loops";
|
|
13075
|
-
process.stdout.write("[jobs] no flat capability fan-out; goals and loops own scheduled capability decisions\n");
|
|
13076
|
-
};
|
|
13077
|
-
}
|
|
13078
|
-
});
|
|
13079
|
-
|
|
13080
|
-
// src/scripts/dispatchCapabilityTicks.ts
|
|
13081
|
-
function listIssuesByLabel(label, cwd) {
|
|
13082
|
-
let raw = "";
|
|
13083
|
-
try {
|
|
13084
|
-
raw = gh(["issue", "list", "--state", "open", "--label", label, "--limit", "100", "--json", "number,title"], {
|
|
13085
|
-
cwd
|
|
13086
|
-
});
|
|
13087
|
-
} catch {
|
|
13088
|
-
return [];
|
|
13089
|
-
}
|
|
13090
|
-
let list;
|
|
13091
|
-
try {
|
|
13092
|
-
list = JSON.parse(raw);
|
|
13093
|
-
} catch {
|
|
13094
|
-
return [];
|
|
13095
|
-
}
|
|
13096
|
-
if (!Array.isArray(list)) return [];
|
|
13097
|
-
return list.filter((x) => typeof x.number === "number" && typeof x.title === "string").map((x) => ({ number: x.number, title: x.title }));
|
|
13098
|
-
}
|
|
13099
|
-
var dispatchCapabilityTicks;
|
|
13100
|
-
var init_dispatchCapabilityTicks = __esm({
|
|
13101
|
-
"src/scripts/dispatchCapabilityTicks.ts"() {
|
|
13102
|
-
"use strict";
|
|
13103
|
-
init_issue();
|
|
13104
|
-
init_job();
|
|
13105
|
-
dispatchCapabilityTicks = async (ctx, _profile, args) => {
|
|
13106
|
-
ctx.skipAgent = true;
|
|
13107
|
-
const label = String(args?.label ?? "");
|
|
13108
|
-
const targetImplementation = String(args?.targetImplementation ?? "");
|
|
13109
|
-
if (!label) throw new Error("dispatchCapabilityTicks: `with.label` is required");
|
|
13110
|
-
if (!targetImplementation) throw new Error("dispatchCapabilityTicks: `with.targetImplementation` is required");
|
|
13111
|
-
const issueArg = String(args?.issueArg ?? "issue");
|
|
13112
|
-
const issues = listIssuesByLabel(label, ctx.cwd);
|
|
13113
|
-
ctx.data.jobIssueCount = issues.length;
|
|
13114
|
-
if (issues.length === 0) {
|
|
13115
|
-
process.stdout.write(`[jobs] no open issues with label "${label}"
|
|
13116
|
-
`);
|
|
13117
|
-
return;
|
|
13118
|
-
}
|
|
13119
|
-
process.stdout.write(`[jobs] ticking ${issues.length} issue(s) via ${targetImplementation}
|
|
13120
|
-
`);
|
|
13121
|
-
const results = [];
|
|
13122
|
-
for (const issue2 of issues) {
|
|
13123
|
-
process.stdout.write(`[jobs] \u2192 tick #${issue2.number}: ${issue2.title}
|
|
13124
|
-
`);
|
|
13125
|
-
try {
|
|
13126
|
-
const out = await runJob(
|
|
13127
|
-
mintScheduledJob({
|
|
13128
|
-
capability: targetImplementation,
|
|
13129
|
-
implementation: targetImplementation,
|
|
13130
|
-
cliArgs: { [issueArg]: issue2.number }
|
|
13131
|
-
}),
|
|
13132
|
-
{ cwd: ctx.cwd, config: ctx.config, verbose: ctx.verbose, quiet: ctx.quiet, chain: false }
|
|
13133
|
-
);
|
|
13134
|
-
results.push({ issue: issue2.number, exitCode: out.exitCode, reason: out.reason });
|
|
13135
|
-
if (out.exitCode !== 0) {
|
|
13136
|
-
process.stderr.write(`[jobs] tick #${issue2.number} failed (exit ${out.exitCode}): ${out.reason ?? ""}
|
|
13137
|
-
`);
|
|
13138
|
-
}
|
|
13139
|
-
} catch (err) {
|
|
13140
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
13141
|
-
process.stderr.write(`[jobs] tick #${issue2.number} crashed: ${msg}
|
|
13142
|
-
`);
|
|
13143
|
-
results.push({ issue: issue2.number, exitCode: 99, reason: msg });
|
|
13144
|
-
}
|
|
13145
|
-
}
|
|
13146
|
-
ctx.data.jobTickResults = results;
|
|
13147
|
-
ctx.output.exitCode = 0;
|
|
13148
|
-
};
|
|
13149
|
-
}
|
|
13150
|
-
});
|
|
13151
|
-
|
|
13152
|
-
// src/scripts/dispatchClassified.ts
|
|
13153
|
-
var VALID_CLASSES2, dispatchClassified;
|
|
13154
|
-
var init_dispatchClassified = __esm({
|
|
13155
|
-
"src/scripts/dispatchClassified.ts"() {
|
|
13156
|
-
"use strict";
|
|
13157
|
-
init_registry();
|
|
13158
|
-
init_state();
|
|
13159
|
-
init_saveTaskState();
|
|
13160
|
-
VALID_CLASSES2 = /* @__PURE__ */ new Set(["feature", "bug", "spec", "chore"]);
|
|
13161
|
-
dispatchClassified = async (ctx, profile) => {
|
|
13162
|
-
const issueNumber = ctx.args.issue;
|
|
13163
|
-
if (!issueNumber) return;
|
|
13164
|
-
const classification = ctx.data.classification;
|
|
13165
|
-
if (!classification || !VALID_CLASSES2.has(classification)) return;
|
|
13166
|
-
const action = ctx.data.action;
|
|
13167
|
-
if (!action) return;
|
|
13168
|
-
const base = typeof ctx.args.base === "string" && ctx.args.base.length > 0 ? ctx.args.base : void 0;
|
|
13169
|
-
const state = ctx.data.taskState ?? emptyState();
|
|
13170
|
-
const nextState = reduce(state, "classify", action, void 0, profile.agent, jobMetaFromData(ctx.data));
|
|
13171
|
-
ctx.data.taskState = nextState;
|
|
13172
|
-
ctx.data.taskStateRendered = renderStateComment(nextState);
|
|
13173
|
-
await writeTaskState("issue", issueNumber, nextState, ctx.cwd, ctx.config);
|
|
13174
|
-
const cliArgs = { issue: issueNumber };
|
|
13175
|
-
if (base && getProfileInputs(classification)?.some((i) => i.name === "base")) {
|
|
13176
|
-
cliArgs.base = base;
|
|
13177
|
-
}
|
|
13178
|
-
ctx.output.nextDispatch = { action: classification, cliArgs };
|
|
13179
|
-
};
|
|
13180
|
-
}
|
|
13181
|
-
});
|
|
13182
|
-
|
|
13183
13060
|
// src/goal/agencyModelRepository.ts
|
|
13184
13061
|
import {
|
|
13185
13062
|
createAgentDefinition,
|
|
@@ -13855,72 +13732,256 @@ var init_dispatchAgencyLoops = __esm({
|
|
|
13855
13732
|
}
|
|
13856
13733
|
});
|
|
13857
13734
|
|
|
13858
|
-
// src/
|
|
13859
|
-
|
|
13860
|
-
|
|
13861
|
-
|
|
13862
|
-
|
|
13863
|
-
|
|
13864
|
-
|
|
13865
|
-
|
|
13866
|
-
|
|
13867
|
-
|
|
13868
|
-
|
|
13869
|
-
|
|
13870
|
-
if (targetKind !== "workflow" && targetKind !== "capability" || typeof targetId !== "string" || !ID.test(targetId)) {
|
|
13871
|
-
return null;
|
|
13735
|
+
// src/scripts/dispatchCapabilityFileTicks.ts
|
|
13736
|
+
var dispatchCapabilityFileTicks;
|
|
13737
|
+
var init_dispatchCapabilityFileTicks = __esm({
|
|
13738
|
+
"src/scripts/dispatchCapabilityFileTicks.ts"() {
|
|
13739
|
+
"use strict";
|
|
13740
|
+
dispatchCapabilityFileTicks = async (ctx) => {
|
|
13741
|
+
ctx.skipAgent = true;
|
|
13742
|
+
ctx.data.jobTickResults = [];
|
|
13743
|
+
ctx.output.exitCode = 0;
|
|
13744
|
+
ctx.output.reason = "capability scheduling is owned by goals and loops";
|
|
13745
|
+
process.stdout.write("[jobs] no flat capability fan-out; goals and loops own scheduled capability decisions\n");
|
|
13746
|
+
};
|
|
13872
13747
|
}
|
|
13873
|
-
|
|
13874
|
-
|
|
13875
|
-
|
|
13876
|
-
|
|
13877
|
-
|
|
13878
|
-
|
|
13879
|
-
|
|
13880
|
-
|
|
13881
|
-
|
|
13748
|
+
});
|
|
13749
|
+
|
|
13750
|
+
// src/scripts/dispatchCapabilityTicks.ts
|
|
13751
|
+
function listIssuesByLabel(label, cwd) {
|
|
13752
|
+
let raw = "";
|
|
13753
|
+
try {
|
|
13754
|
+
raw = gh(["issue", "list", "--state", "open", "--label", label, "--limit", "100", "--json", "number,title"], {
|
|
13755
|
+
cwd
|
|
13756
|
+
});
|
|
13757
|
+
} catch {
|
|
13758
|
+
return [];
|
|
13759
|
+
}
|
|
13760
|
+
let list;
|
|
13761
|
+
try {
|
|
13762
|
+
list = JSON.parse(raw);
|
|
13763
|
+
} catch {
|
|
13764
|
+
return [];
|
|
13765
|
+
}
|
|
13766
|
+
if (!Array.isArray(list)) return [];
|
|
13767
|
+
return list.filter((x) => typeof x.number === "number" && typeof x.title === "string").map((x) => ({ number: x.number, title: x.title }));
|
|
13882
13768
|
}
|
|
13883
|
-
|
|
13884
|
-
|
|
13885
|
-
|
|
13886
|
-
|
|
13887
|
-
|
|
13888
|
-
|
|
13889
|
-
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
|
|
13769
|
+
var dispatchCapabilityTicks;
|
|
13770
|
+
var init_dispatchCapabilityTicks = __esm({
|
|
13771
|
+
"src/scripts/dispatchCapabilityTicks.ts"() {
|
|
13772
|
+
"use strict";
|
|
13773
|
+
init_issue();
|
|
13774
|
+
init_job();
|
|
13775
|
+
dispatchCapabilityTicks = async (ctx, _profile, args) => {
|
|
13776
|
+
ctx.skipAgent = true;
|
|
13777
|
+
const label = String(args?.label ?? "");
|
|
13778
|
+
const targetImplementation = String(args?.targetImplementation ?? "");
|
|
13779
|
+
if (!label) throw new Error("dispatchCapabilityTicks: `with.label` is required");
|
|
13780
|
+
if (!targetImplementation) throw new Error("dispatchCapabilityTicks: `with.targetImplementation` is required");
|
|
13781
|
+
const issueArg = String(args?.issueArg ?? "issue");
|
|
13782
|
+
const issues = listIssuesByLabel(label, ctx.cwd);
|
|
13783
|
+
ctx.data.jobIssueCount = issues.length;
|
|
13784
|
+
if (issues.length === 0) {
|
|
13785
|
+
process.stdout.write(`[jobs] no open issues with label "${label}"
|
|
13893
13786
|
`);
|
|
13894
|
-
|
|
13895
|
-
|
|
13787
|
+
return;
|
|
13788
|
+
}
|
|
13789
|
+
process.stdout.write(`[jobs] ticking ${issues.length} issue(s) via ${targetImplementation}
|
|
13896
13790
|
`);
|
|
13897
|
-
|
|
13898
|
-
|
|
13899
|
-
|
|
13900
|
-
|
|
13901
|
-
|
|
13902
|
-
|
|
13903
|
-
|
|
13904
|
-
|
|
13905
|
-
|
|
13906
|
-
|
|
13907
|
-
|
|
13908
|
-
|
|
13909
|
-
|
|
13910
|
-
|
|
13911
|
-
|
|
13912
|
-
|
|
13913
|
-
|
|
13914
|
-
|
|
13915
|
-
|
|
13916
|
-
|
|
13917
|
-
|
|
13918
|
-
} catch {
|
|
13919
|
-
process.stderr.write(`[kody] unreadable simple Loop definition: ${filePath}
|
|
13791
|
+
const results = [];
|
|
13792
|
+
for (const issue2 of issues) {
|
|
13793
|
+
process.stdout.write(`[jobs] \u2192 tick #${issue2.number}: ${issue2.title}
|
|
13794
|
+
`);
|
|
13795
|
+
try {
|
|
13796
|
+
const out = await runJob(
|
|
13797
|
+
mintScheduledJob({
|
|
13798
|
+
capability: targetImplementation,
|
|
13799
|
+
implementation: targetImplementation,
|
|
13800
|
+
cliArgs: { [issueArg]: issue2.number }
|
|
13801
|
+
}),
|
|
13802
|
+
{ cwd: ctx.cwd, config: ctx.config, verbose: ctx.verbose, quiet: ctx.quiet, chain: false }
|
|
13803
|
+
);
|
|
13804
|
+
results.push({ issue: issue2.number, exitCode: out.exitCode, reason: out.reason });
|
|
13805
|
+
if (out.exitCode !== 0) {
|
|
13806
|
+
process.stderr.write(`[jobs] tick #${issue2.number} failed (exit ${out.exitCode}): ${out.reason ?? ""}
|
|
13807
|
+
`);
|
|
13808
|
+
}
|
|
13809
|
+
} catch (err) {
|
|
13810
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
13811
|
+
process.stderr.write(`[jobs] tick #${issue2.number} crashed: ${msg}
|
|
13920
13812
|
`);
|
|
13813
|
+
results.push({ issue: issue2.number, exitCode: 99, reason: msg });
|
|
13814
|
+
}
|
|
13921
13815
|
}
|
|
13922
|
-
|
|
13923
|
-
|
|
13816
|
+
ctx.data.jobTickResults = results;
|
|
13817
|
+
ctx.output.exitCode = 0;
|
|
13818
|
+
};
|
|
13819
|
+
}
|
|
13820
|
+
});
|
|
13821
|
+
|
|
13822
|
+
// src/scripts/dispatchClassified.ts
|
|
13823
|
+
var VALID_CLASSES2, dispatchClassified;
|
|
13824
|
+
var init_dispatchClassified = __esm({
|
|
13825
|
+
"src/scripts/dispatchClassified.ts"() {
|
|
13826
|
+
"use strict";
|
|
13827
|
+
init_registry();
|
|
13828
|
+
init_state();
|
|
13829
|
+
init_saveTaskState();
|
|
13830
|
+
VALID_CLASSES2 = /* @__PURE__ */ new Set(["feature", "bug", "spec", "chore"]);
|
|
13831
|
+
dispatchClassified = async (ctx, profile) => {
|
|
13832
|
+
const issueNumber = ctx.args.issue;
|
|
13833
|
+
if (!issueNumber) return;
|
|
13834
|
+
const classification = ctx.data.classification;
|
|
13835
|
+
if (!classification || !VALID_CLASSES2.has(classification)) return;
|
|
13836
|
+
const action = ctx.data.action;
|
|
13837
|
+
if (!action) return;
|
|
13838
|
+
const base = typeof ctx.args.base === "string" && ctx.args.base.length > 0 ? ctx.args.base : void 0;
|
|
13839
|
+
const state = ctx.data.taskState ?? emptyState();
|
|
13840
|
+
const nextState = reduce(state, "classify", action, void 0, profile.agent, jobMetaFromData(ctx.data));
|
|
13841
|
+
ctx.data.taskState = nextState;
|
|
13842
|
+
ctx.data.taskStateRendered = renderStateComment(nextState);
|
|
13843
|
+
await writeTaskState("issue", issueNumber, nextState, ctx.cwd, ctx.config);
|
|
13844
|
+
const cliArgs = { issue: issueNumber };
|
|
13845
|
+
if (base && getProfileInputs(classification)?.some((i) => i.name === "base")) {
|
|
13846
|
+
cliArgs.base = base;
|
|
13847
|
+
}
|
|
13848
|
+
ctx.output.nextDispatch = { action: classification, cliArgs };
|
|
13849
|
+
};
|
|
13850
|
+
}
|
|
13851
|
+
});
|
|
13852
|
+
|
|
13853
|
+
// src/jobIdentity.ts
|
|
13854
|
+
function stableJobKey(job) {
|
|
13855
|
+
const capability = job.workflow ?? job.capability ?? job.action;
|
|
13856
|
+
const implementation = job.implementation ?? capability ?? "unknown";
|
|
13857
|
+
if (job.flavor === "scheduled" && job.capability) return `scheduled:${job.capability}:${implementation}`;
|
|
13858
|
+
const target = typeof job.target === "number" ? job.target : targetFromCliArgs(job.cliArgs);
|
|
13859
|
+
const work = capability && implementation && implementation !== capability ? `${capability}:${implementation}` : capability ?? implementation;
|
|
13860
|
+
return target === void 0 ? `${job.flavor}:${work}` : `${job.flavor}:${work}:${target}`;
|
|
13861
|
+
}
|
|
13862
|
+
function targetFromCliArgs(cliArgs) {
|
|
13863
|
+
if (!cliArgs) return void 0;
|
|
13864
|
+
for (const key of ["issue", "pr", "target", "issue_number"]) {
|
|
13865
|
+
const value = cliArgs[key];
|
|
13866
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
13867
|
+
}
|
|
13868
|
+
return void 0;
|
|
13869
|
+
}
|
|
13870
|
+
var init_jobIdentity = __esm({
|
|
13871
|
+
"src/jobIdentity.ts"() {
|
|
13872
|
+
"use strict";
|
|
13873
|
+
}
|
|
13874
|
+
});
|
|
13875
|
+
|
|
13876
|
+
// src/scripts/dispatchNextTaskJob.ts
|
|
13877
|
+
function taskJobToJob(job, issueArg) {
|
|
13878
|
+
const target = typeof job.target === "number" ? job.target : typeof issueArg === "number" ? issueArg : void 0;
|
|
13879
|
+
return {
|
|
13880
|
+
capability: job.capability ?? job.implementation,
|
|
13881
|
+
implementation: job.implementation,
|
|
13882
|
+
...job.reason ? { why: job.reason } : {},
|
|
13883
|
+
...job.agent ? { agent: job.agent } : {},
|
|
13884
|
+
...job.schedule ? { schedule: job.schedule } : {},
|
|
13885
|
+
...typeof target === "number" ? { target, cliArgs: { issue: target } } : { cliArgs: {} },
|
|
13886
|
+
flavor: job.flavor ?? "instant"
|
|
13887
|
+
};
|
|
13888
|
+
}
|
|
13889
|
+
function isJob(input) {
|
|
13890
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) return false;
|
|
13891
|
+
const job = input;
|
|
13892
|
+
return (typeof job.capability === "string" || typeof job.action === "string") && (job.flavor === "instant" || job.flavor === "scheduled") && (!job.cliArgs || typeof job.cliArgs === "object" && !Array.isArray(job.cliArgs));
|
|
13893
|
+
}
|
|
13894
|
+
var dispatchNextTaskJob;
|
|
13895
|
+
var init_dispatchNextTaskJob = __esm({
|
|
13896
|
+
"src/scripts/dispatchNextTaskJob.ts"() {
|
|
13897
|
+
"use strict";
|
|
13898
|
+
init_jobIdentity();
|
|
13899
|
+
init_state();
|
|
13900
|
+
dispatchNextTaskJob = async (ctx, profile) => {
|
|
13901
|
+
const state = ctx.data.taskState ?? emptyState();
|
|
13902
|
+
const ids = Array.isArray(ctx.data.plannedTaskJobIds) ? ctx.data.plannedTaskJobIds.filter((id) => typeof id === "string") : void 0;
|
|
13903
|
+
const next = nextPendingTaskJob(state, ids);
|
|
13904
|
+
ctx.skipAgent = true;
|
|
13905
|
+
if (!next) {
|
|
13906
|
+
ctx.output.exitCode = 0;
|
|
13907
|
+
ctx.output.reason = "all planned task jobs are complete";
|
|
13908
|
+
return;
|
|
13909
|
+
}
|
|
13910
|
+
const plannedJobs = Array.isArray(ctx.data.plannedTaskJobs) ? ctx.data.plannedTaskJobs.filter(isJob) : [];
|
|
13911
|
+
ctx.output.nextJob = plannedJobs.find((job) => stableJobKey(job) === next.id) ?? taskJobToJob(next, ctx.args.issue);
|
|
13912
|
+
if (typeof ctx.args.issue === "number") {
|
|
13913
|
+
ctx.output.afterNextJob = { action: profile.action ?? profile.name, cliArgs: { issue: ctx.args.issue } };
|
|
13914
|
+
}
|
|
13915
|
+
};
|
|
13916
|
+
}
|
|
13917
|
+
});
|
|
13918
|
+
|
|
13919
|
+
// src/loopDefinitions.ts
|
|
13920
|
+
import * as fs36 from "fs";
|
|
13921
|
+
import * as path34 from "path";
|
|
13922
|
+
function normalizeLoopDefinition(value) {
|
|
13923
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
13924
|
+
const raw = value;
|
|
13925
|
+
if (Object.keys(raw).some((key) => !["id", "trigger", "target", "input", "enabled"].includes(key))) return null;
|
|
13926
|
+
if (typeof raw.id !== "string" || !ID.test(raw.id)) return null;
|
|
13927
|
+
if (typeof raw.enabled !== "boolean") return null;
|
|
13928
|
+
if (!isObject(raw.input) || !isObject(raw.trigger) || !isObject(raw.target)) return null;
|
|
13929
|
+
const targetKind = raw.target.kind;
|
|
13930
|
+
const targetId = raw.target.id;
|
|
13931
|
+
if (targetKind !== "workflow" && targetKind !== "capability" || typeof targetId !== "string" || !ID.test(targetId)) {
|
|
13932
|
+
return null;
|
|
13933
|
+
}
|
|
13934
|
+
const trigger = normalizeTrigger(raw.trigger);
|
|
13935
|
+
if (!trigger) return null;
|
|
13936
|
+
return {
|
|
13937
|
+
id: raw.id,
|
|
13938
|
+
trigger,
|
|
13939
|
+
target: { kind: targetKind, id: targetId },
|
|
13940
|
+
input: raw.input,
|
|
13941
|
+
enabled: raw.enabled
|
|
13942
|
+
};
|
|
13943
|
+
}
|
|
13944
|
+
function readLoopDefinition(cwd, id) {
|
|
13945
|
+
if (!ID.test(id)) return null;
|
|
13946
|
+
const roots = loopRoots(cwd);
|
|
13947
|
+
for (const root of roots) {
|
|
13948
|
+
const filePath = path34.join(root, "loops", id, "loop.json");
|
|
13949
|
+
if (!fs36.existsSync(filePath)) continue;
|
|
13950
|
+
try {
|
|
13951
|
+
const loop = normalizeLoopDefinition(JSON.parse(fs36.readFileSync(filePath, "utf8")));
|
|
13952
|
+
if (loop?.id === id) return loop;
|
|
13953
|
+
process.stderr.write(`[kody] invalid simple Loop definition: ${filePath}
|
|
13954
|
+
`);
|
|
13955
|
+
} catch {
|
|
13956
|
+
process.stderr.write(`[kody] unreadable simple Loop definition: ${filePath}
|
|
13957
|
+
`);
|
|
13958
|
+
}
|
|
13959
|
+
}
|
|
13960
|
+
process.stderr.write(
|
|
13961
|
+
`[kody] simple Loop not found: ${id} (${roots.map((root) => path34.join(root, "loops", id, "loop.json")).join(", ")})
|
|
13962
|
+
`
|
|
13963
|
+
);
|
|
13964
|
+
return null;
|
|
13965
|
+
}
|
|
13966
|
+
function listLoopDefinitions(cwd) {
|
|
13967
|
+
const roots = loopRoots(cwd);
|
|
13968
|
+
const byId = /* @__PURE__ */ new Map();
|
|
13969
|
+
for (const root of roots.reverse()) {
|
|
13970
|
+
const loopsDir = path34.join(root, "loops");
|
|
13971
|
+
if (!fs36.existsSync(loopsDir)) continue;
|
|
13972
|
+
for (const id of fs36.readdirSync(loopsDir).sort()) {
|
|
13973
|
+
if (!ID.test(id)) continue;
|
|
13974
|
+
const filePath = path34.join(loopsDir, id, "loop.json");
|
|
13975
|
+
if (!fs36.existsSync(filePath)) continue;
|
|
13976
|
+
try {
|
|
13977
|
+
const loop = normalizeLoopDefinition(JSON.parse(fs36.readFileSync(filePath, "utf8")));
|
|
13978
|
+
if (loop?.id === id) byId.set(id, loop);
|
|
13979
|
+
} catch {
|
|
13980
|
+
process.stderr.write(`[kody] unreadable simple Loop definition: ${filePath}
|
|
13981
|
+
`);
|
|
13982
|
+
}
|
|
13983
|
+
}
|
|
13984
|
+
}
|
|
13924
13985
|
return [...byId.values()].sort((left, right) => left.id.localeCompare(right.id));
|
|
13925
13986
|
}
|
|
13926
13987
|
function loopRoots(cwd) {
|
|
@@ -14080,72 +14141,6 @@ var init_dispatchSimpleLoops = __esm({
|
|
|
14080
14141
|
}
|
|
14081
14142
|
});
|
|
14082
14143
|
|
|
14083
|
-
// src/jobIdentity.ts
|
|
14084
|
-
function stableJobKey(job) {
|
|
14085
|
-
const capability = job.workflow ?? job.capability ?? job.action;
|
|
14086
|
-
const implementation = job.implementation ?? capability ?? "unknown";
|
|
14087
|
-
if (job.flavor === "scheduled" && job.capability) return `scheduled:${job.capability}:${implementation}`;
|
|
14088
|
-
const target = typeof job.target === "number" ? job.target : targetFromCliArgs(job.cliArgs);
|
|
14089
|
-
const work = capability && implementation && implementation !== capability ? `${capability}:${implementation}` : capability ?? implementation;
|
|
14090
|
-
return target === void 0 ? `${job.flavor}:${work}` : `${job.flavor}:${work}:${target}`;
|
|
14091
|
-
}
|
|
14092
|
-
function targetFromCliArgs(cliArgs) {
|
|
14093
|
-
if (!cliArgs) return void 0;
|
|
14094
|
-
for (const key of ["issue", "pr", "target", "issue_number"]) {
|
|
14095
|
-
const value = cliArgs[key];
|
|
14096
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
14097
|
-
}
|
|
14098
|
-
return void 0;
|
|
14099
|
-
}
|
|
14100
|
-
var init_jobIdentity = __esm({
|
|
14101
|
-
"src/jobIdentity.ts"() {
|
|
14102
|
-
"use strict";
|
|
14103
|
-
}
|
|
14104
|
-
});
|
|
14105
|
-
|
|
14106
|
-
// src/scripts/dispatchNextTaskJob.ts
|
|
14107
|
-
function taskJobToJob(job, issueArg) {
|
|
14108
|
-
const target = typeof job.target === "number" ? job.target : typeof issueArg === "number" ? issueArg : void 0;
|
|
14109
|
-
return {
|
|
14110
|
-
capability: job.capability ?? job.implementation,
|
|
14111
|
-
implementation: job.implementation,
|
|
14112
|
-
...job.reason ? { why: job.reason } : {},
|
|
14113
|
-
...job.agent ? { agent: job.agent } : {},
|
|
14114
|
-
...job.schedule ? { schedule: job.schedule } : {},
|
|
14115
|
-
...typeof target === "number" ? { target, cliArgs: { issue: target } } : { cliArgs: {} },
|
|
14116
|
-
flavor: job.flavor ?? "instant"
|
|
14117
|
-
};
|
|
14118
|
-
}
|
|
14119
|
-
function isJob(input) {
|
|
14120
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) return false;
|
|
14121
|
-
const job = input;
|
|
14122
|
-
return (typeof job.capability === "string" || typeof job.action === "string") && (job.flavor === "instant" || job.flavor === "scheduled") && (!job.cliArgs || typeof job.cliArgs === "object" && !Array.isArray(job.cliArgs));
|
|
14123
|
-
}
|
|
14124
|
-
var dispatchNextTaskJob;
|
|
14125
|
-
var init_dispatchNextTaskJob = __esm({
|
|
14126
|
-
"src/scripts/dispatchNextTaskJob.ts"() {
|
|
14127
|
-
"use strict";
|
|
14128
|
-
init_jobIdentity();
|
|
14129
|
-
init_state();
|
|
14130
|
-
dispatchNextTaskJob = async (ctx, profile) => {
|
|
14131
|
-
const state = ctx.data.taskState ?? emptyState();
|
|
14132
|
-
const ids = Array.isArray(ctx.data.plannedTaskJobIds) ? ctx.data.plannedTaskJobIds.filter((id) => typeof id === "string") : void 0;
|
|
14133
|
-
const next = nextPendingTaskJob(state, ids);
|
|
14134
|
-
ctx.skipAgent = true;
|
|
14135
|
-
if (!next) {
|
|
14136
|
-
ctx.output.exitCode = 0;
|
|
14137
|
-
ctx.output.reason = "all planned task jobs are complete";
|
|
14138
|
-
return;
|
|
14139
|
-
}
|
|
14140
|
-
const plannedJobs = Array.isArray(ctx.data.plannedTaskJobs) ? ctx.data.plannedTaskJobs.filter(isJob) : [];
|
|
14141
|
-
ctx.output.nextJob = plannedJobs.find((job) => stableJobKey(job) === next.id) ?? taskJobToJob(next, ctx.args.issue);
|
|
14142
|
-
if (typeof ctx.args.issue === "number") {
|
|
14143
|
-
ctx.output.afterNextJob = { action: profile.action ?? profile.name, cliArgs: { issue: ctx.args.issue } };
|
|
14144
|
-
}
|
|
14145
|
-
};
|
|
14146
|
-
}
|
|
14147
|
-
});
|
|
14148
|
-
|
|
14149
14144
|
// src/pr.ts
|
|
14150
14145
|
import { execFileSync as execFileSync10 } from "child_process";
|
|
14151
14146
|
function prMergeStatus(prNumber, cwd) {
|
|
@@ -15451,139 +15446,6 @@ var init_loadCapabilityState = __esm({
|
|
|
15451
15446
|
}
|
|
15452
15447
|
});
|
|
15453
15448
|
|
|
15454
|
-
// src/scripts/loadSimpleCapability.ts
|
|
15455
|
-
import * as fs40 from "fs";
|
|
15456
|
-
import * as path37 from "path";
|
|
15457
|
-
function parseInput(supplied) {
|
|
15458
|
-
if (typeof supplied !== "string") return supplied;
|
|
15459
|
-
try {
|
|
15460
|
-
return JSON.parse(supplied);
|
|
15461
|
-
} catch {
|
|
15462
|
-
return parseFlagInput(supplied) ?? supplied;
|
|
15463
|
-
}
|
|
15464
|
-
}
|
|
15465
|
-
function parseFlagInput(value) {
|
|
15466
|
-
const tokens = value.trim().split(/\s+/).filter(Boolean);
|
|
15467
|
-
if (!tokens.some((token) => token.startsWith("--"))) return null;
|
|
15468
|
-
const input = {};
|
|
15469
|
-
const text2 = [];
|
|
15470
|
-
for (let index = 0; index < tokens.length; index += 1) {
|
|
15471
|
-
const token = tokens[index];
|
|
15472
|
-
if (!token.startsWith("--") || token.length === 2) {
|
|
15473
|
-
text2.push(token);
|
|
15474
|
-
continue;
|
|
15475
|
-
}
|
|
15476
|
-
const equalAt = token.indexOf("=");
|
|
15477
|
-
const name = equalAt >= 0 ? token.slice(2, equalAt) : token.slice(2);
|
|
15478
|
-
const next = equalAt >= 0 ? token.slice(equalAt + 1) : tokens[index + 1];
|
|
15479
|
-
if (equalAt < 0 && next && !next.startsWith("--")) index += 1;
|
|
15480
|
-
input[name] = next && !next.startsWith("--") ? scalar(next) : true;
|
|
15481
|
-
}
|
|
15482
|
-
if (text2.length > 0) input.request = text2.join(" ");
|
|
15483
|
-
return input;
|
|
15484
|
-
}
|
|
15485
|
-
function scalar(value) {
|
|
15486
|
-
if (value === "true" || value === "false") return value === "true";
|
|
15487
|
-
if (/^-?\d+$/.test(value)) return Number(value);
|
|
15488
|
-
return value;
|
|
15489
|
-
}
|
|
15490
|
-
function capabilityEnvironment(input) {
|
|
15491
|
-
const environment = {
|
|
15492
|
-
KODY_CAPABILITY_INPUT: JSON.stringify(input ?? null)
|
|
15493
|
-
};
|
|
15494
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) return environment;
|
|
15495
|
-
for (const [name, value] of Object.entries(input)) {
|
|
15496
|
-
if (value === void 0 || value === null) continue;
|
|
15497
|
-
const key = name.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
|
|
15498
|
-
environment[`KODY_ARG_${key}`] = typeof value === "string" ? value : JSON.stringify(value);
|
|
15499
|
-
}
|
|
15500
|
-
return environment;
|
|
15501
|
-
}
|
|
15502
|
-
function listFiles(root) {
|
|
15503
|
-
if (!fs40.existsSync(root)) return [];
|
|
15504
|
-
const files = [];
|
|
15505
|
-
const visit = (dir) => {
|
|
15506
|
-
for (const entry of fs40.readdirSync(dir, { withFileTypes: true })) {
|
|
15507
|
-
const absolute = path37.join(dir, entry.name);
|
|
15508
|
-
if (entry.isSymbolicLink()) continue;
|
|
15509
|
-
if (entry.isDirectory()) visit(absolute);
|
|
15510
|
-
else if (entry.isFile()) files.push(path37.relative(root, absolute));
|
|
15511
|
-
}
|
|
15512
|
-
};
|
|
15513
|
-
visit(root);
|
|
15514
|
-
return files.sort();
|
|
15515
|
-
}
|
|
15516
|
-
var loadSimpleCapability;
|
|
15517
|
-
var init_loadSimpleCapability = __esm({
|
|
15518
|
-
"src/scripts/loadSimpleCapability.ts"() {
|
|
15519
|
-
"use strict";
|
|
15520
|
-
init_capabilityFolders();
|
|
15521
|
-
init_definition_paths();
|
|
15522
|
-
loadSimpleCapability = async (ctx) => {
|
|
15523
|
-
const slug = typeof ctx.args.capability === "string" ? ctx.args.capability.trim() : "";
|
|
15524
|
-
if (!/^[a-z][a-z0-9-]*$/.test(slug)) {
|
|
15525
|
-
throw new Error("capability-run requires a valid capability slug");
|
|
15526
|
-
}
|
|
15527
|
-
const capability = readCapabilityFolder(capabilitiesRoot(ctx.cwd), slug);
|
|
15528
|
-
if (!capability) {
|
|
15529
|
-
throw new Error(`Capability "${slug}" is not a valid simple capability folder`);
|
|
15530
|
-
}
|
|
15531
|
-
const toolRoot = path37.join(capability.dir, "tools");
|
|
15532
|
-
const skillRoot = path37.join(capability.dir, "skills");
|
|
15533
|
-
const toolFiles = listFiles(toolRoot);
|
|
15534
|
-
const skillFiles = listFiles(skillRoot);
|
|
15535
|
-
const input = parseInput(ctx.args.input);
|
|
15536
|
-
const delivery = ctx.data.jobDelivery === "pull-request";
|
|
15537
|
-
ctx.data.jobCapability = slug;
|
|
15538
|
-
ctx.data.capabilityInput = input;
|
|
15539
|
-
ctx.data.capabilityEnvironment = capabilityEnvironment(input);
|
|
15540
|
-
ctx.data.prompt = [
|
|
15541
|
-
capability.rawBody.trim(),
|
|
15542
|
-
"",
|
|
15543
|
-
"## Input",
|
|
15544
|
-
"",
|
|
15545
|
-
"```json",
|
|
15546
|
-
JSON.stringify(input ?? null, null, 2),
|
|
15547
|
-
"```",
|
|
15548
|
-
"",
|
|
15549
|
-
...delivery ? [
|
|
15550
|
-
"## Delivery",
|
|
15551
|
-
"",
|
|
15552
|
-
"The wrapper owns git commits, pushes, and pull requests. Do not run git or gh write commands.",
|
|
15553
|
-
"Finish with exactly this structure:",
|
|
15554
|
-
"",
|
|
15555
|
-
"DONE",
|
|
15556
|
-
"PLAN_DEVIATIONS: none",
|
|
15557
|
-
"COMMIT_MSG: <conventional commit message>",
|
|
15558
|
-
"PR_SUMMARY:",
|
|
15559
|
-
"- <what changed>",
|
|
15560
|
-
"```json",
|
|
15561
|
-
'{"summary":"<result>","status":"changed"}',
|
|
15562
|
-
"```"
|
|
15563
|
-
] : ["Return one JSON value."],
|
|
15564
|
-
...skillFiles.length ? [
|
|
15565
|
-
"",
|
|
15566
|
-
"## Skills",
|
|
15567
|
-
"",
|
|
15568
|
-
...skillFiles.flatMap((file) => [
|
|
15569
|
-
`### ${file}`,
|
|
15570
|
-
"",
|
|
15571
|
-
fs40.readFileSync(path37.join(skillRoot, file), "utf-8"),
|
|
15572
|
-
""
|
|
15573
|
-
])
|
|
15574
|
-
] : [],
|
|
15575
|
-
...toolFiles.length ? [
|
|
15576
|
-
"",
|
|
15577
|
-
"## Tools",
|
|
15578
|
-
"",
|
|
15579
|
-
"Inspect or run these capability-owned files when needed:",
|
|
15580
|
-
...toolFiles.map((file) => `- ${path37.join(toolRoot, file)}`)
|
|
15581
|
-
] : []
|
|
15582
|
-
].join("\n");
|
|
15583
|
-
};
|
|
15584
|
-
}
|
|
15585
|
-
});
|
|
15586
|
-
|
|
15587
15449
|
// src/companyIntent.ts
|
|
15588
15450
|
function isCompanyIntentId(value) {
|
|
15589
15451
|
return SLUG_RE2.test(value);
|
|
@@ -15885,8 +15747,8 @@ var init_loadIssueStateComment = __esm({
|
|
|
15885
15747
|
});
|
|
15886
15748
|
|
|
15887
15749
|
// src/scripts/loadJobFromFile.ts
|
|
15888
|
-
import * as
|
|
15889
|
-
import * as
|
|
15750
|
+
import * as fs40 from "fs";
|
|
15751
|
+
import * as path37 from "path";
|
|
15890
15752
|
function parseJobFile(raw, slug) {
|
|
15891
15753
|
let stripped = raw;
|
|
15892
15754
|
if (stripped.startsWith("---\n")) {
|
|
@@ -15925,10 +15787,10 @@ var init_loadJobFromFile = __esm({
|
|
|
15925
15787
|
if (!slug) {
|
|
15926
15788
|
throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
|
|
15927
15789
|
}
|
|
15928
|
-
const capability = resolveCapabilityFolder(slug,
|
|
15790
|
+
const capability = resolveCapabilityFolder(slug, path37.resolve(ctx.cwd, jobsDir));
|
|
15929
15791
|
if (!capability) {
|
|
15930
15792
|
throw new Error(
|
|
15931
|
-
`loadJobFromFile: capability folder not found or incomplete: ${
|
|
15793
|
+
`loadJobFromFile: capability folder not found or incomplete: ${path37.resolve(ctx.cwd, jobsDir, slug)}`
|
|
15932
15794
|
);
|
|
15933
15795
|
}
|
|
15934
15796
|
const { title, body, config } = capability;
|
|
@@ -15938,12 +15800,12 @@ var init_loadJobFromFile = __esm({
|
|
|
15938
15800
|
let agentIdentity = "";
|
|
15939
15801
|
if (agentSlug) {
|
|
15940
15802
|
const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
|
|
15941
|
-
if (!
|
|
15803
|
+
if (!fs40.existsSync(agentPath)) {
|
|
15942
15804
|
throw new Error(
|
|
15943
15805
|
`loadJobFromFile: capability '${slug}' declares agent '${agentSlug}' but ${agentPath} does not exist`
|
|
15944
15806
|
);
|
|
15945
15807
|
}
|
|
15946
|
-
const agentRaw =
|
|
15808
|
+
const agentRaw = fs40.readFileSync(agentPath, "utf-8");
|
|
15947
15809
|
const parsed = parseJobFile(agentRaw, agentSlug);
|
|
15948
15810
|
agentTitle = parsed.title;
|
|
15949
15811
|
agentIdentity = parsed.body;
|
|
@@ -16023,13 +15885,13 @@ ${truncate2(issue2.body, FINDING_BODY_MAX_BYTES)}`;
|
|
|
16023
15885
|
});
|
|
16024
15886
|
|
|
16025
15887
|
// src/scripts/kodyVariables.ts
|
|
16026
|
-
import * as
|
|
16027
|
-
import * as
|
|
15888
|
+
import * as fs41 from "fs";
|
|
15889
|
+
import * as path38 from "path";
|
|
16028
15890
|
function readKodyVariables(cwd) {
|
|
16029
|
-
const full =
|
|
15891
|
+
const full = path38.join(cwd, KODY_VARIABLES_REL_PATH);
|
|
16030
15892
|
let raw;
|
|
16031
15893
|
try {
|
|
16032
|
-
raw =
|
|
15894
|
+
raw = fs41.readFileSync(full, "utf-8");
|
|
16033
15895
|
} catch {
|
|
16034
15896
|
return {};
|
|
16035
15897
|
}
|
|
@@ -16205,8 +16067,8 @@ var init_runtimeSecrets = __esm({
|
|
|
16205
16067
|
});
|
|
16206
16068
|
|
|
16207
16069
|
// src/scripts/loadQaContext.ts
|
|
16208
|
-
import * as
|
|
16209
|
-
import * as
|
|
16070
|
+
import * as fs42 from "fs";
|
|
16071
|
+
import * as path39 from "path";
|
|
16210
16072
|
function parseSlugList(value) {
|
|
16211
16073
|
const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
16212
16074
|
return inner.split(",").map(
|
|
@@ -16235,18 +16097,18 @@ function readProfileAgents(raw) {
|
|
|
16235
16097
|
return { agent: agent ?? legacy ?? ["kody"], body };
|
|
16236
16098
|
}
|
|
16237
16099
|
function readProfile(cwd) {
|
|
16238
|
-
const dir =
|
|
16239
|
-
if (!
|
|
16100
|
+
const dir = path39.join(cwd, CONTEXT_DIR_REL_PATH);
|
|
16101
|
+
if (!fs42.existsSync(dir)) return "";
|
|
16240
16102
|
let entries;
|
|
16241
16103
|
try {
|
|
16242
|
-
entries =
|
|
16104
|
+
entries = fs42.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
16243
16105
|
} catch {
|
|
16244
16106
|
return "";
|
|
16245
16107
|
}
|
|
16246
16108
|
const blocks = [];
|
|
16247
16109
|
for (const file of entries) {
|
|
16248
16110
|
try {
|
|
16249
|
-
const raw =
|
|
16111
|
+
const raw = fs42.readFileSync(path39.join(dir, file), "utf-8");
|
|
16250
16112
|
const { agent, body } = readProfileAgents(raw);
|
|
16251
16113
|
if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
|
|
16252
16114
|
blocks.push(`## ${file}
|
|
@@ -16273,23 +16135,156 @@ var CONTEXT_DIR_REL_PATH, QA_AGENT, ALL_AGENTS, LEGACY_AUDIENCE_TO_AGENT, FRONTM
|
|
|
16273
16135
|
var init_loadQaContext = __esm({
|
|
16274
16136
|
"src/scripts/loadQaContext.ts"() {
|
|
16275
16137
|
"use strict";
|
|
16276
|
-
init_kodyVariables();
|
|
16277
|
-
init_runtimeSecrets();
|
|
16278
|
-
CONTEXT_DIR_REL_PATH = ".kody-engine/runtime/context";
|
|
16279
|
-
QA_AGENT = "qa-engineer";
|
|
16280
|
-
ALL_AGENTS = "*";
|
|
16281
|
-
LEGACY_AUDIENCE_TO_AGENT = { chat: "kody", qa: QA_AGENT };
|
|
16282
|
-
FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
16283
|
-
loadQaContext = async (ctx) => {
|
|
16284
|
-
const vars = readKodyVariables(ctx.cwd);
|
|
16285
|
-
const login = vars.LOGIN_USER ?? "";
|
|
16286
|
-
const password = await resolveRuntimeSecret("LOGIN_PASSWORD", ctx);
|
|
16287
|
-
const authProfile = ctx.args.authProfile;
|
|
16288
|
-
ctx.data.qaLogin = login;
|
|
16289
|
-
ctx.data.qaPasswordSource = password.source;
|
|
16290
|
-
if (password.warning) ctx.data.qaPasswordWarning = password.warning;
|
|
16291
|
-
ctx.data.qaProfile = readProfile(ctx.cwd);
|
|
16292
|
-
ctx.data.qaAuthBlock = composeAuthBlock(authProfile, login, password.value);
|
|
16138
|
+
init_kodyVariables();
|
|
16139
|
+
init_runtimeSecrets();
|
|
16140
|
+
CONTEXT_DIR_REL_PATH = ".kody-engine/runtime/context";
|
|
16141
|
+
QA_AGENT = "qa-engineer";
|
|
16142
|
+
ALL_AGENTS = "*";
|
|
16143
|
+
LEGACY_AUDIENCE_TO_AGENT = { chat: "kody", qa: QA_AGENT };
|
|
16144
|
+
FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
16145
|
+
loadQaContext = async (ctx) => {
|
|
16146
|
+
const vars = readKodyVariables(ctx.cwd);
|
|
16147
|
+
const login = vars.LOGIN_USER ?? "";
|
|
16148
|
+
const password = await resolveRuntimeSecret("LOGIN_PASSWORD", ctx);
|
|
16149
|
+
const authProfile = ctx.args.authProfile;
|
|
16150
|
+
ctx.data.qaLogin = login;
|
|
16151
|
+
ctx.data.qaPasswordSource = password.source;
|
|
16152
|
+
if (password.warning) ctx.data.qaPasswordWarning = password.warning;
|
|
16153
|
+
ctx.data.qaProfile = readProfile(ctx.cwd);
|
|
16154
|
+
ctx.data.qaAuthBlock = composeAuthBlock(authProfile, login, password.value);
|
|
16155
|
+
};
|
|
16156
|
+
}
|
|
16157
|
+
});
|
|
16158
|
+
|
|
16159
|
+
// src/scripts/loadSimpleCapability.ts
|
|
16160
|
+
import * as fs43 from "fs";
|
|
16161
|
+
import * as path40 from "path";
|
|
16162
|
+
function parseInput(supplied) {
|
|
16163
|
+
if (typeof supplied !== "string") return supplied;
|
|
16164
|
+
try {
|
|
16165
|
+
return JSON.parse(supplied);
|
|
16166
|
+
} catch {
|
|
16167
|
+
return parseFlagInput(supplied) ?? supplied;
|
|
16168
|
+
}
|
|
16169
|
+
}
|
|
16170
|
+
function parseFlagInput(value) {
|
|
16171
|
+
const tokens = value.trim().split(/\s+/).filter(Boolean);
|
|
16172
|
+
if (!tokens.some((token) => token.startsWith("--"))) return null;
|
|
16173
|
+
const input = {};
|
|
16174
|
+
const text2 = [];
|
|
16175
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
16176
|
+
const token = tokens[index];
|
|
16177
|
+
if (!token.startsWith("--") || token.length === 2) {
|
|
16178
|
+
text2.push(token);
|
|
16179
|
+
continue;
|
|
16180
|
+
}
|
|
16181
|
+
const equalAt = token.indexOf("=");
|
|
16182
|
+
const name = equalAt >= 0 ? token.slice(2, equalAt) : token.slice(2);
|
|
16183
|
+
const next = equalAt >= 0 ? token.slice(equalAt + 1) : tokens[index + 1];
|
|
16184
|
+
if (equalAt < 0 && next && !next.startsWith("--")) index += 1;
|
|
16185
|
+
input[name] = next && !next.startsWith("--") ? scalar(next) : true;
|
|
16186
|
+
}
|
|
16187
|
+
if (text2.length > 0) input.request = text2.join(" ");
|
|
16188
|
+
return input;
|
|
16189
|
+
}
|
|
16190
|
+
function scalar(value) {
|
|
16191
|
+
if (value === "true" || value === "false") return value === "true";
|
|
16192
|
+
if (/^-?\d+$/.test(value)) return Number(value);
|
|
16193
|
+
return value;
|
|
16194
|
+
}
|
|
16195
|
+
function capabilityEnvironment(input) {
|
|
16196
|
+
const environment = {
|
|
16197
|
+
KODY_CAPABILITY_INPUT: JSON.stringify(input ?? null)
|
|
16198
|
+
};
|
|
16199
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) return environment;
|
|
16200
|
+
for (const [name, value] of Object.entries(input)) {
|
|
16201
|
+
if (value === void 0 || value === null) continue;
|
|
16202
|
+
const key = name.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
|
|
16203
|
+
environment[`KODY_ARG_${key}`] = typeof value === "string" ? value : JSON.stringify(value);
|
|
16204
|
+
}
|
|
16205
|
+
return environment;
|
|
16206
|
+
}
|
|
16207
|
+
function listFiles(root) {
|
|
16208
|
+
if (!fs43.existsSync(root)) return [];
|
|
16209
|
+
const files = [];
|
|
16210
|
+
const visit = (dir) => {
|
|
16211
|
+
for (const entry of fs43.readdirSync(dir, { withFileTypes: true })) {
|
|
16212
|
+
const absolute = path40.join(dir, entry.name);
|
|
16213
|
+
if (entry.isSymbolicLink()) continue;
|
|
16214
|
+
if (entry.isDirectory()) visit(absolute);
|
|
16215
|
+
else if (entry.isFile()) files.push(path40.relative(root, absolute));
|
|
16216
|
+
}
|
|
16217
|
+
};
|
|
16218
|
+
visit(root);
|
|
16219
|
+
return files.sort();
|
|
16220
|
+
}
|
|
16221
|
+
var loadSimpleCapability;
|
|
16222
|
+
var init_loadSimpleCapability = __esm({
|
|
16223
|
+
"src/scripts/loadSimpleCapability.ts"() {
|
|
16224
|
+
"use strict";
|
|
16225
|
+
init_capabilityFolders();
|
|
16226
|
+
init_definition_paths();
|
|
16227
|
+
loadSimpleCapability = async (ctx) => {
|
|
16228
|
+
const slug = typeof ctx.args.capability === "string" ? ctx.args.capability.trim() : "";
|
|
16229
|
+
if (!/^[a-z][a-z0-9-]*$/.test(slug)) {
|
|
16230
|
+
throw new Error("capability-run requires a valid capability slug");
|
|
16231
|
+
}
|
|
16232
|
+
const capability = readCapabilityFolder(capabilitiesRoot(ctx.cwd), slug);
|
|
16233
|
+
if (!capability) {
|
|
16234
|
+
throw new Error(`Capability "${slug}" is not a valid simple capability folder`);
|
|
16235
|
+
}
|
|
16236
|
+
const toolRoot = path40.join(capability.dir, "tools");
|
|
16237
|
+
const skillRoot = path40.join(capability.dir, "skills");
|
|
16238
|
+
const toolFiles = listFiles(toolRoot);
|
|
16239
|
+
const skillFiles = listFiles(skillRoot);
|
|
16240
|
+
const input = parseInput(ctx.args.input);
|
|
16241
|
+
const delivery = ctx.data.jobDelivery === "pull-request";
|
|
16242
|
+
ctx.data.jobCapability = slug;
|
|
16243
|
+
ctx.data.capabilityInput = input;
|
|
16244
|
+
ctx.data.capabilityEnvironment = capabilityEnvironment(input);
|
|
16245
|
+
ctx.data.prompt = [
|
|
16246
|
+
capability.rawBody.trim(),
|
|
16247
|
+
"",
|
|
16248
|
+
"## Input",
|
|
16249
|
+
"",
|
|
16250
|
+
"```json",
|
|
16251
|
+
JSON.stringify(input ?? null, null, 2),
|
|
16252
|
+
"```",
|
|
16253
|
+
"",
|
|
16254
|
+
...delivery ? [
|
|
16255
|
+
"## Delivery",
|
|
16256
|
+
"",
|
|
16257
|
+
"The wrapper owns git commits, pushes, and pull requests. Do not run git or gh write commands.",
|
|
16258
|
+
"Finish with exactly this structure:",
|
|
16259
|
+
"",
|
|
16260
|
+
"DONE",
|
|
16261
|
+
"PLAN_DEVIATIONS: none",
|
|
16262
|
+
"COMMIT_MSG: <conventional commit message>",
|
|
16263
|
+
"PR_SUMMARY:",
|
|
16264
|
+
"- <what changed>",
|
|
16265
|
+
"```json",
|
|
16266
|
+
'{"summary":"<result>","status":"changed"}',
|
|
16267
|
+
"```"
|
|
16268
|
+
] : ["Return one JSON value."],
|
|
16269
|
+
...skillFiles.length ? [
|
|
16270
|
+
"",
|
|
16271
|
+
"## Skills",
|
|
16272
|
+
"",
|
|
16273
|
+
...skillFiles.flatMap((file) => [
|
|
16274
|
+
`### ${file}`,
|
|
16275
|
+
"",
|
|
16276
|
+
fs43.readFileSync(path40.join(skillRoot, file), "utf-8"),
|
|
16277
|
+
""
|
|
16278
|
+
])
|
|
16279
|
+
] : [],
|
|
16280
|
+
...toolFiles.length ? [
|
|
16281
|
+
"",
|
|
16282
|
+
"## Tools",
|
|
16283
|
+
"",
|
|
16284
|
+
"Inspect or run these capability-owned files when needed:",
|
|
16285
|
+
...toolFiles.map((file) => `- ${path40.join(toolRoot, file)}`)
|
|
16286
|
+
] : []
|
|
16287
|
+
].join("\n");
|
|
16293
16288
|
};
|
|
16294
16289
|
}
|
|
16295
16290
|
});
|
|
@@ -17127,90 +17122,6 @@ var init_parseJobStateFromAgentResult = __esm({
|
|
|
17127
17122
|
}
|
|
17128
17123
|
});
|
|
17129
17124
|
|
|
17130
|
-
// src/scripts/parseSimpleCapabilityOutput.ts
|
|
17131
|
-
function parseOutput(text2) {
|
|
17132
|
-
if (!text2) return void 0;
|
|
17133
|
-
try {
|
|
17134
|
-
return JSON.parse(text2);
|
|
17135
|
-
} catch {
|
|
17136
|
-
}
|
|
17137
|
-
const fences = [...text2.matchAll(/```([a-z0-9_-]+)?\s*([\s\S]*?)\s*```/gi)];
|
|
17138
|
-
const jsonFences = fences.filter((match) => match[1]?.toLowerCase() === "json");
|
|
17139
|
-
const labelledOutput = parseSingleJsonCandidate(jsonFences.map((match) => match[2]));
|
|
17140
|
-
if (labelledOutput.found) return labelledOutput.value;
|
|
17141
|
-
const plainOutput = parseSingleJsonCandidate(fences.filter((match) => !match[1]).map((match) => match[2]));
|
|
17142
|
-
if (plainOutput.found) return plainOutput.value;
|
|
17143
|
-
const legacyText = text2.trim();
|
|
17144
|
-
return legacyText ? { summary: legacyText, output: legacyText } : void 0;
|
|
17145
|
-
}
|
|
17146
|
-
function parseSingleJsonCandidate(candidates) {
|
|
17147
|
-
const parsed = [];
|
|
17148
|
-
for (const candidate of candidates) {
|
|
17149
|
-
if (!candidate) continue;
|
|
17150
|
-
try {
|
|
17151
|
-
parsed.push(JSON.parse(candidate));
|
|
17152
|
-
} catch {
|
|
17153
|
-
}
|
|
17154
|
-
}
|
|
17155
|
-
return parsed.length === 1 ? { found: true, value: parsed[0] } : { found: false };
|
|
17156
|
-
}
|
|
17157
|
-
function isObject2(value) {
|
|
17158
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
17159
|
-
}
|
|
17160
|
-
function stringValue4(value) {
|
|
17161
|
-
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
17162
|
-
}
|
|
17163
|
-
var parseSimpleCapabilityOutput;
|
|
17164
|
-
var init_parseSimpleCapabilityOutput = __esm({
|
|
17165
|
-
"src/scripts/parseSimpleCapabilityOutput.ts"() {
|
|
17166
|
-
"use strict";
|
|
17167
|
-
parseSimpleCapabilityOutput = async (ctx, _profile, agentResult) => {
|
|
17168
|
-
const output = parseOutput(agentResult?.finalText);
|
|
17169
|
-
if (output === void 0) {
|
|
17170
|
-
const reason2 = agentResult?.outcomeKind === "out_of_turns" ? "Capability execution limit reached" : "Capability execution ended before returning a result";
|
|
17171
|
-
const blocked = {
|
|
17172
|
-
status: "blocked",
|
|
17173
|
-
reason: reason2,
|
|
17174
|
-
summary: reason2
|
|
17175
|
-
};
|
|
17176
|
-
ctx.output.reason = reason2;
|
|
17177
|
-
ctx.data.capabilityOutput = blocked;
|
|
17178
|
-
ctx.data.capabilityResults = [
|
|
17179
|
-
{
|
|
17180
|
-
version: 1,
|
|
17181
|
-
status: "blocked",
|
|
17182
|
-
summary: reason2,
|
|
17183
|
-
facts: blocked,
|
|
17184
|
-
artifacts: [],
|
|
17185
|
-
missingEvidence: [],
|
|
17186
|
-
blockers: [reason2]
|
|
17187
|
-
}
|
|
17188
|
-
];
|
|
17189
|
-
return;
|
|
17190
|
-
}
|
|
17191
|
-
ctx.data.capabilityOutput = output;
|
|
17192
|
-
const result = isObject2(output) ? output : {};
|
|
17193
|
-
const data = isObject2(result.data) ? result.data : isObject2(output) ? output : { output };
|
|
17194
|
-
const summary = typeof result.summary === "string" ? result.summary : "Capability completed";
|
|
17195
|
-
const reason = typeof result.reason === "string" ? result.reason : summary;
|
|
17196
|
-
const prUrl = stringValue4(data.pullRequestUrl) ?? stringValue4(data.prUrl) ?? stringValue4(result.pullRequestUrl) ?? stringValue4(result.prUrl);
|
|
17197
|
-
if (prUrl) ctx.output.prUrl = prUrl;
|
|
17198
|
-
ctx.output.reason = reason;
|
|
17199
|
-
ctx.data.capabilityResults = [
|
|
17200
|
-
{
|
|
17201
|
-
version: 1,
|
|
17202
|
-
status: "changed",
|
|
17203
|
-
summary,
|
|
17204
|
-
facts: data,
|
|
17205
|
-
artifacts: prUrl ? [{ label: "Pull request", url: prUrl }] : [],
|
|
17206
|
-
missingEvidence: [],
|
|
17207
|
-
blockers: []
|
|
17208
|
-
}
|
|
17209
|
-
];
|
|
17210
|
-
};
|
|
17211
|
-
}
|
|
17212
|
-
});
|
|
17213
|
-
|
|
17214
17125
|
// src/scripts/parseReproOutput.ts
|
|
17215
17126
|
function extractTestPath(text2) {
|
|
17216
17127
|
const m = text2.match(/^[\s>*_#`~-]*TEST_PATH[\s>*_#`~-]*\s*:\s*(.+?)\s*$/im);
|
|
@@ -17318,6 +17229,90 @@ var init_parseReproOutput = __esm({
|
|
|
17318
17229
|
}
|
|
17319
17230
|
});
|
|
17320
17231
|
|
|
17232
|
+
// src/scripts/parseSimpleCapabilityOutput.ts
|
|
17233
|
+
function parseOutput(text2) {
|
|
17234
|
+
if (!text2) return void 0;
|
|
17235
|
+
try {
|
|
17236
|
+
return JSON.parse(text2);
|
|
17237
|
+
} catch {
|
|
17238
|
+
}
|
|
17239
|
+
const fences = [...text2.matchAll(/```([a-z0-9_-]+)?\s*([\s\S]*?)\s*```/gi)];
|
|
17240
|
+
const jsonFences = fences.filter((match) => match[1]?.toLowerCase() === "json");
|
|
17241
|
+
const labelledOutput = parseSingleJsonCandidate(jsonFences.map((match) => match[2]));
|
|
17242
|
+
if (labelledOutput.found) return labelledOutput.value;
|
|
17243
|
+
const plainOutput = parseSingleJsonCandidate(fences.filter((match) => !match[1]).map((match) => match[2]));
|
|
17244
|
+
if (plainOutput.found) return plainOutput.value;
|
|
17245
|
+
const legacyText = text2.trim();
|
|
17246
|
+
return legacyText ? { summary: legacyText, output: legacyText } : void 0;
|
|
17247
|
+
}
|
|
17248
|
+
function parseSingleJsonCandidate(candidates) {
|
|
17249
|
+
const parsed = [];
|
|
17250
|
+
for (const candidate of candidates) {
|
|
17251
|
+
if (!candidate) continue;
|
|
17252
|
+
try {
|
|
17253
|
+
parsed.push(JSON.parse(candidate));
|
|
17254
|
+
} catch {
|
|
17255
|
+
}
|
|
17256
|
+
}
|
|
17257
|
+
return parsed.length === 1 ? { found: true, value: parsed[0] } : { found: false };
|
|
17258
|
+
}
|
|
17259
|
+
function isObject2(value) {
|
|
17260
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
17261
|
+
}
|
|
17262
|
+
function stringValue4(value) {
|
|
17263
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
17264
|
+
}
|
|
17265
|
+
var parseSimpleCapabilityOutput;
|
|
17266
|
+
var init_parseSimpleCapabilityOutput = __esm({
|
|
17267
|
+
"src/scripts/parseSimpleCapabilityOutput.ts"() {
|
|
17268
|
+
"use strict";
|
|
17269
|
+
parseSimpleCapabilityOutput = async (ctx, _profile, agentResult) => {
|
|
17270
|
+
const output = parseOutput(agentResult?.finalText);
|
|
17271
|
+
if (output === void 0) {
|
|
17272
|
+
const reason2 = agentResult?.outcomeKind === "out_of_turns" ? "Capability execution limit reached" : "Capability execution ended before returning a result";
|
|
17273
|
+
const blocked = {
|
|
17274
|
+
status: "blocked",
|
|
17275
|
+
reason: reason2,
|
|
17276
|
+
summary: reason2
|
|
17277
|
+
};
|
|
17278
|
+
ctx.output.reason = reason2;
|
|
17279
|
+
ctx.data.capabilityOutput = blocked;
|
|
17280
|
+
ctx.data.capabilityResults = [
|
|
17281
|
+
{
|
|
17282
|
+
version: 1,
|
|
17283
|
+
status: "blocked",
|
|
17284
|
+
summary: reason2,
|
|
17285
|
+
facts: blocked,
|
|
17286
|
+
artifacts: [],
|
|
17287
|
+
missingEvidence: [],
|
|
17288
|
+
blockers: [reason2]
|
|
17289
|
+
}
|
|
17290
|
+
];
|
|
17291
|
+
return;
|
|
17292
|
+
}
|
|
17293
|
+
ctx.data.capabilityOutput = output;
|
|
17294
|
+
const result = isObject2(output) ? output : {};
|
|
17295
|
+
const data = isObject2(result.data) ? result.data : isObject2(output) ? output : { output };
|
|
17296
|
+
const summary = typeof result.summary === "string" ? result.summary : "Capability completed";
|
|
17297
|
+
const reason = typeof result.reason === "string" ? result.reason : summary;
|
|
17298
|
+
const prUrl = stringValue4(data.pullRequestUrl) ?? stringValue4(data.prUrl) ?? stringValue4(result.pullRequestUrl) ?? stringValue4(result.prUrl);
|
|
17299
|
+
if (prUrl) ctx.output.prUrl = prUrl;
|
|
17300
|
+
ctx.output.reason = reason;
|
|
17301
|
+
ctx.data.capabilityResults = [
|
|
17302
|
+
{
|
|
17303
|
+
version: 1,
|
|
17304
|
+
status: "changed",
|
|
17305
|
+
summary,
|
|
17306
|
+
facts: data,
|
|
17307
|
+
artifacts: prUrl ? [{ label: "Pull request", url: prUrl }] : [],
|
|
17308
|
+
missingEvidence: [],
|
|
17309
|
+
blockers: []
|
|
17310
|
+
}
|
|
17311
|
+
];
|
|
17312
|
+
};
|
|
17313
|
+
}
|
|
17314
|
+
});
|
|
17315
|
+
|
|
17321
17316
|
// src/scripts/persistArtifacts.ts
|
|
17322
17317
|
function readDottedString(source, dotted) {
|
|
17323
17318
|
const parts = dotted.split(".");
|
|
@@ -18156,9 +18151,7 @@ var init_prepareCapabilityDelivery = __esm({
|
|
|
18156
18151
|
prepareCapabilityDelivery = async (ctx, profile) => {
|
|
18157
18152
|
const target = capabilityDeliveryTarget(ctx.data.capabilityInput);
|
|
18158
18153
|
if (!target) {
|
|
18159
|
-
throw new Error(
|
|
18160
|
-
"pull-request delivery requires exactly one positive issue or pr input"
|
|
18161
|
-
);
|
|
18154
|
+
throw new Error("pull-request delivery requires exactly one positive issue or pr input");
|
|
18162
18155
|
}
|
|
18163
18156
|
ctx.args[target.kind] = target.number;
|
|
18164
18157
|
if (target.kind === "issue") {
|
|
@@ -20901,12 +20894,12 @@ var init_scripts = __esm({
|
|
|
20901
20894
|
init_diagMcp();
|
|
20902
20895
|
init_discoverQaContext();
|
|
20903
20896
|
init_dispatch();
|
|
20897
|
+
init_dispatchAgencyLoops();
|
|
20904
20898
|
init_dispatchCapabilityFileTicks();
|
|
20905
20899
|
init_dispatchCapabilityTicks();
|
|
20906
20900
|
init_dispatchClassified();
|
|
20907
|
-
init_dispatchAgencyLoops();
|
|
20908
|
-
init_dispatchSimpleLoops();
|
|
20909
20901
|
init_dispatchNextTaskJob();
|
|
20902
|
+
init_dispatchSimpleLoops();
|
|
20910
20903
|
init_ensurePr();
|
|
20911
20904
|
init_evaluateAgencyBoundaries();
|
|
20912
20905
|
init_failOnceTaskJob();
|
|
@@ -20917,7 +20910,6 @@ var init_scripts = __esm({
|
|
|
20917
20910
|
init_initFlow();
|
|
20918
20911
|
init_loadAgentAdhoc();
|
|
20919
20912
|
init_loadCapabilityState();
|
|
20920
|
-
init_loadSimpleCapability();
|
|
20921
20913
|
init_loadCompanyIntents();
|
|
20922
20914
|
init_loadCompanyPortfolio();
|
|
20923
20915
|
init_loadConventions();
|
|
@@ -20930,6 +20922,7 @@ var init_scripts = __esm({
|
|
|
20930
20922
|
init_loadMemoryContext();
|
|
20931
20923
|
init_loadPriorArt();
|
|
20932
20924
|
init_loadQaContext();
|
|
20925
|
+
init_loadSimpleCapability();
|
|
20933
20926
|
init_loadTaskContext();
|
|
20934
20927
|
init_loadTaskState();
|
|
20935
20928
|
init_markFlowSuccess();
|
|
@@ -20942,8 +20935,8 @@ var init_scripts = __esm({
|
|
|
20942
20935
|
init_parseAgentResult();
|
|
20943
20936
|
init_parseIssueStateFromAgentResult();
|
|
20944
20937
|
init_parseJobStateFromAgentResult();
|
|
20945
|
-
init_parseSimpleCapabilityOutput();
|
|
20946
20938
|
init_parseReproOutput();
|
|
20939
|
+
init_parseSimpleCapabilityOutput();
|
|
20947
20940
|
init_persistArtifacts();
|
|
20948
20941
|
init_persistFlowState();
|
|
20949
20942
|
init_planTaskJobs();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{{prompt}}
|
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.458",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|