@uzysjung/agent-harness 26.149.0 → 26.151.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 (65) hide show
  1. package/README.ko.md +1 -1
  2. package/README.md +1 -1
  3. package/dist/{chunk-YSW3OLH4.js → chunk-3QBHZUVB.js} +164 -66
  4. package/dist/chunk-3QBHZUVB.js.map +1 -0
  5. package/dist/index.js +397 -293
  6. package/dist/index.js.map +1 -1
  7. package/dist/trust-tier-drift.js +5 -1
  8. package/dist/trust-tier-drift.js.map +1 -1
  9. package/package.json +1 -1
  10. package/templates/CLAUDE.md +145 -164
  11. package/templates/agents/build-error-resolver.md +1 -1
  12. package/templates/agents/plan-checker.md +1 -1
  13. package/templates/agents/reviewer.md +4 -5
  14. package/templates/antigravity/AGENTS.md.template +3 -23
  15. package/templates/codex/AGENTS.md.template +5 -56
  16. package/templates/hooks/protect-files.sh +4 -0
  17. package/templates/hooks/session-start.sh +57 -3
  18. package/templates/opencode/AGENTS.md.template +4 -52
  19. package/templates/opencode/opencode.json.template +0 -8
  20. package/templates/rules/change-management.md +0 -1
  21. package/templates/rules/cli-development.md +1 -1
  22. package/templates/rules/doc-governance.md +2 -0
  23. package/templates/rules/git-policy.md +1 -1
  24. package/templates/rules/ship-checklist.md +3 -3
  25. package/templates/rules/test-policy.md +3 -8
  26. package/templates/settings.json +1 -16
  27. package/templates/skills/agent-introspection-debugging/SKILL.md +1 -1
  28. package/templates/skills/audit-harness-fit/README.md +113 -0
  29. package/templates/skills/audit-harness-fit/SKILL.md +64 -433
  30. package/templates/skills/audit-harness-fit/evals/scenarios.yaml +222 -0
  31. package/templates/skills/audit-harness-fit/references/apply.md +66 -0
  32. package/templates/skills/audit-harness-fit/references/audit.md +160 -0
  33. package/templates/skills/audit-harness-fit/references/populate.md +74 -0
  34. package/templates/skills/audit-harness-fit/references/verification.md +123 -0
  35. package/templates/skills/audit-service-gaps/SKILL.md +6 -7
  36. package/templates/skills/clear-korean-communication/SKILL.md +8 -13
  37. package/templates/skills/compaction-handoff/SKILL.md +29 -12
  38. package/templates/skills/external-model-consult/SKILL.md +13 -24
  39. package/templates/skills/model-orchestration/SKILL.md +18 -15
  40. package/templates/skills/natural-korean/SKILL.md +45 -0
  41. package/templates/skills/north-star/SKILL.md +4 -6
  42. package/templates/skills/north-star/references/roadmap-method.md +2 -2
  43. package/templates/skills/{task-brief → objective-brief}/SKILL.md +17 -18
  44. package/templates/skills/recurrence-prevention/SKILL.md +16 -16
  45. package/dist/chunk-YSW3OLH4.js.map +0 -1
  46. package/templates/agents/code-reviewer.md +0 -237
  47. package/templates/agents/security-reviewer.md +0 -108
  48. package/templates/hooks/task-brief-nudge.sh +0 -57
  49. package/templates/skills/audit-harness-fit/references/official-criteria.md +0 -367
  50. package/templates/skills/continuous-learning-v2/SKILL.md +0 -361
  51. package/templates/skills/continuous-learning-v2/agents/observer-loop.sh +0 -362
  52. package/templates/skills/continuous-learning-v2/agents/observer.md +0 -189
  53. package/templates/skills/continuous-learning-v2/agents/session-guardian.sh +0 -150
  54. package/templates/skills/continuous-learning-v2/agents/start-observer.sh +0 -252
  55. package/templates/skills/continuous-learning-v2/config.json +0 -8
  56. package/templates/skills/continuous-learning-v2/hooks/observe.sh +0 -585
  57. package/templates/skills/continuous-learning-v2/scripts/detect-project.sh +0 -322
  58. package/templates/skills/continuous-learning-v2/scripts/instinct-cli.py +0 -1956
  59. package/templates/skills/continuous-learning-v2/scripts/lib/homunculus-dir.sh +0 -31
  60. package/templates/skills/continuous-learning-v2/scripts/migrate-homunculus.sh +0 -68
  61. package/templates/skills/continuous-learning-v2/scripts/test_parse_instinct.py +0 -1420
  62. package/templates/skills/humanize-korean/SKILL.md +0 -228
  63. package/templates/skills/spec-scaling/SKILL.md +0 -89
  64. package/templates/skills/strategic-compact/SKILL.md +0 -145
  65. package/templates/skills/strategic-compact/suggest-compact.sh +0 -54
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import {
4
4
  CATEGORIES,
5
5
  CATEGORY_TITLES,
6
6
  CLI_BASES,
7
+ CONTINUOUS_SKILLS,
7
8
  DEFAULT_OPTIONS,
8
9
  DEV_METHOD_SKILL_IDS,
9
10
  EXTERNAL_ASSETS,
@@ -12,6 +13,9 @@ import {
12
13
  INSTALL_LOG_DIR,
13
14
  INTERNAL_BUNDLED_SKILL_IDS,
14
15
  POLICY_DIRS,
16
+ RENAMED_SKILL_IDS,
17
+ RETIRED_AGENT_IDS,
18
+ RETIRED_SKILL_IDS,
15
19
  TRACKS,
16
20
  __commonJS,
17
21
  __toESM,
@@ -22,6 +26,7 @@ import {
22
26
  backupDir,
23
27
  backupFile,
24
28
  backupFileIfChanged,
29
+ buildAssetSpec,
25
30
  buildInstallLog,
26
31
  buildManifest,
27
32
  collectPolicyHashes,
@@ -55,8 +60,9 @@ import {
55
60
  stripHarnessImport,
56
61
  summarizeContextCost,
57
62
  upsertHarnessImport,
63
+ withContinuousSkillsNote,
58
64
  writeInstallLog
59
- } from "./chunk-YSW3OLH4.js";
65
+ } from "./chunk-3QBHZUVB.js";
60
66
 
61
67
  // node_modules/sisteransi/src/index.js
62
68
  var require_src = __commonJS({
@@ -741,7 +747,7 @@ var cac = (name = "") => new CAC(name);
741
747
  // package.json
742
748
  var package_default = {
743
749
  name: "@uzysjung/agent-harness",
744
- version: "26.149.0",
750
+ version: "26.151.0",
745
751
  description: "Curate vetted AI-coding skills & plugins by your tech stack \u2014 install only what you need, across Claude Code, Codex, OpenCode & Antigravity",
746
752
  type: "module",
747
753
  publishConfig: {
@@ -979,15 +985,15 @@ function padDisplay(s, width) {
979
985
  // src/installer.ts
980
986
  init_esm_shims();
981
987
  import {
982
- chmodSync as chmodSync2,
983
- existsSync as existsSync13,
988
+ chmodSync as chmodSync3,
989
+ existsSync as existsSync14,
984
990
  mkdirSync as mkdirSync4,
985
991
  readdirSync as readdirSync4,
986
- readFileSync as readFileSync12,
992
+ readFileSync as readFileSync13,
987
993
  unlinkSync as unlinkSync3,
988
994
  writeFileSync as writeFileSync6
989
995
  } from "fs";
990
- import { basename as basename5, dirname as dirname4, join as join12, resolve } from "path";
996
+ import { basename as basename5, dirname as dirname4, join as join13, resolve } from "path";
991
997
 
992
998
  // src/ci-scaffold.ts
993
999
  init_esm_shims();
@@ -1032,8 +1038,8 @@ init_esm_shims();
1032
1038
 
1033
1039
  // src/antigravity/transform.ts
1034
1040
  init_esm_shims();
1035
- import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
1036
- import { basename, join as join4 } from "path";
1041
+ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
1042
+ import { basename, join as join5 } from "path";
1037
1043
 
1038
1044
  // src/codex/agents-md.ts
1039
1045
  init_esm_shims();
@@ -1048,6 +1054,8 @@ function renderAgentsMd(params) {
1048
1054
 
1049
1055
  // src/codex/skills.ts
1050
1056
  init_esm_shims();
1057
+ import { chmodSync, existsSync as existsSync2, readFileSync } from "fs";
1058
+ import { join as join2 } from "path";
1051
1059
  function renderBundledSkill(source) {
1052
1060
  const trimmed = source.trimEnd();
1053
1061
  const lines = trimmed.split(/\r?\n/);
@@ -1075,16 +1083,46 @@ ${portBody(body)}
1075
1083
  function portBody(body) {
1076
1084
  return renameSlashes(body).replace(/CLAUDE_PROJECT_DIR/g, "CODEX_PROJECT_DIR").trimEnd();
1077
1085
  }
1086
+ function writeBundledSkillDirs(params) {
1087
+ const { harnessRoot, projectDir, skillIds, writer } = params;
1088
+ const written = [];
1089
+ for (const id of skillIds) {
1090
+ const srcDir = join2(harnessRoot, "templates/skills", id);
1091
+ const srcSkill = join2(srcDir, "SKILL.md");
1092
+ if (!existsSync2(srcSkill)) {
1093
+ continue;
1094
+ }
1095
+ const targetDir = join2(projectDir, ".agents", "skills", id);
1096
+ const targetSkill = join2(targetDir, "SKILL.md");
1097
+ if (!writer.write(targetSkill, renderBundledSkill(readFileSync(srcSkill, "utf8")))) {
1098
+ continue;
1099
+ }
1100
+ written.push(targetSkill);
1101
+ for (const rel of listFilesRecursive(srcDir)) {
1102
+ if (rel === "SKILL.md") continue;
1103
+ if (rel.split("/").some((segment) => segment.startsWith("."))) continue;
1104
+ const segments = rel.split("/");
1105
+ const raw = readFileSync(join2(srcDir, ...segments), "utf8");
1106
+ const ported = rel.endsWith(".md") || rel.endsWith(".sh") ? `${portBody(raw)}
1107
+ ` : raw;
1108
+ const target = join2(targetDir, ...segments);
1109
+ if (!writer.write(target, ported, { createInRefresh: true })) continue;
1110
+ if (rel.endsWith(".sh")) chmodSync(target, 493);
1111
+ written.push(target);
1112
+ }
1113
+ }
1114
+ return written;
1115
+ }
1078
1116
 
1079
1117
  // src/owned-write.ts
1080
1118
  init_esm_shims();
1081
- import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "fs";
1119
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
1082
1120
  import { dirname, relative, sep } from "path";
1083
1121
 
1084
1122
  // src/foreign-slot.ts
1085
1123
  init_esm_shims();
1086
1124
  import { lstatSync } from "fs";
1087
- import { join as join2 } from "path";
1125
+ import { join as join3 } from "path";
1088
1126
  var SKILL_SLOT = /^((?:\.claude|\.agents)\/skills\/[^/]+)(?:\/|$)/;
1089
1127
  function occupiedByNonDirectory(path) {
1090
1128
  const stat = lstatSync(path, { throwIfNoEntry: false });
@@ -1093,15 +1131,15 @@ function occupiedByNonDirectory(path) {
1093
1131
  function foreignOwnedTarget(projectDir, rel) {
1094
1132
  const slot = SKILL_SLOT.exec(rel)?.[1];
1095
1133
  if (slot === void 0) return null;
1096
- if (occupiedByNonDirectory(join2(projectDir, slot))) return slot;
1134
+ if (occupiedByNonDirectory(join3(projectDir, slot))) return slot;
1097
1135
  if (rel !== slot) {
1098
1136
  const parts = rel.slice(slot.length + 1).split("/");
1099
1137
  let cursor = slot;
1100
1138
  for (const part of parts.slice(0, -1)) {
1101
1139
  cursor = `${cursor}/${part}`;
1102
- if (occupiedByNonDirectory(join2(projectDir, cursor))) return cursor;
1140
+ if (occupiedByNonDirectory(join3(projectDir, cursor))) return cursor;
1103
1141
  }
1104
- const leaf = lstatSync(join2(projectDir, rel), { throwIfNoEntry: false });
1142
+ const leaf = lstatSync(join3(projectDir, rel), { throwIfNoEntry: false });
1105
1143
  if (leaf !== void 0 && !leaf.isFile()) return rel;
1106
1144
  }
1107
1145
  return null;
@@ -1124,13 +1162,13 @@ function createOwnedWriter(projectDir, baseline, options = {}) {
1124
1162
  return false;
1125
1163
  }
1126
1164
  const digest = hashContent(content);
1127
- if (!existsSync2(absPath)) {
1165
+ if (!existsSync3(absPath)) {
1128
1166
  if (refreshOnly && !opts?.createInRefresh) return false;
1129
1167
  mkdirSync(dirname(absPath), { recursive: true });
1130
1168
  writeFileSync(absPath, content);
1131
1169
  updated++;
1132
1170
  } else {
1133
- const current = readFileSync(absPath, "utf8");
1171
+ const current = readFileSync2(absPath, "utf8");
1134
1172
  if (current !== content) {
1135
1173
  if (!isHarnessOwned(baseline, rel, current)) {
1136
1174
  backupPaths.push(backupFile(absPath, now));
@@ -1157,8 +1195,8 @@ function createOwnedWriter(projectDir, baseline, options = {}) {
1157
1195
 
1158
1196
  // src/rules-port.ts
1159
1197
  init_esm_shims();
1160
- import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
1161
- import { join as join3 } from "path";
1198
+ import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
1199
+ import { join as join4 } from "path";
1162
1200
  function stripClaudeFrontmatter(source) {
1163
1201
  if (!source.startsWith("---\n")) return source.trim();
1164
1202
  const end = source.indexOf("\n---", 4);
@@ -1168,9 +1206,9 @@ function stripClaudeFrontmatter(source) {
1168
1206
  function portRules(harnessRoot, ruleNames) {
1169
1207
  const ported = [];
1170
1208
  for (const name of ruleNames) {
1171
- const src = join3(harnessRoot, "templates/rules", `${name}.md`);
1172
- if (!existsSync3(src)) continue;
1173
- ported.push({ name, body: stripClaudeFrontmatter(readFileSync2(src, "utf8")) });
1209
+ const src = join4(harnessRoot, "templates/rules", `${name}.md`);
1210
+ if (!existsSync4(src)) continue;
1211
+ ported.push({ name, body: stripClaudeFrontmatter(readFileSync3(src, "utf8")) });
1174
1212
  }
1175
1213
  return ported;
1176
1214
  }
@@ -1190,27 +1228,23 @@ function runAntigravityTransform(params) {
1190
1228
  refreshOnly
1191
1229
  } = params;
1192
1230
  const writer = createOwnedWriter(projectDir, baseline, { refreshOnly: refreshOnly ?? false });
1193
- const rulesFile = writeRules(harnessRoot, projectDir, writer);
1231
+ const rulesFile = writeRules(harnessRoot, projectDir, writer, selectedInternalSkills);
1194
1232
  const antigravityInstalled = rulesFile !== null;
1195
1233
  const harnessRuleFiles = [];
1196
1234
  for (const rule of portRules(harnessRoot, rules)) {
1197
- const target = join4(projectDir, ".agents", "rules", `${rule.name}.md`);
1235
+ const target = join5(projectDir, ".agents", "rules", `${rule.name}.md`);
1198
1236
  if (!writer.write(target, `${rule.body}
1199
1237
  `, { createInRefresh: antigravityInstalled })) {
1200
1238
  continue;
1201
1239
  }
1202
1240
  harnessRuleFiles.push(target);
1203
1241
  }
1204
- const skillFiles = [];
1205
- for (const id of selectedInternalSkills) {
1206
- const src = join4(harnessRoot, "templates/skills", id, "SKILL.md");
1207
- if (!existsSync4(src)) {
1208
- continue;
1209
- }
1210
- const target = join4(projectDir, ".agents", "skills", id, "SKILL.md");
1211
- if (!writer.write(target, renderBundledSkill(readFileSync3(src, "utf8")))) continue;
1212
- skillFiles.push(target);
1213
- }
1242
+ const skillFiles = writeBundledSkillDirs({
1243
+ harnessRoot,
1244
+ projectDir,
1245
+ skillIds: selectedInternalSkills,
1246
+ writer
1247
+ });
1214
1248
  return {
1215
1249
  rulesFile,
1216
1250
  harnessRuleFiles,
@@ -1218,20 +1252,24 @@ function runAntigravityTransform(params) {
1218
1252
  ownership: writer.result()
1219
1253
  };
1220
1254
  }
1221
- function writeRules(harnessRoot, projectDir, writer) {
1222
- const claudeMdPath = join4(harnessRoot, "templates/CLAUDE.md");
1223
- const templatePath = join4(harnessRoot, "templates/antigravity/AGENTS.md.template");
1224
- if (!existsSync4(claudeMdPath) || !existsSync4(templatePath)) {
1255
+ function writeRules(harnessRoot, projectDir, writer, selectedInternalSkills) {
1256
+ const claudeMdPath = join5(harnessRoot, "templates/CLAUDE.md");
1257
+ const templatePath = join5(harnessRoot, "templates/antigravity/AGENTS.md.template");
1258
+ if (!existsSync5(claudeMdPath) || !existsSync5(templatePath)) {
1225
1259
  return null;
1226
1260
  }
1227
- const claudeMd = readFileSync3(claudeMdPath, "utf8");
1228
- const template = readFileSync3(templatePath, "utf8");
1229
- const target = join4(projectDir, ".agents", "rules", "uzys-harness.md");
1261
+ const claudeMd = readFileSync4(claudeMdPath, "utf8");
1262
+ const template = readFileSync4(templatePath, "utf8");
1263
+ const target = join5(projectDir, ".agents", "rules", "uzys-harness.md");
1230
1264
  const rulesOut = renderAgentsMd({
1231
1265
  template,
1232
1266
  claudeMd,
1233
1267
  projectName: basename(projectDir),
1234
- projectContext: renderFillScaffold("antigravity-rule")
1268
+ // ADR-085 — 상시 스킬 안내는 앵커가 아니라 여기(프로젝트 맥락)에, 깔린 것만.
1269
+ projectContext: withContinuousSkillsNote(
1270
+ renderFillScaffold("antigravity-rule"),
1271
+ selectedInternalSkills
1272
+ )
1235
1273
  });
1236
1274
  return writer.write(target, rulesOut) ? target : null;
1237
1275
  }
@@ -1239,18 +1277,18 @@ function writeRules(harnessRoot, projectDir, writer) {
1239
1277
  // src/codex/opt-in.ts
1240
1278
  init_esm_shims();
1241
1279
  import { homedir } from "os";
1242
- import { join as join5 } from "path";
1280
+ import { join as join6 } from "path";
1243
1281
 
1244
1282
  // src/codex/trust-entry.ts
1245
1283
  init_esm_shims();
1246
- import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
1284
+ import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
1247
1285
  import { dirname as dirname2 } from "path";
1248
1286
  var TRUST_BLOCK_REGEX = /\[projects\."([^"]+)"\]/g;
1249
1287
  function registerTrustEntry(opts) {
1250
1288
  const { configPath, projectDir } = opts;
1251
1289
  try {
1252
1290
  mkdirSync2(dirname2(configPath), { recursive: true });
1253
- const existing = existsSync5(configPath) ? readFileSync4(configPath, "utf8") : "";
1291
+ const existing = existsSync6(configPath) ? readFileSync5(configPath, "utf8") : "";
1254
1292
  if (hasTrustEntry(existing, projectDir)) {
1255
1293
  return { status: "already-present" };
1256
1294
  }
@@ -1274,8 +1312,8 @@ function hasTrustEntry(configContent, projectDir) {
1274
1312
 
1275
1313
  // src/codex/opt-in.ts
1276
1314
  function runCodexOptIn(ctx) {
1277
- const codexHome = ctx.codexHome ?? join5(homedir(), ".codex");
1278
- const configPath = join5(codexHome, "config.toml");
1315
+ const codexHome = ctx.codexHome ?? join6(homedir(), ".codex");
1316
+ const configPath = join6(codexHome, "config.toml");
1279
1317
  const result = registerTrustEntry({ configPath, projectDir: ctx.projectDir });
1280
1318
  return {
1281
1319
  trustEntry: {
@@ -1288,8 +1326,8 @@ function runCodexOptIn(ctx) {
1288
1326
 
1289
1327
  // src/codex/transform.ts
1290
1328
  init_esm_shims();
1291
- import { chmodSync, existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
1292
- import { basename as basename2, join as join6 } from "path";
1329
+ import { chmodSync as chmodSync2, existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
1330
+ import { basename as basename2, join as join7 } from "path";
1293
1331
 
1294
1332
  // src/codex/config-toml.ts
1295
1333
  init_esm_shims();
@@ -1366,23 +1404,27 @@ function runCodexTransform(params) {
1366
1404
  refreshOnly
1367
1405
  } = params;
1368
1406
  const writer = createOwnedWriter(projectDir, baseline, { refreshOnly: refreshOnly ?? false });
1369
- const claudeMd = readRequired(join6(harnessRoot, "templates/CLAUDE.md"));
1370
- const agentsTemplate = readRequired(join6(harnessRoot, "templates/codex/AGENTS.md.template"));
1371
- const configTemplate = readRequired(join6(harnessRoot, "templates/codex/config.toml.template"));
1407
+ const claudeMd = readRequired(join7(harnessRoot, "templates/CLAUDE.md"));
1408
+ const agentsTemplate = readRequired(join7(harnessRoot, "templates/codex/AGENTS.md.template"));
1409
+ const configTemplate = readRequired(join7(harnessRoot, "templates/codex/config.toml.template"));
1372
1410
  const projectName = basename2(projectDir);
1373
- const mcp = readOptionalJson(join6(harnessRoot, ".mcp.json"));
1374
- const agentsMdPath = join6(projectDir, "AGENTS.md");
1411
+ const mcp = readOptionalJson(join7(harnessRoot, ".mcp.json"));
1412
+ const agentsMdPath = join7(projectDir, "AGENTS.md");
1375
1413
  ensureDir(projectDir);
1376
1414
  const agentsMdOut = renderAgentsMd({
1377
1415
  template: agentsTemplate,
1378
1416
  claudeMd,
1379
1417
  projectName,
1380
- projectContext: renderFillScaffold("agents-md"),
1418
+ // ADR-085 — 상시 스킬 안내는 앵커가 아니라 여기(프로젝트 맥락)에, 깔린 것만.
1419
+ projectContext: withContinuousSkillsNote(
1420
+ renderFillScaffold("agents-md"),
1421
+ selectedInternalSkills
1422
+ ),
1381
1423
  // Codex 는 룰 디렉터리가 없다 — 룰이 AGENTS.md 본문에 들어가야 도달한다(§Harness Rules).
1382
1424
  harnessRules: renderRulesBlock(portRules(harnessRoot, rules))
1383
1425
  });
1384
1426
  writer.write(agentsMdPath, agentsMdOut);
1385
- const configTomlPath = join6(projectDir, ".codex/config.toml");
1427
+ const configTomlPath = join7(projectDir, ".codex/config.toml");
1386
1428
  writer.write(
1387
1429
  configTomlPath,
1388
1430
  renderConfigToml({
@@ -1392,29 +1434,25 @@ function runCodexTransform(params) {
1392
1434
  mcp
1393
1435
  })
1394
1436
  );
1395
- const hookDir = join6(projectDir, ".codex/hooks");
1437
+ const hookDir = join7(projectDir, ".codex/hooks");
1396
1438
  const hookFiles = [];
1397
1439
  for (const hook of HOOK_NAMES) {
1398
- const src = join6(harnessRoot, "templates/hooks", `${hook}.sh`);
1399
- if (!existsSync6(src)) {
1440
+ const src = join7(harnessRoot, "templates/hooks", `${hook}.sh`);
1441
+ if (!existsSync7(src)) {
1400
1442
  continue;
1401
1443
  }
1402
- const ported = readFileSync5(src, "utf8").replace(ENV_VAR_RENAME, "CODEX_PROJECT_DIR");
1403
- const target = join6(hookDir, `${hook}.sh`);
1444
+ const ported = readFileSync6(src, "utf8").replace(ENV_VAR_RENAME, "CODEX_PROJECT_DIR");
1445
+ const target = join7(hookDir, `${hook}.sh`);
1404
1446
  if (!writer.write(target, ported)) continue;
1405
- chmodSync(target, 493);
1447
+ chmodSync2(target, 493);
1406
1448
  hookFiles.push(target);
1407
1449
  }
1408
- const skillFiles = [];
1409
- for (const id of selectedInternalSkills) {
1410
- const src = join6(harnessRoot, "templates/skills", id, "SKILL.md");
1411
- if (!existsSync6(src)) {
1412
- continue;
1413
- }
1414
- const target = join6(projectDir, ".agents", "skills", id, "SKILL.md");
1415
- if (!writer.write(target, renderBundledSkill(readFileSync5(src, "utf8")))) continue;
1416
- skillFiles.push(target);
1417
- }
1450
+ const skillFiles = writeBundledSkillDirs({
1451
+ harnessRoot,
1452
+ projectDir,
1453
+ skillIds: selectedInternalSkills,
1454
+ writer
1455
+ });
1418
1456
  return {
1419
1457
  agentsMdPath,
1420
1458
  configTomlPath,
@@ -1424,17 +1462,17 @@ function runCodexTransform(params) {
1424
1462
  };
1425
1463
  }
1426
1464
  function readRequired(path) {
1427
- if (!existsSync6(path)) {
1465
+ if (!existsSync7(path)) {
1428
1466
  throw new Error(`Codex transform: required source missing: ${path}`);
1429
1467
  }
1430
- return readFileSync5(path, "utf8");
1468
+ return readFileSync6(path, "utf8");
1431
1469
  }
1432
1470
  function readOptionalJson(path) {
1433
- if (!existsSync6(path)) {
1471
+ if (!existsSync7(path)) {
1434
1472
  return null;
1435
1473
  }
1436
1474
  try {
1437
- return JSON.parse(readFileSync5(path, "utf8"));
1475
+ return JSON.parse(readFileSync6(path, "utf8"));
1438
1476
  } catch {
1439
1477
  return null;
1440
1478
  }
@@ -1442,8 +1480,8 @@ function readOptionalJson(path) {
1442
1480
 
1443
1481
  // src/opencode/transform.ts
1444
1482
  init_esm_shims();
1445
- import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync6, unlinkSync } from "fs";
1446
- import { basename as basename3, join as join7 } from "path";
1483
+ import { existsSync as existsSync8, readdirSync, readFileSync as readFileSync7, unlinkSync } from "fs";
1484
+ import { basename as basename3, join as join8 } from "path";
1447
1485
 
1448
1486
  // src/opencode/agents-md.ts
1449
1487
  init_esm_shims();
@@ -1486,46 +1524,46 @@ function runOpencodeTransform(params) {
1486
1524
  refreshOnly
1487
1525
  } = params;
1488
1526
  const writer = createOwnedWriter(projectDir, baseline, { refreshOnly: refreshOnly ?? false });
1489
- const claudeMd = readRequired2(join7(harnessRoot, "templates/CLAUDE.md"));
1490
- const agentsTemplate = readRequired2(join7(harnessRoot, "templates/opencode/AGENTS.md.template"));
1527
+ const claudeMd = readRequired2(join8(harnessRoot, "templates/CLAUDE.md"));
1528
+ const agentsTemplate = readRequired2(join8(harnessRoot, "templates/opencode/AGENTS.md.template"));
1491
1529
  const opencodeTemplate = readRequired2(
1492
- join7(harnessRoot, "templates/opencode/opencode.json.template")
1530
+ join8(harnessRoot, "templates/opencode/opencode.json.template")
1493
1531
  );
1494
1532
  const projectName = basename3(projectDir);
1495
- const mcp = readOptionalJson2(join7(harnessRoot, ".mcp.json"));
1533
+ const mcp = readOptionalJson2(join8(harnessRoot, ".mcp.json"));
1496
1534
  ensureDir(projectDir);
1497
- const agentsMdPath = join7(projectDir, "AGENTS.md");
1535
+ const agentsMdPath = join8(projectDir, "AGENTS.md");
1498
1536
  const agentsMdOut = renderAgentsMd2({
1499
1537
  template: agentsTemplate,
1500
1538
  claudeMd,
1501
1539
  projectName,
1502
- projectContext: renderFillScaffold("agents-md"),
1540
+ // ADR-085 — 상시 스킬 안내는 앵커가 아니라 여기(프로젝트 맥락)에, 깔린 것만.
1541
+ projectContext: withContinuousSkillsNote(
1542
+ renderFillScaffold("agents-md"),
1543
+ selectedInternalSkills
1544
+ ),
1503
1545
  // codex 와 **같은 파일**(프로젝트 루트 `AGENTS.md`)이다. 두 transform 이 서로 다른 본문을
1504
1546
  // 쓰면 나중에 도는 쪽이 앞선 쪽을 덮어써, codex+opencode 조합에서 룰이 통째로 사라진다
1505
1547
  // (독립 검증 C-1 실측). 같은 내용을 쓰면 순서가 결과를 바꾸지 않는다.
1506
1548
  harnessRules: renderRulesBlock(portRules(harnessRoot, rules))
1507
1549
  });
1508
1550
  writer.write(agentsMdPath, agentsMdOut);
1509
- const opencodeJsonPath = join7(projectDir, "opencode.json");
1551
+ const opencodeJsonPath = join8(projectDir, "opencode.json");
1510
1552
  writer.write(opencodeJsonPath, renderOpencodeJson({ template: opencodeTemplate, mcp }));
1511
- const skillFiles = [];
1512
- for (const id of selectedInternalSkills) {
1513
- const src = join7(harnessRoot, "templates/skills", id, "SKILL.md");
1514
- if (!existsSync7(src)) {
1515
- continue;
1516
- }
1517
- const target = join7(projectDir, ".agents", "skills", id, "SKILL.md");
1518
- if (!writer.write(target, renderBundledSkill(readFileSync6(src, "utf8")))) continue;
1519
- skillFiles.push(target);
1520
- }
1553
+ const skillFiles = writeBundledSkillDirs({
1554
+ harnessRoot,
1555
+ projectDir,
1556
+ skillIds: selectedInternalSkills,
1557
+ writer
1558
+ });
1521
1559
  const retiredCommands = [];
1522
- const cmdDir = join7(projectDir, ".opencode/commands");
1523
- if (existsSync7(cmdDir)) {
1560
+ const cmdDir = join8(projectDir, ".opencode/commands");
1561
+ if (existsSync8(cmdDir)) {
1524
1562
  for (const entry of readdirSync(cmdDir)) {
1525
1563
  if (!entry.endsWith(".md")) continue;
1526
1564
  const id = entry.slice(0, -3);
1527
- if (!existsSync7(join7(harnessRoot, "templates/skills", id, "SKILL.md"))) continue;
1528
- const victim = join7(cmdDir, entry);
1565
+ if (!existsSync8(join8(harnessRoot, "templates/skills", id, "SKILL.md"))) continue;
1566
+ const victim = join8(cmdDir, entry);
1529
1567
  try {
1530
1568
  backupFile(victim);
1531
1569
  unlinkSync(victim);
@@ -1543,17 +1581,17 @@ function runOpencodeTransform(params) {
1543
1581
  };
1544
1582
  }
1545
1583
  function readRequired2(path) {
1546
- if (!existsSync7(path)) {
1584
+ if (!existsSync8(path)) {
1547
1585
  throw new Error(`OpenCode transform: required source missing: ${path}`);
1548
1586
  }
1549
- return readFileSync6(path, "utf8");
1587
+ return readFileSync7(path, "utf8");
1550
1588
  }
1551
1589
  function readOptionalJson2(path) {
1552
- if (!existsSync7(path)) {
1590
+ if (!existsSync8(path)) {
1553
1591
  return null;
1554
1592
  }
1555
1593
  try {
1556
- return JSON.parse(readFileSync6(path, "utf8"));
1594
+ return JSON.parse(readFileSync7(path, "utf8"));
1557
1595
  } catch {
1558
1596
  return null;
1559
1597
  }
@@ -1645,8 +1683,8 @@ function runCliTransforms(params) {
1645
1683
 
1646
1684
  // src/env-files.ts
1647
1685
  init_esm_shims();
1648
- import { appendFileSync, existsSync as existsSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
1649
- import { join as join8 } from "path";
1686
+ import { appendFileSync, existsSync as existsSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync3 } from "fs";
1687
+ import { join as join9 } from "path";
1650
1688
  var ENV_EXAMPLE_BODY = `# .env.example \u2014 csr-supabase Track
1651
1689
  # Copy to .env (gitignored) and fill in values: cp .env.example .env
1652
1690
 
@@ -1683,19 +1721,19 @@ function writeEnvExample(projectDir, tracks) {
1683
1721
  if (!tracks.some((t) => ENV_EXAMPLE_TRACKS.includes(t))) {
1684
1722
  return false;
1685
1723
  }
1686
- const path = join8(projectDir, ".env.example");
1687
- if (existsSync8(path)) {
1724
+ const path = join9(projectDir, ".env.example");
1725
+ if (existsSync9(path)) {
1688
1726
  return false;
1689
1727
  }
1690
1728
  writeFileSync3(path, ENV_EXAMPLE_BODY);
1691
1729
  return true;
1692
1730
  }
1693
1731
  function addGitignoreEnv(projectDir) {
1694
- const path = join8(projectDir, ".gitignore");
1695
- if (!existsSync8(path)) {
1732
+ const path = join9(projectDir, ".gitignore");
1733
+ if (!existsSync9(path)) {
1696
1734
  return false;
1697
1735
  }
1698
- const content = readFileSync7(path, "utf8");
1736
+ const content = readFileSync8(path, "utf8");
1699
1737
  if (GITIGNORE_ENV_PATTERN.test(content)) {
1700
1738
  return false;
1701
1739
  }
@@ -1709,11 +1747,11 @@ function addGitignoreEnv(projectDir) {
1709
1747
  var AGENT_ARTIFACT_DIRS = [".factory/", ".goose/", ".uzys-agent-harness/"];
1710
1748
  var GITIGNORE_AGENT_ARTIFACT_HEADER = "# agent CLI / harness \uC790\uB3D9 \uC0DD\uC131\uBB3C (auto-added by agent-harness)";
1711
1749
  function addGitignoreAgentArtifacts(projectDir) {
1712
- const path = join8(projectDir, ".gitignore");
1713
- if (!existsSync8(path)) {
1750
+ const path = join9(projectDir, ".gitignore");
1751
+ if (!existsSync9(path)) {
1714
1752
  return [];
1715
1753
  }
1716
- const content = readFileSync7(path, "utf8");
1754
+ const content = readFileSync8(path, "utf8");
1717
1755
  const missing = AGENT_ARTIFACT_DIRS.filter((pattern) => {
1718
1756
  const lineRegex = new RegExp(`^${pattern.replace(/\./g, "\\.").replace(/\//g, "/")}\\s*$`, "m");
1719
1757
  return !lineRegex.test(content);
@@ -1732,9 +1770,9 @@ ${block}
1732
1770
  // src/external-installer.ts
1733
1771
  init_esm_shims();
1734
1772
  import { spawnSync } from "child_process";
1735
- import { existsSync as existsSync9, readdirSync as readdirSync2, readFileSync as readFileSync8 } from "fs";
1773
+ import { existsSync as existsSync10, readdirSync as readdirSync2, readFileSync as readFileSync9 } from "fs";
1736
1774
  import { homedir as homedir2 } from "os";
1737
- import { join as join9 } from "path";
1775
+ import { join as join10 } from "path";
1738
1776
  var DEFAULT_SPAWN_TIMEOUT_MS = 12e4;
1739
1777
  function selectExternalTargets(assets, ctx) {
1740
1778
  const conditionPassed = filterApplicableAssets(assets, ctx).filter(
@@ -1810,8 +1848,8 @@ function installOne(asset, ctx) {
1810
1848
  cwd
1811
1849
  );
1812
1850
  case "shell-script": {
1813
- const scriptPath = join9(ctx.harnessRoot, method.script);
1814
- if (!existsSync9(scriptPath)) {
1851
+ const scriptPath = join10(ctx.harnessRoot, method.script);
1852
+ if (!existsSync10(scriptPath)) {
1815
1853
  return {
1816
1854
  asset,
1817
1855
  ok: false,
@@ -1941,17 +1979,17 @@ function detectVersion(method, spawn) {
1941
1979
  if (at2 <= 0) return void 0;
1942
1980
  const plugin = method.pluginId.slice(0, at2);
1943
1981
  const marketplaceShort = method.pluginId.slice(at2 + 1);
1944
- const cacheBase = join9(homedir2(), ".claude/plugins/cache", marketplaceShort, plugin);
1945
- if (!existsSync9(cacheBase)) return void 0;
1982
+ const cacheBase = join10(homedir2(), ".claude/plugins/cache", marketplaceShort, plugin);
1983
+ if (!existsSync10(cacheBase)) return void 0;
1946
1984
  const versions = readdirSync2(cacheBase).filter((v2) => /^\d/.test(v2)).sort();
1947
1985
  return versions.at(-1);
1948
1986
  }
1949
1987
  case "npm": {
1950
1988
  const npmRoot = getNpmGlobalRoot(spawn);
1951
1989
  if (!npmRoot) return void 0;
1952
- const pkgJson = join9(npmRoot, method.pkg, "package.json");
1953
- if (!existsSync9(pkgJson)) return void 0;
1954
- const parsed = JSON.parse(readFileSync8(pkgJson, "utf8"));
1990
+ const pkgJson = join10(npmRoot, method.pkg, "package.json");
1991
+ if (!existsSync10(pkgJson)) return void 0;
1992
+ const parsed = JSON.parse(readFileSync9(pkgJson, "utf8"));
1955
1993
  return parsed.version;
1956
1994
  }
1957
1995
  default:
@@ -1978,7 +2016,7 @@ function getNpmGlobalRoot(spawn) {
1978
2016
 
1979
2017
  // src/mcp-merge.ts
1980
2018
  init_esm_shims();
1981
- import { existsSync as existsSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "fs";
2019
+ import { existsSync as existsSync11, readFileSync as readFileSync10, writeFileSync as writeFileSync4 } from "fs";
1982
2020
  function parseTrackMcpMap(raw) {
1983
2021
  const rows = [];
1984
2022
  for (const line of raw.split(/\r?\n/)) {
@@ -2029,15 +2067,15 @@ function mergeMcpServers(base, rows, tracks) {
2029
2067
  return out;
2030
2068
  }
2031
2069
  function composeMcpJson(opts) {
2032
- const base = JSON.parse(readFileSync9(opts.templateMcpPath, "utf8"));
2033
- const merged = opts.existingPath && existsSync10(opts.existingPath) ? mergeUserBase(base, opts.existingPath) : base;
2034
- const mapRaw = existsSync10(opts.trackMapPath) ? readFileSync9(opts.trackMapPath, "utf8") : "";
2070
+ const base = JSON.parse(readFileSync10(opts.templateMcpPath, "utf8"));
2071
+ const merged = opts.existingPath && existsSync11(opts.existingPath) ? mergeUserBase(base, opts.existingPath) : base;
2072
+ const mapRaw = existsSync11(opts.trackMapPath) ? readFileSync10(opts.trackMapPath, "utf8") : "";
2035
2073
  const rows = parseTrackMcpMap(mapRaw);
2036
2074
  return mergeMcpServers(merged, rows, opts.tracks);
2037
2075
  }
2038
2076
  function mergeUserBase(base, existingPath) {
2039
2077
  try {
2040
- const existing = JSON.parse(readFileSync9(existingPath, "utf8"));
2078
+ const existing = JSON.parse(readFileSync10(existingPath, "utf8"));
2041
2079
  return {
2042
2080
  ...base,
2043
2081
  mcpServers: { ...base.mcpServers, ...existing.mcpServers }
@@ -2053,8 +2091,8 @@ function writeMcpJson(path, mcp) {
2053
2091
 
2054
2092
  // src/superseded.ts
2055
2093
  init_esm_shims();
2056
- import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
2057
- import { join as join10 } from "path";
2094
+ import { existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
2095
+ import { join as join11 } from "path";
2058
2096
  function sameTracks(a, b2) {
2059
2097
  if (a.length !== b2.length) return false;
2060
2098
  const sa = [...a].sort();
@@ -2078,9 +2116,9 @@ function findSuperseded(projectDir, spec, previous) {
2078
2116
  if (!id) continue;
2079
2117
  const key = policyKey(entry.target.slice(".claude/".length));
2080
2118
  if (!key) continue;
2081
- const abs = join10(projectDir, entry.target);
2082
- if (!existsSync11(abs)) continue;
2083
- if (!isHarnessOwned(baseline, key, readFileSync10(abs, "utf-8"))) continue;
2119
+ const abs = join11(projectDir, entry.target);
2120
+ if (!existsSync12(abs)) continue;
2121
+ if (!isHarnessOwned(baseline, key, readFileSync11(abs, "utf-8"))) continue;
2084
2122
  out.push({ target: entry.target, id, source: entry.source });
2085
2123
  }
2086
2124
  return out;
@@ -2090,14 +2128,14 @@ function findSuperseded(projectDir, spec, previous) {
2090
2128
  init_esm_shims();
2091
2129
  import {
2092
2130
  copyFileSync,
2093
- existsSync as existsSync12,
2131
+ existsSync as existsSync13,
2094
2132
  mkdirSync as mkdirSync3,
2095
2133
  readdirSync as readdirSync3,
2096
- readFileSync as readFileSync11,
2134
+ readFileSync as readFileSync12,
2097
2135
  unlinkSync as unlinkSync2,
2098
2136
  writeFileSync as writeFileSync5
2099
2137
  } from "fs";
2100
- import { basename as basename4, dirname as dirname3, join as join11 } from "path";
2138
+ import { basename as basename4, dirname as dirname3, join as join12 } from "path";
2101
2139
  var LEGACY_ANCHOR_FILE = ".claude/CLAUDE.md";
2102
2140
  function buildUpdateSpec(projectDir, tracks) {
2103
2141
  return {
@@ -2109,7 +2147,7 @@ function buildUpdateSpec(projectDir, tracks) {
2109
2147
  };
2110
2148
  }
2111
2149
  function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}) {
2112
- const claudeDir = join11(projectDir, ".claude");
2150
+ const claudeDir = join12(projectDir, ".claude");
2113
2151
  const report = {
2114
2152
  updated: {},
2115
2153
  pruned: {},
@@ -2117,6 +2155,7 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}) {
2117
2155
  claudeMdUpdated: false,
2118
2156
  anchorCreated: false,
2119
2157
  rootImportAdded: false,
2158
+ rootBlockRefreshed: false,
2120
2159
  legacyAnchor: null,
2121
2160
  skillsBackedUp: [],
2122
2161
  skillsSkippedLinks: [],
@@ -2131,6 +2170,7 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}) {
2131
2170
  installedNew: [],
2132
2171
  restored: [],
2133
2172
  needsReinstall: [],
2173
+ retiredAgents: [],
2134
2174
  mcpAllowlistRetired: null
2135
2175
  };
2136
2176
  const fresh = installNewAssets(projectDir, templatesDir);
@@ -2139,8 +2179,8 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}) {
2139
2179
  report.needsReinstall = fresh.needsReinstall;
2140
2180
  const policyBase = policyBaseline(projectDir);
2141
2181
  for (const { dir, ext } of POLICY_DIRS) {
2142
- const target = join11(claudeDir, dir);
2143
- const source = join11(templatesDir, dir);
2182
+ const target = join12(claudeDir, dir);
2183
+ const source = join12(templatesDir, dir);
2144
2184
  const label = `.claude/${dir}`;
2145
2185
  const ctx = { prefix: dir, baseline: policyBase };
2146
2186
  const synced = updateDir(target, source, ext, ctx);
@@ -2150,8 +2190,8 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}) {
2150
2190
  }
2151
2191
  refreshPolicyBaseline(projectDir, templatesDir);
2152
2192
  const skillSync = syncSkills(
2153
- join11(claudeDir, "skills"),
2154
- join11(templatesDir, "skills"),
2193
+ join12(claudeDir, "skills"),
2194
+ join12(templatesDir, "skills"),
2155
2195
  skillBaseline(projectDir),
2156
2196
  /* @__PURE__ */ new Date(),
2157
2197
  (relInSkills) => foreignOwnedTarget(projectDir, `.claude/skills/${relInSkills}`)
@@ -2161,14 +2201,15 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}) {
2161
2201
  report.skillsSkippedLinks = skillSync.skippedLinks;
2162
2202
  refreshSkillBaseline(projectDir);
2163
2203
  const installLog = readInstallLog(projectDir);
2164
- if (existsSync12(claudeDir) && (installLog === null || installLog.spec.cli.includes("claude"))) {
2204
+ if (existsSync13(claudeDir) && (installLog === null || installLog.spec.cli.includes("claude"))) {
2165
2205
  syncHarnessAnchor(projectDir, templatesDir, report);
2166
2206
  }
2167
- const settingsPath = join11(claudeDir, "settings.json");
2168
- if (existsSync12(settingsPath)) {
2207
+ const settingsPath = join12(claudeDir, "settings.json");
2208
+ if (existsSync13(settingsPath)) {
2169
2209
  report.staleHookRefs = cleanStaleHookRefs(settingsPath, claudeDir);
2170
2210
  }
2171
2211
  report.mcpAllowlistRetired = retireMcpAllowlist(projectDir);
2212
+ report.retiredAgents = staleAgentFiles(claudeDir);
2172
2213
  const external = refreshExternalCli(projectDir, harnessRoot);
2173
2214
  report.externalUpdated = external.externalUpdated;
2174
2215
  report.externalBackedUp = external.externalBackedUp;
@@ -2185,10 +2226,24 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}) {
2185
2226
  const skillRefresh = (deps.refreshSkills ?? refreshExternalSkills)(projectDir);
2186
2227
  report.externalSkillsRefreshed = skillRefresh.refreshed;
2187
2228
  report.externalSkillsFailed = skillRefresh.failed;
2188
- report.externalSkillsNotInCatalog = skillRefresh.notInCatalog;
2229
+ report.externalSkillsNotInCatalog = [
2230
+ ...skillRefresh.notInCatalog,
2231
+ ...staleSkillDirs(claudeDir).filter((id) => !skillRefresh.notInCatalog.includes(id))
2232
+ ];
2189
2233
  report.externalSkillsUnknown = skillRefresh.unknown;
2190
2234
  return report;
2191
2235
  }
2236
+ function staleSkillDirs(claudeDir) {
2237
+ const dir = join12(claudeDir, "skills");
2238
+ if (!existsSync13(dir)) return [];
2239
+ const stale = (id) => RENAMED_SKILL_IDS[id] !== void 0 || RETIRED_SKILL_IDS.includes(id);
2240
+ return readdirSync3(dir, { withFileTypes: true }).filter((e2) => e2.isDirectory() && stale(e2.name)).map((e2) => e2.name);
2241
+ }
2242
+ function staleAgentFiles(claudeDir) {
2243
+ const dir = join12(claudeDir, "agents");
2244
+ if (!existsSync13(dir)) return [];
2245
+ 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
+ }
2192
2247
  function installNewAssets(projectDir, templatesDir) {
2193
2248
  const installed = [];
2194
2249
  const restored = [];
@@ -2201,15 +2256,15 @@ function installNewAssets(projectDir, templatesDir) {
2201
2256
  for (const entry of trackOnlyFileAssets(installedTracks(projectDir))) {
2202
2257
  if (entry.target === HARNESS_ANCHOR_FILE) continue;
2203
2258
  if (isBaselineExcluded(entry.target, baselineExcluded)) continue;
2204
- const target = join11(projectDir, entry.target);
2259
+ const target = join12(projectDir, entry.target);
2205
2260
  const foreign = foreignOwnedTarget(projectDir, entry.target);
2206
2261
  if (foreign !== null) {
2207
2262
  if (!foreignOwned.includes(foreign)) foreignOwned.push(foreign);
2208
2263
  continue;
2209
2264
  }
2210
- if (existsSync12(target)) continue;
2211
- const source = join11(templatesDir, entry.source);
2212
- if (!existsSync12(source)) continue;
2265
+ if (existsSync13(target)) continue;
2266
+ const source = join12(templatesDir, entry.source);
2267
+ if (!existsSync13(source)) continue;
2213
2268
  if (entry.target.startsWith(".claude/")) {
2214
2269
  if (!claudeSelected) continue;
2215
2270
  if (entry.target.startsWith(".claude/hooks/") || entry.target === ".claude/settings.json") {
@@ -2234,16 +2289,17 @@ function trackOnlyFileAssets(tracks) {
2234
2289
  );
2235
2290
  }
2236
2291
  function syncHarnessAnchor(projectDir, templatesDir, report) {
2237
- if (existsSync12(join11(projectDir, LEGACY_ANCHOR_FILE))) {
2292
+ if (existsSync13(join12(projectDir, LEGACY_ANCHOR_FILE))) {
2238
2293
  report.legacyAnchor = LEGACY_ANCHOR_FILE;
2239
2294
  }
2240
- const templateMd = join11(templatesDir, "CLAUDE.md");
2241
- if (!existsSync12(templateMd)) return;
2242
- const anchor = join11(projectDir, HARNESS_ANCHOR_FILE);
2243
- const existed = existsSync12(anchor);
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);
2244
2299
  copyFileSync(templateMd, anchor);
2245
2300
  if (existed) {
2246
2301
  report.claudeMdUpdated = true;
2302
+ report.rootBlockRefreshed = upsertRootImport(projectDir);
2247
2303
  return;
2248
2304
  }
2249
2305
  report.anchorCreated = true;
@@ -2251,11 +2307,16 @@ function syncHarnessAnchor(projectDir, templatesDir, report) {
2251
2307
  recordAnchorBaseline(projectDir, anchor);
2252
2308
  }
2253
2309
  function upsertRootImport(projectDir) {
2254
- const target = join11(projectDir, "CLAUDE.md");
2255
- const existing = existsSync12(target) ? readFileSync11(target, "utf8") : null;
2310
+ const target = join12(projectDir, "CLAUDE.md");
2311
+ const existing = existsSync13(target) ? readFileSync12(target, "utf8") : null;
2256
2312
  const next = upsertHarnessImport(existing, {
2257
2313
  projectName: basename4(projectDir),
2258
- tracks: installedTracks(projectDir)
2314
+ tracks: installedTracks(projectDir),
2315
+ // ADR-085 — update 는 선택 목록을 인자로 받지 않는다. `syncSkills` 와 같은 판정을 쓴다:
2316
+ // `.claude/skills/<id>` 가 있으면 그 스킬은 이 설치가 고른 것이다.
2317
+ continuousSkills: CONTINUOUS_SKILLS.map((s) => s.id).filter(
2318
+ (id) => existsSync13(join12(projectDir, ".claude/skills", id))
2319
+ )
2259
2320
  });
2260
2321
  if (next === existing) return false;
2261
2322
  writeFileSync5(target, next);
@@ -2274,7 +2335,7 @@ function recordAnchorBaseline(projectDir, anchor) {
2274
2335
  ...log.templates,
2275
2336
  rootClaudeMd: {
2276
2337
  path: HARNESS_ANCHOR_FILE,
2277
- sha256: hashContent(readFileSync11(anchor, "utf8"))
2338
+ sha256: hashContent(readFileSync12(anchor, "utf8"))
2278
2339
  }
2279
2340
  }
2280
2341
  };
@@ -2316,16 +2377,16 @@ function isHarnessOwned2(ctx, rel, current) {
2316
2377
  return isHarnessOwned(ctx.baseline, `${ctx.prefix}/${rel}`, current);
2317
2378
  }
2318
2379
  function updateDir(target, source, ext, ctx, now = /* @__PURE__ */ new Date()) {
2319
- if (!existsSync12(target) || !existsSync12(source)) return { updated: 0, backedUp: [] };
2380
+ if (!existsSync13(target) || !existsSync13(source)) return { updated: 0, backedUp: [] };
2320
2381
  let updated = 0;
2321
2382
  const backedUp = [];
2322
2383
  for (const file of readdirSync3(target)) {
2323
2384
  if (!file.endsWith(ext)) continue;
2324
- const targetFile = join11(target, file);
2325
- const sourceFile = join11(source, file);
2326
- if (!existsSync12(sourceFile)) continue;
2327
- const next = readFileSync11(sourceFile, "utf8");
2328
- const current = readFileSync11(targetFile, "utf8");
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");
2329
2390
  if (current === next) continue;
2330
2391
  if (!isHarnessOwned2(ctx, file, current)) {
2331
2392
  backupFile(targetFile, now);
@@ -2337,7 +2398,7 @@ function updateDir(target, source, ext, ctx, now = /* @__PURE__ */ new Date()) {
2337
2398
  return { updated, backedUp };
2338
2399
  }
2339
2400
  function syncSkills(targetDir, sourceDir, baseline, now = /* @__PURE__ */ new Date(), foreignOf) {
2340
- if (!existsSync12(targetDir) || !existsSync12(sourceDir))
2401
+ if (!existsSync13(targetDir) || !existsSync13(sourceDir))
2341
2402
  return { updated: 0, backedUp: [], skippedLinks: [], foreignOwned: [] };
2342
2403
  let updated = 0;
2343
2404
  const backedUp = [];
@@ -2345,27 +2406,27 @@ function syncSkills(targetDir, sourceDir, baseline, now = /* @__PURE__ */ new Da
2345
2406
  const foreignOwned = [];
2346
2407
  for (const skill of readdirSync3(sourceDir, { withFileTypes: true })) {
2347
2408
  if (!skill.isDirectory()) continue;
2348
- const targetSkill = join11(targetDir, skill.name);
2409
+ const targetSkill = join12(targetDir, skill.name);
2349
2410
  if (occupiedByNonDirectory(targetSkill)) {
2350
2411
  skippedLinks.push(skill.name);
2351
2412
  continue;
2352
2413
  }
2353
- if (!existsSync12(targetSkill)) continue;
2354
- for (const rel of listFilesRecursive(join11(sourceDir, skill.name))) {
2355
- const targetFile = join11(targetSkill, rel);
2414
+ if (!existsSync13(targetSkill)) continue;
2415
+ for (const rel of listFilesRecursive(join12(sourceDir, skill.name))) {
2416
+ const targetFile = join12(targetSkill, rel);
2356
2417
  const foreign = foreignOf(`${skill.name}/${rel}`);
2357
2418
  if (foreign !== null) {
2358
2419
  if (!foreignOwned.includes(foreign)) foreignOwned.push(foreign);
2359
2420
  continue;
2360
2421
  }
2361
- const next = readFileSync11(join11(sourceDir, skill.name, rel), "utf8");
2362
- if (!existsSync12(targetFile)) {
2422
+ const next = readFileSync12(join12(sourceDir, skill.name, rel), "utf8");
2423
+ if (!existsSync13(targetFile)) {
2363
2424
  mkdirSync3(dirname3(targetFile), { recursive: true });
2364
2425
  writeFileSync5(targetFile, next);
2365
2426
  updated++;
2366
2427
  continue;
2367
2428
  }
2368
- const current = readFileSync11(targetFile, "utf8");
2429
+ const current = readFileSync12(targetFile, "utf8");
2369
2430
  if (current === next) continue;
2370
2431
  const recorded = baseline.get(`${skill.name}/${rel}`);
2371
2432
  if (recorded === void 0 || hashContent(current) !== recorded) {
@@ -2411,16 +2472,16 @@ function refreshSkillBaseline(projectDir) {
2411
2472
  }
2412
2473
  }
2413
2474
  function pruneOrphans(target, source, ext, ctx, now = /* @__PURE__ */ new Date()) {
2414
- if (!existsSync12(target) || !existsSync12(source)) return [];
2475
+ if (!existsSync13(target) || !existsSync13(source)) return [];
2415
2476
  const removed = [];
2416
2477
  for (const file of readdirSync3(target)) {
2417
2478
  if (!file.endsWith(ext)) continue;
2418
- const sourceFile = join11(source, file);
2419
- if (!existsSync12(sourceFile)) {
2420
- const targetFile = join11(target, file);
2479
+ const sourceFile = join12(source, file);
2480
+ if (!existsSync13(sourceFile)) {
2481
+ const targetFile = join12(target, file);
2421
2482
  if (!ctx.baseline.has(`${ctx.prefix}/${file}`)) continue;
2422
2483
  try {
2423
- const current = readFileSync11(targetFile, "utf8");
2484
+ const current = readFileSync12(targetFile, "utf8");
2424
2485
  if (!isHarnessOwned2(ctx, file, current)) backupFile(targetFile, now);
2425
2486
  unlinkSync2(targetFile);
2426
2487
  removed.push(file);
@@ -2431,8 +2492,8 @@ function pruneOrphans(target, source, ext, ctx, now = /* @__PURE__ */ new Date()
2431
2492
  return removed;
2432
2493
  }
2433
2494
  function retireMcpAllowlist(projectDir, now = /* @__PURE__ */ new Date()) {
2434
- const target = join11(projectDir, ".mcp-allowlist");
2435
- if (!existsSync12(target)) return null;
2495
+ const target = join12(projectDir, ".mcp-allowlist");
2496
+ if (!existsSync13(target)) return null;
2436
2497
  try {
2437
2498
  const backup = backupFile(target, now);
2438
2499
  unlinkSync2(target);
@@ -2444,7 +2505,7 @@ function retireMcpAllowlist(projectDir, now = /* @__PURE__ */ new Date()) {
2444
2505
  function cleanStaleHookRefs(settingsPath, claudeDir) {
2445
2506
  let settings;
2446
2507
  try {
2447
- settings = JSON.parse(readFileSync11(settingsPath, "utf8"));
2508
+ settings = JSON.parse(readFileSync12(settingsPath, "utf8"));
2448
2509
  } catch {
2449
2510
  return [];
2450
2511
  }
@@ -2471,7 +2532,7 @@ function cleanStaleHookRefs(settingsPath, claudeDir) {
2471
2532
  function keepHookRef(hook, claudeDir, removed) {
2472
2533
  const relPath = projectAnchoredRef(hook?.command ?? "", claudeDir);
2473
2534
  if (relPath === void 0) return true;
2474
- const exists = existsSync12(join11(claudeDir, relPath));
2535
+ const exists = existsSync13(join12(claudeDir, relPath));
2475
2536
  if (!exists && !removed.includes(relPath)) removed.push(relPath);
2476
2537
  return exists;
2477
2538
  }
@@ -2498,14 +2559,14 @@ function projectAnchoredRef(command, claudeDir) {
2498
2559
  function runInstall(ctx) {
2499
2560
  const { harnessRoot, projectDir, spec } = ctx;
2500
2561
  const mode = ctx.mode ?? "fresh";
2501
- const templatesDir = join12(harnessRoot, "templates");
2502
- if (!existsSync13(templatesDir)) {
2562
+ const templatesDir = join13(harnessRoot, "templates");
2563
+ if (!existsSync14(templatesDir)) {
2503
2564
  throw new Error(`Templates dir not found: ${templatesDir}`);
2504
2565
  }
2505
- const claudeDir = join12(projectDir, ".claude");
2566
+ const claudeDir = join13(projectDir, ".claude");
2506
2567
  const previousLog = readInstallLog(projectDir);
2507
2568
  const claudeWasSelected = previousLog?.spec.cli.includes("claude") ?? false;
2508
- if (mode === "update" && !existsSync13(claudeDir) && (previousLog === null || claudeWasSelected)) {
2569
+ if (mode === "update" && !existsSync14(claudeDir) && (previousLog === null || claudeWasSelected)) {
2509
2570
  throw new Error(
2510
2571
  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}`
2511
2572
  );
@@ -2599,7 +2660,7 @@ function applySupersededCleanup(spec, projectDir, found) {
2599
2660
  const kept = [];
2600
2661
  for (const asset of found) {
2601
2662
  try {
2602
- unlinkSync3(join12(projectDir, asset.target));
2663
+ unlinkSync3(join13(projectDir, asset.target));
2603
2664
  removed.push(asset.target);
2604
2665
  } catch {
2605
2666
  kept.push(asset.target);
@@ -2609,9 +2670,9 @@ function applySupersededCleanup(spec, projectDir, found) {
2609
2670
  }
2610
2671
  function healStaleHookRefs(spec, projectDir) {
2611
2672
  if (!spec.cli.includes("claude")) return [];
2612
- const settingsPath = join12(projectDir, ".claude/settings.json");
2613
- if (!existsSync13(settingsPath)) return [];
2614
- return cleanStaleHookRefs(settingsPath, join12(projectDir, ".claude"));
2673
+ const settingsPath = join13(projectDir, ".claude/settings.json");
2674
+ if (!existsSync14(settingsPath)) return [];
2675
+ return cleanStaleHookRefs(settingsPath, join13(projectDir, ".claude"));
2615
2676
  }
2616
2677
  function resolveBackupPath(ctx, mode, claudeDir) {
2617
2678
  const wantBackup = ctx.backup ?? (mode === "update" || mode === "reinstall");
@@ -2651,25 +2712,11 @@ function runUpdateInstall(ctx, templatesDir, backupPath) {
2651
2712
  return { ...baseline, external: null, staleHookRefs: [] };
2652
2713
  }
2653
2714
  function buildManifestSpec(spec) {
2654
- const selectionCtx = {
2715
+ return buildAssetSpec({
2655
2716
  tracks: spec.tracks,
2656
2717
  options: spec.options,
2657
2718
  ...spec.userOverride ? { userOverride: spec.userOverride } : {}
2658
- };
2659
- return {
2660
- tracks: spec.tracks,
2661
- withTauri: isAssetSelected("tauri-desktop", selectionCtx),
2662
- // v26.55.0 — withEcc gating (ADR-016). ECC cherry-pick (agents/skills/commands) 항목 토글.
2663
- // withPrune 은 ecc-plugin 사용을 전제 (이전 applyOptionRules `withEcc ||= withPrune` 의미 보존).
2664
- withEcc: isAssetSelected("ecc-plugin", selectionCtx) || spec.options.withPrune,
2665
- // v26.87.0 — internal bundled skills (dev-method + opt-in advisors, v26.95.0). Each id's
2666
- // condition (has-dev-track vs opt-in) is applied by isAssetSelected — manifest copy + the 3
2667
- // non-Claude CLI transforms gate on this filtered list, so opt-in ones install only when
2668
- // wizard-checked / `--with <id>`, and any uncheck / `--without <id>` (forceExclude) drops it.
2669
- selectedInternalSkills: INTERNAL_BUNDLED_SKILL_IDS.filter(
2670
- (id) => isAssetSelected(id, selectionCtx)
2671
- )
2672
- };
2719
+ });
2673
2720
  }
2674
2721
  function emptyClaudeBaseline() {
2675
2722
  return {
@@ -2694,12 +2741,12 @@ function installCliNeutralAssets(manifestSpec, projectDir, templatesDir, baselin
2694
2741
  continue;
2695
2742
  }
2696
2743
  if (!isCliNeutralTarget(entry.target)) continue;
2697
- const source = join12(templatesDir, entry.source);
2698
- if (!existsSync13(source)) {
2744
+ const source = join13(templatesDir, entry.source);
2745
+ if (!existsSync14(source)) {
2699
2746
  result.skipped += 1;
2700
2747
  continue;
2701
2748
  }
2702
- copyFile(source, join12(projectDir, entry.target));
2749
+ copyFile(source, join13(projectDir, entry.target));
2703
2750
  result.filesCopied += 1;
2704
2751
  }
2705
2752
  return result;
@@ -2711,9 +2758,9 @@ function backupEditedPolicyFile(entryTarget, target, source, baseline) {
2711
2758
  if (!POLICY_DIRS.some(({ dir, ext }) => rel.startsWith(`${dir}/`) && rel.endsWith(ext))) {
2712
2759
  return null;
2713
2760
  }
2714
- if (!existsSync13(target)) return null;
2715
- const current = readFileSync12(target, "utf-8");
2716
- if (current === readFileSync12(source, "utf-8")) return null;
2761
+ if (!existsSync14(target)) return null;
2762
+ const current = readFileSync13(target, "utf-8");
2763
+ if (current === readFileSync13(source, "utf-8")) return null;
2717
2764
  const recorded = baseline.get(rel);
2718
2765
  if (recorded !== void 0 && recorded === hashContent(current)) return null;
2719
2766
  return backupFile(target);
@@ -2726,14 +2773,14 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir, policyBas
2726
2773
  if (!entry.applies(manifestSpec)) {
2727
2774
  continue;
2728
2775
  }
2729
- const target = join12(projectDir, entry.target);
2776
+ const target = join13(projectDir, entry.target);
2730
2777
  if (isBaselineExcluded(entry.target, baselineExcluded)) {
2731
2778
  result.excluded.push(entry.target);
2732
- if (existsSync13(target)) result.excludedOnDisk.push(entry.target);
2779
+ if (existsSync14(target)) result.excludedOnDisk.push(entry.target);
2733
2780
  continue;
2734
2781
  }
2735
- const source = join12(templatesDir, entry.source);
2736
- if (!existsSync13(source)) {
2782
+ const source = join13(templatesDir, entry.source);
2783
+ if (!existsSync14(source)) {
2737
2784
  result.skipped += 1;
2738
2785
  continue;
2739
2786
  }
@@ -2744,7 +2791,7 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir, policyBas
2744
2791
  }
2745
2792
  if (entry.type === "file") {
2746
2793
  if (entry.target === ".claude/settings.json") {
2747
- const backup = backupFileIfChanged(target, readFileSync12(source, "utf-8"));
2794
+ const backup = backupFileIfChanged(target, readFileSync13(source, "utf-8"));
2748
2795
  if (backup) {
2749
2796
  result.backups.push(backup);
2750
2797
  }
@@ -2768,20 +2815,24 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir, policyBas
2768
2815
  }
2769
2816
  accumulateCategory(result.categories, entry);
2770
2817
  }
2771
- const hookDir = join12(projectDir, ".claude/hooks");
2772
- if (existsSync13(hookDir)) {
2818
+ const hookDir = join13(projectDir, ".claude/hooks");
2819
+ if (existsSync14(hookDir)) {
2773
2820
  chmodHooksSync(hookDir);
2774
2821
  }
2775
2822
  writeInstalledTracks(projectDir, manifestSpec.tracks);
2776
- const rootClaudeMd = writeRootClaudeMd(projectDir, manifestSpec.tracks);
2823
+ const rootClaudeMd = writeRootClaudeMd(
2824
+ projectDir,
2825
+ manifestSpec.tracks,
2826
+ manifestSpec.selectedInternalSkills ?? []
2827
+ );
2777
2828
  result.rootClaudeMd = { tracks: manifestSpec.tracks, created: rootClaudeMd.created };
2778
2829
  result.rootClaudeMdLog = harnessAnchorLog(projectDir);
2779
2830
  return result;
2780
2831
  }
2781
2832
  function harnessAnchorLog(projectDir) {
2782
- const anchor = join12(projectDir, HARNESS_ANCHOR_FILE);
2783
- if (!existsSync13(anchor)) return null;
2784
- return { path: HARNESS_ANCHOR_FILE, sha256: hashContent(readFileSync12(anchor, "utf-8")) };
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")) };
2785
2836
  }
2786
2837
  function writeEnvironmentFiles(projectDir, tracks) {
2787
2838
  return {
@@ -2840,7 +2891,7 @@ function writeInstallLogSafe(ctx, externalFiles, external, rootClaudeMdLog, prev
2840
2891
  rootFiles
2841
2892
  );
2842
2893
  const skillFiles = collectSkillHashes(ctx.projectDir);
2843
- const policyFiles = collectPolicyHashes(ctx.projectDir, join12(ctx.harnessRoot, "templates"));
2894
+ const policyFiles = collectPolicyHashes(ctx.projectDir, join13(ctx.harnessRoot, "templates"));
2844
2895
  const merged = mergeExternalFiles(ctx.projectDir, previousLog?.externalFiles, externalFiles);
2845
2896
  writeInstallLog(ctx.projectDir, {
2846
2897
  ...log,
@@ -2856,11 +2907,11 @@ function writeInstallLogSafe(ctx, externalFiles, external, rootClaudeMdLog, prev
2856
2907
  }
2857
2908
  }
2858
2909
  function composeAndWriteMcp(harnessRoot, projectDir, spec) {
2859
- const mcpPath = join12(projectDir, ".mcp.json");
2860
- const created = !existsSync13(mcpPath);
2910
+ const mcpPath = join13(projectDir, ".mcp.json");
2911
+ const created = !existsSync14(mcpPath);
2861
2912
  const composed = composeMcpJson({
2862
- templateMcpPath: join12(harnessRoot, "templates/mcp.json"),
2863
- trackMapPath: join12(harnessRoot, "templates/track-mcp-map.tsv"),
2913
+ templateMcpPath: join13(harnessRoot, "templates/mcp.json"),
2914
+ trackMapPath: join13(harnessRoot, "templates/track-mcp-map.tsv"),
2864
2915
  existingPath: mcpPath,
2865
2916
  tracks: spec.tracks
2866
2917
  });
@@ -2913,16 +2964,20 @@ function accumulateCategory(cats, entry) {
2913
2964
  }
2914
2965
  }
2915
2966
  function writeInstalledTracks(projectDir, tracks) {
2916
- const path = join12(projectDir, ".claude/.installed-tracks");
2967
+ const path = join13(projectDir, ".claude/.installed-tracks");
2917
2968
  mkdirSync4(dirname4(path), { recursive: true });
2918
2969
  const sorted = [...new Set(tracks)].sort().join("\n");
2919
2970
  writeFileSync6(path, `${sorted}
2920
2971
  `);
2921
2972
  }
2922
- function writeRootClaudeMd(projectDir, tracks) {
2923
- const target = join12(projectDir, "CLAUDE.md");
2924
- const existing = existsSync13(target) ? readFileSync12(target, "utf-8") : null;
2925
- const content = upsertHarnessImport(existing, { projectName: basename5(projectDir), tracks });
2973
+ function writeRootClaudeMd(projectDir, tracks, continuousSkills) {
2974
+ const target = join13(projectDir, "CLAUDE.md");
2975
+ const existing = existsSync14(target) ? readFileSync13(target, "utf-8") : null;
2976
+ const content = upsertHarnessImport(existing, {
2977
+ projectName: basename5(projectDir),
2978
+ tracks,
2979
+ continuousSkills
2980
+ });
2926
2981
  if (content !== existing) {
2927
2982
  writeFileSync6(target, content);
2928
2983
  }
@@ -2931,7 +2986,7 @@ function writeRootClaudeMd(projectDir, tracks) {
2931
2986
  function chmodHooksSync(hookDir) {
2932
2987
  for (const file of listHookFiles(hookDir)) {
2933
2988
  try {
2934
- chmodSync2(file, 493);
2989
+ chmodSync3(file, 493);
2935
2990
  } catch {
2936
2991
  }
2937
2992
  }
@@ -3007,8 +3062,9 @@ function renderInstallHeader(log, spec, mode) {
3007
3062
  for (const [cat, ids] of groupAssetsByCategory(finalAssets)) {
3008
3063
  log(` ${c.dim(`\xB7 ${cat}:`)} ${ids.join(", ")}`);
3009
3064
  }
3065
+ const assetSpec = buildManifestSpec(spec);
3010
3066
  const cost = formatResidentCostLine(
3011
- residentCost(buildManifest(spec).filter((e2) => e2.applies(spec))),
3067
+ residentCost(buildManifest(assetSpec).filter((e2) => e2.applies(assetSpec))),
3012
3068
  summarizeContextCost(finalAssets).unmeasuredCount
3013
3069
  );
3014
3070
  if (cost) log(` ${c.dim(`\xB7 ${cost}`)}`);
@@ -3097,8 +3153,8 @@ function renderCliArtifacts(log, spec, report) {
3097
3153
  log(
3098
3154
  assetRow(
3099
3155
  "success",
3100
- ".agents/skills/<id>/SKILL.md",
3101
- `${report.codex.skillFiles.length} skills`
3156
+ ".agents/skills/<id>/",
3157
+ `${countSkillDirs(report.codex.skillFiles)} skills`
3102
3158
  )
3103
3159
  );
3104
3160
  }
@@ -3116,7 +3172,7 @@ function renderCliArtifacts(log, spec, report) {
3116
3172
  assetRow(
3117
3173
  "success",
3118
3174
  ".agents/skills/",
3119
- `${report.opencode.skillFiles.length} dev-method skills (codex\xB7antigravity \uC640 \uAC19\uC740 \uC790\uB9AC)`
3175
+ `${countSkillDirs(report.opencode.skillFiles)} dev-method skills (codex\xB7antigravity \uC640 \uAC19\uC740 \uC790\uB9AC)`
3120
3176
  )
3121
3177
  );
3122
3178
  }
@@ -3138,8 +3194,8 @@ function renderCliArtifacts(log, spec, report) {
3138
3194
  log(
3139
3195
  assetRow(
3140
3196
  "success",
3141
- ".agents/skills/<id>/SKILL.md",
3142
- `${report.antigravity.skillFiles.length} skills`
3197
+ ".agents/skills/<id>/",
3198
+ `${countSkillDirs(report.antigravity.skillFiles)} skills`
3143
3199
  )
3144
3200
  );
3145
3201
  }
@@ -3205,15 +3261,25 @@ function renderFinalSummary(log, spec, report, fromWizard) {
3205
3261
  log(infoRow("NEXT", `Open ${c.bold(label)} \u2014 installed rules & skills are now active`));
3206
3262
  const scaffoldFiles = scaffoldFilesForCli(spec.cli);
3207
3263
  if (scaffoldFiles.length > 0) {
3264
+ const auditInstalled = buildManifestSpec(spec).selectedInternalSkills?.includes("audit-harness-fit");
3265
+ const populateHint = auditInstalled ? `, or ask the ${c.bold("audit-harness-fit")} skill to fill it from repository evidence` : "";
3208
3266
  log(
3209
3267
  infoRow(
3210
3268
  "FILL",
3211
- `${scaffoldFiles.map((f) => c.bold(f)).join(" \xB7 ")} \u2014 a fill-in scaffold. Open and paste each ${c.bold("<!-- FILL: \u2026 -->")} prompt to your agent to tailor it to this project`
3269
+ `${scaffoldFiles.map((f) => c.bold(f)).join(" \xB7 ")} \u2014 a fill-in scaffold. Open and paste each ${c.bold("<!-- FILL: \u2026 -->")} prompt to your agent to tailor it to this project${populateHint}`
3212
3270
  )
3213
3271
  );
3214
3272
  }
3215
3273
  log("");
3216
3274
  }
3275
+ function countSkillDirs(skillFiles) {
3276
+ const ids = /* @__PURE__ */ new Set();
3277
+ for (const f of skillFiles) {
3278
+ const m = /[\\/]\.agents[\\/]skills[\\/]([^\\/]+)[\\/]/.exec(f);
3279
+ if (m?.[1] !== void 0) ids.add(m[1]);
3280
+ }
3281
+ return ids.size;
3282
+ }
3217
3283
  function scaffoldFilesForCli(cli2) {
3218
3284
  const files = [];
3219
3285
  if (cli2.includes("claude")) {
@@ -3280,6 +3346,15 @@ function renderPhase1Rows(log, baseline, verbose = false, withEcc = false, claud
3280
3346
  if (baseline.updateMode.rootImportAdded) {
3281
3347
  log(assetRow("success", "CLAUDE.md", `${HARNESS_IMPORT_LINE} import added`));
3282
3348
  }
3349
+ if (baseline.updateMode.rootBlockRefreshed) {
3350
+ log(
3351
+ assetRow(
3352
+ "success",
3353
+ "CLAUDE.md",
3354
+ "harness block refreshed (skills that apply continuously)"
3355
+ )
3356
+ );
3357
+ }
3283
3358
  if (baseline.updateMode.legacyAnchor) {
3284
3359
  log(
3285
3360
  assetRow(
@@ -3325,6 +3400,15 @@ function renderPhase1Rows(log, baseline, verbose = false, withEcc = false, claud
3325
3400
  )
3326
3401
  );
3327
3402
  }
3403
+ for (const id of baseline.updateMode.retiredAgents) {
3404
+ log(
3405
+ assetRow(
3406
+ "skip",
3407
+ "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`
3409
+ )
3410
+ );
3411
+ }
3328
3412
  if (baseline.updateMode.policyBackedUp.length > 0) {
3329
3413
  log(
3330
3414
  assetRow(
@@ -3378,13 +3462,37 @@ function renderPhase1Rows(log, baseline, verbose = false, withEcc = false, claud
3378
3462
  log(assetRow("skip", "external skills", `${meta} \xB7 \uB2E4\uC74C update \uC5D0\uC11C \uB2E4\uC2DC \uC2DC\uB3C4\uD55C\uB2E4`));
3379
3463
  }
3380
3464
  if (baseline.updateMode.externalSkillsNotInCatalog.length > 0) {
3381
- log(
3382
- assetRow(
3383
- "skip",
3384
- "external skills",
3385
- `${baseline.updateMode.externalSkillsNotInCatalog.join(", ")} \xB7 \uCE74\uD0C8\uB85C\uADF8\uC5D0 \uC5C6\uC5B4 \uAC31\uC2E0 \uB300\uC0C1\uC774 \uC544\uB2C8\uB2E4`
3386
- )
3387
- );
3465
+ const ids = baseline.updateMode.externalSkillsNotInCatalog;
3466
+ for (const id of ids) {
3467
+ const renamedTo = RENAMED_SKILL_IDS[id];
3468
+ if (renamedTo) {
3469
+ log(
3470
+ assetRow(
3471
+ "skip",
3472
+ "skills",
3473
+ `${id} \uB294 ${renamedTo} \uAC00 \uB410\uB2E4 \xB7 update \uB4A4 .claude/skills/${id} \uB97C \uC9C0\uC6B0\uACE0 ${renamedTo} \uB97C \uC120\uD0DD\uD574 \uBC1B\uB294\uB2E4`
3474
+ )
3475
+ );
3476
+ } else if (RETIRED_SKILL_IDS.includes(id)) {
3477
+ log(
3478
+ assetRow(
3479
+ "skip",
3480
+ "skills",
3481
+ `${id} \xB7 \uC774 \uB9B4\uB9AC\uC988\uC5D0\uC11C \uC740\uD1F4 \u2014 .claude/skills/${id} \uB97C \uC9C0\uC6CC\uB3C4 \uB41C\uB2E4`
3482
+ )
3483
+ );
3484
+ }
3485
+ }
3486
+ const unknown = ids.filter((id) => !RENAMED_SKILL_IDS[id] && !RETIRED_SKILL_IDS.includes(id));
3487
+ if (unknown.length > 0) {
3488
+ log(
3489
+ assetRow(
3490
+ "skip",
3491
+ "external skills",
3492
+ `${unknown.join(", ")} \xB7 \uCE74\uD0C8\uB85C\uADF8\uC5D0 \uC5C6\uC5B4 \uAC31\uC2E0 \uB300\uC0C1\uC774 \uC544\uB2C8\uB2E4`
3493
+ )
3494
+ );
3495
+ }
3388
3496
  }
3389
3497
  if (baseline.updateMode.externalSkillsUnknown) {
3390
3498
  log(
@@ -3429,12 +3537,7 @@ function renderPhase1Rows(log, baseline, verbose = false, withEcc = false, claud
3429
3537
  );
3430
3538
  }
3431
3539
  if (cats.hooks.length > 0) {
3432
- phase1Row(
3433
- "hooks",
3434
- cats.hooks.length,
3435
- "session-start \xB7 protect-files \xB7 task-brief-nudge",
3436
- cats.hooks
3437
- );
3540
+ phase1Row("hooks", cats.hooks.length, "session-start \xB7 protect-files", cats.hooks);
3438
3541
  }
3439
3542
  if (cats.commands > 0) {
3440
3543
  phase1Row("commands", cats.commands, "slash commands");
@@ -3443,7 +3546,7 @@ function renderPhase1Rows(log, baseline, verbose = false, withEcc = false, claud
3443
3546
  phase1Row(
3444
3547
  "skills",
3445
3548
  cats.skills.length,
3446
- "spec-scaling \xB7 deep-research \xB7 ui-visual-review \xB7 eval-harness (modified)",
3549
+ "deep-research \xB7 ui-visual-review \xB7 eval-harness (modified)",
3447
3550
  cats.skills
3448
3551
  );
3449
3552
  }
@@ -3771,8 +3874,8 @@ function registerInstallCommand(cli2) {
3771
3874
 
3772
3875
  // src/commands/list.ts
3773
3876
  init_esm_shims();
3774
- import { existsSync as existsSync14, readFileSync as readFileSync13 } from "fs";
3775
- import { join as join13, resolve as resolve3 } from "path";
3877
+ import { existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
3878
+ import { join as join14, resolve as resolve3 } from "path";
3776
3879
  function listAction(options = {}, deps = {}) {
3777
3880
  const log = deps.log ?? console.log;
3778
3881
  const err = deps.err ?? console.error;
@@ -3835,8 +3938,8 @@ function formatTemplateRows(log, projectDir) {
3835
3938
  const rows = [` ${c.dim(dirs.join(" "))}`];
3836
3939
  const rootMd = log.templates.rootClaudeMd;
3837
3940
  if (rootMd) {
3838
- const path = join13(projectDir, rootMd.path);
3839
- const modified = existsSync14(path) && hashContent(readFileSync13(path, "utf8")) !== rootMd.sha256;
3941
+ const path = join14(projectDir, rootMd.path);
3942
+ const modified = existsSync15(path) && hashContent(readFileSync14(path, "utf8")) !== rootMd.sha256;
3840
3943
  rows.push(
3841
3944
  modified ? ` ${c.dim(rootMd.path)} ${c.yellow("(\uC218\uC815\uB428 \u2014 uninstall \uC2DC \uBCF4\uC874)")}` : ` ${c.dim(rootMd.path)}`
3842
3945
  );
@@ -3844,7 +3947,7 @@ function formatTemplateRows(log, projectDir) {
3844
3947
  return rows;
3845
3948
  }
3846
3949
  function formatRootFileRows(rootFiles, projectDir) {
3847
- const present = rootFiles.filter((f) => existsSync14(join13(projectDir, f.path)));
3950
+ const present = rootFiles.filter((f) => existsSync15(join14(projectDir, f.path)));
3848
3951
  const width = Math.max(0, ...present.map((f) => f.path.length));
3849
3952
  return present.map(
3850
3953
  (f) => ` ${c.dim(padDisplay(f.path, width))} ${c.dim(f.change === "created" ? "\uC0DD\uC131" : "\uBCD1\uD569")} ${c.dim(f.notes.join(" / "))}`
@@ -3862,15 +3965,15 @@ function registerListCommand(cli2) {
3862
3965
  init_esm_shims();
3863
3966
  import { spawnSync as spawnSync2 } from "child_process";
3864
3967
  import {
3865
- existsSync as existsSync15,
3968
+ existsSync as existsSync16,
3866
3969
  lstatSync as lstatSync2,
3867
3970
  readdirSync as readdirSync5,
3868
- readFileSync as readFileSync14,
3971
+ readFileSync as readFileSync15,
3869
3972
  rmdirSync,
3870
3973
  rmSync,
3871
3974
  writeFileSync as writeFileSync7
3872
3975
  } from "fs";
3873
- import { dirname as dirname5, join as join14, relative as relative2, resolve as resolve4, sep as sep2 } from "path";
3976
+ import { dirname as dirname5, join as join15, relative as relative2, resolve as resolve4, sep as sep2 } from "path";
3874
3977
 
3875
3978
  // src/uninstall-interactive.ts
3876
3979
  init_esm_shims();
@@ -5110,7 +5213,7 @@ function settleLog(ctx, io) {
5110
5213
  return true;
5111
5214
  }
5112
5215
  } else {
5113
- io.rm(join14(projectDir, INSTALL_LOG_DIR));
5216
+ io.rm(join15(projectDir, INSTALL_LOG_DIR));
5114
5217
  io.rm(legacyInstallLogPath(projectDir));
5115
5218
  io.log(` ${status.success("install log removed")}`);
5116
5219
  }
@@ -5160,7 +5263,7 @@ function advisoryLines(plan, projectDir, rootFiles) {
5160
5263
  return lines;
5161
5264
  }
5162
5265
  function rootFileAdvisoryLines(rootFiles, projectDir) {
5163
- const present = rootFiles.filter((f) => existsSync15(join14(projectDir, f.path)));
5266
+ const present = rootFiles.filter((f) => existsSync16(join15(projectDir, f.path)));
5164
5267
  if (present.length === 0) return [];
5165
5268
  return [
5166
5269
  "",
@@ -5261,16 +5364,16 @@ function buildGlobalAdvisoryCmd(asset) {
5261
5364
  }
5262
5365
  }
5263
5366
  function removeTemplates(log, projectDir, rm) {
5264
- rm(join14(projectDir, log.templates.claudeDir));
5265
- if (log.templates.codexDir) rm(join14(projectDir, log.templates.codexDir));
5266
- if (log.templates.opencodeDir) rm(join14(projectDir, log.templates.opencodeDir));
5367
+ rm(join15(projectDir, log.templates.claudeDir));
5368
+ if (log.templates.codexDir) rm(join15(projectDir, log.templates.codexDir));
5369
+ if (log.templates.opencodeDir) rm(join15(projectDir, log.templates.opencodeDir));
5267
5370
  const external = removeExternalFiles(log, projectDir, rm);
5268
5371
  const importStripped = stripRootImport(projectDir);
5269
5372
  const rootMd = log.templates.rootClaudeMd;
5270
5373
  if (rootMd) {
5271
5374
  if (rootClaudeMdModified(log, projectDir))
5272
5375
  return { rootClaudeMdKept: true, importStripped, external };
5273
- rm(join14(projectDir, rootMd.path));
5376
+ rm(join15(projectDir, rootMd.path));
5274
5377
  }
5275
5378
  return { rootClaudeMdKept: false, importStripped, external };
5276
5379
  }
@@ -5278,17 +5381,17 @@ function removeExternalFiles(log, projectDir, rm) {
5278
5381
  const removed = [];
5279
5382
  const kept = [];
5280
5383
  for (const { path, sha256 } of log.externalFiles ?? []) {
5281
- const abs = join14(projectDir, path);
5282
- if (!existsSync15(abs)) continue;
5384
+ const abs = join15(projectDir, path);
5385
+ if (!existsSync16(abs)) continue;
5283
5386
  if (!lstatSync2(abs).isFile()) continue;
5284
- if (hashContent(readFileSync14(abs, "utf8")) !== sha256) {
5387
+ if (hashContent(readFileSync15(abs, "utf8")) !== sha256) {
5285
5388
  kept.push(path);
5286
5389
  continue;
5287
5390
  }
5288
5391
  rm(abs);
5289
5392
  removed.push(path);
5290
5393
  }
5291
- for (const path of removed) pruneEmptyDirsUpward(projectDir, dirname5(join14(projectDir, path)));
5394
+ for (const path of removed) pruneEmptyDirsUpward(projectDir, dirname5(join15(projectDir, path)));
5292
5395
  return { removed, kept };
5293
5396
  }
5294
5397
  function pruneEmptyDirsUpward(projectDir, startDir) {
@@ -5310,7 +5413,7 @@ function stripRootImport(projectDir) {
5310
5413
  const stripped = current === null ? null : stripHarnessImport(current);
5311
5414
  if (stripped === null) return false;
5312
5415
  try {
5313
- writeFileSync7(join14(projectDir, "CLAUDE.md"), stripped, "utf8");
5416
+ writeFileSync7(join15(projectDir, "CLAUDE.md"), stripped, "utf8");
5314
5417
  return true;
5315
5418
  } catch {
5316
5419
  return false;
@@ -5320,9 +5423,9 @@ function previewExternalLines(installLog, projectDir) {
5320
5423
  const lines = [];
5321
5424
  let removable = 0;
5322
5425
  for (const { path, sha256 } of installLog.externalFiles ?? []) {
5323
- const abs = join14(projectDir, path);
5324
- if (!existsSync15(abs)) continue;
5325
- if (hashContent(readFileSync14(abs, "utf8")) !== sha256) {
5426
+ const abs = join15(projectDir, path);
5427
+ if (!existsSync16(abs)) continue;
5428
+ if (hashContent(readFileSync15(abs, "utf8")) !== sha256) {
5326
5429
  lines.push(` \u25CB keep ${path} (modified since install \u2014 preserved)`);
5327
5430
  continue;
5328
5431
  }
@@ -5348,10 +5451,10 @@ function hasRootImport(projectDir) {
5348
5451
  return current !== null && stripHarnessImport(current) !== null;
5349
5452
  }
5350
5453
  function readRootClaudeMd(projectDir) {
5351
- const path = join14(projectDir, "CLAUDE.md");
5352
- if (!existsSync15(path)) return null;
5454
+ const path = join15(projectDir, "CLAUDE.md");
5455
+ if (!existsSync16(path)) return null;
5353
5456
  try {
5354
- return readFileSync14(path, "utf8");
5457
+ return readFileSync15(path, "utf8");
5355
5458
  } catch {
5356
5459
  return null;
5357
5460
  }
@@ -5359,9 +5462,9 @@ function readRootClaudeMd(projectDir) {
5359
5462
  function rootClaudeMdModified(log, projectDir) {
5360
5463
  const rootMd = log.templates.rootClaudeMd;
5361
5464
  if (!rootMd) return false;
5362
- const path = join14(projectDir, rootMd.path);
5363
- if (!existsSync15(path)) return false;
5364
- return hashContent(readFileSync14(path, "utf8")) !== rootMd.sha256;
5465
+ const path = join15(projectDir, rootMd.path);
5466
+ if (!existsSync16(path)) return false;
5467
+ return hashContent(readFileSync15(path, "utf8")) !== rootMd.sha256;
5365
5468
  }
5366
5469
  function formatTemplateList(log) {
5367
5470
  const items = [log.templates.claudeDir];
@@ -5373,7 +5476,7 @@ function defaultSpawn2(cmd, args) {
5373
5476
  return spawnSync2(cmd, [...args], { encoding: "utf8", stdio: "pipe", timeout: 12e4 });
5374
5477
  }
5375
5478
  function defaultRm(path) {
5376
- if (existsSync15(path)) {
5479
+ if (existsSync16(path)) {
5377
5480
  rmSync(path, { recursive: true, force: true });
5378
5481
  }
5379
5482
  }
@@ -5421,8 +5524,8 @@ import { resolve as resolve5 } from "path";
5421
5524
 
5422
5525
  // src/state.ts
5423
5526
  init_esm_shims();
5424
- import { existsSync as existsSync16, readFileSync as readFileSync15 } from "fs";
5425
- import { join as join15 } from "path";
5527
+ import { existsSync as existsSync17, readFileSync as readFileSync16 } from "fs";
5528
+ import { join as join16 } from "path";
5426
5529
  var META_FILE = ".claude/.installed-tracks";
5427
5530
  var LEGACY_SIGNATURES = [
5428
5531
  { rule: "htmx.md", track: "ssr-htmx" },
@@ -5432,11 +5535,11 @@ var LEGACY_SIGNATURES = [
5432
5535
  { rule: "cli-development.md", track: "tooling" }
5433
5536
  ];
5434
5537
  function detectInstallState(projectDir) {
5435
- const claudeDir = join15(projectDir, ".claude");
5436
- const hasClaudeDir = existsSync16(claudeDir);
5538
+ const claudeDir = join16(projectDir, ".claude");
5539
+ const hasClaudeDir = existsSync17(claudeDir);
5437
5540
  if (hasClaudeDir) {
5438
- const metaPath = join15(projectDir, META_FILE);
5439
- if (existsSync16(metaPath)) {
5541
+ const metaPath = join16(projectDir, META_FILE);
5542
+ if (existsSync17(metaPath)) {
5440
5543
  const tracks2 = readMetafile(metaPath);
5441
5544
  return { state: "existing", tracks: tracks2, source: "metafile", hasClaudeDir: true };
5442
5545
  }
@@ -5458,7 +5561,7 @@ function tracksFromLog(tracks) {
5458
5561
  return [...new Set(tracks.filter(isTrack))].sort();
5459
5562
  }
5460
5563
  function readMetafile(path) {
5461
- const raw = readFileSync15(path, "utf8");
5564
+ const raw = readFileSync16(path, "utf8");
5462
5565
  const seen = /* @__PURE__ */ new Set();
5463
5566
  for (const line of raw.split(/\s+/)) {
5464
5567
  const trimmed = line.trim();
@@ -5469,13 +5572,13 @@ function readMetafile(path) {
5469
5572
  return [...seen].sort();
5470
5573
  }
5471
5574
  function inferFromLegacySignatures(projectDir) {
5472
- const rulesDir = join15(projectDir, ".claude/rules");
5473
- if (!existsSync16(rulesDir)) {
5575
+ const rulesDir = join16(projectDir, ".claude/rules");
5576
+ if (!existsSync17(rulesDir)) {
5474
5577
  return [];
5475
5578
  }
5476
5579
  const found = /* @__PURE__ */ new Set();
5477
5580
  for (const sig of LEGACY_SIGNATURES) {
5478
- if (existsSync16(join15(rulesDir, sig.rule))) {
5581
+ if (existsSync17(join16(rulesDir, sig.rule))) {
5479
5582
  found.add(sig.track);
5480
5583
  }
5481
5584
  }
@@ -5605,7 +5708,7 @@ var INSTALL_TARGET_PAGES = [
5605
5708
  // 2026-08-16 — 트랙이 고르는 자산을 **맨 앞에서** 전부 보여준다. 그전까지 이 항목들은 화면에
5606
5709
  // 한 번도 안 나온 채 깔렸고, 사용자는 설치가 끝난 뒤 요약에서 처음 봤다.
5607
5710
  //
5608
- // 2페이지로 나눈 근거는 실측이다: 최대 트랙(`full`)이 32항목(rules 6 · agents 9 · hooks 3 ·
5711
+ // 2페이지로 나눈 근거는 실측이다: 최대 트랙(`full`)이 32항목(당시 실측 — rules 6 · agents 9 · hooks 3 ·
5609
5712
  // skills 14)이라 clack groupMultiselect 의 "페이지당 ≤ ~30행" 제약을 한 페이지로는 못 지킨다.
5610
5713
  // 가르는 축은 역할이다 — 정책·가드가 한쪽, 실행 능력이 다른 쪽.
5611
5714
  { label: "Track baseline \u2014 Rules & Hooks (\uC815\uCC45\xB7\uAC00\uB4DC)", cats: [], baseline: ["rules", "hooks"] },
@@ -6149,10 +6252,11 @@ function formatSummary(spec) {
6149
6252
  for (const [cat, ids] of groupAssetsByCategory(finalAssets)) {
6150
6253
  lines.push(` \xB7 ${cat}: ${ids.join(", ")}`);
6151
6254
  }
6255
+ const assetSpec = buildManifestSpec(spec);
6152
6256
  const cost = formatResidentCostLine(
6153
6257
  residentCost(
6154
- buildManifest(spec).filter(
6155
- (e2) => e2.applies(spec) && !isBaselineExcluded(e2.target, baselineExcluded)
6258
+ buildManifest(assetSpec).filter(
6259
+ (e2) => e2.applies(assetSpec) && !isBaselineExcluded(e2.target, baselineExcluded)
6156
6260
  )
6157
6261
  ),
6158
6262
  summarizeContextCost(finalAssets).unmeasuredCount