@uzysjung/agent-harness 26.158.0 → 26.160.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.
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/dist/{chunk-HHCNPPGS.js → chunk-ZXWOY5VO.js} +59 -291
- package/dist/chunk-ZXWOY5VO.js.map +1 -0
- package/dist/index.js +177 -51
- package/dist/index.js.map +1 -1
- package/dist/trust-tier-drift.js +1 -1
- package/package.json +1 -2
- package/templates/agents/strategist.md +10 -0
- package/dist/chunk-HHCNPPGS.js.map +0 -1
- package/scripts/prune-ecc.sh +0 -310
- package/templates/skills/e2e-testing/SKILL.md +0 -326
- package/templates/skills/e2e-testing/agents/openai.yaml +0 -7
- package/templates/skills/investor-materials/SKILL.md +0 -96
- package/templates/skills/investor-outreach/SKILL.md +0 -91
- package/templates/skills/market-research/SKILL.md +0 -75
- package/templates/skills/market-research/agents/openai.yaml +0 -7
- package/templates/skills/nextjs-turbopack/SKILL.md +0 -44
- package/templates/skills/python-patterns/SKILL.md +0 -750
- package/templates/skills/python-testing/SKILL.md +0 -816
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
CATEGORY_TITLES,
|
|
6
6
|
CLI_BASES,
|
|
7
7
|
CONTINUOUS_SKILLS,
|
|
8
|
+
CONTINUOUS_SKILLS_HEADING,
|
|
8
9
|
DEFAULT_OPTIONS,
|
|
9
10
|
EXTERNAL_ASSETS,
|
|
10
11
|
HARNESS_ANCHOR_FILE,
|
|
@@ -57,6 +58,7 @@ import {
|
|
|
57
58
|
listFilesRecursive,
|
|
58
59
|
mergeExternalFiles,
|
|
59
60
|
readInstallLog,
|
|
61
|
+
renderContinuousSkillsNote,
|
|
60
62
|
renderFillScaffold,
|
|
61
63
|
residentCost,
|
|
62
64
|
resolveBundleRoot,
|
|
@@ -67,7 +69,7 @@ import {
|
|
|
67
69
|
upsertHarnessImport,
|
|
68
70
|
withContinuousSkillsNote,
|
|
69
71
|
writeInstallLog
|
|
70
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-ZXWOY5VO.js";
|
|
71
73
|
|
|
72
74
|
// node_modules/sisteransi/src/index.js
|
|
73
75
|
var require_src = __commonJS({
|
|
@@ -752,7 +754,7 @@ var cac = (name = "") => new CAC(name);
|
|
|
752
754
|
// package.json
|
|
753
755
|
var package_default = {
|
|
754
756
|
name: "@uzysjung/agent-harness",
|
|
755
|
-
version: "26.
|
|
757
|
+
version: "26.160.0",
|
|
756
758
|
description: "Curate vetted AI-coding skills & plugins by your tech stack \u2014 install only what you need, across Claude Code, Codex, OpenCode & Antigravity",
|
|
757
759
|
type: "module",
|
|
758
760
|
publishConfig: {
|
|
@@ -767,7 +769,6 @@ var package_default = {
|
|
|
767
769
|
files: [
|
|
768
770
|
"dist",
|
|
769
771
|
"templates",
|
|
770
|
-
"scripts/prune-ecc.sh",
|
|
771
772
|
"README.md",
|
|
772
773
|
"LICENSE"
|
|
773
774
|
],
|
|
@@ -1085,11 +1086,137 @@ import { basename, join as join6 } from "path";
|
|
|
1085
1086
|
|
|
1086
1087
|
// src/codex/agents-md.ts
|
|
1087
1088
|
init_esm_shims();
|
|
1089
|
+
|
|
1090
|
+
// src/agents-md-merge.ts
|
|
1091
|
+
init_esm_shims();
|
|
1092
|
+
var marker = (name) => ({
|
|
1093
|
+
start: `<!-- uzys-harness:${name}:start -->`,
|
|
1094
|
+
end: `<!-- uzys-harness:${name}:end -->`
|
|
1095
|
+
});
|
|
1096
|
+
var ANCHOR_BLOCK = marker("anchor");
|
|
1097
|
+
var SKILLS_BLOCK = marker("skills");
|
|
1098
|
+
var CONTEXT_SECTION = "Project Context";
|
|
1099
|
+
var RULES_SECTION = "Project Rules";
|
|
1100
|
+
function wrapHarnessBlock(m, body) {
|
|
1101
|
+
return `${m.start}
|
|
1102
|
+
${body}
|
|
1103
|
+
${m.end}`;
|
|
1104
|
+
}
|
|
1105
|
+
function withMarkedContinuousSkillsNote(scaffold, selectedInternalSkills) {
|
|
1106
|
+
const note = renderContinuousSkillsNote(selectedInternalSkills);
|
|
1107
|
+
return note ? `${scaffold}
|
|
1108
|
+
|
|
1109
|
+
${wrapHarnessBlock(SKILLS_BLOCK, note)}` : scaffold;
|
|
1110
|
+
}
|
|
1111
|
+
function sectionNames(template) {
|
|
1112
|
+
return new Set([...template.matchAll(/^## (.+)$/gm)].map((m) => (m[1] ?? "").trim()));
|
|
1113
|
+
}
|
|
1114
|
+
function headingName(line, names) {
|
|
1115
|
+
const name = /^## (.+?)\s*$/.exec(line.replace(/\r$/, ""))?.[1];
|
|
1116
|
+
return name !== void 0 && names.has(name) ? name : null;
|
|
1117
|
+
}
|
|
1118
|
+
function sectionBody(text, names, want) {
|
|
1119
|
+
const lines = text.split("\n");
|
|
1120
|
+
let start = -1;
|
|
1121
|
+
for (const [i, line] of lines.entries()) {
|
|
1122
|
+
const name = headingName(line, names);
|
|
1123
|
+
if (name === null) continue;
|
|
1124
|
+
if (start === -1) {
|
|
1125
|
+
if (name === want) start = i;
|
|
1126
|
+
} else {
|
|
1127
|
+
return lines.slice(start + 1, i);
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
return start === -1 ? null : lines.slice(start + 1);
|
|
1131
|
+
}
|
|
1132
|
+
function assemble(rendered, names, bodies) {
|
|
1133
|
+
const out = [];
|
|
1134
|
+
let replacing = false;
|
|
1135
|
+
for (const line of rendered.split("\n")) {
|
|
1136
|
+
const name = headingName(line, names);
|
|
1137
|
+
if (name !== null) {
|
|
1138
|
+
out.push(line);
|
|
1139
|
+
const override = bodies.get(name);
|
|
1140
|
+
replacing = override !== void 0;
|
|
1141
|
+
if (override !== void 0) out.push(...override);
|
|
1142
|
+
continue;
|
|
1143
|
+
}
|
|
1144
|
+
if (!replacing) out.push(line);
|
|
1145
|
+
}
|
|
1146
|
+
return out.join("\n");
|
|
1147
|
+
}
|
|
1148
|
+
function blockRange(lines, m) {
|
|
1149
|
+
const start = lines.findIndex((l) => l.trim() === m.start);
|
|
1150
|
+
if (start === -1) return null;
|
|
1151
|
+
const end = lines.findIndex((l, i) => i > start && l.trim() === m.end);
|
|
1152
|
+
return end === -1 ? null : [start, end];
|
|
1153
|
+
}
|
|
1154
|
+
function trimTrailingBlanks(lines) {
|
|
1155
|
+
const out = [...lines];
|
|
1156
|
+
while (out.length > 0 && (out.at(-1) ?? "").trim() === "") out.pop();
|
|
1157
|
+
return out;
|
|
1158
|
+
}
|
|
1159
|
+
function refreshBlock(existing, rendered, m, legacyHeading) {
|
|
1160
|
+
const at2 = blockRange(rendered, m);
|
|
1161
|
+
const fresh = at2 === null ? null : rendered.slice(at2[0], at2[1] + 1);
|
|
1162
|
+
const here = blockRange(existing, m);
|
|
1163
|
+
if (here !== null) {
|
|
1164
|
+
const head2 = existing.slice(0, here[0]);
|
|
1165
|
+
const tail2 = existing.slice(here[1] + 1);
|
|
1166
|
+
if (fresh === null) {
|
|
1167
|
+
const kept = trimTrailingBlanks(head2);
|
|
1168
|
+
return tail2.length > 0 ? [...kept, ...tail2] : [...kept, ""];
|
|
1169
|
+
}
|
|
1170
|
+
return [...head2, ...fresh, ...tail2];
|
|
1171
|
+
}
|
|
1172
|
+
const legacyAt = legacyHeading === void 0 ? -1 : existing.findIndex((l) => l.replace(/\r$/, "").trim() === legacyHeading);
|
|
1173
|
+
if (legacyAt === -1) {
|
|
1174
|
+
const kept = trimTrailingBlanks(existing);
|
|
1175
|
+
return fresh === null ? [...kept, ""] : [...kept, "", ...fresh, ""];
|
|
1176
|
+
}
|
|
1177
|
+
const head = trimTrailingBlanks(existing.slice(0, legacyAt));
|
|
1178
|
+
const tail = existing.slice(legacyNoteEnd(existing, legacyAt));
|
|
1179
|
+
while (tail.length > 0 && (tail[0] ?? "").trim() === "") tail.shift();
|
|
1180
|
+
const body = fresh === null ? [...head] : [...head, "", ...fresh];
|
|
1181
|
+
return tail.length > 0 ? [...body, "", ...tail] : [...body, ""];
|
|
1182
|
+
}
|
|
1183
|
+
function legacyNoteEnd(lines, headingAt) {
|
|
1184
|
+
let i = headingAt + 1;
|
|
1185
|
+
while (i < lines.length) {
|
|
1186
|
+
const l = (lines[i] ?? "").replace(/\r$/, "").trim();
|
|
1187
|
+
const isNote = l === "" || l.startsWith("- `") || l.startsWith("These installed skills apply");
|
|
1188
|
+
if (!isNote) break;
|
|
1189
|
+
i++;
|
|
1190
|
+
}
|
|
1191
|
+
return i;
|
|
1192
|
+
}
|
|
1193
|
+
function mergeAgentsMd(params) {
|
|
1194
|
+
const { rendered, existing, template } = params;
|
|
1195
|
+
if (existing === null) return rendered;
|
|
1196
|
+
const names = sectionNames(template);
|
|
1197
|
+
const bodies = /* @__PURE__ */ new Map();
|
|
1198
|
+
const contextNow = sectionBody(existing, names, CONTEXT_SECTION);
|
|
1199
|
+
const contextNew = sectionBody(rendered, names, CONTEXT_SECTION);
|
|
1200
|
+
if (contextNow !== null && contextNew !== null) {
|
|
1201
|
+
bodies.set(
|
|
1202
|
+
CONTEXT_SECTION,
|
|
1203
|
+
refreshBlock(contextNow, contextNew, SKILLS_BLOCK, CONTINUOUS_SKILLS_HEADING)
|
|
1204
|
+
);
|
|
1205
|
+
}
|
|
1206
|
+
const rulesNow = sectionBody(existing, names, RULES_SECTION);
|
|
1207
|
+
const rulesNew = sectionBody(rendered, names, RULES_SECTION);
|
|
1208
|
+
if (rulesNow !== null && rulesNew !== null && blockRange(rulesNow, ANCHOR_BLOCK) !== null) {
|
|
1209
|
+
bodies.set(RULES_SECTION, refreshBlock(rulesNow, rulesNew, ANCHOR_BLOCK));
|
|
1210
|
+
}
|
|
1211
|
+
return bodies.size === 0 ? rendered : assemble(rendered, names, bodies);
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
// src/codex/agents-md.ts
|
|
1088
1215
|
function renameSlashes(text) {
|
|
1089
1216
|
return text.replaceAll("/uzys:", "/uzys-");
|
|
1090
1217
|
}
|
|
1091
1218
|
function renderAgentsMd(params) {
|
|
1092
|
-
const body = params.claudeMd.replace(/^#\s+.*\r?\n/, "").trim();
|
|
1219
|
+
const body = wrapHarnessBlock(ANCHOR_BLOCK, params.claudeMd.replace(/^#\s+.*\r?\n/, "").trim());
|
|
1093
1220
|
const replaced = params.template.replaceAll("{PROJECT_NAME}", params.projectName).replaceAll("{PROJECT_RULES}", body).replaceAll("{PROJECT_CONTEXT}", params.projectContext).replaceAll("{HARNESS_RULES}", params.harnessRules ?? "");
|
|
1094
1221
|
return renameSlashes(replaced);
|
|
1095
1222
|
}
|
|
@@ -1313,7 +1440,8 @@ function writeRules(harnessRoot, projectDir, writer, selectedInternalSkills) {
|
|
|
1313
1440
|
selectedInternalSkills
|
|
1314
1441
|
)
|
|
1315
1442
|
});
|
|
1316
|
-
|
|
1443
|
+
const withoutMarkers = rulesOut.split("\n").filter((l) => !/^<!-- uzys-harness:(?:anchor|skills):(?:start|end) -->$/.test(l.trim())).join("\n");
|
|
1444
|
+
return writer.write(target, withoutMarkers) ? target : null;
|
|
1317
1445
|
}
|
|
1318
1446
|
|
|
1319
1447
|
// src/codex/opt-in.ts
|
|
@@ -1458,14 +1586,22 @@ function runCodexTransform(params) {
|
|
|
1458
1586
|
claudeMd,
|
|
1459
1587
|
projectName,
|
|
1460
1588
|
// ADR-085 — 상시 스킬 안내는 앵커가 아니라 여기(프로젝트 맥락)에, 깔린 것만.
|
|
1461
|
-
|
|
1589
|
+
// #503 — 그 조각은 설치자 소유 절 안에 사니 마커로 감싼다.
|
|
1590
|
+
projectContext: withMarkedContinuousSkillsNote(
|
|
1462
1591
|
renderFillScaffold("agents-md"),
|
|
1463
1592
|
selectedInternalSkills
|
|
1464
1593
|
),
|
|
1465
1594
|
// Codex 는 룰 디렉터리가 없다 — 룰이 AGENTS.md 본문에 들어가야 도달한다(§Harness Rules).
|
|
1466
1595
|
harnessRules: renderRulesBlock(portRules(harnessRoot, rules))
|
|
1467
1596
|
});
|
|
1468
|
-
writer.write(
|
|
1597
|
+
writer.write(
|
|
1598
|
+
agentsMdPath,
|
|
1599
|
+
mergeAgentsMd({
|
|
1600
|
+
rendered: agentsMdOut,
|
|
1601
|
+
existing: existsSync8(agentsMdPath) ? readFileSync7(agentsMdPath, "utf8") : null,
|
|
1602
|
+
template: agentsTemplate
|
|
1603
|
+
})
|
|
1604
|
+
);
|
|
1469
1605
|
const configTomlPath = join8(projectDir, ".codex/config.toml");
|
|
1470
1606
|
writer.write(
|
|
1471
1607
|
configTomlPath,
|
|
@@ -1531,7 +1667,7 @@ function renameSlashes2(text) {
|
|
|
1531
1667
|
return text.replaceAll("/uzys:", "/uzys-");
|
|
1532
1668
|
}
|
|
1533
1669
|
function renderAgentsMd2(params) {
|
|
1534
|
-
const body = params.claudeMd.replace(/^#\s+.*\r?\n/, "").trim();
|
|
1670
|
+
const body = wrapHarnessBlock(ANCHOR_BLOCK, params.claudeMd.replace(/^#\s+.*\r?\n/, "").trim());
|
|
1535
1671
|
const replaced = params.template.replaceAll("{PROJECT_NAME}", params.projectName).replaceAll("{PROJECT_RULES}", body).replaceAll("{PROJECT_CONTEXT}", params.projectContext).replaceAll("{HARNESS_RULES}", params.harnessRules ?? "");
|
|
1536
1672
|
return renameSlashes2(replaced);
|
|
1537
1673
|
}
|
|
@@ -1580,7 +1716,8 @@ function runOpencodeTransform(params) {
|
|
|
1580
1716
|
claudeMd,
|
|
1581
1717
|
projectName,
|
|
1582
1718
|
// ADR-085 — 상시 스킬 안내는 앵커가 아니라 여기(프로젝트 맥락)에, 깔린 것만.
|
|
1583
|
-
|
|
1719
|
+
// #503 — 그 조각은 설치자 소유 절 안에 사니 마커로 감싼다 (codex 와 같은 마커).
|
|
1720
|
+
projectContext: withMarkedContinuousSkillsNote(
|
|
1584
1721
|
renderFillScaffold("agents-md"),
|
|
1585
1722
|
selectedInternalSkills
|
|
1586
1723
|
),
|
|
@@ -1589,7 +1726,14 @@ function runOpencodeTransform(params) {
|
|
|
1589
1726
|
// (독립 검증 C-1 실측). 같은 내용을 쓰면 순서가 결과를 바꾸지 않는다.
|
|
1590
1727
|
harnessRules: renderRulesBlock(portRules(harnessRoot, rules))
|
|
1591
1728
|
});
|
|
1592
|
-
writer.write(
|
|
1729
|
+
writer.write(
|
|
1730
|
+
agentsMdPath,
|
|
1731
|
+
mergeAgentsMd({
|
|
1732
|
+
rendered: agentsMdOut,
|
|
1733
|
+
existing: existsSync9(agentsMdPath) ? readFileSync8(agentsMdPath, "utf8") : null,
|
|
1734
|
+
template: agentsTemplate
|
|
1735
|
+
})
|
|
1736
|
+
);
|
|
1593
1737
|
const opencodeJsonPath = join9(projectDir, "opencode.json");
|
|
1594
1738
|
writer.write(opencodeJsonPath, renderOpencodeJson({ template: opencodeTemplate, mcp }));
|
|
1595
1739
|
const skillFiles = writeBundledSkillDirs({
|
|
@@ -1834,7 +1978,6 @@ function runExternalInstall(ctx, deps = {}) {
|
|
|
1834
1978
|
const warn = deps.warn ?? console.error;
|
|
1835
1979
|
const spawn = deps.spawn ?? defaultSpawn;
|
|
1836
1980
|
const assets = deps.assets ?? EXTERNAL_ASSETS;
|
|
1837
|
-
const harnessRoot = deps.harnessRoot ?? process.cwd();
|
|
1838
1981
|
const projectDir = ctx.projectDir ?? process.cwd();
|
|
1839
1982
|
const { targets: applicable, excludedByCli } = selectExternalTargets(assets, ctx);
|
|
1840
1983
|
const sorted = [...applicable].sort((a, b2) => {
|
|
@@ -1848,7 +1991,7 @@ function runExternalInstall(ctx, deps = {}) {
|
|
|
1848
1991
|
for (const asset of sorted) {
|
|
1849
1992
|
deps.onAssetStart?.(asset);
|
|
1850
1993
|
log(` \u2192 ${asset.description}`);
|
|
1851
|
-
const baseResult = installOne(asset, { spawn,
|
|
1994
|
+
const baseResult = installOne(asset, { spawn, cli: cli2, scope, projectDir });
|
|
1852
1995
|
let result = baseResult;
|
|
1853
1996
|
if (baseResult.ok) {
|
|
1854
1997
|
const v2 = detectVersion(asset.method, spawn);
|
|
@@ -1893,17 +2036,6 @@ function installOne(asset, ctx) {
|
|
|
1893
2036
|
[`${method.cmd}@${method.version}`, ...method.args ?? []],
|
|
1894
2037
|
cwd
|
|
1895
2038
|
);
|
|
1896
|
-
case "shell-script": {
|
|
1897
|
-
const scriptPath = join11(ctx.harnessRoot, method.script);
|
|
1898
|
-
if (!existsSync11(scriptPath)) {
|
|
1899
|
-
return {
|
|
1900
|
-
asset,
|
|
1901
|
-
ok: false,
|
|
1902
|
-
message: `script not found: ${scriptPath}`
|
|
1903
|
-
};
|
|
1904
|
-
}
|
|
1905
|
-
return runSpawn(asset, ctx.spawn, "bash", [scriptPath, ...method.args], cwd);
|
|
1906
|
-
}
|
|
1907
2039
|
case "internal":
|
|
1908
2040
|
return { asset, ok: true, message: "internal template (installed by Phase 1 manifest)" };
|
|
1909
2041
|
}
|
|
@@ -2379,11 +2511,13 @@ function installNewSkillDirs(projectDir, templatesDir, tracks) {
|
|
|
2379
2511
|
const foreignOwned = [];
|
|
2380
2512
|
const log = readInstallLog(projectDir);
|
|
2381
2513
|
const excluded = new Set(log?.spec.baselineExclude ?? []);
|
|
2514
|
+
const skillExcluded = new Set(log?.spec.skillExclude ?? []);
|
|
2382
2515
|
if (!(log?.spec.cli ?? ["claude"]).includes("claude")) return { installed, foreignOwned };
|
|
2383
2516
|
const spec = buildAssetSpec({ tracks, options: DEFAULT_OPTIONS });
|
|
2384
2517
|
for (const entry of buildManifest(spec)) {
|
|
2385
2518
|
if (entry.type !== "dir" || !entry.target.startsWith(".claude/skills/")) continue;
|
|
2386
2519
|
if (!entry.applies(spec) || isBaselineExcluded(entry.target, excluded)) continue;
|
|
2520
|
+
if (skillExcluded.has(entry.target.slice(".claude/skills/".length))) continue;
|
|
2387
2521
|
const target = join12(projectDir, entry.target);
|
|
2388
2522
|
const foreign = foreignOwnedTarget(projectDir, entry.target);
|
|
2389
2523
|
if (foreign !== null) {
|
|
@@ -2413,8 +2547,8 @@ function recordNewSkillBaseline(projectDir, templatesDir, targets) {
|
|
|
2413
2547
|
}
|
|
2414
2548
|
function trackOnlyFileAssets(tracks) {
|
|
2415
2549
|
const base = { tracks, selectedInternalSkills: [] };
|
|
2416
|
-
const optedOut = { ...base,
|
|
2417
|
-
const optedIn = { ...base,
|
|
2550
|
+
const optedOut = { ...base, withTauri: false };
|
|
2551
|
+
const optedIn = { ...base, withTauri: true };
|
|
2418
2552
|
return buildManifest(optedOut).filter(
|
|
2419
2553
|
(e2) => e2.type === "file" && e2.applies(optedOut) && e2.applies(optedIn)
|
|
2420
2554
|
);
|
|
@@ -2486,6 +2620,11 @@ function recordAnchorBaseline(projectDir, anchor) {
|
|
|
2486
2620
|
} catch {
|
|
2487
2621
|
}
|
|
2488
2622
|
}
|
|
2623
|
+
function installedBundledSkills(projectDir) {
|
|
2624
|
+
return INTERNAL_BUNDLED_SKILL_IDS.filter(
|
|
2625
|
+
(id) => existsSync13(join12(projectDir, ".claude/skills", id)) || existsSync13(join12(projectDir, ".agents/skills", id))
|
|
2626
|
+
);
|
|
2627
|
+
}
|
|
2489
2628
|
function refreshExternalCli(projectDir, harnessRoot) {
|
|
2490
2629
|
const log = readInstallLog(projectDir);
|
|
2491
2630
|
const baselineExcluded = new Set(log?.spec.baselineExclude ?? []);
|
|
@@ -2493,8 +2632,11 @@ function refreshExternalCli(projectDir, harnessRoot) {
|
|
|
2493
2632
|
harnessRoot,
|
|
2494
2633
|
projectDir,
|
|
2495
2634
|
cli: ALL_CLI_TARGETS,
|
|
2496
|
-
|
|
2497
|
-
//
|
|
2635
|
+
// 스킬은 **디스크에 있는 것만** 넘긴다. 스킬 *파일*은 전체 목록을 넘겨도 refreshOnly 가
|
|
2636
|
+
// 없는 것을 건너뛰지만, `AGENTS.md` 의 상시 스킬 안내(ADR-085)는 이 목록 그대로 렌더돼
|
|
2637
|
+
// `--without` 으로 뺀 스킬(#505)·opt-in 스킬을 "열어라"고 적었다(실측 2026-09-21). 판정은
|
|
2638
|
+
// `upsertRootImport` 와 같다 — `.claude/skills/<id>` 또는 `.agents/skills/<id>` 가 있으면 깔린 것.
|
|
2639
|
+
selectedInternalSkills: installedBundledSkills(projectDir),
|
|
2498
2640
|
rules: ALL_RULES.filter((r) => !isBaselineExcluded(`.claude/rules/${r}.md`, baselineExcluded)),
|
|
2499
2641
|
previousExternal: log?.externalFiles ?? [],
|
|
2500
2642
|
refreshOnly: true
|
|
@@ -2993,10 +3135,9 @@ function runExternalPhase(ctx) {
|
|
|
2993
3135
|
if (ctx.runExternal === null) {
|
|
2994
3136
|
return null;
|
|
2995
3137
|
}
|
|
2996
|
-
const {
|
|
3138
|
+
const { projectDir, spec } = ctx;
|
|
2997
3139
|
const runExt = ctx.runExternal ?? runExternalInstall;
|
|
2998
3140
|
const externalDeps = {
|
|
2999
|
-
harnessRoot,
|
|
3000
3141
|
log: () => {
|
|
3001
3142
|
},
|
|
3002
3143
|
warn: () => {
|
|
@@ -3231,9 +3372,7 @@ function createInstallRenderer(log, spec, verbose) {
|
|
|
3231
3372
|
const callbacks = {
|
|
3232
3373
|
onProgress: (event) => {
|
|
3233
3374
|
if (event.type === "baseline-complete") {
|
|
3234
|
-
|
|
3235
|
-
const eccWillInstall = claudeSelected && (isAssetSelected("ecc-plugin", spec) || spec.options.withPrune === true);
|
|
3236
|
-
renderPhase1Rows(log, event.baseline, verbose, eccWillInstall, claudeSelected);
|
|
3375
|
+
renderPhase1Rows(log, event.baseline, verbose);
|
|
3237
3376
|
} else if (event.type === "external-start" && event.assetCount > 0) {
|
|
3238
3377
|
log(unifiedSection(`External assets (${event.assetCount})`));
|
|
3239
3378
|
log("");
|
|
@@ -3494,13 +3633,11 @@ function formatAssetMeta(asset, version) {
|
|
|
3494
3633
|
return `npm \xB7 ${m.pkg}@${m.version}`;
|
|
3495
3634
|
case "npx-run":
|
|
3496
3635
|
return `npx \xB7 ${m.cmd}@${m.version}`;
|
|
3497
|
-
case "shell-script":
|
|
3498
|
-
return `bash \xB7 ${m.script}`;
|
|
3499
3636
|
case "internal":
|
|
3500
3637
|
return `internal \xB7 templates (${m.key})`;
|
|
3501
3638
|
}
|
|
3502
3639
|
}
|
|
3503
|
-
function renderPhase1Rows(log, baseline, verbose = false
|
|
3640
|
+
function renderPhase1Rows(log, baseline, verbose = false) {
|
|
3504
3641
|
if (baseline.updateMode) {
|
|
3505
3642
|
if (baseline.backup) {
|
|
3506
3643
|
log(assetRow("success", "backup", shortenPath(baseline.backup)));
|
|
@@ -3841,13 +3978,6 @@ function renderPhase1Rows(log, baseline, verbose = false, withEcc = false, claud
|
|
|
3841
3978
|
}
|
|
3842
3979
|
const mcpList = baseline.mcpServers.join(", ") || "(none)";
|
|
3843
3980
|
log(assetRow("success", ".mcp.json", mcpList, TEMPLATES_COL));
|
|
3844
|
-
if (!withEcc && baseline.categories) {
|
|
3845
|
-
log("");
|
|
3846
|
-
log(` ${c.dim("\xB7")} ${c.dim("ECC plugin not selected \u2014 cherry-pick fallback active")}`);
|
|
3847
|
-
if (claudeSelected) {
|
|
3848
|
-
log(` ${c.dim("\xB7")} ${c.dim("Use --with ecc-plugin to install ECC plugin instead")}`);
|
|
3849
|
-
}
|
|
3850
|
-
}
|
|
3851
3981
|
if (baseline.envFiles.envExampleCreated) {
|
|
3852
3982
|
log(assetRow("success", ".env.example", "Supabase token guide"));
|
|
3853
3983
|
}
|
|
@@ -3981,7 +4111,6 @@ function installAction(options, deps = {}) {
|
|
|
3981
4111
|
// v26.81.0 (ADR-022, BREAKING) — 자산 1:1 boolean 13종 삭제. 자산 선택은 위
|
|
3982
4112
|
// userOverride(--with <id>)로 일원화. 잔존 = 설치 동작 옵션만.
|
|
3983
4113
|
options: {
|
|
3984
|
-
withPrune: options.withPrune === true,
|
|
3985
4114
|
withCodexTrust: options.withCodexTrust === true
|
|
3986
4115
|
},
|
|
3987
4116
|
cli: validated.cli,
|
|
@@ -4077,9 +4206,6 @@ function registerInstallCommand(cli2) {
|
|
|
4077
4206
|
).option(
|
|
4078
4207
|
"--with-codex-trust",
|
|
4079
4208
|
"[Codex] Codex global opt-in: register trust entry in ~/.codex/config.toml"
|
|
4080
|
-
).option(
|
|
4081
|
-
"--with-prune",
|
|
4082
|
-
"[Behavior] Prune ECC items beyond curated 89 (use with --with ecc-plugin)"
|
|
4083
4209
|
).option("--verbose", "[Misc] Show installed file lists per category (default: counts only)").example("install --track tooling --with marketingskills").example("install --track csr-supabase --cli claude --cli codex").example("install --track csr-supabase --without netlify-cli --with railway-skills").action((options) => installAction(options));
|
|
4084
4210
|
}
|
|
4085
4211
|
|
|
@@ -4136,10 +4262,10 @@ function formatAssetRows(assets) {
|
|
|
4136
4262
|
const idWidth = Math.max(0, ...assets.map((a) => a.id.length));
|
|
4137
4263
|
const methodWidth = Math.max(0, ...assets.map((a) => a.method.length));
|
|
4138
4264
|
return assets.map((a) => {
|
|
4139
|
-
const
|
|
4265
|
+
const marker2 = a.scope === "global" ? c.yellow("!") : c.green("\u2713");
|
|
4140
4266
|
const version = a.version ? c.dim(` v${a.version}`) : "";
|
|
4141
4267
|
const note = a.scope === "global" ? c.yellow(" (manual removal \u2014 D16)") : "";
|
|
4142
|
-
return ` ${
|
|
4268
|
+
return ` ${marker2} ${padDisplay(a.id, idWidth)} ${c.dim(padDisplay(a.method, methodWidth))} ${c.dim(a.scope)}${version}${note}`;
|
|
4143
4269
|
});
|
|
4144
4270
|
}
|
|
4145
4271
|
function formatTemplateRows(log, projectDir) {
|
|
@@ -5177,6 +5303,7 @@ function hintFor(asset) {
|
|
|
5177
5303
|
case "npm":
|
|
5178
5304
|
return "npm uninstall --save-dev";
|
|
5179
5305
|
case "npx-run":
|
|
5306
|
+
// shell-script = #492 에서 은퇴한 legacy kind. 옛 로그가 그대로 들어온다.
|
|
5180
5307
|
case "shell-script":
|
|
5181
5308
|
case "internal":
|
|
5182
5309
|
return "\uC790\uB3D9 \uB418\uB3CC\uB9AC\uAE30 \uACBD\uB85C \uC5C6\uC74C \u2014 \uC804\uB7C9 \uC81C\uAC70(`.claude/` \uC0AD\uC81C)\uB85C\uB9CC \uC0AC\uB77C\uC9C4\uB2E4";
|
|
@@ -5294,7 +5421,7 @@ function uninstallAction(options, deps = {}) {
|
|
|
5294
5421
|
const selectedIds = parseOnly(options.only);
|
|
5295
5422
|
if (options.only !== void 0 && selectedIds === null) {
|
|
5296
5423
|
err(status.failure(c.red("ERROR: --only \uC5D0 \uC790\uC0B0 id \uAC00 \uC5C6\uB2E4")));
|
|
5297
|
-
err(c.dim(" \uC608: --only
|
|
5424
|
+
err(c.dim(" \uC608: --only openspec (id \uB294 `agent-harness list` \uC5D0\uC11C \uD655\uC778)"));
|
|
5298
5425
|
exit(1);
|
|
5299
5426
|
return;
|
|
5300
5427
|
}
|
|
@@ -5950,7 +6077,7 @@ var INSTALL_TARGET_PAGES = [
|
|
|
5950
6077
|
{ label: "Business (PM \xB7 Executive \xB7 Documents)", cats: ["business"] },
|
|
5951
6078
|
// v26.85.0 — 코드-퍼스트 비주얼/미디어 제작 (용도별 섹션, 전부 opt-in).
|
|
5952
6079
|
{ label: "Visual & Media (Slides \xB7 Diagrams \xB7 Motion \xB7 Video)", cats: ["visual-media"] },
|
|
5953
|
-
{ label: "Workflow
|
|
6080
|
+
{ label: "Workflow", cats: ["workflow"] }
|
|
5954
6081
|
];
|
|
5955
6082
|
var BASELINE_TITLES = {
|
|
5956
6083
|
rules: "Rules \u2014 \uC0C1\uC2DC \uC0C1\uC8FC\uD558\uB294 \uB300\uC6D0\uCE59 (4 CLI \uC804\uBD80\uC5D0 \uC124\uCE58)",
|
|
@@ -6241,7 +6368,6 @@ function baselineExcludeFrom(offered, checked) {
|
|
|
6241
6368
|
function toOptionFlags(keys) {
|
|
6242
6369
|
const picked = new Set(keys);
|
|
6243
6370
|
return {
|
|
6244
|
-
withPrune: picked.has("withPrune"),
|
|
6245
6371
|
withCodexTrust: picked.has("withCodexTrust")
|
|
6246
6372
|
};
|
|
6247
6373
|
}
|