@kody-ade/kody-engine 0.3.70-beta.6 → 0.3.70
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 +1 -1
- package/dist/executables/release/deploy.sh +2 -17
- package/dist/executables/release/prepare.sh +5 -11
- package/dist/executables/release/profile.json +1 -1
- package/dist/executables/release/publish.sh +7 -35
- package/dist/executables/release/wait.sh +30 -39
- package/package.json +1 -1
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.70
|
|
6
|
+
version: "0.3.70",
|
|
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",
|
|
@@ -91,23 +91,8 @@ open_deploy_pr() {
|
|
|
91
91
|
if [[ -n "$existing" ]]; then
|
|
92
92
|
echo " reusing existing deploy PR: ${existing}" >&2
|
|
93
93
|
pr_url="$existing"
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
# works with plain `repo` scope.
|
|
97
|
-
local pr_num="${pr_url##*/}"
|
|
98
|
-
local owner="${KODY_CFG_GITHUB_OWNER:-}"
|
|
99
|
-
local repo="${KODY_CFG_GITHUB_REPO:-}"
|
|
100
|
-
if [[ -z "$owner" || -z "$repo" ]]; then
|
|
101
|
-
# Fall back to extracting from the URL if config missing.
|
|
102
|
-
local stripped="${pr_url#https://github.com/}"
|
|
103
|
-
owner="${stripped%%/*}"
|
|
104
|
-
repo=$(echo "$stripped" | cut -d/ -f2)
|
|
105
|
-
fi
|
|
106
|
-
local edit_err
|
|
107
|
-
if ! edit_err=$(gh api --method PATCH "repos/${owner}/${repo}/pulls/${pr_num}" -f body="$body" 2>&1 >/dev/null); then
|
|
108
|
-
echo "[deploy] WARN: failed to refresh deploy PR body for ${pr_url}: ${edit_err}" >&2
|
|
109
|
-
else
|
|
110
|
-
echo " refreshed deploy PR body via REST" >&2
|
|
94
|
+
if ! printf '%s' "$body" | gh pr edit "$pr_url" --body-file - >/dev/null 2>&1; then
|
|
95
|
+
echo "[deploy] WARN: failed to refresh deploy PR body" >&2
|
|
111
96
|
fi
|
|
112
97
|
else
|
|
113
98
|
if ! pr_url=$(printf '%s' "$body" | gh pr create --head "$default_branch" --base "$release_branch" --title "deploy: ${default_branch} → ${release_branch} (v${new_version})" --body-file -); then
|
|
@@ -107,18 +107,12 @@ generate_changelog() {
|
|
|
107
107
|
|
|
108
108
|
format_changelog() {
|
|
109
109
|
local new_version="$1"
|
|
110
|
-
local date_str
|
|
110
|
+
local date_str
|
|
111
111
|
date_str=$(date -u +%Y-%m-%d)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
raw=$(cat)
|
|
117
|
-
RAW_CHANGELOG="$raw" NEW_VER="$new_version" DATE_STR="$date_str" python3 - <<'PY'
|
|
118
|
-
import os, re, sys
|
|
119
|
-
new_version = os.environ["NEW_VER"]
|
|
120
|
-
date_str = os.environ["DATE_STR"]
|
|
121
|
-
raw = os.environ.get("RAW_CHANGELOG", "")
|
|
112
|
+
python3 - "$new_version" "$date_str" <<'PY'
|
|
113
|
+
import sys, re
|
|
114
|
+
new_version, date_str = sys.argv[1], sys.argv[2]
|
|
115
|
+
raw = sys.stdin.read()
|
|
122
116
|
buckets = {k: [] for k in ("feat", "fix", "perf", "refactor", "docs", "chore", "other")}
|
|
123
117
|
for line in raw.splitlines():
|
|
124
118
|
line = line.strip()
|
|
@@ -15,33 +15,15 @@ tag_and_publish() {
|
|
|
15
15
|
local timeout_s=$((timeout_ms / 1000))
|
|
16
16
|
local tag="v${new_version}"
|
|
17
17
|
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
head_sha=$(git rev-parse HEAD)
|
|
23
|
-
if local_sha=$(git rev-parse --verify "$tag" 2>/dev/null); then
|
|
24
|
-
if [[ "$local_sha" == "$head_sha" ]]; then
|
|
25
|
-
echo " tag ${tag} already exists locally at HEAD — skipping create" >&2
|
|
26
|
-
else
|
|
27
|
-
echo "[publish] tag ${tag} exists locally at ${local_sha} but HEAD is ${head_sha}" >&2
|
|
28
|
-
return 1
|
|
29
|
-
fi
|
|
30
|
-
else
|
|
31
|
-
git tag -a "$tag" -m "Release ${tag}"
|
|
32
|
-
fi
|
|
33
|
-
# Push the tag if it isn't already on origin (or push always; gh will
|
|
34
|
-
# no-op on existing remote tag at the same sha).
|
|
35
|
-
if remote_sha=$(git ls-remote --tags origin "refs/tags/${tag}" 2>/dev/null | awk '{print $1}'); then
|
|
36
|
-
if [[ -z "$remote_sha" ]]; then
|
|
37
|
-
git push origin "$tag"
|
|
38
|
-
elif [[ "$remote_sha" != "$head_sha" ]]; then
|
|
39
|
-
echo " WARN: remote tag ${tag} points at ${remote_sha}, HEAD is ${head_sha}" >&2
|
|
40
|
-
fi
|
|
41
|
-
else
|
|
42
|
-
git push origin "$tag" || true
|
|
18
|
+
# Refuse if the tag already exists locally (left over from a prior failed run).
|
|
19
|
+
if git rev-parse --verify "$tag" >/dev/null 2>&1; then
|
|
20
|
+
echo "[publish] tag ${tag} already exists locally" >&2
|
|
21
|
+
return 1
|
|
43
22
|
fi
|
|
44
23
|
|
|
24
|
+
git tag -a "$tag" -m "Release ${tag}"
|
|
25
|
+
git push origin "$tag"
|
|
26
|
+
|
|
45
27
|
# publishCommand (optional). Failure here is recorded but does not abort —
|
|
46
28
|
# we still want the GH release entry so the tag is discoverable.
|
|
47
29
|
local publish_status="skipped"
|
|
@@ -66,16 +48,6 @@ create_gh_release() {
|
|
|
66
48
|
local draft_flag=""
|
|
67
49
|
[[ "$draft" == "true" ]] && draft_flag="--draft"
|
|
68
50
|
|
|
69
|
-
# Idempotent: if a release for this tag already exists, reuse it.
|
|
70
|
-
local existing_url
|
|
71
|
-
if existing_url=$(gh release view "$tag" --json url -q .url 2>/dev/null); then
|
|
72
|
-
if [[ -n "$existing_url" ]]; then
|
|
73
|
-
echo " GH release for ${tag} already exists: ${existing_url}" >&2
|
|
74
|
-
echo "$existing_url"
|
|
75
|
-
return 0
|
|
76
|
-
fi
|
|
77
|
-
fi
|
|
78
|
-
|
|
79
51
|
local release_url=""
|
|
80
52
|
if release_url=$(gh release create "$tag" --title "$tag" --notes "Release ${tag} — automated by kody." $draft_flag 2>&1); then
|
|
81
53
|
echo "$release_url"
|
|
@@ -3,12 +3,10 @@
|
|
|
3
3
|
# release/wait.sh — wait_for_ci function: poll a PR's check rollup
|
|
4
4
|
# until all non-skipped checks pass, or timeout.
|
|
5
5
|
#
|
|
6
|
-
# Function: wait_for_ci <pr_number> <timeout_minutes>
|
|
7
|
-
#
|
|
6
|
+
# Function: wait_for_ci <pr_number> <timeout_minutes>
|
|
7
|
+
# Exits 0 on CI_PASSED, exits 1 on CI_FAILED/CI_TIMEOUT.
|
|
8
8
|
#
|
|
9
|
-
#
|
|
10
|
-
# treats that as PASSED after a short stabilization window — so a Tester
|
|
11
|
-
# repo without checks doesn't loop forever.
|
|
9
|
+
# Reads gh pr checks <N> output. Treats SKIPPED as pass.
|
|
12
10
|
|
|
13
11
|
# shellcheck disable=SC2148
|
|
14
12
|
|
|
@@ -26,50 +24,43 @@ wait_for_ci() {
|
|
|
26
24
|
local deadline=$(( $(date +%s) + timeout_minutes * 60 ))
|
|
27
25
|
echo "→ wait_for_ci: PR #${pr_number}, timeout=${timeout_minutes}m"
|
|
28
26
|
|
|
27
|
+
# Initial wait — gives GHA time to register checks.
|
|
29
28
|
sleep "$initial_wait"
|
|
30
29
|
|
|
31
|
-
# Track consecutive "no checks" results so we don't bail prematurely
|
|
32
|
-
# on a PR that's just slow to register checks.
|
|
33
|
-
local empty_count=0
|
|
34
|
-
local empty_threshold=4 # ~2 minutes (4 * poll_seconds=30s) before treating as no-CI
|
|
35
|
-
|
|
36
30
|
while (( $(date +%s) < deadline )); do
|
|
31
|
+
# gh pr checks <N> --json prints an array of {state, name, ...}.
|
|
37
32
|
local raw
|
|
38
|
-
if ! raw=$(gh pr checks "$pr_number" --json state 2>/dev/null); then
|
|
39
|
-
|
|
40
|
-
empty_count=$((empty_count + 1))
|
|
41
|
-
echo " [wait_for_ci] gh pr checks returned non-zero (count=${empty_count})"
|
|
42
|
-
if (( empty_count >= empty_threshold )); then
|
|
43
|
-
echo "→ wait_for_ci: PR #${pr_number} has no CI checks configured — treating as passed"
|
|
44
|
-
return 0
|
|
45
|
-
fi
|
|
33
|
+
if ! raw=$(gh pr checks "$pr_number" --json state,name 2>/dev/null); then
|
|
34
|
+
echo " [wait_for_ci] gh pr checks failed; retrying in ${poll_seconds}s" >&2
|
|
46
35
|
sleep "$poll_seconds"
|
|
47
36
|
continue
|
|
48
37
|
fi
|
|
49
38
|
|
|
50
|
-
#
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
39
|
+
# Tally states. Anything that's still PENDING/IN_PROGRESS/QUEUED → keep waiting.
|
|
40
|
+
# Anything FAILURE/CANCELLED/TIMED_OUT/ACTION_REQUIRED → fail fast.
|
|
41
|
+
# SUCCESS/SKIPPED/NEUTRAL → pass.
|
|
42
|
+
local summary
|
|
43
|
+
summary=$(printf '%s' "$raw" | python3 -c '
|
|
44
|
+
import json, sys
|
|
45
|
+
data = json.load(sys.stdin)
|
|
46
|
+
buckets = {"pending": 0, "passed": 0, "failed": 0, "failed_names": []}
|
|
47
|
+
for r in data:
|
|
48
|
+
s = (r.get("state") or "").upper()
|
|
49
|
+
name = r.get("name") or "?"
|
|
50
|
+
if s in ("PENDING", "IN_PROGRESS", "QUEUED", ""):
|
|
51
|
+
buckets["pending"] += 1
|
|
52
|
+
elif s in ("FAILURE", "CANCELLED", "TIMED_OUT", "ACTION_REQUIRED", "STARTUP_FAILURE"):
|
|
53
|
+
buckets["failed"] += 1
|
|
54
|
+
buckets["failed_names"].append(name)
|
|
55
|
+
else: # SUCCESS, SKIPPED, NEUTRAL, etc.
|
|
56
|
+
buckets["passed"] += 1
|
|
57
|
+
print(f"{buckets[\"pending\"]}|{buckets[\"passed\"]}|{buckets[\"failed\"]}|{','.join(buckets[\"failed_names\"][:5])}")
|
|
58
|
+
')
|
|
64
59
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
pending=$(printf '%s' "$raw" | jq '[.[] | select((.state // "") | IN("PENDING","IN_PROGRESS","QUEUED",""))] | length')
|
|
68
|
-
failed=$(printf '%s' "$raw" | jq '[.[] | select((.state // "") | IN("FAILURE","CANCELLED","TIMED_OUT","ACTION_REQUIRED","STARTUP_FAILURE"))] | length')
|
|
69
|
-
passed=$(printf '%s' "$raw" | jq '[.[] | select((.state // "") | IN("SUCCESS","SKIPPED","NEUTRAL"))] | length')
|
|
70
|
-
failed_names=$(printf '%s' "$raw" | jq -r '[.[] | select((.state // "") | IN("FAILURE","CANCELLED","TIMED_OUT","ACTION_REQUIRED","STARTUP_FAILURE")) | .name] | join(",")')
|
|
60
|
+
local pending passed failed failed_names
|
|
61
|
+
IFS='|' read -r pending passed failed failed_names <<< "$summary"
|
|
71
62
|
|
|
72
|
-
echo " [wait_for_ci] pending=${pending} passed=${passed} failed=${failed}
|
|
63
|
+
echo " [wait_for_ci] pending=${pending} passed=${passed} failed=${failed}"
|
|
73
64
|
|
|
74
65
|
if [[ "$failed" -gt 0 ]]; then
|
|
75
66
|
echo "[wait_for_ci] CI failed on PR #${pr_number}: ${failed_names}" >&2
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.3.70
|
|
3
|
+
"version": "0.3.70",
|
|
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",
|