Lines 12-52typescript
12 * `commitgateDeclared`(D14 — `devDependencies.commitgate` 키 없으면 선행 설치 안내). 둘 다 preflight = 무쓰기 실패.
13 * 3. `KIT_COPY_RELPATHS`(스키마 2종 + review-persona.md) 복사(기존 파일은 --force 없으면 스킵).
14 * **`scripts/req/**` 는 복사하지 않는다**(R3 — 패키지에서 실행).
15 * 4. `req.config.json` 시드(부재 시): 감지한 packageManager + handoffPath:null(프로젝트별 값은 코어 DEFAULTS가 아니라 config에서 흡수)
16 * 5. 대상 `package.json`에 `req:* = commitgate <verb>` 주입(기존 키 미덮어씀). **devDeps는 주입하지 않는다**(R3).
17 * 6. `AGENTS.md` 부재 시 템플릿 생성(있으면 스킵 — Codex 계약 보존)
18 * 7. 에이전트 진입점(.claude/skills·.claude/commands·.cursor/rules) 복사 + `CLAUDE.md` 부재 시 생성 (--no-agent-entrypoints로 생략)
20 * 코어 승인 바인딩·staged tree 검증은 건드리지 않는다. 프로젝트 차이는 req.config.json에서만 흡수.
33import { execFileSync } from 'node:child_process'
34import { createHash } from 'node:crypto'
35import { resolve, join, dirname, relative, isAbsolute } from 'node:path'
36import { fileURLToPath, pathToFileURL } from 'node:url'
37import { loadConfig, stripBom, DEFAULT_REVIEW_PERSONA_RELPATH, type PackageManager } from '../scripts/req/lib/config'
38import { createGitAdapter, type GitRunner } from '../scripts/req/lib/adapters'
39import { parseStatusZ, entryPaths, STATUS_Z_ARGS, type StatusEntry } from '../scripts/req/lib/porcelain'
40import * as semver from 'semver'
42/** 이 패키지 루트(bin/ 기준 1단계 위). 복사 원본. */
43export const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
45/** kit 소스 디렉터리(패키지-상대 = 대상-상대). copyInto가 이 레이아웃을 그대로 재현. */
46export const KIT_SOURCE_DIR_REL = 'scripts/req'
49 * init이 **실제로 복사하는** 스키마 경로(패키지-상대 = 대상-상대). ⚠️ `req.config.json`의 `ticketRoot`/`schemaPath`와 무관하게
50 * 언제나 리터럴 `workflow/` 아래다 — `copyInto`가 `relative(PACKAGE_ROOT, src)`로 상대경로를 재현하기 때문.
51 * runInit(복사)과 uninstall planner(제거 후보)가 이 상수를 **공유**해야 드리프트가 없다(REQ-2026-007 design R1 P2 / D3b).