@uzysjung/agent-harness 26.151.0 → 26.153.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.ko.md +2 -2
  2. package/README.md +2 -2
  3. package/dist/{chunk-3QBHZUVB.js → chunk-OYNSK6QF.js} +49 -33
  4. package/dist/chunk-OYNSK6QF.js.map +1 -0
  5. package/dist/index.js +157 -243
  6. package/dist/index.js.map +1 -1
  7. package/dist/trust-tier-drift.js +1 -1
  8. package/package.json +1 -1
  9. package/templates/CLAUDE.md +93 -145
  10. package/templates/codex/README.md +6 -7
  11. package/templates/codex/config.toml.template +1 -9
  12. package/templates/rules/change-management.md +2 -3
  13. package/templates/rules/cli-development.md +2 -4
  14. package/templates/rules/doc-governance.md +1 -1
  15. package/templates/skills/audit-harness-fit/README.md +76 -43
  16. package/templates/skills/audit-harness-fit/SKILL.md +62 -47
  17. package/templates/skills/audit-harness-fit/evals/scenarios.yaml +179 -22
  18. package/templates/skills/audit-harness-fit/references/apply.md +74 -45
  19. package/templates/skills/audit-harness-fit/references/audit.md +142 -118
  20. package/templates/skills/audit-harness-fit/references/populate.md +53 -49
  21. package/templates/skills/audit-harness-fit/references/verification.md +131 -100
  22. package/templates/skills/audit-service-gaps/SKILL.md +0 -2
  23. package/templates/skills/clear-korean-communication/SKILL.md +76 -209
  24. package/templates/skills/external-model-consult/scripts/codex-ask.sh +9 -4
  25. package/templates/skills/external-model-consult/scripts/gemini-ask.sh +9 -4
  26. package/templates/skills/model-orchestration/SKILL.md +123 -285
  27. package/templates/skills/objective-brief/SKILL.md +3 -3
  28. package/templates/track-mcp-map.tsv +1 -1
  29. package/dist/chunk-3QBHZUVB.js.map +0 -1
  30. package/templates/agents/build-error-resolver.md +0 -111
  31. package/templates/agents/plan-checker.md +0 -116
  32. package/templates/agents/silent-failure-hunter.md +0 -50
  33. package/templates/codex/hooks/README.md +0 -37
  34. package/templates/codex/hooks/session-start.sh +0 -7
  35. package/templates/codex/hooks/uncommitted-check.sh +0 -7
  36. package/templates/skills/agent-introspection-debugging/SKILL.md +0 -153
  37. package/templates/skills/clear-korean-communication/references/pre-send-checklist.md +0 -37
  38. package/templates/skills/clear-korean-communication/references/why-it-works.md +0 -24
  39. package/templates/skills/clear-korean-communication/references/worked-examples.md +0 -89
  40. package/templates/skills/deep-research/SKILL.md +0 -179
  41. package/templates/skills/deep-research/agents/openai.yaml +0 -7
  42. package/templates/skills/eval-harness/SKILL.md +0 -306
  43. package/templates/skills/eval-harness/agents/openai.yaml +0 -7
  44. package/templates/skills/verification-loop/SKILL.md +0 -250
  45. package/templates/skills/verification-loop/agents/openai.yaml +0 -7
  46. package/templates/skills/verification-loop/references/tracks.md +0 -49
package/dist/index.js CHANGED
@@ -14,9 +14,11 @@ import {
14
14
  INTERNAL_BUNDLED_SKILL_IDS,
15
15
  POLICY_DIRS,
16
16
  RENAMED_SKILL_IDS,
17
+ RETIRED_AGENTS,
17
18
  RETIRED_AGENT_IDS,
18
19
  RETIRED_SKILL_IDS,
19
20
  TRACKS,
21
+ TRACK_AGENTS,
20
22
  __commonJS,
21
23
  __toESM,
22
24
  anyTrack,
@@ -62,7 +64,7 @@ import {
62
64
  upsertHarnessImport,
63
65
  withContinuousSkillsNote,
64
66
  writeInstallLog
65
- } from "./chunk-3QBHZUVB.js";
67
+ } from "./chunk-OYNSK6QF.js";
66
68
 
67
69
  // node_modules/sisteransi/src/index.js
68
70
  var require_src = __commonJS({
@@ -747,7 +749,7 @@ var cac = (name = "") => new CAC(name);
747
749
  // package.json
748
750
  var package_default = {
749
751
  name: "@uzysjung/agent-harness",
750
- version: "26.151.0",
752
+ version: "26.153.0",
751
753
  description: "Curate vetted AI-coding skills & plugins by your tech stack \u2014 install only what you need, across Claude Code, Codex, OpenCode & Antigravity",
752
754
  type: "module",
753
755
  publishConfig: {
@@ -986,14 +988,13 @@ function padDisplay(s, width) {
986
988
  init_esm_shims();
987
989
  import {
988
990
  chmodSync as chmodSync3,
989
- existsSync as existsSync14,
991
+ existsSync as existsSync13,
990
992
  mkdirSync as mkdirSync4,
991
993
  readdirSync as readdirSync4,
992
- readFileSync as readFileSync13,
993
- unlinkSync as unlinkSync3,
994
+ readFileSync as readFileSync12,
994
995
  writeFileSync as writeFileSync6
995
996
  } from "fs";
996
- import { basename as basename5, dirname as dirname4, join as join13, resolve } from "path";
997
+ import { basename as basename5, dirname as dirname4, join as join12, resolve } from "path";
997
998
 
998
999
  // src/ci-scaffold.ts
999
1000
  init_esm_shims();
@@ -2089,53 +2090,18 @@ function writeMcpJson(path, mcp) {
2089
2090
  `);
2090
2091
  }
2091
2092
 
2092
- // src/superseded.ts
2093
- init_esm_shims();
2094
- import { existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
2095
- import { join as join11 } from "path";
2096
- function sameTracks(a, b2) {
2097
- if (a.length !== b2.length) return false;
2098
- const sa = [...a].sort();
2099
- const sb = [...b2].sort();
2100
- return sa.every((t, i) => t === sb[i]);
2101
- }
2102
- function policyKey(claudeRelative) {
2103
- return POLICY_DIRS.some(
2104
- ({ dir, ext }) => claudeRelative.startsWith(`${dir}/`) && claudeRelative.endsWith(ext)
2105
- ) ? claudeRelative : null;
2106
- }
2107
- function findSuperseded(projectDir, spec, previous) {
2108
- if (!previous) return [];
2109
- if (!sameTracks(previous.spec.tracks, spec.tracks)) return [];
2110
- const baseline = new Map((previous.policyFiles ?? []).map((f) => [f.path, f.sha256]));
2111
- if (baseline.size === 0) return [];
2112
- const out = [];
2113
- for (const entry of buildManifest(spec)) {
2114
- if (entry.applies(spec)) continue;
2115
- const id = classifyBaselineTarget(entry.target)?.id;
2116
- if (!id) continue;
2117
- const key = policyKey(entry.target.slice(".claude/".length));
2118
- if (!key) continue;
2119
- const abs = join11(projectDir, entry.target);
2120
- if (!existsSync12(abs)) continue;
2121
- if (!isHarnessOwned(baseline, key, readFileSync11(abs, "utf-8"))) continue;
2122
- out.push({ target: entry.target, id, source: entry.source });
2123
- }
2124
- return out;
2125
- }
2126
-
2127
2093
  // src/update-mode.ts
2128
2094
  init_esm_shims();
2129
2095
  import {
2130
2096
  copyFileSync,
2131
- existsSync as existsSync13,
2097
+ existsSync as existsSync12,
2132
2098
  mkdirSync as mkdirSync3,
2133
2099
  readdirSync as readdirSync3,
2134
- readFileSync as readFileSync12,
2100
+ readFileSync as readFileSync11,
2135
2101
  unlinkSync as unlinkSync2,
2136
2102
  writeFileSync as writeFileSync5
2137
2103
  } from "fs";
2138
- import { basename as basename4, dirname as dirname3, join as join12 } from "path";
2104
+ import { basename as basename4, dirname as dirname3, join as join11 } from "path";
2139
2105
  var LEGACY_ANCHOR_FILE = ".claude/CLAUDE.md";
2140
2106
  function buildUpdateSpec(projectDir, tracks) {
2141
2107
  return {
@@ -2147,7 +2113,7 @@ function buildUpdateSpec(projectDir, tracks) {
2147
2113
  };
2148
2114
  }
2149
2115
  function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}) {
2150
- const claudeDir = join12(projectDir, ".claude");
2116
+ const claudeDir = join11(projectDir, ".claude");
2151
2117
  const report = {
2152
2118
  updated: {},
2153
2119
  pruned: {},
@@ -2171,6 +2137,7 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}) {
2171
2137
  restored: [],
2172
2138
  needsReinstall: [],
2173
2139
  retiredAgents: [],
2140
+ demotedAgents: [],
2174
2141
  mcpAllowlistRetired: null
2175
2142
  };
2176
2143
  const fresh = installNewAssets(projectDir, templatesDir);
@@ -2179,8 +2146,8 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}) {
2179
2146
  report.needsReinstall = fresh.needsReinstall;
2180
2147
  const policyBase = policyBaseline(projectDir);
2181
2148
  for (const { dir, ext } of POLICY_DIRS) {
2182
- const target = join12(claudeDir, dir);
2183
- const source = join12(templatesDir, dir);
2149
+ const target = join11(claudeDir, dir);
2150
+ const source = join11(templatesDir, dir);
2184
2151
  const label = `.claude/${dir}`;
2185
2152
  const ctx = { prefix: dir, baseline: policyBase };
2186
2153
  const synced = updateDir(target, source, ext, ctx);
@@ -2190,8 +2157,8 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}) {
2190
2157
  }
2191
2158
  refreshPolicyBaseline(projectDir, templatesDir);
2192
2159
  const skillSync = syncSkills(
2193
- join12(claudeDir, "skills"),
2194
- join12(templatesDir, "skills"),
2160
+ join11(claudeDir, "skills"),
2161
+ join11(templatesDir, "skills"),
2195
2162
  skillBaseline(projectDir),
2196
2163
  /* @__PURE__ */ new Date(),
2197
2164
  (relInSkills) => foreignOwnedTarget(projectDir, `.claude/skills/${relInSkills}`)
@@ -2201,15 +2168,16 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}) {
2201
2168
  report.skillsSkippedLinks = skillSync.skippedLinks;
2202
2169
  refreshSkillBaseline(projectDir);
2203
2170
  const installLog = readInstallLog(projectDir);
2204
- if (existsSync13(claudeDir) && (installLog === null || installLog.spec.cli.includes("claude"))) {
2171
+ if (existsSync12(claudeDir) && (installLog === null || installLog.spec.cli.includes("claude"))) {
2205
2172
  syncHarnessAnchor(projectDir, templatesDir, report);
2206
2173
  }
2207
- const settingsPath = join12(claudeDir, "settings.json");
2208
- if (existsSync13(settingsPath)) {
2174
+ const settingsPath = join11(claudeDir, "settings.json");
2175
+ if (existsSync12(settingsPath)) {
2209
2176
  report.staleHookRefs = cleanStaleHookRefs(settingsPath, claudeDir);
2210
2177
  }
2211
2178
  report.mcpAllowlistRetired = retireMcpAllowlist(projectDir);
2212
2179
  report.retiredAgents = staleAgentFiles(claudeDir);
2180
+ report.demotedAgents = demotedAgentFiles(claudeDir, installedTracks(projectDir));
2213
2181
  const external = refreshExternalCli(projectDir, harnessRoot);
2214
2182
  report.externalUpdated = external.externalUpdated;
2215
2183
  report.externalBackedUp = external.externalBackedUp;
@@ -2234,16 +2202,25 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}) {
2234
2202
  return report;
2235
2203
  }
2236
2204
  function staleSkillDirs(claudeDir) {
2237
- const dir = join12(claudeDir, "skills");
2238
- if (!existsSync13(dir)) return [];
2205
+ const dir = join11(claudeDir, "skills");
2206
+ if (!existsSync12(dir)) return [];
2239
2207
  const stale = (id) => RENAMED_SKILL_IDS[id] !== void 0 || RETIRED_SKILL_IDS.includes(id);
2240
2208
  return readdirSync3(dir, { withFileTypes: true }).filter((e2) => e2.isDirectory() && stale(e2.name)).map((e2) => e2.name);
2241
2209
  }
2242
2210
  function staleAgentFiles(claudeDir) {
2243
- const dir = join12(claudeDir, "agents");
2244
- if (!existsSync13(dir)) return [];
2211
+ const dir = join11(claudeDir, "agents");
2212
+ if (!existsSync12(dir)) return [];
2245
2213
  return readdirSync3(dir, { withFileTypes: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".md")).map((e2) => basename4(e2.name, ".md")).filter((id) => RETIRED_AGENT_IDS.includes(id));
2246
2214
  }
2215
+ function demotedAgentFiles(claudeDir, tracks) {
2216
+ if (tracks.length === 0) return [];
2217
+ const dir = join11(claudeDir, "agents");
2218
+ if (!existsSync12(dir)) return [];
2219
+ const demoted = TRACK_AGENTS.filter(([, pattern]) => !anyTrack(tracks, pattern)).map(
2220
+ ([id]) => id
2221
+ );
2222
+ return readdirSync3(dir, { withFileTypes: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".md")).map((e2) => basename4(e2.name, ".md")).filter((id) => demoted.includes(id));
2223
+ }
2247
2224
  function installNewAssets(projectDir, templatesDir) {
2248
2225
  const installed = [];
2249
2226
  const restored = [];
@@ -2256,15 +2233,15 @@ function installNewAssets(projectDir, templatesDir) {
2256
2233
  for (const entry of trackOnlyFileAssets(installedTracks(projectDir))) {
2257
2234
  if (entry.target === HARNESS_ANCHOR_FILE) continue;
2258
2235
  if (isBaselineExcluded(entry.target, baselineExcluded)) continue;
2259
- const target = join12(projectDir, entry.target);
2236
+ const target = join11(projectDir, entry.target);
2260
2237
  const foreign = foreignOwnedTarget(projectDir, entry.target);
2261
2238
  if (foreign !== null) {
2262
2239
  if (!foreignOwned.includes(foreign)) foreignOwned.push(foreign);
2263
2240
  continue;
2264
2241
  }
2265
- if (existsSync13(target)) continue;
2266
- const source = join12(templatesDir, entry.source);
2267
- if (!existsSync13(source)) continue;
2242
+ if (existsSync12(target)) continue;
2243
+ const source = join11(templatesDir, entry.source);
2244
+ if (!existsSync12(source)) continue;
2268
2245
  if (entry.target.startsWith(".claude/")) {
2269
2246
  if (!claudeSelected) continue;
2270
2247
  if (entry.target.startsWith(".claude/hooks/") || entry.target === ".claude/settings.json") {
@@ -2289,13 +2266,13 @@ function trackOnlyFileAssets(tracks) {
2289
2266
  );
2290
2267
  }
2291
2268
  function syncHarnessAnchor(projectDir, templatesDir, report) {
2292
- if (existsSync13(join12(projectDir, LEGACY_ANCHOR_FILE))) {
2269
+ if (existsSync12(join11(projectDir, LEGACY_ANCHOR_FILE))) {
2293
2270
  report.legacyAnchor = LEGACY_ANCHOR_FILE;
2294
2271
  }
2295
- const templateMd = join12(templatesDir, "CLAUDE.md");
2296
- if (!existsSync13(templateMd)) return;
2297
- const anchor = join12(projectDir, HARNESS_ANCHOR_FILE);
2298
- const existed = existsSync13(anchor);
2272
+ const templateMd = join11(templatesDir, "CLAUDE.md");
2273
+ if (!existsSync12(templateMd)) return;
2274
+ const anchor = join11(projectDir, HARNESS_ANCHOR_FILE);
2275
+ const existed = existsSync12(anchor);
2299
2276
  copyFileSync(templateMd, anchor);
2300
2277
  if (existed) {
2301
2278
  report.claudeMdUpdated = true;
@@ -2307,15 +2284,15 @@ function syncHarnessAnchor(projectDir, templatesDir, report) {
2307
2284
  recordAnchorBaseline(projectDir, anchor);
2308
2285
  }
2309
2286
  function upsertRootImport(projectDir) {
2310
- const target = join12(projectDir, "CLAUDE.md");
2311
- const existing = existsSync13(target) ? readFileSync12(target, "utf8") : null;
2287
+ const target = join11(projectDir, "CLAUDE.md");
2288
+ const existing = existsSync12(target) ? readFileSync11(target, "utf8") : null;
2312
2289
  const next = upsertHarnessImport(existing, {
2313
2290
  projectName: basename4(projectDir),
2314
2291
  tracks: installedTracks(projectDir),
2315
2292
  // ADR-085 — update 는 선택 목록을 인자로 받지 않는다. `syncSkills` 와 같은 판정을 쓴다:
2316
2293
  // `.claude/skills/<id>` 가 있으면 그 스킬은 이 설치가 고른 것이다.
2317
2294
  continuousSkills: CONTINUOUS_SKILLS.map((s) => s.id).filter(
2318
- (id) => existsSync13(join12(projectDir, ".claude/skills", id))
2295
+ (id) => existsSync12(join11(projectDir, ".claude/skills", id))
2319
2296
  )
2320
2297
  });
2321
2298
  if (next === existing) return false;
@@ -2335,7 +2312,7 @@ function recordAnchorBaseline(projectDir, anchor) {
2335
2312
  ...log.templates,
2336
2313
  rootClaudeMd: {
2337
2314
  path: HARNESS_ANCHOR_FILE,
2338
- sha256: hashContent(readFileSync12(anchor, "utf8"))
2315
+ sha256: hashContent(readFileSync11(anchor, "utf8"))
2339
2316
  }
2340
2317
  }
2341
2318
  };
@@ -2377,16 +2354,16 @@ function isHarnessOwned2(ctx, rel, current) {
2377
2354
  return isHarnessOwned(ctx.baseline, `${ctx.prefix}/${rel}`, current);
2378
2355
  }
2379
2356
  function updateDir(target, source, ext, ctx, now = /* @__PURE__ */ new Date()) {
2380
- if (!existsSync13(target) || !existsSync13(source)) return { updated: 0, backedUp: [] };
2357
+ if (!existsSync12(target) || !existsSync12(source)) return { updated: 0, backedUp: [] };
2381
2358
  let updated = 0;
2382
2359
  const backedUp = [];
2383
2360
  for (const file of readdirSync3(target)) {
2384
2361
  if (!file.endsWith(ext)) continue;
2385
- const targetFile = join12(target, file);
2386
- const sourceFile = join12(source, file);
2387
- if (!existsSync13(sourceFile)) continue;
2388
- const next = readFileSync12(sourceFile, "utf8");
2389
- const current = readFileSync12(targetFile, "utf8");
2362
+ const targetFile = join11(target, file);
2363
+ const sourceFile = join11(source, file);
2364
+ if (!existsSync12(sourceFile)) continue;
2365
+ const next = readFileSync11(sourceFile, "utf8");
2366
+ const current = readFileSync11(targetFile, "utf8");
2390
2367
  if (current === next) continue;
2391
2368
  if (!isHarnessOwned2(ctx, file, current)) {
2392
2369
  backupFile(targetFile, now);
@@ -2398,7 +2375,7 @@ function updateDir(target, source, ext, ctx, now = /* @__PURE__ */ new Date()) {
2398
2375
  return { updated, backedUp };
2399
2376
  }
2400
2377
  function syncSkills(targetDir, sourceDir, baseline, now = /* @__PURE__ */ new Date(), foreignOf) {
2401
- if (!existsSync13(targetDir) || !existsSync13(sourceDir))
2378
+ if (!existsSync12(targetDir) || !existsSync12(sourceDir))
2402
2379
  return { updated: 0, backedUp: [], skippedLinks: [], foreignOwned: [] };
2403
2380
  let updated = 0;
2404
2381
  const backedUp = [];
@@ -2406,27 +2383,27 @@ function syncSkills(targetDir, sourceDir, baseline, now = /* @__PURE__ */ new Da
2406
2383
  const foreignOwned = [];
2407
2384
  for (const skill of readdirSync3(sourceDir, { withFileTypes: true })) {
2408
2385
  if (!skill.isDirectory()) continue;
2409
- const targetSkill = join12(targetDir, skill.name);
2386
+ const targetSkill = join11(targetDir, skill.name);
2410
2387
  if (occupiedByNonDirectory(targetSkill)) {
2411
2388
  skippedLinks.push(skill.name);
2412
2389
  continue;
2413
2390
  }
2414
- if (!existsSync13(targetSkill)) continue;
2415
- for (const rel of listFilesRecursive(join12(sourceDir, skill.name))) {
2416
- const targetFile = join12(targetSkill, rel);
2391
+ if (!existsSync12(targetSkill)) continue;
2392
+ for (const rel of listFilesRecursive(join11(sourceDir, skill.name))) {
2393
+ const targetFile = join11(targetSkill, rel);
2417
2394
  const foreign = foreignOf(`${skill.name}/${rel}`);
2418
2395
  if (foreign !== null) {
2419
2396
  if (!foreignOwned.includes(foreign)) foreignOwned.push(foreign);
2420
2397
  continue;
2421
2398
  }
2422
- const next = readFileSync12(join12(sourceDir, skill.name, rel), "utf8");
2423
- if (!existsSync13(targetFile)) {
2399
+ const next = readFileSync11(join11(sourceDir, skill.name, rel), "utf8");
2400
+ if (!existsSync12(targetFile)) {
2424
2401
  mkdirSync3(dirname3(targetFile), { recursive: true });
2425
2402
  writeFileSync5(targetFile, next);
2426
2403
  updated++;
2427
2404
  continue;
2428
2405
  }
2429
- const current = readFileSync12(targetFile, "utf8");
2406
+ const current = readFileSync11(targetFile, "utf8");
2430
2407
  if (current === next) continue;
2431
2408
  const recorded = baseline.get(`${skill.name}/${rel}`);
2432
2409
  if (recorded === void 0 || hashContent(current) !== recorded) {
@@ -2472,16 +2449,16 @@ function refreshSkillBaseline(projectDir) {
2472
2449
  }
2473
2450
  }
2474
2451
  function pruneOrphans(target, source, ext, ctx, now = /* @__PURE__ */ new Date()) {
2475
- if (!existsSync13(target) || !existsSync13(source)) return [];
2452
+ if (!existsSync12(target) || !existsSync12(source)) return [];
2476
2453
  const removed = [];
2477
2454
  for (const file of readdirSync3(target)) {
2478
2455
  if (!file.endsWith(ext)) continue;
2479
- const sourceFile = join12(source, file);
2480
- if (!existsSync13(sourceFile)) {
2481
- const targetFile = join12(target, file);
2456
+ const sourceFile = join11(source, file);
2457
+ if (!existsSync12(sourceFile)) {
2458
+ const targetFile = join11(target, file);
2482
2459
  if (!ctx.baseline.has(`${ctx.prefix}/${file}`)) continue;
2483
2460
  try {
2484
- const current = readFileSync12(targetFile, "utf8");
2461
+ const current = readFileSync11(targetFile, "utf8");
2485
2462
  if (!isHarnessOwned2(ctx, file, current)) backupFile(targetFile, now);
2486
2463
  unlinkSync2(targetFile);
2487
2464
  removed.push(file);
@@ -2492,8 +2469,8 @@ function pruneOrphans(target, source, ext, ctx, now = /* @__PURE__ */ new Date()
2492
2469
  return removed;
2493
2470
  }
2494
2471
  function retireMcpAllowlist(projectDir, now = /* @__PURE__ */ new Date()) {
2495
- const target = join12(projectDir, ".mcp-allowlist");
2496
- if (!existsSync13(target)) return null;
2472
+ const target = join11(projectDir, ".mcp-allowlist");
2473
+ if (!existsSync12(target)) return null;
2497
2474
  try {
2498
2475
  const backup = backupFile(target, now);
2499
2476
  unlinkSync2(target);
@@ -2505,7 +2482,7 @@ function retireMcpAllowlist(projectDir, now = /* @__PURE__ */ new Date()) {
2505
2482
  function cleanStaleHookRefs(settingsPath, claudeDir) {
2506
2483
  let settings;
2507
2484
  try {
2508
- settings = JSON.parse(readFileSync12(settingsPath, "utf8"));
2485
+ settings = JSON.parse(readFileSync11(settingsPath, "utf8"));
2509
2486
  } catch {
2510
2487
  return [];
2511
2488
  }
@@ -2532,7 +2509,7 @@ function cleanStaleHookRefs(settingsPath, claudeDir) {
2532
2509
  function keepHookRef(hook, claudeDir, removed) {
2533
2510
  const relPath = projectAnchoredRef(hook?.command ?? "", claudeDir);
2534
2511
  if (relPath === void 0) return true;
2535
- const exists = existsSync13(join12(claudeDir, relPath));
2512
+ const exists = existsSync12(join11(claudeDir, relPath));
2536
2513
  if (!exists && !removed.includes(relPath)) removed.push(relPath);
2537
2514
  return exists;
2538
2515
  }
@@ -2559,14 +2536,14 @@ function projectAnchoredRef(command, claudeDir) {
2559
2536
  function runInstall(ctx) {
2560
2537
  const { harnessRoot, projectDir, spec } = ctx;
2561
2538
  const mode = ctx.mode ?? "fresh";
2562
- const templatesDir = join13(harnessRoot, "templates");
2563
- if (!existsSync14(templatesDir)) {
2539
+ const templatesDir = join12(harnessRoot, "templates");
2540
+ if (!existsSync13(templatesDir)) {
2564
2541
  throw new Error(`Templates dir not found: ${templatesDir}`);
2565
2542
  }
2566
- const claudeDir = join13(projectDir, ".claude");
2543
+ const claudeDir = join12(projectDir, ".claude");
2567
2544
  const previousLog = readInstallLog(projectDir);
2568
2545
  const claudeWasSelected = previousLog?.spec.cli.includes("claude") ?? false;
2569
- if (mode === "update" && !existsSync14(claudeDir) && (previousLog === null || claudeWasSelected)) {
2546
+ if (mode === "update" && !existsSync13(claudeDir) && (previousLog === null || claudeWasSelected)) {
2570
2547
  throw new Error(
2571
2548
  claudeWasSelected ? `Update mode found a broken install at ${projectDir} \u2014 this project installed Claude Code assets but \`.claude/\` is gone. Reinstall instead: agent-harness install --track <name>` : `Update mode requires an existing install at ${projectDir}`
2572
2549
  );
@@ -2578,7 +2555,6 @@ function runInstall(ctx) {
2578
2555
  const manifestSpec = buildManifestSpec(spec);
2579
2556
  const policyBase = new Map((previousLog?.policyFiles ?? []).map((f) => [f.path, f.sha256]));
2580
2557
  const baselineExcluded = new Set(spec.baselineExclude ?? []);
2581
- const supersededFound = findSuperseded(projectDir, manifestSpec, previousLog);
2582
2558
  const base = spec.cli.includes("claude") ? installClaudeBaseline(manifestSpec, projectDir, templatesDir, policyBase, baselineExcluded) : (
2583
2559
  // claude 미선택이어도 CLI 중립 자산은 깔린다. manifest 전체가 `.claude/` baseline 안에서만
2584
2560
  // 돌던 탓에 이 자산들이 claude 설치에만 도달했는데, **배포 룰 본문이 이 스크립트들을
@@ -2634,10 +2610,7 @@ function runInstall(ctx) {
2634
2610
  baselineForeignOwned: [
2635
2611
  ...base.foreignOwned,
2636
2612
  ...externalForeignOwned.filter((f) => !base.foreignOwned.includes(f))
2637
- ],
2638
- // 밀려난 자산 정리는 **manifest 복사가 끝난 뒤**에 한다. 앞에서 지우면 이번 설치가 다시
2639
- // 깔 수도 있는 파일을 지웠다 되돌리는 셈이라, 무엇이 최종 상태인지 보고가 흐려진다.
2640
- superseded: applySupersededCleanup(spec, projectDir, supersededFound)
2613
+ ]
2641
2614
  };
2642
2615
  ctx.onProgress?.({ type: "baseline-complete", baseline });
2643
2616
  const external = runExternalPhase(ctx);
@@ -2653,26 +2626,11 @@ function runInstall(ctx) {
2653
2626
  );
2654
2627
  return { ...baseline, external, staleHookRefs };
2655
2628
  }
2656
- function applySupersededCleanup(spec, projectDir, found) {
2657
- if (found.length === 0) return { removed: [], kept: [] };
2658
- if (!spec.cleanSuperseded) return { removed: [], kept: found.map((f) => f.target) };
2659
- const removed = [];
2660
- const kept = [];
2661
- for (const asset of found) {
2662
- try {
2663
- unlinkSync3(join13(projectDir, asset.target));
2664
- removed.push(asset.target);
2665
- } catch {
2666
- kept.push(asset.target);
2667
- }
2668
- }
2669
- return { removed, kept };
2670
- }
2671
2629
  function healStaleHookRefs(spec, projectDir) {
2672
2630
  if (!spec.cli.includes("claude")) return [];
2673
- const settingsPath = join13(projectDir, ".claude/settings.json");
2674
- if (!existsSync14(settingsPath)) return [];
2675
- return cleanStaleHookRefs(settingsPath, join13(projectDir, ".claude"));
2631
+ const settingsPath = join12(projectDir, ".claude/settings.json");
2632
+ if (!existsSync13(settingsPath)) return [];
2633
+ return cleanStaleHookRefs(settingsPath, join12(projectDir, ".claude"));
2676
2634
  }
2677
2635
  function resolveBackupPath(ctx, mode, claudeDir) {
2678
2636
  const wantBackup = ctx.backup ?? (mode === "update" || mode === "reinstall");
@@ -2688,9 +2646,6 @@ function runUpdateInstall(ctx, templatesDir, backupPath) {
2688
2646
  baselineExcluded: [],
2689
2647
  baselineExcludedOnDisk: [],
2690
2648
  baselineForeignOwned: [],
2691
- // update 는 밀려난 자산을 다루지 않는다 — 그 판정은 사용자가 옵션을 고르는 설치 경로의
2692
- // 것이고, update 는 무엇을 골랐는지 다시 묻지 않는다.
2693
- superseded: { removed: [], kept: [] },
2694
2649
  backup: backupPath,
2695
2650
  installedTracks: [...ctx.spec.tracks].sort(),
2696
2651
  mcpServers: [],
@@ -2741,12 +2696,12 @@ function installCliNeutralAssets(manifestSpec, projectDir, templatesDir, baselin
2741
2696
  continue;
2742
2697
  }
2743
2698
  if (!isCliNeutralTarget(entry.target)) continue;
2744
- const source = join13(templatesDir, entry.source);
2745
- if (!existsSync14(source)) {
2699
+ const source = join12(templatesDir, entry.source);
2700
+ if (!existsSync13(source)) {
2746
2701
  result.skipped += 1;
2747
2702
  continue;
2748
2703
  }
2749
- copyFile(source, join13(projectDir, entry.target));
2704
+ copyFile(source, join12(projectDir, entry.target));
2750
2705
  result.filesCopied += 1;
2751
2706
  }
2752
2707
  return result;
@@ -2758,9 +2713,9 @@ function backupEditedPolicyFile(entryTarget, target, source, baseline) {
2758
2713
  if (!POLICY_DIRS.some(({ dir, ext }) => rel.startsWith(`${dir}/`) && rel.endsWith(ext))) {
2759
2714
  return null;
2760
2715
  }
2761
- if (!existsSync14(target)) return null;
2762
- const current = readFileSync13(target, "utf-8");
2763
- if (current === readFileSync13(source, "utf-8")) return null;
2716
+ if (!existsSync13(target)) return null;
2717
+ const current = readFileSync12(target, "utf-8");
2718
+ if (current === readFileSync12(source, "utf-8")) return null;
2764
2719
  const recorded = baseline.get(rel);
2765
2720
  if (recorded !== void 0 && recorded === hashContent(current)) return null;
2766
2721
  return backupFile(target);
@@ -2773,14 +2728,14 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir, policyBas
2773
2728
  if (!entry.applies(manifestSpec)) {
2774
2729
  continue;
2775
2730
  }
2776
- const target = join13(projectDir, entry.target);
2731
+ const target = join12(projectDir, entry.target);
2777
2732
  if (isBaselineExcluded(entry.target, baselineExcluded)) {
2778
2733
  result.excluded.push(entry.target);
2779
- if (existsSync14(target)) result.excludedOnDisk.push(entry.target);
2734
+ if (existsSync13(target)) result.excludedOnDisk.push(entry.target);
2780
2735
  continue;
2781
2736
  }
2782
- const source = join13(templatesDir, entry.source);
2783
- if (!existsSync14(source)) {
2737
+ const source = join12(templatesDir, entry.source);
2738
+ if (!existsSync13(source)) {
2784
2739
  result.skipped += 1;
2785
2740
  continue;
2786
2741
  }
@@ -2791,7 +2746,7 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir, policyBas
2791
2746
  }
2792
2747
  if (entry.type === "file") {
2793
2748
  if (entry.target === ".claude/settings.json") {
2794
- const backup = backupFileIfChanged(target, readFileSync13(source, "utf-8"));
2749
+ const backup = backupFileIfChanged(target, readFileSync12(source, "utf-8"));
2795
2750
  if (backup) {
2796
2751
  result.backups.push(backup);
2797
2752
  }
@@ -2815,8 +2770,8 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir, policyBas
2815
2770
  }
2816
2771
  accumulateCategory(result.categories, entry);
2817
2772
  }
2818
- const hookDir = join13(projectDir, ".claude/hooks");
2819
- if (existsSync14(hookDir)) {
2773
+ const hookDir = join12(projectDir, ".claude/hooks");
2774
+ if (existsSync13(hookDir)) {
2820
2775
  chmodHooksSync(hookDir);
2821
2776
  }
2822
2777
  writeInstalledTracks(projectDir, manifestSpec.tracks);
@@ -2830,9 +2785,9 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir, policyBas
2830
2785
  return result;
2831
2786
  }
2832
2787
  function harnessAnchorLog(projectDir) {
2833
- const anchor = join13(projectDir, HARNESS_ANCHOR_FILE);
2834
- if (!existsSync14(anchor)) return null;
2835
- return { path: HARNESS_ANCHOR_FILE, sha256: hashContent(readFileSync13(anchor, "utf-8")) };
2788
+ const anchor = join12(projectDir, HARNESS_ANCHOR_FILE);
2789
+ if (!existsSync13(anchor)) return null;
2790
+ return { path: HARNESS_ANCHOR_FILE, sha256: hashContent(readFileSync12(anchor, "utf-8")) };
2836
2791
  }
2837
2792
  function writeEnvironmentFiles(projectDir, tracks) {
2838
2793
  return {
@@ -2891,7 +2846,7 @@ function writeInstallLogSafe(ctx, externalFiles, external, rootClaudeMdLog, prev
2891
2846
  rootFiles
2892
2847
  );
2893
2848
  const skillFiles = collectSkillHashes(ctx.projectDir);
2894
- const policyFiles = collectPolicyHashes(ctx.projectDir, join13(ctx.harnessRoot, "templates"));
2849
+ const policyFiles = collectPolicyHashes(ctx.projectDir, join12(ctx.harnessRoot, "templates"));
2895
2850
  const merged = mergeExternalFiles(ctx.projectDir, previousLog?.externalFiles, externalFiles);
2896
2851
  writeInstallLog(ctx.projectDir, {
2897
2852
  ...log,
@@ -2907,11 +2862,11 @@ function writeInstallLogSafe(ctx, externalFiles, external, rootClaudeMdLog, prev
2907
2862
  }
2908
2863
  }
2909
2864
  function composeAndWriteMcp(harnessRoot, projectDir, spec) {
2910
- const mcpPath = join13(projectDir, ".mcp.json");
2911
- const created = !existsSync14(mcpPath);
2865
+ const mcpPath = join12(projectDir, ".mcp.json");
2866
+ const created = !existsSync13(mcpPath);
2912
2867
  const composed = composeMcpJson({
2913
- templateMcpPath: join13(harnessRoot, "templates/mcp.json"),
2914
- trackMapPath: join13(harnessRoot, "templates/track-mcp-map.tsv"),
2868
+ templateMcpPath: join12(harnessRoot, "templates/mcp.json"),
2869
+ trackMapPath: join12(harnessRoot, "templates/track-mcp-map.tsv"),
2915
2870
  existingPath: mcpPath,
2916
2871
  tracks: spec.tracks
2917
2872
  });
@@ -2964,15 +2919,15 @@ function accumulateCategory(cats, entry) {
2964
2919
  }
2965
2920
  }
2966
2921
  function writeInstalledTracks(projectDir, tracks) {
2967
- const path = join13(projectDir, ".claude/.installed-tracks");
2922
+ const path = join12(projectDir, ".claude/.installed-tracks");
2968
2923
  mkdirSync4(dirname4(path), { recursive: true });
2969
2924
  const sorted = [...new Set(tracks)].sort().join("\n");
2970
2925
  writeFileSync6(path, `${sorted}
2971
2926
  `);
2972
2927
  }
2973
2928
  function writeRootClaudeMd(projectDir, tracks, continuousSkills) {
2974
- const target = join13(projectDir, "CLAUDE.md");
2975
- const existing = existsSync14(target) ? readFileSync13(target, "utf-8") : null;
2929
+ const target = join12(projectDir, "CLAUDE.md");
2930
+ const existing = existsSync13(target) ? readFileSync12(target, "utf-8") : null;
2976
2931
  const content = upsertHarnessImport(existing, {
2977
2932
  projectName: basename5(projectDir),
2978
2933
  tracks,
@@ -2997,6 +2952,8 @@ function listHookFiles(hookDir) {
2997
2952
 
2998
2953
  // src/commands/install-render.ts
2999
2954
  init_esm_shims();
2955
+ import { existsSync as existsSync14, readdirSync as readdirSync5 } from "fs";
2956
+ import { join as join13 } from "path";
3000
2957
 
3001
2958
  // src/preset-recommend.ts
3002
2959
  init_esm_shims();
@@ -3062,12 +3019,14 @@ function renderInstallHeader(log, spec, mode) {
3062
3019
  for (const [cat, ids] of groupAssetsByCategory(finalAssets)) {
3063
3020
  log(` ${c.dim(`\xB7 ${cat}:`)} ${ids.join(", ")}`);
3064
3021
  }
3065
- const assetSpec = buildManifestSpec(spec);
3066
- const cost = formatResidentCostLine(
3067
- residentCost(buildManifest(assetSpec).filter((e2) => e2.applies(assetSpec))),
3068
- summarizeContextCost(finalAssets).unmeasuredCount
3069
- );
3070
- if (cost) log(` ${c.dim(`\xB7 ${cost}`)}`);
3022
+ if (mode !== "update") {
3023
+ const assetSpec = buildManifestSpec(spec);
3024
+ const cost = formatResidentCostLine(
3025
+ residentCost(buildManifest(assetSpec).filter((e2) => e2.applies(assetSpec))),
3026
+ summarizeContextCost(finalAssets).unmeasuredCount
3027
+ );
3028
+ if (cost) log(` ${c.dim(`\xB7 ${cost}`)}`);
3029
+ }
3071
3030
  }
3072
3031
  log("");
3073
3032
  }
@@ -3121,7 +3080,7 @@ function createInstallRenderer(log, spec, verbose) {
3121
3080
  };
3122
3081
  return { callbacks, phase2HeaderPrinted: () => phase2HeaderPrinted };
3123
3082
  }
3124
- function renderUpdateSummary(log, report) {
3083
+ function renderUpdateSummary(log, spec, report) {
3125
3084
  log("");
3126
3085
  log(unifiedSection("Summary"));
3127
3086
  log("");
@@ -3131,8 +3090,26 @@ function renderUpdateSummary(log, report) {
3131
3090
  log(infoRow("BACKUP", shortenPath(report.backup)));
3132
3091
  log(infoRow("ROLLBACK", `rm -rf .claude && mv ${shortenPath(report.backup)} .claude`));
3133
3092
  }
3093
+ const cost = formatResidentCostLine(
3094
+ residentCost(residentEntriesOnDisk(spec)),
3095
+ summarizeContextCost(finalSelectedAssets(spec.tracks, spec.userOverride)).unmeasuredCount
3096
+ );
3097
+ if (cost) log(infoRow("CONTEXT", cost));
3134
3098
  log("");
3135
3099
  }
3100
+ function residentEntriesOnDisk(spec) {
3101
+ const assetSpec = buildManifestSpec(spec);
3102
+ const planned = buildManifest(assetSpec).filter((e2) => e2.applies(assetSpec));
3103
+ const agentsDir = join13(spec.projectDir, ".claude", "agents");
3104
+ const onDisk = existsSync14(agentsDir) ? readdirSync5(agentsDir, { withFileTypes: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".md")).map((e2) => ({
3105
+ source: `agents/${e2.name}`,
3106
+ target: `.claude/agents/${e2.name}`,
3107
+ // 배포판이 아니라 **이 프로젝트의 파일**을 잰다 — 사용자가 고친 descriptor 도,
3108
+ // 배포판에 더는 없는 에이전트도 실제로 상주하는 것은 이쪽이다.
3109
+ file: join13(agentsDir, e2.name)
3110
+ })) : [];
3111
+ return [...planned.filter((e2) => !e2.target.startsWith(".claude/agents/")), ...onDisk];
3112
+ }
3136
3113
  function renderCliArtifacts(log, spec, report) {
3137
3114
  const hasArtifacts = Boolean(report.codex || report.opencode || report.antigravity);
3138
3115
  const cliSelected = targetsInclude(spec.cli, "codex") || targetsInclude(spec.cli, "opencode") || targetsInclude(spec.cli, "antigravity");
@@ -3401,11 +3378,22 @@ function renderPhase1Rows(log, baseline, verbose = false, withEcc = false, claud
3401
3378
  );
3402
3379
  }
3403
3380
  for (const id of baseline.updateMode.retiredAgents) {
3381
+ const instead = RETIRED_AGENTS.find((a) => a.id === id)?.instead;
3382
+ log(
3383
+ assetRow(
3384
+ "skip",
3385
+ "agents",
3386
+ `${id} \xB7 \uC774 \uB9B4\uB9AC\uC988\uC5D0\uC11C \uC740\uD1F4 \u2014 .claude/agents/${id}.md \uB97C \uC9C0\uC6CC\uB3C4 \uB41C\uB2E4` + (instead === void 0 ? "" : ` \xB7 ${instead}`)
3387
+ )
3388
+ );
3389
+ }
3390
+ for (const [id, pattern] of TRACK_AGENTS) {
3391
+ if (!baseline.updateMode.demotedAgents.includes(id)) continue;
3404
3392
  log(
3405
3393
  assetRow(
3406
3394
  "skip",
3407
3395
  "agents",
3408
- `${id} \xB7 \uC774 \uB9B4\uB9AC\uC988\uC5D0\uC11C \uC740\uD1F4 \u2014 .claude/agents/${id}.md \uB97C \uC9C0\uC6CC\uB3C4 \uB41C\uB2E4 \xB7 Claude Code \uC758 \`/code-review\` \xB7 \`/security-review\` \uAC00 \uAC19\uC740 \uC77C\uC744 \uD55C\uB2E4`
3396
+ `${id} \xB7 \uC774 \uD2B8\uB799\uC5D0\uC11C\uB294 \uB354 \uC774\uC0C1 \uC124\uCE58\uD558\uC9C0 \uC54A\uB294\uB2E4 \u2014 ${pattern.split("|").join(" \xB7 ")} \uD2B8\uB799 \uC804\uC6A9 \xB7 .claude/agents/${id}.md \uB97C \uC9C0\uC6CC\uB3C4 \uB41C\uB2E4`
3409
3397
  )
3410
3398
  );
3411
3399
  }
@@ -3532,7 +3520,7 @@ function renderPhase1Rows(log, baseline, verbose = false, withEcc = false, claud
3532
3520
  phase1Row(
3533
3521
  "agents",
3534
3522
  cats.agents.length,
3535
- "SOD reviewer (opus, independent verifier) + 3 base",
3523
+ "independent verifier \xB7 implementation lane \xB7 domain lanes (track)",
3536
3524
  cats.agents
3537
3525
  );
3538
3526
  }
@@ -3546,7 +3534,7 @@ function renderPhase1Rows(log, baseline, verbose = false, withEcc = false, claud
3546
3534
  phase1Row(
3547
3535
  "skills",
3548
3536
  cats.skills.length,
3549
- "deep-research \xB7 ui-visual-review \xB7 eval-harness (modified)",
3537
+ "bundled methodology skills (track \xB7 opt-in)",
3550
3538
  cats.skills
3551
3539
  );
3552
3540
  }
@@ -3577,24 +3565,6 @@ function renderPhase1Rows(log, baseline, verbose = false, withEcc = false, claud
3577
3565
  )
3578
3566
  );
3579
3567
  }
3580
- if (baseline.superseded.removed.length > 0) {
3581
- log(
3582
- assetRow(
3583
- "success",
3584
- "superseded \u2014 cleaned",
3585
- `${baseline.superseded.removed.length} \u2014 ${baseline.superseded.removed.map((t) => t.replace(/^\.claude\//, "")).join(", ")} \xB7 \uB418\uB3CC\uB9AC\uB824\uBA74 \uADF8 \uC790\uC0B0 \uC5C6\uC774 \uC7AC\uC124\uCE58`
3586
- )
3587
- );
3588
- }
3589
- if (baseline.superseded.kept.length > 0) {
3590
- log(
3591
- assetRow(
3592
- "skip",
3593
- "superseded \u2014 kept",
3594
- `${baseline.superseded.kept.length} \u2014 ${baseline.superseded.kept.map((t) => t.replace(/^\.claude\//, "")).join(", ")} \xB7 \uC774\uBC88 \uC120\uD0DD\uC774 \uB300\uCCB4\uD588\uC9C0\uB9CC \uC9C0\uC6B0\uC9C0 \uC54A\uC558\uB2E4 (\uC81C\uAC70: agent-harness uninstall)`
3595
- )
3596
- );
3597
- }
3598
3568
  const TEMPLATES_COL = 28;
3599
3569
  if (baseline.rootClaudeMd) {
3600
3570
  const n = baseline.rootClaudeMd.tracks.length;
@@ -3809,7 +3779,7 @@ function executeSpec(spec, deps = {}) {
3809
3779
  return;
3810
3780
  }
3811
3781
  if (report.updateMode) {
3812
- renderUpdateSummary(log, report);
3782
+ renderUpdateSummary(log, spec, report);
3813
3783
  return;
3814
3784
  }
3815
3785
  if (renderer.phase2HeaderPrinted()) {
@@ -3874,7 +3844,7 @@ function registerInstallCommand(cli2) {
3874
3844
 
3875
3845
  // src/commands/list.ts
3876
3846
  init_esm_shims();
3877
- import { existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
3847
+ import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
3878
3848
  import { join as join14, resolve as resolve3 } from "path";
3879
3849
  function listAction(options = {}, deps = {}) {
3880
3850
  const log = deps.log ?? console.log;
@@ -3939,7 +3909,7 @@ function formatTemplateRows(log, projectDir) {
3939
3909
  const rootMd = log.templates.rootClaudeMd;
3940
3910
  if (rootMd) {
3941
3911
  const path = join14(projectDir, rootMd.path);
3942
- const modified = existsSync15(path) && hashContent(readFileSync14(path, "utf8")) !== rootMd.sha256;
3912
+ const modified = existsSync15(path) && hashContent(readFileSync13(path, "utf8")) !== rootMd.sha256;
3943
3913
  rows.push(
3944
3914
  modified ? ` ${c.dim(rootMd.path)} ${c.yellow("(\uC218\uC815\uB428 \u2014 uninstall \uC2DC \uBCF4\uC874)")}` : ` ${c.dim(rootMd.path)}`
3945
3915
  );
@@ -3967,8 +3937,8 @@ import { spawnSync as spawnSync2 } from "child_process";
3967
3937
  import {
3968
3938
  existsSync as existsSync16,
3969
3939
  lstatSync as lstatSync2,
3970
- readdirSync as readdirSync5,
3971
- readFileSync as readFileSync15,
3940
+ readdirSync as readdirSync6,
3941
+ readFileSync as readFileSync14,
3972
3942
  rmdirSync,
3973
3943
  rmSync,
3974
3944
  writeFileSync as writeFileSync7
@@ -5384,7 +5354,7 @@ function removeExternalFiles(log, projectDir, rm) {
5384
5354
  const abs = join15(projectDir, path);
5385
5355
  if (!existsSync16(abs)) continue;
5386
5356
  if (!lstatSync2(abs).isFile()) continue;
5387
- if (hashContent(readFileSync15(abs, "utf8")) !== sha256) {
5357
+ if (hashContent(readFileSync14(abs, "utf8")) !== sha256) {
5388
5358
  kept.push(path);
5389
5359
  continue;
5390
5360
  }
@@ -5400,7 +5370,7 @@ function pruneEmptyDirsUpward(projectDir, startDir) {
5400
5370
  const rel = relative2(projectDir, cursor);
5401
5371
  if (rel === "" || rel.startsWith(`..${sep2}`) || rel === "..") return;
5402
5372
  try {
5403
- if (readdirSync5(cursor).length > 0) return;
5373
+ if (readdirSync6(cursor).length > 0) return;
5404
5374
  rmdirSync(cursor);
5405
5375
  } catch {
5406
5376
  return;
@@ -5425,7 +5395,7 @@ function previewExternalLines(installLog, projectDir) {
5425
5395
  for (const { path, sha256 } of installLog.externalFiles ?? []) {
5426
5396
  const abs = join15(projectDir, path);
5427
5397
  if (!existsSync16(abs)) continue;
5428
- if (hashContent(readFileSync15(abs, "utf8")) !== sha256) {
5398
+ if (hashContent(readFileSync14(abs, "utf8")) !== sha256) {
5429
5399
  lines.push(` \u25CB keep ${path} (modified since install \u2014 preserved)`);
5430
5400
  continue;
5431
5401
  }
@@ -5454,7 +5424,7 @@ function readRootClaudeMd(projectDir) {
5454
5424
  const path = join15(projectDir, "CLAUDE.md");
5455
5425
  if (!existsSync16(path)) return null;
5456
5426
  try {
5457
- return readFileSync15(path, "utf8");
5427
+ return readFileSync14(path, "utf8");
5458
5428
  } catch {
5459
5429
  return null;
5460
5430
  }
@@ -5464,7 +5434,7 @@ function rootClaudeMdModified(log, projectDir) {
5464
5434
  if (!rootMd) return false;
5465
5435
  const path = join15(projectDir, rootMd.path);
5466
5436
  if (!existsSync16(path)) return false;
5467
- return hashContent(readFileSync15(path, "utf8")) !== rootMd.sha256;
5437
+ return hashContent(readFileSync14(path, "utf8")) !== rootMd.sha256;
5468
5438
  }
5469
5439
  function formatTemplateList(log) {
5470
5440
  const items = [log.templates.claudeDir];
@@ -5524,7 +5494,7 @@ import { resolve as resolve5 } from "path";
5524
5494
 
5525
5495
  // src/state.ts
5526
5496
  init_esm_shims();
5527
- import { existsSync as existsSync17, readFileSync as readFileSync16 } from "fs";
5497
+ import { existsSync as existsSync17, readFileSync as readFileSync15 } from "fs";
5528
5498
  import { join as join16 } from "path";
5529
5499
  var META_FILE = ".claude/.installed-tracks";
5530
5500
  var LEGACY_SIGNATURES = [
@@ -5561,7 +5531,7 @@ function tracksFromLog(tracks) {
5561
5531
  return [...new Set(tracks.filter(isTrack))].sort();
5562
5532
  }
5563
5533
  function readMetafile(path) {
5564
- const raw = readFileSync16(path, "utf8");
5534
+ const raw = readFileSync15(path, "utf8");
5565
5535
  const seen = /* @__PURE__ */ new Set();
5566
5536
  for (const line of raw.split(/\s+/)) {
5567
5537
  const trimmed = line.trim();
@@ -5890,23 +5860,6 @@ Proceed?`,
5890
5860
  });
5891
5861
  return q(result) ? null : result;
5892
5862
  },
5893
- confirmSupersededCleanup: async (items, context) => {
5894
- const names = items.map((i) => i.target.replace(/^\.claude\//, "")).join("\n ");
5895
- const result = await ue({
5896
- message: [
5897
- `${context.by.join(" \xB7 ")} \uC744(\uB97C) \uACE8\uB77C\uC11C \uC544\uB798 ${items.length}\uAC1C\uAC00 \uC124\uCE58 \uB300\uC0C1\uC5D0\uC11C \uBE60\uC84C\uC2B5\uB2C8\uB2E4.`,
5898
- "\uADF8\uB7F0\uB370 \uC774\uC804 \uC124\uCE58\uBCF8\uC774 \uB514\uC2A4\uD06C\uC5D0 \uADF8\uB300\uB85C \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4:",
5899
- ` ${names}`,
5900
- "",
5901
- `\uADF8\uB300\uB85C \uB450\uBA74 \uAC19\uC740 \uC77C\uC744 \uD558\uB294 \uC5D0\uC774\uC804\uD2B8\uAC00 \uB450 \uBC8C\uC774\uACE0, \uB9E4 \uC138\uC158 ~${context.tokens} tok \uB97C \uACC4\uC18D \uBB45\uB2C8\uB2E4.`,
5902
- "(\uD558\uB124\uC2A4\uAC00 \uAE54\uC558\uACE0 \uC218\uC815\uB418\uC9C0 \uC54A\uC740 \uD30C\uC77C\uB9CC \uB300\uC0C1\uC785\uB2C8\uB2E4 \u2014 \uC9C1\uC811 \uACE0\uCE5C \uD30C\uC77C\uC740 \uAC74\uB4DC\uB9AC\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4)",
5903
- "",
5904
- "\uC815\uB9AC\uD560\uAE4C\uC694?"
5905
- ].join("\n"),
5906
- initialValue: true
5907
- });
5908
- return q(result) ? null : result;
5909
- },
5910
5863
  selectInstallTargets: async (initialChecked, step, recap) => {
5911
5864
  const pages = INSTALL_TARGET_PAGES;
5912
5865
  const baselineTargets = listBaselineTargets({ tracks: recap?.tracks ?? [] });
@@ -6172,50 +6125,11 @@ ${summary}`
6172
6125
  ...userOverride ? { userOverride } : {},
6173
6126
  ...baselineExclude.length > 0 ? { baselineExclude } : {}
6174
6127
  };
6175
- const superseded = findSuperseded(
6176
- projectDir,
6177
- buildManifestSpec(spec),
6178
- readInstallLog(projectDir)
6179
- );
6180
- let cleanSuperseded = false;
6181
- if (superseded.length > 0) {
6182
- const cause = supersededCause(projectDir, spec, readInstallLog(projectDir), superseded);
6183
- const answer = await prompts.confirmSupersededCleanup(superseded, {
6184
- by: cause.length > 0 ? cause : ["\uC774\uBC88 \uC120\uD0DD"],
6185
- tokens: supersededTokens(superseded)
6186
- });
6187
- if (answer === null) {
6188
- step = "confirm";
6189
- continue;
6190
- }
6191
- cleanSuperseded = answer;
6192
- }
6193
6128
  prompts.outro(stepLabel(WIZARD.INSTALL, "Installing..."));
6194
- return {
6195
- ok: true,
6196
- mode,
6197
- spec: { ...spec, ...cleanSuperseded ? { cleanSuperseded } : {} }
6198
- };
6129
+ return { ok: true, mode, spec };
6199
6130
  }
6200
6131
  }
6201
6132
  }
6202
- function supersededTokens(items) {
6203
- const r = residentCost(items.map((i) => ({ source: i.source, target: i.target })));
6204
- return r.rules + r.agentDescriptors + r.skillDescriptors;
6205
- }
6206
- function supersededCause(projectDir, spec, log, found) {
6207
- const selected = spec.userOverride?.forceInclude ?? [];
6208
- return selected.filter((id) => {
6209
- const without = {
6210
- ...spec,
6211
- userOverride: {
6212
- forceInclude: selected.filter((x) => x !== id),
6213
- forceExclude: [...spec.userOverride?.forceExclude ?? [], id]
6214
- }
6215
- };
6216
- return findSuperseded(projectDir, buildManifestSpec(without), log).length < found.length;
6217
- });
6218
- }
6219
6133
  function tracksEqual(a, b2) {
6220
6134
  if (a.length !== b2.length) return false;
6221
6135
  const sortedA = [...a].sort();