@uzysjung/agent-harness 26.125.0 → 26.126.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 +115 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -712,7 +712,7 @@ var cac = (name = "") => new CAC(name);
|
|
|
712
712
|
// package.json
|
|
713
713
|
var package_default = {
|
|
714
714
|
name: "@uzysjung/agent-harness",
|
|
715
|
-
version: "26.
|
|
715
|
+
version: "26.126.1",
|
|
716
716
|
description: "Curate vetted AI-coding skills & plugins by your tech stack \u2014 install only what you need, across Claude Code, Codex, OpenCode & Antigravity",
|
|
717
717
|
type: "module",
|
|
718
718
|
publishConfig: {
|
|
@@ -907,12 +907,12 @@ init_esm_shims();
|
|
|
907
907
|
import {
|
|
908
908
|
chmodSync as chmodSync2,
|
|
909
909
|
existsSync as existsSync12,
|
|
910
|
-
mkdirSync as
|
|
911
|
-
readdirSync as
|
|
910
|
+
mkdirSync as mkdirSync5,
|
|
911
|
+
readdirSync as readdirSync4,
|
|
912
912
|
readFileSync as readFileSync11,
|
|
913
913
|
writeFileSync as writeFileSync9
|
|
914
914
|
} from "fs";
|
|
915
|
-
import { basename as basename4, dirname as
|
|
915
|
+
import { basename as basename4, dirname as dirname5, join as join11, resolve } from "path";
|
|
916
916
|
|
|
917
917
|
// src/antigravity/transform.ts
|
|
918
918
|
init_esm_shims();
|
|
@@ -962,7 +962,15 @@ function portBody(body) {
|
|
|
962
962
|
|
|
963
963
|
// src/fs-ops.ts
|
|
964
964
|
init_esm_shims();
|
|
965
|
-
import {
|
|
965
|
+
import {
|
|
966
|
+
copyFileSync,
|
|
967
|
+
cpSync,
|
|
968
|
+
existsSync,
|
|
969
|
+
mkdirSync,
|
|
970
|
+
readdirSync,
|
|
971
|
+
readFileSync,
|
|
972
|
+
renameSync
|
|
973
|
+
} from "fs";
|
|
966
974
|
import { dirname, join } from "path";
|
|
967
975
|
function ensureDir(path) {
|
|
968
976
|
mkdirSync(path, { recursive: true });
|
|
@@ -1004,10 +1012,26 @@ function backupFileIfChanged(target, newContent, now = /* @__PURE__ */ new Date(
|
|
|
1004
1012
|
if (readFileSync(target, "utf-8") === newContent) {
|
|
1005
1013
|
return null;
|
|
1006
1014
|
}
|
|
1015
|
+
return backupFile(target, now);
|
|
1016
|
+
}
|
|
1017
|
+
function backupFile(target, now = /* @__PURE__ */ new Date()) {
|
|
1007
1018
|
const backup = `${target}.backup-${formatStamp(now)}`;
|
|
1008
1019
|
copyFileSync(target, backup);
|
|
1009
1020
|
return backup;
|
|
1010
1021
|
}
|
|
1022
|
+
function listFilesRecursive(dir, prefix = "") {
|
|
1023
|
+
if (!existsSync(dir)) return [];
|
|
1024
|
+
const out = [];
|
|
1025
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
1026
|
+
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
1027
|
+
if (entry.isDirectory()) {
|
|
1028
|
+
out.push(...listFilesRecursive(join(dir, entry.name), rel));
|
|
1029
|
+
} else if (entry.isFile()) {
|
|
1030
|
+
out.push(rel);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
return out;
|
|
1034
|
+
}
|
|
1011
1035
|
function formatStamp(now) {
|
|
1012
1036
|
return now.toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z").slice(0, 15);
|
|
1013
1037
|
}
|
|
@@ -1508,7 +1532,7 @@ function writeMcpAllowlist(projectDir) {
|
|
|
1508
1532
|
// src/external-installer.ts
|
|
1509
1533
|
init_esm_shims();
|
|
1510
1534
|
import { spawnSync } from "child_process";
|
|
1511
|
-
import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync6 } from "fs";
|
|
1535
|
+
import { existsSync as existsSync7, readdirSync as readdirSync2, readFileSync as readFileSync6 } from "fs";
|
|
1512
1536
|
import { homedir as homedir2 } from "os";
|
|
1513
1537
|
import { join as join7 } from "path";
|
|
1514
1538
|
var DEFAULT_SPAWN_TIMEOUT_MS = 12e4;
|
|
@@ -1679,7 +1703,7 @@ function detectVersion(method, spawn) {
|
|
|
1679
1703
|
const marketplaceShort = method.pluginId.slice(at2 + 1);
|
|
1680
1704
|
const cacheBase = join7(homedir2(), ".claude/plugins/cache", marketplaceShort, plugin);
|
|
1681
1705
|
if (!existsSync7(cacheBase)) return void 0;
|
|
1682
|
-
const versions =
|
|
1706
|
+
const versions = readdirSync2(cacheBase).filter((v2) => /^\d/.test(v2)).sort();
|
|
1683
1707
|
return versions.at(-1);
|
|
1684
1708
|
}
|
|
1685
1709
|
case "npm": {
|
|
@@ -1826,6 +1850,13 @@ function mergeAssets(previous, current) {
|
|
|
1826
1850
|
function hashContent(content) {
|
|
1827
1851
|
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
1828
1852
|
}
|
|
1853
|
+
function collectSkillHashes(projectDir) {
|
|
1854
|
+
const skillsDir = join8(projectDir, ".claude/skills");
|
|
1855
|
+
return listFilesRecursive(skillsDir).map((rel) => ({
|
|
1856
|
+
path: rel,
|
|
1857
|
+
sha256: hashContent(readFileSync7(join8(skillsDir, rel), "utf8"))
|
|
1858
|
+
}));
|
|
1859
|
+
}
|
|
1829
1860
|
function writeInstallLog(projectDir, log) {
|
|
1830
1861
|
const path = join8(projectDir, ".claude", INSTALL_LOG_FILENAME);
|
|
1831
1862
|
mkdirSync3(dirname3(path), { recursive: true });
|
|
@@ -2114,19 +2145,21 @@ init_esm_shims();
|
|
|
2114
2145
|
import {
|
|
2115
2146
|
copyFileSync as copyFileSync2,
|
|
2116
2147
|
existsSync as existsSync11,
|
|
2117
|
-
|
|
2148
|
+
mkdirSync as mkdirSync4,
|
|
2149
|
+
readdirSync as readdirSync3,
|
|
2118
2150
|
readFileSync as readFileSync10,
|
|
2119
2151
|
unlinkSync,
|
|
2120
2152
|
writeFileSync as writeFileSync8
|
|
2121
2153
|
} from "fs";
|
|
2122
|
-
import { join as join10 } from "path";
|
|
2154
|
+
import { dirname as dirname4, join as join10 } from "path";
|
|
2123
2155
|
function runUpdateMode(projectDir, templatesDir) {
|
|
2124
2156
|
const claudeDir = join10(projectDir, ".claude");
|
|
2125
2157
|
const report = {
|
|
2126
2158
|
updated: {},
|
|
2127
2159
|
pruned: {},
|
|
2128
2160
|
staleHookRefs: [],
|
|
2129
|
-
claudeMdUpdated: false
|
|
2161
|
+
claudeMdUpdated: false,
|
|
2162
|
+
skillsBackedUp: []
|
|
2130
2163
|
};
|
|
2131
2164
|
const targets = [
|
|
2132
2165
|
{
|
|
@@ -2158,6 +2191,14 @@ function runUpdateMode(projectDir, templatesDir) {
|
|
|
2158
2191
|
report.updated[t.label] = updateDir(t.target, t.source, t.pattern);
|
|
2159
2192
|
report.pruned[t.label] = pruneOrphans(t.target, t.source, t.pattern);
|
|
2160
2193
|
}
|
|
2194
|
+
const skillSync = syncSkills(
|
|
2195
|
+
join10(claudeDir, "skills"),
|
|
2196
|
+
join10(templatesDir, "skills"),
|
|
2197
|
+
skillBaseline(projectDir)
|
|
2198
|
+
);
|
|
2199
|
+
report.updated[".claude/skills"] = skillSync.updated;
|
|
2200
|
+
report.skillsBackedUp = skillSync.backedUp;
|
|
2201
|
+
refreshSkillBaseline(projectDir);
|
|
2161
2202
|
const claudeMd = join10(claudeDir, "CLAUDE.md");
|
|
2162
2203
|
const templateMd = join10(templatesDir, "CLAUDE.md");
|
|
2163
2204
|
if (existsSync11(claudeMd) && existsSync11(templateMd)) {
|
|
@@ -2173,7 +2214,7 @@ function runUpdateMode(projectDir, templatesDir) {
|
|
|
2173
2214
|
function updateDir(target, source, ext) {
|
|
2174
2215
|
if (!existsSync11(target) || !existsSync11(source)) return 0;
|
|
2175
2216
|
let count = 0;
|
|
2176
|
-
for (const file of
|
|
2217
|
+
for (const file of readdirSync3(target)) {
|
|
2177
2218
|
if (!file.endsWith(ext)) continue;
|
|
2178
2219
|
const targetFile = join10(target, file);
|
|
2179
2220
|
const sourceFile = join10(source, file);
|
|
@@ -2184,10 +2225,56 @@ function updateDir(target, source, ext) {
|
|
|
2184
2225
|
}
|
|
2185
2226
|
return count;
|
|
2186
2227
|
}
|
|
2228
|
+
function syncSkills(targetDir, sourceDir, baseline, now = /* @__PURE__ */ new Date()) {
|
|
2229
|
+
if (!existsSync11(targetDir) || !existsSync11(sourceDir)) return { updated: 0, backedUp: [] };
|
|
2230
|
+
let updated = 0;
|
|
2231
|
+
const backedUp = [];
|
|
2232
|
+
for (const skill of readdirSync3(sourceDir, { withFileTypes: true })) {
|
|
2233
|
+
if (!skill.isDirectory()) continue;
|
|
2234
|
+
const targetSkill = join10(targetDir, skill.name);
|
|
2235
|
+
if (!existsSync11(targetSkill)) continue;
|
|
2236
|
+
for (const rel of listFilesRecursive(join10(sourceDir, skill.name))) {
|
|
2237
|
+
const targetFile = join10(targetSkill, rel);
|
|
2238
|
+
const next = readFileSync10(join10(sourceDir, skill.name, rel), "utf8");
|
|
2239
|
+
if (!existsSync11(targetFile)) {
|
|
2240
|
+
mkdirSync4(dirname4(targetFile), { recursive: true });
|
|
2241
|
+
writeFileSync8(targetFile, next);
|
|
2242
|
+
updated++;
|
|
2243
|
+
continue;
|
|
2244
|
+
}
|
|
2245
|
+
const current = readFileSync10(targetFile, "utf8");
|
|
2246
|
+
if (current === next) continue;
|
|
2247
|
+
const recorded = baseline.get(`${skill.name}/${rel}`);
|
|
2248
|
+
if (recorded === void 0 || hashContent(current) !== recorded) {
|
|
2249
|
+
backupFile(targetFile, now);
|
|
2250
|
+
backedUp.push(`${skill.name}/${rel}`);
|
|
2251
|
+
}
|
|
2252
|
+
writeFileSync8(targetFile, next);
|
|
2253
|
+
updated++;
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
return { updated, backedUp };
|
|
2257
|
+
}
|
|
2258
|
+
function skillBaseline(projectDir) {
|
|
2259
|
+
const log = readInstallLog(projectDir);
|
|
2260
|
+
return new Map((log?.skillFiles ?? []).map((f) => [f.path, f.sha256]));
|
|
2261
|
+
}
|
|
2262
|
+
function refreshSkillBaseline(projectDir) {
|
|
2263
|
+
const log = readInstallLog(projectDir);
|
|
2264
|
+
if (!log) return;
|
|
2265
|
+
const skillFiles = collectSkillHashes(projectDir);
|
|
2266
|
+
const next = { ...log };
|
|
2267
|
+
if (skillFiles.length > 0) next.skillFiles = skillFiles;
|
|
2268
|
+
else delete next.skillFiles;
|
|
2269
|
+
try {
|
|
2270
|
+
writeInstallLog(projectDir, next);
|
|
2271
|
+
} catch {
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2187
2274
|
function pruneOrphans(target, source, ext) {
|
|
2188
2275
|
if (!existsSync11(target) || !existsSync11(source)) return [];
|
|
2189
2276
|
const removed = [];
|
|
2190
|
-
for (const file of
|
|
2277
|
+
for (const file of readdirSync3(target)) {
|
|
2191
2278
|
if (!file.endsWith(ext)) continue;
|
|
2192
2279
|
const sourceFile = join10(source, file);
|
|
2193
2280
|
if (!existsSync11(sourceFile)) {
|
|
@@ -2484,7 +2571,8 @@ function writeInstallLogSafe(ctx, external, rootClaudeMdLog, previousLog, claude
|
|
|
2484
2571
|
claudeDirMovedAside,
|
|
2485
2572
|
rootFiles
|
|
2486
2573
|
);
|
|
2487
|
-
|
|
2574
|
+
const skillFiles = collectSkillHashes(ctx.projectDir);
|
|
2575
|
+
writeInstallLog(ctx.projectDir, skillFiles.length > 0 ? { ...log, skillFiles } : log);
|
|
2488
2576
|
} catch (e2) {
|
|
2489
2577
|
ctx.onProgress?.({
|
|
2490
2578
|
type: "install-log-error",
|
|
@@ -2604,7 +2692,7 @@ function accumulateCategory(cats, entry) {
|
|
|
2604
2692
|
}
|
|
2605
2693
|
function writeInstalledTracks(projectDir, tracks) {
|
|
2606
2694
|
const path = join11(projectDir, ".claude/.installed-tracks");
|
|
2607
|
-
|
|
2695
|
+
mkdirSync5(dirname5(path), { recursive: true });
|
|
2608
2696
|
const sorted = [...new Set(tracks)].sort().join("\n");
|
|
2609
2697
|
writeFileSync9(path, `${sorted}
|
|
2610
2698
|
`);
|
|
@@ -2625,7 +2713,7 @@ function chmodHooksSync(hookDir) {
|
|
|
2625
2713
|
}
|
|
2626
2714
|
}
|
|
2627
2715
|
function listHookFiles(hookDir) {
|
|
2628
|
-
return
|
|
2716
|
+
return readdirSync4(hookDir, { withFileTypes: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".sh")).map((e2) => resolve(hookDir, e2.name));
|
|
2629
2717
|
}
|
|
2630
2718
|
|
|
2631
2719
|
// src/commands/install-render.ts
|
|
@@ -2928,6 +3016,15 @@ function renderPhase1Rows(log, baseline, verbose = false, withEcc = false, claud
|
|
|
2928
3016
|
if (baseline.updateMode.claudeMdUpdated) {
|
|
2929
3017
|
log(assetRow("success", ".claude/CLAUDE.md", "refreshed from template"));
|
|
2930
3018
|
}
|
|
3019
|
+
if (baseline.updateMode.skillsBackedUp.length > 0) {
|
|
3020
|
+
log(
|
|
3021
|
+
assetRow(
|
|
3022
|
+
"skip",
|
|
3023
|
+
".claude/skills edited files",
|
|
3024
|
+
`${baseline.updateMode.skillsBackedUp.length} backed up as *.backup-<time>`
|
|
3025
|
+
)
|
|
3026
|
+
);
|
|
3027
|
+
}
|
|
2931
3028
|
if (baseline.updateMode.staleHookRefs.length > 0) {
|
|
2932
3029
|
log(
|
|
2933
3030
|
assetRow(
|
|
@@ -4871,7 +4968,9 @@ function buildRouterChoices(state) {
|
|
|
4871
4968
|
{
|
|
4872
4969
|
value: "update",
|
|
4873
4970
|
label: "Update policy files (auto-backup)",
|
|
4874
|
-
|
|
4971
|
+
// v26.126.0 (R-3a) — skills 가 목록에 들어왔다. 이 문구가 곧 update 의 광고이고
|
|
4972
|
+
// (update 는 위저드로만 도달한다) 실동작과 어긋나면 그 자체로 거짓출하다.
|
|
4973
|
+
hint: "Refresh rules / agents / commands / hooks / skills \u2014 your edits are backed up",
|
|
4875
4974
|
enabled: true
|
|
4876
4975
|
},
|
|
4877
4976
|
{
|