@kody-ade/kody-engine 0.3.64 → 0.3.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/kody.js +11 -10
- package/dist/executables/release-deploy/deploy.sh +77 -10
- package/dist/executables/release-prepare/prepare.sh +15 -4
- package/dist/executables/release-publish/publish.sh +0 -0
- package/dist/executables/resolve/apply-prefer.sh +0 -0
- package/dist/executables/revert/revert.sh +0 -0
- package/dist/executables/run/prompt.md +1 -0
- package/package.json +15 -14
package/dist/bin/kody.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.3.
|
|
6
|
+
version: "0.3.67",
|
|
7
7
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
8
8
|
license: "MIT",
|
|
9
9
|
type: "module",
|
|
@@ -858,7 +858,14 @@ function autoDispatch(opts) {
|
|
|
858
858
|
if (!executable) {
|
|
859
859
|
executable = isPr ? opts?.config?.defaultPrExecutable ?? "fix" : opts?.config?.defaultExecutable ?? null;
|
|
860
860
|
}
|
|
861
|
-
if (!executable)
|
|
861
|
+
if (!executable) {
|
|
862
|
+
const profileMissing = aliased ? getProfileInputs(aliased) === null : true;
|
|
863
|
+
process.stderr.write(
|
|
864
|
+
`[kody] dispatch: no executable resolved for issue_comment (firstToken=${firstToken ?? "<none>"}, aliased=${aliased ?? "<none>"}, profileFound=${!profileMissing}, defaultExecutable=${opts?.config?.defaultExecutable ?? "<unset>"})
|
|
865
|
+
`
|
|
866
|
+
);
|
|
867
|
+
return null;
|
|
868
|
+
}
|
|
862
869
|
const inputs = getProfileInputs(executable);
|
|
863
870
|
const effectiveInputs = inputs ?? [];
|
|
864
871
|
const unknownProfile = inputs === null;
|
|
@@ -5891,10 +5898,7 @@ function tryPostPr3(prNumber, body, cwd) {
|
|
|
5891
5898
|
function findPreviewDeploymentUrl(prNumber, cwd) {
|
|
5892
5899
|
const sha = getPrHeadSha(prNumber, cwd);
|
|
5893
5900
|
if (!sha) return null;
|
|
5894
|
-
const raw = safeGh2(
|
|
5895
|
-
["api", `repos/{owner}/{repo}/deployments?sha=${sha}&environment=Preview&per_page=10`],
|
|
5896
|
-
cwd
|
|
5897
|
-
);
|
|
5901
|
+
const raw = safeGh2(["api", `repos/{owner}/{repo}/deployments?sha=${sha}&environment=Preview&per_page=10`], cwd);
|
|
5898
5902
|
if (!raw) return null;
|
|
5899
5903
|
let deployments;
|
|
5900
5904
|
try {
|
|
@@ -5916,10 +5920,7 @@ function getPrHeadSha(prNumber, cwd) {
|
|
|
5916
5920
|
return trimmed.length > 0 ? trimmed : null;
|
|
5917
5921
|
}
|
|
5918
5922
|
function latestSuccessUrl(deploymentId, cwd) {
|
|
5919
|
-
const raw = safeGh2(
|
|
5920
|
-
["api", `repos/{owner}/{repo}/deployments/${deploymentId}/statuses?per_page=10`],
|
|
5921
|
-
cwd
|
|
5922
|
-
);
|
|
5923
|
+
const raw = safeGh2(["api", `repos/{owner}/{repo}/deployments/${deploymentId}/statuses?per_page=10`], cwd);
|
|
5923
5924
|
if (!raw) return null;
|
|
5924
5925
|
let statuses;
|
|
5925
5926
|
try {
|
|
@@ -54,6 +54,61 @@ read_version() {
|
|
|
54
54
|
version=$(read_version "$default_branch")
|
|
55
55
|
echo "→ release deploy: v${version}"
|
|
56
56
|
|
|
57
|
+
# Read the CHANGELOG section for $version from the integration branch
|
|
58
|
+
# (where release-prepare just committed it). Handles both header shapes
|
|
59
|
+
# observed in the wild: `## [0.25.0] - 2026-04-15` and `## 0.22.0 (...)`.
|
|
60
|
+
# Prints the body lines (without the matched header). Empty stdout =
|
|
61
|
+
# fall back to the minimal PR body — never break the release.
|
|
62
|
+
read_changelog_section() {
|
|
63
|
+
local branch="$1" ver="$2" raw=""
|
|
64
|
+
if ! raw=$(git show "origin/${branch}:CHANGELOG.md" 2>/dev/null); then
|
|
65
|
+
return 0
|
|
66
|
+
fi
|
|
67
|
+
printf '%s' "$raw" | awk -v ver="$ver" '
|
|
68
|
+
BEGIN { capture = 0 }
|
|
69
|
+
# Match all observed header shapes:
|
|
70
|
+
# "## [0.25.0] - 2026-04-15" (bracketed, dash separator)
|
|
71
|
+
# "## 0.22.0 (2026-03-25)" (bare, parenthesized date)
|
|
72
|
+
# "## v0.25.5 — 2026-05-05" (v-prefixed, em-dash, kody release-prepare style)
|
|
73
|
+
/^##[[:space:]]/ {
|
|
74
|
+
if (capture) { exit }
|
|
75
|
+
header = $0
|
|
76
|
+
sub(/^##[[:space:]]+/, "", header)
|
|
77
|
+
sub(/^\[/, "", header); sub(/\].*/, "", header)
|
|
78
|
+
sub(/[[:space:]].*/, "", header)
|
|
79
|
+
sub(/[(].*/, "", header)
|
|
80
|
+
sub(/^v/, "", header)
|
|
81
|
+
if (header == ver) { capture = 1; next }
|
|
82
|
+
}
|
|
83
|
+
capture { print }
|
|
84
|
+
' | awk '
|
|
85
|
+
# Trim leading and trailing blank lines from the captured block.
|
|
86
|
+
NF { if (!started) started = 1; out[++n] = $0; last = n; next }
|
|
87
|
+
started { out[++n] = $0 }
|
|
88
|
+
END { for (i = 1; i <= last; i++) print out[i] }
|
|
89
|
+
'
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
changelog_section=$(read_changelog_section "$default_branch" "$version" || true)
|
|
93
|
+
if [[ -z "$changelog_section" ]]; then
|
|
94
|
+
echo " no CHANGELOG section for v${version} on origin/${default_branch} — using minimal PR body"
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# Build the kody-managed body block. A marker pair lets us update the
|
|
98
|
+
# section idempotently on re-runs without clobbering anything a human
|
|
99
|
+
# pasted outside the markers.
|
|
100
|
+
build_pr_body() {
|
|
101
|
+
local tracking_line="$1"
|
|
102
|
+
printf 'Automated deploy PR opened by kody — promotes `%s` to `%s` for release **v%s**.\n\n' \
|
|
103
|
+
"$default_branch" "$release_branch" "$version"
|
|
104
|
+
if [[ -n "$changelog_section" ]]; then
|
|
105
|
+
printf '<!-- kody-changelog-start -->\n## What'\''s changing in v%s\n\n%s\n<!-- kody-changelog-end -->\n\n' \
|
|
106
|
+
"$version" "$changelog_section"
|
|
107
|
+
fi
|
|
108
|
+
printf 'Merge this PR to deploy v%s to `%s`.%s\n' \
|
|
109
|
+
"$version" "$release_branch" "$tracking_line"
|
|
110
|
+
}
|
|
111
|
+
|
|
57
112
|
# Single-branch repos: nothing to deploy.
|
|
58
113
|
if [[ -z "$release_branch" || "$release_branch" == "$default_branch" ]]; then
|
|
59
114
|
echo "KODY_REASON=no releaseBranch configured (or equals defaultBranch) — nothing to deploy"
|
|
@@ -78,20 +133,25 @@ existing=$(gh pr list --head "$default_branch" --base "$release_branch" --state
|
|
|
78
133
|
# reuse-existing-PR path.
|
|
79
134
|
issue_arg="${KODY_ARG_ISSUE:-}"
|
|
80
135
|
|
|
136
|
+
# Same Tracking-Issue marker as release-prepare — non-closing reference
|
|
137
|
+
# so the originating release issue stays open through the deploy step
|
|
138
|
+
# while the Kody Dashboard can still link this PR to the task for preview.
|
|
139
|
+
tracking_line=""
|
|
140
|
+
if [[ "$issue_arg" =~ ^[0-9]+$ && "$issue_arg" != "0" ]]; then
|
|
141
|
+
tracking_line=$'\n\nTracking-Issue: #'"${issue_arg}"
|
|
142
|
+
fi
|
|
143
|
+
body=$(build_pr_body "$tracking_line")
|
|
144
|
+
|
|
81
145
|
if [[ -n "$existing" ]]; then
|
|
82
146
|
echo " reusing existing deploy PR: ${existing}"
|
|
83
147
|
pr_url="$existing"
|
|
84
|
-
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if [[ "$issue_arg" =~ ^[0-9]+$ && "$issue_arg" != "0" ]]; then
|
|
90
|
-
tracking_line=$'\n\nTracking-Issue: #'"${issue_arg}"
|
|
148
|
+
# Refresh the body so re-runs converge on the current changelog. Best-
|
|
149
|
+
# effort: a failed edit (e.g. permission-denied) shouldn't fail the
|
|
150
|
+
# release — the PR already exists and its title/branch are unchanged.
|
|
151
|
+
if ! printf '%s' "$body" | gh pr edit "$pr_url" --body-file - >/dev/null 2>&1; then
|
|
152
|
+
echo "[kody release-deploy] WARN: failed to refresh deploy PR body" >&2
|
|
91
153
|
fi
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
Merge this PR to deploy v${version} to \`${release_branch}\`.${tracking_line}"
|
|
154
|
+
else
|
|
95
155
|
if ! pr_url=$(printf '%s' "$body" | gh pr create --head "$default_branch" --base "$release_branch" --title "deploy: ${default_branch} → ${release_branch} (v${version})" --body-file -); then
|
|
96
156
|
echo "KODY_REASON=release deploy: gh pr create failed"
|
|
97
157
|
echo "KODY_SKIP_AGENT=true"
|
|
@@ -127,9 +187,16 @@ echo "RELEASE_DEPLOY_PR=${pr_url}"
|
|
|
127
187
|
echo "KODY_PR_URL=${pr_url}"
|
|
128
188
|
|
|
129
189
|
# Optional post-deploy notification (e.g. Slack ping that a deploy PR is up).
|
|
190
|
+
# Substituted placeholders in the configured command:
|
|
191
|
+
# $VERSION — release version (e.g. 0.25.4)
|
|
192
|
+
# $DEPLOY_PR_URL — URL of the deploy PR just opened/reused
|
|
193
|
+
# The notifyCommand can use $DEPLOY_PR_URL to pull real content (e.g.
|
|
194
|
+
# `gh pr view $DEPLOY_PR_URL --json body --jq .body`) instead of
|
|
195
|
+
# rendering a hardcoded one-liner.
|
|
130
196
|
notify_status="skipped"
|
|
131
197
|
if [[ -n "$notify_cmd" ]]; then
|
|
132
198
|
cmd="${notify_cmd//\$VERSION/$version}"
|
|
199
|
+
cmd="${cmd//\$DEPLOY_PR_URL/$pr_url}"
|
|
133
200
|
echo " notify: ${cmd}"
|
|
134
201
|
if timeout "${timeout_s}" bash -c "$cmd"; then
|
|
135
202
|
notify_status="ok"
|
|
@@ -106,11 +106,22 @@ PY
|
|
|
106
106
|
|
|
107
107
|
generate_changelog() {
|
|
108
108
|
local new_version="$1"
|
|
109
|
-
local last_tag
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
109
|
+
local last_tag count
|
|
110
|
+
# actions/checkout@v4 with fetch-depth: 0 still does NOT fetch tags by
|
|
111
|
+
# default — operators have to opt in via `fetch-tags: true`. When tags
|
|
112
|
+
# are absent, `git describe` returns empty and the else-branch's
|
|
113
|
+
# 100-commit window can over- or under-shoot. Try once to backfill
|
|
114
|
+
# tags before describing, ignoring failures (offline/sandbox runs).
|
|
115
|
+
if ! last_tag=$(git describe --tags --abbrev=0 --match 'v*' 2>/dev/null); then
|
|
116
|
+
git fetch --tags --quiet 2>/dev/null || true
|
|
117
|
+
last_tag=$(git describe --tags --abbrev=0 --match 'v*' 2>/dev/null || true)
|
|
118
|
+
fi
|
|
119
|
+
if [[ -n "$last_tag" ]]; then
|
|
120
|
+
count=$(git rev-list --count "${last_tag}..HEAD" --no-merges 2>/dev/null || echo "?")
|
|
121
|
+
echo " changelog: ${count} commits since ${last_tag}" >&2
|
|
122
|
+
git log "${last_tag}..HEAD" --pretty=format:'%s||%h' --no-merges 2>/dev/null || true
|
|
113
123
|
else
|
|
124
|
+
echo " changelog: no previous v* tag found — using last 100 commits" >&2
|
|
114
125
|
git log -n100 HEAD --pretty=format:'%s||%h' --no-merges 2>/dev/null || true
|
|
115
126
|
fi
|
|
116
127
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -27,6 +27,7 @@ If a prior-art block is present above, READ THE DIFFS — those are failed or su
|
|
|
27
27
|
- Read the tests for each of those files, if tests exist for the module.
|
|
28
28
|
- Read at least one sibling module that already implements the same pattern you're about to follow — your edits should mirror an existing convention unless you can name why a new one is needed.
|
|
29
29
|
- If your change requires writing or modifying a test, also check for repo-level testing guidance: `tests/README.md`, `TESTING.md`, or a "Testing"/"Tests" section in `AGENTS.md`/`CLAUDE.md`. If one exists, treat its patterns (auth setup, fixture creation, what NOT to do) as authoritative — they override anything you might infer from grepping individual files.
|
|
30
|
+
- **Removal/rename refactors** (deleting a call like `console.error`, renaming a function, dropping a method, replacing one API with another): before editing, grep the test directories for assertions tied to the OLD symbol — spies (`vi.spyOn(console`, `jest.spyOn(console`, `consoleErrorSpy`, `mockFn.mock.calls`), the literal function name, and any string the call produced. Enumerate every hit in your plan (step 2) and update those tests in step 4 in the same session. Skipping this grep is a hard failure even if your local test runs pass — the wrapper runs the full suite and you cannot fix breakages after DONE.
|
|
30
31
|
- If a file you need to read does not exist, say so explicitly in your plan (step 2). Do not guess at its contents.
|
|
31
32
|
2. **Plan** — before any Edit/Write, output a short plan (5–10 lines): what files you'll change, the approach, what could go wrong. No fluff.
|
|
32
33
|
3. **Build** — Edit/Write to implement the change. Stay within the plan; if you discover the plan was wrong, briefly say so and adjust.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.67",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -12,6 +12,18 @@
|
|
|
12
12
|
"templates",
|
|
13
13
|
"kody.config.schema.json"
|
|
14
14
|
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"kody": "tsx bin/kody.ts",
|
|
17
|
+
"build": "tsup && node scripts/copy-assets.cjs",
|
|
18
|
+
"test": "vitest run tests/unit tests/int --no-coverage",
|
|
19
|
+
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
20
|
+
"test:all": "vitest run tests --no-coverage",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"lint": "biome check",
|
|
23
|
+
"lint:fix": "biome check --write",
|
|
24
|
+
"format": "biome format --write",
|
|
25
|
+
"prepublishOnly": "pnpm build"
|
|
26
|
+
},
|
|
15
27
|
"dependencies": {
|
|
16
28
|
"@actions/cache": "^6.0.0",
|
|
17
29
|
"@anthropic-ai/claude-agent-sdk": "0.2.119"
|
|
@@ -32,16 +44,5 @@
|
|
|
32
44
|
"url": "git+https://github.com/aharonyaircohen/kody-engine.git"
|
|
33
45
|
},
|
|
34
46
|
"homepage": "https://github.com/aharonyaircohen/kody-engine",
|
|
35
|
-
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
36
|
-
|
|
37
|
-
"kody": "tsx bin/kody.ts",
|
|
38
|
-
"build": "tsup && node scripts/copy-assets.cjs",
|
|
39
|
-
"test": "vitest run tests/unit tests/int --no-coverage",
|
|
40
|
-
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
41
|
-
"test:all": "vitest run tests --no-coverage",
|
|
42
|
-
"typecheck": "tsc --noEmit",
|
|
43
|
-
"lint": "biome check",
|
|
44
|
-
"lint:fix": "biome check --write",
|
|
45
|
-
"format": "biome format --write"
|
|
46
|
-
}
|
|
47
|
-
}
|
|
47
|
+
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
48
|
+
}
|