@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.456",
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/loopDefinitions.ts
13859
- import * as fs36 from "fs";
13860
- import * as path34 from "path";
13861
- function normalizeLoopDefinition(value) {
13862
- if (!value || typeof value !== "object" || Array.isArray(value)) return null;
13863
- const raw = value;
13864
- if (Object.keys(raw).some((key) => !["id", "trigger", "target", "input", "enabled"].includes(key))) return null;
13865
- if (typeof raw.id !== "string" || !ID.test(raw.id)) return null;
13866
- if (typeof raw.enabled !== "boolean") return null;
13867
- if (!isObject(raw.input) || !isObject(raw.trigger) || !isObject(raw.target)) return null;
13868
- const targetKind = raw.target.kind;
13869
- const targetId = raw.target.id;
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
- const trigger = normalizeTrigger(raw.trigger);
13874
- if (!trigger) return null;
13875
- return {
13876
- id: raw.id,
13877
- trigger,
13878
- target: { kind: targetKind, id: targetId },
13879
- input: raw.input,
13880
- enabled: raw.enabled
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
- function readLoopDefinition(cwd, id) {
13884
- if (!ID.test(id)) return null;
13885
- const roots = loopRoots(cwd);
13886
- for (const root of roots) {
13887
- const filePath = path34.join(root, "loops", id, "loop.json");
13888
- if (!fs36.existsSync(filePath)) continue;
13889
- try {
13890
- const loop = normalizeLoopDefinition(JSON.parse(fs36.readFileSync(filePath, "utf8")));
13891
- if (loop?.id === id) return loop;
13892
- process.stderr.write(`[kody] invalid simple Loop definition: ${filePath}
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
- } catch {
13895
- process.stderr.write(`[kody] unreadable simple Loop definition: ${filePath}
13787
+ return;
13788
+ }
13789
+ process.stdout.write(`[jobs] ticking ${issues.length} issue(s) via ${targetImplementation}
13896
13790
  `);
13897
- }
13898
- }
13899
- process.stderr.write(
13900
- `[kody] simple Loop not found: ${id} (${roots.map((root) => path34.join(root, "loops", id, "loop.json")).join(", ")})
13901
- `
13902
- );
13903
- return null;
13904
- }
13905
- function listLoopDefinitions(cwd) {
13906
- const roots = loopRoots(cwd);
13907
- const byId = /* @__PURE__ */ new Map();
13908
- for (const root of roots.reverse()) {
13909
- const loopsDir = path34.join(root, "loops");
13910
- if (!fs36.existsSync(loopsDir)) continue;
13911
- for (const id of fs36.readdirSync(loopsDir).sort()) {
13912
- if (!ID.test(id)) continue;
13913
- const filePath = path34.join(loopsDir, id, "loop.json");
13914
- if (!fs36.existsSync(filePath)) continue;
13915
- try {
13916
- const loop = normalizeLoopDefinition(JSON.parse(fs36.readFileSync(filePath, "utf8")));
13917
- if (loop?.id === id) byId.set(id, loop);
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 fs41 from "fs";
15889
- import * as path38 from "path";
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, path38.resolve(ctx.cwd, jobsDir));
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: ${path38.resolve(ctx.cwd, jobsDir, slug)}`
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 (!fs41.existsSync(agentPath)) {
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 = fs41.readFileSync(agentPath, "utf-8");
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 fs42 from "fs";
16027
- import * as path39 from "path";
15888
+ import * as fs41 from "fs";
15889
+ import * as path38 from "path";
16028
15890
  function readKodyVariables(cwd) {
16029
- const full = path39.join(cwd, KODY_VARIABLES_REL_PATH);
15891
+ const full = path38.join(cwd, KODY_VARIABLES_REL_PATH);
16030
15892
  let raw;
16031
15893
  try {
16032
- raw = fs42.readFileSync(full, "utf-8");
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 fs43 from "fs";
16209
- import * as path40 from "path";
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 = path40.join(cwd, CONTEXT_DIR_REL_PATH);
16239
- if (!fs43.existsSync(dir)) return "";
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 = fs43.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
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 = fs43.readFileSync(path40.join(dir, file), "utf-8");
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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.456",
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",