stack-cleaner 1.1.5 → 1.2.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/package.json +1 -1
- package/public/scan.mjs +31 -0
package/package.json
CHANGED
package/public/scan.mjs
CHANGED
|
@@ -397,6 +397,35 @@ function buildProjectLabels(paths) {
|
|
|
397
397
|
return labels;
|
|
398
398
|
}
|
|
399
399
|
|
|
400
|
+
// Enumerate what an installed plugin bundles, by reading its on-disk dir:
|
|
401
|
+
// <installDir>/skills/<name>/SKILL.md → skill names
|
|
402
|
+
// <installDir>/agents/<name>.md → agent names
|
|
403
|
+
// <installDir>/.mcp.json mcpServers → mcp server names
|
|
404
|
+
// Names only — no contents. Returns undefined when nothing is found.
|
|
405
|
+
export function collectPluginBundles(installDir) {
|
|
406
|
+
if (!installDir || !exists(installDir)) return undefined;
|
|
407
|
+
const skills = [];
|
|
408
|
+
const skillsDir = path.join(installDir, "skills");
|
|
409
|
+
for (const d of listDir(skillsDir, "dir")) {
|
|
410
|
+
if (exists(path.join(skillsDir, d, "SKILL.md"))) skills.push(d);
|
|
411
|
+
}
|
|
412
|
+
const agents = [];
|
|
413
|
+
const agentsDir = path.join(installDir, "agents");
|
|
414
|
+
for (const f of listDir(agentsDir, "file")) {
|
|
415
|
+
if (f.endsWith(".md")) agents.push(f.replace(/\.md$/, ""));
|
|
416
|
+
}
|
|
417
|
+
const mcps = [];
|
|
418
|
+
const mcpCfg = readJSON(path.join(installDir, ".mcp.json"));
|
|
419
|
+
if (mcpCfg && mcpCfg.mcpServers && typeof mcpCfg.mcpServers === "object") {
|
|
420
|
+
for (const name of Object.keys(mcpCfg.mcpServers)) mcps.push(name);
|
|
421
|
+
}
|
|
422
|
+
const out = {};
|
|
423
|
+
if (skills.length) out.skills = skills;
|
|
424
|
+
if (agents.length) out.agents = agents;
|
|
425
|
+
if (mcps.length) out.mcps = mcps;
|
|
426
|
+
return Object.keys(out).length ? out : undefined;
|
|
427
|
+
}
|
|
428
|
+
|
|
400
429
|
// ---------- inventory build ----------
|
|
401
430
|
// Collects every skill / agent / plugin / MCP item from the local install,
|
|
402
431
|
// optionally overlays transcript usage, and returns the inventory OBJECT.
|
|
@@ -504,6 +533,7 @@ export async function buildInventory(opts = {}) {
|
|
|
504
533
|
const installPath = entry && entry.installPath
|
|
505
534
|
? (entry.installPath.startsWith(HOME) ? tilde(entry.installPath) : "<external>")
|
|
506
535
|
: undefined;
|
|
536
|
+
const bundles = entry && entry.installPath ? collectPluginBundles(entry.installPath) : undefined;
|
|
507
537
|
items.push({
|
|
508
538
|
// Bare name; the marketplace lives in `source` (matches the demo shape).
|
|
509
539
|
id: `plugin:global:${pluginName}`,
|
|
@@ -513,6 +543,7 @@ export async function buildInventory(opts = {}) {
|
|
|
513
543
|
source: marketplace || "",
|
|
514
544
|
version: entry ? entry.version : undefined,
|
|
515
545
|
path: installPath,
|
|
546
|
+
bundles,
|
|
516
547
|
usageCount, lastUsedAt, usageClass,
|
|
517
548
|
usageLabel: usageLabel(usageCount, lastUsedAt, usageClass),
|
|
518
549
|
// The CLI wants the full name@marketplace form to uninstall.
|