@kody-ade/kody-engine 0.4.224 → 0.4.225

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.
Files changed (114) hide show
  1. package/README.md +2 -2
  2. package/dist/bin/kody.js +779 -831
  3. package/dist/executables/run/profile.json +1 -1
  4. package/dist/executables/types.ts +3 -1
  5. package/package.json +1 -1
  6. package/dist/duties/duty-scheduler/duty.md +0 -3
  7. package/dist/duties/duty-scheduler/profile.json +0 -6
  8. package/dist/duties/duty-tick/duty.md +0 -3
  9. package/dist/duties/duty-tick/profile.json +0 -6
  10. package/dist/duties/duty-tick-scripted/duty.md +0 -3
  11. package/dist/duties/duty-tick-scripted/profile.json +0 -6
  12. package/dist/duties/fix/duty.md +0 -10
  13. package/dist/duties/fix/profile.json +0 -6
  14. package/dist/duties/fix-ci/duty.md +0 -10
  15. package/dist/duties/fix-ci/profile.json +0 -6
  16. package/dist/duties/goal-scheduler/duty.md +0 -3
  17. package/dist/duties/goal-scheduler/profile.json +0 -6
  18. package/dist/duties/goal-tick/duty.md +0 -3
  19. package/dist/duties/goal-tick/profile.json +0 -6
  20. package/dist/duties/init/duty.md +0 -10
  21. package/dist/duties/init/profile.json +0 -6
  22. package/dist/duties/job-live-verify/duty.md +0 -3
  23. package/dist/duties/job-live-verify/profile.json +0 -6
  24. package/dist/duties/merge/duty.md +0 -10
  25. package/dist/duties/merge/profile.json +0 -6
  26. package/dist/duties/npm-publish/duty.md +0 -17
  27. package/dist/duties/npm-publish/profile.json +0 -6
  28. package/dist/duties/plan-verify/duty.md +0 -3
  29. package/dist/duties/plan-verify/profile.json +0 -6
  30. package/dist/duties/preview-build/duty.md +0 -10
  31. package/dist/duties/preview-build/profile.json +0 -6
  32. package/dist/duties/probe-skill/duty.md +0 -3
  33. package/dist/duties/probe-skill/profile.json +0 -6
  34. package/dist/duties/qa-goal/duty.md +0 -3
  35. package/dist/duties/qa-goal/profile.json +0 -6
  36. package/dist/duties/release/duty.md +0 -10
  37. package/dist/duties/release/profile.json +0 -6
  38. package/dist/duties/release-deploy/duty.md +0 -10
  39. package/dist/duties/release-deploy/profile.json +0 -6
  40. package/dist/duties/release-prepare/duty.md +0 -10
  41. package/dist/duties/release-prepare/profile.json +0 -6
  42. package/dist/duties/release-publish/duty.md +0 -10
  43. package/dist/duties/release-publish/profile.json +0 -6
  44. package/dist/duties/resolve/duty.md +0 -10
  45. package/dist/duties/resolve/profile.json +0 -6
  46. package/dist/duties/revert/duty.md +0 -10
  47. package/dist/duties/revert/profile.json +0 -6
  48. package/dist/duties/sync/duty.md +0 -10
  49. package/dist/duties/sync/profile.json +0 -6
  50. package/dist/duties/task-job-fail-once/duty.md +0 -3
  51. package/dist/duties/task-job-fail-once/profile.json +0 -6
  52. package/dist/duties/task-job-pass-a/duty.md +0 -3
  53. package/dist/duties/task-job-pass-a/profile.json +0 -6
  54. package/dist/duties/task-job-pass-b/duty.md +0 -3
  55. package/dist/duties/task-job-pass-b/profile.json +0 -6
  56. package/dist/duties/task-jobs/duty.md +0 -3
  57. package/dist/duties/task-jobs/profile.json +0 -6
  58. package/dist/duties/worker-ask/duty.md +0 -10
  59. package/dist/duties/worker-ask/profile.json +0 -6
  60. package/dist/executables/duty-scheduler/profile.json +0 -57
  61. package/dist/executables/duty-tick/profile.json +0 -78
  62. package/dist/executables/duty-tick/prompt.md +0 -77
  63. package/dist/executables/duty-tick/prompts/locked.md +0 -50
  64. package/dist/executables/duty-tick-scripted/profile.json +0 -72
  65. package/dist/executables/fix/profile.json +0 -91
  66. package/dist/executables/fix/prompt.md +0 -90
  67. package/dist/executables/fix-ci/profile.json +0 -71
  68. package/dist/executables/fix-ci/prompt.md +0 -78
  69. package/dist/executables/goal-scheduler/profile.json +0 -53
  70. package/dist/executables/goal-scheduler/scheduler.sh +0 -82
  71. package/dist/executables/goal-tick/profile.json +0 -69
  72. package/dist/executables/init/profile.json +0 -36
  73. package/dist/executables/job-live-verify/profile.json +0 -36
  74. package/dist/executables/job-live-verify/prompt.md +0 -42
  75. package/dist/executables/merge/profile.json +0 -54
  76. package/dist/executables/npm-publish/profile.json +0 -73
  77. package/dist/executables/npm-publish/publish.sh +0 -93
  78. package/dist/executables/plan-verify/profile.json +0 -38
  79. package/dist/executables/plan-verify/prompt.md +0 -72
  80. package/dist/executables/preview-build/profile.json +0 -61
  81. package/dist/executables/preview-health/profile.json +0 -48
  82. package/dist/executables/preview-health/tick.sh +0 -319
  83. package/dist/executables/probe-skill/profile.json +0 -35
  84. package/dist/executables/probe-skill/prompt.md +0 -31
  85. package/dist/executables/probe-skill/skills/probe-skill-marker/SKILL.md +0 -18
  86. package/dist/executables/qa-goal/profile.json +0 -65
  87. package/dist/executables/release/deploy.sh +0 -157
  88. package/dist/executables/release/prepare.sh +0 -353
  89. package/dist/executables/release/profile.json +0 -95
  90. package/dist/executables/release/publish.sh +0 -88
  91. package/dist/executables/release/release.sh +0 -230
  92. package/dist/executables/release/wait.sh +0 -88
  93. package/dist/executables/release-deploy/deploy.sh +0 -222
  94. package/dist/executables/release-deploy/profile.json +0 -53
  95. package/dist/executables/release-prepare/prepare.sh +0 -368
  96. package/dist/executables/release-prepare/profile.json +0 -70
  97. package/dist/executables/release-publish/profile.json +0 -53
  98. package/dist/executables/release-publish/publish.sh +0 -137
  99. package/dist/executables/resolve/apply-prefer.sh +0 -54
  100. package/dist/executables/resolve/profile.json +0 -107
  101. package/dist/executables/resolve/prompt.md +0 -51
  102. package/dist/executables/revert/profile.json +0 -82
  103. package/dist/executables/revert/revert.sh +0 -33
  104. package/dist/executables/sync/profile.json +0 -48
  105. package/dist/executables/task-job-fail-once/profile.json +0 -44
  106. package/dist/executables/task-job-fail-once/prompt.md +0 -1
  107. package/dist/executables/task-job-pass-a/profile.json +0 -43
  108. package/dist/executables/task-job-pass-a/prompt.md +0 -1
  109. package/dist/executables/task-job-pass-b/profile.json +0 -43
  110. package/dist/executables/task-job-pass-b/prompt.md +0 -1
  111. package/dist/executables/task-jobs/profile.json +0 -41
  112. package/dist/executables/task-jobs/prompt.md +0 -1
  113. package/dist/executables/worker-ask/profile.json +0 -70
  114. package/dist/executables/worker-ask/prompt.md +0 -60
@@ -1,368 +0,0 @@
1
- #!/usr/bin/env bash
2
- #
3
- # release-prepare: bump version files, generate CHANGELOG.md, commit on a
4
- # release branch, open the release PR. Pure mechanical work — no agent.
5
- #
6
- # Inputs (env, set by the executor):
7
- # KODY_ARG_BUMP patch|minor|major (default: patch)
8
- # KODY_ARG_DRY_RUN true|false
9
- # KODY_ARG_PREFER ours|theirs (optional)
10
- # KODY_ARG_ISSUE triggering issue/PR number (optional)
11
- #
12
- # Config (env, flattened from kody.config.json):
13
- # KODY_CFG_GIT_DEFAULTBRANCH e.g. main
14
- # KODY_CFG_RELEASE_VERSIONFILES JSON array, e.g. ["package.json"]
15
- #
16
- # Stdout signals to the executor:
17
- # KODY_PR_URL=<url> — set ctx.output.prUrl (final PR URL)
18
- # KODY_REASON=<text> — set ctx.output.reason (failure or dry-run note)
19
- # KODY_SKIP_AGENT=true — bypass the agent (always; this is a no-agent flow)
20
-
21
- set -euo pipefail
22
-
23
- # ── Helpers ────────────────────────────────────────────────────────────────
24
-
25
- bump="${KODY_ARG_BUMP:-patch}"
26
- dry_run="${KODY_ARG_DRY_RUN:-false}"
27
- prefer="${KODY_ARG_PREFER:-}"
28
- default_branch="${KODY_CFG_GIT_DEFAULTBRANCH:-main}"
29
- version_files_json="${KODY_CFG_RELEASE_VERSIONFILES:-}"
30
-
31
- fail() {
32
- local reason="$1"
33
- echo "KODY_REASON=$reason"
34
- echo "KODY_SKIP_AGENT=true"
35
- exit "${2:-1}"
36
- }
37
-
38
- bump_version() {
39
- local cur="$1" kind="$2"
40
- local rest="${cur#*-}"
41
- local core="${cur%%-*}"
42
- if ! [[ "$core" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
43
- fail "release prepare: cannot parse version '$cur' (expected x.y.z[-suffix])" 99
44
- fi
45
- local maj="${BASH_REMATCH[1]}" min="${BASH_REMATCH[2]}" pat="${BASH_REMATCH[3]}"
46
- case "$kind" in
47
- major) maj=$((maj + 1)); min=0; pat=0 ;;
48
- minor) min=$((min + 1)); pat=0 ;;
49
- patch|*) pat=$((pat + 1)) ;;
50
- esac
51
- echo "${maj}.${min}.${pat}"
52
- }
53
-
54
- read_pkg_version() {
55
- python3 -c "import json,sys; print(json.load(open('package.json'))['version'])"
56
- }
57
-
58
- write_pkg_version() {
59
- local file="$1" new="$2"
60
- python3 - "$file" "$new" <<'PY'
61
- import json, sys
62
- path, new = sys.argv[1], sys.argv[2]
63
- try:
64
- with open(path) as f:
65
- text = f.read()
66
- except FileNotFoundError:
67
- print("MISSING")
68
- sys.exit(0)
69
- try:
70
- data = json.loads(text)
71
- except Exception:
72
- print("UNCHANGED")
73
- sys.exit(0)
74
- if data.get("version") == new:
75
- print("UNCHANGED")
76
- sys.exit(0)
77
- data["version"] = new
78
- indent = 2
79
- with open(path, "w") as f:
80
- f.write(json.dumps(data, indent=indent) + "\n")
81
- print("WROTE")
82
- PY
83
- }
84
-
85
- resolve_version_files() {
86
- if [[ -z "$version_files_json" ]]; then
87
- echo "package.json"
88
- return
89
- fi
90
- python3 - <<PY
91
- import json, os, sys
92
- raw = os.environ.get("KODY_CFG_RELEASE_VERSIONFILES", "")
93
- try:
94
- arr = json.loads(raw)
95
- except Exception:
96
- print("package.json")
97
- sys.exit(0)
98
- if isinstance(arr, list) and arr:
99
- for f in arr:
100
- if isinstance(f, str) and f:
101
- print(f)
102
- else:
103
- print("package.json")
104
- PY
105
- }
106
-
107
- generate_changelog() {
108
- local new_version="$1"
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
123
- else
124
- echo " changelog: no previous v* tag found — using last 100 commits" >&2
125
- git log -n100 HEAD --pretty=format:'%s||%h' --no-merges 2>/dev/null || true
126
- fi
127
- }
128
-
129
- format_changelog() {
130
- local new_version="$1"
131
- local date_str
132
- date_str=$(date -u +%Y-%m-%d)
133
- python3 - "$new_version" "$date_str" <<PY
134
- import sys, re
135
- new_version, date_str = sys.argv[1], sys.argv[2]
136
- raw = sys.stdin.read()
137
- buckets = {k: [] for k in ("feat", "fix", "perf", "refactor", "docs", "chore", "other")}
138
- for line in raw.splitlines():
139
- line = line.strip()
140
- if not line:
141
- continue
142
- if "||" not in line:
143
- continue
144
- subject, sha = line.split("||", 1)
145
- if re.match(r"(?i)^chore:\s*release\s+v\d", subject):
146
- continue
147
- m = re.match(r"^(\w+)(?:\(.*?\))?\s*:\s*(.+)$", subject)
148
- if m:
149
- kind = m.group(1).lower()
150
- msg = m.group(2)
151
- else:
152
- kind = "other"
153
- msg = subject
154
- buckets.setdefault(kind, buckets["other"]).append(f"- {msg} ({sha})")
155
- labels = [
156
- ("feat", "Features"),
157
- ("fix", "Fixes"),
158
- ("perf", "Performance"),
159
- ("refactor", "Refactoring"),
160
- ("docs", "Docs"),
161
- ("chore", "Chores"),
162
- ("other", "Other"),
163
- ]
164
- parts = [f"## v{new_version} — {date_str}", ""]
165
- emitted = False
166
- for key, label in labels:
167
- items = buckets.get(key) or []
168
- if not items:
169
- continue
170
- parts.append(f"### {label}")
171
- parts.extend(items)
172
- parts.append("")
173
- emitted = True
174
- if not emitted:
175
- parts.append("_No notable commits since the last release._")
176
- parts.append("")
177
- sys.stdout.write("\n".join(parts))
178
- PY
179
- }
180
-
181
- prepend_changelog() {
182
- local entry="$1"
183
- local header='# Changelog
184
-
185
- All notable changes to this project will be documented in this file.
186
-
187
- '
188
- if [[ -f CHANGELOG.md ]]; then
189
- if grep -qE '^#\s*Changelog\b' CHANGELOG.md; then
190
- python3 - "$entry" <<'PY'
191
- import sys
192
- entry = sys.argv[1]
193
- with open("CHANGELOG.md") as f:
194
- prior = f.read()
195
- idx = prior.index("\n", prior.index("# Changelog"))
196
- new = prior[: idx + 1] + "\n" + entry + prior[idx + 1 :]
197
- with open("CHANGELOG.md", "w") as f:
198
- f.write(new)
199
- PY
200
- else
201
- python3 - "$entry" <<'PY'
202
- import sys
203
- entry = sys.argv[1]
204
- header = "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n"
205
- with open("CHANGELOG.md") as f:
206
- prior = f.read()
207
- with open("CHANGELOG.md", "w") as f:
208
- f.write(header + entry + prior)
209
- PY
210
- fi
211
- else
212
- python3 - "$entry" <<'PY'
213
- import sys
214
- entry = sys.argv[1]
215
- header = "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n"
216
- with open("CHANGELOG.md", "w") as f:
217
- f.write(header + entry)
218
- PY
219
- fi
220
- }
221
-
222
- remote_branch_exists() {
223
- local branch="$1"
224
- git ls-remote --heads origin "$branch" 2>/dev/null | grep -q .
225
- }
226
-
227
- find_open_pr() {
228
- local branch="$1"
229
- gh pr list --head "$branch" --state open --json url --limit 1 2>/dev/null \
230
- | python3 -c 'import json,sys; data=json.load(sys.stdin); print(data[0]["url"] if data else "")' 2>/dev/null \
231
- || echo ""
232
- }
233
-
234
- # ── Flow ───────────────────────────────────────────────────────────────────
235
-
236
- if [[ ! -f package.json ]]; then
237
- fail "release prepare: package.json not found" 99
238
- fi
239
-
240
- old_version=$(read_pkg_version)
241
- new_version=$(bump_version "$old_version" "$bump")
242
- tag="v${new_version}"
243
- release_branch="release/${tag}"
244
-
245
- echo "→ release prepare: ${old_version} → ${new_version} (${bump})"
246
-
247
- if [[ "$dry_run" == "true" ]]; then
248
- echo "RELEASE_PLAN=bump=${new_version} tag=${tag}"
249
- echo "KODY_REASON=dry-run — would bump to ${new_version}${prefer:+ (--prefer ${prefer})}"
250
- echo "KODY_SKIP_AGENT=true"
251
- exit 0
252
- fi
253
-
254
- # Branch-collision gate.
255
- collides=false
256
- if remote_branch_exists "$release_branch"; then
257
- collides=true
258
- case "$prefer" in
259
- theirs)
260
- existing=$(find_open_pr "$release_branch")
261
- if [[ -n "$existing" ]]; then
262
- echo " reusing existing PR (--prefer theirs): ${existing}"
263
- echo "KODY_PR_URL=${existing}"
264
- echo "KODY_REASON=reused existing release PR"
265
- echo "KODY_SKIP_AGENT=true"
266
- exit 0
267
- fi
268
- fail "release prepare --prefer theirs: ${release_branch} exists on remote but has no open PR — nothing to reuse" 4
269
- ;;
270
- ours)
271
- echo " branch ${release_branch} exists on remote — will force-push (--prefer ours)"
272
- ;;
273
- *)
274
- fail "release prepare: branch ${release_branch} already exists on remote. Use --prefer ours to force-push, or --prefer theirs to reuse the existing PR." 4
275
- ;;
276
- esac
277
- fi
278
-
279
- # Bump version files.
280
- mapfile -t files < <(resolve_version_files)
281
- touched=()
282
- for f in "${files[@]}"; do
283
- res=$(write_pkg_version "$f" "$new_version")
284
- if [[ "$res" == "WROTE" ]]; then
285
- touched+=("$f")
286
- fi
287
- done
288
- if [[ ${#touched[@]} -eq 0 ]]; then
289
- fail "release prepare: no version strings updated (files: ${files[*]})"
290
- fi
291
- echo " wrote ${touched[*]}"
292
-
293
- # Changelog.
294
- raw_log=$(generate_changelog "$new_version") || raw_log=""
295
- entry=$(printf '%s' "$raw_log" | format_changelog "$new_version")
296
- prepend_changelog "$entry"
297
- echo " wrote CHANGELOG.md"
298
-
299
- # Commit + push.
300
- export HUSKY=0 SKIP_HOOKS=1
301
- git checkout -b "$release_branch"
302
- for f in "${touched[@]}" CHANGELOG.md; do
303
- git add -- "$f"
304
- done
305
- git -c commit.gpgsign=false commit -m "chore: release ${tag}"
306
- if [[ "$collides" == "true" && "$prefer" == "ours" ]]; then
307
- git push -u --force-with-lease origin "$release_branch"
308
- else
309
- git push -u origin "$release_branch"
310
- fi
311
-
312
- # Open PR (or link to existing one if --prefer ours collided).
313
- pr_url=""
314
- if [[ "$collides" == "true" && "$prefer" == "ours" ]]; then
315
- pr_url=$(find_open_pr "$release_branch")
316
- fi
317
-
318
- if [[ -z "$pr_url" ]]; then
319
- body_max=60000
320
- if [[ ${#entry} -gt $body_max ]]; then
321
- body_entry="${entry:0:$body_max}
322
-
323
- _… truncated; see CHANGELOG.md_"
324
- else
325
- body_entry="$entry"
326
- fi
327
- # Link the PR back to the originating release issue WITHOUT auto-closing
328
- # it. The orchestrator continues to publish + deploy after merge using the
329
- # issue as the dispatch target, so the issue must stay open for the
330
- # dashboard to keep showing the task as in-progress until finishFlow
331
- # applies kody:done. We use `Tracking-Issue: #N` (not `Closes #N`) — GitHub
332
- # treats this as plain text, the dashboard parses it as a fallback link
333
- # signal, and no auto-close fires on PR merge.
334
- issue_arg="${KODY_ARG_ISSUE:-}"
335
- tracking_line=""
336
- if [[ "$issue_arg" =~ ^[0-9]+$ && "$issue_arg" != "0" ]]; then
337
- tracking_line=$'\n\nTracking-Issue: #'"${issue_arg}"
338
- fi
339
- 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.'"${tracking_line}"
340
- pr_url=$(printf '%s' "$body" | gh pr create --head "$release_branch" --base "$default_branch" --title "chore: release ${tag}" --body-file -)
341
- fi
342
-
343
- if [[ -z "$pr_url" ]]; then
344
- fail "release prepare: gh pr create returned empty URL" 4
345
- fi
346
-
347
- # Persist a release-PR marker on the originating issue body so the Kody
348
- # Dashboard can link the issue → PR even if @kody fix later overwrites the
349
- # PR body. Idempotent: any existing marker line is stripped before append,
350
- # so re-runs replace the previous PR ref. The issue body is owned by the
351
- # orchestrator (no @kody fix touches it), so this signal is durable.
352
- if [[ "${issue_arg:-}" =~ ^[0-9]+$ && "${issue_arg:-0}" != "0" ]]; then
353
- pr_number="${pr_url##*/}"
354
- if [[ "$pr_number" =~ ^[0-9]+$ ]]; then
355
- cur_body=$(gh issue view "$issue_arg" --json body -q .body 2>/dev/null || echo "")
356
- cleaned_body=$(printf '%s' "$cur_body" | sed -E '/<!-- kody-release-pr:[^>]*-->/d')
357
- {
358
- printf '%s' "$cleaned_body"
359
- printf '\n\n<!-- kody-release-pr: #%s -->\n' "$pr_number"
360
- } | gh issue edit "$issue_arg" --body-file - >/dev/null 2>&1 || \
361
- echo "[kody release-prepare] WARN: failed to write kody-release-pr marker to issue #${issue_arg}"
362
- fi
363
- fi
364
-
365
- echo "RELEASE_PR=${pr_url}"
366
- echo "KODY_PR_URL=${pr_url}"
367
- echo "KODY_REASON=opened release PR for ${tag}"
368
- echo "KODY_SKIP_AGENT=true"
@@ -1,70 +0,0 @@
1
- {
2
- "name": "release-prepare",
3
- "role": "utility",
4
- "phase": "shipped",
5
- "describe": "Bump version files, generate CHANGELOG.md, commit on a release branch, open the release PR. No agent.",
6
- "inputs": [
7
- {
8
- "name": "bump",
9
- "flag": "--bump",
10
- "type": "enum",
11
- "values": ["patch", "minor", "major"],
12
- "required": false,
13
- "describe": "Version bump increment. Default patch."
14
- },
15
- {
16
- "name": "dry-run",
17
- "flag": "--dry-run",
18
- "type": "bool",
19
- "required": false,
20
- "describe": "Print plan without writing files, committing, or opening a PR."
21
- },
22
- {
23
- "name": "prefer",
24
- "flag": "--prefer",
25
- "type": "enum",
26
- "values": ["ours", "theirs"],
27
- "required": false,
28
- "describe": "On release/vX.Y.Z branch collision: 'ours' force-pushes; 'theirs' reuses the existing PR. Default refuses non-ff."
29
- },
30
- {
31
- "name": "issue",
32
- "flag": "--issue",
33
- "type": "int",
34
- "required": false,
35
- "describe": "Issue/PR number to post the terminal notice on. Auto-injected by dispatch."
36
- }
37
- ],
38
- "claudeCode": {
39
- "model": "inherit",
40
- "permissionMode": "acceptEdits",
41
- "maxTurns": 0,
42
- "maxThinkingTokens": null,
43
- "systemPromptAppend": null,
44
- "tools": [],
45
- "hooks": [],
46
- "skills": [],
47
- "commands": [],
48
- "subagents": [],
49
- "plugins": [],
50
- "mcpServers": []
51
- },
52
- "cliTools": [],
53
- "inputArtifacts": [],
54
- "outputArtifacts": [],
55
- "scripts": {
56
- "preflight": [
57
- { "script": "setCommentTarget", "with": { "type": "issue" } },
58
- { "script": "loadTaskState" },
59
- { "shell": "prepare.sh" },
60
- { "script": "skipAgent" }
61
- ],
62
- "postflight": [
63
- { "script": "recordOutcome" },
64
- { "script": "saveTaskState" },
65
- { "script": "mirrorStateToPr" },
66
- { "script": "notifyTerminal", "with": { "label": "release prepare" } },
67
- { "script": "advanceFlow" }
68
- ]
69
- }
70
- }
@@ -1,53 +0,0 @@
1
- {
2
- "name": "release-publish",
3
- "role": "utility",
4
- "phase": "shipped",
5
- "describe": "Tag the merged release commit, run the configured publishCommand, create the GitHub release. No agent.",
6
- "inputs": [
7
- {
8
- "name": "dry-run",
9
- "flag": "--dry-run",
10
- "type": "bool",
11
- "required": false,
12
- "describe": "Print plan without tagging or publishing."
13
- },
14
- {
15
- "name": "issue",
16
- "flag": "--issue",
17
- "type": "int",
18
- "required": false,
19
- "describe": "Issue/PR number to post the terminal notice on. Auto-injected by dispatch."
20
- }
21
- ],
22
- "claudeCode": {
23
- "model": "inherit",
24
- "permissionMode": "acceptEdits",
25
- "maxTurns": 0,
26
- "maxThinkingTokens": null,
27
- "systemPromptAppend": null,
28
- "tools": [],
29
- "hooks": [],
30
- "skills": [],
31
- "commands": [],
32
- "subagents": [],
33
- "plugins": [],
34
- "mcpServers": []
35
- },
36
- "cliTools": [],
37
- "inputArtifacts": [],
38
- "outputArtifacts": [],
39
- "scripts": {
40
- "preflight": [
41
- { "script": "setCommentTarget", "with": { "type": "issue" } },
42
- { "script": "loadTaskState" },
43
- { "shell": "publish.sh" },
44
- { "script": "skipAgent" }
45
- ],
46
- "postflight": [
47
- { "script": "recordOutcome" },
48
- { "script": "saveTaskState" },
49
- { "script": "notifyTerminal", "with": { "label": "release publish" } },
50
- { "script": "advanceFlow" }
51
- ]
52
- }
53
- }
@@ -1,137 +0,0 @@
1
- #!/usr/bin/env bash
2
- #
3
- # release-publish: tag the current package version, push the tag, run the
4
- # configured publishCommand (e.g. `pnpm publish --access public`), create
5
- # the GitHub release. Runs AFTER the orchestrator has merged the release
6
- # PR into the default branch. No agent.
7
- #
8
- # Inputs (env):
9
- # KODY_ARG_DRY_RUN true|false
10
- # KODY_ARG_ISSUE triggering issue/PR number (optional)
11
- #
12
- # Config (env):
13
- # KODY_CFG_GIT_DEFAULTBRANCH e.g. main
14
- # KODY_CFG_RELEASE_PUBLISHCOMMAND optional; $VERSION is substituted
15
- # KODY_CFG_RELEASE_DRAFTRELEASE "true" → create as draft
16
- # KODY_CFG_RELEASE_TIMEOUTMS publish timeout (default 600000ms)
17
- #
18
- # Stdout signals:
19
- # KODY_REASON=<text>
20
- # KODY_PR_URL=<release URL> — gh release create URL (used as the "PR" link)
21
- # KODY_SKIP_AGENT=true
22
-
23
- set -euo pipefail
24
-
25
- dry_run="${KODY_ARG_DRY_RUN:-false}"
26
- default_branch="${KODY_CFG_GIT_DEFAULTBRANCH:-main}"
27
- publish_cmd="${KODY_CFG_RELEASE_PUBLISHCOMMAND:-}"
28
- draft="${KODY_CFG_RELEASE_DRAFTRELEASE:-false}"
29
- timeout_ms="${KODY_CFG_RELEASE_TIMEOUTMS:-600000}"
30
- timeout_s=$((timeout_ms / 1000))
31
-
32
- fail() {
33
- echo "KODY_REASON=$1"
34
- echo "KODY_SKIP_AGENT=true"
35
- exit "${2:-1}"
36
- }
37
-
38
- read_pkg_version() {
39
- python3 -c "import json; print(json.load(open('package.json'))['version'])"
40
- }
41
-
42
- if [[ ! -f package.json ]]; then
43
- fail "release publish: package.json not found" 99
44
- fi
45
-
46
- export HUSKY=0 SKIP_HOOKS=1 CI="${CI:-1}"
47
-
48
- # Make sure we're on the merged commit. The orchestrator merged the release
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"
53
-
54
- version=$(read_pkg_version)
55
- tag="v${version}"
56
-
57
- echo "→ release publish: ${tag}"
58
-
59
- # Recovery is resume-not-overwrite: a release is three steps (push tag, run
60
- # publishCommand, create GH release) and any of them may already be done from
61
- # a prior partial run. We probe each step's state and perform only the missing
62
- # parts. An already-fully-released version is therefore a no-op success, and we
63
- # never re-point or force an existing tag (that would rewrite a shipped version).
64
- tag_local=false
65
- tag_remote=false
66
- release_exists=false
67
- if git rev-parse --verify "$tag" >/dev/null 2>&1; then tag_local=true; fi
68
- if git ls-remote --exit-code --tags origin "refs/tags/$tag" >/dev/null 2>&1; then tag_remote=true; fi
69
- if gh release view "$tag" >/dev/null 2>&1; then release_exists=true; fi
70
-
71
- if [[ "$tag_local" == "true" || "$tag_remote" == "true" || "$release_exists" == "true" ]]; then
72
- echo " resuming: tag exists (local=${tag_local} remote=${tag_remote}), gh-release=${release_exists}"
73
- fi
74
-
75
- if [[ "$dry_run" == "true" ]]; then
76
- echo "KODY_REASON=dry-run — would tag + publish ${tag} (tag_remote=${tag_remote}, gh-release=${release_exists})"
77
- echo "KODY_SKIP_AGENT=true"
78
- exit 0
79
- fi
80
-
81
- # Tag + push (skip whichever half already exists).
82
- if [[ "$tag_local" == "false" && "$tag_remote" == "false" ]]; then
83
- git tag -a "$tag" -m "Release ${tag}"
84
- fi
85
- if [[ "$tag_remote" == "false" ]]; then
86
- git push origin "$tag"
87
- fi
88
-
89
- # publishCommand (optional). A version that's already on the registry is the
90
- # expected recovery case, not an error: treat "already published" as done.
91
- # Any other non-zero is a real failure (recorded, but we still create the GH
92
- # release so the tag is discoverable).
93
- publish_status="skipped"
94
- if [[ -n "$publish_cmd" ]]; then
95
- cmd="${publish_cmd//\$VERSION/$version}"
96
- echo " publish: ${cmd}"
97
- publish_out=""
98
- if publish_out=$(timeout "${timeout_s}" bash -c "$cmd" 2>&1); then
99
- publish_status="ok"
100
- elif echo "$publish_out" | grep -qiE "already exists|cannot publish over|previously published|403 Forbidden"; then
101
- publish_status="already-published"
102
- echo "[kody release-publish] version ${version} already on registry — treating as published"
103
- else
104
- publish_status="failed"
105
- echo "[kody release-publish] publishCommand failed (continuing to create GH release)" >&2
106
- fi
107
- echo "$publish_out"
108
- fi
109
-
110
- # GitHub release (create only if missing).
111
- release_url=""
112
- if [[ "$release_exists" == "true" ]]; then
113
- release_url=$(gh release view "$tag" --json url --jq .url 2>/dev/null || echo "")
114
- else
115
- draft_flag=""
116
- [[ "$draft" == "true" ]] && draft_flag="--draft"
117
- if release_url=$(gh release create "$tag" --title "$tag" --notes "Release ${tag} — automated by kody." $draft_flag 2>&1); then
118
- :
119
- else
120
- echo "[kody release-publish] gh release create failed: $release_url" >&2
121
- release_url=""
122
- fi
123
- fi
124
-
125
- echo "RELEASE_TAG=${tag}"
126
- [[ -n "$release_url" ]] && echo "RELEASE_URL=${release_url}"
127
-
128
- if [[ "$publish_status" == "failed" ]]; then
129
- echo "KODY_REASON=tag + GH release created, but publishCommand failed"
130
- echo "KODY_SKIP_AGENT=true"
131
- exit 1
132
- fi
133
-
134
- [[ -n "$release_url" ]] && echo "KODY_PR_URL=${release_url}"
135
- echo "KODY_REASON=tagged ${tag}, published${publish_status:+ ($publish_status)}"
136
- echo "KODY_SKIP_AGENT=true"
137
- exit 0
@@ -1,54 +0,0 @@
1
- #!/usr/bin/env bash
2
- #
3
- # Deterministic conflict resolution for `kody resolve --prefer ours|theirs`.
4
- #
5
- # Runs as a preflight shell entry (see src/executables/resolve/profile.json).
6
- # Gated by runWhen on args.prefer, so it only fires when the user requested
7
- # a side. Reads the side from $KODY_ARG_PREFER (the executor exposes every
8
- # ctx.args.<key> as an env var).
9
- #
10
- # Preconditions set by the prior `resolveFlow` preflight:
11
- # - cwd is on the PR branch.
12
- # - `git merge origin/<base> --no-edit --no-ff` already ran and conflicted.
13
- # - Working tree has unmerged paths.
14
- #
15
- # Behavior: for each unmerged file, git checkout --ours (or --theirs), add,
16
- # commit the merge, push the branch. Prints `KODY_SKIP_AGENT=true` on
17
- # success so the executor bypasses the agent entirely.
18
- #
19
- # Exits:
20
- # 0 — resolved + pushed (or nothing to resolve)
21
- # 64 — invalid side value
22
- # 1+ — git operation failed (executor will surface stderr)
23
-
24
- set -euo pipefail
25
-
26
- side="${KODY_ARG_PREFER:-}"
27
- if [[ "$side" != "ours" && "$side" != "theirs" ]]; then
28
- echo "apply-prefer: expected KODY_ARG_PREFER=ours|theirs, got '$side'" >&2
29
- exit 64
30
- fi
31
-
32
- unmerged=$(git diff --name-only --diff-filter=U)
33
- if [[ -z "$unmerged" ]]; then
34
- echo "apply-prefer: no unmerged paths — nothing to resolve"
35
- echo "KODY_SKIP_AGENT=true"
36
- exit 0
37
- fi
38
-
39
- count=0
40
- while IFS= read -r f; do
41
- [[ -z "$f" ]] && continue
42
- git checkout "--$side" -- "$f"
43
- git add -- "$f"
44
- count=$((count + 1))
45
- done <<< "$unmerged"
46
- echo "apply-prefer: resolved $count file(s) via --$side"
47
-
48
- # Complete the merge. git merge left MERGE_MSG in place; --no-edit uses it.
49
- HUSKY=0 SKIP_HOOKS=1 git -c commit.gpgsign=false commit --no-edit
50
-
51
- branch=$(git rev-parse --abbrev-ref HEAD)
52
- git push origin "$branch"
53
- echo "apply-prefer: pushed $branch"
54
- echo "KODY_SKIP_AGENT=true"