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