@uzysjung/agent-harness 26.160.0 → 26.160.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -754,7 +754,7 @@ var cac = (name = "") => new CAC(name);
754
754
  // package.json
755
755
  var package_default = {
756
756
  name: "@uzysjung/agent-harness",
757
- version: "26.160.0",
757
+ version: "26.160.1",
758
758
  description: "Curate vetted AI-coding skills & plugins by your tech stack \u2014 install only what you need, across Claude Code, Codex, OpenCode & Antigravity",
759
759
  type: "module",
760
760
  publishConfig: {
@@ -1210,6 +1210,39 @@ function mergeAgentsMd(params) {
1210
1210
  }
1211
1211
  return bodies.size === 0 ? rendered : assemble(rendered, names, bodies);
1212
1212
  }
1213
+ function installerLines(body, m) {
1214
+ if (body === null) return [];
1215
+ const at2 = blockRange(body, m);
1216
+ return at2 === null ? [...body] : [...body.slice(0, at2[0]), ...body.slice(at2[1] + 1)];
1217
+ }
1218
+ function compact(lines) {
1219
+ return lines.map((l) => l.replace(/\r$/, "").trimEnd()).filter((l) => l.trim() !== "");
1220
+ }
1221
+ function trimBlankEdges(lines) {
1222
+ const out = trimTrailingBlanks(lines);
1223
+ while (out.length > 0 && (out[0] ?? "").trim() === "") out.shift();
1224
+ return out;
1225
+ }
1226
+ function stripHarnessFromAgentsMd(params) {
1227
+ const { existing, template } = params;
1228
+ const lines = existing.split("\n");
1229
+ if (blockRange(lines, ANCHOR_BLOCK) === null && blockRange(lines, SKILLS_BLOCK) === null) {
1230
+ return null;
1231
+ }
1232
+ const names = sectionNames(template);
1233
+ const context = installerLines(sectionBody(existing, names, CONTEXT_SECTION), SKILLS_BLOCK);
1234
+ const rules = installerLines(sectionBody(existing, names, RULES_SECTION), ANCHOR_BLOCK);
1235
+ const scaffold = compact(renderFillScaffold("agents-md").split("\n"));
1236
+ const contextFilled = compact(context).join("\n") !== scaffold.join("\n");
1237
+ const rulesFilled = compact(rules).length > 0;
1238
+ if (!contextFilled && !rulesFilled) return null;
1239
+ const out = [];
1240
+ const title = (lines[0] ?? "").replace(/\r$/, "");
1241
+ if (/^# /.test(title)) out.push(title, "");
1242
+ out.push(`## ${CONTEXT_SECTION}`, "", ...trimBlankEdges(context), "");
1243
+ if (rulesFilled) out.push(`## ${RULES_SECTION}`, "", ...trimBlankEdges(rules), "");
1244
+ return out.join("\n");
1245
+ }
1213
1246
 
1214
1247
  // src/codex/agents-md.ts
1215
1248
  function renameSlashes(text) {
@@ -2625,13 +2658,21 @@ function installedBundledSkills(projectDir) {
2625
2658
  (id) => existsSync13(join12(projectDir, ".claude/skills", id)) || existsSync13(join12(projectDir, ".agents/skills", id))
2626
2659
  );
2627
2660
  }
2661
+ function installedCliTargets(log) {
2662
+ if (log === null) return ALL_CLI_TARGETS;
2663
+ return ALL_CLI_TARGETS.filter((cli2) => {
2664
+ if (cli2 === "codex") return log.templates.codexDir !== void 0;
2665
+ if (cli2 === "opencode") return log.templates.opencodeDir !== void 0;
2666
+ return true;
2667
+ });
2668
+ }
2628
2669
  function refreshExternalCli(projectDir, harnessRoot) {
2629
2670
  const log = readInstallLog(projectDir);
2630
2671
  const baselineExcluded = new Set(log?.spec.baselineExclude ?? []);
2631
2672
  const result = runCliTransforms({
2632
2673
  harnessRoot,
2633
2674
  projectDir,
2634
- cli: ALL_CLI_TARGETS,
2675
+ cli: installedCliTargets(log),
2635
2676
  // 스킬은 **디스크에 있는 것만** 넘긴다. 스킬 *파일*은 전체 목록을 넘겨도 refreshOnly 가
2636
2677
  // 없는 것을 건너뛰지만, `AGENTS.md` 의 상시 스킬 안내(ADR-085)는 이 목록 그대로 렌더돼
2637
2678
  // `--without` 으로 뺀 스킬(#505)·opt-in 스킬을 "열어라"고 적었다(실측 2026-09-21). 판정은
@@ -5410,6 +5451,7 @@ function uninstallAction(options, deps = {}) {
5410
5451
  const spawn = deps.spawn ?? defaultSpawn2;
5411
5452
  const rm = deps.rm ?? defaultRm;
5412
5453
  const writeLog = deps.writeLog ?? writeInstallLog;
5454
+ const harnessRoot = (deps.resolveHarnessRoot ?? defaultHarnessRoot)();
5413
5455
  const projectDir = resolve4(options.projectDir ?? process.cwd());
5414
5456
  const installLog = readInstallLog(projectDir);
5415
5457
  if (!installLog) {
@@ -5438,7 +5480,14 @@ function uninstallAction(options, deps = {}) {
5438
5480
  const plan = planReverse(targetAssets, spawn);
5439
5481
  for (const line of headerLines(installLog, selectedIds, targetAssets.length)) log(line);
5440
5482
  if (options.dryRun) {
5441
- for (const line of dryRunLines(plan, installLog, projectDir, keepTemplates, rootFiles)) {
5483
+ for (const line of dryRunLines(
5484
+ plan,
5485
+ installLog,
5486
+ projectDir,
5487
+ keepTemplates,
5488
+ rootFiles,
5489
+ harnessRoot
5490
+ )) {
5442
5491
  log(line);
5443
5492
  }
5444
5493
  exit(0);
@@ -5450,7 +5499,8 @@ function uninstallAction(options, deps = {}) {
5450
5499
  const { rootClaudeMdKept, importStripped, external } = removeTemplates(
5451
5500
  installLog,
5452
5501
  projectDir,
5453
- rm
5502
+ rm,
5503
+ harnessRoot
5454
5504
  );
5455
5505
  log(` ${status.success(`templates removed: ${formatTemplateList(installLog)}`)}`);
5456
5506
  for (const line of externalRemovalLines(external)) log(line);
@@ -5557,7 +5607,7 @@ function settleLog(ctx, io) {
5557
5607
  }
5558
5608
  return false;
5559
5609
  }
5560
- function dryRunLines(plan, installLog, projectDir, keepTemplates, rootFiles) {
5610
+ function dryRunLines(plan, installLog, projectDir, keepTemplates, rootFiles, harnessRoot) {
5561
5611
  const lines = [c.yellow("[DRY RUN] reverse list (\uC2E4\uC81C \uBCC0\uACBD \uC5C6\uC74C):"), ""];
5562
5612
  if (plan.reverseSteps.length === 0) {
5563
5613
  lines.push(c.dim(" (no project-scope assets to reverse)"));
@@ -5579,7 +5629,7 @@ function dryRunLines(plan, installLog, projectDir, keepTemplates, rootFiles) {
5579
5629
  if (hasRootImport(projectDir)) {
5580
5630
  lines.push(" \u25CB strip harness @import from CLAUDE.md (\uBCF8\uBB38 \uBCF4\uC874)");
5581
5631
  }
5582
- lines.push(...previewExternalLines(installLog, projectDir));
5632
+ lines.push(...previewExternalLines(installLog, projectDir, harnessRoot));
5583
5633
  }
5584
5634
  lines.push(...advisoryLines(plan, projectDir, rootFiles), "");
5585
5635
  return lines;
@@ -5701,11 +5751,11 @@ function buildGlobalAdvisoryCmd(asset) {
5701
5751
  return "(no standard reverse \u2014 manual)";
5702
5752
  }
5703
5753
  }
5704
- function removeTemplates(log, projectDir, rm) {
5754
+ function removeTemplates(log, projectDir, rm, harnessRoot) {
5705
5755
  rm(join16(projectDir, log.templates.claudeDir));
5706
5756
  if (log.templates.codexDir) rm(join16(projectDir, log.templates.codexDir));
5707
5757
  if (log.templates.opencodeDir) rm(join16(projectDir, log.templates.opencodeDir));
5708
- const external = removeExternalFiles(log, projectDir, rm);
5758
+ const external = removeExternalFiles(log, projectDir, rm, harnessRoot);
5709
5759
  const importStripped = stripRootImport(projectDir);
5710
5760
  const rootMd = log.templates.rootClaudeMd;
5711
5761
  if (rootMd) {
@@ -5715,22 +5765,55 @@ function removeTemplates(log, projectDir, rm) {
5715
5765
  }
5716
5766
  return { rootClaudeMdKept: false, importStripped, external };
5717
5767
  }
5718
- function removeExternalFiles(log, projectDir, rm) {
5768
+ var AGENTS_MD = "AGENTS.md";
5769
+ function readAgentsMdTemplate(harnessRoot, log) {
5770
+ const flavor = log.templates.opencodeDir ? "opencode" : "codex";
5771
+ try {
5772
+ return readFileSync15(join16(harnessRoot, "templates", flavor, "AGENTS.md.template"), "utf8");
5773
+ } catch {
5774
+ return null;
5775
+ }
5776
+ }
5777
+ function agentsMdRemainder(current, harnessRoot, log) {
5778
+ const template = readAgentsMdTemplate(harnessRoot, log);
5779
+ if (template === null) return { ok: false };
5780
+ return { ok: true, remainder: stripHarnessFromAgentsMd({ existing: current, template }) };
5781
+ }
5782
+ function removeExternalFiles(log, projectDir, rm, harnessRoot) {
5719
5783
  const removed = [];
5720
5784
  const kept = [];
5785
+ const stripped = [];
5786
+ const unjudged = [];
5721
5787
  for (const { path, sha256 } of log.externalFiles ?? []) {
5722
5788
  const abs = join16(projectDir, path);
5723
5789
  if (!existsSync17(abs)) continue;
5724
5790
  if (!lstatSync2(abs).isFile()) continue;
5725
- if (hashContent(readFileSync15(abs, "utf8")) !== sha256) {
5791
+ const current = readFileSync15(abs, "utf8");
5792
+ if (hashContent(current) !== sha256) {
5726
5793
  kept.push(path);
5727
5794
  continue;
5728
5795
  }
5796
+ if (path === AGENTS_MD) {
5797
+ const verdict = agentsMdRemainder(current, harnessRoot, log);
5798
+ if (!verdict.ok) {
5799
+ unjudged.push(path);
5800
+ continue;
5801
+ }
5802
+ if (verdict.remainder !== null) {
5803
+ try {
5804
+ writeFileSync7(abs, verdict.remainder, "utf8");
5805
+ stripped.push(path);
5806
+ } catch {
5807
+ unjudged.push(path);
5808
+ }
5809
+ continue;
5810
+ }
5811
+ }
5729
5812
  rm(abs);
5730
5813
  removed.push(path);
5731
5814
  }
5732
5815
  for (const path of removed) pruneEmptyDirsUpward(projectDir, dirname5(join16(projectDir, path)));
5733
- return { removed, kept };
5816
+ return { removed, kept, stripped, unjudged };
5734
5817
  }
5735
5818
  function pruneEmptyDirsUpward(projectDir, startDir) {
5736
5819
  let cursor = startDir;
@@ -5757,16 +5840,28 @@ function stripRootImport(projectDir) {
5757
5840
  return false;
5758
5841
  }
5759
5842
  }
5760
- function previewExternalLines(installLog, projectDir) {
5843
+ function previewExternalLines(installLog, projectDir, harnessRoot) {
5761
5844
  const lines = [];
5762
5845
  let removable = 0;
5763
5846
  for (const { path, sha256 } of installLog.externalFiles ?? []) {
5764
5847
  const abs = join16(projectDir, path);
5765
5848
  if (!existsSync17(abs)) continue;
5766
- if (hashContent(readFileSync15(abs, "utf8")) !== sha256) {
5849
+ const current = readFileSync15(abs, "utf8");
5850
+ if (hashContent(current) !== sha256) {
5767
5851
  lines.push(` \u25CB keep ${path} (modified since install \u2014 preserved)`);
5768
5852
  continue;
5769
5853
  }
5854
+ if (path === AGENTS_MD) {
5855
+ const verdict = agentsMdRemainder(current, harnessRoot, installLog);
5856
+ if (!verdict.ok) {
5857
+ lines.push(` \u25CB keep ${path} (harness sections could not be separated \u2014 preserved)`);
5858
+ continue;
5859
+ }
5860
+ if (verdict.remainder !== null) {
5861
+ lines.push(` \u25CB strip harness sections from ${path} (\uBCF8\uBB38 \uBCF4\uC874)`);
5862
+ continue;
5863
+ }
5864
+ }
5770
5865
  removable += 1;
5771
5866
  }
5772
5867
  if (removable > 0) lines.unshift(` \u25CB remove ${removable} CLI output file(s)`);
@@ -5777,6 +5872,14 @@ function externalRemovalLines(external) {
5777
5872
  if (external.removed.length > 0) {
5778
5873
  lines.push(` ${status.success(`CLI outputs removed: ${external.removed.length} file(s)`)}`);
5779
5874
  }
5875
+ for (const path of external.stripped) {
5876
+ lines.push(` ${status.success(`${path} \u2014 harness sections removed (\uBCF8\uBB38 \uBCF4\uC874)`)}`);
5877
+ }
5878
+ for (const path of external.unjudged) {
5879
+ lines.push(
5880
+ ` ${c.yellow("\u2298")} ${path} kept \u2014 harness sections could not be separated (template unreadable or write failed). Remove manually if intended.`
5881
+ );
5882
+ }
5780
5883
  for (const path of external.kept) {
5781
5884
  lines.push(
5782
5885
  ` ${c.yellow("\u2298")} ${path} kept \u2014 modified since install. Remove manually if intended.`