@uzysjung/agent-harness 26.147.1 → 26.148.1

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.
@@ -443,23 +443,25 @@ var EXTERNAL_ASSETS = [
443
443
  method: { kind: "npm", pkg: "supabase", version: "2.108.0" }
444
444
  },
445
445
  // === UI tracks (csr-*|ssr-*|full) ===
446
- // v26.92.0 — frontend-design (Anthropic official, claude-plugins-official 984.5K installs).
446
+ // v26.92.0 — frontend-design (Anthropic official).
447
447
  // 사용자 결정: has-dev-track 기본추천 (모든 개발 트랙, executive 제외).
448
448
  // category=frontend (UI 자산, wizard 그룹).
449
- // repoForAsset=marketplace(anthropics/claude-plugins-official); official tier=drift 제외.
449
+ //
450
+ // 2026-08-26 (#344) — **plugin → skill.** 배달 방식이 도달 CLI 를 정한다(assetCliSupport):
451
+ // `plugin` 은 `claude plugin install` 을 spawn 하므로 **구조적으로 Claude Code 전용**이라,
452
+ // Codex·OpenCode·Antigravity 를 고른 사용자는 기본 추천 자산인데도 한 번도 받지 못했다
453
+ // (사용자 적발). 같은 스킬이 `anthropics/skills` 에 원본으로 있고 `npx skills add` 는
454
+ // `--agent` 로 네 CLI 전부에 깐다 — 실재 확인 2026-08-26: `skills/frontend-design/SKILL.md`.
455
+ // tier 는 official 그대로(저자 동일). marketplace 경유가 아니게 되어 upstream 판본을 직접 쓴다.
450
456
  {
451
457
  id: "frontend-design",
452
458
  tier: "official",
453
- // anthropics/claude-plugins-official (Anthropic 저자, 984.5K installs)
459
+ // anthropics/skills (Anthropic 저자, ★171.5K — 2026-08-26 gh api 실측)
454
460
  description: "frontend-design \u2014 distinctive production-grade UI generation (Anthropic official, avoids generic AI aesthetics)",
455
461
  category: "frontend",
456
462
  source: "anthropics",
457
463
  condition: { kind: "has-dev-track" },
458
- method: {
459
- kind: "plugin",
460
- marketplace: "anthropics/claude-plugins-official",
461
- pluginId: "frontend-design@claude-plugins-official"
462
- }
464
+ method: { kind: "skill", source: "anthropics/skills", skill: "frontend-design" }
463
465
  },
464
466
  // 2026-08-02 정비 — 프론트엔드 품질 3종 (사용자 지시). 전부 opt-in: frontend-design 이 기본
465
467
  // 생성기이고 이 셋은 그 위의 취향·디테일 층이라 상시 비용을 물릴 근거가 없다 (ADR-032/035
@@ -1673,25 +1675,19 @@ function buildManifest(spec) {
1673
1675
  type: "file",
1674
1676
  applies: all
1675
1677
  });
1676
- m.push({
1677
- source: "skills/market-research",
1678
- target: ".claude/skills/market-research",
1679
- type: "dir",
1680
- applies: onTracks("executive|full")
1681
- });
1682
- for (const sd of ["investor-materials", "investor-outreach"]) {
1678
+ for (const sd of ["market-research", "investor-materials", "investor-outreach"]) {
1683
1679
  m.push({
1684
1680
  source: `skills/${sd}`,
1685
1681
  target: `.claude/skills/${sd}`,
1686
1682
  type: "dir",
1687
- applies: onTracks("executive|full")
1683
+ applies: (s) => !s.withEcc && onTracks("executive|full")(s)
1688
1684
  });
1689
1685
  }
1690
1686
  m.push({
1691
1687
  source: "skills/nextjs-turbopack",
1692
1688
  target: ".claude/skills/nextjs-turbopack",
1693
1689
  type: "dir",
1694
- applies: onTracks("ssr-nextjs|full")
1690
+ applies: (s) => !s.withEcc && onTracks("ssr-nextjs|full")(s)
1695
1691
  });
1696
1692
  for (const sd of INTERNAL_BUNDLED_SKILL_IDS) {
1697
1693
  m.push({
@@ -2006,4 +2002,4 @@ export {
2006
2002
  formatResidentCostLine,
2007
2003
  formatResidentCostBlock
2008
2004
  };
2009
- //# sourceMappingURL=chunk-B27AJIWG.js.map
2005
+ //# sourceMappingURL=chunk-PTUM2NI3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../src/types.ts","../src/external-assets.ts","../src/track-match.ts","../src/manifest.ts","../src/install-log.ts","../src/fs-ops.ts","../src/project-claude-merge.ts","../src/categories.ts","../src/context-cost.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","/** Available installation tracks. v0.5.0 — 11 Track (PM/Growth Marketing 추가). */\nexport const TRACKS = [\n \"tooling\",\n \"csr-supabase\",\n \"csr-fastify\",\n \"csr-fastapi\",\n \"ssr-htmx\",\n \"ssr-nextjs\",\n \"data\",\n \"executive\",\n \"full\",\n \"project-management\",\n \"growth-marketing\",\n] as const;\nexport type Track = (typeof TRACKS)[number];\n\nexport function isTrack(value: unknown): value is Track {\n return typeof value === \"string\" && (TRACKS as readonly string[]).includes(value);\n}\n\n/**\n * CLI target — multi-select base × combination (v0.8.0 — alias 제거).\n *\n * Base CLI: claude / codex / opencode / antigravity (4 base). 15 combinations possible (2^4 - 1, empty 제외).\n * Legacy `both` / `all` alias는 v0.7.0 deprecation 거쳐 v0.8.0에서 invalid input.\n * Migration: `--cli claude --cli codex` (repeatable) 또는 multiselect 인터랙티브.\n */\nexport const CLI_BASES = [\"claude\", \"codex\", \"opencode\", \"antigravity\"] as const;\nexport type CliBase = (typeof CLI_BASES)[number];\n\nexport function isCliBase(value: unknown): value is CliBase {\n return typeof value === \"string\" && (CLI_BASES as readonly string[]).includes(value);\n}\n\n/** Sorted readonly array of CliBase. install pipeline의 분기 input. */\nexport type CliTargets = ReadonlyArray<CliBase>;\n\n/**\n * v26.64.0 (ADR-020) — Installation scope.\n *\n * - \"project\" (default): claude plugin `--scope project`, npx skills (default), npm `--save-dev`,\n * codex/opencode → 프로젝트 dir (`.codex/`, `.opencode/`). 사용자 명시 동의 없이는 글로벌 미수정.\n * - \"global\" (opt-in): claude plugin `--scope user`, npx skills `-g`, npm `-g`,\n * codex/opencode → `~/.codex/`, `~/.opencode/`. 사용자가 interactive 또는 `--scope global` 로 명시.\n *\n * NORTH_STAR.md D16 본질 — 사용자 무인지 글로벌 write 금지.\n */\nexport const INSTALL_SCOPES = [\"project\", \"global\"] as const;\nexport type InstallScope = (typeof INSTALL_SCOPES)[number];\n\nexport function isInstallScope(value: unknown): value is InstallScope {\n return typeof value === \"string\" && (INSTALL_SCOPES as readonly string[]).includes(value);\n}\n\n/**\n * v26.64.0 (ADR-020) — `InstallSpec.scope` 가 optional 이므로 사용 시 default \"project\" 로 normalize.\n * 모든 분기 코드 (external-installer, codex/*, opencode/*) 는 이 함수로 scope 결정.\n */\nexport function resolveScope(scope: InstallScope | undefined): InstallScope {\n return scope ?? \"project\";\n}\n\n/**\n * Optional opt-in feature flags collected interactively.\n *\n * v26.81.0 (ADR-022, BREAKING) — 자산 1:1 boolean 13종(withGsd/withEcc/withTob/\n * withSuperpowers/withAddyAgentSkills/withWshobsonAgents/withOpenspec/withBmad/\n * withClaudeVideo/withUnderstandAnything/withAgentmemory + withTauri/withUzysHarness)\n * 완전 삭제. 자산 선택은 `userOverride.forceInclude`(wizard 체크 / `--with <id>`)로\n * 일원화 — 자산 추가 시 플래그 코드 0곳. 잔존 6종 = 자산이 아닌 **설치 동작 옵션**만.\n */\nexport interface OptionFlags {\n /** ecc-prune 실행 결합 — prune 은 ecc-plugin 선택을 전제 (installer.ts eccSelected 가 처리). */\n withPrune: boolean;\n /** Codex global opt-in: ~/.codex/config.toml [projects.\"...\"] trust entry. D16 — 사용자 명시 동의 필수. */\n withCodexTrust: boolean;\n}\n\nexport const DEFAULT_OPTIONS: OptionFlags = {\n withPrune: false,\n withCodexTrust: false,\n};\n\n/** Aggregate result of interactive flow — the spec the install pipeline consumes. */\nexport interface InstallSpec {\n tracks: Track[];\n options: OptionFlags;\n /** v0.7.0 — sorted readonly array of CliBase (이전: single CliMode). */\n cli: CliTargets;\n projectDir: string;\n /**\n * v26.64.0 (ADR-020) — Installation scope. Default \"project\" — 사용자 무인지 글로벌 write 방지.\n * Interactive prompt 또는 `--scope global` 명시 시에만 \"global\".\n * Optional + default \"project\" — 명시 안 한 사용처 (기존 tests / wizard non-scope-aware) 안전한 fallback.\n * 사용처는 `resolveScope(spec.scope)` 또는 `scope ?? \"project\"` 로 normalize.\n */\n scope?: InstallScope;\n /**\n * v26.47.0 — User-level override of preset/option condition (Phase C full).\n * `forceInclude`: condition 무관 강제 포함 / `forceExclude`: condition 무관 강제 제외.\n * 우선순위: forceExclude > forceInclude > condition.\n * Optional — 미제공 시 기존 condition 만 평가 (backward compat).\n */\n userOverride?: {\n forceInclude: ReadonlyArray<string>;\n forceExclude: ReadonlyArray<string>;\n };\n /**\n * 2026-08-16 — 사용자가 **해제한** baseline 자산 id (`baseline:<kind>/<name>`).\n *\n * `userOverride.forceExclude` 와 나눈 이유는 대상이 다른 목록이기 때문이다: 저쪽은\n * `EXTERNAL_ASSETS` 의 id 를 보고, 이쪽은 `manifest.ts` 가 트랙에서 유도하는 설치 대상을 본다.\n * 한 필드에 섞으면 오타 하나가 어느 목록의 미스인지 판별할 수 없고, 조용히 아무것도 안 하는\n * 제외 지시가 생긴다.\n *\n * 비어 있거나 없으면 트랙이 고른 것을 전부 깐다 — 즉 **기본 동작은 그대로**다.\n */\n baselineExclude?: ReadonlyArray<string>;\n /**\n * 2026-08-17 (ADR-075) — 이번 선택이 밀어냈는데 디스크에 남아 있는 자산을 **지울까**.\n *\n * 대표 사례: `ecc-plugin` 을 고르면 하네스의 폴백 에이전트 4종이 manifest 상 설치 대상에서\n * 빠지는데, 이미 깔려 있던 파일은 아무도 안 지워서 같은 일을 하는 에이전트가 두 벌 남는다.\n *\n * **기본값은 거짓**이고 위저드 확인 화면에서만 참이 될 수 있다. 비대화형(`--track` 플래그)\n * 설치에는 물어볼 사람이 없고, 물어보지 않은 삭제는 승인 없이 넘은 경계다.\n */\n cleanSuperseded?: boolean;\n}\n","/**\n * External asset matrix — bash setup-harness.sh L791~1067 등가 데이터.\n *\n * SPEC: docs/specs/cli-rewrite-completeness.md F3\n * Source: setup-harness.sh@911c246~1 (v27.18 직전, bash cutover 전)\n *\n * Track 또는 옵션 조건이 충족되면 install pipeline에서 method를 호출.\n * 실패는 \"warn-skip\" — 종료 시 누락 자산 보고 (OQ1 결정).\n *\n * code-style 800줄 cap 예외: 본 파일은 ~85% 가 큐레이션 자산 카탈로그(43 entry × ~13줄)\n * = 데이터. 로직(interface·condition 평가·shouldInstallAsset)은 소량. 데이터/로직 분리는\n * 별도 사이클(Phase R) 후보 — 현재는 카탈로그 단일 SSOT 가독성 우선. (v26.79.0 기준 802줄)\n */\n\nimport type { Category, Source } from \"./categories.js\";\nimport { hasDevTrack } from \"./track-match.js\";\nimport { CLI_BASES, type CliTargets, type OptionFlags, TRACKS, type Track } from \"./types.js\";\n\nexport type ExternalAssetMethod =\n /** `npx skills add <source>[ --skill <name>] --yes` */\n | { kind: \"skill\"; source: string; skill?: string }\n /** `claude plugin marketplace add <marketplace>` + `claude plugin install <pluginId>` */\n | { kind: \"plugin\"; marketplace: string; pluginId: string }\n /**\n * `npm install --save-dev <pkg>@<version>` (global scope 시 `-g`).\n * v26.80.0 — `version` 필수 (pinning). vetting 은 시점 검증인데 unpinned 는 미래 코드\n * 실행 = hijacked vetted repo 직행 구멍 (ADR-021 \"지속 검증\" 주장과 모순). pkg 는 bare\n * 이름 유지 (detectVersion 이 `<npm root>/<pkg>/package.json` 경로로 사용). bump 정책:\n * A2 자산 audit 주기에 Docker 검증 후 갱신 (docs/COMPATIBILITY.md §pinning).\n */\n | { kind: \"npm\"; pkg: string; version: string }\n /** `npx <cmd>@<version> [args...]` — fire-and-forget 실행. v26.80.0 — version 필수 (위와 동일 근거). */\n | { kind: \"npx-run\"; cmd: string; version: string; args?: string[] }\n /** `bash <script> <args...>` — 로컬 스크립트 (예: prune-ecc.sh) */\n | { kind: \"shell-script\"; script: string; args: string[] }\n /**\n * v26.81.0 (ADR-022) — 내부 템플릿 자산. external-installer 가 spawn 하지 않음 —\n * installer Phase 1 의 manifest/transform 게이팅이 `isAssetSelected(key)` 로 읽는다.\n * (이전 OptionFlags.withTauri/withUzysHarness 자리. wizard/CLI 표면은 일반 자산과 동일)\n */\n | {\n kind: \"internal\";\n key:\n | \"tauri-desktop\"\n // v26.87.0 — dev-method skills (uzys 1st-party, repo-bundled templates).\n // 2026-08-02 복원 (ADR-062) — 이관(ADR-060)이 본문을 열화시켜 이 리포 번들로 되돌렸다.\n // 9종 전부 `templates/skills/<id>/` 로 다시 번들된다.\n | \"compaction-handoff\"\n | \"clear-korean-communication\"\n | \"north-star\"\n | \"audit-service-gaps\"\n | \"verification-loop\"\n | \"multi-persona-review\"\n | \"recurrence-prevention\"\n | \"gh-issue-workflow\"\n | \"model-orchestration\"\n | \"external-model-consult\"\n // 위임·요청을 canonical 브리프 형태로 정규화 (UserPromptSubmit 넛지 훅과 한 벌).\n | \"task-brief\"\n // 설치된 상주 조종층(앵커·룰·훅·permissions·descriptor)의 밥값 감사 — 자기유지 루프.\n | \"audit-harness-fit\"\n // v26.108.0 — CI 스캐폴드 (.github/workflows fill-in 템플릿). ADR-037.\n | \"ci-scaffold\";\n };\n\nexport type ExternalAssetCondition =\n /** Track 중 1개 이상이 set와 일치 */\n | { kind: \"any-track\"; tracks: Track[] }\n /** dev track (executive 외 모두) */\n | { kind: \"has-dev-track\" }\n /** OptionFlags 의 특정 플래그 true (잔존 동작 옵션용 — ADR-022 후 자산 토글엔 사용 금지) */\n | { kind: \"option\"; flag: keyof OptionFlags }\n /**\n * v26.81.0 (ADR-022) — 순수 opt-in: condition 매치 항상 false. wizard 체크 또는\n * `--with <id>` 의 forceInclude 로만 설치. 이전의 자산 1:1 OptionFlags(`withBmad` 등\n * 13종)를 대체 — 자산 추가 시 플래그 코드 0곳.\n */\n | { kind: \"opt-in\" };\n\nexport interface ExternalAsset {\n /** 안정 식별자 — 로깅 + 누락 보고 + 테스트에서 사용 */\n id: string;\n /** 사람이 읽는 라벨 (한 줄) */\n description: string;\n /** v26.43.0 — Category-based UI 그룹화. SPEC §3.1. */\n category: Category;\n /** v26.43.0 — 정확한 출처 (GitHub org/user). Step 2 라벨. SPEC §3.5 R6. */\n source: Source;\n condition: ExternalAssetCondition;\n method: ExternalAssetMethod;\n /**\n * v26.79.0 — 검증 Trust Tier. 자산 entry 의 **필수 필드** (SSOT). 이전엔 별도 `TRUST_TIER`\n * Record 였으나 누락(컴파일러 미검출) + stale(좀비 키, v26.76.0 content-creator 제거 전례)\n * drift 가 가능했음 → entry 에 통합: **누락은 컴파일 에러, stale 은 구조적 불가능**.\n * `TRUST_TIER` / `assetTrustTier` 는 이 필드에서 derive (EXTERNAL_ASSETS 정의 뒤).\n * star snapshot(2026-05~06)은 각 entry tier 라인 주석. 실 drift 판정은 trust-tier-drift 가 live fetch.\n */\n tier: TrustTier;\n /**\n * v26.102.0 (ADR-031) — kind 기본 도달 범위의 **개별 자산 예외**. 설정 시 assetCliSupport 가\n * kind derive 대신 이 값을 쓴다. 사용 조건: method 인자/스크립트가 특정 CLI 전용 산출물을\n * 만드는 경우만 (예: bmad `--tools claude-code`). 근거 주석 필수 — SOD 리뷰가 \"예외 0\" 가정을\n * bmad 로 반증(Critical-1)해 도입.\n */\n cliSupportOverride?: CliTargets;\n}\n\n/**\n * v26.71.0 (PRD v26-71) — 검증 Trust Tier. North Star 세 기둥 ②.\n * - official: Anthropic 공식 marketplace + 본 하네스 자체.\n * - vetted: star ≥ 1000 + 활성 유지보수 (D2; 라이선스 미표기/비-OSI 는 출처 신뢰).\n * - experimental: star < 1000 — opt-in + 경고 (pre-check 제외).\n */\nexport type TrustTier = \"official\" | \"vetted\" | \"experimental\";\n\n/** csr-*|ssr-nextjs|full per bash setup-harness.sh L1041 (ssr-htmx 제외 — htmx는 React 미사용). */\nconst CSR_SSR_NEXTJS_FULL: Track[] = [\n \"csr-supabase\",\n \"csr-fastify\",\n \"csr-fastapi\",\n \"ssr-nextjs\",\n \"full\",\n];\n\n/**\n * v0.8.1 — executive-style Track SSOT (reviewer MEDIUM-3 fix).\n *\n * 3 Track 모두 dev/UI baseline 미적용 — `.claude/agents/strategist` + project-claude/<track>.md만.\n * `track-match.ts:hasDevTrack()` 의 negation domain. 사용처:\n * - `shouldInstallAsset` `has-dev-track` 분기 코멘트 (L458)\n * - `tests/external-assets.test.ts` invariant\n *\n * 신규 executive-style Track 추가 시 이 상수만 수정 → 모든 사용처 자동 반영.\n */\nexport const EXECUTIVE_STYLE_TRACKS: ReadonlyArray<Track> = [\n \"executive\",\n \"project-management\",\n \"growth-marketing\",\n];\n\n/**\n * v0.8.1 — `hasDevTrack` SSOT 의 array 표현 (reviewer MEDIUM-3 fix).\n *\n * `track-match.ts:hasDevTrack()` 와 동등 (TRACKS \\ EXECUTIVE_STYLE_TRACKS = 8 Track).\n * `any-track` condition 에 dev set 전체를 인라인하지 않도록 사용.\n */\nexport const DEV_TRACKS: ReadonlyArray<Track> = [\n \"csr-supabase\",\n \"csr-fastify\",\n \"csr-fastapi\",\n \"ssr-htmx\",\n \"ssr-nextjs\",\n \"data\",\n \"tooling\",\n \"full\",\n];\n\n/**\n * 60 자산 매트릭스 (2026-08-17 game-engine · game-studios 추가. 그 전: 2026-08-16 preline 추가. 그 전: 2026-08-02 복원분 + task-brief·audit-harness-fit 신설. 그 전 정비: 모델이 이미 아는\n * pattern-guide·중복 번들 12종 제거\n * [impeccable·polars/dask·python 2종·c-level/business-growth/pm/marketing/research-summarizer·\n * playwright-skill·karpathy-coder] + uzys 방법론 스킬 11종을 이관 리포 npx 설치 9종으로 대체\n * + 프론트엔드 3종 신규 — ADR-060. 이전: v26.110.0 ADR-039 오피셜 플러그인 큐레이션 3종 opt-in\n * [context7 = mcp.json 기본 wiring 기충족으로 미등록, claude-md-management 기각] + v26.108.0\n * ci-scaffold internal + v26.106.0 ADR-035 축 판정 + v26.92.0 frontend-design official +\n * v26.91.0 marketingskills opt-in + v26.86.0 Visual & Media 프레젠테이션 4종 + v26.85.0 5종 +\n * v26.81.0 internal 2종 — ADR-022). bash setup-harness.sh@911c246~1 L791~1067 + 1320~1370 동등.\n *\n * 호출 순서: data → dev-baseline → railway → supabase-cli → dev-tools →\n * supabase-skills → react/ui → next → executive → GSD → ToB → ECC.\n */\nexport const EXTERNAL_ASSETS: ReadonlyArray<ExternalAsset> = [\n // === data Track ===\n {\n id: \"anthropic-data-plugin\",\n tier: \"official\", // anthropics/knowledge-work-plugins 18k\n description: \"Anthropic data plugin (visualization, SQL exploration)\",\n category: \"data\",\n source: \"anthropics\",\n condition: { kind: \"any-track\", tracks: [\"data\", \"full\"] },\n method: {\n kind: \"plugin\",\n marketplace: \"anthropics/knowledge-work-plugins\",\n pluginId: \"data@knowledge-work-plugins\",\n },\n },\n\n // === Internal template assets (v26.81.0, ADR-022 — 이전 OptionFlags.withTauri/withUzysHarness) ===\n {\n id: \"tauri-desktop\",\n tier: \"official\", // uzys 본 하네스 자체 템플릿\n description: \"Tauri desktop rule template (CSR/full tracks — manifest rule mapping)\",\n category: \"frontend\",\n source: \"uzys\",\n condition: { kind: \"opt-in\" },\n method: { kind: \"internal\", key: \"tauri-desktop\" },\n },\n // v26.108.0 (ADR-037, 라이프사이클 자산화 ②) — CI 스캐폴드: `.github/workflows/` fill-in\n // 워크플로(tag-트리거 CI + 실DB 서비스 컨테이너 + coverage 게이트 + Playwright E2E).\n // 실무 CI 패턴의 도메인 중립 일반화 (CI 부재 프로젝트의 갭이 계기). `.claude/` 밖에\n // 쓰는 첫 자산 — opt-in 전용 + 기존 워크플로 파일은 절대 덮어쓰지 않는다 (src/ci-scaffold.ts,\n // manifest 경유 아님 — CLI 선택과 무관하게 설치되는 CLI-agnostic 산출물).\n {\n id: \"ci-scaffold\",\n tier: \"official\", // uzys 본 하네스 자체 템플릿\n description:\n \"CI scaffold — .github/workflows fill-in templates (tag-triggered CI + real-DB service container + coverage gate + Playwright E2E); never overwrites existing workflow files (opt-in)\",\n category: \"workflow\",\n source: \"uzys\",\n condition: { kind: \"opt-in\" },\n method: { kind: \"internal\", key: \"ci-scaffold\" },\n },\n\n // === Repo-bundled internal skills (uzys 1st-party, v26.87.0) ===\n // 2026-08-02 복원 (ADR-062) — 이관(ADR-060) 후 감사에서 본문 열화 104건(dropped 76 ·\n // damaged 28)이 확인돼 9종을 이 리포 번들로 되돌렸다. 아래 10종 전부 `kind: \"internal\"`.\n {\n id: \"compaction-handoff\",\n tier: \"official\", // uzys 본 하네스 자체 템플릿\n description:\n \"Compaction handoff — persist durable state + git snapshot + resume anchor before a context /compact so nothing is lost\",\n category: \"workflow\",\n source: \"uzys\",\n condition: { kind: \"has-dev-track\" },\n method: { kind: \"internal\", key: \"compaction-handoff\" },\n },\n\n // === uzys 방법론 스킬 — 이 리포 번들 (2026-08-02 복원, ADR-062) ===\n // ASIS(ADR-060): `kind: \"skill\"` — uzysjung/uzys-agent-skills 에서 `npx skills add`.\n // TOBE: templates/skills/<id>/ 번들 → 설치 시 dir copy (`kind: \"internal\"`).\n // 이관본이 판정 기준·수치·워크드 예시를 잃어(감사 실측 104건) 스킬이 무엇을 하라는지가\n // 남고 무엇으로 판정하는지가 사라졌다. 배포 경로를 하나로 모으는 이득보다 본문 보존이\n // 앞선다 — 본문 게이트(테스트)가 이 리포에만 있기 때문이다. tier official = 자사\n // (star 무관 — trust-tier-drift 가 official 을 건너뛴다). condition 은 이관 전 도달 범위 유지.\n {\n id: \"clear-korean-communication\",\n tier: \"official\", // uzys 자사 스킬 리포\n description:\n \"Clear Korean communication — restate technical facts from the reader's position (impact and cause first, then evidence) instead of translation-ese; covers decisions, approval requests, and AS-IS/TO-BE contrasts\",\n category: \"workflow\",\n source: \"uzys\",\n condition: { kind: \"has-dev-track\" },\n method: { kind: \"internal\", key: \"clear-korean-communication\" },\n },\n {\n id: \"north-star\",\n tier: \"official\", // uzys 자사 스킬 리포\n description:\n \"North Star — create or safely update the project direction baseline and its revision-linked roadmap, then analyze the impact on audits, verification criteria, issues, and work in progress\",\n category: \"workflow\",\n source: \"uzys\",\n // 전 트랙 상주 보존 — 이관 전에는 manifest COMMON_SKILL_DIRS(조건 없는 전 트랙 설치)였다.\n // 이 카탈로그에 \"always\" kind 가 없어 전 트랙 나열로 같은 도달 범위를 표현한다.\n condition: { kind: \"any-track\", tracks: [...TRACKS] },\n method: { kind: \"internal\", key: \"north-star\" },\n },\n {\n id: \"audit-service-gaps\",\n tier: \"official\", // uzys 자사 스킬 리포\n description:\n \"Audit service gaps — audit observable gaps between the service's current state and an explicit North Star baseline (reverse · defect · experience · benchmark · verify · change-impact · drift modes)\",\n category: \"dev-tools\",\n source: \"uzys\",\n condition: { kind: \"has-dev-track\" },\n method: { kind: \"internal\", key: \"audit-service-gaps\" },\n },\n {\n id: \"verification-loop\",\n tier: \"official\", // uzys 자사 스킬 리포\n description:\n \"Verification loop — run proportional verification tracks (UI · API · CLI · library · docs · real user flow) and end with evidence plus a fixed verdict; a green build is not proof of user-visible completion\",\n category: \"dev-tools\",\n source: \"uzys\",\n condition: { kind: \"has-dev-track\" },\n method: { kind: \"internal\", key: \"verification-loop\" },\n },\n {\n id: \"multi-persona-review\",\n tier: \"official\", // uzys 자사 스킬 리포\n description:\n \"Multi-persona review — review one artifact through independent stakeholder and failure lenses, then synthesize evidence-backed, severity-ranked findings without discarding minority views\",\n category: \"dev-tools\",\n source: \"uzys\",\n condition: { kind: \"has-dev-track\" },\n method: { kind: \"internal\", key: \"multi-persona-review\" },\n },\n {\n id: \"recurrence-prevention\",\n tier: \"official\", // uzys 자사 스킬 리포\n description:\n \"Recurrence prevention — reconstruct a repeated defect's failure signature and timeline, then pick the least costly countermeasure (code · regression test · rule · hook · derivation · gate)\",\n category: \"workflow\",\n source: \"uzys\",\n condition: { kind: \"has-dev-track\" },\n method: { kind: \"internal\", key: \"recurrence-prevention\" },\n },\n {\n id: \"gh-issue-workflow\",\n tier: \"official\", // uzys 자사 스킬 리포\n description:\n \"GitHub issue workflow — run work through issues so user and agent share one backlog: group tasks under a parent (epic) issue, order them with milestones and labels, read comments before starting, promote decisions into the body, and keep read-only, draft, external-write, and status stages distinct\",\n category: \"workflow\",\n source: \"uzys\",\n // 전 트랙 상주 보존 — north-star 와 같은 이유 (이관 전 COMMON_SKILL_DIRS).\n condition: { kind: \"any-track\", tracks: [...TRACKS] },\n method: { kind: \"internal\", key: \"gh-issue-workflow\" },\n },\n {\n id: \"model-orchestration\",\n tier: \"official\", // uzys 자사 스킬 리포\n description:\n \"Model orchestration — decompose work by capability and route independent, bounded tasks to available agents while preserving ownership, permissions, and verification (opt-in — recommended)\",\n category: \"workflow\",\n source: \"uzys\",\n condition: { kind: \"opt-in\" },\n method: { kind: \"internal\", key: \"model-orchestration\" },\n },\n {\n // 전신 = gemini-consult + codex-consult. provider 중립 한 스킬로 통합됐다(통합은 유지 —\n // 되돌린 것은 배포 경로이지 통합이 아니다).\n id: \"external-model-consult\",\n tier: \"official\", // uzys 자사 스킬 리포\n description:\n \"External model consult — ask an available external model/provider for an independent draft, critique, or provider-only output such as image generation (opt-in — recommended; requires that provider's CLI)\",\n category: \"dev-tools\",\n source: \"uzys\",\n condition: { kind: \"opt-in\" },\n method: { kind: \"internal\", key: \"external-model-consult\" },\n },\n {\n // 복원 9종이 아니라 신설이다 — 이관 이력이 없다.\n // 전 트랙인 이유: 위임과 요청 정규화는 개발 트랙의 행위가 아니라 **전 트랙의 행위**다.\n // executive 트랙도 서브에이전트에 일을 넘기고, 그때 브리프가 없으면 완료 판정 기준 없이\n // 넘긴다. 짝인 `task-brief-nudge.sh` 훅이 `ALWAYS_HOOKS`(전 설치본)라 스킬만 좁게 깔면\n // 넛지가 없는 스킬을 가리킨다 — 훅과 스킬의 도달 범위는 같아야 한다.\n id: \"task-brief\",\n tier: \"official\", // uzys 자사 스킬\n description:\n \"Task brief — normalize an incoming request into the canonical brief (objective · inputs · invariants · success criteria · boundaries · autonomy · verification) and write every delegation prompt in that same shape\",\n category: \"workflow\",\n source: \"uzys\",\n condition: { kind: \"any-track\", tracks: [...TRACKS] },\n method: { kind: \"internal\", key: \"task-brief\" },\n },\n {\n // task-brief 와 같은 신설이다 — 이관 이력이 없다.\n // 전 트랙인 이유: 이 하네스는 **모든 트랙에** 앵커·룰·훅을 깐다. 그 상주층이 밥값을 하는지\n // 되묻는 루프만 개발 트랙에 두면, 상주 비용은 전원이 무는데 감사는 일부만 갖는 비대칭이\n // 된다. 감사 대상이 개발 산출물이 아니라 **설치본 자신**이라 트랙 술어와 무관하다.\n id: \"audit-harness-fit\",\n tier: \"official\", // uzys 자사 스킬\n description:\n \"Audit harness fit — audit whether the resident steering layer (anchor · rules · hooks · permissions · skill descriptors) still earns its context, judged by published criteria, block logs, and measurement; relocate procedures to skills, guarantees to hooks/permissions, derivable facts to code\",\n category: \"workflow\",\n source: \"uzys\",\n condition: { kind: \"any-track\", tracks: [...TRACKS] },\n method: { kind: \"internal\", key: \"audit-harness-fit\" },\n },\n\n // === Option-gated (v26.42.0 — opt-in, BREAKING vs prior has-dev-track auto-install) ===\n {\n id: \"addy-agent-skills\",\n tier: \"vetted\", // addyosmani 47k\n description: \"addy agent-skills (general dev)\",\n category: \"workflow\",\n source: \"addyosmani\",\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"plugin\",\n marketplace: \"addyosmani/agent-skills\",\n pluginId: \"agent-skills@addy-agent-skills\",\n },\n },\n {\n id: \"superpowers\",\n tier: \"official\", // anthropics/claude-plugins-official 공식 배포 (소스 obra 213k)\n // 저자 = obra (190k★ github.com/obra/superpowers). 호스팅 = Anthropic 공식\n // marketplace github.com/anthropics/claude-plugins-official (\"Official,\n // Anthropic-managed directory of high quality Claude Code Plugins\").\n // source/marketplace 분리는 의도적 — source=저자, marketplace=registry.\n description: \"Superpowers — agentic skills framework (obra, Anthropic official marketplace)\",\n category: \"workflow\",\n source: \"obra\",\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"plugin\",\n marketplace: \"anthropics/claude-plugins-official\",\n pluginId: \"superpowers@claude-plugins-official\",\n },\n },\n // v26.110.0 (ADR-039, 오피셜 플러그인 큐레이션) — feature-dev: 탐색→설계→구현 워크플로우 +\n // 전용 에이전트 3종(code-architect/code-explorer/code-reviewer). 방법론류 — ADR-032\n // \"워크플로우 강제 구조는 기본 불필요\" + 자체 code-reviewer 가 기본 리뷰 에이전트와 중복\n // → superpowers 와 동급 opt-in.\n {\n id: \"feature-dev\",\n tier: \"official\", // anthropics/claude-plugins-official (242.5K installs, 사용자 관측 2026-07-18)\n description:\n \"feature-dev — guided feature workflow with explore/architect/review agents (Anthropic official)\",\n category: \"workflow\",\n source: \"anthropics\",\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"plugin\",\n marketplace: \"anthropics/claude-plugins-official\",\n pluginId: \"feature-dev@claude-plugins-official\",\n },\n },\n {\n // v26.75.0 (ADR-021) — wshobson/agents marketplace.json name = \"claude-code-workflows\"\n // (84 plugins). 대표 = full-stack-orchestration. 다른 orchestrator(agent-orchestration/\n // tdd-workflows/ship-mate 등): `claude plugin install <name>@claude-code-workflows`.\n id: \"wshobson-agents\",\n tier: \"vetted\", // wshobson/agents 36k\n description: \"wshobson agents — multi-agent orchestration workflows (full-stack/tdd/review)\",\n category: \"workflow\",\n source: \"wshobson\",\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"plugin\",\n marketplace: \"wshobson/agents\",\n pluginId: \"full-stack-orchestration@claude-code-workflows\",\n },\n },\n {\n // v26.75.0 (ADR-021) — `npm i --save-dev @fission-ai/openspec` 후 `openspec init` 로 슬래시 주입.\n id: \"openspec\",\n tier: \"vetted\", // Fission-AI/OpenSpec 53k\n description: \"OpenSpec — spec-driven brownfield delta workflow (propose → apply → archive)\",\n category: \"workflow\",\n source: \"fission-ai\",\n condition: { kind: \"opt-in\" },\n method: { kind: \"npm\", pkg: \"@fission-ai/openspec\", version: \"1.4.1\" },\n },\n {\n // v26.75.0 (ADR-021) — 비대화형 install. v26.75.1: `--directory .` 누락 시 \"Installation\n // directory\" 프롬프트에서 hang (Docker realcli 검출). cwd(=project) 기준 `.` 지정으로 봉합.\n id: \"bmad-method\",\n tier: \"vetted\", // bmad-code-org/BMAD-METHOD 48k\n description: \"BMAD-METHOD — multi-agent agile workflow (PM/Architect/Dev, 12+ agents)\",\n category: \"workflow\",\n source: \"bmad-code-org\",\n condition: { kind: \"opt-in\" },\n // v26.102.0 (ADR-031) — args 의 `--tools claude-code` 하드코딩이 claude 전용 산출물\n // (.claude/ agent commands)을 생성 (Docker 실검증 realcli-workflows-2026-06-06).\n // kind 기본값(npx-run=전 CLI)이 이 자산에선 거짓 → override. 대칭 실현(--tools derive)은 M4+.\n cliSupportOverride: [\"claude\"],\n method: {\n kind: \"npx-run\",\n cmd: \"bmad-method\",\n version: \"6.9.0\",\n args: [\"install\", \"--directory\", \".\", \"--tools\", \"claude-code\", \"--yes\"],\n },\n },\n\n // === Railway (csr-fastify|csr-fastapi|ssr-*|full) ===\n // v0.6.3 — railway-plugin entry 제거. railwayapp/railway-plugin repo 자체 존재 안 함\n // (404 Not Found). 공식 docs (https://docs.railway.com/ai/claude-code-plugin) 형식은\n // marketplace add `railwayapp/railway-skills` + plugin install `railway@railway-skills`만.\n // → 아래 railway-skills entry로 단일화.\n {\n id: \"railway-skills\",\n tier: \"experimental\", // railwayapp/railway-skills 268\n description: \"Railway agent-skills (deploy + project/service/env management)\",\n category: \"backend\",\n source: \"railwayapp\",\n // 2026-08-02 사용자 결정: 트랙 기본 → opt-in (ADR-063)\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"plugin\",\n marketplace: \"railwayapp/railway-skills\",\n pluginId: \"railway@railway-skills\",\n },\n },\n\n // === csr-supabase|full CLI ===\n {\n id: \"vercel-cli\",\n tier: \"vetted\", // vercel/vercel 15k\n description: \"Vercel CLI (npm)\",\n category: \"backend\",\n source: \"vercel\",\n // 2026-08-02 사용자 결정: 트랙 기본 → opt-in (ADR-063)\n condition: { kind: \"opt-in\" },\n method: { kind: \"npm\", pkg: \"vercel\", version: \"54.17.3\" },\n },\n {\n // v26.106.0 (ADR-035, 사용자 승인 B): 배포 CLI 2종 동시 기본의 중복 해소 — npm dl 실측 10.11:1\n // (vercel 2.79M vs netlify 276k /주, 2026-07-18) → vercel 만 기본, netlify 는 opt-in.\n id: \"netlify-cli\",\n tier: \"vetted\", // netlify/cli 1.9k\n description: \"Netlify CLI (npm)\",\n category: \"backend\",\n source: \"netlify\",\n condition: { kind: \"opt-in\" },\n method: { kind: \"npm\", pkg: \"netlify-cli\", version: \"26.1.0\" },\n },\n {\n id: \"supabase-cli\",\n tier: \"vetted\", // supabase 103k\n description: \"Supabase CLI (npm) — first 'supabase login' requires OAuth\",\n category: \"backend\",\n source: \"supabase\",\n // 2026-08-02 사용자 결정: 트랙 기본 → opt-in (ADR-063)\n condition: { kind: \"opt-in\" },\n method: { kind: \"npm\", pkg: \"supabase\", version: \"2.108.0\" },\n },\n\n // === UI tracks (csr-*|ssr-*|full) ===\n // v26.92.0 — frontend-design (Anthropic official).\n // 사용자 결정: has-dev-track 기본추천 (모든 개발 트랙, executive 제외).\n // category=frontend (UI 자산, wizard 그룹).\n //\n // 2026-08-26 (#344) — **plugin → skill.** 배달 방식이 도달 CLI 를 정한다(assetCliSupport):\n // `plugin` 은 `claude plugin install` 을 spawn 하므로 **구조적으로 Claude Code 전용**이라,\n // Codex·OpenCode·Antigravity 를 고른 사용자는 기본 추천 자산인데도 한 번도 받지 못했다\n // (사용자 적발). 같은 스킬이 `anthropics/skills` 에 원본으로 있고 `npx skills add` 는\n // `--agent` 로 네 CLI 전부에 깐다 — 실재 확인 2026-08-26: `skills/frontend-design/SKILL.md`.\n // tier 는 official 그대로(저자 동일). marketplace 경유가 아니게 되어 upstream 판본을 직접 쓴다.\n {\n id: \"frontend-design\",\n tier: \"official\", // anthropics/skills (Anthropic 저자, ★171.5K — 2026-08-26 gh api 실측)\n description:\n \"frontend-design — distinctive production-grade UI generation (Anthropic official, avoids generic AI aesthetics)\",\n category: \"frontend\",\n source: \"anthropics\",\n condition: { kind: \"has-dev-track\" },\n method: { kind: \"skill\", source: \"anthropics/skills\", skill: \"frontend-design\" },\n },\n // 2026-08-02 정비 — 프론트엔드 품질 3종 (사용자 지시). 전부 opt-in: frontend-design 이 기본\n // 생성기이고 이 셋은 그 위의 취향·디테일 층이라 상시 비용을 물릴 근거가 없다 (ADR-032/035\n // 와 같은 축). star 는 각 tier 라인 주석 = 2026-08-02 `gh api` 실측.\n {\n id: \"jakubkrehel-skills\",\n tier: \"vetted\", // jakubkrehel/skills 2,602 (2026-08-02)\n description:\n \"Better-* interface suite — 7 skills reviewing/improving UI detail, typography, OKLCH color, accessibility, layout, and UX writing, one concern per skill\",\n category: \"frontend\",\n source: \"jakubkrehel\",\n condition: { kind: \"opt-in\" },\n // `--skill` 미지정 = 리포의 7 스킬 전부 설치. 다른 multi-skill 출처(K-Dense·softaworks)는\n // 한 자산 = 한 스킬이라 `--skill` 을 썼지만, 여기 광고 문구가 \"7 skills\" 세트다 —\n // 한 개만 깔면 description 이 곧 거짓이 된다. 실호출 형태는 Docker 실설치(AC8)로 확인한다.\n method: { kind: \"skill\", source: \"jakubkrehel/skills\" },\n },\n {\n id: \"taste-skill\",\n tier: \"vetted\", // Leonxlnx/taste-skill 70,078 (2026-08-02)\n description:\n \"Anti-slop frontend design — removes the boilerplate look of AI-generated UI; infers a design language and tunes VARIANCE/MOTION/DENSITY, with minimalist/brutalist/high-end style variants\",\n category: \"frontend\",\n source: \"Leonxlnx\",\n condition: { kind: \"opt-in\" },\n // 리포에 스킬 14종(brandkit·brutalist·minimalist 등)이 있고 본체가 `taste-skill` —\n // 스타일 변형은 그 안에서 고른다. 다른 단일 대표 자산(remotion)과 같은 형태.\n method: { kind: \"skill\", source: \"Leonxlnx/taste-skill\", skill: \"taste-skill\" },\n },\n {\n id: \"scroll-world\",\n tier: \"vetted\", // oso95/scroll-world 6,863 (2026-08-02)\n description:\n \"Scroll-driven 3D world landing pages — interviews for brand/scene direction, generates AI assets, then builds a continuous camera-flight scroll engine\",\n category: \"frontend\",\n source: \"oso95\",\n condition: { kind: \"opt-in\" },\n method: { kind: \"skill\", source: \"oso95/scroll-world\", skill: \"scroll-world\" },\n },\n // 2026-08-16 — Preline 은 Tailwind 컴포넌트 킷이지만 **프레임워크에 매이지 않는다**: htmx·\n // vanilla 에도 붙는다(사용자 확인). 그래서 `frontend` 이면서 React/Vue 트랙 전용이 아니다.\n //\n // 리포 안에 스킬은 `skills/theme-generator/` **하나**다 — 공식 문서는 이것을\n // \"preline-theme-generator\" 라 부르지만 실제 디렉터리명은 `theme-generator` 이고,\n // `npx skills add` 가 보는 것은 디렉터리명이다(실측 2026-08-16). 문서 표기를 그대로 옮겼다면\n // 설치가 조용히 빗나갔다.\n //\n // 같은 날 조사한 flowbite 는 **넣지 않는다**: 에이전트용 제공물이 MCP 서버뿐인데, 이 저장소의\n // `.mcp.json` 조립은 트랙 조건만 읽어 opt-in 경로가 없다 — 넣으면 해당 트랙 전원에게 항상\n // 켜진다. 안 쓰는 사람에게 MCP 툴 스키마만큼의 상주 비용을 물리는 형태라 기각(사용자 확정).\n {\n id: \"preline\",\n tier: \"vetted\", // htmlstreamofficial/preline 6,386 (2026-08-16)\n description:\n \"Preline theme generator — turns a brand description into a Preline UI Tailwind theme (tokens, dark mode, component overrides); framework-agnostic, works with plain HTML and htmx\",\n category: \"frontend\",\n source: \"htmlstreamofficial\",\n condition: { kind: \"opt-in\" },\n method: { kind: \"skill\", source: \"htmlstreamofficial/preline\", skill: \"theme-generator\" },\n },\n\n // === dev tools (has_dev_track) ===\n // v26.110.0 (ADR-039) — code-review: /code-review 커맨드 1개 (다중 에이전트 confidence\n // 스코어링 PR 리뷰). 기본 리뷰 스택(reviewer·code-reviewer·security-reviewer)과 표면 중복\n // + 최신 Claude Code 네이티브 /code-review 와 충돌 소지 → opt-in.\n {\n id: \"code-review\",\n tier: \"official\", // anthropics/claude-plugins-official (404.3K installs, 사용자 관측 2026-07-18)\n description: \"code-review — multi-agent PR review with confidence scoring (Anthropic official)\",\n category: \"dev-tools\",\n source: \"anthropics\",\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"plugin\",\n marketplace: \"anthropics/claude-plugins-official\",\n pluginId: \"code-review@claude-plugins-official\",\n },\n },\n // v26.110.0 (ADR-039) — security-guidance: 매 편집 패턴 경고 + LLM diff 리뷰 (훅 12파일,\n // Python + Agent SDK 의존). 상시 훅 = 매 편집 비용 + 폭발 반경 — 실측 전 기본설치 금지\n // (Context Cost NSM) → opt-in. security-reviewer 에이전트·agentshield ship 게이트와 보완.\n {\n id: \"security-guidance\",\n tier: \"official\", // anthropics/claude-plugins-official (220.8K installs, 사용자 관측 2026-07-18)\n description:\n \"security-guidance — pattern-based security warnings on edits + LLM diff review (Anthropic official)\",\n category: \"dev-tools\",\n source: \"anthropics\",\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"plugin\",\n marketplace: \"anthropics/claude-plugins-official\",\n pluginId: \"security-guidance@claude-plugins-official\",\n },\n },\n {\n id: \"find-skills\",\n tier: \"vetted\", // vercel-labs/skills 20k (license none — 출처 신뢰)\n description: \"find-skills — search · rank all installed skills (vercel-labs, all dev tracks)\",\n category: \"dev-tools\",\n source: \"vercel-labs\",\n condition: { kind: \"has-dev-track\" },\n method: { kind: \"skill\", source: \"vercel-labs/skills\", skill: \"find-skills\" },\n },\n // v26.110.0 (ADR-039) — context7 플러그인은 **미등록** (검토 후 철회): templates/mcp.json ·\n // codex config.toml.template · opencode 설정이 이미 @upstash/context7-mcp 를 기본 wiring —\n // 플러그인 추가 = 동일 서버 중복 등록이고 도달 범위도 더 좁다(plugin=claude-only vs\n // 템플릿=claude+codex+opencode). \"문서 조회 기본 제공\" 요구는 기충족.\n {\n id: \"agent-browser\",\n tier: \"vetted\", // vercel-labs/agent-browser 34k\n description:\n \"agent-browser — agent-friendly Playwright wrapper (screenshot · DOM search CLI, dev tracks)\",\n // v26.78.0 — Understanding 으로 재분류: 웹 지각(screenshot·DOM). 영상/코드 지각과 같은 축.\n category: \"understanding\",\n source: \"vercel-labs\",\n condition: { kind: \"has-dev-track\" },\n method: { kind: \"npm\", pkg: \"agent-browser\", version: \"0.31.0\" },\n },\n // v26.78.0 — Understanding 신규 3종 (plugin, opt-in). 에이전트 인지 증강: 영상·코드 지각 + 메모리.\n {\n id: \"claude-video\",\n tier: \"vetted\", // bradautomates/claude-video 1.8k\n description:\n \"Claude Video — /watch downloads any video, extracts frames + transcript so Claude can see + hear it (yt-dlp/ffmpeg auto on first run)\",\n category: \"understanding\",\n source: \"bradautomates\",\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"plugin\",\n marketplace: \"bradautomates/claude-video\",\n pluginId: \"watch@claude-video\",\n },\n },\n {\n id: \"understand-anything\",\n tier: \"vetted\", // Lum1104/Understand-Anything 53k\n description:\n \"Understand Anything — multi-agent pipeline builds an interactive knowledge graph of your codebase (files/functions/deps) to explore + query\",\n category: \"understanding\",\n source: \"Lum1104\",\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"plugin\",\n marketplace: \"Lum1104/Understand-Anything\",\n pluginId: \"understand-anything@understand-anything\",\n },\n },\n {\n id: \"agentmemory\",\n tier: \"vetted\", // rohitg00/agentmemory 21k\n description:\n \"AgentMemory — persistent memory runtime; plugin auto-wires MCP (53 tools) + hooks + skills. Runtime server: npx @agentmemory/agentmemory\",\n category: \"understanding\",\n source: \"rohitg00\",\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"plugin\",\n marketplace: \"rohitg00/agentmemory\",\n pluginId: \"agentmemory@agentmemory\",\n },\n },\n\n // === Visual & Media (v26.85.0) — 코드-퍼스트 제작 자산. 전부 opt-in. ===\n // Docker 실설치 검증 PASS (실 claude 2.1.177): plugin install / npx skills add resolve 확인.\n {\n id: \"frontend-slides\",\n tier: \"vetted\", // zarazhangrui/frontend-slides 21k\n description:\n \"frontend-slides — dependency-free HTML slide decks (presets · templates · PPTX→HTML · PDF export)\",\n category: \"visual-media\",\n source: \"zarazhangrui\",\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"plugin\",\n marketplace: \"zarazhangrui/frontend-slides\",\n pluginId: \"frontend-slides@frontend-slides\",\n },\n },\n {\n id: \"marp-slide\",\n tier: \"vetted\", // softaworks/agent-toolkit 2k\n description: \"marp-slide — Marp Markdown slides (7 themes · PPTX/PDF export)\",\n category: \"visual-media\",\n source: \"softaworks\",\n // softaworks plugin dir 는 plugin.json 부재 → skill 경로가 안전 (Docker 검증).\n condition: { kind: \"opt-in\" },\n method: { kind: \"skill\", source: \"softaworks/agent-toolkit\", skill: \"marp-slide\" },\n },\n {\n id: \"mermaid-diagrams\",\n tier: \"vetted\", // softaworks/agent-toolkit 2k\n description:\n \"mermaid-diagrams — Mermaid flow/sequence/ER/state diagram authoring (code · docs)\",\n category: \"visual-media\",\n source: \"softaworks\",\n condition: { kind: \"opt-in\" },\n method: { kind: \"skill\", source: \"softaworks/agent-toolkit\", skill: \"mermaid-diagrams\" },\n },\n {\n id: \"gsap-skills\",\n tier: \"vetted\", // greensock/gsap-skills 9k (GSAP 본가 공식)\n description:\n \"GSAP skills — official GreenSock motion/scroll animation guide (8 skills: timeline · scrolltrigger · react)\",\n category: \"visual-media\",\n source: \"greensock\",\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"plugin\",\n marketplace: \"greensock/gsap-skills\",\n pluginId: \"gsap-skills@gsap-skills\",\n },\n },\n {\n // remotion: star 3.6k → vetted (star 기반 tier SSOT + trust-tier-drift CI 정합, 사용자 결정 2026-06-13).\n // 코어 BUSL(Business Source License) — opt-in + description 고지로 신중 취급 (경고 배지 대신).\n // --skill 값 = remotion-best-practices (dir `remotion` ≠ frontmatter name, Docker 실측 확정).\n id: \"remotion\",\n tier: \"vetted\", // remotion-dev/skills 3.6k (license none — 출처 신뢰; 코어 BUSL 고지)\n description:\n \"Remotion — programmatic MP4 video from React components (data-driven). Core license = BUSL\",\n category: \"visual-media\",\n source: \"remotion-dev\",\n condition: { kind: \"opt-in\" },\n method: { kind: \"skill\", source: \"remotion-dev/skills\", skill: \"remotion-best-practices\" },\n },\n // Issue #176 — 프레젠테이션 생성 스택 4종 (Docker 실설치 4/4 PASS: skills@1.5.11 add <src> --agent claude-code --skill, 2026-06-20).\n {\n id: \"ppt-master\",\n tier: \"vetted\", // hugohe3/ppt-master 29k\n description:\n \"ppt-master — editable PowerPoint (.pptx) from any document (native shapes · speaker notes · custom .pptx template)\",\n category: \"visual-media\",\n source: \"hugohe3\",\n condition: { kind: \"opt-in\" },\n method: { kind: \"skill\", source: \"hugohe3/ppt-master\", skill: \"ppt-master\" },\n },\n {\n // deer-flow 72k 거대 harness지만 --skill 로 ppt-generation 단일 skill만 설치 (skills/public/ 중첩, Docker 확인).\n id: \"ppt-generation\",\n tier: \"vetted\", // bytedance/deer-flow 72k\n description:\n \"ppt-generation — PPTX by generating an image per slide and composing into PowerPoint (deer-flow skill)\",\n category: \"visual-media\",\n source: \"bytedance\",\n condition: { kind: \"opt-in\" },\n method: { kind: \"skill\", source: \"bytedance/deer-flow\", skill: \"ppt-generation\" },\n },\n {\n id: \"web-video-presentation\",\n tier: \"vetted\", // ConardLi/garden-skills 8.4k\n description:\n \"web-video-presentation — click-driven 16:9 web decks that look like video (optional TTS narration; garden-skills)\",\n category: \"visual-media\",\n source: \"ConardLi\",\n condition: { kind: \"opt-in\" },\n method: { kind: \"skill\", source: \"ConardLi/garden-skills\", skill: \"web-video-presentation\" },\n },\n {\n id: \"revealjs\",\n tier: \"experimental\", // ryanbbrown/revealjs-skill 347 (<1000 → experimental, opt-in + 경고)\n description:\n \"reveal.js — polished HTML presentations (themes · multi-column · code highlight · speaker notes, no build step)\",\n category: \"visual-media\",\n source: \"ryanbbrown\",\n condition: { kind: \"opt-in\" },\n method: { kind: \"skill\", source: \"ryanbbrown/revealjs-skill\", skill: \"revealjs\" },\n },\n\n // === Supabase agent-skills (csr-supabase|full) ===\n {\n id: \"supabase-agent-skills\",\n tier: \"vetted\", // supabase/agent-skills 2.2k\n description:\n \"Supabase — RLS · auth · edge function · realtime guide (csr-supabase · full tracks)\",\n category: \"backend\",\n source: \"supabase\",\n condition: { kind: \"any-track\", tracks: [\"csr-supabase\", \"full\"] },\n method: {\n kind: \"plugin\",\n marketplace: \"supabase/agent-skills\",\n pluginId: \"supabase@supabase-agent-skills\",\n },\n },\n {\n id: \"postgres-best-practices\",\n tier: \"vetted\", // supabase/agent-skills 2.2k\n description:\n \"Postgres best practices — schema · index · query patterns (csr-supabase · full tracks)\",\n category: \"backend\",\n source: \"supabase\",\n condition: { kind: \"any-track\", tracks: [\"csr-supabase\", \"full\"] },\n method: {\n kind: \"plugin\",\n marketplace: \"supabase/agent-skills\",\n pluginId: \"postgres-best-practices@supabase-agent-skills\",\n },\n },\n\n // === React + Next UI tracks ===\n // v0.6.3 — vercel-labs/agent-skills source는 short form 안 됨. full HTTPS URL 필요.\n // 사용자 확인 형식: `npx skills add https://github.com/vercel-labs/agent-skills --skill <name>`.\n {\n id: \"react-best-practices\",\n tier: \"vetted\", // vercel-labs/agent-skills 27k (license none — 출처 신뢰)\n description:\n \"React best practices — Vercel's hook · perf · component patterns (CSR · SSR · Next tracks)\",\n category: \"frontend\",\n source: \"vercel-labs\",\n condition: { kind: \"any-track\", tracks: CSR_SSR_NEXTJS_FULL },\n method: {\n kind: \"skill\",\n source: \"https://github.com/vercel-labs/agent-skills\",\n // v0.6.5 — skills.sh registry name. GitHub dir 이름(react-best-practices)과 다름.\n // skills.sh: 대부분 vercel- prefix (web-design-guidelines, deploy-to-vercel만 예외).\n skill: \"vercel-react-best-practices\",\n },\n },\n {\n id: \"shadcn-ui\",\n tier: \"vetted\", // shadcn-ui/ui 115k\n description: \"shadcn/ui — Radix-based React component copy + Tailwind theme (shadcn official)\",\n category: \"frontend\",\n source: \"shadcn-ui\",\n condition: { kind: \"any-track\", tracks: CSR_SSR_NEXTJS_FULL },\n // v26.54.1 — shadcn/ui repo 의 실제 skill 이름은 `shadcn` (자산 id 와 다름).\n method: { kind: \"skill\", source: \"shadcn/ui\", skill: \"shadcn\" },\n },\n {\n // v26.106.0 (ADR-035, 사용자 승인 D): 순수 pattern-guide(일반 디자인 가이드라인) → opt-in 강등\n // (T2 가설 전제 — taste 3종 중복 주장은 검증자 정정으로 기각, 근거는 P축 단독).\n id: \"web-design-guidelines\",\n tier: \"vetted\", // vercel-labs/agent-skills 27k (license none — 출처 신뢰)\n description:\n \"Web design guidelines — Vercel's visual hierarchy · color · spacing (CSR · SSR · Next tracks)\",\n category: \"frontend\",\n source: \"vercel-labs\",\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"skill\",\n source: \"https://github.com/vercel-labs/agent-skills\",\n skill: \"web-design-guidelines\",\n },\n },\n {\n // 2026-08-17 (사용자 지정) — 웹 게임 개발. **웹 전용이다**: 스킬 본문 frontmatter 가\n // \"HTML5, Canvas, WebGL, and JavaScript\" 로 스스로 범위를 적고 있고 프레임워크도\n // Phaser · Three.js · Babylon.js · A-Frame 이다. Unity/Unreal/Godot 은 안 덮으므로\n // description 에 \"web\" 을 남긴다 — 엔진 이름을 지우면 네이티브 엔진까지 되는 것처럼 읽힌다.\n // opt-in 인 이유: frontend 트랙 사용자 대부분은 게임을 만들지 않는다. 게임 트랙은 아직 없다.\n id: \"game-engine\",\n tier: \"vetted\", // github/awesome-copilot 37,909★ (MIT, 2026-08-17 `gh api` 실측 · GitHub 공식 조직)\n description:\n \"Game engine — web game development with HTML5 Canvas · WebGL (Phaser · Three.js · Babylon.js): game loop, physics, collision, sprites, tilemaps, gamepad input, WebRTC multiplayer\",\n category: \"frontend\",\n source: \"github\",\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"skill\",\n source: \"https://github.com/github/awesome-copilot\",\n skill: \"game-engine\",\n },\n },\n {\n // 2026-08-17 (사용자 지정) — 게임 스튜디오 **프로세스** 스킬 73종.\n //\n // description 이 두 가지를 반드시 말해야 하는 이유 (둘 다 Docker 실측):\n // ① **에이전트는 안 깔린다.** 리포의 엔진 전문성(`godot-specialist`·`unity-specialist`·\n // `unreal-specialist`)은 49개 *에이전트*에 있는데 `npx skills add` 는 `.claude/skills/`\n // 만 가져온다(실측: 73 SKILL.md, settings.json·rules·hooks 미설치). \"Unity 되나?\" 로\n // 고른 사용자가 스프린트 계획 스킬을 받게 되므로 안 적으면 그게 거짓 광고다.\n // ② **상주 ~4,440 tok/세션.** 73 descriptor 실측(17,760자/4). tooling 트랙 baseline 전체가\n // ~5,037 tok 이라 이 자산 하나가 상주를 거의 두 배로 만든다 — 이 저장소의 1차 지표를\n // 가장 크게 움직이는 자산이라 선택 시점에 숫자가 보여야 한다.\n //\n // 저자의 공식 설치법은 `git clone` (프로젝트 템플릿)이다. 그 경로는 `.claude/settings.json`·\n // rules·hooks 를 함께 들여와 우리 하네스와 같은 자리를 다투므로 카탈로그에 넣지 않는다.\n id: \"game-studios\",\n tier: \"vetted\", // Donchitos/Claude-Code-Game-Studios 23,924★ (MIT · 최종 push 2026-05-21, 2026-08-17 `gh api` 실측)\n description:\n \"Game studio workflow — 73 process skills (sprint-plan · qa-plan · playtest-report · release-checklist · art-bible · balance-check). Skills only: the repo's 49 engine agents (godot/unity/unreal-specialist) are NOT installed. ~4,440 tok/session resident\",\n category: \"workflow\",\n source: \"Donchitos\",\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"skill\",\n source: \"https://github.com/Donchitos/Claude-Code-Game-Studios\",\n },\n },\n // === Executive tracks ===\n {\n id: \"anthropic-document-skills\",\n tier: \"official\", // anthropics/skills 144k\n description: \"Anthropic document-skills (pptx/docx/xlsx/pdf)\",\n category: \"business\",\n source: \"anthropics\",\n condition: { kind: \"any-track\", tracks: [\"executive\", \"full\"] },\n method: {\n kind: \"plugin\",\n marketplace: \"anthropics/skills\",\n pluginId: \"document-skills@anthropic-agent-skills\",\n },\n },\n // alirezarezvani/claude-skills marketplace (v2.3.0) — 2026-04-25 통합 갱신.\n // 기존 alirezarezvani/c-level-skills + alirezarezvani/finance-skills 별도 marketplace\n // → 통합된 alirezarezvani/claude-skills marketplace (claude-code-skills 이름)로 이동.\n {\n id: \"finance-skills\",\n tier: \"vetted\", // alirezarezvani 16k\n description: \"finance-skills (3 — financial analyst, SaaS metrics, investment advisor)\",\n category: \"business\",\n source: \"alirezarezvani\",\n // 2026-08-02 사용자 결정: 트랙 기본 → opt-in (ADR-063)\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"plugin\",\n marketplace: \"alirezarezvani/claude-skills\",\n pluginId: \"finance-skills@claude-code-skills\",\n },\n },\n\n // === Project Management Track (v0.5.0) ===\n // SPEC §3.5 — product-skills: has-dev-track + project-management 합집합 (executive/growth-marketing 제외).\n {\n id: \"product-skills\",\n tier: \"vetted\", // alirezarezvani 16k\n description: \"product-skills (15 — RICE, PRD, agile PO, UX research, SaaS scaffolder ...)\",\n category: \"dev-tools\",\n source: \"alirezarezvani\",\n // v26.106.0 (ADR-035, 사용자 승인 C): dev 8트랙 기본에서 제외 — PM 스킬 15종은 PM 트랙 목적\n // 자산. dev 트랙은 wizard 체크 / --with 로 opt-in.\n // 2026-08-02 사용자 결정: 트랙 기본 → opt-in (ADR-063)\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"plugin\",\n marketplace: \"alirezarezvani/claude-skills\",\n pluginId: \"product-skills@claude-code-skills\",\n },\n },\n\n // === Growth Marketing Track (v0.5.0) ===\n // 2026-08-02 정비 — alirezarezvani 번들 4종(c-level·business-growth·pm·marketing) +\n // research-summarizer 제거. 남는 마케팅 번들은 아래 coreyhaines31/marketingskills 하나로,\n // 동명이물(marketing-skills ≠ marketingskills) 병존도 이로써 해소된다.\n // v26.91.0 — coreyhaines31/marketingskills (35k★, MIT, plugin v2.5.1). opt-in =\n // growth-marketing 외 전 트랙에서도 wizard 토글 + `--with marketingskills` 로 설치 가능\n // (\"SEO 는 일반 개발에도 활용\" 충족: dev 트랙에서 본 번들 토글). 45 스킬 중 SEO 7종\n // (seo-audit/schema/ai-seo/site-architecture/programmatic-seo/content/aso)은 상호참조\n // (product-marketing 우선 + seo-audit↔schema↔ai-seo)라 부분 추출 시 포인터 깨짐 → 번들\n // 통째 설치만 정합. repoForAsset = marketplace(coreyhaines31/marketingskills) → drift 라이브.\n {\n id: \"marketingskills\",\n tier: \"vetted\", // coreyhaines31 35k\n description: \"marketingskills (45 — CRO/copywriting/SEO/AI-SEO/ads/growth, coreyhaines31 35k★)\",\n category: \"business\",\n source: \"coreyhaines31\",\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"plugin\",\n marketplace: \"coreyhaines31/marketingskills\",\n pluginId: \"marketing-skills@marketingskills\",\n },\n },\n // v26.76.0 — content-creator / demand-gen 제거: alirezarezvani/claude-skills marketplace.json 에\n // 해당 plugin 부재(Docker 실설치 검출, exit 1). 거짓 광고 0건 원칙(Promise=Implementation).\n\n // 2026-08-02 정비 — karpathy-coder 제거. Write|Edit 마다 Python complexity 검사를 돌리는\n // 상시 훅이었고, 그 검사는 현행 모델이 이미 하는 일이다 (Opus 5 가이드의 \"legacy harness\n // scaffolding\"에 정확히 해당). 딸린 배선(`--with-karpathy-hook` 플래그 · templates/hooks/\n // karpathy-gate.sh · settings.json PreToolUse auto-wire)도 함께 삭제 — BREAKING, ADR-060.\n\n // === Option-gated ===\n {\n // v26.39.2 fix — marketplace name = \"trailofbits\" (NOT \"trailofbits-skills\") +\n // \"trailofbits-skills\" plugin 자체가 존재하지 않음. marketplace 안에 14+ 개별 plugin.\n // 단일 대표 plugin = `differential-review` (코드 변경 보안 리뷰, 가장 보편).\n // 추가 plugin 원하는 사용자는: `claude plugin install <name>@trailofbits` (예: audit-context-building)\n id: \"trailofbits-skills\",\n tier: \"vetted\", // trailofbits/skills 5.5k (CC-BY-SA — 출처 신뢰)\n description: \"Trail of Bits differential-review plugin (security-focused code review)\",\n category: \"dev-tools\",\n source: \"trailofbits\",\n condition: { kind: \"opt-in\" },\n method: {\n kind: \"plugin\",\n marketplace: \"trailofbits/skills\",\n pluginId: \"differential-review@trailofbits\",\n },\n },\n {\n id: \"ecc-plugin\",\n tier: \"vetted\", // affaan-m/everything-claude-code 199k\n description: \"ECC — 60 agents · 230 skills · 75 commands. Affaan's hackathon package\",\n category: \"ecc-suite\",\n source: \"affaan-m\",\n condition: { kind: \"opt-in\" },\n // v26.54.1 — upstream marketplace.json 의 name 은 \"ecc\" (plugin name 도 \"ecc\").\n // 기존 매핑 `everything-claude-code@everything-claude-code` 는 marketplace 가\n // 그 이름으로 등록되던 옛 버전 기준. fresh install 에서는 \"Plugin not found\" 발생.\n method: {\n kind: \"plugin\",\n marketplace: \"affaan-m/everything-claude-code\",\n pluginId: \"ecc@ecc\",\n },\n },\n {\n id: \"ecc-prune\",\n tier: \"official\", // uzys 본 하네스 자체\n description:\n \"ECC prune (drop items beyond curated 89 KEEP → copy to .claude/local-plugins/ecc/)\",\n category: \"ecc-suite\",\n source: \"uzys\",\n condition: { kind: \"option\", flag: \"withPrune\" },\n method: {\n kind: \"shell-script\",\n script: \"scripts/prune-ecc.sh\",\n args: [\"--apply\", \"--force\"],\n },\n },\n];\n\n/**\n * v26.87.0 — dev-method skill ids (uzys 1st-party, internal templates). installer 의\n * `selectedInternalSkills` 계산 + manifest copy 게이팅 + 테스트가 공유하는 SSOT.\n * 각 id 는 method.kind===\"internal\" 이며 `templates/skills/<id>/SKILL.md` 로 번들된다.\n *\n * 2026-08-02 복원 (ADR-062) — 이관(ADR-060)으로 1종까지 줄었던 목록이 6종으로 돌아왔다.\n * 멤버십 기준은 **`condition.kind === \"has-dev-track\"` 인 번들 방법론 스킬**이다 (그 불변식을\n * `tests/external-assets.test.ts` 가 단언한다). 전 트랙(any-track)·opt-in 번들 스킬은 여기\n * 들어오지 않는다 — 조건이 섞이면 wizard 번들이 부분집합이 되어 사용자가 안 고른 자산을\n * 설치한다 (`tests/wizard-bundle.test.ts` 의 recommended ∩ members ∈ {∅, 전체}).\n * 현재 dev-method skills 6종.\n */\nexport const DEV_METHOD_SKILL_IDS: ReadonlyArray<string> = [\n \"compaction-handoff\",\n \"clear-korean-communication\",\n \"audit-service-gaps\",\n \"multi-persona-review\",\n \"recurrence-prevention\",\n \"verification-loop\",\n];\n\n/**\n * v26.95.0 — ALL repo-bundled internal skill ids (dev-method + opt-in advisors). Bundling is\n * condition-agnostic: manifest Claude dir-copy, the 3 non-Claude CLI transforms, and\n * gen-compatibility iterate THIS superset so every bundled skill renders across CLIs; each entry's\n * `condition` (has-dev-track vs opt-in) still gates whether it actually installs. Kept separate\n * from `DEV_METHOD_SKILL_IDS` so \"dev-method\" keeps meaning the has-dev-track methodology skills.\n *\n * 2026-08-02 복원 (ADR-062) — superset 이 다시 진부분집합이 됐다. dev-method 6종에 더해\n * 전 트랙 2종(north-star·gh-issue-workflow)과 opt-in 2종(model-orchestration·\n * external-model-consult)이 번들이다. 이 4종은 `DEV_METHOD_SKILL_IDS` 의 has-dev-track\n * 불변식을 깨거나(전자) wizard 번들을 부분집합으로 만들기(후자) 때문에 여기에만 있다.\n */\nexport const INTERNAL_BUNDLED_SKILL_IDS: ReadonlyArray<string> = [\n ...DEV_METHOD_SKILL_IDS,\n \"north-star\",\n \"gh-issue-workflow\",\n \"task-brief\",\n \"audit-harness-fit\",\n \"model-orchestration\",\n \"external-model-consult\",\n];\n\n/**\n * v26.79.0 — `TRUST_TIER` 는 EXTERNAL_ASSETS.tier 에서 derive (단일 출처). 별도 Record 유지 시\n * 누락/stale drift 가능 → 제거. 기존 소비자(prompts.ts·gen-compatibility·trust-tier-drift)는\n * 이 derived map 을 그대로 import. id 키는 각 자산 id 와 1:1 (자산 추가 시 자동 반영).\n */\nexport const TRUST_TIER: Record<string, TrustTier> = Object.fromEntries(\n EXTERNAL_ASSETS.map((a) => [a.id, a.tier]),\n);\n\n/** 자산의 검증 tier. 미분류(catalog 외 id)는 보수적으로 experimental. */\nexport function assetTrustTier(assetId: string): TrustTier {\n return TRUST_TIER[assetId] ?? \"experimental\";\n}\n\n/**\n * v26.47.0 — User override of preset/option condition (Phase C full, SPEC §3.1).\n * - `forceInclude`: condition 무관 강제 포함 (사용자가 명시 추가)\n * - `forceExclude`: condition 무관 강제 제외 (사용자가 추천 ✓ 풀음)\n *\n * 우선순위: `forceExclude` > `forceInclude` > `condition`.\n */\nexport interface UserOverride {\n forceInclude: ReadonlyArray<string>;\n forceExclude: ReadonlyArray<string>;\n}\n\n/**\n * 조건 평가 — 주어진 spec(tracks + options + userOverride)에서 자산이 설치 대상인지 판정.\n */\nexport function shouldInstallAsset(\n asset: ExternalAsset,\n ctx: {\n tracks: ReadonlyArray<Track>;\n options: OptionFlags;\n userOverride?: UserOverride;\n },\n): boolean {\n // v26.47.0 — userOverride 우선순위: forceExclude > forceInclude > condition.\n if (ctx.userOverride?.forceExclude.includes(asset.id)) return false;\n if (ctx.userOverride?.forceInclude.includes(asset.id)) return true;\n // v26.71.1 — experimental(T3) opt-in only (PRD v26-71 R6/AC4). condition 매치만으론 미설치.\n // --with <id> (forceInclude) 또는 interactive 체크(→forceInclude) 시에만 설치 — 선택권 유지(강제 차단 아님).\n // v26.71.0 은 recommendedExternalAssets(pre-check)에만 제외 적용 → 비대화형/미체크 install 경로 누락 버그 fix.\n // 게이트는 명시 분류(TRUST_TIER[id])만 본다 — assetTrustTier()의 unknown→experimental default 는\n // DISPLAY(경고 배지)용이며 설치 게이트엔 미적용. 실 자산 전부 매핑은 \"no-missing\" 테스트가 강제(AC1).\n if (TRUST_TIER[asset.id] === \"experimental\") return false;\n return matchesCondition(asset, ctx);\n}\n\n/**\n * Track/option condition 매치만 평가 (tier·override 무관). shouldInstallAsset 의 조건절 +\n * experimentalOptInCandidates 의 \"조건은 맞지만 T3\" 판정에서 공유 (SSOT).\n */\nfunction matchesCondition(\n asset: ExternalAsset,\n ctx: { tracks: ReadonlyArray<Track>; options: OptionFlags },\n): boolean {\n const cond = asset.condition;\n switch (cond.kind) {\n case \"any-track\":\n return ctx.tracks.some((t) => cond.tracks.includes(t));\n case \"has-dev-track\":\n // SSOT — track-match.ts hasDevTrack(): csr-*|ssr-*|data|full|tooling (= DEV_TRACKS).\n // EXECUTIVE_STYLE_TRACKS (executive + project-management + growth-marketing) 는 제외.\n return hasDevTrack(ctx.tracks);\n case \"option\":\n return ctx.options[cond.flag] === true;\n case \"opt-in\":\n // v26.81.0 (ADR-022) — 순수 opt-in: condition 으론 절대 설치 안 됨.\n // forceInclude(wizard 체크 / --with <id>)가 shouldInstallAsset 상위에서 처리.\n return false;\n }\n}\n\n/**\n * v26.81.0 (ADR-022) — spec 에서 특정 자산의 선택 여부 판정.\n * 내부 자산(tauri-desktop)의 manifest/transform 게이팅이 이전\n * `spec.options.withTauri` 등 boolean 자리를 대체해 호출. (wizard 체크/--with 는\n * forceInclude 로 들어오므로 shouldInstallAsset 가 그대로 판정)\n */\nexport function isAssetSelected(\n assetId: string,\n ctx: {\n tracks: ReadonlyArray<Track>;\n options: OptionFlags;\n userOverride?: UserOverride;\n },\n): boolean {\n const asset = EXTERNAL_ASSETS.find((a) => a.id === assetId);\n return asset ? shouldInstallAsset(asset, ctx) : false;\n}\n\n/**\n * v26.71.1 — track/option condition 은 매치하지만 T3(experimental)라서 default 설치에서 제외된 자산.\n * forceInclude(--with / interactive 체크)된 것은 이미 설치되므로 제외. 비대화형 install 의\n * discoverability 힌트용 (Transparent Defaults — 숨김 0건. --with 로 opt-in 가능함을 사용자에게 알림).\n */\nexport function experimentalOptInCandidates(ctx: {\n tracks: ReadonlyArray<Track>;\n options: OptionFlags;\n userOverride?: UserOverride;\n}): ReadonlyArray<ExternalAsset> {\n return EXTERNAL_ASSETS.filter(\n (a) =>\n TRUST_TIER[a.id] === \"experimental\" &&\n !ctx.userOverride?.forceInclude.includes(a.id) &&\n matchesCondition(a, ctx),\n );\n}\n\n/**\n * spec에 적용 가능한 자산 필터.\n */\n/**\n * v26.102.0 (ADR-031, Batch3) — 자산의 CLI 도달 범위. 별도 필드가 아니라 method.kind 에서\n * **derive** 한다: 도달 범위의 SSOT 는 installOne 의 실동작이며, 같은 사실을 entry 필드로\n * 중복 기입하면 kind 와 필드가 어긋나는 drift 가 가능해진다 (no-false-ship \"동일 목록 2곳\n * 하드코딩 금지\").\n * - plugin: installPlugin 이 `claude plugin marketplace/install` 을 spawn — 구조적 claude 전용\n * - shell-script: ecc-prune 이 `.claude/local-plugins/` 에 write — claude 전용\n * - skill: skills CLI 가 `--agent` 매핑(SKILLS_CLI_AGENT_MAP)으로 선택 CLI 전부에 설치\n * - npm/npx-run: 프로젝트 레벨 (CLI 무관)\n * - internal: Phase 1 manifest/transform 이 CLI 별 렌더 (external spawn 단계 미도달)\n */\nexport function assetCliSupport(asset: ExternalAsset): CliTargets {\n // v26.102.0 SOD 리뷰 Critical-1 — kind 기본값이 거짓인 자산(bmad `--tools claude-code`)은\n // entry 의 cliSupportOverride 가 우선한다.\n if (asset.cliSupportOverride) {\n return [...asset.cliSupportOverride];\n }\n switch (asset.method.kind) {\n case \"plugin\":\n case \"shell-script\":\n return [\"claude\"];\n case \"skill\":\n case \"npm\":\n case \"npx-run\":\n case \"internal\":\n // 공유 배열 원본 대신 사본 반환 — 타입 없는 소비자(gen-compatibility.mjs)의\n // in-place sort 가 CLI_BASES 를 전역 변형하는 사고 차단 (불변성 rule).\n return [...CLI_BASES];\n }\n}\n\n/**\n * 선택 CLI 와 자산 도달 범위의 교집합 여부. `cli` 가 빈 배열이면 레거시 관례\n * (buildSkillArgs 등 \"미지정 = 전체\")를 따라 필터하지 않는다.\n */\nexport function assetReachesCli(asset: ExternalAsset, cli: CliTargets): boolean {\n if (cli.length === 0) {\n return true;\n }\n const support = assetCliSupport(asset);\n return cli.some((c) => support.includes(c));\n}\n\nexport function filterApplicableAssets(\n assets: ReadonlyArray<ExternalAsset>,\n ctx: {\n tracks: ReadonlyArray<Track>;\n options: OptionFlags;\n userOverride?: UserOverride;\n },\n): ReadonlyArray<ExternalAsset> {\n return assets.filter((a) => shouldInstallAsset(a, ctx));\n}\n","import type { Track } from \"./types.js\";\n\n/** Match a track against a glob-style pattern (bash-compatible: `csr-*`, `csr-*|full`). */\nexport function matchTrack(track: Track, pattern: string): boolean {\n return pattern.split(\"|\").some((p) => globToRegex(p.trim()).test(track));\n}\n\nexport function anyTrack(tracks: ReadonlyArray<Track>, pattern: string): boolean {\n return tracks.some((t) => matchTrack(t, pattern));\n}\n\nexport function hasDevTrack(tracks: ReadonlyArray<Track>): boolean {\n // Dev tracks = anything that is NOT executive AND NOT tooling-only-meta.\n // Mirrors setup-harness.sh has_dev_track: csr-*, ssr-*, data, full, tooling.\n return anyTrack(tracks, \"csr-*|ssr-*|data|full|tooling\");\n}\n\nexport function hasUiTrack(tracks: ReadonlyArray<Track>): boolean {\n return anyTrack(tracks, \"csr-*|ssr-*|full\");\n}\n\n/** Convert a bash glob (only `*` is supported) to a strict-anchored RegExp. */\nfunction globToRegex(pattern: string): RegExp {\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\*/g, \".*\");\n return new RegExp(`^${escaped}$`);\n}\n","import { INTERNAL_BUNDLED_SKILL_IDS } from \"./external-assets.js\";\nimport { INSTALL_LOG_DIR } from \"./install-log.js\";\nimport { HARNESS_ANCHOR_FILE } from \"./project-claude-merge.js\";\nimport { anyTrack, hasDevTrack, hasUiTrack } from \"./track-match.js\";\nimport { TRACKS, type Track } from \"./types.js\";\n\n/**\n * Source-relative paths under `templates/` map to project-relative targets under\n * the project root (typically `.claude/...` or `CLAUDE.md`).\n *\n * Each entry declares an `applies(spec)` predicate based on the selected tracks.\n * Phase C scope: rules + commands + agents + base skills + hooks + project CLAUDE.md.\n * Phase E will extend with the remaining track-specific skills.\n */\n\nexport interface AssetSpec {\n /** Selected tracks (union). */\n tracks: ReadonlyArray<Track>;\n /**\n * Optional opt-in: --with-tauri.\n * Note: copied from `OptionFlags.withTauri` by installer; keep both fields in sync\n * when adding new opt-in flags that affect manifest gating.\n *\n * 2026-08-02 정비 — `tauri` **룰**이 배포에서 빠져 이 필드를 읽는 게이팅은 현재 없다.\n * 필드를 남긴 이유는 `tauri-desktop` 자산 선택 자체는 살아 있고(installer 가 여전히 채운다)\n * 트랙×opt-in 곱을 도는 게이트들이 이 축을 그대로 쓰기 때문이다.\n */\n withTauri?: boolean;\n /**\n * v26.58.0 — withEcc opt-out gating (BREAKING vs v26.55.0). ADR-019 supersedes ADR-016 부분.\n * Note: copied from `OptionFlags.withEcc` by installer; keep both fields in sync.\n *\n * 정책 (cherry-pick × plugin gating):\n * - C1 (단순 중복): 매핑 자체 삭제.\n * - C2 (plugin OFF fallback): `applies: (s) => !s.withEcc && <track>`.\n * - C3 (modified or 별개 source): `applies: <track only>` (withEcc 무관 항상 install).\n *\n * **개수를 여기 적지 않는다** — 주석의 숫자는 두 번째 사본이라 썩는다 (#340 에서 실제로\n * 19/3 이 실측과 어긋나 있었다). 그리고 **`_ECC` 접미 목록을 세는 것으로는 C2 가 안 나온다**:\n * 이 파일의 `buildManifest` 안에는 목록 없이 인라인 `applies` 로 `!s.withEcc` 를 붙인 엔트리가\n * 따로 있어(#340 에서 추가), 목록만 세면 그만큼 모자란다.\n * C2 의 모집단은 **`buildManifest` 를 withEcc on/off 로 두 번 만들어 `applies()` 통과 대상을\n * diff** 해서 얻는다 — 조건식을 읽는 대신 결과를 재는 이 방법이 인라인 게이트까지 포함한다.\n * C3 는 `MODIFIED_ECC_SKILL_DIRS`. `tests/vnv-verdict.test.ts` 가 같은 방법으로 양방향 정합을\n * 문다.\n *\n * 분류 표 SSOT: docs/PRD/v26-58-cherry-pick-plugin-gating.md §6.\n */\n withEcc?: boolean;\n /**\n * v26.87.0 — 선택된 내부 dev-method skill id 집합 (uzys 1st-party, repo-bundled).\n * installer 가 `DEV_METHOD_SKILL_IDS` 를 `isAssetSelected` 로 필터해 채운다 — 즉\n * track(has-dev-track) 기본 + wizard uncheck / `--without <id>` (forceExclude) 반영.\n * buildManifest 의 skill-dir copy 가 이 목록에 포함된 id 만 게이팅한다.\n */\n selectedInternalSkills?: ReadonlyArray<string>;\n}\n\nexport interface AssetEntry {\n source: string; // relative to repo `templates/`\n target: string; // relative to project root\n type: \"file\" | \"dir\";\n applies: (spec: AssetSpec) => boolean;\n}\n\nconst all = (): boolean => true;\nconst dev = (s: AssetSpec): boolean => hasDevTrack(s.tracks);\nconst ui = (s: AssetSpec): boolean => hasUiTrack(s.tracks);\nconst onTracks =\n (pattern: string) =>\n (s: AssetSpec): boolean =>\n anyTrack(s.tracks, pattern);\n\n// v26.107.0 (ADR-036, 라이프사이클 자산화 ①) — doc-governance: SSOT 위계 + \"merge = 코드 +\n// 추적 동기화\" 의무. 실무 관행의 일반화. 문서 규약은 전 트랙 공통.\n// 2026-08-02 정비 ② — `gates-taxonomy` 제거. 게이트 4유형(Pre-flight/Revision/Escalation/Abort)은\n// 모델이 이미 아는 분류였고, 설치자가 받아 가는 것은 판정이 아니라 어휘표였다.\nconst COMMON_RULES = [\"git-policy\", \"change-management\", \"doc-governance\"];\nconst DEV_RULES = [\"test-policy\", \"ship-checklist\"];\n// 2026-08-04 (#284) — `benchmark-parity` 제거. 그 룰이 담고 있던 것은 gap.md 표 스키마 · PR\n// 의무 필드 · dogfood walkthrough 절차였다. 전부 **그 작업을 할 때만** 필요한 절차인데 매\n// 세션 상주했다.\n// 2026-08-12 — `playwright-launch` 제거(사용자 결정). 남은 것은 브라우저 금지문이었는데,\n// 그 룰 본문이 스스로 \"절차는 `ui-visual-review` 스킬이 SSOT\" 라고 적고 있었다. 금지와 절차가\n// 한 자리에 있는 편이 낫다고 판단해 스킬로 합쳤고, 발화가 늦는 위험은 스킬 description 이\n// \"브라우저를 여는 어떤 방법이든 그 전에 읽어라\"로 흡수한다. UI 트랙 전용 룰은 이제 없다.\nconst UI_RULES: string[] = [];\n\n// 2026-08-02 정비 — 기술스택 상세 룰(shadcn·nextjs·htmx·pyside6·database·api-contract·\n// data-analysis·tauri)을 배포에서 뺐다. 모델이 이미 아는 것을 상주로 부담시키던 자리다.\n// 남은 트랙 매핑은 `cli-development` 하나뿐 — 그래도 표를 유지하는 이유는 트랙별 룰이라는\n// 축 자체는 살아 있고, 배열을 없애면 다음에 트랙 룰을 넣을 자리가 사라지기 때문이다.\nconst TRACK_RULES: Record<Track, string[]> = {\n \"csr-supabase\": [],\n \"csr-fastify\": [],\n \"csr-fastapi\": [],\n \"ssr-htmx\": [],\n \"ssr-nextjs\": [],\n data: [],\n executive: [],\n tooling: [\"cli-development\"],\n full: [\"cli-development\"],\n // v0.5.0 — executive-style baselines (no dev rules; common rules only).\n \"project-management\": [],\n \"growth-marketing\": [],\n};\n\n/** Resolve the unique set of rule names to install for the given spec. */\nexport function resolveRules(spec: AssetSpec): string[] {\n const set = new Set<string>(COMMON_RULES);\n if (hasDevTrack(spec.tracks)) {\n for (const r of DEV_RULES) {\n set.add(r);\n }\n }\n if (hasUiTrack(spec.tracks)) {\n for (const r of UI_RULES) {\n set.add(r);\n }\n }\n for (const t of spec.tracks) {\n for (const r of TRACK_RULES[t]) {\n set.add(r);\n }\n }\n return [...set].sort();\n}\n\n/**\n * 모든 트랙의 룰 union — `update` 가 쓴다. 전부 넘기고 \"이 프로젝트에 뭐가 깔렸나\"는\n * `refreshOnly` 가 디스크로 대신 판정한다 (`ALL_CLI_TARGETS` · `INTERNAL_BUNDLED_SKILL_IDS` 와\n * 같은 형태). `resolveRules` 에서 파생하므로 룰이 늘거나 줄어도 여기를 고칠 필요가 없다.\n */\nexport const ALL_RULES: ReadonlyArray<string> = resolveRules({ tracks: [...TRACKS] });\n\n// v26.58.0 — ECC cherry-pick × plugin gating. ADR-019.\n// 본 프로젝트 (always): reviewer, data-analyst, strategist\n// ECC cherry-pick C2 (plugin OFF 시 fallback — opt-out gating, !s.withEcc):\n// code-reviewer, security-reviewer, silent-failure-hunter, build-error-resolver\nconst CORE_AGENTS = [\"reviewer\", \"data-analyst\", \"strategist\"];\nconst CORE_AGENTS_ECC = [\"code-reviewer\", \"security-reviewer\"];\n\n// v26.138.0 — implementer: 구현 레인. 기존 에이전트 8종이 전부 검토·검증·도메인 특화라\n// 설치자는 \"코드를 볼 사람\"만 받고 \"쓸 사람\"은 못 받았다. 근거 = 두 코퍼스 실측 대조에서\n// 서브에이전트 코드 Edit 433 vs 3 — 규율 차이가 아니라 **레인 부재**였다.\nconst DEV_AGENTS = [\"plan-checker\", \"implementer\"];\nconst DEV_AGENTS_ECC = [\"silent-failure-hunter\", \"build-error-resolver\"];\n\n/**\n * Hooks installed for every project (parity with setup-harness.sh L815-826).\n *\n * 2026-08-02 정비 — `spec-drift-check.sh` 제거. 산문(doc-governance·ship-checklist)은 이것을\n * 차단 게이트로 적었지만 실제로는 어디에도 배선돼 있지 않았고(`templates/settings.json` 미참조),\n * 미완 체크박스가 쌓인 상태에서도 `ship` 모드가 exit 0 이었다 — 즉 설치자가 매 프로젝트에서\n * 받아 가는 것은 게이트가 아니라 게이트라는 **이름**이었다.\n *\n * 2026-08-02 정비 ② — `checkpoint-snapshot.sh` 제거. 같은 형태의 다른 결말이다: 배선이 없어\n * (`\"PostToolUse\": []`) 설치는 되고 **실행은 0** 이었다. 안 도는 훅은 실패 증상이 없어 프로즈로는\n * 못 잡는다 — 재발은 `tests/hook-wiring-parity.test.ts` 가 양방향으로 문다.\n *\n * 2026-08-16 정비 ③ — `mcp-pre-exec.sh` 제거(ADR-072). 앞의 둘과 달리 이건 **돌고 있었고 잘\n * 돌았다** — 지운 이유가 배선이 아니라 목적이다. 이 하네스가 파는 것은 \"사용자가 AI 코딩 도구로\n * 개발을 잘하게 만드는 것\"인데, MCP 서버를 새로 붙이는 순간 차단하는 훅은 그 반대로 작동한다\n * (판정 기준 = 루트 `CLAUDE.md` §판정은 목적에서 시작한다). 결정론적으로 구현됐다는 사실은\n * 목적 적합성의 증거가 아니다.\n */\nexport const ALWAYS_HOOKS = [\n \"session-start.sh\",\n \"protect-files.sh\",\n // UserPromptSubmit 넛지. 차단하지 않는 유일한 훅 — 판정은 결정적 두 조건뿐이고(길이 ·\n // `<objective>` 표식 부재) 변환 자체는 `task-brief` 스킬 몫이다. `templates/settings.json`\n // 배선과 한 벌 (hook-wiring-parity 가 한쪽만 있는 상태를 문다).\n \"task-brief-nudge.sh\",\n];\n\n// v26.58.0 — ECC cherry-pick × plugin gating. ADR-019.\n// 2026-08-02 정비 (ADR-060) — north-star · gh-issue-workflow 는 uzysjung/uzys-agent-skills 로\n// 이관돼 카탈로그 엔트리(`kind: \"skill\"`)가 됐다. 전 트랙 도달 범위는 그 엔트리의\n// `any-track: 전 트랙` condition 이 이어받는다 (강등 아님).\nconst COMMON_SKILL_DIRS: string[] = [];\n// C2 (plugin OFF fallback, opt-out).\n// v26.121.0 — continuous-learning-v2 가 C3 → C2. 우리 판본이 upstream 에서 agents/(관측을\n// instinct 로 바꾸는 분석기)를 뺀 진부분집합이었고, 그래서 \"plugin 으로 갈음 불가\"라는 C3 근거가\n// 뒤집혀 있었다 — 갈음 불가의 내용이 기능 제거였다. upstream 전체를 복원해 동일해졌으므로\n// (lock modified:false) plugin ON 이면 비켜서는 것이 맞다. 데몬은 upstream 기본값대로 꺼져 있다\n// (config.json observer.enabled=false) — 켜면 백그라운드에서 claude 를 주기 호출하므로 사용자 선택.\n// #340 — strategic-compact 은 lock 에서 `modified:true` 지만 **C2 로 두는 것이 의도**다.\n// `modified` 는 `sync-cherrypicks.sh --apply` 의 덮어쓰기 방지 플래그이지 설치 게이팅이 아니다.\n// ECC 를 고르면 이 디렉터리가 안 깔리고, 그때 `settings.json` 이 남기는 훅 참조는 install 의\n// 치유 패스가 지운다(M-1, `tests/installer.test.ts` 가 문다). 두 축을 같은 것으로 읽으면\n// 이 결정이 사고로 보인다 — 그래서 아래 게이트에 예외로 **이름을 적어** 둔다.\nconst COMMON_SKILL_DIRS_ECC = [\"strategic-compact\", \"continuous-learning-v2\"];\n// C3 (modified=true — plugin 으로 갈음 불가, 항상 install). deep-research = v26.114.0\n// 리서치 원장(confirmed/killed + caveat) 주입, ADR-042.\nconst MODIFIED_COMMON_SKILL_DIRS = [\"deep-research\"];\n\nconst DEV_SKILL_DIRS: string[] = [];\nconst DEV_SKILL_DIRS_ECC = [\"agent-introspection-debugging\"];\n// C3 (modified=true): plugin 으로 갈음 불가, dev 트랙 항상 install.\n// eval-harness = v26.114.0 eval spec 아티팩트 계약(C·R ID·baseline·Test Command·Status, ADR-042).\n// 2026-08-02 정비 (ADR-060) — verification-loop 은 C3 계약을 해체했다: 우리 판본이\n// uzysjung/uzys-agent-skills 로 이관돼 더는 ECC 파생 번들이 아니다. cherrypicks.lock 의\n// `ecc-verification-loop` 행도 함께 제거 — lock 과 이 목록은 1:1 이어야 한다(아래 주석).\nconst MODIFIED_DEV_SKILL_DIRS = [\"eval-harness\"];\n\n/**\n * C3 로 분류된 ECC cherry-pick 스킬 전체 (수정본 — plugin 으로 갈음 불가).\n * `.dev-references/cherrypicks.lock` 의 `modified: true` 와 1:1 이어야 한다 — lock 이\n * false 로 남으면 `sync-cherrypicks.sh --apply` 의 rsync --delete 가 로컬 수정을 조용히\n * 덮어쓴다. 정합은 tests/vnv-verdict.test.ts 가 강제한다. ADR-041.\n */\nexport const MODIFIED_ECC_SKILL_DIRS = [...MODIFIED_COMMON_SKILL_DIRS, ...MODIFIED_DEV_SKILL_DIRS];\n\nconst UI_SKILL_DIRS = [\"ui-visual-review\"];\nconst UI_SKILL_DIRS_ECC = [\"e2e-testing\"];\n\n// python-* skills (data|csr-fastapi|full) — C2 (plugin OFF fallback).\nconst PYTHON_SKILL_DIRS_ECC = [\"python-patterns\", \"python-testing\"];\n\n/**\n * CLI 중립 자산인가 — `.uzys-agent-harness/` 아래는 4개 CLI 와 사람이 함께 쓰는 슬롯이다\n * (install log 와 같은 디렉터리, ADR-050). claude 를 고르지 않은 설치에도 이 자산들은 깔린다.\n *\n * 접두사에서 derive 하는 이유: 대상 목록을 두 번 적으면 그 사본이 다음 drift 서식지가 된다.\n * 아래 두 entry 의 주석이 이미 \"CLI 중립 슬롯\"이라 적고 있었는데 배선만 그러지 못했다.\n */\nexport function isCliNeutralTarget(target: string): boolean {\n return target.startsWith(`${INSTALL_LOG_DIR}/`);\n}\n\n/** Build the full asset manifest for the given spec. */\nexport function buildManifest(spec: AssetSpec): AssetEntry[] {\n const m: AssetEntry[] = [];\n\n // Rules\n for (const r of resolveRules(spec)) {\n m.push({\n source: `rules/${r}.md`,\n target: `.claude/rules/${r}.md`,\n type: \"file\",\n applies: all,\n });\n }\n\n // 2026-08-16 — `commands/ecc` 8종 삭제 (ADR-073). ADR-019 는 이것을 \"ECC 플러그인을 안 고른\n // 사람도 같은 명령을 쓰게\" 하는 opt-out 폴백으로 넣었는데, 8개 중 **2개**(`e2e`·`eval`)가\n // 플러그인 에이전트(`everything-claude-code:*`)를 직접 불러 폴백 상황에서 아예 못 돌았다.\n // 나머지 6개는 돌았지만 플러그인이 여섯을 모두 제공하므로 폴백을 기본값에 둘 이유가 없다.\n // 2026-08-18 정정(#338) — 이 주석과 ADR-073 Context 는 \"5개가 안 고른 자산을 가리킨다\"로\n // 적고 있었다. `evolve`·`instinct-status`·`promote` 가 부르는 `continuous-learning-v2` 는\n // 바로 아래 `COMMON_SKILL_DIRS_ECC` 항목이라 **같은 `!s.withEcc` 조건으로 함께 깔린다** —\n // \"별도 opt-in 스킬이라 대개 없다\"가 틀렸다. 결정은 유지, 숫자만 정정.\n //\n // `ecc-prune` 은 남는다 — 그쪽은 ECC 를 **고른 사람**의 설치를 최적화하는 opt-in 이라 방향이\n // 반대다(사용자 확정 2026-08-16).\n\n // 하네스 앵커 — **프로젝트 루트**에 하네스 소유 파일로 나간다 (P5 · ADR-060).\n // 루트 `CLAUDE.md` 는 사용자 것이고, 거기엔 이 파일을 끌어오는 `@import` 한 줄만 들어간다\n // (`project-claude-merge.ts` upsertHarnessImport). 파일명은 그 모듈이 SSOT.\n m.push({\n source: \"CLAUDE.md\",\n target: HARNESS_ANCHOR_FILE,\n type: \"file\",\n applies: all,\n });\n\n // Server-side git guards. Target is CLI-neutral on purpose — a repository rule protects the\n // default branch for every CLI and every human at once, so it does not belong under `.claude/`.\n // Same directory as the install log (ADR-050), which is already the CLI-agnostic slot.\n m.push({\n source: \"scripts/protect-branch.sh\",\n target: \".uzys-agent-harness/protect-branch.sh\",\n type: \"file\",\n applies: all,\n });\n\n // SPEC/TODO drift 탐지기. **훅이 아니라 명시 호출 스크립트다** — 자동 발화 경로가 없는 것이\n // 정직한 상태이고(옛 훅 판본이 죽은 이유가 배선 없는 훅 라벨이었다), 호출 지점은 배포판 룰\n // 둘이 적는다: ship-checklist 의 SPEC/PRD 정합성 항목(exit 2 = 차단) · doc-governance 검증\n // 게이트 절. 타깃은 protect-branch 와 같은 CLI 중립 슬롯 — 문서 drift 는 4개 CLI 와 사람이\n // 함께 보는 관심사라 `.claude/` 아래가 아니다.\n m.push({\n source: \"scripts/spec-drift-check.sh\",\n target: \".uzys-agent-harness/spec-drift-check.sh\",\n type: \"file\",\n applies: all,\n });\n\n // 부정 결론(\"없다\"·\"안 된다\")의 대조군 강제기. 룰 `cli-development` 이 세 규약을 프로즈로 적고\n // 있었는데 같은 실수가 계속 났다 — 프로즈는 사람이 매번 기억해야 하고, 기억해야 하는 규약은\n // 규약이 아니다. 타깃이 CLI 중립 슬롯인 이유는 protect-branch·spec-drift-check 과 같다:\n // 검증 규율은 4개 CLI 와 사람이 함께 쓰는 관심사라 `.claude/` 아래가 아니다.\n m.push({\n source: \"scripts/check-absence.sh\",\n target: \".uzys-agent-harness/check-absence.sh\",\n type: \"file\",\n applies: all,\n });\n\n // Agents (본 프로젝트)\n for (const a of CORE_AGENTS) {\n m.push({\n source: `agents/${a}.md`,\n target: `.claude/agents/${a}.md`,\n type: \"file\",\n applies: all,\n });\n }\n for (const a of DEV_AGENTS) {\n m.push({\n source: `agents/${a}.md`,\n target: `.claude/agents/${a}.md`,\n type: \"file\",\n applies: dev,\n });\n }\n // v26.58.0 — Agents (ECC cherry-pick). ADR-019. C2: plugin OFF 시만 install (opt-out).\n for (const a of CORE_AGENTS_ECC) {\n m.push({\n source: `agents/${a}.md`,\n target: `.claude/agents/${a}.md`,\n type: \"file\",\n applies: (s) => !s.withEcc,\n });\n }\n for (const a of DEV_AGENTS_ECC) {\n m.push({\n source: `agents/${a}.md`,\n target: `.claude/agents/${a}.md`,\n type: \"file\",\n applies: (s) => !s.withEcc && hasDevTrack(s.tracks),\n });\n }\n\n // Common skill directories\n for (const sd of COMMON_SKILL_DIRS) {\n m.push({\n source: `skills/${sd}`,\n target: `.claude/skills/${sd}`,\n type: \"dir\",\n applies: all,\n });\n }\n // v26.58.0 — Common skill dirs (ECC cherry-pick). ADR-019. C2: plugin OFF 시만 install (opt-out).\n for (const sd of COMMON_SKILL_DIRS_ECC) {\n m.push({\n source: `skills/${sd}`,\n target: `.claude/skills/${sd}`,\n type: \"dir\",\n applies: (s) => !s.withEcc,\n });\n }\n // v26.58.0 — C3 (modified=true). plugin 으로 갈음 불가, 항상 install. ADR-019.\n for (const sd of MODIFIED_COMMON_SKILL_DIRS) {\n m.push({\n source: `skills/${sd}`,\n target: `.claude/skills/${sd}`,\n type: \"dir\",\n applies: all,\n });\n }\n m.push({\n source: \"skills/spec-scaling/SKILL.md\",\n target: \".claude/skills/spec-scaling/SKILL.md\",\n type: \"file\",\n applies: all,\n });\n // #340 — 아래 4종은 `cherrypicks.lock` 에서 `modified:false`(= 우리가 안 고친 사본)인데\n // `!s.withEcc` 가 빠져 있었다. ECC 플러그인을 고른 사용자가 **같은 스킬을 두 판본** 받았고,\n // 어느 쪽이 로드되는지 예측할 수 없었다. C2 규칙(ADR-019)에 맞춘다.\n for (const sd of [\"market-research\", \"investor-materials\", \"investor-outreach\"]) {\n m.push({\n source: `skills/${sd}`,\n target: `.claude/skills/${sd}`,\n type: \"dir\",\n applies: (s) => !s.withEcc && onTracks(\"executive|full\")(s),\n });\n }\n m.push({\n source: \"skills/nextjs-turbopack\",\n target: \".claude/skills/nextjs-turbopack\",\n type: \"dir\",\n applies: (s) => !s.withEcc && onTracks(\"ssr-nextjs|full\")(s),\n });\n // v26.87.0 — internal bundled skills (uzys 1st-party templates: dev-method + opt-in advisors,\n // v26.95.0). Whole-dir copy so sidecar files ship too (e.g. gemini-consult/scripts/gemini-ask.sh).\n // Gated on `selectedInternalSkills` (installer computes it via isAssetSelected) — NOT track alone —\n // so a wizard uncheck / `--without <id>` drops the copy, and opt-in ones copy only when selected.\n for (const sd of INTERNAL_BUNDLED_SKILL_IDS) {\n m.push({\n source: `skills/${sd}`,\n target: `.claude/skills/${sd}`,\n type: \"dir\",\n applies: (s) => (s.selectedInternalSkills ?? []).includes(sd),\n });\n }\n // v26.58.0 — python-* / DEV_SKILL_DIRS / UI_SKILL_DIRS 중 ECC 출처는 opt-out gating. ADR-019. C2.\n for (const sd of PYTHON_SKILL_DIRS_ECC) {\n m.push({\n source: `skills/${sd}`,\n target: `.claude/skills/${sd}`,\n type: \"dir\",\n applies: (s) => !s.withEcc && anyTrack(s.tracks, \"data|csr-fastapi|full\"),\n });\n }\n for (const sd of DEV_SKILL_DIRS) {\n m.push({\n source: `skills/${sd}`,\n target: `.claude/skills/${sd}`,\n type: \"dir\",\n applies: dev,\n });\n }\n for (const sd of DEV_SKILL_DIRS_ECC) {\n m.push({\n source: `skills/${sd}`,\n target: `.claude/skills/${sd}`,\n type: \"dir\",\n applies: (s) => !s.withEcc && hasDevTrack(s.tracks),\n });\n }\n // C3 (modified=true). plugin 으로 갈음 불가 — verdict 어휘는 ECC plugin 판에 없다. ADR-041.\n for (const sd of MODIFIED_DEV_SKILL_DIRS) {\n m.push({\n source: `skills/${sd}`,\n target: `.claude/skills/${sd}`,\n type: \"dir\",\n applies: dev,\n });\n }\n for (const sd of UI_SKILL_DIRS) {\n m.push({\n source: `skills/${sd}`,\n target: `.claude/skills/${sd}`,\n type: \"dir\",\n applies: ui,\n });\n }\n for (const sd of UI_SKILL_DIRS_ECC) {\n m.push({\n source: `skills/${sd}`,\n target: `.claude/skills/${sd}`,\n type: \"dir\",\n applies: (s) => !s.withEcc && hasUiTrack(s.tracks),\n });\n }\n\n // Hooks\n for (const h of ALWAYS_HOOKS) {\n m.push({\n source: `hooks/${h}`,\n target: `.claude/hooks/${h}`,\n type: \"file\",\n applies: all,\n });\n }\n\n // settings.json\n m.push({\n source: \"settings.json\",\n target: \".claude/settings.json\",\n type: \"file\",\n applies: all,\n });\n\n // Project root CLAUDE.md — handled outside manifest by `mergeProjectClaude`\n // (single/multi/full tracks all merged from fragments in installer.ts).\n\n return m;\n}\n","/**\n * Install log — `.uzys-agent-harness/.harness-install.json`.\n *\n * v26.64.0 (ADR-020) — install 종료 시 자산 list + scope + timestamp 기록.\n * uninstall command 가 본 log 를 읽어 정확한 reverse 수행.\n *\n * 글로벌 자산 (scope=global 또는 codexOptIn) 은 log 에 안내용으로만 기록 — uninstall 시 자동 삭제 X (D16).\n */\n\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { ExternalAsset, ExternalAssetMethod } from \"./external-assets.js\";\nimport type { ExternalInstallReport } from \"./external-installer.js\";\nimport { listFilesRecursive } from \"./fs-ops.js\";\nimport type { InstallScope, InstallSpec } from \"./types.js\";\n\nexport const INSTALL_LOG_FILENAME = \".harness-install.json\";\n/**\n * v26.135.0 (#253 · ADR-050) — 설치 로그 디렉터리. **CLI 중립이라 CLI 디렉터리 밖에 둔다.**\n *\n * v26.134.1 까지는 `.claude/` 에 뒀는데, opencode/codex 단독 설치에서도 로그를 쓰려고\n * `.claude/` 를 만들어 버렸다 — 고르지 않은 CLI 의 디렉터리가 생기고, 그 안엔 로그 하나뿐이다.\n */\nexport const INSTALL_LOG_DIR = \".uzys-agent-harness\";\n/** v26.64.0 ~ v26.134.1 의 위치. 읽기 폴백 + 다음 write 때 1회 이관 대상. */\nexport const LEGACY_INSTALL_LOG_DIR = \".claude\";\nexport const INSTALL_LOG_VERSION = 1;\n\nexport interface InstallLogAsset {\n id: string;\n category: string;\n /** External asset method.kind 그대로. uninstall reverse 시 분기 기준. */\n method: ExternalAssetMethod[\"kind\"];\n /** scope=global 자산은 uninstall 시 안내만 (D16 — 글로벌 자동 삭제 금지). */\n scope: InstallScope;\n /** method 별 추가 정보. plugin: marketplace + pluginId. skill: source. npm: pkg. */\n detail: Record<string, string>;\n /** installed 시점 version (detectVersion 결과, 없으면 undefined). */\n version?: string;\n}\n\n/**\n * v26.124.0 (F-1f) — install 이 `.claude/` **밖**에 만들거나 고친 프로젝트 루트 파일.\n *\n * uninstall 은 이 목록을 **안내만 하고 지우지 않는다**. `.mcp.json`/`.gitignore` 에는 사용자\n * 내용이 섞이고, `.github/workflows/` 는 설치 후 사용자 소유물이기 때문 (ci-scaffold.ts 안전\n * 계약 2 · F-1d 와 같은 방침). 기록이 없으면 안내도 없다 — 그래서 install 이 적어 둔다.\n */\nexport interface InstallLogRootFile {\n /** project-relative 경로 (예: `.mcp.json`, `.github/workflows/ci.yml`) */\n path: string;\n /**\n * created = 하네스가 없던 파일을 만들었다 (내용 전부 하네스 것 → 손 안 댔으면 지워도 안전).\n * modified = 이미 있던 사용자 파일에 병합/추가했다 (직접 확인이 필요하다).\n */\n change: \"created\" | \"modified\";\n /** 무엇을 했는지 — uninstall 안내에 그대로 나온다. 재설치 시 합집합으로 누적된다. */\n notes: string[];\n}\n\n/**\n * v26.126.0 (R-3a · ADR-046) — `.claude/skills/` 안 파일 하나의 **설치 시점 기준선**.\n *\n * update 는 이 해시로 \"사용자가 고쳤는가\"를 판정한다. 기록이 없으면 판정이 불가능하고,\n * 그때는 내용 비교로 폴백해 보수적으로 백업한다 (ADR-046 파생규칙 3).\n */\nexport interface InstallLogSkillFile {\n /** `.claude/skills/` 기준 상대 경로 (예: `multi-persona-review/SKILL.md`) */\n path: string;\n /** 하네스가 그 자리에 놓아둔 내용의 sha256. 지금 디스크가 이것과 다르면 = 사용자가 고쳤다. */\n sha256: string;\n}\n\n/**\n * v26.132.0 (ADR-047) — update 가 동기화하는 정책 디렉터리. **이 목록이 SSOT 다.**\n *\n * `runUpdateMode` 의 동기화 대상과 `collectPolicyHashes` 의 기준선 범위가 같은 목록에서\n * 나와야 한다. 두 곳에 따로 적으면 한쪽에만 디렉터리가 추가됐을 때 조용히 갈리고, 그러면\n * **기준선 없는 디렉터리가 생겨 그 안의 파일이 전부 \"판정 불가\"로 떨어진다** — 이 repo 가\n * 반복해서 당한 \"열거 사본\" 실패 모드다 (`no-false-ship.md` \"게이트는 열거하지 말고 훑어라\").\n */\nexport const POLICY_DIRS = [\n { dir: \"rules\", ext: \".md\" },\n { dir: \"agents\", ext: \".md\" },\n { dir: \"commands/uzys\", ext: \".md\" },\n { dir: \"hooks\", ext: \".sh\" },\n] as const;\n\nexport interface InstallLog {\n /** schema version — backward compat 검출용 */\n schemaVersion: number;\n /** harness 가 install 한 시점 ISO timestamp */\n installedAt: string;\n /** 전체 install scope. 자산 per-asset scope 와 동일 (현재는 single global scope) */\n scope: InstallScope;\n /** install 시 spec 요약 (tracks/cli — uninstall reasoning 용) */\n spec: {\n tracks: ReadonlyArray<string>;\n cli: ReadonlyArray<string>;\n /**\n * 2026-08-16 (ADR-074) — 사용자가 위저드/`--without` 로 **해제한** 트랙 baseline 자산 id\n * (`baseline:<kind>/<name>`). 아무것도 안 뺐으면 필드 자체가 없다(기존 로그도 이 상태).\n *\n * **`update` 가 이걸 읽어야 해제가 유지된다.** 안 남기면 update 는 트랙에서 manifest 를\n * 다시 유도할 뿐이라 사용자가 뺀 룰·에이전트를 되살리고, 화면엔 *\"added by this release\"*\n * 라고 적는다 — 같은 릴리즈에서 방금 설치한 파일인데도. 독립 리뷰가 실측으로 잡았다.\n *\n * `tracks`·`cli` 와 같이 **누적하지 않는다**: install 은 매번 이 목록대로 다시 거르므로\n * 로그는 마지막 설치가 실제로 한 일이어야 한다. 제외 없이 다시 깔면 파일이 돌아오고,\n * 그때 기록이 남아 있으면 로그가 디스크와 다른 말을 한다.\n */\n baselineExclude?: ReadonlyArray<string>;\n };\n /** templates 출처 — uninstall 시 templates 제거 위치 */\n templates: {\n /** .claude/ project local */\n claudeDir: string;\n /** .codex/ project local (cli=codex 시) */\n codexDir?: string;\n /** .opencode/ project local (cli=opencode 시) */\n opencodeDir?: string;\n /**\n * project root CLAUDE.md (cli=claude 시 생성).\n * uninstall 시 sha256 이 install 시점과 동일할 때만 삭제 — 사용자가 수정했으면 보존.\n */\n rootClaudeMd?: { path: string; sha256: string };\n };\n /** external-installer 가 install 한 자산 (ok=true 만) */\n assets: ReadonlyArray<InstallLogAsset>;\n /**\n * v26.124.0 (F-1f) — `.claude/` 밖 루트 파일. 건드린 게 없으면 필드 자체가 없다\n * (v26.123.0 이하 로그도 이 상태 — 읽는 쪽은 부재를 정상으로 다뤄야 한다).\n */\n rootFiles?: ReadonlyArray<InstallLogRootFile>;\n /**\n * v26.126.0 (R-3a · ADR-046) — 스킬 파일 기준선 해시. 스킬을 안 깔았으면 필드 자체가 없다\n * (v26.125.0 이하 로그도 이 상태 — 읽는 쪽은 부재를 정상으로 다뤄야 한다).\n */\n skillFiles?: ReadonlyArray<InstallLogSkillFile>;\n /**\n * v26.132.0 (ADR-047) — 정책 파일(rules/agents/commands/hooks) 기준선 해시.\n * 경로는 `.claude/` 상대 (예: `rules/git-policy.md`).\n *\n * 두 가지를 판정한다: ⓐ 덮어쓰기 전 \"사용자가 고쳤는가\" ⓑ prune 시 \"하네스가 깔았던 것인가\".\n * ⓑ 때문에 **부재를 \"전부 하네스 것\"으로 읽으면 안 된다** — 기록이 없으면 소유를 주장할 수\n * 없으므로 아무것도 지우지 않는다 (v26.131.x 이하 로그가 이 상태).\n */\n policyFiles?: ReadonlyArray<InstallLogSkillFile>;\n /**\n * v26.133.0 (ADR-048) — 외부 CLI 산출물 기준선. 경로는 **projectDir 상대**\n * (`AGENTS.md` · `.codex/hooks/session-start.sh` · `.agents/skills/<id>/SKILL.md` ·\n * `opencode.json` · `.opencode/commands/<id>.md`).\n *\n * `policyFiles` 와 달리 prune 판정에는 쓰지 않는다 — 외부 CLI 쪽은 삭제 경로 자체가 없다.\n * 덮어쓰기 전 \"사용자가 고쳤는가\" 하나만 판정한다. codex/opencode 를 안 깔았으면 필드가\n * 없다 (v26.132.x 이하 로그도 이 상태 — 부재는 정상이고, 그때는 보수적 백업으로 떨어진다).\n */\n externalFiles?: ReadonlyArray<InstallLogSkillFile>;\n}\n\n/**\n * external-installer 의 result 를 InstallLogAsset 으로 변환.\n * ok=false 자산은 제외 (실제 install 안 됨 → uninstall 대상 아님).\n */\nexport function buildAssetEntries(\n report: ExternalInstallReport | null,\n scope: InstallScope,\n): InstallLogAsset[] {\n if (!report) return [];\n return report.attempted\n .filter((r) => r.ok)\n .map((r) => assetToLogEntry(r.asset, scope, r.version));\n}\n\nfunction assetToLogEntry(\n asset: ExternalAsset,\n scope: InstallScope,\n version: string | undefined,\n): InstallLogAsset {\n const detail = methodDetail(asset.method);\n const entry: InstallLogAsset = {\n id: asset.id,\n category: asset.category,\n method: asset.method.kind,\n scope,\n detail,\n };\n if (version) entry.version = version;\n return entry;\n}\n\nfunction methodDetail(method: ExternalAssetMethod): Record<string, string> {\n switch (method.kind) {\n case \"plugin\":\n return { marketplace: method.marketplace, pluginId: method.pluginId };\n case \"skill\":\n return { source: method.source, ...(method.skill ? { skill: method.skill } : {}) };\n case \"npm\":\n return { pkg: method.pkg };\n case \"npx-run\":\n return { cmd: method.cmd, args: (method.args ?? []).join(\" \") };\n case \"shell-script\":\n return { script: method.script, args: method.args.join(\" \") };\n case \"internal\":\n // v26.81.0 (ADR-022) — Phase 1 manifest 가 설치 주체. external 단계에선 미기록이 정상.\n return { key: method.key };\n }\n}\n\n/**\n * install log 생성. `previous` 가 있으면 **누적**한다 (v26.123.0 — F-1a).\n *\n * install 은 이전에 설치한 것을 지우지 않는다. 그런데 로그는 매번 새로 만들어 덮어썼으므로,\n * 나중에 `install --with <id>` 를 한 번만 해도 1회차 자산이 기록에서 사라지고 **uninstall 이\n * 그걸 못 찾아 남긴다**. 디스크에는 남아 있는데 기록에는 없는 = 로그가 거짓이 되는 상태.\n *\n * 누적 대상은 uninstall 이 실제로 읽는 두 필드뿐이다 (`assets` · `templates`). `spec`(tracks/cli)은\n * 누적하지 않는다: `.claude/` 가 backup 으로 밀리는 설치(reinstall)에선 이전 트랙 파일이 실제로\n * 사라져 합집합이 거짓이 된다. 게다가 uninstall 은 `spec` 을 읽지 않는다 (표시용).\n *\n * `claudeDirMovedAside` = 이번 설치가 `.claude/` 를 backup 으로 rename 했는가. 그 경우\n * **`.claude/` 안에 살던 이전 자산은 실제로 사라졌으므로 누적에서 뺀다** — 안 빼면 F-1a 를\n * 반대 방향으로 재현한다(있지도 않은 걸 있다고 기록). 해당: project scope 의 `skill`\n * (`npx skills add` 가 `.claude/skills/` 에 설치) 와 `shell-script`(ecc-prune →\n * `.claude/local-plugins/`). plugin/npm 은 프로젝트 밖에 살아 남으므로 유지한다.\n */\nexport function buildInstallLog(\n spec: InstallSpec,\n external: ExternalInstallReport | null,\n scope: InstallScope,\n rootClaudeMd?: { path: string; sha256: string } | null,\n previous?: InstallLog | null,\n claudeDirMovedAside = false,\n rootFiles: ReadonlyArray<InstallLogRootFile> = [],\n): InstallLog {\n const templates: InstallLog[\"templates\"] = {\n claudeDir: \".claude/\",\n ...(spec.cli.includes(\"codex\") ? { codexDir: \".codex/\" } : {}),\n ...(spec.cli.includes(\"opencode\") ? { opencodeDir: \".opencode/\" } : {}),\n ...(rootClaudeMd ? { rootClaudeMd } : {}),\n };\n const log: InstallLog = {\n schemaVersion: INSTALL_LOG_VERSION,\n installedAt: new Date().toISOString(),\n scope,\n spec: {\n tracks: spec.tracks,\n cli: spec.cli,\n ...(spec.baselineExclude && spec.baselineExclude.length > 0\n ? { baselineExclude: spec.baselineExclude }\n : {}),\n },\n // 이번 설치가 만든 항목이 이기고, 이번에 안 만든 항목은 이전 값을 그대로 둔다.\n // (예: claude 로 깔고 나중에 codex 만 추가 설치해도 root CLAUDE.md 기록이 살아남는다)\n templates: { ...previous?.templates, ...templates },\n assets: mergeAssets(\n claudeDirMovedAside ? previous?.assets?.filter(survivesClaudeDirRename) : previous?.assets,\n buildAssetEntries(external, scope),\n ),\n };\n // 루트 파일은 `.claude/` 밖이라 backup rename 과 무관하게 살아남는다 → 무조건 누적.\n const mergedRootFiles = mergeRootFiles(previous?.rootFiles, rootFiles);\n if (mergedRootFiles.length > 0) log.rootFiles = mergedRootFiles;\n return log;\n}\n\n/**\n * 경로 기준 합집합. 자산과 달리 **이번 설치분이 이전 것을 덮지 않고 합친다** — `.gitignore` 에\n * 1회차는 `.env`, 2회차는 `.factory/` 를 추가하면 둘 다 디스크에 남아 있으므로 둘 다 알려야 한다.\n * `change` 는 한 번이라도 created 면 created — 하네스가 만든 파일에 나중에 병합한 것뿐이고,\n * 사용자에게는 \"전부 하네스 것\"이 여전히 참이다 (modified 로 낮추면 지워도 될 것을 못 지운다).\n */\nfunction mergeRootFiles(\n previous: ReadonlyArray<InstallLogRootFile> | undefined,\n current: ReadonlyArray<InstallLogRootFile>,\n): InstallLogRootFile[] {\n const byPath = new Map<string, InstallLogRootFile>();\n for (const file of [...(previous ?? []), ...current]) {\n const prior = byPath.get(file.path);\n byPath.set(\n file.path,\n prior\n ? {\n path: file.path,\n change: prior.change === \"created\" ? \"created\" : file.change,\n notes: [...new Set([...prior.notes, ...file.notes])],\n }\n : file,\n );\n }\n return [...byPath.values()];\n}\n\n/**\n * `.claude/` 가 backup 으로 밀려도 살아남는 자산인가 — 산출물이 프로젝트 `.claude/` 밖인가.\n *\n * **exhaustive switch 로 쓴다(default 없음).** method 종류가 늘면 빌드가 깨져서 이 판단을\n * 강제로 하게 만든다 — `!==` 목록이면 새 method 가 조용히 \"살아남음\"으로 분류되고, 그건\n * 곧 없는 걸 있다고 기록하는 것이다 (`no-false-ship` §Drift 구조 차단: 하드코딩 목록에는\n * exhaustiveness 가드 없이 머지 금지, 기본값은 면제가 아니라 검사).\n */\nfunction survivesClaudeDirRename(asset: InstallLogAsset): boolean {\n if (asset.scope === \"global\") return true; // 글로벌 영역은 install 이 건드리지 않는다\n switch (asset.method) {\n case \"plugin\":\n return true; // `~/.claude/plugins/cache` — 프로젝트 밖\n case \"npm\":\n return true; // `node_modules/`\n case \"skill\":\n return false; // `npx skills add` project scope → `.claude/skills/`\n case \"shell-script\":\n return false; // ecc-prune → `.claude/local-plugins/`\n case \"npx-run\":\n // bmad-method 는 `--tools claude-code` 로 `.claude/` 안에 agent command 를 만든다\n // (external-assets.ts 의 cliSupportOverride 주석 + Docker 실증 realcli-workflows-2026-06-06).\n // `_bmad/` 는 루트에 남지만, `.claude/` 산출물이 사라진 이상 \"그대로 설치됨\"이 아니다.\n return false;\n case \"internal\":\n // 실제로는 로그에 실리지 않는다(external-installer 가 사전 제외). 그래도 기본값은 검사.\n return false;\n }\n}\n\n/** id 기준 합집합 — 같은 id 는 이번 설치분이 이긴다 (version/scope 가 최신). 순서는 안정적. */\nfunction mergeAssets(\n previous: ReadonlyArray<InstallLogAsset> | undefined,\n current: ReadonlyArray<InstallLogAsset>,\n): InstallLogAsset[] {\n if (!previous || previous.length === 0) return [...current];\n const currentById = new Map(current.map((a) => [a.id, a]));\n const previousIds = new Set(previous.map((a) => a.id));\n return [\n ...previous.map((a) => currentById.get(a.id) ?? a),\n ...current.filter((a) => !previousIds.has(a.id)),\n ];\n}\n\n/** install log + root CLAUDE.md 등 자산 무결성 비교용 sha256 (hex). */\nexport function hashContent(content: string): string {\n return createHash(\"sha256\").update(content, \"utf8\").digest(\"hex\");\n}\n\n/**\n * 디스크 내용이 하네스가 놓아둔 것 그대로인가 (v26.133.0 · ADR-048).\n *\n * **기록이 없으면 소유를 주장할 수 없다 → false.** 이 기본값이 뒤집히면 사용자 파일을\n * 하네스 것으로 오인해 백업 없이 밀거나 지운다.\n *\n * 판정식이 세 곳(install · update · 외부 CLI transform)에서 각자 살면 한 곳만 고쳐졌을 때\n * 조용히 갈린다 — 소유 판정은 사용자 파일 삭제 여부를 가르므로 갈리면 피해가 크다.\n * 그래서 술어는 여기 하나만 둔다 (`no-false-ship.md` §Drift 구조 차단).\n */\nexport function isHarnessOwned(\n baseline: ReadonlyMap<string, string>,\n key: string,\n current: string,\n): boolean {\n const recorded = baseline.get(key);\n return recorded !== undefined && recorded === hashContent(current);\n}\n\n/**\n * 외부 CLI 기준선 누적 (v26.133.0 · ADR-048).\n *\n * 이번 실행이 안 건드린 산출물(예: 지난번엔 opencode 도 깔았는데 이번엔 codex 만)은 디스크에\n * 그대로 있으므로 **이전 기록을 유지한다** — 지우면 다음 실행이 판정 불가로 떨어져 멀쩡한\n * 파일을 백업한다. 대신 디스크에서 사라진 항목은 뺀다. 기준선은 이력이 아니라 현재 상태다.\n */\nexport function mergeExternalFiles(\n projectDir: string,\n previous: ReadonlyArray<InstallLogSkillFile> | undefined,\n current: ReadonlyArray<InstallLogSkillFile>,\n): InstallLogSkillFile[] {\n const byPath = new Map<string, InstallLogSkillFile>();\n for (const file of [...(previous ?? []), ...current]) byPath.set(file.path, file);\n return [...byPath.values()].filter((f) => existsSync(join(projectDir, f.path)));\n}\n\n/**\n * `.claude/skills/` 전체를 훑어 파일별 sha256 스냅샷을 만든다 (v26.126.0 · ADR-046).\n *\n * **복사가 끝난 뒤에 호출해야 한다.** 이 값이 \"하네스가 놓아둔 내용\"의 기준선이 되고, 다음\n * update 는 디스크가 이것과 다른지로 사용자 편집을 판정한다. 복사 **전에** 부르면 옛 내용이\n * 기준선이 돼 다음 update 가 멀쩡한 파일을 전부 \"사용자가 고쳤다\"로 오판한다.\n *\n * 누적하지 않고 **매번 통째로 교체**한다 (`rootFiles` 와 반대다) — 이건 이력이 아니라 현재\n * 디스크 상태의 스냅샷이고, 지워진 파일의 해시가 남으면 그 자체로 거짓 기록이 된다.\n */\nexport function collectSkillHashes(projectDir: string): InstallLogSkillFile[] {\n const skillsDir = join(projectDir, \".claude/skills\");\n return listFilesRecursive(skillsDir).map((rel) => ({\n path: rel,\n sha256: hashContent(readFileSync(join(skillsDir, rel), \"utf8\")),\n }));\n}\n\n/**\n * 정책 파일 기준선 스냅샷 (v26.132.0 · ADR-047). `collectSkillHashes` 와 같은 규율:\n * **복사가 끝난 뒤** 호출해야 이 값이 \"하네스가 놓아둔 내용\"의 기준선이 된다.\n *\n * 소유 판정은 **templates 에 그 파일이 있는가**로 한다. 디스크에만 있는 파일은 사용자가\n * 만든 것이므로 기준선에 넣지 않는다 — 넣으면 다음 update 의 prune 이 그걸 \"하네스가 깔았던\n * 것\"으로 읽고 지운다. 즉 이 필터가 사용자 파일 삭제를 막는 마지막 문이다.\n */\nexport function collectPolicyHashes(\n projectDir: string,\n templatesDir: string,\n): InstallLogSkillFile[] {\n const out: InstallLogSkillFile[] = [];\n for (const { dir, ext } of POLICY_DIRS) {\n const targetDir = join(projectDir, \".claude\", dir);\n const sourceDir = join(templatesDir, dir);\n for (const rel of listFilesRecursive(targetDir)) {\n if (!rel.endsWith(ext)) continue;\n if (!existsSync(join(sourceDir, rel))) continue; // 사용자가 만든 파일 — 소유 주장 안 함\n out.push({\n path: `${dir}/${rel}`,\n sha256: hashContent(readFileSync(join(targetDir, rel), \"utf8\")),\n });\n }\n }\n return out;\n}\n\n/**\n * install log write. 위치: `<projectDir>/.uzys-agent-harness/.harness-install.json`.\n *\n * 디렉터리는 write 직전에 보장한다 — 하네스 전용이라 다른 어떤 phase 도 만들지 않는다.\n *\n * v26.135.0 (#253) — 구 위치(`.claude/`)에 파일이 있으면 **여기서 이관이 끝난다**: 새 위치에\n * 쓴 뒤 구 파일을 지운다. 이관을 별도 명령이나 install 경로에만 두면, 로그를 쓰는 다른 경로\n * (`update` 의 refreshExternalCli, `uninstall --only` 의 로그 갱신)가 구 파일을 남긴 채\n * 새 파일을 만들어 **같은 프로젝트에 로그가 2벌** 남는다.\n */\nexport function writeInstallLog(projectDir: string, log: InstallLog): string {\n const path = installLogPath(projectDir);\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, `${JSON.stringify(log, null, 2)}\\n`, \"utf8\");\n migrateAwayLegacyLog(projectDir);\n return path;\n}\n\n/**\n * 구 위치 파일 제거. 실패해도 **install 을 죽이지 않는다** — 읽기는 새 위치가 우선이라\n * 남은 구 파일은 더 이상 아무것도 결정하지 않는다(무해한 잔재). 반대로 여기서 throw 하면\n * 정상 완료된 설치가 \"실패\"로 보고된다. 조용한 성공이 아니라 **의도된 비치명 처리**다.\n */\nfunction migrateAwayLegacyLog(projectDir: string): void {\n const legacy = legacyInstallLogPath(projectDir);\n if (!existsSync(legacy)) return;\n try {\n rmSync(legacy);\n } catch {\n /* 위 주석 참조 — 새 위치가 이미 SSOT */\n }\n}\n\n/**\n * 새 위치 → 구 위치 순으로 찾는다. 구 위치 폴백이 없으면 v26.134.1 이하로 설치한 사용자의\n * `list` / `uninstall` / `update` 가 전부 \"install log not found\" 로 죽는다.\n */\nexport function readInstallLog(projectDir: string): InstallLog | null {\n const path = [installLogPath(projectDir), legacyInstallLogPath(projectDir)].find((p) =>\n existsSync(p),\n );\n if (!path) return null;\n try {\n const parsed = JSON.parse(readFileSync(path, \"utf8\")) as InstallLog;\n // v26.68.0 — backward compat: method.kind \"npm-global\" → \"npm\" rename.\n // v26.64.0 ~ v26.67.0 시점 install log 가 새 uninstall 에서 작동하도록 normalize.\n if (Array.isArray(parsed.assets)) {\n parsed.assets = parsed.assets.map((a) =>\n (a.method as string) === \"npm-global\" ? { ...a, method: \"npm\" } : a,\n );\n }\n return parsed;\n } catch {\n return null;\n }\n}\n\nexport function installLogPath(projectDir: string): string {\n return join(projectDir, INSTALL_LOG_DIR, INSTALL_LOG_FILENAME);\n}\n\n/** v26.134.1 이하가 쓰던 위치. 읽기 폴백과 이관에만 쓴다 — 새로 쓰는 곳은 없다. */\nexport function legacyInstallLogPath(projectDir: string): string {\n return join(projectDir, LEGACY_INSTALL_LOG_DIR, INSTALL_LOG_FILENAME);\n}\n","import {\n copyFileSync,\n cpSync,\n existsSync,\n constants as fsConstants,\n mkdirSync,\n readdirSync,\n readFileSync,\n realpathSync,\n renameSync,\n rmdirSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\n/** Ensure a directory exists, creating parents as needed. Idempotent. */\nexport function ensureDir(path: string): void {\n mkdirSync(path, { recursive: true });\n}\n\nexport interface CopyResult {\n copied: number;\n skipped: number;\n}\n\n/** Copy a single file, creating parent dirs as needed. Idempotent. */\nexport function copyFile(source: string, target: string): void {\n if (!existsSync(source)) {\n throw new Error(`Source not found: ${source}`);\n }\n mkdirSync(dirname(target), { recursive: true });\n copyFileSync(source, target);\n}\n\n/**\n * Copy a directory's **files** recursively. Creates target if missing.\n *\n * 계약이 통짜 `cpSync` 보다 좁다 — source 쪽 **심볼릭 링크와 빈 디렉터리는 재현되지 않는다**.\n * 지금 `templates/` 에는 둘 다 0개이고(git 은 빈 디렉터리를 담지 못한다) 실행 비트·내용·\n * 사용자 추가 파일 보존은 종전과 같다. 스킬에 심링크를 넣게 되면 이 줄부터 다시 볼 것.\n *\n * **파일 단위로 돈다** (`cpSync` 통짜 복사가 아니다, #343). 통짜 복사는 대상 트리 안에 링크가\n * 섞여 있어도 그대로 따라가 남의 파일을 덮는데, 그것을 걸러낼 자리가 호출자에게 없었다.\n * 무엇을 건너뛸지 **판정은 호출자 몫**이다 — fs 층에 소유권 정책을 넣으면 그 정책이 두 번째\n * 사본으로 자라난다(`foreign-slot.ts` 가 그 SSOT).\n *\n * @param foreignOf **필수**다. 옵셔널로 두면 다음 호출자가 조용히 빠뜨리고, 그 형태가\n * 이 사이클에 세 번 났다(쓰는 주체가 판정을 안 부름). 가드가 필요 없는 호출은 `() => null` 로\n * **명시**한다 — 사람이 매번 기억해야 하는 규약은 규약이 아니다.\n * source 기준 상대경로를 받아, 그 파일을 쓰면 남의 것을 건드리는 경우\n * **그 자리의 경로**를 돌려준다(아니면 null). 파일 경로가 아니라 자리를 받는 이유는\n * 사용자가 옮겨야 할 대상이 파일이 아니라 그 자리(예: 중간 디렉터리 링크)이기 때문이다.\n * @returns 건너뛴 자리들 (**중복 포함** — 거르는 것은 호출자 몫). 화면에 낸다 — 침묵 금지\n */\nexport function copyDir(\n source: string,\n target: string,\n foreignOf: (relFile: string) => string | null,\n): string[] {\n if (!existsSync(source)) {\n throw new Error(`Source dir not found: ${source}`);\n }\n mkdirSync(target, { recursive: true });\n const skipped: string[] = [];\n for (const rel of listFilesRecursive(source)) {\n const foreign = foreignOf(rel);\n if (foreign !== null) {\n // 한 자리가 여러 파일을 가릴 수 있다(중간 디렉터리 링크) — 같은 자리가 여러 번 담긴다.\n // 중복 제거는 **호출자가** 한다: 엔트리를 넘나드는 중복은 여기서 볼 수 없어 어차피\n // 그쪽이 한 번 더 걸러야 하고, 같은 규칙을 두 곳에 두면 한쪽이 죽은 줄이 된다.\n skipped.push(foreign);\n continue;\n }\n copyFile(join(source, rel), join(target, rel));\n }\n return skipped;\n}\n\n/** 같은 초 안에서 허용하는 백업 개수 상한. 넘으면 조용히 덮는 대신 크게 실패한다. */\nconst MAX_BACKUP_CLAIMS = 100;\n\n/**\n * 한 이름을 **원자적으로 선점**해서 돌려준다 — 같은 stamp 로 두 번 백업해도 앞선 백업을 덮지 않게.\n *\n * `formatStamp` 은 초 해상도라 사용자가 `update`/재설치를 연달아 돌리면 같은 이름이 나온다.\n * 그때 세 백업 함수가 서로 다르게 망가졌다 (R-3m):\n * - `cpSync`/`copyFileSync` 는 조용히 **앞선 백업을 덮는다** — 지키려던 사용자 편집분이 사라진다.\n * - `renameSync` 는 ENOTEMPTY 로 죽는다 — 재설치가 크래시한다.\n *\n * `existsSync` 로 \"비었나\"를 **판정하지 않는다**: 확인과 생성 사이가 곧 경합 창이다 (ADR-049\n * \"판정하지 말고 디스크가 답하게 하라\"). 생성 자체를 원자적으로 시도하고 EEXIST 를 디스크의\n * 대답으로 받는다 — `mkdirSync`(비재귀)와 `copyFileSync(..., COPYFILE_EXCL)` 둘 다 그 성질을 준다.\n */\nfunction claimBackupPath(base: string, claim: (candidate: string) => void): string {\n for (let n = 1; n <= MAX_BACKUP_CLAIMS; n++) {\n const candidate = n === 1 ? base : `${base}-${n}`;\n try {\n claim(candidate);\n return candidate;\n } catch (err) {\n // EEXIST = \"그 이름은 이미 누가 썼다\". 그 외(ENOENT·EACCES…)는 재시도로 풀릴 문제가 아니다.\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") throw err;\n }\n }\n throw new Error(`Cannot allocate a backup path for ${base} (${MAX_BACKUP_CLAIMS} taken)`);\n}\n\n/**\n * Move an existing directory to a timestamped backup sibling.\n * Returns the backup path, or null when nothing to back up.\n */\nexport function backupDir(target: string, now: Date = new Date()): string | null {\n if (!existsSync(target)) {\n return null;\n }\n const backup = claimBackupPath(`${target}.backup-${formatStamp(now)}`, (c) => mkdirSync(c));\n // 선점은 빈 디렉터리로 해 두고, 옮기기 직전에 치운다. 존재하는 디렉터리로의 rename 은\n // POSIX 에선 (비어 있으면) 통하지만 Windows 는 거부하므로 양쪽 다 되게 rmdir 을 먼저 한다.\n rmdirSync(backup);\n // 심볼릭 링크는 **풀지 않는다**. rename 은 옮기는 것이라 target 이 링크면 링크가 통째로\n // 백업 자리로 가고, 재설치는 빈 자리에 새 실체 디렉터리를 만든다 — 링크도 링크가 가리키던\n // 내용도 그대로 남는다. (copyBackupDir 은 원본을 계속 쓰면서 복사하므로 판단이 반대다.)\n renameSync(target, backup);\n return backup;\n}\n\n/**\n * Copy backup — original target preserved (for in-place update mode).\n * bash setup-harness.sh L477 `cp -R .claude \"$BACKUP_DIR\"` 등가.\n *\n * 무엇을 보존하려는 백업인가: **update 직전 상태로 되돌아갈 수 있게 하는 스냅샷**. 원본은\n * 그 자리에 남아 계속 덮어써지므로, 백업은 그 시점 **내용**을 들고 있어야 의미가 있다.\n * 그래서 최상위와 안쪽 링크의 처리가 갈린다:\n *\n * | 대상 | 처리 | 왜 |\n * |---|---|---|\n * | target 자체가 링크 (`.claude` → 공유 dotfiles) | **실체를 복사** | 링크를 복사하면 update 가 그 링크를 통해 원본을 덮는 순간 백업이 가리키는 내용도 같이 바뀐다 — 되돌릴 수 없는 백업 |\n * | 안쪽 링크 (`skills/<id>` → `npx skills add` 저장소) | **링크인 채로** | 남의 저장소를 백업에 복제해 넣지 않는다. 끊어진 링크(스킬을 지운 뒤)에서도 죽지 않는다 |\n *\n * 최상위를 `realpathSync` 로 풀어 넘긴다. `dereference: true` 로도 이 케이스는 통과하지만\n * 그 옵션에 기대지 않는다 — 문서상 의미(\"심볼릭 링크를 따라간다\")와 실측(Node 26.5.0 에선\n * 안쪽 링크를 풀지 않았다)이 갈리는 옵션이라, 버전이 바뀌면 위 표의 두 번째 행이 조용히\n * 뒤집힌다. \"최상위만 실체로\"는 옵션이 아니라 코드로 적는다.\n */\nexport function copyBackupDir(target: string, now: Date = new Date()): string | null {\n if (!existsSync(target)) {\n return null;\n }\n const backup = claimBackupPath(`${target}.backup-${formatStamp(now)}`, (c) => mkdirSync(c));\n cpSync(realpathSync(target), backup, { recursive: true });\n return backup;\n}\n\n/**\n * 사용자 편집 가능 파일(settings.json·CLAUDE.md)을 덮어쓰기 전 보호.\n * 기존 파일이 있고 새 내용과 다르면 timestamp 백업본을 만들고 그 경로를 반환한다.\n * 부재하거나 내용이 동일하면(idempotent 재설치) null — 불필요한 백업을 만들지 않는다.\n * audit SEC-1/CODE-2 — add 모드(.claude/ backup 없음)에서 통째 덮어쓰기로 인한 데이터 손실 방지.\n */\nexport function backupFileIfChanged(\n target: string,\n newContent: string,\n now: Date = new Date(),\n): string | null {\n if (!existsSync(target)) {\n return null;\n }\n if (readFileSync(target, \"utf-8\") === newContent) {\n return null;\n }\n return backupFile(target, now);\n}\n\n/**\n * 기존 파일을 timestamp 백업본으로 복사하고 그 경로를 반환한다. **판정은 호출자 몫.**\n *\n * `backupFileIfChanged` 와 나뉜 이유는 술어가 다르기 때문이다: 저쪽은 \"새 내용과 다른가\",\n * update 의 스킬 갱신(ADR-046)은 \"**설치 시점**과 다른가\"로 판정한다. 하네스가 개선해서\n * 달라진 파일은 사용자가 안 건드렸으므로 백업 없이 덮어써야 하고, 내용 비교만으로는 그\n * 둘을 구분할 수 없다.\n *\n * 심볼릭 링크는 **실체 내용으로** 백업된다 (`copyFileSync` 가 링크를 따라간다) — `copyBackupDir`\n * 최상위와 같은 잣대다. 호출자는 백업 직후 같은 경로를 덮어쓰는데, 그 쓰기도 링크를 따라가\n * 링크 대상을 바꾼다. 링크 사본을 남기면 백업이 가리키는 내용도 같이 바뀌어 아무것도 못 지킨다.\n */\nexport function backupFile(target: string, now: Date = new Date()): string {\n return claimBackupPath(`${target}.backup-${formatStamp(now)}`, (c) =>\n copyFileSync(target, c, fsConstants.COPYFILE_EXCL),\n );\n}\n\n/**\n * `dir` 아래 모든 파일의 상대 경로 (디렉터리 자체는 제외). 순서는 readdir 순.\n *\n * `readdirSync(dir, { recursive: true })` 를 안 쓰는 이유: 그 옵션은 Node 20.1.0 에 들어왔는데\n * `engines` 는 `>=20.0.0` 이다. 20.0.x 에서 조용히 `undefined` 를 흘리는 대신 직접 순회한다.\n */\nexport function listFilesRecursive(dir: string, prefix = \"\"): string[] {\n if (!existsSync(dir)) return [];\n const out: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const rel = prefix ? `${prefix}/${entry.name}` : entry.name;\n if (entry.isDirectory()) {\n out.push(...listFilesRecursive(join(dir, entry.name), rel));\n } else if (entry.isFile()) {\n out.push(rel);\n }\n }\n return out;\n}\n\nfunction formatStamp(now: Date): string {\n return now\n .toISOString()\n .replace(/[-:]/g, \"\")\n .replace(/\\.\\d+Z$/, \"Z\")\n .slice(0, 15);\n}\n\n/** Create a project skeleton: <project>/.claude/{commands/uzys,rules,skills,agents,hooks}. */\nexport function ensureProjectSkeleton(projectDir: string): void {\n const dirs = [\n \".claude/commands/uzys\",\n \".claude/rules\",\n \".claude/skills\",\n \".claude/agents\",\n \".claude/hooks\",\n \"docs/decisions\",\n ];\n for (const d of dirs) {\n mkdirSync(join(projectDir, d), { recursive: true });\n }\n}\n","import { TRACKS, type Track } from \"./types.js\";\n\n/**\n * Project-context scaffold for the delivered CLAUDE.md / AGENTS.md.\n *\n * The installer is a pure Node CLI and CANNOT run an LLM, so it cannot fill a\n * project-specific context file at install time. Shipping generic per-track prose\n * instead produced \"meaningless\" files (a literal `# [Project Name]` title, a Bash\n * stack advertised to every project, phantom rule names). This module ships an\n * honest fill-in SCAFFOLD instead: each section carries an embedded `<!-- FILL: -->`\n * instruction the user runs in their own coding agent post-install (or by hand).\n * The same scaffold body feeds BOTH the Claude Code root CLAUDE.md and the\n * `{PROJECT_CONTEXT}` block of every AGENTS.md — one source, byte-identical across\n * all 4 CLIs, with no disk read-back coupling.\n */\n\n/**\n * 하네스 앵커의 **설치 파일명** (프로젝트 루트). manifest target · 루트 CLAUDE.md 의 `@import`\n * 줄 · update 갱신 · uninstall 회수가 전부 이 상수를 쓴다.\n *\n * 이름이 여러 곳에 리터럴로 살면 한 곳만 바뀌었을 때 조용히 갈리고, 그때 생기는 것은 아무도\n * 갱신·회수하지 않는 고아 파일이다 (`no-false-ship.md` §Drift 구조 차단).\n */\nexport const HARNESS_ANCHOR_FILE = \"CLAUDE-uzys-harness.md\";\n\n/** 루트 CLAUDE.md 가 앵커를 끌어오는 Claude Code memory import 줄. */\nexport const HARNESS_IMPORT_LINE = `@${HARNESS_ANCHOR_FILE}`;\n\n/**\n * 관리 마커 — **하네스가 넣은 줄과 사용자가 쓴 줄을 가르는 유일한 표식**이다.\n * 재실행 시 중복 추가를 막고(idempotent), uninstall 이 사용자 본문을 건드리지 않고\n * 이 블록만 도려낼 수 있게 한다.\n */\nconst IMPORT_MARKER_START = \"<!-- uzys-harness:import:start -->\";\nconst IMPORT_MARKER_END = \"<!-- uzys-harness:import:end -->\";\nconst IMPORT_BLOCK = `${IMPORT_MARKER_START}\\n${HARNESS_IMPORT_LINE}\\n${IMPORT_MARKER_END}`;\n\nexport const TRACK_DISPLAY_NAMES: Record<Track, string> = {\n tooling: \"Tooling\",\n \"csr-supabase\": \"CSR Supabase\",\n \"csr-fastify\": \"CSR Fastify\",\n \"csr-fastapi\": \"CSR FastAPI\",\n \"ssr-htmx\": \"SSR HTMX\",\n \"ssr-nextjs\": \"SSR Next.js\",\n data: \"Data\",\n executive: \"Executive\",\n full: \"Full\",\n \"project-management\": \"Project Management\",\n \"growth-marketing\": \"Growth Marketing\",\n};\n\n/** Tracks expanded when 'full' is selected — every track except 'full' itself.\n * Derived from TRACKS so a future track can't be silently omitted from a 'full' install. */\nconst FULL_EXPANSION: ReadonlyArray<Track> = TRACKS.filter((t) => t !== \"full\");\n\n/**\n * The MUST-HAVE project-context sections, from a harness perspective: the context\n * an agent needs to work on ANY project with few round-trips. Order is intentional\n * (identity → stack → architecture → assets → boundaries → verify).\n */\nexport const FILL_SECTIONS = [\n \"identity\",\n \"stack\",\n \"architecture\",\n \"installed-assets\",\n \"boundaries\",\n \"verify\",\n] as const;\nexport type FillSection = (typeof FILL_SECTIONS)[number];\n\ninterface FillSpec {\n /** Rendered `## <title>` header. */\n title: string;\n /** Body of the `<!-- FILL:<id> — … -->` comment: what to inspect and write. */\n prompt: string;\n /** Honest `_(not filled yet — …)_` line so an unfilled section never states a false fact. */\n placeholder: string;\n}\n\nconst FILL_SPECS: Record<FillSection, FillSpec> = {\n identity: {\n title: \"Identity & Purpose\",\n prompt:\n 'Replace the H1 title above with this project\\'s real name, then state in 1-2 plain sentences what it does, who uses it, and why it exists. Sources: README.md, the package.json / pyproject.toml \"description\", docs/. Do NOT describe the harness itself. Delete this comment when done.',\n placeholder: \"what this project is, who it is for, and why it exists\",\n },\n stack: {\n title: \"Stack & Commands\",\n prompt:\n \"Replace the list below with this project's REAL stack. Inspect package.json / pyproject.toml / go.mod / Cargo.toml / Gemfile + lockfiles and any Makefile/justfile/package scripts. List the language(s)+versions, framework(s), package manager, and the exact install/build/test/run commands. Verify each command exists before writing it — never guess. Delete lines that do not apply, then delete this comment.\",\n placeholder: \"languages, runtimes, package manager, and the install/build/test/run commands\",\n },\n architecture: {\n title: \"Architecture & Layout\",\n prompt:\n \"Map this repository. List each top-level source directory and what it holds, the entry point(s), the 3-5 files a newcomer reads first, and how data/requests flow between the main layers. View the real tree (e.g. `git ls-files | sed 's#/.*##' | sort -u`) — do not assume a framework's conventional layout. Flag any generated/vendored directories that must never be hand-edited. If this is a single small module, say so in one line. Delete this comment when done.\",\n placeholder: \"where things live, the entry points, and how data flows between layers\",\n },\n \"installed-assets\": {\n title: \"Installed Harness Assets\",\n prompt:\n \"List the harness assets installed in this project (rules / skills / agents / commands) and add one line each on when to reach for it here. Verify against .claude/rules/*.md, .claude/skills/, .claude/agents/, .claude/commands/ (or this CLI's equivalent) and list ONLY assets whose file exists on disk — do not invent any. Do NOT restate the harness's working principles (they live in this project's harness anchor and rules layer) — cross-reference them instead. Delete this comment when done.\",\n placeholder: \"the installed rules/skills/agents/commands and when to use each\",\n },\n boundaries: {\n title: \"Boundaries — Always / Ask First / Never\",\n prompt:\n 'Fill the Always / Ask First / Never lists with this repo\\'s real red lines. Read the CI config, CODEOWNERS, .gitignore, and release/deploy scripts. Never must include secrets, generated files, force-push, and direct commits to the default branch, plus any repo-specific \"do not touch\" directories. Every entry must be specific and enforceable here. Delete this comment when done.',\n placeholder: \"what to always do, ask before doing, and never do in this repo\",\n },\n verify: {\n title: \"Verification Gate\",\n prompt:\n 'State the single command (or short sequence) that PROVES a change is safe here — the test/lint/typecheck/build gate you run before committing — plus the coverage/CI threshold and what \"done\" means. Sources: package scripts, CI workflow files, CONTRIBUTING. An agent must be able to self-verify without guessing. Delete this comment when done.',\n placeholder: \"the single command that proves a change is safe, and the done bar\",\n },\n};\n\n/** Visible (rendered-markdown) banner — HTML FILL comments are invisible in a preview, so this\n * blockquote is what stops the scaffold from reading as verified project fact for a human. */\nexport const SCAFFOLD_BANNER = [\n \"> ⚙️ **SCAFFOLD — not filled in yet.** The sections below are a fill-in template for THIS project, not verified facts.\",\n \"> To fill: open this file and paste each `<!-- FILL: … -->` comment's instruction into your coding agent (e.g. Claude Code) — it will inspect the real repo and write the section. You can also fill them by hand; the comments are the instructions.\",\n `> The working principles live in this project's harness anchor — \\`${HARNESS_ANCHOR_FILE}\\` (Claude Code, imported from this file), \\`AGENTS.md\\` (Codex/OpenCode), or \\`.agents/rules/uzys-harness.md\\` (Antigravity). This file is **project-specific context only**.`,\n].join(\"\\n\");\n\n/**\n * Shared project-context scaffold body: the visible banner followed by the six MUST-HAVE\n * sections, each a `## Title` + a self-contained `<!-- FILL:id — … -->` comment + an honest\n * `_(not filled yet — …)_` placeholder. Pure and track-agnostic, so the Claude Code CLAUDE.md\n * and every AGENTS.md `{PROJECT_CONTEXT}` block get byte-identical prompts from one source.\n */\nexport function renderFillScaffold(): string {\n const blocks = FILL_SECTIONS.map((id) => {\n const spec = FILL_SPECS[id];\n return `## ${spec.title}\\n\\n<!-- FILL:${id} — ${spec.prompt} -->\\n\\n_(not filled yet — ${spec.placeholder})_`;\n });\n return `${SCAFFOLD_BANNER}\\n\\n${blocks.join(\"\\n\\n\")}`;\n}\n\nexport interface MergeOptions {\n /** Project directory basename → the H1 title (fixes the shipped `# [Project Name]` literal). */\n projectName: string;\n /** Selected tracks → the active-track note (genuine install metadata). */\n tracks: ReadonlyArray<Track>;\n}\n\n/**\n * Build the project-root CLAUDE.md: a real H1 project name + the active-track note (genuine\n * install metadata) + the shared fill scaffold. The scaffold is track-agnostic — the selected\n * tracks are recorded in the note; the installed-assets section is filled from real files at\n * fill time rather than from static per-track prose.\n */\nexport function mergeProjectClaude(opts: MergeOptions): string {\n const expanded = expandTracks(opts.tracks);\n const trackList = expanded.map((t) => TRACK_DISPLAY_NAMES[t]).join(\", \");\n const header = `# ${opts.projectName}\\n\\n> Active track(s): ${trackList}`;\n return `${header}\\n\\n${renderFillScaffold()}\\n`;\n}\n\n/**\n * 루트 `CLAUDE.md` 에 하네스 앵커 import 를 **비파괴로** 얹는다 (P5 · ADR-060).\n *\n * v26.140.0 까지 설치는 이 파일을 `mergeProjectClaude()` 결과로 **통째 덮어썼다** — 백업은\n * 남겼지만, 사용자가 채워 넣은 프로젝트 맥락이 매 재설치마다 스캐폴드로 되돌아갔다. 하네스\n * 내용은 `HARNESS_ANCHOR_FILE` 로 따로 나가므로, 루트 CLAUDE.md 에는 그것을 끌어오는 한 줄만\n * 있으면 된다. 그래서 소유가 갈린다: 앵커 파일 = 하네스 소유(갱신·회수 가능), 루트 CLAUDE.md\n * = 사용자 소유(우리는 마커 블록만 책임진다).\n *\n * @param existing 디스크의 현재 내용. 파일이 없으면 `null`.\n * @returns 기록할 내용. 이미 import 가 있으면 **입력과 바이트 동일**(= 쓰지 않아도 된다).\n */\nexport function upsertHarnessImport(existing: string | null, opts: MergeOptions): string {\n if (existing === null) {\n return `${mergeProjectClaude(opts)}\\n${IMPORT_BLOCK}\\n`;\n }\n if (hasHarnessImport(existing)) {\n return existing;\n }\n const body = existing.endsWith(\"\\n\") ? existing : `${existing}\\n`;\n return `${body}\\n${IMPORT_BLOCK}\\n`;\n}\n\n/**\n * 마커 블록만 도려낸다 — uninstall 이 사용자 본문을 지우지 않고 하네스 몫만 회수하는 경로.\n *\n * 블록 앞뒤로 우리가 넣었던 빈 줄까지 되돌리므로, 설치 전 내용이 그대로였다면 결과는\n * **설치 전과 바이트 동일**해진다.\n *\n * @returns 회수 후 내용. 마커가 없으면 `null` (= 우리가 건드린 적 없다 → 파일을 만지지 않는다).\n */\nexport function stripHarnessImport(text: string): string | null {\n const start = text.indexOf(IMPORT_MARKER_START);\n if (start === -1) return null;\n const endAt = text.indexOf(IMPORT_MARKER_END, start);\n if (endAt === -1) return null;\n const before = text.slice(0, start).replace(/\\n+$/, \"\\n\");\n const after = text.slice(endAt + IMPORT_MARKER_END.length).replace(/^\\n+/, \"\");\n return `${before}${after}`;\n}\n\n/**\n * import 가 이미 사는가 — 마커 블록이거나, 사용자가 손으로 적은 실제 import 줄이거나.\n *\n * **코드펜스 안은 세지 않는다.** Claude Code 는 펜스 안의 `@path` 를 import 로 읽지 않으므로,\n * 문서에서 이 파일명을 예시로 인용한 것을 import 로 오인하면 진짜 import 를 영영 안 넣는다\n * (= 앵커가 조용히 안 실린다).\n */\nfunction hasHarnessImport(text: string): boolean {\n if (text.includes(IMPORT_MARKER_START)) return true;\n let inFence = false;\n for (const line of text.split(\"\\n\")) {\n if (/^\\s*(?:```|~~~)/.test(line)) {\n inFence = !inFence;\n continue;\n }\n if (!inFence && line.trim() === HARNESS_IMPORT_LINE) return true;\n }\n return false;\n}\n\nfunction expandTracks(tracks: ReadonlyArray<Track>): ReadonlyArray<Track> {\n if (tracks.includes(\"full\")) {\n return FULL_EXPANSION;\n }\n return tracks;\n}\n","/**\n * Category-based installer (v26.43.0) — 분야별 대표 스킬 큐레이션.\n *\n * 9 카테고리: Frontend / Backend / Data / Business / Dev Tools / Understanding / Visual & Media / Workflow / ECC Suite.\n * 각 카테고리 안에서 자산은 (출처, ExternalAsset.id) 로 식별. Step 2 UI 그룹화 기준.\n *\n * Source labels = 정확한 GitHub org/user (Phase A의 SSOT).\n * `[3rd-party]` 같은 generic 라벨 금지 (SPEC R6).\n */\n\nexport const CATEGORIES = [\n \"frontend\",\n \"backend\",\n \"data\",\n \"business\",\n \"dev-tools\",\n \"understanding\",\n \"visual-media\",\n \"workflow\",\n \"ecc-suite\",\n] as const;\nexport type Category = (typeof CATEGORIES)[number];\n\nexport const CATEGORY_TITLES: Record<Category, string> = {\n frontend: \"🎨 Frontend (UI · Design)\",\n backend: \"🗄️ Backend (API · DB · Deploy)\",\n data: \"📊 Data\",\n business: \"💼 Business (Documents)\",\n \"dev-tools\": \"🛡️ Dev Tools (Security · Quality)\",\n // v26.78.0 — 에이전트 인지 증강: 환경에 대한 지각(영상·웹·코드) + 기억(memory).\n understanding: \"🧠 Understanding (Perception · Memory)\",\n // v26.85.0 — 코드-퍼스트 비주얼/미디어 제작: 슬라이드·다이어그램·모션·동영상.\n \"visual-media\": \"🎬 Visual & Media (Slides · Diagrams · Motion · Video)\",\n workflow: \"🔄 Workflow (Development Cycle)\",\n \"ecc-suite\": \"📦 ECC Suite\",\n};\n\n/** Source labels — GitHub org/user. Maps the canonical owner shown to the user. */\nexport const SOURCE_LABELS = {\n anthropics: \"anthropics\",\n \"vercel-labs\": \"vercel-labs\",\n \"shadcn-ui\": \"shadcn/ui\",\n vercel: \"vercel\",\n netlify: \"netlify\",\n supabase: \"supabase\",\n railwayapp: \"railwayapp\",\n trailofbits: \"trailofbits\",\n obra: \"obra\",\n addyosmani: \"addyosmani\",\n pbakaus: \"pbakaus\",\n \"K-Dense-AI\": \"K-Dense-AI\",\n wshobson: \"wshobson\",\n \"testdino-hq\": \"testdino-hq\",\n yonatangross: \"yonatangross\",\n alirezarezvani: \"alirezarezvani\",\n \"affaan-m\": \"affaan-m\",\n \"get-shit-done-cc\": \"get-shit-done-cc\",\n \"fission-ai\": \"Fission-AI\",\n \"bmad-code-org\": \"bmad-code-org\",\n // v26.78.0 — Understanding 카테고리 신규 출처\n bradautomates: \"bradautomates\",\n Lum1104: \"Lum1104\",\n rohitg00: \"rohitg00\",\n // v26.85.0 — Visual & Media 카테고리 출처 (Docker 실설치 검증 PASS).\n zarazhangrui: \"zarazhangrui\",\n greensock: \"greensock\",\n softaworks: \"softaworks\",\n \"remotion-dev\": \"remotion-dev\",\n // v26.86.0 — Visual & Media 프레젠테이션 4종 (Issue #176, Docker 실설치 4/4 PASS).\n hugohe3: \"hugohe3\",\n bytedance: \"bytedance\",\n ConardLi: \"ConardLi\",\n ryanbbrown: \"ryanbbrown\",\n // v26.91.0 — Business 카테고리 마케팅 번들 (coreyhaines31/marketingskills 35k★, MIT).\n coreyhaines31: \"coreyhaines31\",\n // 2026-08-02 정비 — Frontend 카테고리 신규 출처 (star 실측 2026-08-02, gh api).\n jakubkrehel: \"jakubkrehel\",\n Leonxlnx: \"Leonxlnx\",\n oso95: \"oso95\",\n // 2026-08-16 — Preline UI (6,386★ 실측, MIT + Preline UI Fair Use 듀얼 라이선스로 상업 이용 가능).\n htmlstreamofficial: \"Preline\",\n // 2026-08-17 — GitHub 공식 조직의 awesome-copilot (37,909★ 실측, MIT).\n github: \"GitHub\",\n // 2026-08-17 — Claude-Code-Game-Studios (23,924★ 실측, MIT).\n Donchitos: \"Donchitos\",\n uzys: \"this project\",\n} as const;\nexport type Source = keyof typeof SOURCE_LABELS;\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { EXTERNAL_ASSETS } from \"./external-assets.js\";\nimport { renderFillScaffold } from \"./project-claude-merge.js\";\n\n/**\n * v26.103.0 (ADR-032) — Session-Start Context Cost.\n *\n * 설치 자산이 세션 시작 시 상주시키는 descriptor(SKILL.md frontmatter: name + description)의\n * 토큰 추정치. NORTH_STAR §2 NSM \"Session-Start Context Cost\" 의 계측 구현.\n *\n * 측정 범위 (no-false-ship):\n * - repo-bundled internal 스킬만 실측 — frontmatter 문자수 → chars/4 근사 (표기는 항상 \"~\").\n * - 외부 자산(plugin/skill/npm/npx-run/shell-script)은 설치 시점에 frontmatter 를 알 수 없어\n * **unmeasured** 로 표기한다. 추정치를 실측처럼 표기하지 않는다.\n */\nexport const CHARS_PER_TOKEN = 4;\n\nexport function estimateTokens(chars: number): number {\n return Math.ceil(chars / CHARS_PER_TOKEN);\n}\n\n/**\n * 패키지 루트(= `templates/` 가 있는 곳) 해석. 이 파일은 src/ 최상위(dev)와 dist/ 번들 출력\n * 양쪽에서 한 단계 위가 패키지 루트라 동일 식이 성립한다 — `defaultHarnessRoot` 와 식은 같지만\n * 그쪽은 src/commands/ 아래라 dev 에선 틀려 테스트 주입이 필수인 것과 달리, 여기는 양쪽 유효.\n * `fileURLToPath` 필수 — `.pathname` 은 공백/비ASCII 경로를 percent-encoded 로 남겨\n * existsSync 가 전부 실패한다 (SOD 리뷰 F1).\n */\nexport function resolveBundleRoot(): string {\n return resolve(fileURLToPath(new URL(\".\", import.meta.url)), \"..\");\n}\n\n/** SKILL.md 선두의 frontmatter 블록(`---` ... `---`) 내용. 없으면 null. */\nexport function extractFrontmatter(content: string): string | null {\n // BOM/CRLF 허용 — Windows 클론(core.autocrlf)에서 전량 unmeasured 강등 방지 (SOD 리뷰 F7).\n const m = content.match(/^?---\\r?\\n([\\s\\S]*?)\\r?\\n---/);\n return m?.[1] ?? null;\n}\n\n/**\n * 자산 1개의 descriptor 토큰 추정. internal(repo-bundled) + 템플릿 실재 + frontmatter 존재일\n * 때만 숫자, 그 외 null(unmeasured). 표시용 계측이므로 파일 이상 시 throw 하지 않는다 —\n * 없는 값을 만들어내는 대신 unmeasured 로 강등된다.\n */\nexport function assetDescriptorTokens(\n assetId: string,\n root: string = resolveBundleRoot(),\n): number | null {\n const asset = EXTERNAL_ASSETS.find((a) => a.id === assetId);\n if (!asset || asset.method.kind !== \"internal\") return null;\n const skillMd = join(root, \"templates\", \"skills\", asset.method.key, \"SKILL.md\");\n if (!existsSync(skillMd)) return null;\n const fm = extractFrontmatter(readFileSync(skillMd, \"utf8\"));\n return fm === null ? null : estimateTokens(fm.length);\n}\n\n/**\n * v26.116.0 (ADR-043) — 발화(fired) 비용. 스킬이 실제로 트리거되면 body 전체가 컨텍스트에 들어온다.\n * descriptor 는 전원이 매 세션 무는 상주 비용이고 body 는 트리거될 때만 무는 비용이라 **단위가\n * 다르다** — 두 값을 더한 \"총합\"은 만들지 않는다 (근거 없는 가중 합산 금지).\n */\nexport function assetBodyTokens(\n assetId: string,\n root: string = resolveBundleRoot(),\n): number | null {\n const asset = EXTERNAL_ASSETS.find((a) => a.id === assetId);\n if (!asset || asset.method.kind !== \"internal\") return null;\n const skillMd = join(root, \"templates\", \"skills\", asset.method.key, \"SKILL.md\");\n if (!existsSync(skillMd)) return null;\n const content = readFileSync(skillMd, \"utf8\");\n const fm = extractFrontmatter(content);\n // frontmatter 가 없으면 파일 전체가 body. 있으면 닫는 `---` 이후만.\n if (fm === null) return estimateTokens(content.length);\n const close = content.indexOf(\"\\n---\", content.indexOf(fm) + fm.length);\n const body = close === -1 ? \"\" : content.slice(close + \"\\n---\".length);\n return estimateTokens(body.trim().length);\n}\n\nexport interface AssetCostRow {\n id: string;\n /** 상주 — 설치한 전원이 매 세션 무는 비용. */\n descriptorTokens: number | null;\n /** 발화 — 스킬이 트리거될 때만 무는 비용. */\n bodyTokens: number | null;\n}\n\n/**\n * 자산별 비용 행. **발화 비용 내림차순** 정렬 — \"무엇부터 검토할 것인가\"의 순서다 (ADR-043\n * 1단계: 값싼 전수 계측으로 순위를 세우고, 비싼 eval 은 상위에만). unmeasured(외부 자산)는 뒤로.\n */\nexport function assetCostRows(\n assetIds: ReadonlyArray<string>,\n root: string = resolveBundleRoot(),\n): AssetCostRow[] {\n return assetIds\n .map((id) => ({\n id,\n descriptorTokens: assetDescriptorTokens(id, root),\n bodyTokens: assetBodyTokens(id, root),\n }))\n .sort((a, b) => (b.bodyTokens ?? -1) - (a.bodyTokens ?? -1));\n}\n\n/**\n * v26.117.0 (ADR-044) — 상주 비용의 **표면 전체**.\n *\n * v26.116.0 까지는 스킬 descriptor 만 셌다. 그 정의에는 굿하트 구멍이 있다: SKILL.md 산문을\n * 룰 파일로 옮기면 **발화 시에만 내던 비용이 매 세션 상주로 바뀌어 실제로는 악화**되는데 지표는\n * 개선으로 표시된다. 사용자를 나쁘게 만드는 리팩터링을 보상하는 지표는 없느니만 못하다.\n *\n * 판정 기준은 **표면 열거가 아니라 \"상주인가 발화인가\"** — 새 표면이 생겨도 기준이 그대로다.\n * - 상주: rules(전문) · CLAUDE.md(전문) · skills/agents 의 descriptor\n * - 발화: skills/agents 의 body — 트리거될 때만\n * - 비대상: hooks — **단, 근거는 \"실행될 뿐\"이 아니다** (v26.137.0 정정). 훅 stdout 은 CLI 의\n * `content` 필드로만 컨텍스트에 진입하고, 그 필드는 훅이\n * `hookSpecificOutput.{additionalContext|initialUserMessage}` 를 쓰거나 stdout 이 **비-JSON 일 때만**\n * 채워진다. 우리 SessionStart 훅은 전자를 쓰므로 진입하되 양이 ~19 tok/세션(실측)이라 계측\n * 대상에서 뺀다 — **조건부 제외이지 구조적 제외가 아니다.** 훅이 늘거나 출력이 길어지면\n * 상주에 얹힌다. 외부 플러그인 훅은 여기 안 잡힌다: 올바른 스키마를 쓰는 플러그인 훅 하나가\n * 실측상 +2,222 tok/세션(+37.8%)을 아무 고지 없이 얹을 수 있었다.\n */\nexport interface ResidentCost {\n rules: number;\n projectClaudeMd: number;\n skillDescriptors: number;\n agentDescriptors: number;\n total: number;\n /** 같은 표면의 **개수**. 토큰과 단위가 다르므로 절대 같은 필드에 섞지 않는다 (아래 주석). */\n items: ResidentItemCount;\n}\n\n/**\n * v26.140.0 — 상주 비용의 **양(quantity) 축**.\n *\n * 토큰은 버리지 않되(부수 표시값 + ratchet 유지) 1차 축은 **개수**다. 근거: ADR-051 실측에서\n * 토큰의 금전 비용은 무의미했고($2.94/1k요청 · 컨텍스트 0.59%), 실제로 아픈 비용 — 교차참조,\n * 서로 모순되는 지시, 문서 drift, 유지보수 — 는 **항목 수**에 비례한다. 5,000 토큰이 룰 1개일\n * 때와 룰 20개일 때는 같은 비용이 아니다.\n *\n * 세는 대상은 토큰을 재는 대상과 **정확히 같다** (한쪽만 늘어나는 drift 방지):\n * rules 1파일 = 1 · skills 1디렉터리 = 1 · agents 1파일 = 1 · CLAUDE.md **2**(앵커 + 스캐폴드).\n * hooks 는 여기서도 비대상 — 상주 표면이 아니다.\n */\nexport interface ResidentItemCount {\n rules: number;\n skills: number;\n agents: number;\n claudeMd: number;\n total: number;\n}\n\n/** 파일 1개의 토큰. 없으면 0 (합계를 오염시키지 않되 throw 하지 않는다). */\nfunction fileTokens(path: string): number {\n return existsSync(path) ? estimateTokens(readFileSync(path, \"utf8\").trim().length) : 0;\n}\n\n/** descriptor(frontmatter)만. frontmatter 가 없으면 0 — 상주 비용이 아니다. */\nfunction descriptorTokens(path: string): number {\n if (!existsSync(path)) return 0;\n const fm = extractFrontmatter(readFileSync(path, \"utf8\"));\n return fm === null ? 0 : estimateTokens(fm.length);\n}\n\n/**\n * 설치 계획(manifest 엔트리)에서 상주 비용을 실측. `applies` 로 이미 걸러진 엔트리를 받으므로\n * **트랙별 실제 설치분**이 반영된다 (templates/ 전체 합계 같은 부풀린 수치가 아니다).\n */\nexport function residentCost(\n entries: ReadonlyArray<{ source: string; target: string }>,\n root: string = resolveBundleRoot(),\n): ResidentCost {\n const tpl = (source: string): string => join(root, \"templates\", source);\n let rules = 0;\n let skillDescriptors = 0;\n let agentDescriptors = 0;\n let ruleItems = 0;\n let skillItems = 0;\n let agentItems = 0;\n for (const e of entries) {\n // 토큰과 개수를 **같은 분기에서** 올린다 — 분기를 나누면 둘이 다른 대상을 세게 된다.\n if (e.target.startsWith(\".claude/rules/\")) {\n rules += fileTokens(tpl(e.source));\n ruleItems += 1;\n } else if (e.target.startsWith(\".claude/agents/\")) {\n agentDescriptors += descriptorTokens(tpl(e.source));\n agentItems += 1;\n } else if (e.target.startsWith(\".claude/skills/\")) {\n // skills 엔트리는 디렉토리 — SKILL.md 가 descriptor 를 담는다.\n skillDescriptors += descriptorTokens(join(tpl(e.source), \"SKILL.md\"));\n skillItems += 1;\n }\n }\n // 설치가 상주시키는 CLAUDE.md 는 **둘**이다. v26.140.0 까지는 앵커만 재면서 라벨은\n // \"스캐폴드\"였다 — 이름과 실측 대상이 다르면 그 지표로는 before/after 를 판정할 수 없다.\n // ① 하네스 앵커 `CLAUDE-uzys-harness.md` (루트) — manifest `applies: all` 이라 항상 깔린다.\n // v26.140.0 까지는 `.claude/CLAUDE.md` 였다 (P5 · ADR-060 에서 루트로 이동). 어느 쪽이든\n // **원본은 `templates/CLAUDE.md` 하나**라 여기서 재는 값은 이동과 무관하다.\n // ② 프로젝트 스캐폴드 루트 `CLAUDE.md` — manifest 밖에서 `writeRootClaudeMd()` 가 쓴다\n // (없으면 스캐폴드 생성, 있으면 앵커 import 한 줄 추가). **파일이 아니라 생성물**이라\n // `fileTokens` 로는 영원히 0 이었다.\n // ②는 `renderFillScaffold()` 만 잰다 — `mergeProjectClaude()` 의 머리 2줄(프로젝트명·트랙)은\n // 설치처마다 길이가 달라 ratchet 축으로 못 쓴다. 그만큼 이 값은 **하한**이다.\n const harnessAnchor = fileTokens(join(root, \"templates\", \"CLAUDE.md\"));\n const projectScaffold = estimateTokens(renderFillScaffold().trim().length);\n const projectClaudeMd = harnessAnchor + projectScaffold;\n // 토큰이 0 인 쪽은 항목도 0 (한쪽만 세면 그게 곧 drift). 앵커는 부재할 수 있고,\n // 스캐폴드는 코드 생성물이라 부재할 수 없다.\n const claudeMdItems = (harnessAnchor > 0 ? 1 : 0) + (projectScaffold > 0 ? 1 : 0);\n return {\n rules,\n projectClaudeMd,\n skillDescriptors,\n agentDescriptors,\n total: rules + projectClaudeMd + skillDescriptors + agentDescriptors,\n items: {\n rules: ruleItems,\n skills: skillItems,\n agents: agentItems,\n claudeMd: claudeMdItems,\n total: ruleItems + skillItems + agentItems + claudeMdItems,\n },\n };\n}\n\nexport interface ContextCostSummary {\n /** 실측된 스킬들의 토큰 합 (추정치). */\n measuredTokens: number;\n measuredCount: number;\n unmeasuredCount: number;\n}\n\nexport function summarizeContextCost(\n assetIds: ReadonlyArray<string>,\n root: string = resolveBundleRoot(),\n): ContextCostSummary {\n let measuredTokens = 0;\n let measuredCount = 0;\n let unmeasuredCount = 0;\n for (const id of assetIds) {\n const tokens = assetDescriptorTokens(id, root);\n if (tokens === null) unmeasuredCount += 1;\n else {\n measuredTokens += tokens;\n measuredCount += 1;\n }\n }\n return { measuredTokens, measuredCount, unmeasuredCount };\n}\n\n/**\n * 표시 라인. wizard confirm 과 비대화형 header 가 동일 문구를 쓴다 (표면별 상이 문구 금지 —\n * v26.88.0 이중 고지 사고의 교훈). 자산 0개면 null.\n */\nexport function formatContextCostLine(s: ContextCostSummary): string | null {\n if (s.measuredCount === 0 && s.unmeasuredCount === 0) return null;\n if (s.measuredCount === 0) {\n return `session-start context cost: unmeasured (${s.unmeasuredCount} external asset${s.unmeasuredCount === 1 ? \"\" : \"s\"})`;\n }\n const skills = `${s.measuredCount} bundled skill${s.measuredCount === 1 ? \"\" : \"s\"} measured`;\n const external = s.unmeasuredCount > 0 ? ` · ${s.unmeasuredCount} external unmeasured` : \"\";\n return `session-start context cost: ~${s.measuredTokens} tokens (${skills}${external})`;\n}\n\n/**\n * v26.117.0 (ADR-044) — 설치 요약에 표시하는 상주 비용 라인.\n *\n * 이전 라인(`formatContextCostLine`)은 **스킬 descriptor 만** 세면서 \"session-start context\n * cost\" 라고 표기해, 실측상 상주 비용의 ~10% 를 전부인 양 보여주고 있었다 (tooling 트랙 실측:\n * 스킬 descriptor ~547 vs 상주 합계 ~5,194). 표시 숫자가 실제의 9분의 1이면 그것은 계측이\n * 아니라 오보다 (no-false-ship). 내역을 함께 보여 어디에 비용이 있는지 드러낸다.\n *\n * v26.140.0 — **개수가 먼저, 토큰이 뒤.** 1차 축이 항목 수로 바뀌었으므로 읽는 순서도 그대로\n * 따라간다 (표면마다 순서가 다르면 그 자체가 혼선이다 — cost:report 도 같은 순서).\n *\n * 이 함수가 상주 비용 **표시의 단일 출처**다. 표면(설치 헤더 / wizard confirm / cost:report)이\n * 각자 문자열을 조립하면 한 표면만 갱신되는 drift 가 다시 생긴다 — 지난번에 개수가 리포트에만\n * 붙고 나머지 둘에 없던 것이 정확히 그 형태였다. 계약은\n * `tests/context-cost-display-parity.test.ts` 가 글롭으로 강제한다.\n */\nexport function formatResidentCostLine(r: ResidentCost, unmeasuredCount: number): string | null {\n if (r.total === 0) return null;\n const parts = [\n `rules ${r.items.rules} ~${r.rules}`,\n `CLAUDE.md ${r.items.claudeMd} ~${r.projectClaudeMd}`,\n `skills ${r.items.skills} ~${r.skillDescriptors}`,\n `agents ${r.items.agents} ~${r.agentDescriptors}`,\n ].join(\" · \");\n const external =\n unmeasuredCount > 0\n ? ` · ${unmeasuredCount} external asset${unmeasuredCount === 1 ? \"\" : \"s\"} unmeasured`\n : \"\";\n return `session-start context cost: ${r.items.total} items resident · ~${r.total} tokens/session (${parts}${external})`;\n}\n\n/**\n * cost:report 상주 표의 행 정의. `gap` = 라벨 뒤 공백 수 — 한글 라벨이 2배폭이라 `padEnd` 로는\n * 정렬이 안 맞아 행마다 명시한다.\n */\nconst RESIDENT_ROWS: ReadonlyArray<{\n label: string;\n gap: number;\n count: (r: ResidentCost) => number;\n tokens: (r: ResidentCost) => number;\n}> = [\n { label: \"rules\", gap: 14, count: (r) => r.items.rules, tokens: (r) => r.rules },\n {\n // 한 행에 두 파일(앵커 + 스캐폴드). 개수 열이 2 를 뱉어 그 사실을 드러낸다 — 라벨로\n // 하나만 이름 붙이면 v26.140.0 이전과 같은 거짓 라벨이 된다.\n label: \"CLAUDE.md\",\n gap: 11,\n count: (r) => r.items.claudeMd,\n tokens: (r) => r.projectClaudeMd,\n },\n {\n label: \"skill descriptors\",\n gap: 2,\n count: (r) => r.items.skills,\n tokens: (r) => r.skillDescriptors,\n },\n {\n label: \"agent descriptors\",\n gap: 2,\n count: (r) => r.items.agents,\n tokens: (r) => r.agentDescriptors,\n },\n];\n\n/**\n * v26.140.0 — `npm run cost:report` 의 상주 표. 한 줄 라인과 **같은 함수 가족**에 둔다.\n *\n * 스크립트가 자기 표를 직접 조립하던 동안 개수 열은 리포트에만 있고 설치 표면 둘에는 없었다.\n * 숫자 렌더를 여기로 모아 두면 표면이 늘어도 개수/토큰이 함께 따라간다.\n */\nexport function formatResidentCostBlock(r: ResidentCost): string[] {\n const n = (v: number): string => String(v).padStart(3);\n return [\n \" 개수 토큰\",\n ...RESIDENT_ROWS.map(\n (row) => ` ${row.label}${\" \".repeat(row.gap)}${n(row.count(r))}개 ~${row.tokens(r)}`,\n ),\n \" ─────────────────────────────────\",\n ` 상주 합계 ${n(r.items.total)}개 상주 · ~${r.total} tokens/세션`,\n ];\n}\n"],"mappings":"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","names":["existsSync","mkdirSync","readFileSync","dirname","join","path","existsSync","join","readFileSync","path","mkdirSync","dirname","existsSync","readFileSync","join","fileURLToPath","fileURLToPath","join","existsSync","readFileSync","path"]}