@kody-ade/kody-engine 0.2.46 → 0.2.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/kody2.js +39 -3
- package/dist/executables/orchestrator-plan-build-review/profile.json +76 -0
- package/dist/executables/orchestrator-plan-build-review/prompt.md +7 -0
- package/package.json +1 -1
- package/dist/executables/orchestrator/profile.json +0 -67
- package/dist/executables/orchestrator/prompt.md +0 -56
package/dist/bin/kody2.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// package.json
|
|
4
4
|
var package_default = {
|
|
5
5
|
name: "@kody-ade/kody-engine",
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.47",
|
|
7
7
|
description: "kody2 \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
8
8
|
license: "MIT",
|
|
9
9
|
type: "module",
|
|
@@ -591,7 +591,19 @@ function autoDispatch(opts) {
|
|
|
591
591
|
return asDispatch(defaultExec, targetNum);
|
|
592
592
|
}
|
|
593
593
|
if (sub === "orchestrate" || sub === "orchestrator") {
|
|
594
|
-
|
|
594
|
+
const flow = extractFlowName(afterTag);
|
|
595
|
+
if (flow) {
|
|
596
|
+
return {
|
|
597
|
+
executable: `orchestrator-${flow}`,
|
|
598
|
+
cliArgs: { issue: targetNum, flow },
|
|
599
|
+
target: targetNum
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
return {
|
|
603
|
+
executable: "orchestrator-plan-build-review",
|
|
604
|
+
cliArgs: { issue: targetNum, flow: "plan-build-review" },
|
|
605
|
+
target: targetNum
|
|
606
|
+
};
|
|
595
607
|
}
|
|
596
608
|
if (sub === "build") {
|
|
597
609
|
return { executable: "run", cliArgs: { issue: targetNum }, target: targetNum };
|
|
@@ -611,6 +623,10 @@ function extractSubcommand(afterTag) {
|
|
|
611
623
|
if (!match) return null;
|
|
612
624
|
return match[1];
|
|
613
625
|
}
|
|
626
|
+
function extractFlowName(afterTag) {
|
|
627
|
+
const match = afterTag.match(/--flow[=\s]+([a-z][a-z0-9-]{0,60})/);
|
|
628
|
+
return match ? match[1] : null;
|
|
629
|
+
}
|
|
614
630
|
function extractFeedback(afterTag) {
|
|
615
631
|
const cleaned = afterTag.replace(/^(fix|please|kindly)(?:[\s:,.-]+|$)/i, "").trim();
|
|
616
632
|
return cleaned.length > 0 ? cleaned : void 0;
|
|
@@ -948,6 +964,9 @@ function parseScriptList(p, key, raw) {
|
|
|
948
964
|
if (r.runWhen && typeof r.runWhen === "object") {
|
|
949
965
|
entry.runWhen = r.runWhen;
|
|
950
966
|
}
|
|
967
|
+
if (r.with && typeof r.with === "object") {
|
|
968
|
+
entry.with = r.with;
|
|
969
|
+
}
|
|
951
970
|
out.push(entry);
|
|
952
971
|
}
|
|
953
972
|
return out;
|
|
@@ -2931,6 +2950,22 @@ function readDottedString(source, dotted) {
|
|
|
2931
2950
|
return String(cur);
|
|
2932
2951
|
}
|
|
2933
2952
|
|
|
2953
|
+
// src/scripts/persistFlowState.ts
|
|
2954
|
+
var persistFlowState = async (ctx) => {
|
|
2955
|
+
const state = ctx.data.taskState;
|
|
2956
|
+
if (!state) return;
|
|
2957
|
+
const issueNumber = ctx.args.issue ?? state.flow?.issueNumber;
|
|
2958
|
+
if (!issueNumber) return;
|
|
2959
|
+
try {
|
|
2960
|
+
writeTaskState("issue", issueNumber, state, ctx.cwd);
|
|
2961
|
+
} catch (err) {
|
|
2962
|
+
process.stderr.write(
|
|
2963
|
+
`[kody2 persistFlowState] failed to write state on issue #${issueNumber}: ${err instanceof Error ? err.message : String(err)}
|
|
2964
|
+
`
|
|
2965
|
+
);
|
|
2966
|
+
}
|
|
2967
|
+
};
|
|
2968
|
+
|
|
2934
2969
|
// src/scripts/postIssueComment.ts
|
|
2935
2970
|
var postIssueComment2 = async (ctx) => {
|
|
2936
2971
|
if (ctx.skipAgent && ctx.output.exitCode !== void 0) return;
|
|
@@ -4022,7 +4057,8 @@ var postflightScripts = {
|
|
|
4022
4057
|
startFlow,
|
|
4023
4058
|
dispatch,
|
|
4024
4059
|
finishFlow,
|
|
4025
|
-
advanceFlow
|
|
4060
|
+
advanceFlow,
|
|
4061
|
+
persistFlowState
|
|
4026
4062
|
};
|
|
4027
4063
|
var allScriptNames = /* @__PURE__ */ new Set([
|
|
4028
4064
|
...Object.keys(preflightScripts),
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "orchestrator-plan-build-review",
|
|
3
|
+
"describe": "Deterministic orchestrator for the plan → build → review (→ fix on concerns/fail) flow. No agent — the postflight entries ARE the transition table, evaluated top-to-bottom via runWhen.",
|
|
4
|
+
"inputs": [
|
|
5
|
+
{
|
|
6
|
+
"name": "issue",
|
|
7
|
+
"flag": "--issue",
|
|
8
|
+
"type": "int",
|
|
9
|
+
"required": true,
|
|
10
|
+
"describe": "GitHub issue number to drive the flow on."
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "flow",
|
|
14
|
+
"flag": "--flow",
|
|
15
|
+
"type": "string",
|
|
16
|
+
"required": false,
|
|
17
|
+
"describe": "Flow name (cosmetic — recorded in state.flow.name)."
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"claudeCode": {
|
|
21
|
+
"model": "inherit",
|
|
22
|
+
"permissionMode": "default",
|
|
23
|
+
"maxTurns": 0,
|
|
24
|
+
"maxThinkingTokens": null,
|
|
25
|
+
"systemPromptAppend": null,
|
|
26
|
+
"tools": [],
|
|
27
|
+
"hooks": [],
|
|
28
|
+
"skills": [],
|
|
29
|
+
"commands": [],
|
|
30
|
+
"subagents": [],
|
|
31
|
+
"plugins": [],
|
|
32
|
+
"mcpServers": []
|
|
33
|
+
},
|
|
34
|
+
"cliTools": [],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"preflight": [
|
|
37
|
+
{ "script": "loadIssueContext" },
|
|
38
|
+
{ "script": "loadTaskState" },
|
|
39
|
+
{ "script": "skipAgent" }
|
|
40
|
+
],
|
|
41
|
+
"postflight": [
|
|
42
|
+
{ "script": "startFlow", "with": { "entry": "plan", "target": "issue" },
|
|
43
|
+
"runWhen": { "data.taskState.core.lastOutcome": null } },
|
|
44
|
+
|
|
45
|
+
{ "script": "dispatch", "with": { "next": "run", "target": "issue" },
|
|
46
|
+
"runWhen": { "data.taskState.core.lastOutcome.type": "PLAN_COMPLETED" } },
|
|
47
|
+
|
|
48
|
+
{ "script": "dispatch", "with": { "next": "review", "target": "pr" },
|
|
49
|
+
"runWhen": { "data.taskState.core.lastOutcome.type": "RUN_COMPLETED" } },
|
|
50
|
+
|
|
51
|
+
{ "script": "finishFlow", "with": { "reason": "review-passed" },
|
|
52
|
+
"runWhen": { "data.taskState.core.lastOutcome.type": "REVIEW_PASS" } },
|
|
53
|
+
|
|
54
|
+
{ "script": "dispatch", "with": { "next": "fix", "target": "pr" },
|
|
55
|
+
"runWhen": { "data.taskState.core.lastOutcome.type": ["REVIEW_CONCERNS", "REVIEW_FAIL"] } },
|
|
56
|
+
|
|
57
|
+
{ "script": "finishFlow", "with": { "reason": "review-failed" },
|
|
58
|
+
"runWhen": { "data.taskState.core.lastOutcome.type": "REVIEW_FAILED" } },
|
|
59
|
+
|
|
60
|
+
{ "script": "finishFlow", "with": { "reason": "fix-applied" },
|
|
61
|
+
"runWhen": { "data.taskState.core.lastOutcome.type": "FIX_COMPLETED" } },
|
|
62
|
+
|
|
63
|
+
{ "script": "finishFlow", "with": { "reason": "aborted" },
|
|
64
|
+
"runWhen": { "data.taskState.core.lastOutcome.type": ["PLAN_FAILED", "RUN_FAILED", "FIX_FAILED", "AGENT_NOT_RUN"] } },
|
|
65
|
+
|
|
66
|
+
{ "script": "persistFlowState" }
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
"output": {
|
|
70
|
+
"actionTypes": [
|
|
71
|
+
"FLOW_STARTED",
|
|
72
|
+
"FLOW_COMPLETED",
|
|
73
|
+
"FLOW_ABORTED"
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
This file exists only because the executor's profile loader expects a
|
|
3
|
+
prompt.md sibling. The orchestrator-plan-build-review executable runs
|
|
4
|
+
with maxTurns: 0 and a `skipAgent` preflight, so this prompt is never
|
|
5
|
+
actually delivered to Claude. The transition logic lives entirely in
|
|
6
|
+
profile.json's postflight entries.
|
|
7
|
+
-->
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.47",
|
|
4
4
|
"description": "kody2 — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "orchestrator",
|
|
3
|
-
"describe": "Drive a chain of kody2 executables by posting @kody2 subcommand comments and polling the task-state comment. Atomic \u2014 one orchestrator run fires one flow.",
|
|
4
|
-
"inputs": [
|
|
5
|
-
{
|
|
6
|
-
"name": "issue",
|
|
7
|
-
"flag": "--issue",
|
|
8
|
-
"type": "int",
|
|
9
|
-
"required": true,
|
|
10
|
-
"describe": "GitHub issue number to drive."
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
"name": "flow",
|
|
14
|
-
"flag": "--flow",
|
|
15
|
-
"type": "string",
|
|
16
|
-
"required": false,
|
|
17
|
-
"describe": "Named flow to run (e.g. 'plan-then-build'). Defaults to plan-then-build."
|
|
18
|
-
}
|
|
19
|
-
],
|
|
20
|
-
"claudeCode": {
|
|
21
|
-
"model": "inherit",
|
|
22
|
-
"permissionMode": "default",
|
|
23
|
-
"maxTurns": null,
|
|
24
|
-
"systemPromptAppend": null,
|
|
25
|
-
"tools": [
|
|
26
|
-
"Bash",
|
|
27
|
-
"Read"
|
|
28
|
-
],
|
|
29
|
-
"hooks": [],
|
|
30
|
-
"skills": [],
|
|
31
|
-
"commands": [],
|
|
32
|
-
"subagents": [],
|
|
33
|
-
"plugins": [],
|
|
34
|
-
"mcpServers": []
|
|
35
|
-
},
|
|
36
|
-
"cliTools": [],
|
|
37
|
-
"scripts": {
|
|
38
|
-
"preflight": [
|
|
39
|
-
{
|
|
40
|
-
"script": "loadIssueContext"
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
"script": "loadTaskState"
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
"script": "composePrompt"
|
|
47
|
-
}
|
|
48
|
-
],
|
|
49
|
-
"postflight": [
|
|
50
|
-
{
|
|
51
|
-
"script": "parseAgentResult"
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
"script": "writeRunSummary"
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
"script": "saveTaskState"
|
|
58
|
-
}
|
|
59
|
-
]
|
|
60
|
-
},
|
|
61
|
-
"output": {
|
|
62
|
-
"actionTypes": [
|
|
63
|
-
"ORCHESTRATION_COMPLETED",
|
|
64
|
-
"ORCHESTRATION_FAILED"
|
|
65
|
-
]
|
|
66
|
-
}
|
|
67
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
You are the **kody2 orchestrator** for issue #{{issue.number}} on {{repoOwner}}/{{repoName}}.
|
|
2
|
-
|
|
3
|
-
Your job: drive a 2-step flow **plan → build** by posting `@kody2 <subcommand>` comments on the issue and watching the state-comment for completion signals. You do NOT edit files. You do NOT run git. You use `gh` (via Bash) only to post comments and read the state-comment.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Issue #{{issue.number}}: {{issue.title}}
|
|
8
|
-
|
|
9
|
-
{{issue.body}}
|
|
10
|
-
|
|
11
|
-
# Required flow (plan-then-build)
|
|
12
|
-
|
|
13
|
-
1. **Kick off plan.** Post an issue comment with EXACTLY this body:
|
|
14
|
-
```
|
|
15
|
-
@kody2 plan
|
|
16
|
-
```
|
|
17
|
-
Use: `gh issue comment {{issue.number}} --body "@kody2 plan"` (in the cwd).
|
|
18
|
-
2. **Wait for plan to complete.** Poll the issue's state-comment every ~30s. The state-comment is the one whose body starts with `<!-- kody2:state:v1:begin -->`. Fetch it with:
|
|
19
|
-
```
|
|
20
|
-
gh api repos/{{repoOwner}}/{{repoName}}/issues/{{issue.number}}/comments --paginate --jq '.[] | select(.body | contains("kody2:state:v1:begin")) | .body'
|
|
21
|
-
```
|
|
22
|
-
Parse the JSON block inside the sentinels. Look for `core.lastOutcome.type == "PLAN_COMPLETED"`.
|
|
23
|
-
If `core.lastOutcome.type == "PLAN_FAILED"` OR if 10 minutes pass without completion → abort with:
|
|
24
|
-
```
|
|
25
|
-
FAILED: plan did not complete (<reason from state or "timeout">)
|
|
26
|
-
```
|
|
27
|
-
3. **Kick off build.** Post:
|
|
28
|
-
```
|
|
29
|
-
@kody2 build
|
|
30
|
-
```
|
|
31
|
-
Same `gh issue comment` command.
|
|
32
|
-
4. **Wait for build to complete.** Same poll technique. Look for `core.lastOutcome.type == "RUN_COMPLETED"` (build's success marker) or `RUN_FAILED`. If `RUN_FAILED` or 30 minutes pass → abort with `FAILED: build did not complete (...)`.
|
|
33
|
-
5. **Emit final summary.**
|
|
34
|
-
|
|
35
|
-
# Required final output
|
|
36
|
-
|
|
37
|
-
On success:
|
|
38
|
-
|
|
39
|
-
```
|
|
40
|
-
DONE
|
|
41
|
-
COMMIT_MSG: chore(orchestrator): plan-then-build for #{{issue.number}}
|
|
42
|
-
PR_SUMMARY:
|
|
43
|
-
- Posted `@kody2 plan` and observed PLAN_COMPLETED.
|
|
44
|
-
- Posted `@kody2 build` and observed RUN_COMPLETED.
|
|
45
|
-
- Final PR: <prUrl from state>
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
On failure, a single line: `FAILED: <concrete reason>`.
|
|
49
|
-
|
|
50
|
-
# Rules
|
|
51
|
-
|
|
52
|
-
- NEVER edit files. Read-only flow.
|
|
53
|
-
- NEVER run git. Only `gh` via Bash for comment posting and state polling.
|
|
54
|
-
- Between polls, sleep ~30 seconds. Do NOT poll faster than once every 30 seconds.
|
|
55
|
-
- Hard cap: 40 turns total across the whole flow. If you're approaching the cap, fail early with `FAILED: turn budget exhausted`.
|
|
56
|
-
- If you post an `@kody2` comment and the state-comment does NOT update within the poll window, the child executable likely didn't run — check the GitHub Actions runs tab URL via `gh run list --limit 5 --json conclusion,status,url` to diagnose, then fail with a concrete reason.
|