@kody-ade/kody-engine 0.4.258 → 0.4.260

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/README.md CHANGED
@@ -27,7 +27,7 @@ kody: reads the issue → writes the code → runs your tests → opens a PR
27
27
  - **No infrastructure.** Runs on the GitHub Actions you already have. One ~20-line
28
28
  workflow file, installed via `npx`. Nothing to deploy or keep online.
29
29
  - **Whole PR lifecycle, not just authoring.** `run`, `resolve`, `sync`, `merge`,
30
- `revert`, previews, releases, and scheduled agentResponsibilities — one executor, many verbs.
30
+ `revert`, previews, releases, and scheduled capabilities — one executor, many verbs.
31
31
  - **Declarative & extensible.** Every command is a folder of `profile.json` +
32
32
  `prompt.md` + shell. Add a command by dropping a folder — no engine changes.
33
33
  - **Bring your own model.** Anthropic native, or any provider via the built-in
@@ -74,19 +74,31 @@ See [SECURITY.md](SECURITY.md) to report a vulnerability.
74
74
  ┌─────────────────────────────────────────────┐
75
75
  │ kody-engine CLI (@kody-ade/kody-engine) │
76
76
  │ bin/kody.ts — entrypoint │
77
- │ src/dispatch.ts — agentResponsibility-driven routing
78
- │ src/executor.ts — runs agentResponsibility implementations│
77
+ │ src/dispatch.ts — capability-driven routing
78
+ │ src/executor.ts — runs capability implementations
79
+ │ .kody/capabilities/<slug>/ │
80
+ │ profile.json · capability.md · optional skills/scripts │
79
81
  │ .kody/agent-responsibilities/<slug>/ │
80
- │ profile.json · agent-responsibility.md
81
- src/agent-actions/<name>/
82
- │ profile.json · prompt.md · *.sh
82
+ legacy fallback: profile.json · agent-responsibility.md
83
+ .kody/agent-actions/<name>/
84
+ legacy fallback: profile.json · prompt.md · *.sh
83
85
  │ src/scripts/*.ts — cross-cutting catalog │
84
86
  └─────────────────────────────────────────────┘
85
87
  ```
86
88
 
87
- Every top-level command is an auto-discovered agentResponsibility action. The router has **zero agentAction names hardcoded** — comment dispatch resolves the first token after `@kody` through `config.aliases`, then falls back to the legacy-named `config.defaultAgentAction` / `config.defaultPrAgentAction` fields as default agentResponsibility actions. Drop a new `.kody/agent-responsibilities/<slug>/` directory with `profile.json` + `agent-responsibility.md`; that agentResponsibility chooses its implementation agentAction.
89
+ Every top-level command is an auto-discovered capability action. The router has
90
+ **zero agentAction names hardcoded** - comment dispatch resolves the first token
91
+ after `@kody` through `config.aliases`, then falls back to the legacy-named
92
+ `config.defaultAgentAction` / `config.defaultPrAgentAction` fields as default
93
+ capability actions. Drop a new `.kody/capabilities/<slug>/` directory with
94
+ `profile.json` + `capability.md`; legacy `.kody/agent-responsibilities/` and
95
+ `.kody/agent-actions/` roots still load while repos migrate.
88
96
 
89
- AgentAction directories are private implementation units and contain **only** three kinds of files: `profile.json` (declaration), `prompt.md` (agent instructions), and `.sh` scripts (mechanical side-effect work). Cross-cutting TypeScript lives in [src/scripts/](src/scripts/); it can't import from `src/agent-actions/` and can't branch on `profile.name`.
97
+ Legacy AgentAction directories are private implementation units and contain
98
+ **only** three kinds of files: `profile.json` (declaration), `prompt.md` (agent
99
+ instructions), and `.sh` scripts (mechanical side-effect work). Cross-cutting
100
+ TypeScript lives in [src/scripts/](src/scripts/); it can't import from
101
+ `src/agent-actions/` and can't branch on `profile.name`.
90
102
 
91
103
  ## Install in a consumer repo
92
104
 
@@ -94,7 +106,10 @@ AgentAction directories are private implementation units and contain **only** th
94
106
  npx -y -p @kody-ade/kody-engine@latest kody-engine init
95
107
  ```
96
108
 
97
- `kody-engine init` scaffolds [kody.config.json](kody.config.schema.json), `.github/workflows/kody.yml` (generated from `WORKFLOW_TEMPLATE` in [src/scripts/initFlow.ts](src/scripts/initFlow.ts)), and per-scheduled-agentResponsibility workflow files. Idempotent — pass `--force` to overwrite.
109
+ `kody-engine init` scaffolds [kody.config.json](kody.config.schema.json),
110
+ `.github/workflows/kody.yml` (generated from `WORKFLOW_TEMPLATE` in
111
+ [src/scripts/initFlow.ts](src/scripts/initFlow.ts)), and scheduled capability
112
+ workflow files. Idempotent — pass `--force` to overwrite.
98
113
 
99
114
  Required repo secrets: at least one model provider key (e.g. `MINIMAX_API_KEY`, `ANTHROPIC_API_KEY`). Recommended: `KODY_TOKEN` PAT so kody's commits trigger downstream CI and can modify `.github/workflows/*`.
100
115
 
@@ -123,10 +138,10 @@ kody-engine release-publish --issue <N> [--dry-run]
123
138
  kody-engine release-deploy --issue <N> [--dry-run]
124
139
  kody-engine npm-publish [--tag latest] [--access public] [--dry-run]
125
140
 
126
- # scheduled agentResponsibilities and goals
127
- kody-engine agent-responsibility-scheduler # fan out due .kody/agent-responsibilities/<slug>/ folders
128
- kody-engine agent-responsibility-tick --agentResponsibility <slug> [--force] # one agent tick for one agentResponsibility
129
- kody-engine agent-responsibility-tick-scripted --agentResponsibility <slug> [--force] # one deterministic tickScript agentResponsibility tick
141
+ # scheduled capabilities and goals
142
+ kody-engine agent-responsibility-scheduler # fan out due .kody/capabilities/<slug>/ folders plus legacy fallbacks
143
+ kody-engine agent-responsibility-tick --agentResponsibility <slug> [--force] # one agent tick for one capability
144
+ kody-engine agent-responsibility-tick-scripted --agentResponsibility <slug> [--force] # one deterministic tickScript capability tick
130
145
  kody-engine goal-scheduler # fan out active goal instances in configured state repo
131
146
  kody-engine goal-manager --goal <id> # advance one managed goal instance
132
147
 
@@ -142,11 +157,19 @@ kody-engine agent-ask --agent <slug> --message "..." # ad-hoc agent run
142
157
  kody-engine stats # inspect run/event history
143
158
  ```
144
159
 
145
- ### AgentResponsibilities
160
+ ### Capabilities
146
161
 
147
- A **agentResponsibility** is a folder at `.kody/agent-responsibilities/<slug>/` with `profile.json` metadata (`every`, `agent`, `action`, `agentAction`, `stage`, and related fields) plus human-owned prose in `agent-responsibility.md`. `agent-responsibility-scheduler` wakes on cron, finds due agentResponsibilities, and dispatches either `agent-responsibility-tick` for an agent tick or `agent-responsibility-tick-scripted` for a deterministic `tickScript` agentResponsibility. `kody-engine init` copies built-in starter agentResponsibilities and scaffolds `.kody/agents/kody.md`.
162
+ A **capability** is a folder at `.kody/capabilities/<slug>/` with
163
+ `profile.json` metadata (`action`, `capabilityKind`, `agent`, `every`, and
164
+ related fields) plus human-owned prose in `capability.md`. The scheduler wakes
165
+ on cron, finds due capabilities, and dispatches either
166
+ `agent-responsibility-tick` for an agent tick or
167
+ `agent-responsibility-tick-scripted` for a deterministic `tickScript`
168
+ capability. The CLI names are still legacy during migration.
148
169
 
149
- Locked-toolbox agentResponsibilities can declare `"tools": [...]` in `profile.json` to run with only the named high-level MCP intents plus `submit_state`; agentResponsibilities without `tools` keep the legacy Bash/gh toolbox.
170
+ Locked-toolbox capabilities can declare `"tools": [...]` in `profile.json` to
171
+ run with only the named high-level MCP intents plus `submit_state`; capabilities
172
+ without `tools` keep the legacy Bash/gh toolbox.
150
173
 
151
174
  ### `release`
152
175
 
@@ -154,7 +177,11 @@ Locked-toolbox agentResponsibilities can declare `"tools": [...]` in `profile.js
154
177
 
155
178
  ## Profiles
156
179
 
157
- A profile is declarative JSON + an adjacent `prompt.md`. See any directory under [src/agent-actions/](src/agent-actions/) for examples. Adding a new command = new directory + profile + prompt + any `.sh` scripts + registering any new shared TS utilities under [src/scripts/](src/scripts/). No executor, entry, or dispatch changes.
180
+ A profile is declarative JSON plus an adjacent markdown body. New public work
181
+ should live under `.kody/capabilities/<slug>/` with `capability.md`; legacy
182
+ implementations under [src/agent-actions/](src/agent-actions/) still show the
183
+ older split profile + prompt shape. Adding a new capability should not require
184
+ executor, entry, or dispatch changes.
158
185
 
159
186
  See [AGENTS.md](AGENTS.md) for the full architectural contract.
160
187
 
@@ -22,10 +22,16 @@ Design the smallest Kody model structure that satisfies the request. You may cre
22
22
 
23
23
  Use the current Kody vocabulary:
24
24
 
25
+ - intent: why the agency should care
26
+ - goal: what should become true
27
+ - loop: when to check or wake work
25
28
  - agent: who runs
26
- - agentResponsibility: why/when and public action ownership
27
- - agentAction: how work runs
28
- - goal: related task list/state
29
+ - capability: how the agency can produce a result
30
+
31
+ Use current storage names when producing files:
32
+
33
+ - agentResponsibility: capability contract, public action ownership, kind, agent, cadence, and output contract
34
+ - agentAction: capability implementation
29
35
 
30
36
  # Boundaries
31
37
 
@@ -56,11 +56,12 @@ export interface Profile {
56
56
  */
57
57
  role: "primitive" | "orchestrator" | "container" | "watch" | "utility"
58
58
  /**
59
- * A agentResponsibility is the WHY layer: it references an agentAction (the HOW) by name
60
- * rather than embedding it. When set, loader resolves the agentAction's
61
- * full profile (claudeCode/scripts/prompt/agents) and overlays agentResponsibility's
62
- * name + agent (WHO) + mentions. Absent -> this profile IS an
63
- * agentAction (defines its own how). agentAction = how, agent = who, agentResponsibility = why.
59
+ * A agentResponsibility is the capability contract storage layer: it references
60
+ * an agentAction implementation by name rather than embedding it. When set,
61
+ * loader resolves the agentAction's full profile (claudeCode/scripts/prompt/agents)
62
+ * and overlays agentResponsibility name + agent (who) + mentions. Absent -> this
63
+ * profile IS an agentAction implementation. Intent = why, agent = who,
64
+ * capability = how, agentAction = implementation.
64
65
  */
65
66
  agentAction?: string
66
67
  /**
@@ -469,23 +470,23 @@ export interface Context {
469
470
  * `@kody <next>` comment, which is silently ignored when Kody comments as
470
471
  * a GitHub App (bot author), stalling the pipeline at classify.
471
472
  */
472
- nextDispatch?: {
473
- action?: string
474
- agentResponsibility?: string
475
- agentAction?: string
476
- cliArgs: Record<string, unknown>
477
- saveReport?: boolean
478
- }
473
+ nextDispatch?: {
474
+ action?: string
475
+ agentResponsibility?: string
476
+ agentAction?: string
477
+ cliArgs: Record<string, unknown>
478
+ saveReport?: boolean
479
+ }
479
480
  /** In-process hand-off to a full Job, preserving job identity in task state. */
480
481
  nextJob?: Job
481
482
  /** Where to return after nextJob succeeds. Used by task-jobs to keep draining pending work. */
482
- afterNextJob?: {
483
- action?: string
484
- agentResponsibility?: string
485
- agentAction?: string
486
- cliArgs: Record<string, unknown>
487
- saveReport?: boolean
488
- }
483
+ afterNextJob?: {
484
+ action?: string
485
+ agentResponsibility?: string
486
+ agentAction?: string
487
+ cliArgs: Record<string, unknown>
488
+ saveReport?: boolean
489
+ }
489
490
  }
490
491
  /**
491
492
  * If a preflight script sets this to true, the executor skips the agent
@@ -517,8 +518,9 @@ export type AnyScript = PreflightScript | PostflightScript
517
518
  // Job — the unified work request (task-state jobs collect run attempts).
518
519
  //
519
520
  // A Job is the required work the engine tries to execute, regardless of how it
520
- // was triggered. It must reference a agentResponsibility/action (why). The agentAction is only
521
- // the agentResponsibility-selected implementation detail (how), never a standalone request.
521
+ // was triggered. It must reference an agentResponsibility/action capability
522
+ // contract. The agentAction is only the selected implementation detail, never a
523
+ // standalone request.
522
524
  // Task state stores this durable job separately from individual run attempts.
523
525
  // Two flavors:
524
526
  // - "instant" — run once now (an `@kody <verb>` comment or a manual dispatch)
@@ -552,6 +554,6 @@ export interface Job {
552
554
  flavor: JobFlavor
553
555
  /** Manual force-run (bypass cadence) for a scheduled job. */
554
556
  force?: boolean
555
- /** Save this responsibility run output as reports/<responsibility>.md. */
557
+ /** Ask the owning goal/loop to refresh reports/<goal-or-loop>.md after its persisted decision. */
556
558
  saveReport?: boolean
557
559
  }
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.258",
18
+ version: "0.4.260",
19
19
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative agentAction profiles.",
20
20
  license: "MIT",
21
21
  type: "module",
@@ -1364,12 +1364,14 @@ function listAgentResponsibilityFolderSlugs(absDir) {
1364
1364
  return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).filter((e) => isAgentResponsibilityFolder(path6.join(absDir, e.name))).map((e) => e.name).sort();
1365
1365
  }
1366
1366
  function isAgentResponsibilityFolder(dir) {
1367
- return fs4.existsSync(path6.join(dir, AGENT_RESPONSIBILITY_PROFILE_FILE)) && fs4.existsSync(path6.join(dir, AGENT_RESPONSIBILITY_BODY_FILE));
1367
+ return fs4.existsSync(path6.join(dir, AGENT_RESPONSIBILITY_PROFILE_FILE)) && (fs4.existsSync(path6.join(dir, CAPABILITY_BODY_FILE)) || fs4.existsSync(path6.join(dir, AGENT_RESPONSIBILITY_BODY_FILE)));
1368
1368
  }
1369
1369
  function readAgentResponsibilityFolder(root, slug2) {
1370
1370
  const dir = path6.join(root, slug2);
1371
1371
  const profilePath = path6.join(dir, AGENT_RESPONSIBILITY_PROFILE_FILE);
1372
- const bodyPath = path6.join(dir, AGENT_RESPONSIBILITY_BODY_FILE);
1372
+ const capabilityBodyPath = path6.join(dir, CAPABILITY_BODY_FILE);
1373
+ const legacyBodyPath = path6.join(dir, AGENT_RESPONSIBILITY_BODY_FILE);
1374
+ const bodyPath = fs4.existsSync(capabilityBodyPath) ? capabilityBodyPath : legacyBodyPath;
1373
1375
  if (!fs4.existsSync(profilePath) || !fs4.statSync(profilePath).isFile()) return null;
1374
1376
  if (!fs4.existsSync(bodyPath) || !fs4.statSync(bodyPath).isFile()) return null;
1375
1377
  try {
@@ -1403,6 +1405,7 @@ function parseAgentResponsibilityConfig(raw) {
1403
1405
  tools,
1404
1406
  agentActions: stringList(raw.agentActions),
1405
1407
  capabilityKind: capabilityKindField(raw.capabilityKind),
1408
+ role: stringField(raw.role),
1406
1409
  describe: stringField(raw.describe),
1407
1410
  stage: stringField(raw.stage),
1408
1411
  readsFrom: stringList(raw.readsFrom ?? raw.reads_from),
@@ -1446,12 +1449,13 @@ function capabilityKindField(value) {
1446
1449
  if (value === "observe" || value === "act" || value === "verify") return value;
1447
1450
  return void 0;
1448
1451
  }
1449
- var AGENT_RESPONSIBILITY_PROFILE_FILE, AGENT_RESPONSIBILITY_BODY_FILE;
1452
+ var AGENT_RESPONSIBILITY_PROFILE_FILE, AGENT_RESPONSIBILITY_BODY_FILE, CAPABILITY_BODY_FILE;
1450
1453
  var init_agent_responsibilityFolders = __esm({
1451
1454
  "src/agent-responsibilityFolders.ts"() {
1452
1455
  "use strict";
1453
1456
  AGENT_RESPONSIBILITY_PROFILE_FILE = "profile.json";
1454
1457
  AGENT_RESPONSIBILITY_BODY_FILE = "agent-responsibility.md";
1458
+ CAPABILITY_BODY_FILE = "capability.md";
1455
1459
  }
1456
1460
  });
1457
1461
 
@@ -1474,6 +1478,7 @@ function getCompanyStoreAssetRoot(kind) {
1474
1478
  const root = getCompanyStoreRoot();
1475
1479
  if (!root) return null;
1476
1480
  const folderByKind = {
1481
+ capabilities: "capabilities",
1477
1482
  agentResponsibilities: "agent-responsibilities",
1478
1483
  agentActions: "agent-actions",
1479
1484
  goals: "goals",
@@ -1583,12 +1588,18 @@ function getAgentActionsRoot() {
1583
1588
  function getProjectAgentActionsRoot() {
1584
1589
  return path8.join(process.cwd(), ".kody", "agent-actions");
1585
1590
  }
1591
+ function getProjectCapabilitiesRoot() {
1592
+ return path8.join(process.cwd(), ".kody", "capabilities");
1593
+ }
1586
1594
  function getProjectAgentResponsibilitiesRoot() {
1587
1595
  return path8.join(process.cwd(), ".kody", "agent-responsibilities");
1588
1596
  }
1589
1597
  function getCompanyStoreAgentActionsRoot() {
1590
1598
  return getCompanyStoreAssetRoot("agentActions");
1591
1599
  }
1600
+ function getCompanyStoreCapabilitiesRoot() {
1601
+ return getCompanyStoreAssetRoot("capabilities");
1602
+ }
1592
1603
  function getCompanyStoreAgentResponsibilitiesRoot() {
1593
1604
  return getCompanyStoreAssetRoot("agentResponsibilities");
1594
1605
  }
@@ -1608,12 +1619,28 @@ function getBuiltinAgentResponsibilitiesRoot() {
1608
1619
  return candidates[0];
1609
1620
  }
1610
1621
  function getAgentActionRoots() {
1622
+ const projectCapabilitiesRoot = getProjectCapabilitiesRoot();
1623
+ const storeCapabilitiesRoot = getCompanyStoreCapabilitiesRoot();
1611
1624
  const storeRoot = getCompanyStoreAgentActionsRoot();
1612
- return [getProjectAgentActionsRoot(), ...storeRoot ? [storeRoot] : [], getAgentActionsRoot()];
1625
+ return [
1626
+ projectCapabilitiesRoot,
1627
+ getProjectAgentActionsRoot(),
1628
+ ...storeCapabilitiesRoot ? [storeCapabilitiesRoot] : [],
1629
+ ...storeRoot ? [storeRoot] : [],
1630
+ getAgentActionsRoot()
1631
+ ];
1613
1632
  }
1614
1633
  function getAgentResponsibilityRoots(projectAgentResponsibilitiesRoot = getProjectAgentResponsibilitiesRoot()) {
1634
+ const projectCapabilitiesRoot = getProjectCapabilitiesRoot();
1635
+ const storeCapabilitiesRoot = getCompanyStoreCapabilitiesRoot();
1615
1636
  const storeRoot = getCompanyStoreAgentResponsibilitiesRoot();
1616
- return [projectAgentResponsibilitiesRoot, ...storeRoot ? [storeRoot] : [], getBuiltinAgentResponsibilitiesRoot()];
1637
+ return [
1638
+ projectCapabilitiesRoot,
1639
+ projectAgentResponsibilitiesRoot,
1640
+ ...storeCapabilitiesRoot ? [storeCapabilitiesRoot] : [],
1641
+ ...storeRoot ? [storeRoot] : [],
1642
+ getBuiltinAgentResponsibilitiesRoot()
1643
+ ];
1617
1644
  }
1618
1645
  function listAgentActions(roots = getAgentActionRoots()) {
1619
1646
  const rootList = typeof roots === "string" ? [roots] : roots;
@@ -1621,12 +1648,13 @@ function listAgentActions(roots = getAgentActionRoots()) {
1621
1648
  const out = [];
1622
1649
  for (const root of rootList) {
1623
1650
  if (!fs6.existsSync(root)) continue;
1651
+ const requireImplementationProfile = isCapabilityRoot(root);
1624
1652
  const entries = fs6.readdirSync(root, { withFileTypes: true });
1625
1653
  for (const ent of entries) {
1626
1654
  if (!ent.isDirectory()) continue;
1627
1655
  if (seen.has(ent.name)) continue;
1628
1656
  const profilePath = path8.join(root, ent.name, AGENT_RESPONSIBILITY_PROFILE_FILE);
1629
- if (fs6.existsSync(profilePath) && fs6.statSync(profilePath).isFile()) {
1657
+ if (fs6.existsSync(profilePath) && fs6.statSync(profilePath).isFile() && isImplementationProfile(profilePath, requireImplementationProfile)) {
1630
1658
  out.push({ name: ent.name, profilePath });
1631
1659
  seen.add(ent.name);
1632
1660
  }
@@ -1639,7 +1667,7 @@ function resolveAgentAction(name, roots = getAgentActionRoots()) {
1639
1667
  const rootList = typeof roots === "string" ? [roots] : roots;
1640
1668
  for (const root of rootList) {
1641
1669
  const profilePath = path8.join(root, name, "profile.json");
1642
- if (fs6.existsSync(profilePath) && fs6.statSync(profilePath).isFile()) {
1670
+ if (fs6.existsSync(profilePath) && fs6.statSync(profilePath).isFile() && isImplementationProfile(profilePath, isCapabilityRoot(root))) {
1643
1671
  return profilePath;
1644
1672
  }
1645
1673
  }
@@ -1654,18 +1682,29 @@ function listAgentResponsibilityActions(projectAgentResponsibilitiesRoot = getPr
1654
1682
  seen.add(action.action);
1655
1683
  out.push(action);
1656
1684
  };
1657
- const roots = getAgentResponsibilityRoots(projectAgentResponsibilitiesRoot);
1658
1685
  const executableRoots = getAgentActionRoots();
1659
- for (const action of listFolderAgentResponsibilityActions(roots[0], "project-folder")) add(action);
1660
- for (const action of listAgentActionResponsibilityActions(executableRoots[0], "project-agentAction")) add(action);
1661
- if (roots.length === 3) {
1662
- for (const action of listFolderAgentResponsibilityActions(roots[1], "company-store")) add(action);
1663
- for (const action of listAgentActionResponsibilityActions(executableRoots[1], "company-store-agentAction"))
1664
- add(action);
1665
- for (const action of listBuiltinAgentResponsibilityActions(roots[2])) add(action);
1666
- } else {
1667
- for (const action of listBuiltinAgentResponsibilityActions(roots[1])) add(action);
1668
- }
1686
+ const projectCapabilitiesRoot = getProjectCapabilitiesRoot();
1687
+ const projectLegacyRoot = projectAgentResponsibilitiesRoot;
1688
+ const storeCapabilitiesRoot = getCompanyStoreCapabilitiesRoot();
1689
+ const storeLegacyRoot = getCompanyStoreAgentResponsibilitiesRoot();
1690
+ const projectExecutableRoots = executableRoots.slice(0, 2);
1691
+ const storeExecutableRoots = executableRoots.slice(2, -1);
1692
+ for (const action of listFolderAgentResponsibilityActions(projectCapabilitiesRoot, "project-folder", true))
1693
+ add(action);
1694
+ for (const action of listFolderAgentResponsibilityActions(projectLegacyRoot, "project-folder")) add(action);
1695
+ for (const root of projectExecutableRoots) {
1696
+ for (const action of listAgentActionResponsibilityActions(root, "project-agentAction")) add(action);
1697
+ }
1698
+ if (storeCapabilitiesRoot) {
1699
+ for (const action of listFolderAgentResponsibilityActions(storeCapabilitiesRoot, "company-store", true)) add(action);
1700
+ }
1701
+ if (storeLegacyRoot) {
1702
+ for (const action of listFolderAgentResponsibilityActions(storeLegacyRoot, "company-store")) add(action);
1703
+ }
1704
+ for (const root of storeExecutableRoots) {
1705
+ for (const action of listAgentActionResponsibilityActions(root, "company-store-agentAction")) add(action);
1706
+ }
1707
+ for (const action of listBuiltinAgentResponsibilityActions(getBuiltinAgentResponsibilitiesRoot())) add(action);
1669
1708
  return out.sort((a, b) => a.action.localeCompare(b.action));
1670
1709
  }
1671
1710
  function resolveAgentResponsibilityAction(action, projectAgentResponsibilitiesRoot = getProjectAgentResponsibilitiesRoot()) {
@@ -1684,7 +1723,7 @@ function resolveAgentResponsibilityFolder(slug2, projectAgentResponsibilitiesRoo
1684
1723
  return null;
1685
1724
  }
1686
1725
  function resolveAgentResponsibilityExecution(agentResponsibility) {
1687
- const agentAction = agentResponsibility.config.agentAction ?? agentResponsibility.config.agentActions?.[0] ?? (agentResponsibility.config.tickScript ? "agent-responsibility-tick-scripted" : "agent-responsibility-tick");
1726
+ const agentAction = agentResponsibility.config.agentAction ?? agentResponsibility.config.agentActions?.[0] ?? (agentResponsibility.config.role ? agentResponsibility.slug : void 0) ?? (agentResponsibility.config.tickScript ? "agent-responsibility-tick-scripted" : "agent-responsibility-tick");
1688
1727
  const cliArgs = agentActionDeclaresInput(agentAction, "agentResponsibility") ? { agentResponsibility: agentResponsibility.slug } : {};
1689
1728
  return { agentAction, cliArgs };
1690
1729
  }
@@ -1706,6 +1745,19 @@ function agentActionDeclaresInput(agentAction, inputName) {
1706
1745
  function isSafeName(name) {
1707
1746
  return /^[a-z][a-z0-9-]*$/.test(name) && !name.includes("..");
1708
1747
  }
1748
+ function isCapabilityRoot(root) {
1749
+ const normalized = path8.normalize(root);
1750
+ return path8.basename(normalized) === "capabilities" && path8.basename(path8.dirname(normalized)) === ".kody";
1751
+ }
1752
+ function isImplementationProfile(profilePath, requireImplementationProfile) {
1753
+ if (!requireImplementationProfile) return true;
1754
+ try {
1755
+ const raw = JSON.parse(fs6.readFileSync(profilePath, "utf-8"));
1756
+ return typeof raw.role === "string" && PUBLIC_AGENT_ACTION_ACTION_ROLES.has(raw.role);
1757
+ } catch {
1758
+ return false;
1759
+ }
1760
+ }
1709
1761
  function listAgentActionResponsibilityActions(root, source) {
1710
1762
  if (!fs6.existsSync(root) || !fs6.statSync(root).isDirectory()) return [];
1711
1763
  const out = [];
@@ -1734,13 +1786,14 @@ function listAgentActionResponsibilityActions(root, source) {
1734
1786
  }
1735
1787
  return out.sort((a, b) => a.action.localeCompare(b.action));
1736
1788
  }
1737
- function listFolderAgentResponsibilityActions(root, source) {
1789
+ function listFolderAgentResponsibilityActions(root, source, requireCapabilityKind = false) {
1738
1790
  if (!fs6.existsSync(root) || !fs6.statSync(root).isDirectory()) return [];
1739
1791
  const out = [];
1740
1792
  for (const slug2 of listAgentResponsibilityFolderSlugs(root)) {
1741
1793
  if (!isSafeName(slug2)) continue;
1742
1794
  const agentResponsibility = readAgentResponsibilityFolder(root, slug2);
1743
1795
  if (!agentResponsibility) continue;
1796
+ if (requireCapabilityKind && !agentResponsibility.config.capabilityKind) continue;
1744
1797
  const action = agentResponsibility.config.action ?? slug2;
1745
1798
  const { agentAction, cliArgs } = resolveAgentResponsibilityExecution(agentResponsibility);
1746
1799
  out.push({
@@ -8241,6 +8294,224 @@ var init_agent_responsibilityEvidence = __esm({
8241
8294
  }
8242
8295
  });
8243
8296
 
8297
+ // src/goal/report.ts
8298
+ function goalDashboardReportRequested(data, state) {
8299
+ return data.jobSaveReport === true || state?.extra.saveReport === true;
8300
+ }
8301
+ function refreshGoalDashboardReport(input) {
8302
+ const evidenceItems = input.evidenceItems ?? [];
8303
+ if (!goalDashboardReportRequested(input.data, input.state)) return null;
8304
+ if (!REPORT_SLUG_RE.test(input.goalId)) {
8305
+ throw new Error(`goal report: invalid goal id "${input.goalId}"`);
8306
+ }
8307
+ const filePath = `reports/${input.goalId}.md`;
8308
+ const body = goalReportBody(
8309
+ input.goalId,
8310
+ input.state,
8311
+ snapshotFromState(input.goalId, input.state),
8312
+ latestGoalRunLogEvent(input.data, input.goalId),
8313
+ evidenceItems
8314
+ );
8315
+ const current = readStateText(input.config, input.cwd, filePath);
8316
+ if (current?.content === body) {
8317
+ const report2 = { slug: input.goalId, path: current.path, changed: false };
8318
+ recordGoalReport(input.data, report2);
8319
+ return report2;
8320
+ }
8321
+ upsertStateText(input.config, input.cwd, filePath, body, `chore(reports): refresh ${input.goalId}`);
8322
+ const report = { slug: input.goalId, path: filePath, changed: true };
8323
+ recordGoalReport(input.data, report);
8324
+ return report;
8325
+ }
8326
+ function responsibilityEvidenceOutput(evidence) {
8327
+ return {
8328
+ kind: "responsibility-evidence",
8329
+ sources: evidence.sources,
8330
+ status: evidence.status,
8331
+ summary: evidence.summary,
8332
+ evidence: evidence.evidence ?? {},
8333
+ facts: evidence.facts,
8334
+ artifacts: evidence.artifacts,
8335
+ missingEvidence: evidence.missingEvidence,
8336
+ blockers: evidence.blockers
8337
+ };
8338
+ }
8339
+ function goalReportBody(goalId, state, snapshot, latestEvent, evidenceItems) {
8340
+ const outputs = evidenceItems.map(responsibilityEvidenceOutput);
8341
+ const latestOutput = outputs.at(-1);
8342
+ const facts = recordField2(snapshot, "facts") ?? recordField2(state.extra, "facts") ?? {};
8343
+ const blockers = uniqueStrings2([
8344
+ ...stringArrayField(snapshot, "blockers"),
8345
+ ...stringArrayField(latestEvent, "blockers"),
8346
+ ...evidenceItems.flatMap((item) => item.blockers)
8347
+ ]);
8348
+ const missingEvidence = uniqueStrings2([
8349
+ ...stringArrayField(snapshot, "missingEvidence"),
8350
+ ...evidenceItems.flatMap((item) => item.missingEvidence)
8351
+ ]);
8352
+ const artifacts = uniqueArtifacts2([
8353
+ ...evidenceItems.flatMap((item) => item.artifacts),
8354
+ ...artifactArrayField(latestEvent, "artifacts")
8355
+ ]);
8356
+ return [
8357
+ `# ${goalId}`,
8358
+ "",
8359
+ "## Status",
8360
+ `- State: ${state.state}`,
8361
+ `- Stage: ${stringField3(snapshot, "stage") ?? stringField3(state.extra, "stage") ?? "unknown"}`,
8362
+ `- Next step: ${nextStepFromEvent(state, snapshot, latestOutput, latestEvent)}`,
8363
+ `- Updated: ${state.updatedAt ?? state.createdAt ?? state.startedAt ?? "unknown"}`,
8364
+ "",
8365
+ "## Decision",
8366
+ `- Event: ${stringField3(latestEvent, "event") ?? "unknown"}`,
8367
+ `- Reason: ${decisionReason(state, latestEvent, latestOutput, missingEvidence, blockers)}`,
8368
+ `- Required evidence: ${listOrNone(stringArrayField(snapshot, "requiredEvidence"))}`,
8369
+ `- Satisfied evidence: ${listOrNone(stringArrayField(snapshot, "satisfiedEvidence"))}`,
8370
+ `- Missing evidence: ${listOrNone(missingEvidence)}`,
8371
+ `- Blockers: ${listOrNone(blockers)}`,
8372
+ "",
8373
+ "## Responsibility Evidence",
8374
+ ...responsibilityEvidenceMarkdown(outputs),
8375
+ "",
8376
+ "## Facts",
8377
+ fencedJson(facts),
8378
+ "",
8379
+ "## Artifacts",
8380
+ ...artifactMarkdown(artifacts),
8381
+ ""
8382
+ ].join("\n");
8383
+ }
8384
+ function responsibilityEvidenceMarkdown(outputs) {
8385
+ if (outputs.length === 0) return ["- none"];
8386
+ return outputs.flatMap((output, index) => evidenceOutputMarkdown(index + 1, output));
8387
+ }
8388
+ function decisionReason(state, latestEvent, latestOutput, missingEvidence, blockers) {
8389
+ if (state.state === "done") return "destination evidence satisfied";
8390
+ if (blockers.length > 0) return blockers[0] ?? "blocked";
8391
+ const eventReason = stringField3(latestEvent, "reason") ?? stringField3(recordField2(latestEvent, "decision"), "reason");
8392
+ if (eventReason) return eventReason;
8393
+ const summary = stringField3(latestOutput, "summary");
8394
+ if (summary) return summary;
8395
+ if (missingEvidence.length > 0) return `waiting for ${missingEvidence[0]}`;
8396
+ return "waiting for more evidence";
8397
+ }
8398
+ function evidenceOutputMarkdown(index, output) {
8399
+ return [
8400
+ `### Output ${index}`,
8401
+ `- Status: ${stringField3(output, "status") ?? "unknown"}`,
8402
+ `- Summary: ${stringField3(output, "summary") ?? "no summary"}`,
8403
+ `- Sources: ${listOrNone(stringArrayField(output, "sources"))}`,
8404
+ `- Evidence values: ${inlineJson(recordField2(output, "evidence") ?? {})}`,
8405
+ `- Missing evidence: ${listOrNone(stringArrayField(output, "missingEvidence"))}`,
8406
+ `- Blockers: ${listOrNone(stringArrayField(output, "blockers"))}`,
8407
+ ""
8408
+ ];
8409
+ }
8410
+ function artifactMarkdown(artifacts) {
8411
+ if (artifacts.length === 0) return ["- none"];
8412
+ return artifacts.map((artifact) => {
8413
+ if (artifact.url) return `- [${artifact.label}](${artifact.url})`;
8414
+ return `- ${artifact.label}: ${artifact.path}`;
8415
+ });
8416
+ }
8417
+ function fencedJson(value) {
8418
+ return ["```json", JSON.stringify(value, null, 2), "```"].join("\n");
8419
+ }
8420
+ function inlineJson(value) {
8421
+ return JSON.stringify(value);
8422
+ }
8423
+ function listOrNone(values) {
8424
+ return values.length > 0 ? values.join(", ") : "none";
8425
+ }
8426
+ function uniqueStrings2(values) {
8427
+ return [...new Set(values)].sort();
8428
+ }
8429
+ function stringField3(record2, key) {
8430
+ const value = record2?.[key];
8431
+ return typeof value === "string" && value.trim() ? value : void 0;
8432
+ }
8433
+ function recordField2(record2, key) {
8434
+ const value = record2?.[key];
8435
+ return value && typeof value === "object" && !Array.isArray(value) ? { ...value } : void 0;
8436
+ }
8437
+ function stringArrayField(record2, key) {
8438
+ const value = record2?.[key];
8439
+ return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : [];
8440
+ }
8441
+ function artifactArrayField(record2, key) {
8442
+ const value = record2?.[key];
8443
+ if (!Array.isArray(value)) return [];
8444
+ return value.filter(isArtifact);
8445
+ }
8446
+ function isArtifact(value) {
8447
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
8448
+ const record2 = value;
8449
+ return typeof record2.label === "string" && (record2.url === void 0 || typeof record2.url === "string") && (record2.path === void 0 || typeof record2.path === "string");
8450
+ }
8451
+ function uniqueArtifacts2(artifacts) {
8452
+ const seen = /* @__PURE__ */ new Set();
8453
+ const out = [];
8454
+ for (const artifact of artifacts) {
8455
+ const key = `${artifact.label}
8456
+ ${artifact.url ?? ""}
8457
+ ${artifact.path ?? ""}`;
8458
+ if (seen.has(key)) continue;
8459
+ seen.add(key);
8460
+ out.push(artifact);
8461
+ }
8462
+ return out;
8463
+ }
8464
+ function nextStepFromEvent(state, goalAfter, responsibilityOutput, latestEvent) {
8465
+ if (state.state === "done") return "done";
8466
+ const decisionKind = stringField3(recordField2(latestEvent, "decision"), "kind") ?? stringField3(latestEvent, "status");
8467
+ if (decisionKind === "done") return "done";
8468
+ if (decisionKind === "dispatch") return "dispatch";
8469
+ if (decisionKind === "blocked" || decisionKind === "reject-evidence") return "block";
8470
+ if (decisionKind === "wait" || decisionKind === "idle" || decisionKind === "no-state-change") return "wait";
8471
+ if (responsibilityOutput) return nextStepFromEvidence(goalAfter, responsibilityOutput);
8472
+ return "wait";
8473
+ }
8474
+ function nextStepFromEvidence(goalAfter, responsibilityOutput) {
8475
+ const status = typeof responsibilityOutput.status === "string" ? responsibilityOutput.status : "";
8476
+ const outputBlockers = stringArrayField(responsibilityOutput, "blockers");
8477
+ const goalBlockers = stringArrayField(goalAfter, "blockers");
8478
+ const missingEvidence = stringArrayField(goalAfter, "missingEvidence");
8479
+ if (goalAfter && missingEvidence.length === 0) return "done";
8480
+ if (status === "fail" || status === "blocked" || outputBlockers.length > 0) return "rescue";
8481
+ if (goalBlockers.length > 0) return "block";
8482
+ if (missingEvidence.length > 0 && status !== "noop") return "dispatch";
8483
+ return "wait";
8484
+ }
8485
+ function snapshotFromState(goalId, state) {
8486
+ const managed = managedGoalFromState(state);
8487
+ return managed ? goalRunLogSnapshot(goalId, state.state, managed) : null;
8488
+ }
8489
+ function latestGoalRunLogEvent(data, goalId) {
8490
+ const logs = data[GOAL_LOGS_KEY];
8491
+ if (!logs || typeof logs !== "object" || Array.isArray(logs)) return void 0;
8492
+ const log2 = logs[goalId];
8493
+ if (!log2 || typeof log2 !== "object" || Array.isArray(log2)) return void 0;
8494
+ const events = log2.events;
8495
+ if (!Array.isArray(events)) return void 0;
8496
+ const latest = events.at(-1);
8497
+ return latest && typeof latest === "object" && !Array.isArray(latest) ? latest : void 0;
8498
+ }
8499
+ function recordGoalReport(data, report) {
8500
+ const prior = Array.isArray(data.goalReports) ? data.goalReports : [];
8501
+ data.goalReports = [...prior, report];
8502
+ }
8503
+ var REPORT_SLUG_RE, GOAL_LOGS_KEY;
8504
+ var init_report = __esm({
8505
+ "src/goal/report.ts"() {
8506
+ "use strict";
8507
+ init_stateRepo();
8508
+ init_manager();
8509
+ init_runLog();
8510
+ REPORT_SLUG_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/;
8511
+ GOAL_LOGS_KEY = "__goalRunLogs";
8512
+ }
8513
+ });
8514
+
8244
8515
  // src/scripts/applyAgentResponsibilityReports.ts
8245
8516
  function flushLogs(ctx) {
8246
8517
  try {
@@ -8252,6 +8523,24 @@ function flushLogs(ctx) {
8252
8523
  );
8253
8524
  }
8254
8525
  }
8526
+ function refreshReportOrFail(ctx, goalId, state, evidenceItems) {
8527
+ try {
8528
+ refreshGoalDashboardReport({
8529
+ config: ctx.config,
8530
+ cwd: ctx.cwd,
8531
+ data: ctx.data,
8532
+ goalId,
8533
+ state,
8534
+ evidenceItems
8535
+ });
8536
+ } catch (err) {
8537
+ fail(ctx, err instanceof Error ? err.message : String(err));
8538
+ }
8539
+ }
8540
+ function fail(ctx, reason) {
8541
+ ctx.output.reason = ctx.output.reason ? `${ctx.output.reason}; ${reason}` : reason;
8542
+ if (ctx.output.exitCode === 0) ctx.output.exitCode = 99;
8543
+ }
8255
8544
  function collectReports(raw, agentResult) {
8256
8545
  const out = [];
8257
8546
  if (Array.isArray(raw)) {
@@ -8304,23 +8593,10 @@ function completeSatisfiedManagedGoal(state) {
8304
8593
  if (decision.kind !== "done") return state;
8305
8594
  return writeManagedGoalToState({ ...state, state: "done" }, managed);
8306
8595
  }
8307
- function snapshotFromState(goalId, state) {
8596
+ function snapshotFromState2(goalId, state) {
8308
8597
  const managed = managedGoalFromState(state);
8309
8598
  return managed ? goalRunLogSnapshot(goalId, state.state, managed) : null;
8310
8599
  }
8311
- function responsibilityEvidenceOutput(evidence) {
8312
- return {
8313
- kind: "responsibility-evidence",
8314
- sources: evidence.sources,
8315
- status: evidence.status,
8316
- summary: evidence.summary,
8317
- evidence: evidence.evidence ?? {},
8318
- facts: evidence.facts,
8319
- artifacts: evidence.artifacts,
8320
- missingEvidence: evidence.missingEvidence,
8321
- blockers: evidence.blockers
8322
- };
8323
- }
8324
8600
  function evidenceInspection(goalBefore, goalAfter, responsibilityOutput, explicitEvidence) {
8325
8601
  return {
8326
8602
  expectedEvidence: {
@@ -8342,22 +8618,22 @@ function evidenceDecision(change, goalAfter, responsibilityOutput) {
8342
8618
  return {
8343
8619
  kind: change ? "accept-evidence" : "no-state-change",
8344
8620
  status: responsibilityOutput.status,
8345
- nextStep: nextStepFromEvidence(goalAfter, responsibilityOutput),
8621
+ nextStep: nextStepFromEvidence2(goalAfter, responsibilityOutput),
8346
8622
  reason: responsibilityOutput.summary
8347
8623
  };
8348
8624
  }
8349
- function nextStepFromEvidence(goalAfter, responsibilityOutput) {
8625
+ function nextStepFromEvidence2(goalAfter, responsibilityOutput) {
8350
8626
  const status = typeof responsibilityOutput.status === "string" ? responsibilityOutput.status : "";
8351
- const outputBlockers = stringArrayField(responsibilityOutput, "blockers");
8352
- const goalBlockers = stringArrayField(goalAfter, "blockers");
8353
- const missingEvidence = stringArrayField(goalAfter, "missingEvidence");
8627
+ const outputBlockers = stringArrayField2(responsibilityOutput, "blockers");
8628
+ const goalBlockers = stringArrayField2(goalAfter, "blockers");
8629
+ const missingEvidence = stringArrayField2(goalAfter, "missingEvidence");
8354
8630
  if (goalAfter && missingEvidence.length === 0) return "done";
8355
8631
  if (status === "fail" || status === "blocked" || outputBlockers.length > 0) return "rescue";
8356
8632
  if (goalBlockers.length > 0) return "block";
8357
8633
  if (missingEvidence.length > 0 && status !== "noop") return "dispatch";
8358
8634
  return "wait";
8359
8635
  }
8360
- function stringArrayField(record2, key) {
8636
+ function stringArrayField2(record2, key) {
8361
8637
  const value = record2?.[key];
8362
8638
  return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : [];
8363
8639
  }
@@ -8373,6 +8649,7 @@ var init_applyAgentResponsibilityReports = __esm({
8373
8649
  init_agent_responsibilityReport();
8374
8650
  init_agent_responsibilityResult();
8375
8651
  init_manager();
8652
+ init_report();
8376
8653
  init_runLog();
8377
8654
  init_state2();
8378
8655
  init_stateStore();
@@ -8410,9 +8687,9 @@ var init_applyAgentResponsibilityReports = __esm({
8410
8687
  }
8411
8688
  let next = prior;
8412
8689
  for (const evidence of goalEvidence) {
8413
- const beforeSnapshot = snapshotFromState(goalId, next);
8690
+ const beforeSnapshot = snapshotFromState2(goalId, next);
8414
8691
  next = applyAgentResponsibilityEvidenceToGoalState(next, evidence);
8415
- const afterSnapshot = snapshotFromState(goalId, next);
8692
+ const afterSnapshot = snapshotFromState2(goalId, next);
8416
8693
  const change = goalRunLogChange(beforeSnapshot, afterSnapshot);
8417
8694
  const output = responsibilityEvidenceOutput(evidence);
8418
8695
  stageGoalRunLogEvent(ctx.data, goalId, {
@@ -8435,9 +8712,9 @@ var init_applyAgentResponsibilityReports = __esm({
8435
8712
  change
8436
8713
  });
8437
8714
  }
8438
- const beforeCompletionSnapshot = snapshotFromState(goalId, next);
8715
+ const beforeCompletionSnapshot = snapshotFromState2(goalId, next);
8439
8716
  next = completeSatisfiedManagedGoal(next);
8440
- const afterCompletionSnapshot = snapshotFromState(goalId, next);
8717
+ const afterCompletionSnapshot = snapshotFromState2(goalId, next);
8441
8718
  if (prior.state !== "done" && next.state === "done") {
8442
8719
  stageGoalRunLogEvent(ctx.data, goalId, {
8443
8720
  source: "goal-loop",
@@ -8455,12 +8732,16 @@ var init_applyAgentResponsibilityReports = __esm({
8455
8732
  change: goalRunLogChange(beforeCompletionSnapshot, afterCompletionSnapshot)
8456
8733
  });
8457
8734
  }
8458
- if (serializeGoalState(next) === serializeGoalState(prior)) {
8735
+ const changed = serializeGoalState(next) !== serializeGoalState(prior);
8736
+ const nextForOutput = changed ? { ...next, updatedAt: nowIso() } : next;
8737
+ try {
8738
+ if (changed) {
8739
+ putGoalState(ctx.config, goalId, nextForOutput, describeMessage(goalId, goalEvidence), ctx.cwd);
8740
+ }
8741
+ refreshReportOrFail(ctx, goalId, nextForOutput, goalEvidence);
8742
+ } finally {
8459
8743
  flushLogs(ctx);
8460
- continue;
8461
8744
  }
8462
- putGoalState(ctx.config, goalId, { ...next, updatedAt: nowIso() }, describeMessage(goalId, goalEvidence), ctx.cwd);
8463
- flushLogs(ctx);
8464
8745
  }
8465
8746
  };
8466
8747
  }
@@ -8732,6 +9013,22 @@ var init_commitAndPush = __esm({
8732
9013
  });
8733
9014
 
8734
9015
  // src/scripts/commitGoalState.ts
9016
+ function refreshReportOrFail2(ctx, goalId, state) {
9017
+ if (!state) return;
9018
+ try {
9019
+ refreshGoalDashboardReport({
9020
+ config: ctx.config,
9021
+ cwd: ctx.cwd,
9022
+ data: ctx.data,
9023
+ goalId,
9024
+ state
9025
+ });
9026
+ } catch (err) {
9027
+ const reason = err instanceof Error ? err.message : String(err);
9028
+ ctx.output.reason = ctx.output.reason ? `${ctx.output.reason}; ${reason}` : reason;
9029
+ if (ctx.output.exitCode === 0) ctx.output.exitCode = 99;
9030
+ }
9031
+ }
8735
9032
  function flushLogs2(ctx) {
8736
9033
  try {
8737
9034
  flushGoalRunLogEvents(ctx.config, ctx.cwd, ctx.data);
@@ -8750,6 +9047,7 @@ var commitGoalState;
8750
9047
  var init_commitGoalState = __esm({
8751
9048
  "src/scripts/commitGoalState.ts"() {
8752
9049
  "use strict";
9050
+ init_report();
8753
9051
  init_runLog();
8754
9052
  init_stateStore();
8755
9053
  commitGoalState = async (ctx) => {
@@ -8759,6 +9057,7 @@ var init_commitGoalState = __esm({
8759
9057
  return;
8760
9058
  }
8761
9059
  if (ctx.data.goalPersistChanged !== true) {
9060
+ refreshReportOrFail2(ctx, goal.id, goal.raw);
8762
9061
  flushLogs2(ctx);
8763
9062
  return;
8764
9063
  }
@@ -8769,6 +9068,7 @@ var init_commitGoalState = __esm({
8769
9068
  }
8770
9069
  try {
8771
9070
  putGoalState(ctx.config, goal.id, updated, describeCommitMessage(goal), ctx.cwd);
9071
+ refreshReportOrFail2(ctx, goal.id, updated);
8772
9072
  } catch (err) {
8773
9073
  process.stderr.write(
8774
9074
  `[goal-manager] commitGoalState: persist to state repo failed (${err instanceof Error ? err.message : String(err)}); will retry next tick
@@ -12039,7 +12339,7 @@ var init_markFlowSuccess = __esm({
12039
12339
  });
12040
12340
 
12041
12341
  // src/goal/operations.ts
12042
- function fail(err) {
12342
+ function fail2(err) {
12043
12343
  if (err instanceof Error) {
12044
12344
  const lines = err.message.split("\n").filter(Boolean);
12045
12345
  return { ok: false, error: lines[0] ?? err.message };
@@ -12051,7 +12351,7 @@ function commentOnIssue(issueNumber, body, cwd) {
12051
12351
  gh(["issue", "comment", String(issueNumber), "--body", body], { cwd });
12052
12352
  return { ok: true };
12053
12353
  } catch (err) {
12054
- return fail(err);
12354
+ return fail2(err);
12055
12355
  }
12056
12356
  }
12057
12357
  function mergePrSquash(prNumber, cwd) {
@@ -12059,7 +12359,7 @@ function mergePrSquash(prNumber, cwd) {
12059
12359
  gh(["pr", "merge", String(prNumber), "--squash", "--delete-branch"], { cwd });
12060
12360
  return { ok: true };
12061
12361
  } catch (err) {
12062
- return fail(err);
12362
+ return fail2(err);
12063
12363
  }
12064
12364
  }
12065
12365
  var init_operations = __esm({
@@ -12590,21 +12890,21 @@ var init_openQaIssue = __esm({
12590
12890
  ctx.data.action = failedAction3(reason);
12591
12891
  return;
12592
12892
  }
12593
- const reportBody2 = agentResult.finalText.trim();
12594
- if (!reportBody2) {
12893
+ const reportBody = agentResult.finalText.trim();
12894
+ if (!reportBody) {
12595
12895
  process.stderr.write("qa-engineer: agent produced no report body\n");
12596
12896
  ctx.output.exitCode = 1;
12597
12897
  ctx.output.reason = "empty report body";
12598
12898
  ctx.data.action = failedAction3("empty report body");
12599
12899
  return;
12600
12900
  }
12601
- const verdict = detectVerdict(reportBody2);
12901
+ const verdict = detectVerdict(reportBody);
12602
12902
  ctx.data.qaVerdict = verdict;
12603
- ctx.data.qaReport = reportBody2;
12903
+ ctx.data.qaReport = reportBody;
12604
12904
  const existingIssue = ctx.args.issue;
12605
12905
  if (typeof existingIssue === "number" && Number.isFinite(existingIssue) && existingIssue > 0) {
12606
12906
  try {
12607
- postIssueComment(existingIssue, reportBody2, ctx.cwd);
12907
+ postIssueComment(existingIssue, reportBody, ctx.cwd);
12608
12908
  } catch (err) {
12609
12909
  const msg = err instanceof Error ? err.message : String(err);
12610
12910
  ctx.output.exitCode = 4;
@@ -12626,7 +12926,7 @@ QA_REPORT_POSTED=https://github.com/${ctx.config.github.owner}/${ctx.config.gith
12626
12926
  const hasLabel = ensureLabel2(ctx.cwd);
12627
12927
  let created;
12628
12928
  try {
12629
- created = createQaIssue(title, reportBody2, hasLabel, ctx.cwd);
12929
+ created = createQaIssue(title, reportBody, hasLabel, ctx.cwd);
12630
12930
  } catch (err) {
12631
12931
  const msg = err instanceof Error ? err.message : String(err);
12632
12932
  ctx.output.exitCode = 4;
@@ -15958,86 +16258,6 @@ var init_writeJobStateFile = __esm({
15958
16258
  }
15959
16259
  });
15960
16260
 
15961
- // src/scripts/writeResponsibilityReport.ts
15962
- function writeReport(ctx, profile, agentResult) {
15963
- const slug2 = responsibilitySlug(ctx);
15964
- if (!slug2) {
15965
- fail2(ctx, "writeResponsibilityReport: missing responsibility slug");
15966
- return;
15967
- }
15968
- if (!REPORT_SLUG_RE.test(slug2)) {
15969
- fail2(ctx, `writeResponsibilityReport: invalid responsibility slug "${slug2}"`);
15970
- return;
15971
- }
15972
- const body = reportBody(ctx, agentResult, profile);
15973
- if (!body.trim()) {
15974
- fail2(ctx, `writeResponsibilityReport: ${slug2} produced no report output`);
15975
- return;
15976
- }
15977
- const filePath = `reports/${slug2}.md`;
15978
- const current = readStateText(ctx.config, ctx.cwd, filePath);
15979
- if (current?.content === body) {
15980
- ctx.data.responsibilityReport = { slug: slug2, path: current.path, changed: false };
15981
- return;
15982
- }
15983
- upsertStateText(
15984
- ctx.config,
15985
- ctx.cwd,
15986
- filePath,
15987
- body,
15988
- `chore(reports): refresh ${slug2}`
15989
- );
15990
- ctx.data.responsibilityReport = { slug: slug2, path: filePath, changed: true };
15991
- }
15992
- function responsibilitySlug(ctx) {
15993
- const candidates = [
15994
- ctx.data.jobAgentResponsibility,
15995
- ctx.data.agentResponsibilitySlug,
15996
- ctx.data.jobSlug
15997
- ];
15998
- for (const candidate of candidates) {
15999
- if (typeof candidate === "string" && candidate.trim()) return candidate.trim();
16000
- }
16001
- return null;
16002
- }
16003
- function reportBody(ctx, agentResult, profile) {
16004
- const prSummary = ctx.data.prSummary;
16005
- if (typeof prSummary === "string" && prSummary.trim()) return ensureTrailingNewline(prSummary.trim());
16006
- if (agentResult?.finalText.trim()) return ensureTrailingNewline(agentResult.finalText.trim());
16007
- const reason = ctx.output.reason || ctx.data.agentFailureReason || agentResult?.error;
16008
- if (typeof reason === "string" && reason.trim()) {
16009
- return `# ${profile.name}
16010
-
16011
- FAILED: ${reason.trim()}
16012
- `;
16013
- }
16014
- return "";
16015
- }
16016
- function fail2(ctx, reason) {
16017
- ctx.output.reason = ctx.output.reason ? `${ctx.output.reason}; ${reason}` : reason;
16018
- if (ctx.output.exitCode === 0) ctx.output.exitCode = 99;
16019
- }
16020
- function ensureTrailingNewline(value) {
16021
- return value.endsWith("\n") ? value : `${value}
16022
- `;
16023
- }
16024
- var REPORT_SLUG_RE, writeResponsibilityReport;
16025
- var init_writeResponsibilityReport = __esm({
16026
- "src/scripts/writeResponsibilityReport.ts"() {
16027
- "use strict";
16028
- init_stateRepo();
16029
- REPORT_SLUG_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/;
16030
- writeResponsibilityReport = async (ctx, profile, agentResult) => {
16031
- if (ctx.data.jobSaveReport !== true) return;
16032
- try {
16033
- writeReport(ctx, profile, agentResult);
16034
- } catch (err) {
16035
- fail2(ctx, `writeResponsibilityReport: ${err instanceof Error ? err.message : String(err)}`);
16036
- }
16037
- };
16038
- }
16039
- });
16040
-
16041
16261
  // src/scripts/index.ts
16042
16262
  var preflightScripts, postflightScripts, allScriptNames;
16043
16263
  var init_scripts = __esm({
@@ -16139,7 +16359,6 @@ var init_scripts = __esm({
16139
16359
  init_writeAgentRunSummary();
16140
16360
  init_writeIssueStateComment();
16141
16361
  init_writeJobStateFile();
16142
- init_writeResponsibilityReport();
16143
16362
  preflightScripts = {
16144
16363
  runFlow,
16145
16364
  fixFlow,
@@ -16218,7 +16437,6 @@ var init_scripts = __esm({
16218
16437
  postReviewResult,
16219
16438
  persistArtifacts,
16220
16439
  writeAgentRunSummary,
16221
- writeResponsibilityReport,
16222
16440
  saveTaskState,
16223
16441
  mirrorStateToPr,
16224
16442
  startFlow,
@@ -16778,7 +16996,6 @@ async function runAgentAction(profileName, input) {
16778
16996
  outcome: postOutcome
16779
16997
  });
16780
16998
  }
16781
- await writeResponsibilityReport(ctx, profile, agentResult);
16782
16999
  return finishAndEnd({
16783
17000
  exitCode: ctx.output.exitCode ?? 0,
16784
17001
  prUrl: ctx.output.prUrl,
@@ -17176,9 +17393,8 @@ var init_executor = __esm({
17176
17393
  init_registry();
17177
17394
  init_runtimePaths();
17178
17395
  init_scripts();
17179
- init_writeResponsibilityReport();
17180
- init_subagents();
17181
17396
  init_stateWorkspace();
17397
+ init_subagents();
17182
17398
  init_task_artifacts();
17183
17399
  init_tools();
17184
17400
  MUTATING_POSTFLIGHTS = /* @__PURE__ */ new Set([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.258",
3
+ "version": "0.4.260",
4
4
  "description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative agentAction profiles.",
5
5
  "license": "MIT",
6
6
  "type": "module",