@kody-ade/kody-engine 0.3.25 → 0.3.27

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 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.25",
6
+ version: "0.3.27",
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",
@@ -223,11 +223,9 @@ function parseReleaseConfig(raw) {
223
223
  if (Array.isArray(r.versionFiles)) out.versionFiles = r.versionFiles.filter((f) => typeof f === "string");
224
224
  if (typeof r.publishCommand === "string") out.publishCommand = r.publishCommand;
225
225
  if (typeof r.notifyCommand === "string") out.notifyCommand = r.notifyCommand;
226
- if (typeof r.deployCommand === "string") out.deployCommand = r.deployCommand;
227
226
  if (typeof r.e2eCommand === "string") out.e2eCommand = r.e2eCommand;
228
227
  if (typeof r.draftRelease === "boolean") out.draftRelease = r.draftRelease;
229
228
  if (typeof r.releaseBranch === "string") out.releaseBranch = r.releaseBranch;
230
- if (typeof r.devBranch === "string" && r.devBranch.length > 0) out.devBranch = r.devBranch;
231
229
  if (typeof r.timeoutMs === "number" && r.timeoutMs > 0) out.timeoutMs = Math.floor(r.timeoutMs);
232
230
  return Object.keys(out).length > 0 ? out : void 0;
233
231
  }
@@ -1,30 +1,31 @@
1
1
  #!/usr/bin/env bash
2
2
  #
3
- # release-deploy: promote the integration branch (dev) to the default
4
- # branch (main). Runs AFTER release-publish has tagged the bump commit
5
- # on dev. No agent.
3
+ # release-deploy: open a PR from the integration branch (git.defaultBranch)
4
+ # into the production target (release.releaseBranch) the human gate for
5
+ # production deploy. The orchestrator's chain ENDS with this PR opened;
6
+ # merging it is a manual step. No agent.
6
7
  #
7
8
  # Behavior:
8
- # - If release.devBranch is unset OR equals git.defaultBranch:
9
- # no-op success (single-branch repos have nothing to promote).
10
- # - Else: fast-forward `defaultBranch` to `devBranch` and push. If a
11
- # fast-forward isn't possible (defaultBranch has commits dev doesn't
12
- # have), fall back to `git merge --no-ff` so history is preserved.
9
+ # - If release.releaseBranch is unset OR equals git.defaultBranch:
10
+ # no-op success (single-branch repos have nothing to deploy).
11
+ # - Else: idempotently open PR `defaultBranch` `releaseBranch`. If an
12
+ # open PR for that pair already exists, reuse its URL.
13
13
  #
14
- # After the merge, runs `release.notifyCommand` (if set) as a best-effort
15
- # post-deploy hook.
14
+ # After the PR is opened, runs `release.notifyCommand` (if set) as a
15
+ # best-effort post-deploy hook.
16
16
  #
17
17
  # Inputs (env):
18
18
  # KODY_ARG_DRY_RUN true|false
19
19
  # KODY_ARG_ISSUE triggering issue/PR number (optional)
20
20
  #
21
21
  # Config (env):
22
- # KODY_CFG_GIT_DEFAULTBRANCH e.g. main
23
- # KODY_CFG_RELEASE_DEVBRANCH e.g. dev (unset → no-op)
22
+ # KODY_CFG_GIT_DEFAULTBRANCH e.g. dev
23
+ # KODY_CFG_RELEASE_RELEASEBRANCH e.g. main (unset → no-op)
24
24
  # KODY_CFG_RELEASE_NOTIFYCOMMAND optional; $VERSION substituted
25
25
  # KODY_CFG_RELEASE_TIMEOUTMS per-command timeout in ms (default 600000)
26
26
  #
27
27
  # Stdout signals:
28
+ # KODY_PR_URL=<deploy PR url>
28
29
  # KODY_REASON=<text>
29
30
  # KODY_SKIP_AGENT=true
30
31
 
@@ -32,61 +33,71 @@ set -euo pipefail
32
33
 
33
34
  dry_run="${KODY_ARG_DRY_RUN:-false}"
34
35
  default_branch="${KODY_CFG_GIT_DEFAULTBRANCH:-main}"
35
- dev_branch="${KODY_CFG_RELEASE_DEVBRANCH:-}"
36
+ release_branch="${KODY_CFG_RELEASE_RELEASEBRANCH:-}"
36
37
  notify_cmd="${KODY_CFG_RELEASE_NOTIFYCOMMAND:-}"
37
38
  timeout_ms="${KODY_CFG_RELEASE_TIMEOUTMS:-600000}"
38
39
  timeout_s=$((timeout_ms / 1000))
39
40
 
40
- read_pkg_version() {
41
+ # Read version from the integration branch tip (where the bump commit lives),
42
+ # not from the local working tree (the workflow may have checked out another
43
+ # branch). Falls back to local package.json if the fetch fails.
44
+ read_version() {
45
+ local branch="$1"
46
+ if git fetch origin "$branch" --quiet 2>/dev/null; then
47
+ if pkg=$(git show "origin/${branch}:package.json" 2>/dev/null); then
48
+ echo "$pkg" | python3 -c "import json,sys; print(json.load(sys.stdin)['version'])" 2>/dev/null && return
49
+ fi
50
+ fi
41
51
  python3 -c "import json; print(json.load(open('package.json'))['version'])" 2>/dev/null || echo "unknown"
42
52
  }
43
53
 
44
- version=$(read_pkg_version)
54
+ version=$(read_version "$default_branch")
45
55
  echo "→ release deploy: v${version}"
46
56
 
47
- # Single-branch repos: nothing to promote.
48
- if [[ -z "$dev_branch" || "$dev_branch" == "$default_branch" ]]; then
49
- echo "KODY_REASON=no devBranch configured (or equals defaultBranch) — nothing to promote"
57
+ # Single-branch repos: nothing to deploy.
58
+ if [[ -z "$release_branch" || "$release_branch" == "$default_branch" ]]; then
59
+ echo "KODY_REASON=no releaseBranch configured (or equals defaultBranch) — nothing to deploy"
50
60
  echo "KODY_SKIP_AGENT=true"
51
61
  exit 0
52
62
  fi
53
63
 
54
64
  if [[ "$dry_run" == "true" ]]; then
55
- echo "KODY_REASON=dry-run — would merge ${dev_branch} into ${default_branch}"
65
+ echo "KODY_REASON=dry-run — would open PR ${default_branch} ${release_branch}"
56
66
  echo "KODY_SKIP_AGENT=true"
57
67
  exit 0
58
68
  fi
59
69
 
60
70
  export HUSKY=0 SKIP_HOOKS=1 CI="${CI:-1}"
61
71
 
62
- # Sync local refs.
63
- git fetch origin "$dev_branch" "$default_branch" --tags
64
-
65
- # Move to defaultBranch and reset to its remote tip.
66
- git checkout "$default_branch"
67
- git reset --hard "origin/$default_branch"
72
+ # Idempotency: reuse an open PR for this branch pair if one exists.
73
+ existing=$(gh pr list --head "$default_branch" --base "$release_branch" --state open --json url --limit 1 2>/dev/null \
74
+ | python3 -c 'import json,sys; data=json.load(sys.stdin); print(data[0]["url"] if data else "")' 2>/dev/null \
75
+ || echo "")
68
76
 
69
- # Try fast-forward first; fall back to a merge commit.
70
- if git merge --ff-only "origin/$dev_branch" 2>/dev/null; then
71
- echo " fast-forwarded ${default_branch} to origin/${dev_branch}"
77
+ if [[ -n "$existing" ]]; then
78
+ echo " reusing existing deploy PR: ${existing}"
79
+ pr_url="$existing"
72
80
  else
73
- echo " fast-forward not possibleusing --no-ff merge"
74
- if ! git -c commit.gpgsign=false merge --no-ff "origin/$dev_branch" -m "chore: deploy ${dev_branch} → ${default_branch} (v${version})"; then
75
- echo "KODY_REASON=release deploy: merge ${dev_branch} into ${default_branch} failed (conflicts?)"
81
+ body="Automated deploy PR opened by kody promotes \`${default_branch}\` to \`${release_branch}\` for release **v${version}**.
82
+
83
+ Merge this PR to deploy v${version} to \`${release_branch}\`."
84
+ 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
85
+ echo "KODY_REASON=release deploy: gh pr create failed"
76
86
  echo "KODY_SKIP_AGENT=true"
77
87
  exit 1
78
88
  fi
79
89
  fi
80
90
 
81
- if ! git push origin "$default_branch"; then
82
- echo "KODY_REASON=release deploy: push to origin/${default_branch} failed"
91
+ if [[ -z "$pr_url" ]]; then
92
+ echo "KODY_REASON=release deploy: empty PR URL after gh pr create"
83
93
  echo "KODY_SKIP_AGENT=true"
84
94
  exit 1
85
95
  fi
86
96
 
87
- echo " pushed ${default_branch}"
97
+ echo "RELEASE_DEPLOY_PR=${pr_url}"
98
+ echo "KODY_PR_URL=${pr_url}"
88
99
 
89
- # Optional post-deploy notification.
100
+ # Optional post-deploy notification (e.g. Slack ping that a deploy PR is up).
90
101
  notify_status="skipped"
91
102
  if [[ -n "$notify_cmd" ]]; then
92
103
  cmd="${notify_cmd//\$VERSION/$version}"
@@ -99,5 +110,5 @@ if [[ -n "$notify_cmd" ]]; then
99
110
  fi
100
111
  fi
101
112
 
102
- echo "KODY_REASON=promoted ${dev_branch} → ${default_branch} (notify=${notify_status})"
113
+ echo "KODY_REASON=opened deploy PR ${default_branch} → ${release_branch} (notify=${notify_status})"
103
114
  echo "KODY_SKIP_AGENT=true"
@@ -26,10 +26,6 @@ bump="${KODY_ARG_BUMP:-patch}"
26
26
  dry_run="${KODY_ARG_DRY_RUN:-false}"
27
27
  prefer="${KODY_ARG_PREFER:-}"
28
28
  default_branch="${KODY_CFG_GIT_DEFAULTBRANCH:-main}"
29
- dev_branch="${KODY_CFG_RELEASE_DEVBRANCH:-}"
30
- # PR target: dev branch when configured (and different from default), else default.
31
- pr_base="${dev_branch:-$default_branch}"
32
- [[ "$pr_base" == "$default_branch" ]] && pr_base="$default_branch"
33
29
  version_files_json="${KODY_CFG_RELEASE_VERSIONFILES:-}"
34
30
 
35
31
  fail() {
@@ -317,8 +313,8 @@ _… truncated; see CHANGELOG.md_"
317
313
  else
318
314
  body_entry="$entry"
319
315
  fi
320
- body=$'Automated release PR opened by kody.\n\n'"$body_entry"$'\n\nThe release orchestrator will merge this into `'"${pr_base}"$'` and continue to publish + deploy.'
321
- pr_url=$(printf '%s' "$body" | gh pr create --head "$release_branch" --base "$pr_base" --title "chore: release ${tag}" --body-file -)
316
+ body=$'Automated release PR opened by kody.\n\n'"$body_entry"$'\n\nThe release orchestrator will merge this into `'"${default_branch}"$'` and continue to publish + deploy.'
317
+ pr_url=$(printf '%s' "$body" | gh pr create --head "$release_branch" --base "$default_branch" --title "chore: release ${tag}" --body-file -)
322
318
  fi
323
319
 
324
320
  if [[ -z "$pr_url" ]]; then
@@ -24,13 +24,6 @@ set -euo pipefail
24
24
 
25
25
  dry_run="${KODY_ARG_DRY_RUN:-false}"
26
26
  default_branch="${KODY_CFG_GIT_DEFAULTBRANCH:-main}"
27
- dev_branch="${KODY_CFG_RELEASE_DEVBRANCH:-}"
28
- # Tag the branch where the release-prepare PR was merged: devBranch when set
29
- # (and different from default), else defaultBranch.
30
- target_branch="$default_branch"
31
- if [[ -n "$dev_branch" && "$dev_branch" != "$default_branch" ]]; then
32
- target_branch="$dev_branch"
33
- fi
34
27
  publish_cmd="${KODY_CFG_RELEASE_PUBLISHCOMMAND:-}"
35
28
  draft="${KODY_CFG_RELEASE_DRAFTRELEASE:-false}"
36
29
  timeout_ms="${KODY_CFG_RELEASE_TIMEOUTMS:-600000}"
@@ -53,10 +46,10 @@ fi
53
46
  export HUSKY=0 SKIP_HOOKS=1 CI="${CI:-1}"
54
47
 
55
48
  # Make sure we're on the merged commit. The orchestrator merged the release
56
- # PR into target_branch; pull so the local tree has the bump commit.
57
- git fetch origin "$target_branch" --tags
58
- git checkout "$target_branch"
59
- git reset --hard "origin/$target_branch"
49
+ # PR into default_branch; pull so the local tree has the bump commit.
50
+ git fetch origin "$default_branch" --tags
51
+ git checkout "$default_branch"
52
+ git reset --hard "origin/$default_branch"
60
53
 
61
54
  version=$(read_pkg_version)
62
55
  tag="v${version}"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.3.25",
3
+ "version": "0.3.27",
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",