oh-my-customcode 1.1.38 → 1.1.40

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/cli/index.js CHANGED
@@ -241,7 +241,7 @@ var init_package = __esm(() => {
241
241
  workspaces: [
242
242
  "packages/*"
243
243
  ],
244
- version: "1.1.38",
244
+ version: "1.1.40",
245
245
  description: "Batteries-included agent harness for Claude Code",
246
246
  type: "module",
247
247
  bin: {
package/dist/index.js CHANGED
@@ -2031,7 +2031,7 @@ var package_default = {
2031
2031
  workspaces: [
2032
2032
  "packages/*"
2033
2033
  ],
2034
- version: "1.1.38",
2034
+ version: "1.1.40",
2035
2035
  description: "Batteries-included agent harness for Claude Code",
2036
2036
  type: "module",
2037
2037
  bin: {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "workspaces": [
4
4
  "packages/*"
5
5
  ],
6
- "version": "1.1.38",
6
+ "version": "1.1.40",
7
7
  "description": "Batteries-included agent harness for Claude Code",
8
8
  "type": "module",
9
9
  "bin": {
@@ -261,12 +261,16 @@
261
261
  "type": "command",
262
262
  "command": "bash .claude/hooks/scripts/auto-continue-guard.sh"
263
263
  },
264
+ {
265
+ "type": "command",
266
+ "command": "bash .claude/hooks/scripts/r007-r008-drift-advisor.sh"
267
+ },
264
268
  {
265
269
  "type": "prompt",
266
270
  "prompt": "A background subagent just completed. If it FAILED, do NOT auto-continue \u2014 report the failure and wait for user input."
267
271
  }
268
272
  ],
269
- "description": "Record agent outcomes + auto-continue workflow on subagent completion"
273
+ "description": "Record agent outcomes + auto-continue workflow + R007/R008 drift advisory on subagent completion (autonomous-loop re-entry, #1545)"
270
274
  }
271
275
  ],
272
276
  "CwdChanged": [
@@ -1,15 +1,43 @@
1
1
  #!/usr/bin/env bash
2
- # r007-r008-drift-advisor.sh — UserPromptSubmit hook: PROACTIVE R007/R008 drift advisory (#1229)
2
+ # r007-r008-drift-advisor.sh — PROACTIVE R007/R008 drift advisory (#1229, #1545, #1547)
3
+ #
4
+ # Wired to TWO trigger points:
5
+ # 1. UserPromptSubmit — fires before Claude responds to a user-typed prompt (#1229).
6
+ # 2. SubagentStop — fires when a background subagent (Agent tool) completes, covering
7
+ # autonomous-loop re-entry (e.g. /fsd) where the orchestrator resumes WITHOUT a
8
+ # UserPromptSubmit event. Prior to #1545, autonomous-loop re-entry had zero R007/R008
9
+ # advisory coverage since UserPromptSubmit never fires in that path.
3
10
  #
4
11
  # Inspects the LAST completed assistant turn in the session transcript for R007/R008
5
12
  # compliance BEFORE Claude responds. If the previous turn drifted (missing identification
6
- # header / tool prefix), emits a stderr advisory so the upcoming response self-corrects.
13
+ # header / tool prefix), delivers an advisory so the upcoming response self-corrects.
7
14
  #
8
15
  # This is the PROACTIVE complement to the retroactive session-reflection.sh (Stop hook, #1190).
9
16
  # Detection patterns are reused from session-reflection.sh.
10
17
  #
11
- # Advisory-only: ALWAYS exits 0, ALWAYS passes stdin through to stdout, NEVER blocks.
18
+ # Advisory-only: ALWAYS exits 0, NEVER blocks.
12
19
  # Performance: parses ONLY the last assistant turn (not the whole transcript).
20
+ # Input-schema note: session_id/transcript_path are COMMON fields present on both
21
+ # UserPromptSubmit and SubagentStop hook payloads, so the detection logic below is
22
+ # event-agnostic and required no functional changes for the SubagentStop wiring.
23
+ #
24
+ # Delivery mechanism (#1547 fix):
25
+ # Prior to this fix, the advisory was written to stderr with exit 0. Per the official
26
+ # Claude Code hook spec, stderr on exit 0 is NEVER fed into the model's context for ANY
27
+ # hook event (it is only visible in transcript debug mode, i.e. to a human, not Claude) —
28
+ # so #1545's SubagentStop wiring never actually reached the model despite firing correctly.
29
+ # The confirmed non-blocking delivery path for BOTH UserPromptSubmit and SubagentStop is
30
+ # `hookSpecificOutput.additionalContext` in JSON stdout with exit 0:
31
+ # {"hookSpecificOutput": {"hookEventName": "<event>", "additionalContext": "<text>"}}
32
+ # This is NOT the same as `"decision": "block"` — that would force Stop/SubagentStop to
33
+ # block (refuse to stop), which is exactly the blocking behavior R021 (advisory-first
34
+ # enforcement) forbids for this hook. additionalContext alone (no `decision` field) is
35
+ # non-blocking: Claude is allowed to stop/continue normally and simply sees the extra
36
+ # context on its next turn. Exit code MUST stay 0 — exit 2 causes Claude Code to discard
37
+ # any JSON output and treat stderr as a blocking error instead (see Common JSON Fields /
38
+ # Exit Code Behavior in the official hook reference).
39
+ # The stderr line is kept for human-visible audit trail (harmless on exit 0) but is no
40
+ # longer the delivery mechanism.
13
41
  #
14
42
  # 환경변수 override (테스트/디버깅용):
15
43
  # OMCUSTOM_R007_ADVISOR=off — advisory 완전 비활성화 (pass-through)
@@ -17,34 +45,36 @@
17
45
 
18
46
  set -euo pipefail
19
47
 
20
- # ── UserPromptSubmit 프로토콜: stdin을 먼저 읽음 ──
48
+ # ── stdin 읽기 ──
21
49
  input=$(cat)
22
50
 
23
51
  # ── Opt-out 체크 ──
24
52
  if [ "${OMCUSTOM_R007_ADVISOR:-}" = "off" ]; then
25
- echo "$input"
26
53
  exit 0
27
54
  fi
28
55
 
29
56
  # ── jq 의존성 체크 ──
30
57
  if ! command -v jq >/dev/null 2>&1; then
31
- echo "$input"
32
58
  exit 0
33
59
  fi
34
60
 
35
61
  # ── session_id 추출 ──
36
62
  session_id=$(echo "$input" | jq -r '.session_id // empty' 2>/dev/null)
37
63
  if [ -z "$session_id" ]; then
38
- echo "$input"
39
64
  exit 0
40
65
  fi
41
66
 
67
+ # ── hook_event_name 추출 (hookSpecificOutput.hookEventName에 되돌려줄 값) ──
68
+ hook_event_name=$(echo "$input" | jq -r '.hook_event_name // empty' 2>/dev/null)
69
+ if [ -z "$hook_event_name" ]; then
70
+ hook_event_name="UserPromptSubmit"
71
+ fi
72
+
42
73
  # ── 경로 결정 (환경변수 override 지원) ──
43
74
  TRANSCRIPT_BASE="${OMCUSTOM_TRANSCRIPT_BASE:-${HOME}/.claude/projects/-Users-sangyi-workspace-projects-oh-my-customcode}"
44
75
  TRANSCRIPT_PATH="${TRANSCRIPT_BASE}/${session_id}.jsonl"
45
76
 
46
77
  if [ ! -f "$TRANSCRIPT_PATH" ]; then
47
- echo "$input"
48
78
  exit 0
49
79
  fi
50
80
 
@@ -60,7 +90,6 @@ while IFS= read -r line; do
60
90
  done < <(tail -r "$TRANSCRIPT_PATH" 2>/dev/null || tac "$TRANSCRIPT_PATH" 2>/dev/null)
61
91
 
62
92
  if [ -z "$last_assistant" ]; then
63
- echo "$input"
64
93
  exit 0
65
94
  fi
66
95
 
@@ -106,12 +135,21 @@ while [ "$i" -lt "$content_length" ]; do
106
135
  i=$((i+1))
107
136
  done
108
137
 
109
- # ── advisory 출력 (위반 시에만) ──
138
+ # ── advisory 전달 (위반 시에만) ──
110
139
  if [ "$r007_violations" -gt 0 ] || [ "$r008_violations" -gt 0 ]; then
111
- printf '[R007/R008 Advisory] 직전 응답에서 식별 누락 감지 (R007 헤더=%d, R008 접두사=%d). 이번 응답은 ┌─ Agent: 헤더로 시작하고, 모든 도구 호출에 [agent][model] → Tool: 접두사를 포함하십시오.\n' \
112
- "$r007_violations" "$r008_violations" >&2
140
+ advisory_text=$(printf '[R007/R008 Advisory] 직전 응답에서 식별 누락 감지 (R007 헤더=%d, R008 접두사=%d). 이번 응답은 ┌─ Agent: 헤더로 시작하고, 모든 도구 호출에 [agent][model] → Tool: 접두사를 포함하십시오.' \
141
+ "$r007_violations" "$r008_violations")
142
+
143
+ # 사람이 보는 감사 추적용 (exit 0에서는 모델에 전달되지 않음 — #1547 참고)
144
+ printf '%s\n' "$advisory_text" >&2
145
+
146
+ # #1547 fix: hookSpecificOutput.additionalContext로 모델 컨텍스트에 실제 전달.
147
+ # decision 필드는 절대 포함하지 않는다 — "block"을 쓰면 Stop/SubagentStop 정지를
148
+ # 강제로 막아버려 advisory-only 원칙(R021)을 위반하게 된다. exit code는 반드시 0.
149
+ jq -cn --arg event "$hook_event_name" --arg ctx "$advisory_text" \
150
+ '{hookSpecificOutput: {hookEventName: $event, additionalContext: $ctx}}'
113
151
  fi
114
152
 
115
- # ── 항상 stdin pass-through 후 exit 0 (advisory는 절대 차단 금지) ──
116
- echo "$input"
153
+ # ── 위반이 없으면 아무것도 출력하지 않는다 (오탐 방지) ──
154
+ # ── 항상 exit 0 (advisory는 절대 차단 금지) ──
117
155
  exit 0
@@ -14,7 +14,7 @@ oh-my-customcode uses an **advisory-first enforcement model**. Most rules are en
14
14
  | Soft Block | Stop hook prompt | R011 session-end saves | Auto-performs then approves |
15
15
  | Conversation Block | PostToolUse hook + `continueOnBlock` (CC v2.1.139+), exit 2 | stuck-detector, context-budget-advisor, cost-cap-advisor | Feeds rejection reason into conversation; Claude continues with awareness |
16
16
  | Advisory | PostToolUse hooks | R007, R008, R009, R010, R018 | Warns via stderr, never blocks |
17
- | Advisory (proactive) | UserPromptSubmit hook | R007, R008 (`r007-r008-drift-advisor.sh`, #1229) | Reads last assistant turn; emits stderr advisory before next response if header/prefix absent. Complements retroactive Stop-hook (`session-reflection.sh`, #1190). |
17
+ | Advisory (proactive) | UserPromptSubmit + SubagentStop hooks | R007, R008 (`r007-r008-drift-advisor.sh`, #1229 UserPromptSubmit; #1545 added SubagentStop) | Reads last assistant turn; emits stderr advisory if header/prefix absent. SubagentStop wiring (#1545) closes a structural gap: UserPromptSubmit fires only on user input, so long-lived autonomous loops (e.g. `/fsd`) that re-enter via task notifications (no user input) never reached the advisor — measured 2026-07-30: 6 responses / 12 tool calls with missing R007/R008 and zero advisory fires. Complements retroactive Stop-hook (`session-reflection.sh`, #1190). **Delivery gap resolved (#1547, v1.1.40)**: stderr on exit 0 is never injected into model context by any hook event, so #1545's wiring fired without reaching the model. The advisory is now delivered via `hookSpecificOutput.additionalContext` (JSON stdout, exit 0) — the confirmed non-blocking context-injection path for both events; stderr is retained only as a human-visible audit trail. No top-level `decision`/`continue`/`stopReason` field is emitted, so the hook stays advisory (never blocks a Stop/SubagentStop). |
18
18
  | Prompt-based | CLAUDE.md + rules/ + PostCompact | All MUST rules | Behavioral guidance in context |
19
19
 
20
20
  <!--
@@ -34,7 +34,7 @@ oh-my-customcode uses an **advisory-first enforcement model**. Most rules are en
34
34
  3. **Composability**: External skills and internal rules can coexist without deadlocks
35
35
  4. **PostCompact reinforcement**: R007/R008/R009/R010/R018 are re-injected after context compaction
36
36
 
37
- ## Hard Enforcement Candidates — R010 git-delegation-guard (conditional), R007/R008 UserPromptSubmit advisory **implemented** (#1229, proactive) + retroactive Stop-hook (#1190); hard-block variant still candidate if advisory insufficient (#1096). Promoted: rule-deletion-guard.sh (2026-04-08). See details via Read tool.
37
+ ## Hard Enforcement Candidates — R010 git-delegation-guard (conditional), R007/R008 advisory **implemented** (#1229 UserPromptSubmit, proactive) + **#1545 SubagentStop** (closes autonomous-loop gap) + retroactive Stop-hook (#1190); model-context delivery fixed via `hookSpecificOutput.additionalContext` (#1547, v1.1.40); hard-block variant still candidate if advisory insufficient (#1096). Promoted: rule-deletion-guard.sh (2026-04-08). See details via Read tool.
38
38
 
39
39
  <!-- DETAIL: Hard Enforcement Candidates (Future)
40
40
  If advisory enforcement proves insufficient for specific rules, these are candidates for promotion to hard-block:
@@ -42,7 +42,7 @@ If advisory enforcement proves insufficient for specific rules, these are candid
42
42
  | Rule | Candidate Hook | Status | Condition for Promotion |
43
43
  |------|---------------|--------|------------------------|
44
44
  | R010 | git-delegation-guard.sh | Candidate | If orchestrator-direct-write violations exceed 3/session |
45
- | R007/R008 | `r007-r008-drift-advisor.sh` (UserPromptSubmit, #1229) | **Advisory implemented** — proactive pre-response check; retroactive: `session-reflection.sh` (Stop, #1190). Two-layer drift detection: proactive (#1229) + retroactive (#1190). | Promote to hard-block if advisory proves insufficient (#1096) |
45
+ | R007/R008 | `r007-r008-drift-advisor.sh` (UserPromptSubmit #1229 + SubagentStop #1545) | **Advisory implemented** — proactive pre-response check now wired to both UserPromptSubmit and SubagentStop; the SubagentStop leg (#1545) closes the no-user-input autonomous-loop gap (`/fsd` etc.). Retroactive: `session-reflection.sh` (Stop, #1190). Two-layer drift detection: proactive (#1229/#1545) + retroactive (#1190). **Delivery mechanism fixed (#1547, v1.1.40)** — stderr on exit 0 reaches only a human (transcript debug mode), never the model, so wiring alone did not prove advisory reach; the advisory now travels via `hookSpecificOutput.additionalContext` on JSON stdout with exit 0, and emits no top-level `decision`/`continue`/`stopReason` so it remains non-blocking. | Promote to hard-block if advisory proves insufficient (#1096) |
46
46
 
47
47
  Promotion requires: (1) measured violation rate data, (2) user approval, (3) rollback plan.
48
48
 
@@ -210,7 +210,11 @@ steps:
210
210
  - Detect file types in scope and route to matching agent
211
211
  - Use specialized agents (lang-*, be-*, fe-*, infra-*) over general-purpose
212
212
  4. TDD via superpowers:test-driven-development when tests apply
213
- 5. Commit via mgr-gitnerd with `Fixes #<N>` trailer in body
213
+ 5. Commit via mgr-gitnerd with `Refs #<N>` trailer in body — NEVER `Fixes`/`Closes`/`Resolves` (#1542).
214
+ ⚠ implement-stage commits land directly on develop (no PR gate here). A close-keyword trailer on a
215
+ develop-bound commit auto-closes the issue on push — BEFORE release/tag/publish (observed v1.1.38,
216
+ 07:49:26Z). Close keywords belong ONLY in the release-stage PR body (see release step 3.b) — auto-tag.yml
217
+ greps the PR body, not commit messages, to decide which issues to close.
214
218
  6. On success: remove in-progress, add verify-ready
215
219
  7. On failure: remove in-progress, add needs-review, comment error summary
216
220
 
@@ -299,21 +303,38 @@ steps:
299
303
  Reference: issue #1141 (v0.135.0 follow-up), mgr-gitnerd MEMORY.md.
300
304
 
301
305
  1. Version bump (mandatory):
302
- Orchestrator delegates to mgr-updater (R010). mgr-updater executes the following atomic edits:
303
- Determine NEW version per semver rules below.
306
+ Orchestrator delegates to mgr-updater (R010) for the file edits below; mgr-gitnerd (R010) for branch/commit/push.
307
+ Determine NEW version per semver rules below FIRST — before touching any file.
308
+
309
+ ⚠ Branch-before-bump (#1542, observed v1.1.38): for npm project with auto-tag.yml (this repo), the
310
+ version-bump commit MUST be created ON release/v{NEW}, and MUST NOT be pushed to develop directly.
311
+ Pushing the bump commit to develop before branching leaves develop and release/v{NEW} pointing at the
312
+ SAME commit → PR diff=0 → `gh pr create` fails with "GraphQL: No commits between develop and
313
+ release/v{NEW}". Evidence: PR #1538 (v1.1.37) and PR #1534 (v1.1.36) each contain exactly ONE commit
314
+ (the bump commit) — proof the bump belongs on the release branch, never on develop directly.
315
+
304
316
  npm project (package.json exists):
305
- a. package.json: jq '.version = "<NEW>"' package.json > package.json.tmp && mv package.json.tmp package.json
317
+ a. mgr-gitnerd: git checkout develop && git pull origin develop
318
+ (R017 Pre-Branch Freshness Gate — ensures local develop holds every merged feature commit before branching)
319
+ b. mgr-gitnerd creates release/v{NEW} branch from develop and checks it out — BEFORE any edit in c–i below.
320
+ (This is the step that used to run AFTER the bump in step 3.a of the old ordering — moving it here
321
+ is the #1542 fix. Do NOT perform steps c–i on develop.)
322
+ c. package.json: jq '.version = "<NEW>"' package.json > package.json.tmp && mv package.json.tmp package.json [on release/v{NEW}]
306
323
  # ⚠ jq '.version=...' PRESERVES the manifest structure {version, lastUpdated, omcustomMinClaudeCode, components[]}.
307
324
  # Edit ONLY the .version field — do NOT overwrite templates/manifest.json wholesale (e.g. a source-hash path→hash map).
308
325
  # Recover a corrupted manifest: git show HEAD:templates/manifest.json | jq '.version="<NEW>"' > templates/manifest.json (#1423/#1154).
309
- b. templates/manifest.json: jq '.version = "<NEW>"' templates/manifest.json > templates/manifest.json.tmp && mv templates/manifest.json.tmp templates/manifest.json
310
- c. bun run build — run standalone (NO pipe), read exit code directly ($? after a pipe is the last command's, R005/#1492).
311
- This regenerates .omcustom.lock.json (generatorVersion/templateVersion) to <NEW> via scripts/sync-source-lockfile.ts.
312
- d. git status --short — enumerate ALL tracked drift (`^ M`) the build produced; stage EVERY one (esp. .omcustom.lock.json) before commit.
313
- (#1531 — .omcustom.lock.json missed staging across 4 consecutive releases after v1.1.29; root cause was no build step between version bump and commit.)
314
- e. mgr-gitnerd commit: "chore(release): bump to v<NEW>" — MUST include the drift from step d
315
- f. mgr-gitnerd push develop
316
- g. mandatory verification (with existence guard for partial-update safety):
326
+ d. templates/manifest.json: jq '.version = "<NEW>"' templates/manifest.json > templates/manifest.json.tmp && mv templates/manifest.json.tmp templates/manifest.json [on release/v{NEW}]
327
+ e. bun run build — run standalone (NO pipe), read exit code directly ($? after a pipe is the last command's, R005/#1492).
328
+ This regenerates .omcustom.lock.json (generatorVersion/templateVersion) to <NEW> via scripts/sync-source-lockfile.ts. [on release/v{NEW}]
329
+ f. git status --short — enumerate ALL tracked drift (`^ M`) the build produced; stage EVERY one (esp. .omcustom.lock.json) before commit.
330
+ (#1531 — .omcustom.lock.json missed staging across 4 consecutive releases after v1.1.29; root cause was no build step between version bump and commit.) [on release/v{NEW}]
331
+ g. mgr-gitnerd commit: "chore(release): bump to v<NEW>" — MUST include the drift from step f.
332
+ ⚠ do NOT add Closes/Fixes/Resolves keywords to this commit message (#1542) — this commit merges into
333
+ develop later via the release PR; a close keyword here bypasses the PR-body mechanism auto-tag.yml
334
+ relies on (see step 3.b below). Use `Refs #N` if a cross-reference is needed.
335
+ h. mgr-gitnerd push release/v{NEW} to origin — NEVER push this commit to develop directly. Pushing to
336
+ develop here reproduces the diff=0 PR failure this reordering fixes (#1542).
337
+ i. mandatory verification (with existence guard for partial-update safety), run on release/v{NEW}:
317
338
  [ -f scripts/verify-version-sync.sh ] && bash scripts/verify-version-sync.sh || echo "::warning::verify-version-sync.sh not found, version sync verification skipped"
318
339
  (verify-version-sync.sh 가 exit 1 시 release 단계 halt)
319
340
 
@@ -328,9 +349,10 @@ steps:
328
349
  2. Release notes via omcustom-release-notes skill
329
350
  3. Adapt release mechanism to project (determines how steps 3-5 execute):
330
351
  - npm project with auto-tag.yml (this repo — release/v* PR pattern):
331
- a. mgr-gitnerd creates release/v{NEW} branch from develop with the version-bump commit
352
+ a. release/v{NEW} branch + version-bump commit were already created in step 1.b–1.h above — do NOT
353
+ re-create the branch or re-run the bump here; this step only opens the PR against the existing branch.
332
354
  b. mgr-gitnerd creates PR: gh pr create --base develop --head release/v{NEW} --title "chore(release): bump to v{NEW}" --body "<MUST include 'Closes #N' for EVERY issue this release resolves>"
333
- ⚠ auto-tag.yml closes issues by grep'ing Closes/Fixes/Resolves keywords in the PR BODY — NOT by milestone membership. If the keywords are missing, no issues close and the workflow still reports success (#1531).
355
+ ⚠ auto-tag.yml closes issues by grep'ing Closes/Fixes/Resolves keywords in the PR BODY — NOT by milestone membership NOR by commit message trailers. If the keywords are missing, no issues close and the workflow still reports success (#1531). Commit-message close keywords are explicitly forbidden during `implement` and step 1.g above (#1542) — the PR body is the ONLY place a close keyword should appear.
334
356
  Before creating the PR (whether via inline --body or --body-file), confirm the body text actually contains a Closes line per issue.
335
357
  c. mgr-gitnerd merges PR (admin merge required due to branch protection)
336
358
  d. DO NOT manually git tag or gh release create.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.38",
2
+ "version": "1.1.40",
3
3
  "lastUpdated": "2026-07-14T00:00:00.000Z",
4
4
  "omcustomMinClaudeCode": "2.1.121",
5
5
  "omcustomMinClaudeCodeReason": "Sensitive-path direct Write/Edit on .claude/** under bypassPermissions (R010 deprecation, #1101)",
@@ -210,7 +210,11 @@ steps:
210
210
  - Detect file types in scope and route to matching agent
211
211
  - Use specialized agents (lang-*, be-*, fe-*, infra-*) over general-purpose
212
212
  4. TDD via superpowers:test-driven-development when tests apply
213
- 5. Commit via mgr-gitnerd with `Fixes #<N>` trailer in body
213
+ 5. Commit via mgr-gitnerd with `Refs #<N>` trailer in body — NEVER `Fixes`/`Closes`/`Resolves` (#1542).
214
+ ⚠ implement-stage commits land directly on develop (no PR gate here). A close-keyword trailer on a
215
+ develop-bound commit auto-closes the issue on push — BEFORE release/tag/publish (observed v1.1.38,
216
+ 07:49:26Z). Close keywords belong ONLY in the release-stage PR body (see release step 3.b) — auto-tag.yml
217
+ greps the PR body, not commit messages, to decide which issues to close.
214
218
  6. On success: remove in-progress, add verify-ready
215
219
  7. On failure: remove in-progress, add needs-review, comment error summary
216
220
 
@@ -299,21 +303,38 @@ steps:
299
303
  Reference: issue #1141 (v0.135.0 follow-up), mgr-gitnerd MEMORY.md.
300
304
 
301
305
  1. Version bump (mandatory):
302
- Orchestrator delegates to mgr-updater (R010). mgr-updater executes the following atomic edits:
303
- Determine NEW version per semver rules below.
306
+ Orchestrator delegates to mgr-updater (R010) for the file edits below; mgr-gitnerd (R010) for branch/commit/push.
307
+ Determine NEW version per semver rules below FIRST — before touching any file.
308
+
309
+ ⚠ Branch-before-bump (#1542, observed v1.1.38): for npm project with auto-tag.yml (this repo), the
310
+ version-bump commit MUST be created ON release/v{NEW}, and MUST NOT be pushed to develop directly.
311
+ Pushing the bump commit to develop before branching leaves develop and release/v{NEW} pointing at the
312
+ SAME commit → PR diff=0 → `gh pr create` fails with "GraphQL: No commits between develop and
313
+ release/v{NEW}". Evidence: PR #1538 (v1.1.37) and PR #1534 (v1.1.36) each contain exactly ONE commit
314
+ (the bump commit) — proof the bump belongs on the release branch, never on develop directly.
315
+
304
316
  npm project (package.json exists):
305
- a. package.json: jq '.version = "<NEW>"' package.json > package.json.tmp && mv package.json.tmp package.json
317
+ a. mgr-gitnerd: git checkout develop && git pull origin develop
318
+ (R017 Pre-Branch Freshness Gate — ensures local develop holds every merged feature commit before branching)
319
+ b. mgr-gitnerd creates release/v{NEW} branch from develop and checks it out — BEFORE any edit in c–i below.
320
+ (This is the step that used to run AFTER the bump in step 3.a of the old ordering — moving it here
321
+ is the #1542 fix. Do NOT perform steps c–i on develop.)
322
+ c. package.json: jq '.version = "<NEW>"' package.json > package.json.tmp && mv package.json.tmp package.json [on release/v{NEW}]
306
323
  # ⚠ jq '.version=...' PRESERVES the manifest structure {version, lastUpdated, omcustomMinClaudeCode, components[]}.
307
324
  # Edit ONLY the .version field — do NOT overwrite templates/manifest.json wholesale (e.g. a source-hash path→hash map).
308
325
  # Recover a corrupted manifest: git show HEAD:templates/manifest.json | jq '.version="<NEW>"' > templates/manifest.json (#1423/#1154).
309
- b. templates/manifest.json: jq '.version = "<NEW>"' templates/manifest.json > templates/manifest.json.tmp && mv templates/manifest.json.tmp templates/manifest.json
310
- c. bun run build — run standalone (NO pipe), read exit code directly ($? after a pipe is the last command's, R005/#1492).
311
- This regenerates .omcustom.lock.json (generatorVersion/templateVersion) to <NEW> via scripts/sync-source-lockfile.ts.
312
- d. git status --short — enumerate ALL tracked drift (`^ M`) the build produced; stage EVERY one (esp. .omcustom.lock.json) before commit.
313
- (#1531 — .omcustom.lock.json missed staging across 4 consecutive releases after v1.1.29; root cause was no build step between version bump and commit.)
314
- e. mgr-gitnerd commit: "chore(release): bump to v<NEW>" — MUST include the drift from step d
315
- f. mgr-gitnerd push develop
316
- g. mandatory verification (with existence guard for partial-update safety):
326
+ d. templates/manifest.json: jq '.version = "<NEW>"' templates/manifest.json > templates/manifest.json.tmp && mv templates/manifest.json.tmp templates/manifest.json [on release/v{NEW}]
327
+ e. bun run build — run standalone (NO pipe), read exit code directly ($? after a pipe is the last command's, R005/#1492).
328
+ This regenerates .omcustom.lock.json (generatorVersion/templateVersion) to <NEW> via scripts/sync-source-lockfile.ts. [on release/v{NEW}]
329
+ f. git status --short — enumerate ALL tracked drift (`^ M`) the build produced; stage EVERY one (esp. .omcustom.lock.json) before commit.
330
+ (#1531 — .omcustom.lock.json missed staging across 4 consecutive releases after v1.1.29; root cause was no build step between version bump and commit.) [on release/v{NEW}]
331
+ g. mgr-gitnerd commit: "chore(release): bump to v<NEW>" — MUST include the drift from step f.
332
+ ⚠ do NOT add Closes/Fixes/Resolves keywords to this commit message (#1542) — this commit merges into
333
+ develop later via the release PR; a close keyword here bypasses the PR-body mechanism auto-tag.yml
334
+ relies on (see step 3.b below). Use `Refs #N` if a cross-reference is needed.
335
+ h. mgr-gitnerd push release/v{NEW} to origin — NEVER push this commit to develop directly. Pushing to
336
+ develop here reproduces the diff=0 PR failure this reordering fixes (#1542).
337
+ i. mandatory verification (with existence guard for partial-update safety), run on release/v{NEW}:
317
338
  [ -f scripts/verify-version-sync.sh ] && bash scripts/verify-version-sync.sh || echo "::warning::verify-version-sync.sh not found, version sync verification skipped"
318
339
  (verify-version-sync.sh 가 exit 1 시 release 단계 halt)
319
340
 
@@ -328,9 +349,10 @@ steps:
328
349
  2. Release notes via omcustom-release-notes skill
329
350
  3. Adapt release mechanism to project (determines how steps 3-5 execute):
330
351
  - npm project with auto-tag.yml (this repo — release/v* PR pattern):
331
- a. mgr-gitnerd creates release/v{NEW} branch from develop with the version-bump commit
352
+ a. release/v{NEW} branch + version-bump commit were already created in step 1.b–1.h above — do NOT
353
+ re-create the branch or re-run the bump here; this step only opens the PR against the existing branch.
332
354
  b. mgr-gitnerd creates PR: gh pr create --base develop --head release/v{NEW} --title "chore(release): bump to v{NEW}" --body "<MUST include 'Closes #N' for EVERY issue this release resolves>"
333
- ⚠ auto-tag.yml closes issues by grep'ing Closes/Fixes/Resolves keywords in the PR BODY — NOT by milestone membership. If the keywords are missing, no issues close and the workflow still reports success (#1531).
355
+ ⚠ auto-tag.yml closes issues by grep'ing Closes/Fixes/Resolves keywords in the PR BODY — NOT by milestone membership NOR by commit message trailers. If the keywords are missing, no issues close and the workflow still reports success (#1531). Commit-message close keywords are explicitly forbidden during `implement` and step 1.g above (#1542) — the PR body is the ONLY place a close keyword should appear.
334
356
  Before creating the PR (whether via inline --body or --body-file), confirm the body text actually contains a Closes line per issue.
335
357
  c. mgr-gitnerd merges PR (admin merge required due to branch protection)
336
358
  d. DO NOT manually git tag or gh release create.