@kody-ade/kody-engine 0.4.520 → 0.4.522

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.
Files changed (2) hide show
  1. package/dist/bin/kody.js +182 -38
  2. package/package.json +1 -1
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.520",
18
+ version: "0.4.522",
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",
@@ -4638,7 +4638,8 @@ function normalizeWorkflowDefinition(value) {
4638
4638
  }
4639
4639
  const workflow = parseCapabilityWorkflow({
4640
4640
  steps: raw.steps,
4641
- startAt: raw.startAt
4641
+ startAt: raw.startAt,
4642
+ report: raw.report
4642
4643
  });
4643
4644
  const steps = workflow?.steps;
4644
4645
  const capabilities = steps ? steps.map((step) => step.capability) : normalizeWorkflowCapabilities(raw.capabilities);
@@ -4650,6 +4651,7 @@ function normalizeWorkflowDefinition(value) {
4650
4651
  ...raw.runWithoutApproval === true ? { runWithoutApproval: true } : {},
4651
4652
  ...steps ? { steps } : {},
4652
4653
  ...workflow?.startAt ? { startAt: workflow.startAt } : {},
4654
+ ...workflow?.report ? { report: workflow.report } : {},
4653
4655
  ...typeof raw.createdAt === "string" ? { createdAt: raw.createdAt } : {},
4654
4656
  ...typeof raw.updatedAt === "string" ? { updatedAt: raw.updatedAt } : {}
4655
4657
  };
@@ -4702,7 +4704,8 @@ function normalizeWorkflowCapabilities(value) {
4702
4704
  function workflowDefinitionToConfig(workflow) {
4703
4705
  return {
4704
4706
  steps: workflow.steps ?? workflow.capabilities.map((capability) => ({ capability })),
4705
- ...workflow.startAt ? { startAt: workflow.startAt } : {}
4707
+ ...workflow.startAt ? { startAt: workflow.startAt } : {},
4708
+ ...workflow.report ? { report: workflow.report } : {}
4706
4709
  };
4707
4710
  }
4708
4711
  function parseWorkflowDefinition(content) {
@@ -17881,27 +17884,171 @@ var init_promoteQaGoal = __esm({
17881
17884
 
17882
17885
  // src/scripts/publishReport.ts
17883
17886
  function buildRuntimeReportMarkdown(input) {
17884
- return [
17885
- "---",
17886
- `generatedAt: ${yamlString(input.generatedAt)}`,
17887
- `reportType: ${input.reportType}`,
17888
- `reportTypeVersion: ${input.reportTypeVersion}`,
17889
- "producer:",
17890
- ` model: ${input.owner}`,
17891
- ` capability: ${input.capability}`,
17892
- ...input.reviewStatus ? [`reviewStatus: ${input.reviewStatus}`] : [],
17893
- ...input.reviewArea ? [`reviewArea: ${input.reviewArea}`] : [],
17894
- "---",
17887
+ const lines = [
17895
17888
  `# ${input.title}`,
17896
17889
  "",
17897
17890
  input.summary,
17898
17891
  "",
17899
- "## Report data",
17900
- "```json",
17901
- JSON.stringify(input.data, null, 2),
17902
- "```",
17903
- ""
17904
- ].join("\n");
17892
+ "## About",
17893
+ markdownField("Type", input.reportType),
17894
+ markdownField("Version", input.reportTypeVersion),
17895
+ markdownField("Generated", input.generatedAt),
17896
+ markdownField("Owner", input.owner),
17897
+ markdownField("Capability", input.capability),
17898
+ ...input.reviewStatus ? [markdownField("Review status", input.reviewStatus)] : [],
17899
+ ...input.reviewArea ? [markdownField("Review area", input.reviewArea)] : [],
17900
+ "",
17901
+ ...renderReportData(input.data)
17902
+ ];
17903
+ return `${lines.join("\n").trimEnd()}
17904
+ `;
17905
+ }
17906
+ function renderReportData(data) {
17907
+ const lines = [];
17908
+ const workflow = recordField4(data.workflow);
17909
+ const finding = recordField4(data.finding);
17910
+ const observation = recordField4(data.observation);
17911
+ const learning = recordField4(data.learning);
17912
+ if (workflow) lines.push(...renderWorkflow(workflow));
17913
+ if (finding) lines.push(...renderFinding(finding));
17914
+ if (observation) lines.push(...renderObservation(observation));
17915
+ if (learning) lines.push(...renderLearning(learning));
17916
+ const rest = omitKeys(data, ["workflow", "finding", "observation", "learning"]);
17917
+ if (Object.keys(rest).length > 0) {
17918
+ lines.push("## Results", ...renderObjectFields(rest, 3), "");
17919
+ }
17920
+ return lines;
17921
+ }
17922
+ function renderWorkflow(workflow) {
17923
+ const lines = ["## Run"];
17924
+ pushField(lines, "Status", workflow.status);
17925
+ pushField(lines, "Blocker", workflow.blocker);
17926
+ const completed = stringArray3(workflow.completedStepIds);
17927
+ if (completed.length > 0) {
17928
+ lines.push("", "## Completed checks", ...completed.map((step) => `- ${humanize(step)}`));
17929
+ }
17930
+ const facts = recordField4(workflow.facts) ?? {};
17931
+ const finding = recordField4(facts.finding);
17932
+ const observation = recordField4(facts.observation);
17933
+ if (finding) lines.push("", ...renderFinding(finding));
17934
+ if (observation) lines.push("", ...renderObservation(observation));
17935
+ const remainingFacts = omitKeys(facts, ["finding", "observation"]);
17936
+ if (Object.keys(remainingFacts).length > 0) {
17937
+ lines.push("", "## Results", ...renderObjectFields(remainingFacts, 3));
17938
+ }
17939
+ const artifacts = Array.isArray(workflow.artifacts) ? workflow.artifacts : [];
17940
+ const evidence = renderEvidence(artifacts);
17941
+ if (evidence.length > 0) lines.push("", "## Evidence", ...evidence);
17942
+ lines.push("");
17943
+ return lines;
17944
+ }
17945
+ function renderFinding(finding) {
17946
+ const lines = ["## Finding"];
17947
+ for (const [label, key] of [
17948
+ ["ID", "id"],
17949
+ ["Status", "status"],
17950
+ ["Severity", "severity"],
17951
+ ["Observer", "observerId"],
17952
+ ["Subject", "subject"],
17953
+ ["Expected", "expectation"],
17954
+ ["Actual", "actual"],
17955
+ ["Observation ID", "observationId"],
17956
+ ["Observed", "observedAt"],
17957
+ ["Operator activity", "operatorActivityAt"]
17958
+ ]) {
17959
+ pushField(lines, label, finding[key]);
17960
+ }
17961
+ lines.push("");
17962
+ return lines;
17963
+ }
17964
+ function renderObservation(observation) {
17965
+ const lines = ["## Observation"];
17966
+ for (const [label, key] of [
17967
+ ["ID", "id"],
17968
+ ["Status", "status"],
17969
+ ["Summary", "summary"],
17970
+ ["Observer", "observerId"],
17971
+ ["Capability", "capability"],
17972
+ ["Subject", "subject"],
17973
+ ["Observed", "observedAt"]
17974
+ ]) {
17975
+ pushField(lines, label, observation[key]);
17976
+ }
17977
+ const evidence = renderEvidence(Array.isArray(observation.evidence) ? observation.evidence : []);
17978
+ if (evidence.length > 0) lines.push("", "### Evidence", ...evidence);
17979
+ lines.push("");
17980
+ return lines;
17981
+ }
17982
+ function renderLearning(learning) {
17983
+ const lines = ["## Learning"];
17984
+ for (const [label, key] of [
17985
+ ["ID", "id"],
17986
+ ["Finding ID", "findingId"],
17987
+ ["Summary", "summary"],
17988
+ ["Change", "change"],
17989
+ ["Evidence", "evidence"]
17990
+ ]) {
17991
+ pushField(lines, label, learning[key]);
17992
+ }
17993
+ lines.push("");
17994
+ return lines;
17995
+ }
17996
+ function renderObjectFields(value, headingLevel) {
17997
+ const lines = [];
17998
+ for (const [key, item] of Object.entries(value)) {
17999
+ const label = humanize(key);
18000
+ if (isScalar(item)) {
18001
+ lines.push(markdownField(label, item));
18002
+ continue;
18003
+ }
18004
+ if (Array.isArray(item)) {
18005
+ if (item.length === 0) continue;
18006
+ lines.push(`${"#".repeat(Math.min(headingLevel, 6))} ${label}`);
18007
+ for (const entry of item) {
18008
+ if (isScalar(entry)) lines.push(`- ${markdownValue(entry)}`);
18009
+ else if (recordField4(entry)) lines.push(...renderObjectFields(recordField4(entry), headingLevel + 1));
18010
+ }
18011
+ continue;
18012
+ }
18013
+ const record2 = recordField4(item);
18014
+ if (!record2 || Object.keys(record2).length === 0) continue;
18015
+ lines.push(`${"#".repeat(Math.min(headingLevel, 6))} ${label}`, ...renderObjectFields(record2, headingLevel + 1));
18016
+ }
18017
+ return lines;
18018
+ }
18019
+ function renderEvidence(items) {
18020
+ return items.flatMap((item) => {
18021
+ const record2 = recordField4(item);
18022
+ if (!record2) return [];
18023
+ const label = stringValue5(record2.label) ?? stringValue5(record2.kind) ?? "Evidence";
18024
+ const url = stringValue5(record2.url);
18025
+ const status = stringValue5(record2.status);
18026
+ const suffix = status ? ` \u2014 ${humanize(status)}` : "";
18027
+ return [`- ${url ? `[${label}](${url})` : label}${suffix}`];
18028
+ });
18029
+ }
18030
+ function omitKeys(value, keys) {
18031
+ const omitted = new Set(keys);
18032
+ return Object.fromEntries(Object.entries(value).filter(([key]) => !omitted.has(key)));
18033
+ }
18034
+ function stringArray3(value) {
18035
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
18036
+ }
18037
+ function isScalar(value) {
18038
+ return value === null || value === void 0 || ["string", "number", "boolean"].includes(typeof value);
18039
+ }
18040
+ function pushField(lines, label, value) {
18041
+ if (isScalar(value) && value !== void 0 && value !== null && value !== "") {
18042
+ lines.push(markdownField(label, value));
18043
+ }
18044
+ }
18045
+ function markdownField(label, value) {
18046
+ return `- **${label}:** ${markdownValue(value)}`;
18047
+ }
18048
+ function markdownValue(value) {
18049
+ if (value === null || value === void 0) return "None";
18050
+ if (typeof value === "boolean") return value ? "Yes" : "No";
18051
+ return String(value).replace(/\r?\n/g, " ").trim();
17905
18052
  }
17906
18053
  async function publishWorkflowReport(input) {
17907
18054
  const slug = input.publication.slug;
@@ -17983,10 +18130,7 @@ function stringValue5(value) {
17983
18130
  return typeof value === "string" && value.trim() ? value.trim() : null;
17984
18131
  }
17985
18132
  function humanize(value) {
17986
- return value.split(/[-_]+/).filter(Boolean).map((part) => part[0].toUpperCase() + part.slice(1)).join(" ");
17987
- }
17988
- function yamlString(value) {
17989
- return JSON.stringify(value);
18133
+ return value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[-_]+/).filter(Boolean).map((part) => part[0].toUpperCase() + part.slice(1)).join(" ");
17990
18134
  }
17991
18135
  var SAFE_SLUG, publishReport;
17992
18136
  var init_publishReport = __esm({
@@ -19702,7 +19846,7 @@ function validateOneModel(rawModel, files, label, strictSingleModel, failures, e
19702
19846
  const slug = stringField5(model.slug);
19703
19847
  if (!isSlug(slug)) failures.push(`${label}.slug must be a lowercase slug`);
19704
19848
  if (isModelKind(kind)) {
19705
- const docsUsed = stringArray3(model.docsUsed);
19849
+ const docsUsed = stringArray4(model.docsUsed);
19706
19850
  for (const doc of REQUIRED_DOCS[kind]) {
19707
19851
  if (!docsUsed.includes(doc)) failures.push(`${label} docsUsed missing ${doc}`);
19708
19852
  }
@@ -19800,12 +19944,12 @@ function validateModelShape(kind, model, files, slug, failures) {
19800
19944
  if (!isFiniteNumber(intent?.priority)) failures.push("intent file must declare numeric priority");
19801
19945
  if (!hasScope(model.scope)) failures.push("intent model scope must include a repo or area");
19802
19946
  if (!hasScope(intent?.scope)) failures.push("intent file scope must include a repo or area");
19803
- if (stringArray3(model.principles).length === 0) failures.push("intent model principles must be non-empty");
19804
- if (stringArray3(intent?.principles).length === 0) failures.push("intent file principles must be non-empty");
19805
- if (stringArray3(model.successMeasures).length === 0) {
19947
+ if (stringArray4(model.principles).length === 0) failures.push("intent model principles must be non-empty");
19948
+ if (stringArray4(intent?.principles).length === 0) failures.push("intent file principles must be non-empty");
19949
+ if (stringArray4(model.successMeasures).length === 0) {
19806
19950
  failures.push("intent model successMeasures must be non-empty");
19807
19951
  }
19808
- if (stringArray3(intent?.metrics).length === 0) failures.push("intent file metrics must be non-empty");
19952
+ if (stringArray4(intent?.metrics).length === 0) failures.push("intent file metrics must be non-empty");
19809
19953
  if (!recordField5(model.policy)) failures.push("intent model must declare policy");
19810
19954
  if (!recordField5(intent?.policy)) failures.push("intent file must declare policy");
19811
19955
  if (stringField5(model.status) !== "paused" || stringField5(intent?.status) !== "paused") {
@@ -19820,10 +19964,10 @@ function validateModelShape(kind, model, files, slug, failures) {
19820
19964
  const operation = parseJsonFile(files, `operations/${slug}/operation.json`, failures);
19821
19965
  if (!stringField5(model.responsibility)) failures.push("operation model must declare responsibility");
19822
19966
  if (!stringField5(operation?.responsibility)) failures.push("operation file must declare responsibility");
19823
- if (stringArray3(model.intentIds).length === 0) failures.push("operation model intentIds must be non-empty");
19824
- if (stringArray3(operation?.intentIds).length === 0) failures.push("operation file intentIds must be non-empty");
19825
- if (stringArray3(model.doesNotOwn).length === 0) failures.push("operation model doesNotOwn must be non-empty");
19826
- if (stringArray3(operation?.doesNotOwn).length === 0) failures.push("operation file doesNotOwn must be non-empty");
19967
+ if (stringArray4(model.intentIds).length === 0) failures.push("operation model intentIds must be non-empty");
19968
+ if (stringArray4(operation?.intentIds).length === 0) failures.push("operation file intentIds must be non-empty");
19969
+ if (stringArray4(model.doesNotOwn).length === 0) failures.push("operation model doesNotOwn must be non-empty");
19970
+ if (stringArray4(operation?.doesNotOwn).length === 0) failures.push("operation file doesNotOwn must be non-empty");
19827
19971
  if (stringField5(model.status) !== "proposed" || stringField5(operation?.status) !== "proposed") {
19828
19972
  failures.push("operation proposal status must be proposed");
19829
19973
  }
@@ -19832,7 +19976,7 @@ function validateModelShape(kind, model, files, slug, failures) {
19832
19976
  }
19833
19977
  if (kind === "agent") {
19834
19978
  const agentFile = textFile(files, `agents/${slug}.md`);
19835
- if (!stringArray3(model.owns).includes("identity") && !containsWord(agentFile, "identity")) {
19979
+ if (!stringArray4(model.owns).includes("identity") && !containsWord(agentFile, "identity")) {
19836
19980
  failures.push("agent owns must include identity");
19837
19981
  }
19838
19982
  requireStringArrayIncludes(model.doesNotOwn, "tasks", "agent doesNotOwn", failures);
@@ -19875,7 +20019,7 @@ function validateModelShape(kind, model, files, slug, failures) {
19875
20019
  }
19876
20020
  }
19877
20021
  function capabilityRefs(value) {
19878
- return [...stringArray3(value?.capabilities), ...stringArray3(value?.allowedCapabilities)];
20022
+ return [...stringArray4(value?.capabilities), ...stringArray4(value?.allowedCapabilities)];
19879
20023
  }
19880
20024
  function evidenceRefs(value) {
19881
20025
  if (!value) return [];
@@ -19947,7 +20091,7 @@ function normalizeBundlePath(filePath) {
19947
20091
  function stringField5(value) {
19948
20092
  return typeof value === "string" ? value.trim() : "";
19949
20093
  }
19950
- function stringArray3(value) {
20094
+ function stringArray4(value) {
19951
20095
  if (!Array.isArray(value)) return [];
19952
20096
  return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
19953
20097
  }
@@ -19959,10 +20103,10 @@ function isFiniteNumber(value) {
19959
20103
  }
19960
20104
  function hasScope(value) {
19961
20105
  const scope = recordField5(value);
19962
- return stringArray3(scope?.repos).length > 0 || stringArray3(scope?.areas).length > 0;
20106
+ return stringArray4(scope?.repos).length > 0 || stringArray4(scope?.areas).length > 0;
19963
20107
  }
19964
20108
  function requireStringArrayIncludes(value, expected, label, failures) {
19965
- if (!stringArray3(value).includes(expected)) failures.push(`${label} must include ${expected}`);
20109
+ if (!stringArray4(value).includes(expected)) failures.push(`${label} must include ${expected}`);
19966
20110
  }
19967
20111
  function isSlug(value) {
19968
20112
  return /^[a-z][a-z0-9-]{0,63}$/.test(value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.520",
3
+ "version": "0.4.522",
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",