@overscore/cli 0.11.7 → 0.11.10
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 +132 -2
- package/package.json +1 -1
- package/templates/analysis/.claude/CLAUDE.md +1 -0
package/dist/index.js
CHANGED
|
@@ -1171,6 +1171,9 @@ async function syncHubManagedRules(targetDir, baseUrl, projectSlug, apiKey) {
|
|
|
1171
1171
|
catch {
|
|
1172
1172
|
// Non-fatal
|
|
1173
1173
|
}
|
|
1174
|
+
// Platform rules (skills, capabilities) — same sync that dashboard pull/deploy gets.
|
|
1175
|
+
await syncPlatformRules(targetDir, baseUrl, apiKey);
|
|
1176
|
+
syncClaudeMdImports(targetDir);
|
|
1174
1177
|
}
|
|
1175
1178
|
/**
|
|
1176
1179
|
* Sync the project knowledge base from the Hub into .claude/knowledge/.
|
|
@@ -1269,6 +1272,41 @@ async function uploadKnowledgeBase(targetDir, baseUrl, projectSlug, apiKey) {
|
|
|
1269
1272
|
* User-owned files (company-context.md, this-dashboard.md, knowledge/)
|
|
1270
1273
|
* are NOT touched — those sync via separate mechanisms.
|
|
1271
1274
|
*/
|
|
1275
|
+
const DASHBOARD_IMPORTS = [
|
|
1276
|
+
"@.claude/rules/this-dashboard.md",
|
|
1277
|
+
"@.claude/knowledge/INDEX.md",
|
|
1278
|
+
"@.claude/platform-capabilities.md",
|
|
1279
|
+
];
|
|
1280
|
+
const ANALYSIS_IMPORTS = [
|
|
1281
|
+
"@this-analysis.md",
|
|
1282
|
+
"@.claude/knowledge/INDEX.md",
|
|
1283
|
+
"@.claude/platform-capabilities.md",
|
|
1284
|
+
];
|
|
1285
|
+
/**
|
|
1286
|
+
* Ensures the project's CLAUDE.md has the standard @import lines at the top.
|
|
1287
|
+
* Detects dashboard vs analysis by file presence. Injects only what's missing —
|
|
1288
|
+
* never overwrites existing content. Returns true if CLAUDE.md was modified.
|
|
1289
|
+
*/
|
|
1290
|
+
function syncClaudeMdImports(targetDir) {
|
|
1291
|
+
const claudeMdPath = path.join(targetDir, ".claude", "CLAUDE.md");
|
|
1292
|
+
if (!fs.existsSync(claudeMdPath))
|
|
1293
|
+
return false;
|
|
1294
|
+
const isAnalysis = fs.existsSync(path.join(targetDir, "analysis-log.md"));
|
|
1295
|
+
const requiredImports = isAnalysis ? ANALYSIS_IMPORTS : DASHBOARD_IMPORTS;
|
|
1296
|
+
let content = fs.readFileSync(claudeMdPath, "utf-8");
|
|
1297
|
+
const missing = requiredImports.filter((imp) => !content.includes(imp));
|
|
1298
|
+
if (missing.length === 0)
|
|
1299
|
+
return false;
|
|
1300
|
+
// Inject missing imports right after the first # heading line
|
|
1301
|
+
const lines = content.split("\n");
|
|
1302
|
+
const headingIdx = lines.findIndex((l) => l.startsWith("# "));
|
|
1303
|
+
if (headingIdx === -1)
|
|
1304
|
+
return false;
|
|
1305
|
+
lines.splice(headingIdx + 1, 0, "", ...missing);
|
|
1306
|
+
const updated = lines.join("\n").replace(/\n{3,}/g, "\n\n");
|
|
1307
|
+
fs.writeFileSync(claudeMdPath, updated);
|
|
1308
|
+
return true;
|
|
1309
|
+
}
|
|
1272
1310
|
async function syncPlatformRules(targetDir, baseUrl, apiKey) {
|
|
1273
1311
|
try {
|
|
1274
1312
|
const res = await fetch(`${baseUrl}/api/projects/platform-rules`, {
|
|
@@ -1286,14 +1324,85 @@ async function syncPlatformRules(targetDir, baseUrl, apiKey) {
|
|
|
1286
1324
|
fs.writeFileSync(fullPath, content);
|
|
1287
1325
|
count++;
|
|
1288
1326
|
}
|
|
1289
|
-
|
|
1290
|
-
|
|
1327
|
+
const claudeUpdated = syncClaudeMdImports(targetDir);
|
|
1328
|
+
const total = count + (claudeUpdated ? 1 : 0);
|
|
1329
|
+
if (total > 0) {
|
|
1330
|
+
console.log(` Platform rules synced (${count} files${claudeUpdated ? " + CLAUDE.md updated" : ""}).`);
|
|
1291
1331
|
}
|
|
1292
1332
|
}
|
|
1293
1333
|
catch {
|
|
1294
1334
|
// Non-fatal — existing rules stay in place
|
|
1295
1335
|
}
|
|
1296
1336
|
}
|
|
1337
|
+
/**
|
|
1338
|
+
* Explicit on-demand platform rules sync. Reports what changed so Claude
|
|
1339
|
+
* can tell the user what's new. Called by `npx @overscore/cli platform update`.
|
|
1340
|
+
*/
|
|
1341
|
+
async function platformUpdate() {
|
|
1342
|
+
const { apiUrl, apiKey } = await loadEnv();
|
|
1343
|
+
const baseUrl = apiUrl.replace(/\/api$/, "");
|
|
1344
|
+
console.log("\n Syncing platform rules from Hub...\n");
|
|
1345
|
+
const capPath = path.resolve(process.cwd(), ".claude", "platform-capabilities.md");
|
|
1346
|
+
const prevContent = fs.existsSync(capPath) ? fs.readFileSync(capPath, "utf-8") : null;
|
|
1347
|
+
const prevVersion = prevContent?.match(/^version:\s*(.+)$/m)?.[1]?.trim() ?? null;
|
|
1348
|
+
const res = await fetch(`${baseUrl}/api/projects/platform-rules`, {
|
|
1349
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
1350
|
+
});
|
|
1351
|
+
if (!res.ok) {
|
|
1352
|
+
console.error(`\n Error: Could not reach Hub (HTTP ${res.status})\n`);
|
|
1353
|
+
process.exit(1);
|
|
1354
|
+
}
|
|
1355
|
+
const data = (await res.json());
|
|
1356
|
+
if (!data.files) {
|
|
1357
|
+
console.error("\n Error: No files in platform-rules response.\n");
|
|
1358
|
+
process.exit(1);
|
|
1359
|
+
}
|
|
1360
|
+
const updated = [];
|
|
1361
|
+
for (const [relPath, content] of Object.entries(data.files)) {
|
|
1362
|
+
const fullPath = path.join(process.cwd(), ".claude", relPath);
|
|
1363
|
+
const existing = fs.existsSync(fullPath) ? fs.readFileSync(fullPath, "utf-8") : null;
|
|
1364
|
+
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
1365
|
+
fs.writeFileSync(fullPath, content);
|
|
1366
|
+
if (existing !== content)
|
|
1367
|
+
updated.push(relPath);
|
|
1368
|
+
}
|
|
1369
|
+
const claudeUpdated = syncClaudeMdImports(process.cwd());
|
|
1370
|
+
if (claudeUpdated)
|
|
1371
|
+
updated.push(".claude/CLAUDE.md (@imports updated)");
|
|
1372
|
+
if (updated.length === 0) {
|
|
1373
|
+
console.log(" Already up to date — no changes.\n");
|
|
1374
|
+
return;
|
|
1375
|
+
}
|
|
1376
|
+
console.log(` Updated ${updated.length} file${updated.length === 1 ? "" : "s"}:\n`);
|
|
1377
|
+
for (const f of updated)
|
|
1378
|
+
console.log(` ${f}`);
|
|
1379
|
+
if (updated.includes("platform-capabilities.md")) {
|
|
1380
|
+
const newContent = data.files["platform-capabilities.md"];
|
|
1381
|
+
const newVersion = newContent.match(/^version:\s*(.+)$/m)?.[1]?.trim() ?? "unknown";
|
|
1382
|
+
if (prevVersion && prevVersion !== newVersion) {
|
|
1383
|
+
console.log(`\n Capabilities updated: ${prevVersion} → ${newVersion}`);
|
|
1384
|
+
const changelog = extractChangelogSince(newContent, prevVersion);
|
|
1385
|
+
if (changelog)
|
|
1386
|
+
console.log(`\n What's new:\n\n${changelog}`);
|
|
1387
|
+
}
|
|
1388
|
+
else if (!prevVersion) {
|
|
1389
|
+
console.log(`\n Platform capabilities synced (v${newVersion}).`);
|
|
1390
|
+
console.log(` Re-read .claude/platform-capabilities.md in your Claude session to see available commands.`);
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
console.log();
|
|
1394
|
+
}
|
|
1395
|
+
function extractChangelogSince(content, sinceVersion) {
|
|
1396
|
+
const match = content.match(/## Changelog\n([\s\S]*?)(?=\n## |\s*$)/);
|
|
1397
|
+
if (!match)
|
|
1398
|
+
return null;
|
|
1399
|
+
const blocks = match[1].split(/(?=### )/);
|
|
1400
|
+
const newer = blocks.filter((b) => {
|
|
1401
|
+
const v = b.match(/### (\d{4}-\d{2}-\d{2})/)?.[1];
|
|
1402
|
+
return v && v > sinceVersion;
|
|
1403
|
+
});
|
|
1404
|
+
return newer.length ? newer.join("").trim() : null;
|
|
1405
|
+
}
|
|
1297
1406
|
/**
|
|
1298
1407
|
* Recursively copies a template directory to a target directory, substituting
|
|
1299
1408
|
* `{{KEY}}` placeholders in text files. Mirrors directory structure.
|
|
@@ -1616,6 +1725,9 @@ async function analysisPublish() {
|
|
|
1616
1725
|
console.log(`\n URL: ${data.url}\n`);
|
|
1617
1726
|
// Upload knowledge base so insights from this analysis persist
|
|
1618
1727
|
await uploadKnowledgeBase(process.cwd(), baseUrl, meta.project_slug, cfg.apiKey);
|
|
1728
|
+
// Sync platform rules so skills and capabilities stay current
|
|
1729
|
+
await syncPlatformRules(process.cwd(), baseUrl, cfg.apiKey);
|
|
1730
|
+
syncClaudeMdImports(process.cwd());
|
|
1619
1731
|
}
|
|
1620
1732
|
/**
|
|
1621
1733
|
* Ensure analysis.json has a valid id by fetching from the Hub.
|
|
@@ -2281,6 +2393,22 @@ else if (command === "analysis") {
|
|
|
2281
2393
|
`);
|
|
2282
2394
|
}
|
|
2283
2395
|
}
|
|
2396
|
+
else if (command === "platform") {
|
|
2397
|
+
if (subcommand === "update") {
|
|
2398
|
+
platformUpdate();
|
|
2399
|
+
}
|
|
2400
|
+
else {
|
|
2401
|
+
console.log(`
|
|
2402
|
+
overscore platform — Manage platform rules and capabilities
|
|
2403
|
+
|
|
2404
|
+
Commands:
|
|
2405
|
+
update Sync latest platform rules, skills, and capabilities from Hub
|
|
2406
|
+
|
|
2407
|
+
Example:
|
|
2408
|
+
npx @overscore/cli platform update
|
|
2409
|
+
`);
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2284
2412
|
else if (command === "query") {
|
|
2285
2413
|
if (subcommand === "list") {
|
|
2286
2414
|
queryList();
|
|
@@ -2339,6 +2467,7 @@ else {
|
|
|
2339
2467
|
pull <slug> Pull source code from the hub
|
|
2340
2468
|
versions List deploy history
|
|
2341
2469
|
query <subcommand> Manage dashboard queries
|
|
2470
|
+
platform <subcommand> Sync platform rules and capabilities
|
|
2342
2471
|
analysis <subcommand> Manage analyses (frozen investigations)
|
|
2343
2472
|
install-skills Install the Overscore skill library into ~/.claude/skills/
|
|
2344
2473
|
|
|
@@ -2350,6 +2479,7 @@ else {
|
|
|
2350
2479
|
npx @overscore/cli pull <slug>
|
|
2351
2480
|
npx @overscore/cli pull <slug> --version 3
|
|
2352
2481
|
npx @overscore/cli versions
|
|
2482
|
+
npx @overscore/cli platform update
|
|
2353
2483
|
npx @overscore/cli query list
|
|
2354
2484
|
npx @overscore/cli query add <name> "<sql>"
|
|
2355
2485
|
npx @overscore/cli query update <name> "<sql>"
|
package/package.json
CHANGED