@uzysjung/agent-harness 26.148.1 → 26.150.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.
@@ -287,6 +287,36 @@ var EXTERNAL_ASSETS = [
287
287
  condition: { kind: "any-track", tracks: [...TRACKS] },
288
288
  method: { kind: "internal", key: "audit-harness-fit" }
289
289
  },
290
+ {
291
+ // CI 가 멈췄을 때(결제 실패·쿼터 소진·Actions 장애) 검증을 포기하지도, 위조하지도 않는 절차.
292
+ // has-dev-track 인 이유: 이건 **누가 요청해서 켜는 것이 아니라 사고가 났을 때 켜지는** 것이다.
293
+ // CI 가 죽고 나서야 필요해지는 자산을 opt-in 으로 두면, 정작 그 순간에 없다. 대신 executive
294
+ // 트랙에는 깔지 않는다 — 거기엔 워크플로가 없다.
295
+ // DEV_METHOD_SKILL_IDS 에 넣지 않는 이유: 저건 wizard 의 "하네스 방법론 N종" 묶음이고,
296
+ // 이건 방법론이 아니라 사고 대응 런북이다. 묶음에 끼면 묶음의 뜻이 흐려진다.
297
+ id: "self-hosted-github-runner",
298
+ tier: "official",
299
+ // uzys 자사 스킬
300
+ description: "Self-hosted GitHub runner \u2014 when hosted runners stop (billing failure, spending limit, minutes exhausted, org quota, Actions outage), run the repo's existing workflow files unchanged on a Docker self-hosted runner instead of copying CI steps into a local script; covers runner-label switching, architecture and cache-key traps, container isolation, the risk that pull_request jobs then execute on your own machine, and the rollback path",
301
+ category: "dev-tools",
302
+ source: "uzys",
303
+ condition: { kind: "has-dev-track" },
304
+ method: { kind: "internal", key: "self-hosted-github-runner" }
305
+ },
306
+ {
307
+ // 트랙과 무관한 글쓰기 규율이라 어느 트랙에서도 고를 수 있고, 어느 트랙에도 자동으로는
308
+ // 안 깔린다(opt-in). 한국어로 쓰지 않는 사용자에게 기본 설치되면 그대로 낭비다.
309
+ // clear-korean-communication 과의 경계: 저쪽은 **무엇을 어떤 형식으로 말할지**(설명·승인
310
+ // 요청의 구조)이고, 이쪽은 **이미 쓴 글의 문체**를 진단해 최소 수정한다.
311
+ id: "humanize-korean",
312
+ tier: "official",
313
+ // uzys 자사 스킬
314
+ description: "Humanize Korean \u2014 diagnose what actually reads as translationese, AI clich\xE9, or mechanical structure in Korean prose, then fix only what the diagnosis justifies, preserving facts, numbers, terminology and register (opt-in). References epoko77-ai/im-not-ai",
315
+ category: "workflow",
316
+ source: "uzys",
317
+ condition: { kind: "opt-in" },
318
+ method: { kind: "internal", key: "humanize-korean" }
319
+ },
290
320
  // === Option-gated (v26.42.0 — opt-in, BREAKING vs prior has-dev-track auto-install) ===
291
321
  {
292
322
  id: "addy-agent-skills",
@@ -999,7 +1029,9 @@ var INTERNAL_BUNDLED_SKILL_IDS = [
999
1029
  "task-brief",
1000
1030
  "audit-harness-fit",
1001
1031
  "model-orchestration",
1002
- "external-model-consult"
1032
+ "external-model-consult",
1033
+ "self-hosted-github-runner",
1034
+ "humanize-korean"
1003
1035
  ];
1004
1036
  var TRUST_TIER = Object.fromEntries(
1005
1037
  EXTERNAL_ASSETS.map((a) => [a.id, a.tier])
@@ -1440,12 +1472,21 @@ var FILL_SPECS = {
1440
1472
  placeholder: "the single command that proves a change is safe, and the done bar"
1441
1473
  }
1442
1474
  };
1443
- var SCAFFOLD_BANNER = [
1444
- "> \u2699\uFE0F **SCAFFOLD \u2014 not filled in yet.** The sections below are a fill-in template for THIS project, not verified facts.",
1445
- "> To fill: open this file and paste each `<!-- FILL: \u2026 -->` comment's instruction into your coding agent (e.g. Claude Code) \u2014 it will inspect the real repo and write the section. You can also fill them by hand; the comments are the instructions.",
1446
- `> The working principles live in this project's harness anchor \u2014 \`${HARNESS_ANCHOR_FILE}\` (Claude Code, imported from this file), \`AGENTS.md\` (Codex/OpenCode), or \`.agents/rules/uzys-harness.md\` (Antigravity). This file is **project-specific context only**.`
1447
- ].join("\n");
1448
- function renderFillScaffold() {
1475
+ function anchorLine(surface) {
1476
+ if (surface === "claude") {
1477
+ return `> The working principles live in this project's harness anchor \`${HARNESS_ANCHOR_FILE}\`, imported at the bottom of this file. Everything above that import is **project-specific context only**.`;
1478
+ }
1479
+ const self = surface === "antigravity-rule" ? "`.agents/rules/uzys-harness.md`" : "`AGENTS.md`";
1480
+ return `> **This file (${self}) is the harness anchor** \u2014 it carries the working principles in full, further down. Only the \`## \u2026\` sections immediately below are project-specific context for you to fill in.`;
1481
+ }
1482
+ function scaffoldBanner(surface) {
1483
+ return [
1484
+ "> \u2699\uFE0F **SCAFFOLD \u2014 not filled in yet.** The sections below are a fill-in template for THIS project, not verified facts.",
1485
+ "> To fill: open this file and paste each `<!-- FILL: \u2026 -->` comment's instruction into your coding agent (e.g. Claude Code) \u2014 it will inspect the real repo and write the section. You can also fill them by hand; the comments are the instructions.",
1486
+ anchorLine(surface)
1487
+ ].join("\n");
1488
+ }
1489
+ function renderFillScaffold(surface = "claude") {
1449
1490
  const blocks = FILL_SECTIONS.map((id) => {
1450
1491
  const spec = FILL_SPECS[id];
1451
1492
  return `## ${spec.title}
@@ -1454,7 +1495,7 @@ function renderFillScaffold() {
1454
1495
 
1455
1496
  _(not filled yet \u2014 ${spec.placeholder})_`;
1456
1497
  });
1457
- return `${SCAFFOLD_BANNER}
1498
+ return `${scaffoldBanner(surface)}
1458
1499
 
1459
1500
  ${blocks.join("\n\n")}`;
1460
1501
  }
@@ -1513,6 +1554,17 @@ function expandTracks(tracks) {
1513
1554
  }
1514
1555
 
1515
1556
  // src/manifest.ts
1557
+ function buildAssetSpec(ctx) {
1558
+ return {
1559
+ tracks: ctx.tracks,
1560
+ withTauri: isAssetSelected("tauri-desktop", ctx),
1561
+ // v26.55.0 — withEcc gating (ADR-016). withPrune 은 ecc-plugin 사용을 전제한다.
1562
+ withEcc: isAssetSelected("ecc-plugin", ctx) || ctx.options.withPrune === true,
1563
+ // v26.87.0 — internal bundled skills (dev-method + opt-in advisors, v26.95.0). id 별 condition
1564
+ // (has-dev-track vs opt-in)은 isAssetSelected 가 적용한다.
1565
+ selectedInternalSkills: INTERNAL_BUNDLED_SKILL_IDS.filter((id) => isAssetSelected(id, ctx))
1566
+ };
1567
+ }
1516
1568
  var all = () => true;
1517
1569
  var dev = (s) => hasDevTrack(s.tracks);
1518
1570
  var ui = (s) => hasUiTrack(s.tracks);
@@ -1670,9 +1722,9 @@ function buildManifest(spec) {
1670
1722
  });
1671
1723
  }
1672
1724
  m.push({
1673
- source: "skills/spec-scaling/SKILL.md",
1674
- target: ".claude/skills/spec-scaling/SKILL.md",
1675
- type: "file",
1725
+ source: "skills/spec-scaling",
1726
+ target: ".claude/skills/spec-scaling",
1727
+ type: "dir",
1676
1728
  applies: all
1677
1729
  });
1678
1730
  for (const sd of ["market-research", "investor-materials", "investor-outreach"]) {
@@ -1832,6 +1884,21 @@ function assetCostRows(assetIds, root = resolveBundleRoot()) {
1832
1884
  bodyTokens: assetBodyTokens(id, root)
1833
1885
  })).sort((a, b) => (b.bodyTokens ?? -1) - (a.bodyTokens ?? -1));
1834
1886
  }
1887
+ function makeResidentCost(base) {
1888
+ return {
1889
+ ...base,
1890
+ perSkillDescriptor: base.perSkillDescriptor ?? {},
1891
+ total: base.rules + base.projectClaudeMd + base.skillDescriptors + base.agentDescriptors,
1892
+ directive: {
1893
+ items: base.items.rules + base.items.claudeMd,
1894
+ tokens: base.rules + base.projectClaudeMd
1895
+ },
1896
+ firing: {
1897
+ items: base.items.skills + base.items.agents,
1898
+ tokens: base.skillDescriptors + base.agentDescriptors
1899
+ }
1900
+ };
1901
+ }
1835
1902
  function fileTokens(path2) {
1836
1903
  return existsSync3(path2) ? estimateTokens(readFileSync3(path2, "utf8").trim().length) : 0;
1837
1904
  }
@@ -1842,6 +1909,7 @@ function descriptorTokens(path2) {
1842
1909
  }
1843
1910
  function residentCost(entries, root = resolveBundleRoot()) {
1844
1911
  const tpl = (source) => join3(root, "templates", source);
1912
+ const perSkill = {};
1845
1913
  let rules = 0;
1846
1914
  let skillDescriptors = 0;
1847
1915
  let agentDescriptors = 0;
@@ -1856,20 +1924,23 @@ function residentCost(entries, root = resolveBundleRoot()) {
1856
1924
  agentDescriptors += descriptorTokens(tpl(e.source));
1857
1925
  agentItems += 1;
1858
1926
  } else if (e.target.startsWith(".claude/skills/")) {
1859
- skillDescriptors += descriptorTokens(join3(tpl(e.source), "SKILL.md"));
1927
+ const t = descriptorTokens(join3(tpl(e.source), "SKILL.md"));
1928
+ skillDescriptors += t;
1860
1929
  skillItems += 1;
1930
+ const id = /\.claude\/skills\/([^/]+)/.exec(e.target)?.[1];
1931
+ if (id !== void 0) perSkill[id] = (perSkill[id] ?? 0) + t;
1861
1932
  }
1862
1933
  }
1863
1934
  const harnessAnchor = fileTokens(join3(root, "templates", "CLAUDE.md"));
1864
1935
  const projectScaffold = estimateTokens(renderFillScaffold().trim().length);
1865
1936
  const projectClaudeMd = harnessAnchor + projectScaffold;
1866
1937
  const claudeMdItems = (harnessAnchor > 0 ? 1 : 0) + (projectScaffold > 0 ? 1 : 0);
1867
- return {
1938
+ return makeResidentCost({
1868
1939
  rules,
1869
1940
  projectClaudeMd,
1870
1941
  skillDescriptors,
1871
1942
  agentDescriptors,
1872
- total: rules + projectClaudeMd + skillDescriptors + agentDescriptors,
1943
+ perSkillDescriptor: perSkill,
1873
1944
  items: {
1874
1945
  rules: ruleItems,
1875
1946
  skills: skillItems,
@@ -1877,7 +1948,7 @@ function residentCost(entries, root = resolveBundleRoot()) {
1877
1948
  claudeMd: claudeMdItems,
1878
1949
  total: ruleItems + skillItems + agentItems + claudeMdItems
1879
1950
  }
1880
- };
1951
+ });
1881
1952
  }
1882
1953
  function summarizeContextCost(assetIds, root = resolveBundleRoot()) {
1883
1954
  let measuredTokens = 0;
@@ -1896,33 +1967,47 @@ function summarizeContextCost(assetIds, root = resolveBundleRoot()) {
1896
1967
  function formatResidentCostLine(r, unmeasuredCount) {
1897
1968
  if (r.total === 0) return null;
1898
1969
  const parts = [
1899
- `rules ${r.items.rules} ~${r.rules}`,
1900
- `CLAUDE.md ${r.items.claudeMd} ~${r.projectClaudeMd}`,
1901
- `skills ${r.items.skills} ~${r.skillDescriptors}`,
1902
- `agents ${r.items.agents} ~${r.agentDescriptors}`
1970
+ `directives ${r.directive.items} ~${r.directive.tokens}`,
1971
+ `[rules ${r.items.rules} ~${r.rules} \xB7 CLAUDE.md ${r.items.claudeMd} ~${r.projectClaudeMd}]`,
1972
+ `triggers ${r.firing.items} ~${r.firing.tokens}`,
1973
+ `[skills ${r.items.skills} ~${r.skillDescriptors} \xB7 agents ${r.items.agents} ~${r.agentDescriptors}]`
1903
1974
  ].join(" \xB7 ");
1904
1975
  const external = unmeasuredCount > 0 ? ` \xB7 ${unmeasuredCount} external asset${unmeasuredCount === 1 ? "" : "s"} unmeasured` : "";
1905
1976
  return `session-start context cost: ${r.items.total} items resident \xB7 ~${r.total} tokens/session (${parts}${external})`;
1906
1977
  }
1907
1978
  var RESIDENT_ROWS = [
1908
- { label: "rules", gap: 14, count: (r) => r.items.rules, tokens: (r) => r.rules },
1979
+ {
1980
+ // ADR-083 — 축 소계를 **행으로** 낸다. 소계가 없으면 읽는 사람이 네 줄을 머리로 더해야
1981
+ // 하고, 그러면 "무엇을 줄여야 하나"가 표에서 안 보인다.
1982
+ label: "\uC9C0\uC2DC\uBB38",
1983
+ gap: 13,
1984
+ count: (r) => r.directive.items,
1985
+ tokens: (r) => r.directive.tokens
1986
+ },
1987
+ { label: " rules", gap: 12, count: (r) => r.items.rules, tokens: (r) => r.rules },
1909
1988
  {
1910
1989
  // 한 행에 두 파일(앵커 + 스캐폴드). 개수 열이 2 를 뱉어 그 사실을 드러낸다 — 라벨로
1911
1990
  // 하나만 이름 붙이면 v26.140.0 이전과 같은 거짓 라벨이 된다.
1912
- label: "CLAUDE.md",
1913
- gap: 11,
1991
+ label: " CLAUDE.md",
1992
+ gap: 8,
1914
1993
  count: (r) => r.items.claudeMd,
1915
1994
  tokens: (r) => r.projectClaudeMd
1916
1995
  },
1917
1996
  {
1918
- label: "skill descriptors",
1919
- gap: 2,
1997
+ label: "\uBC1C\uD654 \uD45C\uBA74",
1998
+ gap: 10,
1999
+ count: (r) => r.firing.items,
2000
+ tokens: (r) => r.firing.tokens
2001
+ },
2002
+ {
2003
+ label: " skill descriptors",
2004
+ gap: 0,
1920
2005
  count: (r) => r.items.skills,
1921
2006
  tokens: (r) => r.skillDescriptors
1922
2007
  },
1923
2008
  {
1924
- label: "agent descriptors",
1925
- gap: 2,
2009
+ label: " agent descriptors",
2010
+ gap: 0,
1926
2011
  count: (r) => r.items.agents,
1927
2012
  tokens: (r) => r.agentDescriptors
1928
2013
  }
@@ -1935,7 +2020,11 @@ function formatResidentCostBlock(r) {
1935
2020
  (row) => ` ${row.label}${" ".repeat(row.gap)}${n(row.count(r))}\uAC1C ~${row.tokens(r)}`
1936
2021
  ),
1937
2022
  " \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
1938
- ` \uC0C1\uC8FC \uD569\uACC4 ${n(r.items.total)}\uAC1C \uC0C1\uC8FC \xB7 ~${r.total} tokens/\uC138\uC158`
2023
+ ` \uC0C1\uC8FC \uD569\uACC4 ${n(r.items.total)}\uAC1C \uC0C1\uC8FC \xB7 ~${r.total} tokens/\uC138\uC158`,
2024
+ "",
2025
+ " \uC9C0\uC2DC\uBB38 = \uC6B0\uB9AC\uAC00 \uD56D\uC0C1 \uC77D\uD788\uAC8C \uB123\uC740 \uAC83. **\uC791\uC744\uC218\uB85D \uC88B\uC740 \uAC12\uC774 \uC544\uB2C8\uB2E4** \u2014 \uD310\uB2E8\uC740",
2026
+ " '\uBD88\uD544\uC694\uD55C \uC9C0\uC2DC\uBB38\uC774 \uC788\uB098'\uB85C \uD55C\uB2E4. ratchet \uC740 \uC870\uC6A9\uD55C \uC99D\uAC00\uB9CC \uB9C9\uB294\uB2E4.",
2027
+ " \uBC1C\uD654 \uD45C\uBA74 = \uC2A4\uD0AC\xB7\uC5D0\uC774\uC804\uD2B8\uAC00 \uBD88\uB9AC\uB824\uACE0 \uC0C1\uC8FC\uC2DC\uD0A4\uB294 descriptor. \uAE4E\uC73C\uBA74 \uC548 \uBD88\uB9B0\uB2E4."
1939
2028
  ];
1940
2029
  }
1941
2030
 
@@ -1988,6 +2077,7 @@ export {
1988
2077
  renderFillScaffold,
1989
2078
  upsertHarnessImport,
1990
2079
  stripHarnessImport,
2080
+ buildAssetSpec,
1991
2081
  resolveRules,
1992
2082
  ALL_RULES,
1993
2083
  isCliNeutralTarget,
@@ -2002,4 +2092,4 @@ export {
2002
2092
  formatResidentCostLine,
2003
2093
  formatResidentCostBlock
2004
2094
  };
2005
- //# sourceMappingURL=chunk-PTUM2NI3.js.map
2095
+ //# sourceMappingURL=chunk-NKBUDHPC.js.map