@uzysjung/agent-harness 26.107.0 → 26.108.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.md +3 -1
- package/dist/{chunk-HINGFZ65.js → chunk-ZEV3DL6G.js} +16 -1
- package/dist/chunk-ZEV3DL6G.js.map +1 -0
- package/dist/index.js +192 -139
- package/dist/index.js.map +1 -1
- package/dist/trust-tier-drift.js +1 -1
- package/package.json +1 -1
- package/templates/github-workflows/ci-node.yml +56 -0
- package/templates/github-workflows/ci-python.yml +54 -0
- package/templates/github-workflows/e2e.yml +31 -0
- package/dist/chunk-HINGFZ65.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
isInstallScope,
|
|
25
25
|
isTrack,
|
|
26
26
|
resolveScope
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-ZEV3DL6G.js";
|
|
28
28
|
|
|
29
29
|
// node_modules/sisteransi/src/index.js
|
|
30
30
|
var require_src = __commonJS({
|
|
@@ -709,7 +709,7 @@ var cac = (name = "") => new CAC(name);
|
|
|
709
709
|
// package.json
|
|
710
710
|
var package_default = {
|
|
711
711
|
name: "@uzysjung/agent-harness",
|
|
712
|
-
version: "26.
|
|
712
|
+
version: "26.108.0",
|
|
713
713
|
description: "Curate vetted AI-coding skills & plugins by your tech stack \u2014 install only what you need, across Claude Code, Codex, OpenCode & Antigravity",
|
|
714
714
|
type: "module",
|
|
715
715
|
publishConfig: {
|
|
@@ -902,13 +902,13 @@ function padDisplay(s, width) {
|
|
|
902
902
|
init_esm_shims();
|
|
903
903
|
import {
|
|
904
904
|
chmodSync as chmodSync2,
|
|
905
|
-
existsSync as
|
|
905
|
+
existsSync as existsSync12,
|
|
906
906
|
mkdirSync as mkdirSync4,
|
|
907
907
|
readdirSync as readdirSync3,
|
|
908
908
|
readFileSync as readFileSync11,
|
|
909
909
|
writeFileSync as writeFileSync9
|
|
910
910
|
} from "fs";
|
|
911
|
-
import { basename as basename4, dirname as dirname4, join as
|
|
911
|
+
import { basename as basename4, dirname as dirname4, join as join11, resolve } from "path";
|
|
912
912
|
|
|
913
913
|
// src/antigravity/transform.ts
|
|
914
914
|
init_esm_shims();
|
|
@@ -1154,21 +1154,59 @@ function writeRules(harnessRoot, projectDir) {
|
|
|
1154
1154
|
return target;
|
|
1155
1155
|
}
|
|
1156
1156
|
|
|
1157
|
+
// src/ci-scaffold.ts
|
|
1158
|
+
init_esm_shims();
|
|
1159
|
+
import { existsSync as existsSync3 } from "fs";
|
|
1160
|
+
import { join as join3 } from "path";
|
|
1161
|
+
var PYTHON_TRACKS = "data|csr-fastapi|full";
|
|
1162
|
+
var VARIANTS = [
|
|
1163
|
+
{
|
|
1164
|
+
source: "ci-node.yml",
|
|
1165
|
+
target: "ci.yml",
|
|
1166
|
+
applies: (tracks) => anyTrack(tracks, "csr-*|ssr-*|tooling|full") || !anyTrack(tracks, PYTHON_TRACKS)
|
|
1167
|
+
},
|
|
1168
|
+
{
|
|
1169
|
+
source: "ci-python.yml",
|
|
1170
|
+
target: "ci-python.yml",
|
|
1171
|
+
applies: (tracks) => anyTrack(tracks, PYTHON_TRACKS)
|
|
1172
|
+
},
|
|
1173
|
+
{
|
|
1174
|
+
source: "e2e.yml",
|
|
1175
|
+
target: "e2e.yml",
|
|
1176
|
+
applies: (tracks) => hasUiTrack(tracks)
|
|
1177
|
+
}
|
|
1178
|
+
];
|
|
1179
|
+
function installCiScaffold(ctx) {
|
|
1180
|
+
const report = { written: [], skippedExisting: [] };
|
|
1181
|
+
for (const v2 of VARIANTS) {
|
|
1182
|
+
if (!v2.applies(ctx.tracks)) continue;
|
|
1183
|
+
const relTarget = `.github/workflows/${v2.target}`;
|
|
1184
|
+
const target = join3(ctx.projectDir, relTarget);
|
|
1185
|
+
if (existsSync3(target)) {
|
|
1186
|
+
report.skippedExisting.push(relTarget);
|
|
1187
|
+
continue;
|
|
1188
|
+
}
|
|
1189
|
+
copyFile(join3(ctx.harnessRoot, "templates/github-workflows", v2.source), target);
|
|
1190
|
+
report.written.push(relTarget);
|
|
1191
|
+
}
|
|
1192
|
+
return report;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1157
1195
|
// src/codex/opt-in.ts
|
|
1158
1196
|
init_esm_shims();
|
|
1159
1197
|
import { homedir } from "os";
|
|
1160
|
-
import { join as
|
|
1198
|
+
import { join as join4 } from "path";
|
|
1161
1199
|
|
|
1162
1200
|
// src/codex/trust-entry.ts
|
|
1163
1201
|
init_esm_shims();
|
|
1164
|
-
import { existsSync as
|
|
1202
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
1165
1203
|
import { dirname as dirname2 } from "path";
|
|
1166
1204
|
var TRUST_BLOCK_REGEX = /\[projects\."([^"]+)"\]/g;
|
|
1167
1205
|
function registerTrustEntry(opts) {
|
|
1168
1206
|
const { configPath, projectDir } = opts;
|
|
1169
1207
|
try {
|
|
1170
1208
|
mkdirSync2(dirname2(configPath), { recursive: true });
|
|
1171
|
-
const existing =
|
|
1209
|
+
const existing = existsSync4(configPath) ? readFileSync3(configPath, "utf8") : "";
|
|
1172
1210
|
if (hasTrustEntry(existing, projectDir)) {
|
|
1173
1211
|
return { status: "already-present" };
|
|
1174
1212
|
}
|
|
@@ -1192,8 +1230,8 @@ function hasTrustEntry(configContent, projectDir) {
|
|
|
1192
1230
|
|
|
1193
1231
|
// src/codex/opt-in.ts
|
|
1194
1232
|
function runCodexOptIn(ctx) {
|
|
1195
|
-
const codexHome = ctx.codexHome ??
|
|
1196
|
-
const configPath =
|
|
1233
|
+
const codexHome = ctx.codexHome ?? join4(homedir(), ".codex");
|
|
1234
|
+
const configPath = join4(codexHome, "config.toml");
|
|
1197
1235
|
const result = registerTrustEntry({ configPath, projectDir: ctx.projectDir });
|
|
1198
1236
|
return {
|
|
1199
1237
|
trustEntry: {
|
|
@@ -1206,8 +1244,8 @@ function runCodexOptIn(ctx) {
|
|
|
1206
1244
|
|
|
1207
1245
|
// src/codex/transform.ts
|
|
1208
1246
|
init_esm_shims();
|
|
1209
|
-
import { chmodSync, existsSync as
|
|
1210
|
-
import { basename as basename2, join as
|
|
1247
|
+
import { chmodSync, existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
1248
|
+
import { basename as basename2, join as join5 } from "path";
|
|
1211
1249
|
|
|
1212
1250
|
// src/codex/config-toml.ts
|
|
1213
1251
|
init_esm_shims();
|
|
@@ -1276,12 +1314,12 @@ var HOOK_NAMES = ["session-start", "hito-counter"];
|
|
|
1276
1314
|
var ENV_VAR_RENAME = /CLAUDE_PROJECT_DIR/g;
|
|
1277
1315
|
function runCodexTransform(params) {
|
|
1278
1316
|
const { harnessRoot, projectDir, selectedInternalSkills = [] } = params;
|
|
1279
|
-
const claudeMd = readRequired(
|
|
1280
|
-
const agentsTemplate = readRequired(
|
|
1281
|
-
const configTemplate = readRequired(
|
|
1317
|
+
const claudeMd = readRequired(join5(harnessRoot, "templates/CLAUDE.md"));
|
|
1318
|
+
const agentsTemplate = readRequired(join5(harnessRoot, "templates/codex/AGENTS.md.template"));
|
|
1319
|
+
const configTemplate = readRequired(join5(harnessRoot, "templates/codex/config.toml.template"));
|
|
1282
1320
|
const projectName = basename2(projectDir);
|
|
1283
|
-
const mcp = readOptionalJson(
|
|
1284
|
-
const agentsMdPath =
|
|
1321
|
+
const mcp = readOptionalJson(join5(harnessRoot, ".mcp.json"));
|
|
1322
|
+
const agentsMdPath = join5(projectDir, "AGENTS.md");
|
|
1285
1323
|
ensureDir(projectDir);
|
|
1286
1324
|
const agentsMdOut = renderAgentsMd({
|
|
1287
1325
|
template: agentsTemplate,
|
|
@@ -1291,8 +1329,8 @@ function runCodexTransform(params) {
|
|
|
1291
1329
|
});
|
|
1292
1330
|
backupFileIfChanged(agentsMdPath, agentsMdOut);
|
|
1293
1331
|
writeFileSync3(agentsMdPath, agentsMdOut);
|
|
1294
|
-
const configTomlPath =
|
|
1295
|
-
ensureDir(
|
|
1332
|
+
const configTomlPath = join5(projectDir, ".codex/config.toml");
|
|
1333
|
+
ensureDir(join5(projectDir, ".codex"));
|
|
1296
1334
|
writeFileSync3(
|
|
1297
1335
|
configTomlPath,
|
|
1298
1336
|
renderConfigToml({
|
|
@@ -1302,42 +1340,42 @@ function runCodexTransform(params) {
|
|
|
1302
1340
|
mcp
|
|
1303
1341
|
})
|
|
1304
1342
|
);
|
|
1305
|
-
const hookDir =
|
|
1343
|
+
const hookDir = join5(projectDir, ".codex/hooks");
|
|
1306
1344
|
ensureDir(hookDir);
|
|
1307
1345
|
const hookFiles = [];
|
|
1308
1346
|
for (const hook of HOOK_NAMES) {
|
|
1309
|
-
const src =
|
|
1310
|
-
if (!
|
|
1347
|
+
const src = join5(harnessRoot, "templates/hooks", `${hook}.sh`);
|
|
1348
|
+
if (!existsSync5(src)) {
|
|
1311
1349
|
continue;
|
|
1312
1350
|
}
|
|
1313
1351
|
const ported = readFileSync4(src, "utf8").replace(ENV_VAR_RENAME, "CODEX_PROJECT_DIR");
|
|
1314
|
-
const target =
|
|
1352
|
+
const target = join5(hookDir, `${hook}.sh`);
|
|
1315
1353
|
writeFileSync3(target, ported);
|
|
1316
1354
|
chmodSync(target, 493);
|
|
1317
1355
|
hookFiles.push(target);
|
|
1318
1356
|
}
|
|
1319
1357
|
const skillFiles = [];
|
|
1320
1358
|
for (const id of selectedInternalSkills) {
|
|
1321
|
-
const src =
|
|
1322
|
-
if (!
|
|
1359
|
+
const src = join5(harnessRoot, "templates/skills", id, "SKILL.md");
|
|
1360
|
+
if (!existsSync5(src)) {
|
|
1323
1361
|
continue;
|
|
1324
1362
|
}
|
|
1325
|
-
const skillDir =
|
|
1363
|
+
const skillDir = join5(projectDir, ".agents", "skills", id);
|
|
1326
1364
|
ensureDir(skillDir);
|
|
1327
|
-
const target =
|
|
1365
|
+
const target = join5(skillDir, "SKILL.md");
|
|
1328
1366
|
writeFileSync3(target, renderBundledSkill(readFileSync4(src, "utf8")));
|
|
1329
1367
|
skillFiles.push(target);
|
|
1330
1368
|
}
|
|
1331
1369
|
return { agentsMdPath, configTomlPath, hookFiles, skillFiles };
|
|
1332
1370
|
}
|
|
1333
1371
|
function readRequired(path) {
|
|
1334
|
-
if (!
|
|
1372
|
+
if (!existsSync5(path)) {
|
|
1335
1373
|
throw new Error(`Codex transform: required source missing: ${path}`);
|
|
1336
1374
|
}
|
|
1337
1375
|
return readFileSync4(path, "utf8");
|
|
1338
1376
|
}
|
|
1339
1377
|
function readOptionalJson(path) {
|
|
1340
|
-
if (!
|
|
1378
|
+
if (!existsSync5(path)) {
|
|
1341
1379
|
return null;
|
|
1342
1380
|
}
|
|
1343
1381
|
try {
|
|
@@ -1349,8 +1387,8 @@ function readOptionalJson(path) {
|
|
|
1349
1387
|
|
|
1350
1388
|
// src/env-files.ts
|
|
1351
1389
|
init_esm_shims();
|
|
1352
|
-
import { appendFileSync, existsSync as
|
|
1353
|
-
import { join as
|
|
1390
|
+
import { appendFileSync, existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
1391
|
+
import { join as join6 } from "path";
|
|
1354
1392
|
var ENV_EXAMPLE_BODY = `# .env.example \u2014 csr-supabase Track
|
|
1355
1393
|
# Copy to .env (gitignored) and fill in values: cp .env.example .env
|
|
1356
1394
|
|
|
@@ -1387,16 +1425,16 @@ function writeEnvExample(projectDir, tracks) {
|
|
|
1387
1425
|
if (!tracks.some((t) => ENV_EXAMPLE_TRACKS.includes(t))) {
|
|
1388
1426
|
return false;
|
|
1389
1427
|
}
|
|
1390
|
-
const path =
|
|
1391
|
-
if (
|
|
1428
|
+
const path = join6(projectDir, ".env.example");
|
|
1429
|
+
if (existsSync6(path)) {
|
|
1392
1430
|
return false;
|
|
1393
1431
|
}
|
|
1394
1432
|
writeFileSync4(path, ENV_EXAMPLE_BODY);
|
|
1395
1433
|
return true;
|
|
1396
1434
|
}
|
|
1397
1435
|
function addGitignoreEnv(projectDir) {
|
|
1398
|
-
const path =
|
|
1399
|
-
if (!
|
|
1436
|
+
const path = join6(projectDir, ".gitignore");
|
|
1437
|
+
if (!existsSync6(path)) {
|
|
1400
1438
|
return false;
|
|
1401
1439
|
}
|
|
1402
1440
|
const content = readFileSync5(path, "utf8");
|
|
@@ -1413,8 +1451,8 @@ function addGitignoreEnv(projectDir) {
|
|
|
1413
1451
|
var NPX_SKILLS_AGENT_DIRS = [".factory/", ".goose/"];
|
|
1414
1452
|
var GITIGNORE_NPX_SKILLS_HEADER = "# npx skills add multi-CLI cache (auto-added by agent-harness)";
|
|
1415
1453
|
function addGitignoreNpxSkillsAgents(projectDir) {
|
|
1416
|
-
const path =
|
|
1417
|
-
if (!
|
|
1454
|
+
const path = join6(projectDir, ".gitignore");
|
|
1455
|
+
if (!existsSync6(path)) {
|
|
1418
1456
|
return [];
|
|
1419
1457
|
}
|
|
1420
1458
|
const content = readFileSync5(path, "utf8");
|
|
@@ -1433,12 +1471,12 @@ ${block}
|
|
|
1433
1471
|
return [...missing];
|
|
1434
1472
|
}
|
|
1435
1473
|
function writeMcpAllowlist(projectDir) {
|
|
1436
|
-
const allowlistPath =
|
|
1437
|
-
if (
|
|
1474
|
+
const allowlistPath = join6(projectDir, ".mcp-allowlist");
|
|
1475
|
+
if (existsSync6(allowlistPath)) {
|
|
1438
1476
|
return null;
|
|
1439
1477
|
}
|
|
1440
|
-
const mcpPath =
|
|
1441
|
-
if (!
|
|
1478
|
+
const mcpPath = join6(projectDir, ".mcp.json");
|
|
1479
|
+
if (!existsSync6(mcpPath)) {
|
|
1442
1480
|
return null;
|
|
1443
1481
|
}
|
|
1444
1482
|
let names = [];
|
|
@@ -1466,9 +1504,9 @@ function writeMcpAllowlist(projectDir) {
|
|
|
1466
1504
|
// src/external-installer.ts
|
|
1467
1505
|
init_esm_shims();
|
|
1468
1506
|
import { spawnSync } from "child_process";
|
|
1469
|
-
import { existsSync as
|
|
1507
|
+
import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync6 } from "fs";
|
|
1470
1508
|
import { homedir as homedir2 } from "os";
|
|
1471
|
-
import { join as
|
|
1509
|
+
import { join as join7 } from "path";
|
|
1472
1510
|
var DEFAULT_SPAWN_TIMEOUT_MS = 12e4;
|
|
1473
1511
|
function selectExternalTargets(assets, ctx) {
|
|
1474
1512
|
const conditionPassed = filterApplicableAssets(assets, ctx).filter(
|
|
@@ -1544,8 +1582,8 @@ function installOne(asset, ctx) {
|
|
|
1544
1582
|
cwd
|
|
1545
1583
|
);
|
|
1546
1584
|
case "shell-script": {
|
|
1547
|
-
const scriptPath =
|
|
1548
|
-
if (!
|
|
1585
|
+
const scriptPath = join7(ctx.harnessRoot, method.script);
|
|
1586
|
+
if (!existsSync7(scriptPath)) {
|
|
1549
1587
|
return {
|
|
1550
1588
|
asset,
|
|
1551
1589
|
ok: false,
|
|
@@ -1635,16 +1673,16 @@ function detectVersion(method, spawn) {
|
|
|
1635
1673
|
if (at2 <= 0) return void 0;
|
|
1636
1674
|
const plugin = method.pluginId.slice(0, at2);
|
|
1637
1675
|
const marketplaceShort = method.pluginId.slice(at2 + 1);
|
|
1638
|
-
const cacheBase =
|
|
1639
|
-
if (!
|
|
1676
|
+
const cacheBase = join7(homedir2(), ".claude/plugins/cache", marketplaceShort, plugin);
|
|
1677
|
+
if (!existsSync7(cacheBase)) return void 0;
|
|
1640
1678
|
const versions = readdirSync(cacheBase).filter((v2) => /^\d/.test(v2)).sort();
|
|
1641
1679
|
return versions.at(-1);
|
|
1642
1680
|
}
|
|
1643
1681
|
case "npm": {
|
|
1644
1682
|
const npmRoot = getNpmGlobalRoot(spawn);
|
|
1645
1683
|
if (!npmRoot) return void 0;
|
|
1646
|
-
const pkgJson =
|
|
1647
|
-
if (!
|
|
1684
|
+
const pkgJson = join7(npmRoot, method.pkg, "package.json");
|
|
1685
|
+
if (!existsSync7(pkgJson)) return void 0;
|
|
1648
1686
|
const parsed = JSON.parse(readFileSync6(pkgJson, "utf8"));
|
|
1649
1687
|
return parsed.version;
|
|
1650
1688
|
}
|
|
@@ -1673,8 +1711,8 @@ function getNpmGlobalRoot(spawn) {
|
|
|
1673
1711
|
// src/install-log.ts
|
|
1674
1712
|
init_esm_shims();
|
|
1675
1713
|
import { createHash } from "crypto";
|
|
1676
|
-
import { existsSync as
|
|
1677
|
-
import { dirname as dirname3, join as
|
|
1714
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
1715
|
+
import { dirname as dirname3, join as join8 } from "path";
|
|
1678
1716
|
var INSTALL_LOG_FILENAME = ".harness-install.json";
|
|
1679
1717
|
var INSTALL_LOG_VERSION = 1;
|
|
1680
1718
|
function buildAssetEntries(report, scope) {
|
|
@@ -1732,15 +1770,15 @@ function hashContent(content) {
|
|
|
1732
1770
|
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
1733
1771
|
}
|
|
1734
1772
|
function writeInstallLog(projectDir, log) {
|
|
1735
|
-
const path =
|
|
1773
|
+
const path = join8(projectDir, ".claude", INSTALL_LOG_FILENAME);
|
|
1736
1774
|
mkdirSync3(dirname3(path), { recursive: true });
|
|
1737
1775
|
writeFileSync5(path, `${JSON.stringify(log, null, 2)}
|
|
1738
1776
|
`, "utf8");
|
|
1739
1777
|
return path;
|
|
1740
1778
|
}
|
|
1741
1779
|
function readInstallLog(projectDir) {
|
|
1742
|
-
const path =
|
|
1743
|
-
if (!
|
|
1780
|
+
const path = join8(projectDir, ".claude", INSTALL_LOG_FILENAME);
|
|
1781
|
+
if (!existsSync8(path)) return null;
|
|
1744
1782
|
try {
|
|
1745
1783
|
const parsed = JSON.parse(readFileSync7(path, "utf8"));
|
|
1746
1784
|
if (Array.isArray(parsed.assets)) {
|
|
@@ -1754,7 +1792,7 @@ function readInstallLog(projectDir) {
|
|
|
1754
1792
|
}
|
|
1755
1793
|
}
|
|
1756
1794
|
function installLogPath(projectDir) {
|
|
1757
|
-
return
|
|
1795
|
+
return join8(projectDir, ".claude", INSTALL_LOG_FILENAME);
|
|
1758
1796
|
}
|
|
1759
1797
|
|
|
1760
1798
|
// src/manifest.ts
|
|
@@ -2002,7 +2040,7 @@ function buildManifest(spec) {
|
|
|
2002
2040
|
|
|
2003
2041
|
// src/mcp-merge.ts
|
|
2004
2042
|
init_esm_shims();
|
|
2005
|
-
import { existsSync as
|
|
2043
|
+
import { existsSync as existsSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
|
|
2006
2044
|
function parseTrackMcpMap(raw) {
|
|
2007
2045
|
const rows = [];
|
|
2008
2046
|
for (const line of raw.split(/\r?\n/)) {
|
|
@@ -2054,8 +2092,8 @@ function mergeMcpServers(base, rows, tracks) {
|
|
|
2054
2092
|
}
|
|
2055
2093
|
function composeMcpJson(opts) {
|
|
2056
2094
|
const base = JSON.parse(readFileSync8(opts.templateMcpPath, "utf8"));
|
|
2057
|
-
const merged = opts.existingPath &&
|
|
2058
|
-
const mapRaw =
|
|
2095
|
+
const merged = opts.existingPath && existsSync9(opts.existingPath) ? mergeUserBase(base, opts.existingPath) : base;
|
|
2096
|
+
const mapRaw = existsSync9(opts.trackMapPath) ? readFileSync8(opts.trackMapPath, "utf8") : "";
|
|
2059
2097
|
const rows = parseTrackMcpMap(mapRaw);
|
|
2060
2098
|
return mergeMcpServers(merged, rows, opts.tracks);
|
|
2061
2099
|
}
|
|
@@ -2077,8 +2115,8 @@ function writeMcpJson(path, mcp) {
|
|
|
2077
2115
|
|
|
2078
2116
|
// src/opencode/transform.ts
|
|
2079
2117
|
init_esm_shims();
|
|
2080
|
-
import { existsSync as
|
|
2081
|
-
import { basename as basename3, join as
|
|
2118
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
2119
|
+
import { basename as basename3, join as join9 } from "path";
|
|
2082
2120
|
|
|
2083
2121
|
// src/opencode/agents-md.ts
|
|
2084
2122
|
init_esm_shims();
|
|
@@ -2179,15 +2217,15 @@ function parseTemplate(template) {
|
|
|
2179
2217
|
// src/opencode/transform.ts
|
|
2180
2218
|
function runOpencodeTransform(params) {
|
|
2181
2219
|
const { harnessRoot, projectDir, selectedInternalSkills = [] } = params;
|
|
2182
|
-
const claudeMd = readRequired2(
|
|
2183
|
-
const agentsTemplate = readRequired2(
|
|
2220
|
+
const claudeMd = readRequired2(join9(harnessRoot, "templates/CLAUDE.md"));
|
|
2221
|
+
const agentsTemplate = readRequired2(join9(harnessRoot, "templates/opencode/AGENTS.md.template"));
|
|
2184
2222
|
const opencodeTemplate = readRequired2(
|
|
2185
|
-
|
|
2223
|
+
join9(harnessRoot, "templates/opencode/opencode.json.template")
|
|
2186
2224
|
);
|
|
2187
2225
|
const projectName = basename3(projectDir);
|
|
2188
|
-
const mcp = readOptionalJson2(
|
|
2226
|
+
const mcp = readOptionalJson2(join9(harnessRoot, ".mcp.json"));
|
|
2189
2227
|
ensureDir(projectDir);
|
|
2190
|
-
const agentsMdPath =
|
|
2228
|
+
const agentsMdPath = join9(projectDir, "AGENTS.md");
|
|
2191
2229
|
const agentsMdOut = renderAgentsMd2({
|
|
2192
2230
|
template: agentsTemplate,
|
|
2193
2231
|
claudeMd,
|
|
@@ -2196,18 +2234,18 @@ function runOpencodeTransform(params) {
|
|
|
2196
2234
|
});
|
|
2197
2235
|
backupFileIfChanged(agentsMdPath, agentsMdOut);
|
|
2198
2236
|
writeFileSync7(agentsMdPath, agentsMdOut);
|
|
2199
|
-
const opencodeJsonPath =
|
|
2237
|
+
const opencodeJsonPath = join9(projectDir, "opencode.json");
|
|
2200
2238
|
writeFileSync7(opencodeJsonPath, renderOpencodeJson({ template: opencodeTemplate, mcp }));
|
|
2201
|
-
const cmdDir =
|
|
2239
|
+
const cmdDir = join9(projectDir, ".opencode/commands");
|
|
2202
2240
|
ensureDir(cmdDir);
|
|
2203
2241
|
const commandFiles = [];
|
|
2204
2242
|
for (const id of selectedInternalSkills) {
|
|
2205
|
-
const src =
|
|
2206
|
-
if (!
|
|
2243
|
+
const src = join9(harnessRoot, "templates/skills", id, "SKILL.md");
|
|
2244
|
+
if (!existsSync10(src)) {
|
|
2207
2245
|
continue;
|
|
2208
2246
|
}
|
|
2209
|
-
const target =
|
|
2210
|
-
const shellDependent =
|
|
2247
|
+
const target = join9(cmdDir, `${id}.md`);
|
|
2248
|
+
const shellDependent = existsSync10(join9(harnessRoot, "templates/skills", id, "scripts"));
|
|
2211
2249
|
writeFileSync7(
|
|
2212
2250
|
target,
|
|
2213
2251
|
renderCommandFromSkill(readFileSync9(src, "utf8"), id, { shellDependent })
|
|
@@ -2217,13 +2255,13 @@ function runOpencodeTransform(params) {
|
|
|
2217
2255
|
return { agentsMdPath, opencodeJsonPath, commandFiles };
|
|
2218
2256
|
}
|
|
2219
2257
|
function readRequired2(path) {
|
|
2220
|
-
if (!
|
|
2258
|
+
if (!existsSync10(path)) {
|
|
2221
2259
|
throw new Error(`OpenCode transform: required source missing: ${path}`);
|
|
2222
2260
|
}
|
|
2223
2261
|
return readFileSync9(path, "utf8");
|
|
2224
2262
|
}
|
|
2225
2263
|
function readOptionalJson2(path) {
|
|
2226
|
-
if (!
|
|
2264
|
+
if (!existsSync10(path)) {
|
|
2227
2265
|
return null;
|
|
2228
2266
|
}
|
|
2229
2267
|
try {
|
|
@@ -2261,15 +2299,15 @@ function addPreToolUseHook(settings, matcher, command) {
|
|
|
2261
2299
|
init_esm_shims();
|
|
2262
2300
|
import {
|
|
2263
2301
|
copyFileSync as copyFileSync2,
|
|
2264
|
-
existsSync as
|
|
2302
|
+
existsSync as existsSync11,
|
|
2265
2303
|
readdirSync as readdirSync2,
|
|
2266
2304
|
readFileSync as readFileSync10,
|
|
2267
2305
|
unlinkSync,
|
|
2268
2306
|
writeFileSync as writeFileSync8
|
|
2269
2307
|
} from "fs";
|
|
2270
|
-
import { join as
|
|
2308
|
+
import { join as join10 } from "path";
|
|
2271
2309
|
function runUpdateMode(projectDir, templatesDir) {
|
|
2272
|
-
const claudeDir =
|
|
2310
|
+
const claudeDir = join10(projectDir, ".claude");
|
|
2273
2311
|
const report = {
|
|
2274
2312
|
updated: {},
|
|
2275
2313
|
pruned: {},
|
|
@@ -2278,26 +2316,26 @@ function runUpdateMode(projectDir, templatesDir) {
|
|
|
2278
2316
|
};
|
|
2279
2317
|
const targets = [
|
|
2280
2318
|
{
|
|
2281
|
-
target:
|
|
2282
|
-
source:
|
|
2319
|
+
target: join10(claudeDir, "rules"),
|
|
2320
|
+
source: join10(templatesDir, "rules"),
|
|
2283
2321
|
pattern: ".md",
|
|
2284
2322
|
label: ".claude/rules"
|
|
2285
2323
|
},
|
|
2286
2324
|
{
|
|
2287
|
-
target:
|
|
2288
|
-
source:
|
|
2325
|
+
target: join10(claudeDir, "agents"),
|
|
2326
|
+
source: join10(templatesDir, "agents"),
|
|
2289
2327
|
pattern: ".md",
|
|
2290
2328
|
label: ".claude/agents"
|
|
2291
2329
|
},
|
|
2292
2330
|
{
|
|
2293
|
-
target:
|
|
2294
|
-
source:
|
|
2331
|
+
target: join10(claudeDir, "commands/uzys"),
|
|
2332
|
+
source: join10(templatesDir, "commands/uzys"),
|
|
2295
2333
|
pattern: ".md",
|
|
2296
2334
|
label: ".claude/commands/uzys"
|
|
2297
2335
|
},
|
|
2298
2336
|
{
|
|
2299
|
-
target:
|
|
2300
|
-
source:
|
|
2337
|
+
target: join10(claudeDir, "hooks"),
|
|
2338
|
+
source: join10(templatesDir, "hooks"),
|
|
2301
2339
|
pattern: ".sh",
|
|
2302
2340
|
label: ".claude/hooks"
|
|
2303
2341
|
}
|
|
@@ -2306,26 +2344,26 @@ function runUpdateMode(projectDir, templatesDir) {
|
|
|
2306
2344
|
report.updated[t.label] = updateDir(t.target, t.source, t.pattern);
|
|
2307
2345
|
report.pruned[t.label] = pruneOrphans(t.target, t.source, t.pattern);
|
|
2308
2346
|
}
|
|
2309
|
-
const claudeMd =
|
|
2310
|
-
const templateMd =
|
|
2311
|
-
if (
|
|
2347
|
+
const claudeMd = join10(claudeDir, "CLAUDE.md");
|
|
2348
|
+
const templateMd = join10(templatesDir, "CLAUDE.md");
|
|
2349
|
+
if (existsSync11(claudeMd) && existsSync11(templateMd)) {
|
|
2312
2350
|
copyFileSync2(templateMd, claudeMd);
|
|
2313
2351
|
report.claudeMdUpdated = true;
|
|
2314
2352
|
}
|
|
2315
|
-
const settingsPath =
|
|
2316
|
-
if (
|
|
2317
|
-
report.staleHookRefs = cleanStaleHookRefs(settingsPath,
|
|
2353
|
+
const settingsPath = join10(claudeDir, "settings.json");
|
|
2354
|
+
if (existsSync11(settingsPath)) {
|
|
2355
|
+
report.staleHookRefs = cleanStaleHookRefs(settingsPath, join10(claudeDir, "hooks"));
|
|
2318
2356
|
}
|
|
2319
2357
|
return report;
|
|
2320
2358
|
}
|
|
2321
2359
|
function updateDir(target, source, ext) {
|
|
2322
|
-
if (!
|
|
2360
|
+
if (!existsSync11(target) || !existsSync11(source)) return 0;
|
|
2323
2361
|
let count = 0;
|
|
2324
2362
|
for (const file of readdirSync2(target)) {
|
|
2325
2363
|
if (!file.endsWith(ext)) continue;
|
|
2326
|
-
const targetFile =
|
|
2327
|
-
const sourceFile =
|
|
2328
|
-
if (
|
|
2364
|
+
const targetFile = join10(target, file);
|
|
2365
|
+
const sourceFile = join10(source, file);
|
|
2366
|
+
if (existsSync11(sourceFile)) {
|
|
2329
2367
|
copyFileSync2(sourceFile, targetFile);
|
|
2330
2368
|
count++;
|
|
2331
2369
|
}
|
|
@@ -2333,13 +2371,13 @@ function updateDir(target, source, ext) {
|
|
|
2333
2371
|
return count;
|
|
2334
2372
|
}
|
|
2335
2373
|
function pruneOrphans(target, source, ext) {
|
|
2336
|
-
if (!
|
|
2374
|
+
if (!existsSync11(target) || !existsSync11(source)) return [];
|
|
2337
2375
|
const removed = [];
|
|
2338
2376
|
for (const file of readdirSync2(target)) {
|
|
2339
2377
|
if (!file.endsWith(ext)) continue;
|
|
2340
|
-
const sourceFile =
|
|
2341
|
-
if (!
|
|
2342
|
-
const targetFile =
|
|
2378
|
+
const sourceFile = join10(source, file);
|
|
2379
|
+
if (!existsSync11(sourceFile)) {
|
|
2380
|
+
const targetFile = join10(target, file);
|
|
2343
2381
|
try {
|
|
2344
2382
|
unlinkSync(targetFile);
|
|
2345
2383
|
removed.push(file);
|
|
@@ -2380,7 +2418,7 @@ function keepHookRef(hook, hooksDir, removed) {
|
|
|
2380
2418
|
const refMatch = (hook?.command ?? "").match(/\/\.claude\/hooks\/([^"\s/]+\.sh)/);
|
|
2381
2419
|
if (!refMatch?.[1]) return true;
|
|
2382
2420
|
const fname = refMatch[1];
|
|
2383
|
-
const exists =
|
|
2421
|
+
const exists = existsSync11(join10(hooksDir, fname));
|
|
2384
2422
|
if (!exists && !removed.includes(fname)) removed.push(fname);
|
|
2385
2423
|
return exists;
|
|
2386
2424
|
}
|
|
@@ -2391,12 +2429,12 @@ var KARPATHY_ASSET_ID = "karpathy-coder";
|
|
|
2391
2429
|
function runInstall(ctx) {
|
|
2392
2430
|
const { harnessRoot, projectDir, spec } = ctx;
|
|
2393
2431
|
const mode = ctx.mode ?? "fresh";
|
|
2394
|
-
const templatesDir =
|
|
2395
|
-
if (!
|
|
2432
|
+
const templatesDir = join11(harnessRoot, "templates");
|
|
2433
|
+
if (!existsSync12(templatesDir)) {
|
|
2396
2434
|
throw new Error(`Templates dir not found: ${templatesDir}`);
|
|
2397
2435
|
}
|
|
2398
|
-
const claudeDir =
|
|
2399
|
-
if (mode === "update" && !
|
|
2436
|
+
const claudeDir = join11(projectDir, ".claude");
|
|
2437
|
+
if (mode === "update" && !existsSync12(claudeDir)) {
|
|
2400
2438
|
throw new Error(`Update mode requires existing .claude/ at ${claudeDir}`);
|
|
2401
2439
|
}
|
|
2402
2440
|
const backupPath = resolveBackupPath(ctx, mode, claudeDir);
|
|
@@ -2406,6 +2444,11 @@ function runInstall(ctx) {
|
|
|
2406
2444
|
const manifestSpec = buildManifestSpec(spec);
|
|
2407
2445
|
const base = spec.cli.includes("claude") ? installClaudeBaseline(manifestSpec, projectDir, templatesDir) : emptyClaudeBaseline();
|
|
2408
2446
|
const mcpResult = composeAndWriteMcp(harnessRoot, projectDir, spec);
|
|
2447
|
+
const ciScaffold = isAssetSelected("ci-scaffold", {
|
|
2448
|
+
tracks: spec.tracks,
|
|
2449
|
+
options: spec.options,
|
|
2450
|
+
...spec.userOverride ? { userOverride: spec.userOverride } : {}
|
|
2451
|
+
}) ? installCiScaffold({ harnessRoot, projectDir, tracks: spec.tracks }) : null;
|
|
2409
2452
|
const baseline = {
|
|
2410
2453
|
filesCopied: base.filesCopied,
|
|
2411
2454
|
dirsCopied: base.dirsCopied,
|
|
@@ -2414,6 +2457,7 @@ function runInstall(ctx) {
|
|
|
2414
2457
|
installedTracks: [...spec.tracks].sort(),
|
|
2415
2458
|
mcpServers: Object.keys(mcpResult.mcpServers).sort(),
|
|
2416
2459
|
...runCliTransforms(spec, harnessRoot, projectDir, manifestSpec.selectedInternalSkills),
|
|
2460
|
+
ciScaffold,
|
|
2417
2461
|
updateMode: null,
|
|
2418
2462
|
mode,
|
|
2419
2463
|
envFiles: writeEnvironmentFiles(projectDir, spec.tracks),
|
|
@@ -2445,6 +2489,7 @@ function runUpdateInstall(ctx, templatesDir, backupPath) {
|
|
|
2445
2489
|
codexOptIn: null,
|
|
2446
2490
|
opencode: null,
|
|
2447
2491
|
antigravity: null,
|
|
2492
|
+
ciScaffold: null,
|
|
2448
2493
|
updateMode: updateReport,
|
|
2449
2494
|
mode: "update",
|
|
2450
2495
|
envFiles: {
|
|
@@ -2498,9 +2543,9 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir) {
|
|
|
2498
2543
|
if (!entry.applies(manifestSpec)) {
|
|
2499
2544
|
continue;
|
|
2500
2545
|
}
|
|
2501
|
-
const source =
|
|
2502
|
-
const target =
|
|
2503
|
-
if (!
|
|
2546
|
+
const source = join11(templatesDir, entry.source);
|
|
2547
|
+
const target = join11(projectDir, entry.target);
|
|
2548
|
+
if (!existsSync12(source)) {
|
|
2504
2549
|
result.skipped += 1;
|
|
2505
2550
|
continue;
|
|
2506
2551
|
}
|
|
@@ -2519,8 +2564,8 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir) {
|
|
|
2519
2564
|
}
|
|
2520
2565
|
accumulateCategory(result.categories, entry);
|
|
2521
2566
|
}
|
|
2522
|
-
const hookDir =
|
|
2523
|
-
if (
|
|
2567
|
+
const hookDir = join11(projectDir, ".claude/hooks");
|
|
2568
|
+
if (existsSync12(hookDir)) {
|
|
2524
2569
|
chmodHooksSync(hookDir);
|
|
2525
2570
|
}
|
|
2526
2571
|
writeInstalledTracks(projectDir, manifestSpec.tracks);
|
|
@@ -2630,10 +2675,10 @@ function wireKarpathyHook(spec, external, harnessRoot, projectDir) {
|
|
|
2630
2675
|
if (!karpathyResult?.ok) {
|
|
2631
2676
|
return { wired: false, reason: "plugin-install-failed" };
|
|
2632
2677
|
}
|
|
2633
|
-
const sourceHook =
|
|
2634
|
-
const targetHook =
|
|
2678
|
+
const sourceHook = join11(harnessRoot, "templates/hooks/karpathy-gate.sh");
|
|
2679
|
+
const targetHook = join11(projectDir, ".claude/hooks/karpathy-gate.sh");
|
|
2635
2680
|
let hookScriptCopied = false;
|
|
2636
|
-
if (
|
|
2681
|
+
if (existsSync12(sourceHook)) {
|
|
2637
2682
|
copyFile(sourceHook, targetHook);
|
|
2638
2683
|
try {
|
|
2639
2684
|
chmodSync2(targetHook, 493);
|
|
@@ -2641,9 +2686,9 @@ function wireKarpathyHook(spec, external, harnessRoot, projectDir) {
|
|
|
2641
2686
|
}
|
|
2642
2687
|
hookScriptCopied = true;
|
|
2643
2688
|
}
|
|
2644
|
-
const settingsPath =
|
|
2689
|
+
const settingsPath = join11(projectDir, ".claude/settings.json");
|
|
2645
2690
|
let settingsUpdated = false;
|
|
2646
|
-
if (
|
|
2691
|
+
if (existsSync12(settingsPath)) {
|
|
2647
2692
|
const raw = readFileSync11(settingsPath, "utf8");
|
|
2648
2693
|
let before;
|
|
2649
2694
|
try {
|
|
@@ -2663,10 +2708,10 @@ function wireKarpathyHook(spec, external, harnessRoot, projectDir) {
|
|
|
2663
2708
|
return { wired: true, settingsUpdated, hookScriptCopied };
|
|
2664
2709
|
}
|
|
2665
2710
|
function composeAndWriteMcp(harnessRoot, projectDir, spec) {
|
|
2666
|
-
const mcpPath =
|
|
2711
|
+
const mcpPath = join11(projectDir, ".mcp.json");
|
|
2667
2712
|
const composed = composeMcpJson({
|
|
2668
|
-
templateMcpPath:
|
|
2669
|
-
trackMapPath:
|
|
2713
|
+
templateMcpPath: join11(harnessRoot, "templates/mcp.json"),
|
|
2714
|
+
trackMapPath: join11(harnessRoot, "templates/track-mcp-map.tsv"),
|
|
2670
2715
|
existingPath: mcpPath,
|
|
2671
2716
|
tracks: spec.tracks
|
|
2672
2717
|
});
|
|
@@ -2692,7 +2737,7 @@ function accumulateCategory(cats, entry) {
|
|
|
2692
2737
|
}
|
|
2693
2738
|
}
|
|
2694
2739
|
function writeInstalledTracks(projectDir, tracks) {
|
|
2695
|
-
const path =
|
|
2740
|
+
const path = join11(projectDir, ".claude/.installed-tracks");
|
|
2696
2741
|
mkdirSync4(dirname4(path), { recursive: true });
|
|
2697
2742
|
const sorted = [...new Set(tracks)].sort().join("\n");
|
|
2698
2743
|
writeFileSync9(path, `${sorted}
|
|
@@ -2700,7 +2745,7 @@ function writeInstalledTracks(projectDir, tracks) {
|
|
|
2700
2745
|
}
|
|
2701
2746
|
function writeRootClaudeMd(projectDir, tracks) {
|
|
2702
2747
|
const content = mergeProjectClaude(tracks, { projectName: basename4(projectDir) });
|
|
2703
|
-
const target =
|
|
2748
|
+
const target = join11(projectDir, "CLAUDE.md");
|
|
2704
2749
|
const backup = backupFileIfChanged(target, content);
|
|
2705
2750
|
writeFileSync9(target, content);
|
|
2706
2751
|
return { content, backup };
|
|
@@ -2722,8 +2767,8 @@ init_esm_shims();
|
|
|
2722
2767
|
|
|
2723
2768
|
// src/context-cost.ts
|
|
2724
2769
|
init_esm_shims();
|
|
2725
|
-
import { existsSync as
|
|
2726
|
-
import { join as
|
|
2770
|
+
import { existsSync as existsSync13, readFileSync as readFileSync12 } from "fs";
|
|
2771
|
+
import { join as join12, resolve as resolve2 } from "path";
|
|
2727
2772
|
import { fileURLToPath } from "url";
|
|
2728
2773
|
var CHARS_PER_TOKEN = 4;
|
|
2729
2774
|
function estimateTokens(chars) {
|
|
@@ -2739,8 +2784,8 @@ function extractFrontmatter(content) {
|
|
|
2739
2784
|
function assetDescriptorTokens(assetId, root = resolveBundleRoot()) {
|
|
2740
2785
|
const asset = EXTERNAL_ASSETS.find((a) => a.id === assetId);
|
|
2741
2786
|
if (!asset || asset.method.kind !== "internal") return null;
|
|
2742
|
-
const skillMd =
|
|
2743
|
-
if (!
|
|
2787
|
+
const skillMd = join12(root, "templates", "skills", asset.method.key, "SKILL.md");
|
|
2788
|
+
if (!existsSync13(skillMd)) return null;
|
|
2744
2789
|
const fm = extractFrontmatter(readFileSync12(skillMd, "utf8"));
|
|
2745
2790
|
return fm === null ? null : estimateTokens(fm.length);
|
|
2746
2791
|
}
|
|
@@ -3139,6 +3184,14 @@ function renderPhase1Rows(log, baseline, verbose = false, withEcc = false, claud
|
|
|
3139
3184
|
)
|
|
3140
3185
|
);
|
|
3141
3186
|
}
|
|
3187
|
+
if (baseline.ciScaffold) {
|
|
3188
|
+
for (const f of baseline.ciScaffold.written) {
|
|
3189
|
+
log(assetRow("success", f, "CI scaffold (fill-in template)", TEMPLATES_COL));
|
|
3190
|
+
}
|
|
3191
|
+
for (const f of baseline.ciScaffold.skippedExisting) {
|
|
3192
|
+
log(assetRow("skip", f, "exists \u2014 preserved (no overwrite)", TEMPLATES_COL));
|
|
3193
|
+
}
|
|
3194
|
+
}
|
|
3142
3195
|
if (baseline.skipped > 0) {
|
|
3143
3196
|
log(
|
|
3144
3197
|
assetRow(
|
|
@@ -3403,8 +3456,8 @@ function registerInstallCommand(cli2) {
|
|
|
3403
3456
|
// src/commands/uninstall.ts
|
|
3404
3457
|
init_esm_shims();
|
|
3405
3458
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
3406
|
-
import { existsSync as
|
|
3407
|
-
import { join as
|
|
3459
|
+
import { existsSync as existsSync14, readFileSync as readFileSync13, rmSync } from "fs";
|
|
3460
|
+
import { join as join13, resolve as resolve4 } from "path";
|
|
3408
3461
|
function uninstallAction(options, deps = {}) {
|
|
3409
3462
|
const log = deps.log ?? console.log;
|
|
3410
3463
|
const err = deps.err ?? console.error;
|
|
@@ -3576,21 +3629,21 @@ function buildGlobalAdvisoryCmd(asset) {
|
|
|
3576
3629
|
}
|
|
3577
3630
|
}
|
|
3578
3631
|
function removeTemplates(log, projectDir, rm) {
|
|
3579
|
-
rm(
|
|
3580
|
-
if (log.templates.codexDir) rm(
|
|
3581
|
-
if (log.templates.opencodeDir) rm(
|
|
3632
|
+
rm(join13(projectDir, log.templates.claudeDir));
|
|
3633
|
+
if (log.templates.codexDir) rm(join13(projectDir, log.templates.codexDir));
|
|
3634
|
+
if (log.templates.opencodeDir) rm(join13(projectDir, log.templates.opencodeDir));
|
|
3582
3635
|
const rootMd = log.templates.rootClaudeMd;
|
|
3583
3636
|
if (rootMd) {
|
|
3584
3637
|
if (rootClaudeMdModified(log, projectDir)) return { rootClaudeMdKept: true };
|
|
3585
|
-
rm(
|
|
3638
|
+
rm(join13(projectDir, rootMd.path));
|
|
3586
3639
|
}
|
|
3587
3640
|
return { rootClaudeMdKept: false };
|
|
3588
3641
|
}
|
|
3589
3642
|
function rootClaudeMdModified(log, projectDir) {
|
|
3590
3643
|
const rootMd = log.templates.rootClaudeMd;
|
|
3591
3644
|
if (!rootMd) return false;
|
|
3592
|
-
const path =
|
|
3593
|
-
if (!
|
|
3645
|
+
const path = join13(projectDir, rootMd.path);
|
|
3646
|
+
if (!existsSync14(path)) return false;
|
|
3594
3647
|
return hashContent(readFileSync13(path, "utf8")) !== rootMd.sha256;
|
|
3595
3648
|
}
|
|
3596
3649
|
function formatTemplateList(log) {
|
|
@@ -3603,7 +3656,7 @@ function defaultSpawn2(cmd, args) {
|
|
|
3603
3656
|
return spawnSync2(cmd, [...args], { encoding: "utf8", stdio: "pipe", timeout: 12e4 });
|
|
3604
3657
|
}
|
|
3605
3658
|
function defaultRm(path) {
|
|
3606
|
-
if (
|
|
3659
|
+
if (existsSync14(path)) {
|
|
3607
3660
|
rmSync(path, { recursive: true, force: true });
|
|
3608
3661
|
}
|
|
3609
3662
|
}
|
|
@@ -4897,8 +4950,8 @@ Proceed?`,
|
|
|
4897
4950
|
|
|
4898
4951
|
// src/state.ts
|
|
4899
4952
|
init_esm_shims();
|
|
4900
|
-
import { existsSync as
|
|
4901
|
-
import { join as
|
|
4953
|
+
import { existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
|
|
4954
|
+
import { join as join14 } from "path";
|
|
4902
4955
|
var META_FILE = ".claude/.installed-tracks";
|
|
4903
4956
|
var LEGACY_SIGNATURES = [
|
|
4904
4957
|
{ rule: "htmx.md", track: "ssr-htmx" },
|
|
@@ -4908,13 +4961,13 @@ var LEGACY_SIGNATURES = [
|
|
|
4908
4961
|
{ rule: "cli-development.md", track: "tooling" }
|
|
4909
4962
|
];
|
|
4910
4963
|
function detectInstallState(projectDir) {
|
|
4911
|
-
const claudeDir =
|
|
4912
|
-
const hasClaudeDir =
|
|
4964
|
+
const claudeDir = join14(projectDir, ".claude");
|
|
4965
|
+
const hasClaudeDir = existsSync15(claudeDir);
|
|
4913
4966
|
if (!hasClaudeDir) {
|
|
4914
4967
|
return { state: "new", tracks: [], source: "none", hasClaudeDir: false };
|
|
4915
4968
|
}
|
|
4916
|
-
const metaPath =
|
|
4917
|
-
if (
|
|
4969
|
+
const metaPath = join14(projectDir, META_FILE);
|
|
4970
|
+
if (existsSync15(metaPath)) {
|
|
4918
4971
|
const tracks2 = readMetafile(metaPath);
|
|
4919
4972
|
return { state: "existing", tracks: tracks2, source: "metafile", hasClaudeDir: true };
|
|
4920
4973
|
}
|
|
@@ -4933,13 +4986,13 @@ function readMetafile(path) {
|
|
|
4933
4986
|
return [...seen].sort();
|
|
4934
4987
|
}
|
|
4935
4988
|
function inferFromLegacySignatures(projectDir) {
|
|
4936
|
-
const rulesDir =
|
|
4937
|
-
if (!
|
|
4989
|
+
const rulesDir = join14(projectDir, ".claude/rules");
|
|
4990
|
+
if (!existsSync15(rulesDir)) {
|
|
4938
4991
|
return [];
|
|
4939
4992
|
}
|
|
4940
4993
|
const found = /* @__PURE__ */ new Set();
|
|
4941
4994
|
for (const sig of LEGACY_SIGNATURES) {
|
|
4942
|
-
if (
|
|
4995
|
+
if (existsSync15(join14(rulesDir, sig.rule))) {
|
|
4943
4996
|
found.add(sig.track);
|
|
4944
4997
|
}
|
|
4945
4998
|
}
|