oh-my-customcode 1.1.47 → 1.1.48
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 +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/templates/.claude/rules/MAY-optimization.md +2 -0
- package/templates/.claude/rules/MUST-completion-verification.md +8 -2
- package/templates/.claude/rules/MUST-intent-transparency.md +7 -2
- package/templates/.claude/rules/MUST-orchestrator-coordination.md +11 -5
- package/templates/.claude/rules/MUST-sync-verification.md +5 -2
- package/templates/.claude/skills/pipeline/workflows/auto-dev.yaml +26 -3
- package/templates/.github/workflows/wiki-sync.yml +1 -1
- package/templates/manifest.json +1 -1
- package/templates/workflows/auto-dev.yaml +26 -3
package/dist/cli/index.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
|
|
29
29
|
> **계수/매칭 방법 확인 (#1521)**: 카운트를 대조하기 전에 **비교 대상이 무엇을 어떻게 세는지** 먼저 확인한다 — 같은 지표라도 계수 방법이 다르면 값이 달라진다. 대표 함정 4종: (a) glob(`ls *.md`, 최상위만) vs 재귀 `find`(하위 디렉토리 포함), (b) 부분 문자열 grep(`grep "sdd"`가 `sdd-dev`까지 매칭), (c) 확장자 필터(`--include='*.md'`가 `CLAUDE.md.en`을 미매칭), (d) **머지 커밋 diff 기본 생략** — `git show --name-only <머지커밋>`은 diff를 기본적으로 출력하지 않아 변경 파일 0개로 오독된다. 머지 커밋의 변경 파일을 세려면 `--first-parent`(1차 부모 대비) 또는 `-m`(각 부모별 diff)을 명시한다. 검증 스크립트와 대조할 때는 **스크립트의 실제 계수 로직을 읽고** 같은 방법으로 센다. 위 `ls | tail` 시계열 오판(#1417)과 동류로, 도구의 기본 동작을 확인하지 않은 채 결과를 해석해 오탐에 이르는 패턴이다. Origin: #1521 (2026-07-20 세션에서 3회 반복; 두 서브에이전트가 독립적으로 동일 오탐에 도달); (d)는 #1553 찐빠 #4 (2026-07-30 세션에서 머지 커밋 `--name-only` 0파일을 "변경 없음"으로 오독).
|
|
30
30
|
|
|
31
|
+
> **도구 이름 ≠ 그 프로그램 (#1590)**: 도구를 쓰기 전에 `type <tool>`로 실체를 확인한다. Bash 도구의 `grep`은 `~/.claude/shell-snapshots/snapshot-zsh-*.sh`의 **셸 함수**이며 `ugrep --ignore-files`에 위임한다. 그 결과 `.gitignore`의 리터럴 `CLAUDE.md` 패턴을 존중해, **force-tracked 파일을 재귀 탐색에서 조용히 누락**한다(에러 없이 exit 0). 명시 경로를 준 grep은 정상 동작하므로 **traversal만 영향**을 받는다. 실측(2026-08-15): 동일 패턴·동일 대상에 대해 셸 함수 36 / `command grep` 43 / `git grep` 38 히트 — 셸 함수만 `CLAUDE.md`를 0 히트로 놓쳤다. 진단 함정: `git check-ignore`는 **index-aware**라 tracked 파일에 "not ignored"(exit 1)를 반환한다 — 원인을 보려면 `git check-ignore --no-index`를 써야 한다. 처방: 저장소 전수 조사는 `git grep`을 표준으로 한다(R017 Count Sync cross-ref). Origin: #1590.
|
|
32
|
+
|
|
31
33
|
<!--
|
|
32
34
|
> **v2.1.206+**: `/doctor`에 checked-in CLAUDE.md에서 코드베이스로부터 파생 가능한 내용을 잘라내도록 제안하는 체크가 추가되었습니다 — R005 "Context Optimization via HTML Comments"의 컨텍스트 절감 원칙과 정합(모델 불필요 메타데이터 축소).
|
|
33
35
|
-->
|
|
@@ -280,15 +280,21 @@ Origin: #1266 ④.
|
|
|
280
280
|
위 파싱 레시피는 **"사용자 프롬프트 = 턴 경계"**를 암묵 전제한다. `/fsd` 같은 자율 루프는 사용자 프롬프트가 거의 없어(실측: 사용자 프롬프트 4개 대 assistant 응답 30여 회) 이 전제로는 경계 재구성이 실패하고, 계수 자체가 성립하지 않는다. 자율 루프 transcript를 셀 때는 **두 단계를 순서대로** 수행하고, 완료 전에는 **위반 횟수를 단정하지 않는다**.
|
|
281
281
|
|
|
282
282
|
1. **전처리 — `.message.role`이 존재하는 라인만 필터링**한다. 트랜스크립트에는 role 없는 라인(메타·이벤트·요약)이 assistant/user 사이에 대량으로 끼어 있어, 필터 없이는 **인접성 판정 자체가 깨진다**. 2단계의 어떤 경계 정의도 이 필터 없이는 성립하지 않는다.
|
|
283
|
-
2.
|
|
283
|
+
2. **경계 정의(규범)** — 응답 시작 경계는 **`content`에 `tool_result` 블록을 포함하지 않는 user 메시지**로 정의한다. 도구 결과도 `role: user`로 기록되므로, "user→assistant 전이 = 응답 시작"이라는 단순 정의는 도구 결과 뒤에 이어지는 assistant 메시지를 전부 새 응답으로 오인해 **위반 건수를 대폭 과대 계상**한다. 실증: 이 정의를 쓰지 않고 파싱했을 때 R007 위반이 177건으로 나왔으나, 위 규범대로 경계를 고치자 1건이 됐다(177배 과대). R008도 44 → 33으로 정정됐다.
|
|
284
|
+
|
|
285
|
+
### 자가 계수는 advisor 판정식을 재현한다
|
|
286
|
+
|
|
287
|
+
자체 해석 패턴으로 위반을 세지 말고, `.claude/hooks/scripts/r007-r008-drift-advisor.sh`의 판정식을 **1:1 재현**한다. 실증: 자체 announce 패턴을 advisor보다 좁게 잡아(번호 매긴 병렬 스폰 라인 `[N] agent:model → desc` 형식을 announce로 미포함) R008 위반을 과대 계상했다 — advisor 스크립트 자체를 참조하지 않고 "그럴듯한 정의"로 재구현하면 같은 종류의 오차가 반복된다.
|
|
284
288
|
|
|
285
289
|
| Anti-pattern | Required |
|
|
286
290
|
|--------------|----------|
|
|
287
291
|
| 자율 루프 transcript를 사용자 프롬프트 경계로 파싱해 위반 N회로 단정 | 1단계 필터 + 2단계 경계 정의를 먼저 확정; 확정 전에는 횟수 단정 금지 |
|
|
288
292
|
| 필터 없이 원본 라인 순서로 인접성을 판정 → 계수 실패를 경계 정의 탓으로 오진 | `.message.role` 필터를 먼저 적용한 뒤 경계 정의를 평가 |
|
|
289
293
|
| 경계 재구성 실패를 "위반 없음"으로 해석 | 경계 무관 지표로 대체 보고 — `┌─ Agent:` 헤더 총량, tool_use 대 announce 라인 비율 |
|
|
294
|
+
| "user→assistant 전이"를 응답 시작 경계로 단순 정의 → `tool_result`(role=user) 뒤 assistant 응답을 전부 새 응답으로 오산입 | 경계 = `tool_result` 블록을 포함하지 않는 user 메시지 (규범) |
|
|
295
|
+
| 자체 해석 패턴(예: 좁게 잡은 announce 정규식)으로 위반을 재계산 | `r007-r008-drift-advisor.sh`의 판정식을 그대로 재현 |
|
|
290
296
|
|
|
291
|
-
Origin: #1574 (v1.1.44 세션 — 자율 루프에서 R007 헤더 누락 계수를 시도했으나 사용자 프롬프트 4개로 턴 경계 재구성 불가); 1단계 필터는 #1584 #3 (v1.1.45 세션 — 위 조항을 신설했음에도 계수가 재실패. 실제 장애물은 경계 정의가 아니라 **`role=null` 라인 661개 / 전체 1215줄의 54%**였고, 필터 추가 즉시 성립(응답 시작 50, R007 위반 0) — 조항이 원인을 절반만 짚어 재발한 사례). Cross-ref: R005(계수/매칭 방법 확인 — 도구 기본 동작 미확인 시 결과 오해석).
|
|
297
|
+
Origin: #1574 (v1.1.44 세션 — 자율 루프에서 R007 헤더 누락 계수를 시도했으나 사용자 프롬프트 4개로 턴 경계 재구성 불가); 1단계 필터는 #1584 #3 (v1.1.45 세션 — 위 조항을 신설했음에도 계수가 재실패. 실제 장애물은 경계 정의가 아니라 **`role=null` 라인 661개 / 전체 1215줄의 54%**였고, 필터 추가 즉시 성립(응답 시작 50, R007 위반 0) — 조항이 원인을 절반만 짚어 재발한 사례). 경계 규범 승격 및 advisor 판정식 재현은 #1593 #6 (경계 오정의로 R007 177배 과대 계상, `tool_result` 배제 정의로 정정; R008은 좁은 announce 패턴 자가 재구현으로 44→33 정정). Cross-ref: R005(계수/매칭 방법 확인 — 도구 기본 동작 미확인 시 결과 오해석).
|
|
292
298
|
|
|
293
299
|
### Proxy Signal vs Canonical Ground-Truth (#1336 ①②)
|
|
294
300
|
|
|
@@ -114,13 +114,18 @@ The Git Push Continuation pattern (first-time strict / follow-up relaxed, scoped
|
|
|
114
114
|
| 1st explicit approval (category C, target T) | Proceed; advisory warning emitted |
|
|
115
115
|
| Follow-up same session (same C + same T) | No re-confirmation (directive persistence) |
|
|
116
116
|
| Different category or target | Fresh confirmation required |
|
|
117
|
-
| Platform
|
|
117
|
+
| Platform **permission prompt** repeats (asking to re-approve an already-allowed command) | Add a `settings.json` permission `allow` rule scoped to the specific command — this suppresses the prompt |
|
|
118
|
+
| Platform **safety classifier BLOCK** (e.g. auto-mode refuses/flags the action, not merely prompting) | `allow` rule addition is **NOT effective** — the classifier is a separate layer from the permission-prompt layer. Have the user run the command directly (`!` prefix), or remove the trigger itself (e.g. drop an unnecessary bypass flag — see R010 「우회 플래그는 우회 대상과 근거를 명시」) |
|
|
118
119
|
|
|
119
120
|
**R001 exclusion (MUST)**: R001-listed catastrophic git operations (`git reset --hard`, `git clean -fd`, `git push --force` to shared branches, `git branch -D` with unmerged commits) are EXCLUDED from this persistence rule — they always require explicit per-invocation approval regardless of prior session approvals.
|
|
120
121
|
|
|
121
122
|
**Boundary / honesty note**: This rule is ADVISORY and governs model behavior only. It CANNOT suppress Claude Code's platform-level auto-mode classifier prompts. For genuine prompt suppression on a repeated destructive command, the user must add a `settings.json` permission allow rule scoped to the specific command (e.g., a specific `supabase db push` invocation). The model SHOULD surface this workaround when the user expresses friction about repeated prompts.
|
|
122
123
|
|
|
123
|
-
|
|
124
|
+
`settings.json` **allow 규칙은 permission prompt를 억제하지만, safety classifier 차단은 억제하지 못한다 — 서로 다른 층이다** (#1592). 실효 경로는 두 가지뿐이다: (a) 사용자가 직접 실행, (b) 차단 트리거 자체를 제거(예: 불필요한 `--admin` 제거). 부가로, CC v2.1.229+는 위험 플래그(`--force`/`--amend`/`--no-verify`)를 가진 git/gh 명령을 auto-approve하지 않는다(설치 버전 실측 v2.1.233).
|
|
125
|
+
|
|
126
|
+
> Origin: #1592 (v1.1.47 세션 실측) — `permissions.allow`에 `Bash(gh:*)`와 `defaultMode: bypassPermissions`가 있는데도 `--admin` 포함 머지 위임이 auto-mode classifier에 차단됐다. `Edit(.claude/**)` allow 규칙이 있는데도 `.claude/settings.local.json` 편집이 차단됐다. 두 사례 모두 allow 규칙이 걸어둔 permission-prompt 층을 이미 통과한 상태에서 별도의 classifier 층이 차단한 것 — allow 규칙 추가로는 해소되지 않았고, 실효 해법은 (a) `--admin` 제거(R010 선행 실측 조항, #1591), (b) 사용자 직접 실행이었다.
|
|
127
|
+
|
|
128
|
+
Cross-references: R001 (safety — destructive operation pre-checks still apply), R002 (permission tiers), R010 (우회 플래그 선행 실측 — 차단 트리거 제거 경로). Reference issues: #1230, #1226 (item 2), #1592.
|
|
124
129
|
|
|
125
130
|
## User-Provided Input Precedence
|
|
126
131
|
|
|
@@ -282,17 +282,21 @@ The Subagent Scope-Creep STOP Protocol (above) is REACTIVE — it halts an agent
|
|
|
282
282
|
|
|
283
283
|
Cross-reference: the Subagent Scope-Creep STOP Protocol (reactive halt after trips) and R001 (credential/privileged-scope guardrails, re-confirm scope before irreversible shared-infra actions).
|
|
284
284
|
|
|
285
|
-
#### 우회 플래그는 우회 대상과 근거를 명시 (Origin: #1584 #6)
|
|
285
|
+
#### 우회 플래그는 우회 대상과 근거를 명시 (Origin: #1584 #6, #1591)
|
|
286
286
|
|
|
287
|
-
|
|
287
|
+
**선행 실측 (신설, #1591)**: 우회 플래그(`--admin`, `--force`, `--no-verify` 등)를 위임 프롬프트에 지시하기 **전에**, 그 플래그가 실제로 필요한지 먼저 실측한다(`gh api repos/{owner}/{repo}/branches/{branch}/protection`). 불필요하면 정답은 **서술 보강이 아니라 플래그 제거**다 — 근거 서술은 플래그가 실제로 필요할 때에만 의미가 있다.
|
|
288
|
+
|
|
289
|
+
보호장치를 우회하는 플래그를 위임 프롬프트에 지시할 때는 **무엇을 우회하는지와 그것이 정당한 근거**를 함께 적는다. 플래그만 적으면 하니스·에이전트가 무권한 우회로 판정해 플래그하거나 거부한다.
|
|
288
290
|
|
|
289
291
|
| Anti-pattern | Required |
|
|
290
292
|
|--------------|----------|
|
|
291
|
-
| `
|
|
293
|
+
| 우회 플래그(`--admin` 등)만 지시하고 근거 없음 | 실측 branch protection과 대조 후, 플래그가 실제로 필요할 때만 우회 대상·근거를 명시 — 예: "required status check 6종 전부 pass 확인함. `enforce_admins=false`이므로 `--admin`이 우회하는 것은 **그 6종 CI 게이트**뿐이며, [사유]로 이를 승인한다" |
|
|
292
294
|
|
|
293
295
|
목적은 권한 확보가 아니라 **감사 추적**이다. 승인의 인용이 아니라 우회 범위의 사실 서술이므로 아래 「Delegation Prompt Framing — 승인 인용 금지」와 충돌하지 않는다.
|
|
294
296
|
|
|
295
|
-
|
|
297
|
+
**실측 기록 (2026-08-15, `gh api repos/{owner}/{repo}/branches/develop/protection`)**: required status checks **6종** — `Test`, `Lint`, `Template Sync`, `Version Sync`, `Dependency Security Audit`, `Rust Tests` (`strict=true`). **`enforce_admins=false`**. **`required_pull_request_reviews` 부재** — 리뷰어 승인 요건 자체가 없다. 다음 릴리즈가 재확인하지 않도록 이 값을 여기 고정 기록한다.
|
|
298
|
+
|
|
299
|
+
Origin: #1584 #6 — v1.1.45·v1.1.46 릴리즈 PR 머지에서 하니스가 "no visible user authorization naming that bypass"로 플래그했다. #1591 (v1.1.47 세션 실측) — v1.1.47이 신설한 위 표의 예시가 사실과 달랐다: "required status check **10종**"은 실제 **6종**이었고, "`--admin`이 우회하는 것은 **리뷰어 승인 요건**뿐"은 틀렸다 — 리뷰어 승인 요건 자체가 존재하지 않고 `enforce_admins=false`이므로 `--admin`이 실제로 우회하는 것은 **CI 게이트 6종**이었다. 기존 예시는 더 위험한 우회를 무해한 것처럼 서술하고 있었다. 근본 원인 진단 결과 develop 브랜치에는 `--admin`이 애초에 불필요했다 — 실측 없이 확정형 근거를 적으면 우회 범위 자체를 오판할 수 있다는 사례.
|
|
296
300
|
|
|
297
301
|
<!-- ARCHIVED CC version note (historical):
|
|
298
302
|
> **v2.1.178+**: Auto mode now evaluates subagent spawns with the safety classifier BEFORE launch, closing a gap where a spawned subagent could request a blocked action without prior review. This is the PLATFORM-level complement to the (advisory) Pre-Delegation Privileged-Scope Boundary above: the orchestrator still states the approved/forbidden scope in the delegation prompt (proactive, model-level), and CC now also gates the spawn itself (platform-level). The two are defense-in-depth — the prompt-stated boundary remains required because the classifier gates ACTIONS, not task SCOPE.
|
|
@@ -449,6 +453,8 @@ Before spawning any agent:
|
|
|
449
453
|
|
|
450
454
|
Before delegating a task to a subagent, MUST verify the target agent's tool capabilities against the task requirements. Failure to pre-check causes round-trip waste (delegation → failure → re-delegation).
|
|
451
455
|
|
|
456
|
+
> **표 조회 배선 (MUST, #1593 #1)**: 위임 프롬프트를 작성하기 **전에** 아래 "Known Limitations (Active Cache)" 표에서 대상 에이전트 이름을 조회한다. 표에 항목이 있으면 그 제약에 걸리는 완료 조건 항목을 제거하거나 대체 경로를 지정한다. **표가 존재해도 참조되지 않으면 무효**다 — R016 Rule Wiring Check의 "텍스트 ≠ 배선" 원칙이 위임 습관에도 그대로 적용된다.
|
|
457
|
+
|
|
452
458
|
### Required Checks
|
|
453
459
|
|
|
454
460
|
| Task involves | Verify in target agent frontmatter |
|
|
@@ -481,7 +487,7 @@ Before delegating a task to a subagent, MUST verify the target agent's tool capa
|
|
|
481
487
|
|
|
482
488
|
| Agent | Limitation | Workaround |
|
|
483
489
|
|-------|-----------|-----------|
|
|
484
|
-
| `arch-documenter` | `disallowedTools: [Bash]` — cannot run `gh`, shell scripts | Pre-collect data via orchestrator, pass as content; OR use `general-purpose` for the Bash-needing portion |
|
|
490
|
+
| `arch-documenter` | `disallowedTools: [Bash]` — cannot run `gh`, shell scripts, `diff`/`md5`/`verify-*.sh` | Pre-collect data via orchestrator, pass as content; OR use `general-purpose` for the Bash-needing portion. **Completion-condition guard (#1593 #1)**: do NOT put `diff` / `md5` / `verify-*.sh` execution into arch-documenter's completion criteria — the orchestrator must run these itself, or split off a `general-purpose` agent for the Bash-needing verification |
|
|
485
491
|
| `qa-engineer` | (verify each invocation) | — |
|
|
486
492
|
|
|
487
493
|
### Common Violation
|
|
@@ -97,7 +97,7 @@ Origin: #1512 (v1.1.28 커밋 staging에 dist/ 2파일 포함, 커밋 전 실측
|
|
|
97
97
|
|
|
98
98
|
카운트(스킬/에이전트/룰/가이드 수) 동기화는 **파일 목록 열거가 아니라 저장소 전수 grep + 의미 판별**로 수행한다. 같은 카운트가 15곳 이상에 흩어져 있어 열거식 위임은 목록에서 빠진 곳을 구조적으로 놓친다.
|
|
99
99
|
|
|
100
|
-
절차: (a) 실제 개수 실측(`ls -1d .claude/skills/*/ | wc -l` 등) → (b) 이전 값을 저장소 전역 grep → (c) 각 히트가 **카운트를 의미하는지 판별** → (d) 카운트 의미인 것만 정정.
|
|
100
|
+
절차: (a) 실제 개수 실측(`ls -1d .claude/skills/*/ | wc -l` 등) → (b) 이전 값을 저장소 전역 `git grep -n`으로 조사 → (c) 각 히트가 **카운트를 의미하는지 판별** → (d) 카운트 의미인 것만 정정.
|
|
101
101
|
|
|
102
102
|
무관한 숫자는 건드리지 않는다 — 버전번호(`v0.118.x`, CC `v2.1.118`), 이슈 번호, 과거 이력 서술("skill-count correction 114→118"), 스크립트 예시 주석은 정정 대상이 아니며 판단 근거와 함께 보고한다. grep 필터 주의: `--include='*.md'`는 `CLAUDE.md.en`/`CLAUDE.md.ko` 같은 **이중 확장자 파일을 매칭하지 못하므로**, 확장자 필터 없이 훑거나 별도 패턴을 병행한다.
|
|
103
103
|
|
|
@@ -105,10 +105,13 @@ Origin: #1512 (v1.1.28 커밋 staging에 dist/ 2파일 포함, 커밋 전 실측
|
|
|
105
105
|
|--------------|----------|
|
|
106
106
|
| 카운트 동기화를 "갱신할 파일 목록" 열거로 위임 | 전수 grep으로 이전 값 히트를 모두 수집한 뒤 카운트 의미만 정정 |
|
|
107
107
|
| `--include='*.md'` 필터로 전수 grep 수행 | 확장자 필터 없이 훑거나 이중 확장자 패턴 병행 |
|
|
108
|
+
| 셸의 `grep -rn`으로 전수 조사 | `git grep -n` 사용 — tracked 기준이라 릴리즈 대상과 일치하고 셸 함수/alias 셰이딩에 면역 (#1590) |
|
|
108
109
|
|
|
109
110
|
위임 프롬프트에는 항상 **"실측값 기준으로 동기화하라, 추측으로 숫자를 바꾸지 말라"**를 명시해, 오케스트레이터의 잘못된 전제를 서브에이전트가 정정할 여지를 남긴다(#1443).
|
|
110
111
|
|
|
111
|
-
|
|
112
|
+
`git grep`은 **untracked 파일을 보지 못한다** — 조사 전 `git status --porcelain`으로 untracked 0을 확인하거나, untracked 가능성이 있으면 `command grep`을 병행한다.
|
|
113
|
+
|
|
114
|
+
Origin: #1521 (찐빠 #2 — v1.1.32 skills 118→114 동기화에서 파일 열거식 위임이 6곳만 갱신, CI 3곳 지적 + 전수 grep 9곳 추가 발견, 최종 15곳); #1590 (셸 `grep`이 shell function으로 shadow되어 tracked 파일을 재귀 탐색에서 누락 — `git grep` 표준화). Cross-ref: #1443 (실측값 기준 명시), #1287 (multi-copy 일관성).
|
|
112
115
|
|
|
113
116
|
## When Required
|
|
114
117
|
|
|
@@ -398,8 +398,18 @@ steps:
|
|
|
398
398
|
# Edit ONLY the .version field — do NOT overwrite templates/manifest.json wholesale (e.g. a source-hash path→hash map).
|
|
399
399
|
# Recover a corrupted manifest: git show HEAD:templates/manifest.json | jq '.version="<NEW>"' > templates/manifest.json (#1423/#1154).
|
|
400
400
|
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}]
|
|
401
|
-
e.
|
|
402
|
-
|
|
401
|
+
e. ⚠ PREREQUISITE: steps c (package.json) AND d (templates/manifest.json) MUST BOTH be completed
|
|
402
|
+
before running this step. bun run build — run standalone (NO pipe), read exit code directly
|
|
403
|
+
($? after a pipe is the last command's, R005/#1492).
|
|
404
|
+
Actual mechanism (corrected, #1593): `bun run build` invokes `scripts/sync-source-lockfile.ts`
|
|
405
|
+
(a 10-line wrapper with no version literals of its own), which calls
|
|
406
|
+
`generateAndWriteLockfileForDir` (`src/core/lockfile.ts`). That function reads versions via
|
|
407
|
+
`loadVersions()` (`src/core/sync.ts`) — `generatorVersion` FROM package.json, `templateVersion`
|
|
408
|
+
FROM templates/manifest.json — and writes both into .omcustom.lock.json. If step d has not yet
|
|
409
|
+
landed when this runs, the lockfile silently records the PREVIOUS templateVersion — no warning,
|
|
410
|
+
no error. Observed contamination: v1.1.47 shipped generatorVersion=1.1.47 / templateVersion=1.1.46
|
|
411
|
+
because the bump commit created package.json + lockfile together and manifest.json was bumped in
|
|
412
|
+
a later commit. Do NOT run this step until BOTH c and d are staged. [on release/v{NEW}]
|
|
403
413
|
f. git status --short — enumerate ALL tracked drift (`^ M`) the build produced; stage EVERY one (esp. .omcustom.lock.json) before commit.
|
|
404
414
|
(#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}]
|
|
405
415
|
g. mgr-gitnerd commit: "chore(release): bump to v<NEW>" — MUST include the drift from step f.
|
|
@@ -411,6 +421,11 @@ steps:
|
|
|
411
421
|
i. mandatory verification (with existence guard for partial-update safety), run on release/v{NEW}:
|
|
412
422
|
[ -f scripts/verify-version-sync.sh ] && bash scripts/verify-version-sync.sh || echo "::warning::verify-version-sync.sh not found, version sync verification skipped"
|
|
413
423
|
(verify-version-sync.sh 가 exit 1 시 release 단계 halt)
|
|
424
|
+
j. lockfile 3-way assertion (#1593 제안3, closes the gap step i's 2-way check misses) — run standalone
|
|
425
|
+
(NO pipe), read exit code directly, on release/v{NEW}:
|
|
426
|
+
jq -e --arg v "<NEW>" '.generatorVersion==$v and .templateVersion==$v' .omcustom.lock.json
|
|
427
|
+
실패 시 release 단계 halt — cause is almost always step e run before step d landed; fix by
|
|
428
|
+
re-running step d then step e, re-staging, and re-running this assertion.
|
|
414
429
|
|
|
415
430
|
Version decision (semver) — PATCH-PREFERRED policy (post-1.0.0):
|
|
416
431
|
- No existing tags → v0.1.0
|
|
@@ -428,7 +443,15 @@ steps:
|
|
|
428
443
|
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>"
|
|
429
444
|
⚠ 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.
|
|
430
445
|
Before creating the PR (whether via inline --body or --body-file), confirm the body text actually contains a Closes line per issue.
|
|
431
|
-
c. mgr-gitnerd merges PR
|
|
446
|
+
c. mgr-gitnerd merges PR: gh pr merge {n} --merge --delete-branch (plain merge — NOT --admin).
|
|
447
|
+
Ground-truth (measured 2026-08-15, `gh api repos/{owner}/{repo}/branches/develop/protection`):
|
|
448
|
+
required status checks are exactly 6 — Test, Lint, Template Sync, Version Sync,
|
|
449
|
+
Dependency Security Audit, Rust Tests (strict=true); enforce_admins=false; NO
|
|
450
|
+
required_pull_request_reviews (no reviewer-approval requirement exists). v1.1.47 merged with a
|
|
451
|
+
plain `gh pr merge 1585 --merge --delete-branch` — no --admin needed. A plain merge succeeds
|
|
452
|
+
once all 6 checks report green. If the merge is rejected, do NOT reflexively add --admin —
|
|
453
|
+
re-run the protection query above to re-measure current requirements and report the actual
|
|
454
|
+
blocker (R010 bypass-flag pre-check: name what is bypassed and why before ever using --admin).
|
|
432
455
|
d. DO NOT manually git tag or gh release create.
|
|
433
456
|
auto-tag.yml fires on release/v* PR merge → creates tag → closes issues linked via PR-body Closes/Fixes/Resolves keywords → closes milestone → deletes release branch.
|
|
434
457
|
release.yml fires on the tag → npm publish + GitHub Release creation.
|
|
@@ -127,6 +127,6 @@ jobs:
|
|
|
127
127
|
TOTAL_GUIDES=$(find guides -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l | tr -d ' ')
|
|
128
128
|
TOTAL_WIKI=$(find wiki -name "*.md" ! -name "index.md" ! -name "log.md" 2>/dev/null | wc -l | tr -d ' ')
|
|
129
129
|
|
|
130
|
-
echo "Source entities: agents=$TOTAL_AGENTS skills=$TOTAL_SKILLS rules=$TOTAL_RULES
|
|
130
|
+
echo "Source entities: agents=$TOTAL_AGENTS skills=$TOTAL_SKILLS rules=$TOTAL_RULES guide_topics=$TOTAL_GUIDES"
|
|
131
131
|
echo "Wiki pages: $TOTAL_WIKI"
|
|
132
132
|
echo "All wiki pages present — sync OK"
|
package/templates/manifest.json
CHANGED
|
@@ -398,8 +398,18 @@ steps:
|
|
|
398
398
|
# Edit ONLY the .version field — do NOT overwrite templates/manifest.json wholesale (e.g. a source-hash path→hash map).
|
|
399
399
|
# Recover a corrupted manifest: git show HEAD:templates/manifest.json | jq '.version="<NEW>"' > templates/manifest.json (#1423/#1154).
|
|
400
400
|
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}]
|
|
401
|
-
e.
|
|
402
|
-
|
|
401
|
+
e. ⚠ PREREQUISITE: steps c (package.json) AND d (templates/manifest.json) MUST BOTH be completed
|
|
402
|
+
before running this step. bun run build — run standalone (NO pipe), read exit code directly
|
|
403
|
+
($? after a pipe is the last command's, R005/#1492).
|
|
404
|
+
Actual mechanism (corrected, #1593): `bun run build` invokes `scripts/sync-source-lockfile.ts`
|
|
405
|
+
(a 10-line wrapper with no version literals of its own), which calls
|
|
406
|
+
`generateAndWriteLockfileForDir` (`src/core/lockfile.ts`). That function reads versions via
|
|
407
|
+
`loadVersions()` (`src/core/sync.ts`) — `generatorVersion` FROM package.json, `templateVersion`
|
|
408
|
+
FROM templates/manifest.json — and writes both into .omcustom.lock.json. If step d has not yet
|
|
409
|
+
landed when this runs, the lockfile silently records the PREVIOUS templateVersion — no warning,
|
|
410
|
+
no error. Observed contamination: v1.1.47 shipped generatorVersion=1.1.47 / templateVersion=1.1.46
|
|
411
|
+
because the bump commit created package.json + lockfile together and manifest.json was bumped in
|
|
412
|
+
a later commit. Do NOT run this step until BOTH c and d are staged. [on release/v{NEW}]
|
|
403
413
|
f. git status --short — enumerate ALL tracked drift (`^ M`) the build produced; stage EVERY one (esp. .omcustom.lock.json) before commit.
|
|
404
414
|
(#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}]
|
|
405
415
|
g. mgr-gitnerd commit: "chore(release): bump to v<NEW>" — MUST include the drift from step f.
|
|
@@ -411,6 +421,11 @@ steps:
|
|
|
411
421
|
i. mandatory verification (with existence guard for partial-update safety), run on release/v{NEW}:
|
|
412
422
|
[ -f scripts/verify-version-sync.sh ] && bash scripts/verify-version-sync.sh || echo "::warning::verify-version-sync.sh not found, version sync verification skipped"
|
|
413
423
|
(verify-version-sync.sh 가 exit 1 시 release 단계 halt)
|
|
424
|
+
j. lockfile 3-way assertion (#1593 제안3, closes the gap step i's 2-way check misses) — run standalone
|
|
425
|
+
(NO pipe), read exit code directly, on release/v{NEW}:
|
|
426
|
+
jq -e --arg v "<NEW>" '.generatorVersion==$v and .templateVersion==$v' .omcustom.lock.json
|
|
427
|
+
실패 시 release 단계 halt — cause is almost always step e run before step d landed; fix by
|
|
428
|
+
re-running step d then step e, re-staging, and re-running this assertion.
|
|
414
429
|
|
|
415
430
|
Version decision (semver) — PATCH-PREFERRED policy (post-1.0.0):
|
|
416
431
|
- No existing tags → v0.1.0
|
|
@@ -428,7 +443,15 @@ steps:
|
|
|
428
443
|
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>"
|
|
429
444
|
⚠ 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.
|
|
430
445
|
Before creating the PR (whether via inline --body or --body-file), confirm the body text actually contains a Closes line per issue.
|
|
431
|
-
c. mgr-gitnerd merges PR
|
|
446
|
+
c. mgr-gitnerd merges PR: gh pr merge {n} --merge --delete-branch (plain merge — NOT --admin).
|
|
447
|
+
Ground-truth (measured 2026-08-15, `gh api repos/{owner}/{repo}/branches/develop/protection`):
|
|
448
|
+
required status checks are exactly 6 — Test, Lint, Template Sync, Version Sync,
|
|
449
|
+
Dependency Security Audit, Rust Tests (strict=true); enforce_admins=false; NO
|
|
450
|
+
required_pull_request_reviews (no reviewer-approval requirement exists). v1.1.47 merged with a
|
|
451
|
+
plain `gh pr merge 1585 --merge --delete-branch` — no --admin needed. A plain merge succeeds
|
|
452
|
+
once all 6 checks report green. If the merge is rejected, do NOT reflexively add --admin —
|
|
453
|
+
re-run the protection query above to re-measure current requirements and report the actual
|
|
454
|
+
blocker (R010 bypass-flag pre-check: name what is bypassed and why before ever using --admin).
|
|
432
455
|
d. DO NOT manually git tag or gh release create.
|
|
433
456
|
auto-tag.yml fires on release/v* PR merge → creates tag → closes issues linked via PR-body Closes/Fixes/Resolves keywords → closes milestone → deletes release branch.
|
|
434
457
|
release.yml fires on the tag → npm publish + GitHub Release creation.
|