@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 +44 -17
- package/dist/agent-actions/agent-factory/prompt.md +9 -3
- package/dist/agent-actions/types.ts +24 -22
- package/dist/bin/kody.js +359 -143
- package/package.json +1 -1
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
|
|
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 —
|
|
78
|
-
│ src/executor.ts — runs
|
|
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
|
-
│
|
|
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
|
|
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
|
|
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),
|
|
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
|
|
127
|
-
kody-engine agent-responsibility-scheduler # fan out due .kody/
|
|
128
|
-
kody-engine agent-responsibility-tick --agentResponsibility <slug> [--force] # one agent tick for one
|
|
129
|
-
kody-engine agent-responsibility-tick-scripted --agentResponsibility <slug> [--force] # one deterministic tickScript
|
|
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
|
-
###
|
|
160
|
+
### Capabilities
|
|
146
161
|
|
|
147
|
-
A **
|
|
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
|
|
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
|
|
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
|
-
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
|
60
|
-
* rather than embedding it. When set,
|
|
61
|
-
* full profile (claudeCode/scripts/prompt/agents)
|
|
62
|
-
* name + agent (
|
|
63
|
-
*
|
|
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
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
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
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
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
|
|
521
|
-
// the
|
|
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
|
-
/**
|
|
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.
|
|
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
|
|
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 [
|
|
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 [
|
|
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
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
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
|
|
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:
|
|
8621
|
+
nextStep: nextStepFromEvidence2(goalAfter, responsibilityOutput),
|
|
8346
8622
|
reason: responsibilityOutput.summary
|
|
8347
8623
|
};
|
|
8348
8624
|
}
|
|
8349
|
-
function
|
|
8625
|
+
function nextStepFromEvidence2(goalAfter, responsibilityOutput) {
|
|
8350
8626
|
const status = typeof responsibilityOutput.status === "string" ? responsibilityOutput.status : "";
|
|
8351
|
-
const outputBlockers =
|
|
8352
|
-
const goalBlockers =
|
|
8353
|
-
const 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
|
|
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 =
|
|
8690
|
+
const beforeSnapshot = snapshotFromState2(goalId, next);
|
|
8414
8691
|
next = applyAgentResponsibilityEvidenceToGoalState(next, evidence);
|
|
8415
|
-
const afterSnapshot =
|
|
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 =
|
|
8715
|
+
const beforeCompletionSnapshot = snapshotFromState2(goalId, next);
|
|
8439
8716
|
next = completeSatisfiedManagedGoal(next);
|
|
8440
|
-
const afterCompletionSnapshot =
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
12594
|
-
if (!
|
|
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(
|
|
12901
|
+
const verdict = detectVerdict(reportBody);
|
|
12602
12902
|
ctx.data.qaVerdict = verdict;
|
|
12603
|
-
ctx.data.qaReport =
|
|
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,
|
|
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,
|
|
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.
|
|
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",
|