@gobing-ai/superskill 0.1.4 → 0.1.6

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.
Files changed (3) hide show
  1. package/README.md +73 -12
  2. package/dist/index.js +701 -420
  3. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -9378,8 +9378,339 @@ function getProposalsDir(opts) {
9378
9378
  return join2(getDataRoot(opts), ".superskill", "proposals");
9379
9379
  }
9380
9380
  var init_paths = () => {};
9381
+ // ../../packages/core/src/pipeline/frontmatter-walk.ts
9382
+ function walkFrontmatter(content, opts) {
9383
+ const lines = content.split(`
9384
+ `);
9385
+ const out = [];
9386
+ const seenInBlock = [];
9387
+ let inFrontmatter = false;
9388
+ let pastOpener = false;
9389
+ let injectedName = false;
9390
+ for (const line of lines) {
9391
+ if (!pastOpener) {
9392
+ if (line.trim() === "---") {
9393
+ inFrontmatter = true;
9394
+ pastOpener = true;
9395
+ out.push(line);
9396
+ out.push(`name: ${opts.expectedName}`);
9397
+ injectedName = true;
9398
+ continue;
9399
+ }
9400
+ out.push(line);
9401
+ continue;
9402
+ }
9403
+ if (inFrontmatter) {
9404
+ if (line.trim() === "---") {
9405
+ if (opts.closerInjection?.shouldInject(seenInBlock)) {
9406
+ out.push(...opts.closerInjection.lines);
9407
+ }
9408
+ inFrontmatter = false;
9409
+ out.push(line);
9410
+ continue;
9411
+ }
9412
+ if (/^name:\s*/.test(line))
9413
+ continue;
9414
+ seenInBlock.push(line);
9415
+ const rule = opts.lineRules?.find((r) => r.test(line));
9416
+ if (rule) {
9417
+ const rewritten = rule.rewrite(line);
9418
+ if (rewritten !== null)
9419
+ out.push(rewritten);
9420
+ continue;
9421
+ }
9422
+ out.push(line);
9423
+ continue;
9424
+ }
9425
+ out.push(line);
9426
+ }
9427
+ if (!injectedName) {
9428
+ return `${opts.fallbackBlock}
9429
+
9430
+ ${content}`;
9431
+ }
9432
+ return out.join(`
9433
+ `);
9434
+ }
9435
+
9436
+ // ../../packages/core/src/pipeline/rewrite-references.ts
9437
+ function rewriteSkillReferences(content, pluginPrefix) {
9438
+ if (!pluginPrefix || !content)
9439
+ return content;
9440
+ const escaped = pluginPrefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9441
+ const re = new RegExp(`\\b(${escaped}):([a-z][a-z0-9-]*)`, "gi");
9442
+ return content.split(`
9443
+ `).map((line) => SLASH_COMMAND_LINE_RE.test(line) ? line : line.replace(re, "$1-$2")).join(`
9444
+ `);
9445
+ }
9446
+ var SLASH_COMMAND_LINE_RE;
9447
+ var init_rewrite_references = __esm(() => {
9448
+ SLASH_COMMAND_LINE_RE = /^\s*\/[a-zA-Z0-9._-]+:[a-zA-Z0-9._-]+(\s|$)/;
9449
+ });
9450
+
9451
+ // ../../packages/core/src/pipeline/adapt-command.ts
9452
+ function adaptCommandToSkill(source, expectedName, pluginPrefix) {
9453
+ let result;
9454
+ if (source.startsWith("---")) {
9455
+ result = normalizeCommandFrontmatter(source, expectedName);
9456
+ } else {
9457
+ const firstLine = source.split(`
9458
+ `).slice(0, 5).find((l) => l.trim() && !l.startsWith("#"));
9459
+ const description = firstLine?.trim() || `${expectedName} command`;
9460
+ result = `---
9461
+ name: ${expectedName}
9462
+ description: "${description}"
9463
+ disable-model-invocation: true
9464
+ ---
9465
+
9466
+ ${source}`;
9467
+ }
9468
+ return rewriteSkillReferences(result, pluginPrefix);
9469
+ }
9470
+ function normalizeCommandFrontmatter(content, expectedName) {
9471
+ return walkFrontmatter(content, {
9472
+ expectedName,
9473
+ lineRules: [
9474
+ {
9475
+ test: (line) => /^argument-hint:\s*/.test(line),
9476
+ rewrite: (line) => `argument-hint: ${quoteYaml(line.slice(line.indexOf(":") + 1).trim())}`
9477
+ },
9478
+ {
9479
+ test: (line) => /^allowed-tools:\s*/.test(line),
9480
+ rewrite: (line) => {
9481
+ const value = line.slice(line.indexOf(":") + 1).trim();
9482
+ if (value.startsWith("["))
9483
+ return line;
9484
+ const parts = value.split(/,\s*/).map((p) => p.trim()).filter(Boolean);
9485
+ return `allowed-tools: [${parts.join(", ")}]`;
9486
+ }
9487
+ }
9488
+ ],
9489
+ closerInjection: {
9490
+ lines: ["disable-model-invocation: true"],
9491
+ shouldInject: (seen) => !seen.some((l) => /^disable-model-invocation:\s*/.test(l))
9492
+ },
9493
+ fallbackBlock: `---
9494
+ name: ${expectedName}
9495
+ disable-model-invocation: true
9496
+ ---`
9497
+ });
9498
+ }
9499
+ function quoteYaml(value) {
9500
+ const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
9501
+ return `"${escaped}"`;
9502
+ }
9503
+ var init_adapt_command = __esm(() => {
9504
+ init_rewrite_references();
9505
+ });
9506
+
9507
+ // ../../packages/core/src/pipeline/pi-tools.ts
9508
+ function expandPiToolName(raw) {
9509
+ const trimmed = raw.trim().replace(/^["']|["']$/g, "");
9510
+ if (DROPPED_TOOLS.has(trimmed))
9511
+ return "";
9512
+ if (trimmed.startsWith("mcp__") || trimmed.startsWith("mcp:"))
9513
+ return "mcp";
9514
+ return PI_TOOL_MAP[trimmed] ?? "";
9515
+ }
9516
+ function parseToolsList(raw) {
9517
+ const trimmed = raw.trim();
9518
+ const cleaned = trimmed.replace(/^\[|\]$/g, "");
9519
+ if (!cleaned.trim())
9520
+ return [];
9521
+ return cleaned.split(",").map((t) => t.trim()).filter(Boolean);
9522
+ }
9523
+ function normalizePiToolList(raw) {
9524
+ const parts = parseToolsList(raw);
9525
+ const mapped = [];
9526
+ for (const part of parts) {
9527
+ for (const token of expandPiToolName(part).split(",").map((t) => t.trim())) {
9528
+ if (token && !mapped.includes(token))
9529
+ mapped.push(token);
9530
+ }
9531
+ }
9532
+ return mapped.join(", ");
9533
+ }
9534
+ var PI_TOOL_MAP, DROPPED_TOOLS;
9535
+ var init_pi_tools = __esm(() => {
9536
+ PI_TOOL_MAP = {
9537
+ Read: "read",
9538
+ read: "read",
9539
+ Write: "write",
9540
+ write: "write",
9541
+ Edit: "edit",
9542
+ edit: "edit",
9543
+ Bash: "bash",
9544
+ bash: "bash",
9545
+ Grep: "grep",
9546
+ grep: "grep",
9547
+ Glob: "find, ls",
9548
+ glob: "find, ls",
9549
+ Find: "find",
9550
+ find: "find",
9551
+ Ls: "ls",
9552
+ LS: "ls",
9553
+ ls: "ls",
9554
+ Agent: "subagent",
9555
+ agent: "subagent",
9556
+ subagent: "subagent",
9557
+ WebSearch: "web_search, fetch_content, get_search_content",
9558
+ WebFetch: "web_search, fetch_content, get_search_content",
9559
+ web_search: "web_search",
9560
+ fetch_content: "fetch_content",
9561
+ get_search_content: "get_search_content",
9562
+ mcp: "mcp"
9563
+ };
9564
+ DROPPED_TOOLS = new Set(["Skill", "skill", "Task", "task", "AskUserQuestion", "askuserquestion"]);
9565
+ });
9566
+
9567
+ // ../../packages/core/src/pipeline/adapt-subagent.ts
9568
+ function asString(value) {
9569
+ if (typeof value === "string")
9570
+ return value;
9571
+ if (Array.isArray(value))
9572
+ return value.join(", ");
9573
+ return "";
9574
+ }
9575
+ function adaptSubagentToSkill(source, expectedName, pluginPrefix) {
9576
+ let result;
9577
+ if (source.startsWith("---")) {
9578
+ result = normalizeSubagentFrontmatter(source, expectedName);
9579
+ } else {
9580
+ const firstLine = source.split(`
9581
+ `).slice(0, 5).find((l) => l.trim() && !l.startsWith("#"));
9582
+ const description = firstLine?.trim() || `${expectedName} subagent`;
9583
+ result = `---
9584
+ name: ${expectedName}
9585
+ description: "${description}"
9586
+ ---
9587
+
9588
+ ${source}`;
9589
+ }
9590
+ return rewriteSkillReferences(result, pluginPrefix);
9591
+ }
9592
+ function normalizeSubagentFrontmatter(content, expectedName) {
9593
+ return walkFrontmatter(content, {
9594
+ expectedName,
9595
+ fallbackBlock: `---
9596
+ name: ${expectedName}
9597
+ ---`
9598
+ });
9599
+ }
9600
+ function adaptSubagentToPi(source, expectedName, pluginPrefix, skillExists) {
9601
+ let data;
9602
+ let body;
9603
+ try {
9604
+ const fm = parseFrontmatter(source);
9605
+ data = fm.data;
9606
+ body = fm.body.trim();
9607
+ } catch {
9608
+ const minimal = `---
9609
+ name: ${expectedName}
9610
+ ---
9611
+
9612
+ ${source}`;
9613
+ return rewriteSkillReferences(minimal, pluginPrefix);
9614
+ }
9615
+ const rawToolsStr = asString(data.tools);
9616
+ const piTools = normalizePiToolList(rawToolsStr);
9617
+ const description = asString(data.description) || `${expectedName} subagent`;
9618
+ let model = asString(data.model);
9619
+ if (model === "inherit")
9620
+ model = "";
9621
+ const skillsList = resolvePiSkills(data, body, pluginPrefix, skillExists);
9622
+ const skillsCsv = skillsList.join(", ");
9623
+ const fields = [`name: ${expectedName}`];
9624
+ if (description)
9625
+ fields.push(`description: ${description}`);
9626
+ if (piTools)
9627
+ fields.push(`tools: ${piTools}`);
9628
+ if (model)
9629
+ fields.push(`model: ${model}`);
9630
+ if (skillsCsv)
9631
+ fields.push(`skill: ${skillsCsv}`);
9632
+ const runtimeNotes = buildPiRuntimeNotes(parseToolsList(rawToolsStr), skillsCsv);
9633
+ const finalBody = runtimeNotes ? `${body}
9634
+
9635
+ ${runtimeNotes}` : body;
9636
+ const result = `---
9637
+ ${fields.join(`
9638
+ `)}
9639
+ ---
9640
+
9641
+ ${finalBody}
9642
+ `;
9643
+ return rewriteSkillReferences(result, pluginPrefix);
9644
+ }
9645
+ function resolvePiSkills(data, body, pluginPrefix, skillExists) {
9646
+ const rawSkillsStr = asString(data.skills) || asString(data.skill);
9647
+ if (rawSkillsStr) {
9648
+ const seen2 = new Set;
9649
+ const out2 = [];
9650
+ for (const s of rawSkillsStr.split(",")) {
9651
+ const normalized = s.trim().replace(/:/g, "-");
9652
+ if (normalized && !seen2.has(normalized)) {
9653
+ seen2.add(normalized);
9654
+ out2.push(normalized);
9655
+ }
9656
+ }
9657
+ return out2;
9658
+ }
9659
+ const prefix = `${pluginPrefix}:`;
9660
+ const seen = new Set;
9661
+ const out = [];
9662
+ const matches = body.matchAll(/\b([a-z][a-z0-9-]*):([a-z][a-z0-9-]*)\b/gi);
9663
+ for (const m of matches) {
9664
+ const fullRef = `${m[1]}-${m[2]}`;
9665
+ if (`${m[1]}:${m[2]}`.startsWith(prefix) && !seen.has(fullRef)) {
9666
+ const dirName = fullRef.startsWith(`${pluginPrefix}-`) ? fullRef.slice(pluginPrefix.length + 1) : fullRef;
9667
+ if (skillExists(dirName)) {
9668
+ seen.add(fullRef);
9669
+ out.push(fullRef);
9670
+ }
9671
+ }
9672
+ }
9673
+ return out;
9674
+ }
9675
+ function buildPiRuntimeNotes(rawTools, skillsCsv) {
9676
+ const toolSet = new Set(rawTools.map((t) => t.trim()));
9677
+ const sections = [];
9678
+ if ((toolSet.has("Skill") || toolSet.has("skill")) && skillsCsv) {
9679
+ sections.push(`- Skills in \`skill:\` are injected into this prompt. Treat any mention of a Skill tool as applying those injected skills directly: \`${skillsCsv}\`.
9680
+ `);
9681
+ }
9682
+ if (toolSet.has("Agent") || toolSet.has("agent") || toolSet.has("subagent")) {
9683
+ sections.push("- Any mention of an Agent tool or agent delegation maps to Pi's `subagent` tool.\n");
9684
+ }
9685
+ if (toolSet.has("AskUserQuestion") || toolSet.has("askuserquestion")) {
9686
+ sections.push(`- Any AskUserQuestion-style step should be handled by asking the user directly in the conversation.
9687
+ `);
9688
+ }
9689
+ if (toolSet.has("Task") || toolSet.has("task")) {
9690
+ sections.push(`- Any Task tool reference should be handled with repository files or CLI workflows.
9691
+ `);
9692
+ }
9693
+ if (toolSet.has("Glob") || toolSet.has("glob")) {
9694
+ sections.push("- File discovery maps to Pi's `find` and `ls` tools instead of Claude-style Glob.\n");
9695
+ }
9696
+ if (toolSet.has("WebSearch") || toolSet.has("WebFetch") || toolSet.has("web_search") || rawTools.some((t) => t.startsWith("mcp__"))) {
9697
+ sections.push("- Web research maps to Pi web-access style tools (`web_search`, `fetch_content`, `get_search_content`). Install `pi-web-access` if you want those capabilities available.\n");
9698
+ }
9699
+ if (sections.length === 0)
9700
+ return "";
9701
+ return `## Pi Runtime Adaptation
9702
+
9703
+ ${sections.join(`
9704
+ `)}`;
9705
+ }
9706
+ var init_adapt_subagent = __esm(() => {
9707
+ init_frontmatter();
9708
+ init_pi_tools();
9709
+ init_rewrite_references();
9710
+ });
9711
+
9381
9712
  // ../../packages/core/src/mapper.ts
9382
- import { existsSync as existsSync3, mkdirSync, readdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
9713
+ import { existsSync as existsSync3, mkdirSync, readdirSync, readFileSync as readFileSync2, statSync, writeFileSync } from "fs";
9383
9714
  import { join as join3 } from "path";
9384
9715
  function mapPluginToRulesync(pluginPath, pluginName, outputDir) {
9385
9716
  assertSafePathSegment(pluginName, "plugin name");
@@ -9389,45 +9720,78 @@ function mapPluginToRulesync(pluginPath, pluginName, outputDir) {
9389
9720
  if (existsSync3(skillsDir)) {
9390
9721
  const skillsOut = join3(outputDir, "skills");
9391
9722
  for (const entry of readdirSync(skillsDir)) {
9392
- if (!entry.endsWith(".md"))
9723
+ const flatPath = join3(skillsDir, entry);
9724
+ const dirSkillPath = join3(skillsDir, entry, "SKILL.md");
9725
+ let skillName = null;
9726
+ let sourcePath = null;
9727
+ let sourceDir = null;
9728
+ if (entry.endsWith(".md")) {
9729
+ skillName = entry.replace(/\.md$/, "");
9730
+ sourcePath = flatPath;
9731
+ } else if (existsSync3(dirSkillPath)) {
9732
+ skillName = entry;
9733
+ sourcePath = dirSkillPath;
9734
+ sourceDir = join3(skillsDir, entry);
9735
+ }
9736
+ if (!skillName || !sourcePath)
9393
9737
  continue;
9394
- const skillName = entry.replace(/\.md$/, "");
9395
9738
  const dir = join3(skillsOut, `${pluginName}-${skillName}`);
9396
9739
  mkdirSync(dir, { recursive: true });
9397
- writeFileSync(join3(dir, "SKILL.md"), readFileSync2(join3(skillsDir, entry)));
9740
+ const content = rewriteSkillReferences(readFileSync2(sourcePath, "utf-8"), pluginName);
9741
+ writeFileSync(join3(dir, "SKILL.md"), content);
9742
+ if (sourceDir) {
9743
+ for (const subdir of ["scripts", "references", "templates", "assets"]) {
9744
+ const subdirPath = join3(sourceDir, subdir);
9745
+ if (existsSync3(subdirPath)) {
9746
+ copyAndRewriteDirectory(subdirPath, join3(dir, subdir), pluginName);
9747
+ }
9748
+ }
9749
+ }
9398
9750
  result.skills++;
9399
9751
  }
9400
9752
  }
9401
9753
  const commandsDir = join3(pluginPath, "commands");
9402
9754
  if (existsSync3(commandsDir)) {
9403
- const commandsOut = join3(outputDir, "commands");
9404
- mkdirSync(commandsOut, { recursive: true });
9755
+ const skillsOut = join3(outputDir, "skills");
9405
9756
  for (const entry of readdirSync(commandsDir)) {
9406
9757
  if (!entry.endsWith(".md"))
9407
9758
  continue;
9408
9759
  const cmdName = entry.replace(/\.md$/, "");
9409
- writeFileSync(join3(commandsOut, `${pluginName}-${cmdName}.md`), readFileSync2(join3(commandsDir, entry)));
9760
+ const expectedName = `${pluginName}-${cmdName}`;
9761
+ const dir = join3(skillsOut, expectedName);
9762
+ mkdirSync(dir, { recursive: true });
9763
+ const source = readFileSync2(join3(commandsDir, entry), "utf-8");
9764
+ const adapted = adaptCommandToSkill(source, expectedName, pluginName);
9765
+ writeFileSync(join3(dir, "SKILL.md"), adapted);
9410
9766
  result.commands++;
9411
9767
  }
9412
9768
  }
9413
9769
  const agentsDir = join3(pluginPath, "agents");
9414
9770
  if (existsSync3(agentsDir)) {
9415
- const subagentsOut = join3(outputDir, "subagents");
9416
- mkdirSync(subagentsOut, { recursive: true });
9771
+ const skillsOut = join3(outputDir, "skills");
9417
9772
  for (const entry of readdirSync(agentsDir)) {
9418
9773
  if (!entry.endsWith(".md"))
9419
9774
  continue;
9420
9775
  const agentName = entry.replace(/\.md$/, "");
9421
- writeFileSync(join3(subagentsOut, `${pluginName}-${agentName}.md`), readFileSync2(join3(agentsDir, entry)));
9776
+ const expectedName = `${pluginName}-${agentName}`;
9777
+ const dir = join3(skillsOut, expectedName);
9778
+ mkdirSync(dir, { recursive: true });
9779
+ const source = readFileSync2(join3(agentsDir, entry), "utf-8");
9780
+ const adapted = adaptSubagentToSkill(source, expectedName, pluginName);
9781
+ writeFileSync(join3(dir, "SKILL.md"), adapted);
9422
9782
  result.subagents++;
9423
9783
  }
9424
9784
  }
9425
- const hooksPath = join3(pluginPath, "hooks.json");
9785
+ const hooksRootPath = join3(pluginPath, "hooks.json");
9786
+ const hooksSubdirPath = join3(pluginPath, "hooks", "hooks.json");
9787
+ const hooksPath = existsSync3(hooksRootPath) ? hooksRootPath : hooksSubdirPath;
9426
9788
  if (existsSync3(hooksPath)) {
9427
9789
  deepMergeJsonFile(hooksPath, join3(outputDir, "hooks.json"));
9428
9790
  result.hooks = true;
9429
9791
  }
9430
- const mcpPath = join3(pluginPath, "mcp.json");
9792
+ const mcpRootPath = join3(pluginPath, "mcp.json");
9793
+ const mcpSubdirPath = join3(pluginPath, "mcp", "mcp.json");
9794
+ const mcpPath = existsSync3(mcpRootPath) ? mcpRootPath : mcpSubdirPath;
9431
9795
  if (existsSync3(mcpPath)) {
9432
9796
  deepMergeJsonFile(mcpPath, join3(outputDir, "mcp.json"));
9433
9797
  result.mcp = true;
@@ -9464,7 +9828,24 @@ function deepMerge2(target, source) {
9464
9828
  function isJsonObject(value) {
9465
9829
  return typeof value === "object" && value !== null && !Array.isArray(value);
9466
9830
  }
9467
- var init_mapper = () => {};
9831
+ function copyAndRewriteDirectory(source, destination, pluginName) {
9832
+ mkdirSync(destination, { recursive: true });
9833
+ for (const entry of readdirSync(source)) {
9834
+ const srcPath = join3(source, entry);
9835
+ const destPath = join3(destination, entry);
9836
+ if (statSync(srcPath).isDirectory()) {
9837
+ copyAndRewriteDirectory(srcPath, destPath, pluginName);
9838
+ } else {
9839
+ const content = readFileSync2(srcPath, "utf-8");
9840
+ writeFileSync(destPath, rewriteSkillReferences(content, pluginName));
9841
+ }
9842
+ }
9843
+ }
9844
+ var init_mapper = __esm(() => {
9845
+ init_adapt_command();
9846
+ init_adapt_subagent();
9847
+ init_rewrite_references();
9848
+ });
9468
9849
 
9469
9850
  // ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.js
9470
9851
  var util, objectUtil, ZodParsedType, getParsedType = (data) => {
@@ -13474,7 +13855,7 @@ function resolvePlugin(marketplacePath, pluginName) {
13474
13855
  if (!source.startsWith("./")) {
13475
13856
  throw new Error(`Remote sources not yet supported for plugin '${pluginName}'. Phase 1 only supports relative-path sources (starting with './').`);
13476
13857
  }
13477
- if (source.includes("..")) {
13858
+ if (/(?:^|\/)\.\.(?:\/|$)/.test(source)) {
13478
13859
  throw new Error(`Plugin source for '${pluginName}' escapes the marketplace root: '${source}'.`);
13479
13860
  }
13480
13861
  const marketplaceRoot = resolve(manifestPath, "..", "..");
@@ -13578,7 +13959,7 @@ function mergeSkillBodies(sources) {
13578
13959
  return dedupeLines(concatenated);
13579
13960
  }
13580
13961
  function dedupeLines(text) {
13581
- const seen = new Set;
13962
+ const seenHeadings = new Set;
13582
13963
  const out = [];
13583
13964
  let prevBlank = false;
13584
13965
  for (const line of text.split(`
@@ -13590,10 +13971,12 @@ function dedupeLines(text) {
13590
13971
  continue;
13591
13972
  }
13592
13973
  prevBlank = false;
13593
- if (!seen.has(line)) {
13594
- seen.add(line);
13595
- out.push(line);
13974
+ if (/^#{1,6} /.test(line)) {
13975
+ if (seenHeadings.has(line))
13976
+ continue;
13977
+ seenHeadings.add(line);
13596
13978
  }
13979
+ out.push(line);
13597
13980
  }
13598
13981
  while (out.length > 0 && out[out.length - 1] === "")
13599
13982
  out.pop();
@@ -13630,7 +14013,7 @@ var init_migrate = __esm(() => {
13630
14013
  });
13631
14014
 
13632
14015
  // ../../packages/core/src/operations/package.ts
13633
- import { cpSync, existsSync as existsSync6, mkdirSync as mkdirSync3, statSync } from "fs";
14016
+ import { cpSync, existsSync as existsSync6, mkdirSync as mkdirSync3, statSync as statSync2 } from "fs";
13634
14017
  import { basename as basename2, dirname as dirname3, join as join5 } from "path";
13635
14018
  import { cwd as cwd3 } from "process";
13636
14019
  function resolveSkillDir(name) {
@@ -13638,7 +14021,7 @@ function resolveSkillDir(name) {
13638
14021
  if (!skillPath) {
13639
14022
  throw Object.assign(new Error(`Skill not found: ${name}`), { code: "ENOENT" });
13640
14023
  }
13641
- const dir = statSync(skillPath).isDirectory() ? skillPath : dirname3(skillPath);
14024
+ const dir = statSync2(skillPath).isDirectory() ? skillPath : dirname3(skillPath);
13642
14025
  return { dir, name: basename2(dir) };
13643
14026
  }
13644
14027
  function copyDirIfExists(src, dest) {
@@ -13719,13 +14102,43 @@ async function scaffold(type, name, opts = {}) {
13719
14102
  var PLACEHOLDER_NAME = "<!-- NAME -->", PLACEHOLDER_DESCRIPTION = "<!-- DESCRIPTION -->", PLACEHOLDER_TARGET = "<!-- TARGET -->", PLACEHOLDER_BODY = "<!-- BODY -->";
13720
14103
  var init_scaffold = () => {};
13721
14104
 
13722
- // ../../packages/core/src/quality/dimensions.ts
14105
+ // ../../packages/core/src/quality/types.ts
13723
14106
  function computeAggregate(dimensions) {
13724
14107
  const scores = Object.values(dimensions).map((d) => d.score);
13725
14108
  if (scores.length === 0)
13726
14109
  return 0;
13727
14110
  return scores.reduce((a, b) => a + b, 0) / scores.length;
13728
14111
  }
14112
+ var DIMENSION_REGISTRY, IMPERATIVE_KEYWORDS, VAGUE_KEYWORDS, REQUIRED_FIELDS;
14113
+ var init_types2 = __esm(() => {
14114
+ DIMENSION_REGISTRY = {
14115
+ skill: ["completeness", "clarity", "trigger-accuracy", "anti-hallucination", "conciseness"],
14116
+ command: ["completeness", "clarity", "argument-hints", "tool-references", "slash-syntax"],
14117
+ agent: ["completeness", "role-clarity", "tool-selection", "skill-linkage", "model-fit"],
14118
+ hook: ["correctness", "event-coverage", "safety", "pattern-match-quality"],
14119
+ magent: ["completeness", "platform-coverage", "conciseness", "tone-consistency", "safety"]
14120
+ };
14121
+ IMPERATIVE_KEYWORDS = ["must", "should", "never", "always", "required", "ensure", "validate"];
14122
+ VAGUE_KEYWORDS = ["maybe", "perhaps", "might", "could be", "probably"];
14123
+ REQUIRED_FIELDS = {
14124
+ skill: ["name", "description"],
14125
+ command: ["name", "description"],
14126
+ agent: ["name", "description", "model", "tools"],
14127
+ hook: ["name", "description", "event"],
14128
+ magent: ["name", "description"]
14129
+ };
14130
+ });
14131
+
14132
+ // ../../packages/core/src/quality/heuristics.ts
14133
+ function scoreClarityFromDensities(body) {
14134
+ const imperative = keywordDensity(body, [...IMPERATIVE_KEYWORDS]);
14135
+ const vague = keywordDensity(body, [...VAGUE_KEYWORDS]);
14136
+ const score = clamp((imperative - vague) / 2 + 0.5);
14137
+ const lower = body.toLowerCase();
14138
+ const found = VAGUE_KEYWORDS.filter((t) => lower.includes(t));
14139
+ const note = found.length === 0 ? "Good imperative style" : `Vague terms found: ${found.join(", ")}`;
14140
+ return { score, note };
14141
+ }
13729
14142
  function parseFrontmatterSafe(content) {
13730
14143
  try {
13731
14144
  return parseFrontmatter(content).data;
@@ -13805,23 +14218,9 @@ function clamp(n) {
13805
14218
  function escapeRegex(s) {
13806
14219
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
13807
14220
  }
13808
- var DIMENSION_REGISTRY, REQUIRED_FIELDS;
13809
- var init_dimensions = __esm(() => {
14221
+ var init_heuristics = __esm(() => {
13810
14222
  init_frontmatter();
13811
- DIMENSION_REGISTRY = {
13812
- skill: ["completeness", "clarity", "trigger-accuracy", "anti-hallucination", "conciseness"],
13813
- command: ["completeness", "clarity", "argument-hints", "tool-references", "slash-syntax"],
13814
- agent: ["completeness", "role-clarity", "tool-selection", "skill-linkage", "model-fit"],
13815
- hook: ["correctness", "event-coverage", "safety", "pattern-match-quality"],
13816
- magent: ["completeness", "platform-coverage", "conciseness", "tone-consistency", "safety"]
13817
- };
13818
- REQUIRED_FIELDS = {
13819
- skill: ["name", "description"],
13820
- command: ["name", "description"],
13821
- agent: ["name", "description", "model", "tools"],
13822
- hook: ["name", "description", "event"],
13823
- magent: ["name", "description"]
13824
- };
14223
+ init_types2();
13825
14224
  });
13826
14225
 
13827
14226
  // ../../packages/core/src/quality/hook.ts
@@ -13918,7 +14317,8 @@ function evaluateHook(content, target) {
13918
14317
  }
13919
14318
  var KNOWN_HOOK_EVENTS;
13920
14319
  var init_hook = __esm(() => {
13921
- init_dimensions();
14320
+ init_heuristics();
14321
+ init_types2();
13922
14322
  KNOWN_HOOK_EVENTS = [
13923
14323
  "PreToolUse",
13924
14324
  "PostToolUse",
@@ -13933,7 +14333,7 @@ var init_hook = __esm(() => {
13933
14333
  });
13934
14334
 
13935
14335
  // ../../packages/core/src/operations/validate.ts
13936
- import { existsSync as existsSync8, statSync as statSync2 } from "fs";
14336
+ import { existsSync as existsSync8, statSync as statSync3 } from "fs";
13937
14337
  import { dirname as dirname4 } from "path";
13938
14338
  async function validate(type, nameOrPath, opts) {
13939
14339
  const resolvedPath = resolveContentPath(type, nameOrPath);
@@ -13945,7 +14345,7 @@ async function validate(type, nameOrPath, opts) {
13945
14345
  }
13946
14346
  let stat;
13947
14347
  try {
13948
- stat = statSync2(resolvedPath);
14348
+ stat = statSync3(resolvedPath);
13949
14349
  } catch {
13950
14350
  return sentinelResult(`File not found: ${resolvedPath}`);
13951
14351
  }
@@ -14182,8 +14582,8 @@ var MODEL_ALIASES, FIELD_TYPES, DEPRECATED_FIELDS;
14182
14582
  var init_validate = __esm(() => {
14183
14583
  init_frontmatter();
14184
14584
  init_identity();
14185
- init_dimensions();
14186
14585
  init_hook();
14586
+ init_types2();
14187
14587
  MODEL_ALIASES = ["inherit", "sonnet", "opus", "haiku"];
14188
14588
  FIELD_TYPES = {
14189
14589
  skill: {
@@ -14220,176 +14620,13 @@ var init_validate = __esm(() => {
14220
14620
  version: "Version is derived from the source repository."
14221
14621
  };
14222
14622
  });
14223
- // ../../packages/core/src/pipeline/frontmatter.ts
14224
- function normalizeFrontmatter(content, name) {
14225
- if (!content.startsWith(`---
14226
- `)) {
14227
- return `---
14228
- name: ${name}
14229
- ---
14230
-
14231
- ${content}`;
14232
- }
14233
- const end = content.indexOf(`
14234
- ---`, 4);
14235
- if (end === -1) {
14236
- return content;
14237
- }
14238
- const frontmatter = content.slice(4, end);
14239
- if (/^name\s*:/m.test(frontmatter)) {
14240
- return content;
14241
- }
14242
- return `---
14243
- name: ${name}
14244
- ${content.slice(4)}`;
14245
- }
14246
14623
 
14247
14624
  // ../../packages/core/src/pipeline/pi-subagent.ts
14248
- function expandPiTool(raw) {
14249
- const trimmed = raw.trim().replace(/^["']|["']$/g, "");
14250
- if (DROPPED_TOOLS.has(trimmed))
14251
- return "";
14252
- if (trimmed.startsWith("mcp__") || trimmed.startsWith("mcp:"))
14253
- return "mcp";
14254
- return PI_TOOL_MAP[trimmed] ?? "";
14255
- }
14256
- function parseToolsList(raw) {
14257
- const trimmed = raw.trim();
14258
- const cleaned = trimmed.replace(/^\[|\]$/g, "");
14259
- if (!cleaned.trim())
14260
- return [];
14261
- return cleaned.split(",").map((t) => t.trim()).filter(Boolean);
14262
- }
14263
- function extractSkillsFromBody(body) {
14264
- const matches = body.matchAll(/\b([a-z][a-z0-9-]*):([a-z][a-z0-9-]*)\b/gi);
14265
- const skills = new Set;
14266
- for (const m of matches) {
14267
- skills.add(`${m[1]}-${m[2]}`);
14268
- }
14269
- return [...skills];
14270
- }
14271
- function asString(value) {
14272
- if (typeof value === "string")
14273
- return value;
14274
- if (Array.isArray(value))
14275
- return value.join(", ");
14276
- return "";
14277
- }
14278
- function buildPiRuntimeNotes(rawTools, skillsCsv) {
14279
- const toolSet = new Set(rawTools.map((t) => t.trim()));
14280
- const sections = [];
14281
- if ((toolSet.has("Skill") || toolSet.has("skill")) && skillsCsv) {
14282
- sections.push(`- Skills in \`skill:\` are injected into this prompt. Treat any mention of a Skill tool as applying those injected skills directly: \`${skillsCsv}\`.
14283
- `);
14284
- }
14285
- if (toolSet.has("Agent") || toolSet.has("agent") || toolSet.has("subagent")) {
14286
- sections.push("- Any mention of an Agent tool or agent delegation maps to Pi's `subagent` tool.\n");
14287
- }
14288
- if (toolSet.has("AskUserQuestion") || toolSet.has("askuserquestion")) {
14289
- sections.push(`- Any AskUserQuestion-style step should be handled by asking the user directly in the conversation.
14290
- `);
14291
- }
14292
- if (toolSet.has("Task") || toolSet.has("task")) {
14293
- sections.push(`- Any Task tool reference should be handled with repository files or CLI workflows.
14294
- `);
14295
- }
14296
- if (toolSet.has("Glob") || toolSet.has("glob")) {
14297
- sections.push("- File discovery maps to Pi's `find` and `ls` tools instead of Claude-style Glob.\n");
14298
- }
14299
- if (toolSet.has("WebSearch") || toolSet.has("WebFetch") || toolSet.has("web_search") || rawTools.some((t) => t.startsWith("mcp__"))) {
14300
- sections.push("- Web research maps to Pi web-access style tools (`web_search`, `fetch_content`, `get_search_content`). Install `pi-web-access` if you want those capabilities available.\n");
14301
- }
14302
- if (sections.length === 0)
14303
- return "";
14304
- return `## Pi Runtime Adaptation
14305
-
14306
- ${sections.join(`
14307
- `)}`;
14308
- }
14309
- function convertToPiSubagent(content) {
14310
- let data;
14311
- let body;
14312
- try {
14313
- const fm = parseFrontmatter(content);
14314
- data = fm.data;
14315
- body = fm.body.trim();
14316
- } catch {
14317
- return content;
14318
- }
14319
- const rawToolsStr = asString(data.tools);
14320
- const rawTools = parseToolsList(rawToolsStr);
14321
- const piTools = rawTools.map(expandPiTool).filter(Boolean).join(", ");
14322
- const rawSkillsStr = asString(data.skills) || asString(data.skill);
14323
- const explicitSkills = rawSkillsStr ? rawSkillsStr.split(",").map((s) => s.trim().replace(":", "-")) : [];
14324
- let skillsList = explicitSkills;
14325
- if (skillsList.length === 0) {
14326
- skillsList = extractSkillsFromBody(body);
14327
- }
14328
- const skillsCsv = skillsList.join(", ");
14329
- let model = asString(data.model);
14330
- if (model === "inherit")
14331
- model = "";
14332
- const piFields = [];
14333
- piFields.push(`name: ${asString(data.name)}`);
14334
- if (data.description)
14335
- piFields.push(`description: ${asString(data.description)}`);
14336
- if (piTools)
14337
- piFields.push(`tools: ${piTools}`);
14338
- if (skillsCsv)
14339
- piFields.push(`skill: ${skillsCsv}`);
14340
- if (model)
14341
- piFields.push(`model: ${model}`);
14342
- const runtimeNotes = buildPiRuntimeNotes(rawTools, skillsCsv);
14343
- const finalBody = runtimeNotes ? `${body}
14344
-
14345
- ${runtimeNotes}` : body;
14346
- return `---
14347
- ${piFields.join(`
14348
- `)}
14349
- ---
14350
-
14351
- ${finalBody}
14352
- `;
14353
- }
14354
- var PI_TOOL_MAP, DROPPED_TOOLS;
14355
14625
  var init_pi_subagent = __esm(() => {
14356
14626
  init_frontmatter();
14357
- PI_TOOL_MAP = {
14358
- Read: "read",
14359
- read: "read",
14360
- Write: "write",
14361
- write: "write",
14362
- Edit: "edit",
14363
- edit: "edit",
14364
- Bash: "bash",
14365
- bash: "bash",
14366
- Grep: "grep",
14367
- grep: "grep",
14368
- Glob: "find, ls",
14369
- glob: "find, ls",
14370
- Find: "find",
14371
- find: "find",
14372
- Ls: "ls",
14373
- LS: "ls",
14374
- ls: "ls",
14375
- Agent: "subagent",
14376
- agent: "subagent",
14377
- subagent: "subagent",
14378
- WebSearch: "web_search, fetch_content, get_search_content",
14379
- WebFetch: "web_search, fetch_content, get_search_content",
14380
- web_search: "web_search",
14381
- fetch_content: "fetch_content",
14382
- get_search_content: "get_search_content",
14383
- mcp: "mcp"
14384
- };
14385
- DROPPED_TOOLS = new Set(["Skill", "skill", "Task", "task", "AskUserQuestion", "askuserquestion"]);
14627
+ init_pi_tools();
14386
14628
  });
14387
14629
 
14388
- // ../../packages/core/src/pipeline/rewrite-colons.ts
14389
- function rewriteColonRefs(content) {
14390
- return content.replace(/\b(rd3|wt):([a-z][a-z0-9-]*)\b/gi, (_match, prefix, name) => `${prefix}-${name}`);
14391
- }
14392
-
14393
14630
  // ../../node_modules/.bun/@logtape+logtape@2.1.5/node_modules/@logtape/logtape/dist/context.js
14394
14631
  function getCategoryPrefix() {
14395
14632
  const rootLogger = LoggerImpl.getLogger();
@@ -31971,7 +32208,7 @@ var init_config = __esm(() => {
31971
32208
  });
31972
32209
 
31973
32210
  // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.3.21/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
31974
- import { appendFileSync, cpSync as cpSync2, createWriteStream, existsSync as existsSync9, mkdirSync as mkdirSync5, readdirSync as readdirSync2, readFileSync as readFileSync6, renameSync, rmSync as rmSync2, statSync as statSync3, writeFileSync as writeFileSync4 } from "fs";
32211
+ import { appendFileSync, cpSync as cpSync2, createWriteStream, existsSync as existsSync9, mkdirSync as mkdirSync5, readdirSync as readdirSync2, readFileSync as readFileSync6, renameSync, rmSync as rmSync2, statSync as statSync4, writeFileSync as writeFileSync4 } from "fs";
31975
32212
  import { dirname as dirname5, resolve as resolvePath } from "path";
31976
32213
  function createNodeFileSystem(root) {
31977
32214
  const projectRoot = root ?? findProjectRoot(process.cwd());
@@ -32007,7 +32244,7 @@ function createNodeFileSystem(root) {
32007
32244
  },
32008
32245
  stat: (path) => {
32009
32246
  try {
32010
- const s = statSync3(path);
32247
+ const s = statSync4(path);
32011
32248
  return {
32012
32249
  isFile: () => s.isFile(),
32013
32250
  isDirectory: () => s.isDirectory(),
@@ -34635,7 +34872,7 @@ var init_encoding_option = __esm(() => {
34635
34872
  });
34636
34873
 
34637
34874
  // ../../node_modules/.bun/execa@9.6.1/node_modules/execa/lib/arguments/cwd.js
34638
- import { statSync as statSync4 } from "fs";
34875
+ import { statSync as statSync5 } from "fs";
34639
34876
  import path4 from "path";
34640
34877
  import process6 from "process";
34641
34878
  var normalizeCwd = (cwd5 = getDefaultCwd()) => {
@@ -34655,7 +34892,7 @@ ${error51.message}`;
34655
34892
  }
34656
34893
  let cwdStat;
34657
34894
  try {
34658
- cwdStat = statSync4(cwd5);
34895
+ cwdStat = statSync5(cwd5);
34659
34896
  } catch (error51) {
34660
34897
  return `The "cwd" option is invalid: ${cwd5}.
34661
34898
  ${error51.message}
@@ -39608,7 +39845,7 @@ var init_schema_validation = __esm(() => {
39608
39845
  });
39609
39846
 
39610
39847
  // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.3.21/node_modules/@gobing-ai/ts-runtime/dist/types.js
39611
- var init_types2 = () => {};
39848
+ var init_types3 = () => {};
39612
39849
 
39613
39850
  // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.3.21/node_modules/@gobing-ai/ts-runtime/dist/index.js
39614
39851
  var init_dist4 = __esm(() => {
@@ -39618,7 +39855,7 @@ var init_dist4 = __esm(() => {
39618
39855
  init_context2();
39619
39856
  init_path();
39620
39857
  init_schema_validation();
39621
- init_types2();
39858
+ init_types3();
39622
39859
  });
39623
39860
 
39624
39861
  // ../../node_modules/.bun/@gobing-ai+ts-ai-runner@0.3.21+5a4f8cc6c6b198a4/node_modules/@gobing-ai/ts-ai-runner/dist/identity.js
@@ -40083,7 +40320,7 @@ var init_dist5 = __esm(() => {
40083
40320
  });
40084
40321
 
40085
40322
  // ../../packages/core/src/targets.ts
40086
- var TARGETS, TARGET_TO_RULESYNC, TARGET_TO_AGENT_NAME;
40323
+ var TARGETS, TARGET_TO_RULESYNC, TARGET_SKILLS_RELDIR, TARGET_TO_AGENT_NAME;
40087
40324
  var init_targets = __esm(() => {
40088
40325
  TARGETS = [
40089
40326
  "claude",
@@ -40102,6 +40339,13 @@ var init_targets = __esm(() => {
40102
40339
  "antigravity-cli": "antigravity-cli",
40103
40340
  "antigravity-ide": "antigravity-ide"
40104
40341
  };
40342
+ TARGET_SKILLS_RELDIR = {
40343
+ codex: ".agents/skills",
40344
+ pi: ".pi/skills",
40345
+ opencode: ".opencode/skills",
40346
+ "antigravity-cli": ".agents/skills",
40347
+ "antigravity-ide": ".agents/skills"
40348
+ };
40105
40349
  TARGET_TO_AGENT_NAME = {
40106
40350
  claude: "claude",
40107
40351
  codex: "codex",
@@ -40237,7 +40481,8 @@ function evaluateAgent(content, target) {
40237
40481
  };
40238
40482
  }
40239
40483
  var init_agent = __esm(() => {
40240
- init_dimensions();
40484
+ init_heuristics();
40485
+ init_types2();
40241
40486
  });
40242
40487
 
40243
40488
  // ../../packages/core/src/quality/command.ts
@@ -40255,17 +40500,7 @@ function scoreCompleteness2(data) {
40255
40500
  return { score, note };
40256
40501
  }
40257
40502
  function scoreClarity(body) {
40258
- const imperative = keywordDensity(body, ["must", "should", "never", "always", "required", "ensure", "validate"]);
40259
- const vague = keywordDensity(body, ["maybe", "perhaps", "might", "could be", "probably"]);
40260
- const score = clamp(imperative - vague);
40261
- const detectedVague = [];
40262
- for (const v of ["maybe", "perhaps", "might", "could be", "probably"]) {
40263
- if (new RegExp(`(?:^|\\s)${v.replace(/\s/g, "\\s")}(?:\\s|$|[.,;:!?])`, "i").test(body)) {
40264
- detectedVague.push(v);
40265
- }
40266
- }
40267
- const note = detectedVague.length > 0 ? `Uses vague language: ${detectedVague.join(", ")}` : "Good imperative style";
40268
- return { score, note };
40503
+ return scoreClarityFromDensities(body);
40269
40504
  }
40270
40505
  function scoreArgumentHints(data) {
40271
40506
  const args = data.arguments;
@@ -40285,20 +40520,15 @@ function scoreArgumentHints(data) {
40285
40520
  return { score, note: `${withHints}/${args.length} arguments have hints` };
40286
40521
  }
40287
40522
  function scoreToolReferences(body) {
40288
- const toolRefs = [/`[a-z][a-z0-9_-]*`/g, /tool:/gi, /tools:/gi];
40289
- let count2 = 0;
40290
- for (const pattern of toolRefs) {
40291
- pattern.lastIndex = 0;
40292
- const matches = body.match(pattern);
40293
- if (matches)
40294
- count2 += matches.length;
40295
- }
40523
+ const structuredCount = (body.match(/\btools?:/gi) ?? []).length;
40524
+ const backtickCount = (body.match(/`[a-z][a-z0-9_-]*`/g) ?? []).length;
40525
+ const weightedCount = structuredCount + Math.min(backtickCount, 1);
40296
40526
  let score;
40297
40527
  let note;
40298
- if (count2 >= 2) {
40528
+ if (structuredCount >= 1 || weightedCount >= 2) {
40299
40529
  score = 1;
40300
40530
  note = "Uses tool references";
40301
- } else if (count2 === 1) {
40531
+ } else if (weightedCount === 1) {
40302
40532
  score = 0.6;
40303
40533
  note = "Limited tool references";
40304
40534
  } else {
@@ -40344,7 +40574,8 @@ function evaluateCommand(content, target) {
40344
40574
  };
40345
40575
  }
40346
40576
  var init_command3 = __esm(() => {
40347
- init_dimensions();
40577
+ init_heuristics();
40578
+ init_types2();
40348
40579
  });
40349
40580
 
40350
40581
  // ../../packages/core/src/quality/magent.ts
@@ -40426,99 +40657,11 @@ function evaluateMagent(content, target) {
40426
40657
  }
40427
40658
  var MAGENT_SECTIONS;
40428
40659
  var init_magent = __esm(() => {
40429
- init_dimensions();
40660
+ init_heuristics();
40661
+ init_types2();
40430
40662
  MAGENT_SECTIONS = [/^## IDENTITY/m, /^## SOUL/m, /^## AGENTS/m, /^## USER/m];
40431
40663
  });
40432
40664
 
40433
- // ../../packages/core/src/quality/rubric.ts
40434
- import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
40435
- import { homedir as homedir3 } from "os";
40436
- import { join as join7 } from "path";
40437
- function resolveRubricContent(type, opts) {
40438
- if (opts?.path) {
40439
- if (!existsSync10(opts.path)) {
40440
- throw new RubricError("path", `Rubric file not found: ${opts.path}`, opts.path);
40441
- }
40442
- return readFileSync9(opts.path, "utf-8");
40443
- }
40444
- const homeDir = process.env.HOME ?? homedir3();
40445
- const userPath = join7(homeDir, ".superskill", "rubrics", `${type}.yaml`);
40446
- if (existsSync10(userPath)) {
40447
- return readFileSync9(userPath, "utf-8");
40448
- }
40449
- const devPath = join7(import.meta.dir, "..", "rubrics", `${type}.yaml`);
40450
- if (existsSync10(devPath)) {
40451
- return readFileSync9(devPath, "utf-8");
40452
- }
40453
- const prodPath = join7(import.meta.dir, "..", "..", "rubrics", `${type}.yaml`);
40454
- if (existsSync10(prodPath)) {
40455
- return readFileSync9(prodPath, "utf-8");
40456
- }
40457
- throw new RubricError("path", `No rubric found for type "${type}". Searched: ${opts?.path ?? "(no explicit path)"}, ${userPath}, ${devPath}, ${prodPath}`, type);
40458
- }
40459
- function loadRubric(type, opts) {
40460
- const raw = resolveRubricContent(type, opts);
40461
- let parsed;
40462
- try {
40463
- parsed = $parse(raw);
40464
- } catch (e) {
40465
- throw new RubricError("yaml", `Failed to parse rubric YAML: ${e instanceof Error ? e.message : String(e)}`);
40466
- }
40467
- const result = RubricSchema.safeParse(parsed);
40468
- if (!result.success) {
40469
- const issue2 = result.error.issues[0];
40470
- if (!issue2) {
40471
- throw new RubricError("root", "Rubric schema validation failed with no issue reported.");
40472
- }
40473
- const field = issue2.path.length > 0 ? issue2.path.join(".") : "root";
40474
- throw new RubricError(field, `Rubric schema validation failed: ${issue2.message}`);
40475
- }
40476
- const rubric = result.data;
40477
- const allowed = DIMENSION_REGISTRY[rubric.type];
40478
- for (const [i2, dim2] of rubric.dimensions.entries()) {
40479
- if (!allowed.includes(dim2.name)) {
40480
- throw new RubricError(`dimensions[${i2}].name`, `Unknown dimension name "${dim2.name}" for type "${rubric.type}". Allowed: ${allowed.join(", ")}`, dim2.name);
40481
- }
40482
- }
40483
- const weightSum = rubric.dimensions.reduce((acc, d) => acc + d.weight, 0);
40484
- if (Math.abs(weightSum - 1) > WEIGHT_SUM_TOLERANCE) {
40485
- throw new RubricError("weights.sum", `Dimension weights sum to ${weightSum}, expected 1.0 (\xB1${WEIGHT_SUM_TOLERANCE}).`, weightSum);
40486
- }
40487
- return rubric;
40488
- }
40489
- var CONTENT_TYPES, RubricSchema, RubricError, WEIGHT_SUM_TOLERANCE = 0.001;
40490
- var init_rubric = __esm(() => {
40491
- init_dist2();
40492
- init_zod();
40493
- init_dimensions();
40494
- CONTENT_TYPES = ["skill", "command", "agent", "hook", "magent"];
40495
- RubricSchema = exports_external.object({
40496
- version: exports_external.number().int().min(1),
40497
- type: exports_external.enum(CONTENT_TYPES),
40498
- dimensions: exports_external.array(exports_external.object({
40499
- name: exports_external.string().min(1),
40500
- weight: exports_external.number().min(0).max(1),
40501
- criterion: exports_external.string().min(1),
40502
- anchors: exports_external.object({
40503
- excellent: exports_external.string().optional(),
40504
- poor: exports_external.string().optional()
40505
- }).optional()
40506
- })).min(1)
40507
- });
40508
- RubricError = class RubricError extends Error {
40509
- field;
40510
- actual;
40511
- constructor(field, message, actual) {
40512
- super(message);
40513
- this.name = "RubricError";
40514
- this.field = field;
40515
- if (actual !== undefined) {
40516
- this.actual = actual;
40517
- }
40518
- }
40519
- };
40520
- });
40521
-
40522
40665
  // ../../packages/core/src/quality/skill.ts
40523
40666
  function evaluateSkill(content, target) {
40524
40667
  const data = parseFrontmatterSafe(content);
@@ -40554,21 +40697,7 @@ function scoreCompleteness4(content, data, body) {
40554
40697
  return { score, note };
40555
40698
  }
40556
40699
  function scoreClarity2(body) {
40557
- const imperativeDensity = keywordDensity(body, [
40558
- "must",
40559
- "should",
40560
- "never",
40561
- "always",
40562
- "required",
40563
- "ensure",
40564
- "validate"
40565
- ]);
40566
- const vagueDensity = keywordDensity(body, ["maybe", "perhaps", "might", "could be", "probably"]);
40567
- const score = clamp((imperativeDensity - vagueDensity) / 2 + 0.5);
40568
- const lower = body.toLowerCase();
40569
- const vagueTerms = ["maybe", "perhaps", "might", "could be", "probably"].filter((t) => lower.includes(t));
40570
- const note = vagueTerms.length === 0 ? "Good imperative style" : `Vague terms found: ${vagueTerms.join(", ")}`;
40571
- return { score, note };
40700
+ return scoreClarityFromDensities(body);
40572
40701
  }
40573
40702
  function scoreTriggerAccuracy(body) {
40574
40703
  const count2 = countTriggerPhrases(body);
@@ -40635,7 +40764,117 @@ function countTriggerPhrases(body) {
40635
40764
  return count2;
40636
40765
  }
40637
40766
  var init_skill = __esm(() => {
40638
- init_dimensions();
40767
+ init_heuristics();
40768
+ init_types2();
40769
+ });
40770
+
40771
+ // ../../packages/core/src/quality/evaluate.ts
40772
+ function evaluate(type, content, target) {
40773
+ return EVALUATORS[type](content, target);
40774
+ }
40775
+ var EVALUATORS;
40776
+ var init_evaluate = __esm(() => {
40777
+ init_agent();
40778
+ init_command3();
40779
+ init_hook();
40780
+ init_magent();
40781
+ init_skill();
40782
+ EVALUATORS = {
40783
+ skill: evaluateSkill,
40784
+ command: evaluateCommand,
40785
+ agent: evaluateAgent,
40786
+ hook: evaluateHook,
40787
+ magent: evaluateMagent
40788
+ };
40789
+ });
40790
+
40791
+ // ../../packages/core/src/quality/rubric.ts
40792
+ import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
40793
+ import { homedir as homedir3 } from "os";
40794
+ import { join as join7 } from "path";
40795
+ function resolveRubricContent(type, opts) {
40796
+ if (opts?.path) {
40797
+ if (!existsSync10(opts.path)) {
40798
+ throw new RubricError("path", `Rubric file not found: ${opts.path}`, opts.path);
40799
+ }
40800
+ return readFileSync9(opts.path, "utf-8");
40801
+ }
40802
+ const homeDir = process.env.HOME ?? homedir3();
40803
+ const userPath = join7(homeDir, ".superskill", "rubrics", `${type}.yaml`);
40804
+ if (existsSync10(userPath)) {
40805
+ return readFileSync9(userPath, "utf-8");
40806
+ }
40807
+ const devPath = join7(import.meta.dir, "..", "rubrics", `${type}.yaml`);
40808
+ if (existsSync10(devPath)) {
40809
+ return readFileSync9(devPath, "utf-8");
40810
+ }
40811
+ const prodPath = join7(import.meta.dir, "..", "..", "rubrics", `${type}.yaml`);
40812
+ if (existsSync10(prodPath)) {
40813
+ return readFileSync9(prodPath, "utf-8");
40814
+ }
40815
+ throw new RubricError("path", `No rubric found for type "${type}". Searched: ${opts?.path ?? "(no explicit path)"}, ${userPath}, ${devPath}, ${prodPath}`, type);
40816
+ }
40817
+ function loadRubric(type, opts) {
40818
+ const raw = resolveRubricContent(type, opts);
40819
+ let parsed;
40820
+ try {
40821
+ parsed = $parse(raw);
40822
+ } catch (e) {
40823
+ throw new RubricError("yaml", `Failed to parse rubric YAML: ${e instanceof Error ? e.message : String(e)}`);
40824
+ }
40825
+ const result = RubricSchema.safeParse(parsed);
40826
+ if (!result.success) {
40827
+ const issue2 = result.error.issues[0];
40828
+ if (!issue2) {
40829
+ throw new RubricError("root", "Rubric schema validation failed with no issue reported.");
40830
+ }
40831
+ const field = issue2.path.length > 0 ? issue2.path.join(".") : "root";
40832
+ throw new RubricError(field, `Rubric schema validation failed: ${issue2.message}`);
40833
+ }
40834
+ const rubric = result.data;
40835
+ const allowed = DIMENSION_REGISTRY[rubric.type];
40836
+ for (const [i2, dim2] of rubric.dimensions.entries()) {
40837
+ if (!allowed.includes(dim2.name)) {
40838
+ throw new RubricError(`dimensions[${i2}].name`, `Unknown dimension name "${dim2.name}" for type "${rubric.type}". Allowed: ${allowed.join(", ")}`, dim2.name);
40839
+ }
40840
+ }
40841
+ const weightSum = rubric.dimensions.reduce((acc, d) => acc + d.weight, 0);
40842
+ if (Math.abs(weightSum - 1) > WEIGHT_SUM_TOLERANCE) {
40843
+ throw new RubricError("weights.sum", `Dimension weights sum to ${weightSum}, expected 1.0 (\xB1${WEIGHT_SUM_TOLERANCE}).`, weightSum);
40844
+ }
40845
+ return rubric;
40846
+ }
40847
+ var CONTENT_TYPES, RubricSchema, RubricError, WEIGHT_SUM_TOLERANCE = 0.001;
40848
+ var init_rubric = __esm(() => {
40849
+ init_dist2();
40850
+ init_zod();
40851
+ init_types2();
40852
+ CONTENT_TYPES = ["skill", "command", "agent", "hook", "magent"];
40853
+ RubricSchema = exports_external.object({
40854
+ version: exports_external.number().int().min(1),
40855
+ type: exports_external.enum(CONTENT_TYPES),
40856
+ dimensions: exports_external.array(exports_external.object({
40857
+ name: exports_external.string().min(1),
40858
+ weight: exports_external.number().min(0).max(1),
40859
+ criterion: exports_external.string().min(1),
40860
+ anchors: exports_external.object({
40861
+ excellent: exports_external.string().optional(),
40862
+ poor: exports_external.string().optional()
40863
+ }).optional()
40864
+ })).min(1)
40865
+ });
40866
+ RubricError = class RubricError extends Error {
40867
+ field;
40868
+ actual;
40869
+ constructor(field, message, actual) {
40870
+ super(message);
40871
+ this.name = "RubricError";
40872
+ this.field = field;
40873
+ if (actual !== undefined) {
40874
+ this.actual = actual;
40875
+ }
40876
+ }
40877
+ };
40639
40878
  });
40640
40879
 
40641
40880
  // ../../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/mini/parse.js
@@ -46400,11 +46639,11 @@ var require_out = __commonJS((exports) => {
46400
46639
  async.read(path7, getSettings(optionsOrSettingsOrCallback), callback);
46401
46640
  }
46402
46641
  exports.stat = stat;
46403
- function statSync5(path7, optionsOrSettings) {
46642
+ function statSync6(path7, optionsOrSettings) {
46404
46643
  const settings = getSettings(optionsOrSettings);
46405
46644
  return sync.read(path7, settings);
46406
46645
  }
46407
- exports.statSync = statSync5;
46646
+ exports.statSync = statSync6;
46408
46647
  function getSettings(settingsOrOptions = {}) {
46409
46648
  if (settingsOrOptions instanceof settings_1.default) {
46410
46649
  return settingsOrOptions;
@@ -88643,12 +88882,14 @@ async function runRulesync(targets, features, inputRoot, options2) {
88643
88882
  hasDiff: false
88644
88883
  };
88645
88884
  }
88885
+ const root = options2.outputRoot ?? (options2.global ? homedir4() : process.cwd());
88886
+ const rulesyncGlobal = options2.outputRoot ? false : options2.global;
88646
88887
  return generate2({
88647
88888
  targets: mappedTargets,
88648
88889
  features,
88649
88890
  inputRoot,
88650
- outputRoots: [options2.global ? homedir4() : process.cwd()],
88651
- global: options2.global,
88891
+ outputRoots: [root],
88892
+ global: rulesyncGlobal,
88652
88893
  dryRun: options2.dryRun,
88653
88894
  verbose: options2.verbose,
88654
88895
  delete: false
@@ -88673,15 +88914,21 @@ var init_src = __esm(() => {
88673
88914
  init_package();
88674
88915
  init_scaffold();
88675
88916
  init_validate();
88917
+ init_adapt_command();
88918
+ init_adapt_subagent();
88676
88919
  init_pi_subagent();
88920
+ init_pi_tools();
88921
+ init_rewrite_references();
88677
88922
  init_slash_command2();
88678
88923
  init_agent();
88679
88924
  init_command3();
88680
- init_dimensions();
88925
+ init_evaluate();
88926
+ init_heuristics();
88681
88927
  init_hook();
88682
88928
  init_magent();
88683
88929
  init_rubric();
88684
88930
  init_skill();
88931
+ init_types2();
88685
88932
  init_rulesync();
88686
88933
  init_targets();
88687
88934
  });
@@ -94413,14 +94660,7 @@ function deserializeEvaluation(row) {
94413
94660
  }
94414
94661
 
94415
94662
  // src/operations/evaluate.ts
94416
- var EVALUATORS = {
94417
- skill: evaluateSkill,
94418
- command: evaluateCommand,
94419
- agent: evaluateAgent,
94420
- hook: evaluateHook,
94421
- magent: evaluateMagent
94422
- };
94423
- async function evaluate(type, nameOrPath, opts) {
94663
+ async function evaluate3(type, nameOrPath, opts) {
94424
94664
  const resolvedPath = resolveContentPath(type, nameOrPath);
94425
94665
  if (!resolvedPath) {
94426
94666
  throw Object.assign(new Error(`File not found: ${nameOrPath}`), { code: 2 });
@@ -94438,8 +94678,7 @@ async function evaluate(type, nameOrPath, opts) {
94438
94678
  if (opts?.rubric) {
94439
94679
  return emitEnvelope(type, resolvedPath, content, resolvedTarget, opts);
94440
94680
  }
94441
- const evaluator = EVALUATORS[type];
94442
- const report = evaluator(content, resolvedTarget);
94681
+ const report = evaluate(type, content, resolvedTarget);
94443
94682
  report.content = resolveContentName(resolvedPath);
94444
94683
  if (opts?.save) {
94445
94684
  await persistEvaluation(type, resolvedPath, resolvedTarget, report, opts);
@@ -94459,7 +94698,7 @@ function computeWeightedAggregate(scores, rubric2) {
94459
94698
  function emitEnvelope(type, resolvedPath, content, resolvedTarget, opts) {
94460
94699
  const rubric2 = loadRubric(type, { path: opts.rubric });
94461
94700
  const contentName = resolveContentName(resolvedPath);
94462
- const baseline = EVALUATORS[type](content, resolvedTarget);
94701
+ const baseline = evaluate(type, content, resolvedTarget);
94463
94702
  baseline.content = contentName;
94464
94703
  const envelope = {
94465
94704
  type,
@@ -94520,14 +94759,14 @@ async function ingestScores(type, resolvedPath, resolvedTarget, opts) {
94520
94759
  });
94521
94760
  }
94522
94761
  }
94523
- const dimensions2 = scores.dimensions;
94524
- const aggregate2 = computeWeightedAggregate(dimensions2, rubric2);
94762
+ const dimensions = scores.dimensions;
94763
+ const aggregate2 = computeWeightedAggregate(dimensions, rubric2);
94525
94764
  const report = {
94526
94765
  content: contentName,
94527
94766
  type,
94528
94767
  target: resolvedTarget,
94529
94768
  aggregate: aggregate2,
94530
- dimensions: dimensions2
94769
+ dimensions
94531
94770
  };
94532
94771
  if (opts.save) {
94533
94772
  await persistEvaluation(type, resolvedPath, resolvedTarget, report, opts, "rubric", rubric2.version);
@@ -94742,11 +94981,11 @@ function computeAnchorHash(anchor) {
94742
94981
  }
94743
94982
  function computeBaselineAnchorHash(content) {
94744
94983
  const parsed = parseFrontmatter(content);
94745
- const frontmatter3 = parsed.data;
94984
+ const frontmatter2 = parsed.data;
94746
94985
  return computeAnchorHash({
94747
- frontmatter: frontmatter3,
94986
+ frontmatter: frontmatter2,
94748
94987
  rubric_criteria: "",
94749
- negative_constraints: extractNegativeConstraints(frontmatter3.description)
94988
+ negative_constraints: extractNegativeConstraints(frontmatter2.description)
94750
94989
  });
94751
94990
  }
94752
94991
  async function runGate(input) {
@@ -94789,14 +95028,14 @@ async function runGate(input) {
94789
95028
  function emitGenerationEnvelope(type, resolvedPath, content, baseline, trends) {
94790
95029
  const rubric2 = loadRubric(type);
94791
95030
  const parsed = parseFrontmatter(content);
94792
- const frontmatter3 = parsed.data;
94793
- const description = frontmatter3.description;
95031
+ const frontmatter2 = parsed.data;
95032
+ const description = frontmatter2.description;
94794
95033
  const negativeConstraints = extractNegativeConstraints(description);
94795
95034
  const contentName = resolveContentName(resolvedPath);
94796
95035
  const dimMap = new Map(Object.entries(baseline.dimensions));
94797
95036
  const rubricByName = new Map(rubric2.dimensions.map((d) => [d.name, d]));
94798
95037
  const anchorHash = computeAnchorHash({
94799
- frontmatter: frontmatter3,
95038
+ frontmatter: frontmatter2,
94800
95039
  rubric_criteria: "",
94801
95040
  negative_constraints: negativeConstraints
94802
95041
  });
@@ -94809,7 +95048,7 @@ function emitGenerationEnvelope(type, resolvedPath, content, baseline, trends) {
94809
95048
  current_text: typeof description === "string" ? description : "",
94810
95049
  target_criterion: rubricDim?.criterion ?? `Improve ${dimName}`,
94811
95050
  anchor: {
94812
- frontmatter: frontmatter3,
95051
+ frontmatter: frontmatter2,
94813
95052
  rubric_criteria: rubricDim?.criterion ?? "",
94814
95053
  negative_constraints: negativeConstraints
94815
95054
  },
@@ -95079,7 +95318,7 @@ async function stepVerify(type, name, filePath, baselineScore, proposalDbId, opt
95079
95318
  let postScore = baselineScore;
95080
95319
  let postReport;
95081
95320
  try {
95082
- const report = await evaluate(type, filePath, {
95321
+ const report = await evaluate3(type, filePath, {
95083
95322
  target: opts?.target,
95084
95323
  adapter: db2,
95085
95324
  save: true,
@@ -95157,7 +95396,7 @@ async function evolve(type, name, opts) {
95157
95396
  }
95158
95397
  let baselineReport;
95159
95398
  try {
95160
- const report = await evaluate(type, resolvedPath, { target: opts?.target });
95399
+ const report = await evaluate3(type, resolvedPath, { target: opts?.target });
95161
95400
  if (!report)
95162
95401
  throw new Error("evaluate returned null in heuristic mode");
95163
95402
  baselineReport = report;
@@ -95430,7 +95669,7 @@ async function refine3(type, nameOrPath, opts) {
95430
95669
  let preScore;
95431
95670
  let preDimensions;
95432
95671
  try {
95433
- const report = await evaluate(type, resolvedPath ?? nameOrPath, { target: resolvedTarget });
95672
+ const report = await evaluate3(type, resolvedPath ?? nameOrPath, { target: resolvedTarget });
95434
95673
  if (!report)
95435
95674
  throw new Error("evaluate returned null in heuristic mode");
95436
95675
  preScore = report.aggregate;
@@ -95488,7 +95727,7 @@ async function refine3(type, nameOrPath, opts) {
95488
95727
  }
95489
95728
  let postScore;
95490
95729
  try {
95491
- const postReport = await evaluate(type, resolvedPath ?? nameOrPath, { target: resolvedTarget });
95730
+ const postReport = await evaluate3(type, resolvedPath ?? nameOrPath, { target: resolvedTarget });
95492
95731
  if (!postReport)
95493
95732
  throw new Error("evaluate returned null in heuristic mode");
95494
95733
  postScore = postReport.aggregate;
@@ -95505,7 +95744,7 @@ async function refine3(type, nameOrPath, opts) {
95505
95744
  }
95506
95745
  if (opts?.save) {
95507
95746
  try {
95508
- await evaluate(type, resolvedPath ?? nameOrPath, {
95747
+ await evaluate3(type, resolvedPath ?? nameOrPath, {
95509
95748
  target: resolvedTarget,
95510
95749
  save: true,
95511
95750
  operation: "refine"
@@ -95597,7 +95836,7 @@ async function agentValidate(opts) {
95597
95836
  }
95598
95837
  async function agentEvaluate(opts) {
95599
95838
  const target = resolveTarget(opts);
95600
- const report = await evaluate("agent", opts.nameOrPath, {
95839
+ const report = await evaluate3("agent", opts.nameOrPath, {
95601
95840
  target,
95602
95841
  save: opts.save,
95603
95842
  ...opts.rubric ? { rubric: opts.rubric } : {},
@@ -95687,7 +95926,7 @@ async function commandValidate(opts) {
95687
95926
  }
95688
95927
  async function commandEvaluate(opts) {
95689
95928
  const target = resolveTarget(opts);
95690
- const report = await evaluate("command", opts.nameOrPath, {
95929
+ const report = await evaluate3("command", opts.nameOrPath, {
95691
95930
  target,
95692
95931
  save: opts.save,
95693
95932
  ...opts.rubric ? { rubric: opts.rubric } : {},
@@ -95768,11 +96007,11 @@ import {
95768
96007
  readdirSync as readdirSync3,
95769
96008
  readFileSync as readFileSync13,
95770
96009
  rmSync as rmSync4,
95771
- statSync as statSync5,
96010
+ statSync as statSync6,
95772
96011
  writeFileSync as writeFileSync8
95773
96012
  } from "fs";
95774
96013
  import { homedir as homedir5 } from "os";
95775
- import { basename as basename13, join as join223 } from "path";
96014
+ import { join as join223 } from "path";
95776
96015
 
95777
96016
  // src/hooks.ts
95778
96017
  import { copyFileSync, existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "fs";
@@ -95907,9 +96146,11 @@ function registerInstall(program2) {
95907
96146
  }
95908
96147
  async function executeInstall(plugin, targets2, options2, dependencies = {}) {
95909
96148
  const runRulesyncImpl = dependencies.runRulesync ?? runRulesync;
96149
+ const runClaudeInstallImpl = dependencies.runClaudeInstall ?? defaultRunClaudeInstall;
95910
96150
  if (options2.verbose)
95911
96151
  echo(`Resolving plugin '${plugin}'...`);
95912
- const pluginRoot = resolvePluginRoot(plugin, options2.marketplacePath);
96152
+ const resolution = resolvePluginRoot(plugin, options2.marketplacePath);
96153
+ const pluginRoot = resolution.pluginRoot;
95913
96154
  if (options2.verbose)
95914
96155
  echo(`Plugin root: ${pluginRoot}`);
95915
96156
  const outputDir = ".rulesync";
@@ -95921,32 +96162,42 @@ async function executeInstall(plugin, targets2, options2, dependencies = {}) {
95921
96162
  }
95922
96163
  const targetInputRoots = new Map;
95923
96164
  for (const target of targets2) {
95924
- const targetInputRoot = prepareTargetRulesyncInput(outputDir, target);
96165
+ const targetInputRoot = prepareTargetRulesyncInput(outputDir, target, plugin);
95925
96166
  targetInputRoots.set(target, targetInputRoot);
95926
96167
  }
95927
- const rulesyncFeatures = ["skills", "commands", "subagents", "hooks", "mcp"];
96168
+ const rulesyncFeatures = ["skills", "hooks", ...mapResult.mcp ? ["mcp"] : []];
95928
96169
  const rulesyncTargets = targets2.filter((t) => t !== "claude" && t !== "hermes" && t !== "omp");
95929
96170
  if (targets2.includes("omp") && !targets2.includes("pi")) {
95930
96171
  if (!targetInputRoots.has("pi")) {
95931
- targetInputRoots.set("pi", prepareTargetRulesyncInput(outputDir, "pi"));
96172
+ targetInputRoots.set("pi", prepareTargetRulesyncInput(outputDir, "pi", plugin));
95932
96173
  }
95933
96174
  rulesyncTargets.push("pi");
95934
96175
  }
95935
96176
  if (targets2.includes("hermes") && !targets2.includes("opencode")) {
95936
96177
  if (!targetInputRoots.has("opencode")) {
95937
- targetInputRoots.set("opencode", prepareTargetRulesyncInput(outputDir, "opencode"));
96178
+ targetInputRoots.set("opencode", prepareTargetRulesyncInput(outputDir, "opencode", plugin));
95938
96179
  }
95939
96180
  rulesyncTargets.push("opencode");
95940
96181
  }
95941
96182
  const resultCounts = { skillsCount: 0, commandsCount: 0, subagentsCount: 0, hooksCount: 0 };
95942
96183
  if (rulesyncTargets.length > 0) {
96184
+ const usesProjectLayout = !options2.global || options2.outputRoot !== undefined;
96185
+ if (!options2.dryRun && usesProjectLayout) {
96186
+ const rulesyncRoot = options2.outputRoot ?? process.cwd();
96187
+ for (const target of rulesyncTargets) {
96188
+ const reldir = TARGET_SKILLS_RELDIR[target];
96189
+ if (reldir)
96190
+ mkdirSync9(join223(rulesyncRoot, reldir), { recursive: true });
96191
+ }
96192
+ }
95943
96193
  if (options2.verbose)
95944
96194
  echo(`Running rulesync for ${rulesyncTargets.join(", ")}...`);
95945
96195
  for (const target of rulesyncTargets) {
95946
96196
  const result = await runRulesyncImpl([target], [...rulesyncFeatures], targetInputRoots.get(target) ?? outputDir, {
95947
96197
  global: options2.global,
95948
96198
  dryRun: options2.dryRun,
95949
- verbose: options2.verbose
96199
+ verbose: options2.verbose,
96200
+ outputRoot: options2.outputRoot
95950
96201
  });
95951
96202
  resultCounts.skillsCount += result.skillsCount;
95952
96203
  resultCounts.commandsCount += result.commandsCount;
@@ -95962,13 +96213,14 @@ async function executeInstall(plugin, targets2, options2, dependencies = {}) {
95962
96213
  for (const target of targets2) {
95963
96214
  if (target === "claude") {
95964
96215
  if (options2.verbose)
95965
- echo("Claude Code: plugin marketplace update...");
96216
+ echo("Claude Code: registering marketplace and installing plugin...");
95966
96217
  if (!options2.dryRun) {
95967
- const proc = Bun.spawn(["claude", "plugin", "install", `${plugin}@local`, "--path", pluginRoot], {
95968
- stdout: "inherit",
95969
- stderr: "inherit"
95970
- });
95971
- await proc.exited;
96218
+ const marketplaceName = resolution.marketplaceName ?? "superskill";
96219
+ const marketplaceRoot = resolution.marketplaceRoot ?? process.cwd();
96220
+ const cacheDir = join223(homedir5(), ".claude", "plugins", "cache", marketplaceName);
96221
+ if (existsSync14(cacheDir))
96222
+ rmSync4(cacheDir, { recursive: true, force: true });
96223
+ await runClaudeInstallImpl(marketplaceRoot, marketplaceName, plugin);
95972
96224
  }
95973
96225
  }
95974
96226
  if (target === "hermes") {
@@ -96000,6 +96252,23 @@ async function executeInstall(plugin, targets2, options2, dependencies = {}) {
96000
96252
  hookEmitResults.push(hookResult);
96001
96253
  if (options2.verbose)
96002
96254
  echo(` ${hookResult.message}`);
96255
+ const agentsDir = join223(pluginRoot, "agents");
96256
+ if (existsSync14(agentsDir) && !options2.dryRun) {
96257
+ const piAgentsDir = join223(outputRoot, ".pi", "agent", "agents");
96258
+ mkdirSync9(piAgentsDir, { recursive: true });
96259
+ for (const entry of readdirSync3(agentsDir)) {
96260
+ if (!entry.endsWith(".md"))
96261
+ continue;
96262
+ const agentName = entry.replace(/\.md$/, "");
96263
+ const expectedName = `${plugin}-${agentName}`;
96264
+ const source = readFileSync13(join223(agentsDir, entry), "utf-8");
96265
+ const skillExists = (bare) => existsSync14(join223(pluginRoot, "skills", bare));
96266
+ const adapted = adaptSubagentToPi(source, expectedName, plugin, skillExists);
96267
+ writeFileSync8(join223(piAgentsDir, `${expectedName}.md`), adapted);
96268
+ }
96269
+ if (options2.verbose)
96270
+ echo(` Pi agents: dispatched to ${piAgentsDir}`);
96271
+ }
96003
96272
  }
96004
96273
  }
96005
96274
  for (const result of hookEmitResults) {
@@ -96011,6 +96280,18 @@ async function executeInstall(plugin, targets2, options2, dependencies = {}) {
96011
96280
  echo(`Installed '${plugin}' to ${targets2.length} target(s).`);
96012
96281
  }
96013
96282
  }
96283
+ async function defaultRunClaudeInstall(marketplaceRoot, marketplaceName, plugin) {
96284
+ const addProc = Bun.spawn(["claude", "plugin", "marketplace", "add", marketplaceRoot], {
96285
+ stdout: "inherit",
96286
+ stderr: "inherit"
96287
+ });
96288
+ await addProc.exited;
96289
+ const installProc = Bun.spawn(["claude", "plugin", "install", `${plugin}@${marketplaceName}`], {
96290
+ stdout: "inherit",
96291
+ stderr: "inherit"
96292
+ });
96293
+ await installProc.exited;
96294
+ }
96014
96295
  function parseTargets(raw) {
96015
96296
  if (!raw)
96016
96297
  return [...TARGETS];
@@ -96026,21 +96307,32 @@ function parseTargets(raw) {
96026
96307
  }
96027
96308
  function resolvePluginRoot(plugin, marketplacePath) {
96028
96309
  const resolved = resolvePlugin(marketplacePath, plugin);
96029
- if (resolved)
96030
- return resolved.pluginRoot;
96310
+ if (resolved) {
96311
+ const manifestRoot = resolved.marketplaceRoot;
96312
+ const manifestPath = join223(manifestRoot, ".claude-plugin", "marketplace.json");
96313
+ let marketplaceName;
96314
+ if (existsSync14(manifestPath)) {
96315
+ try {
96316
+ const raw = readFileSync13(manifestPath, "utf-8");
96317
+ const parsed = JSON.parse(raw);
96318
+ marketplaceName = parsed.name;
96319
+ } catch {}
96320
+ }
96321
+ return { pluginRoot: resolved.pluginRoot, marketplaceRoot: manifestRoot, marketplaceName };
96322
+ }
96031
96323
  const fallback = join223("plugins", plugin);
96032
96324
  if (existsSync14(join223(fallback, "plugin.json")))
96033
- return fallback;
96325
+ return { pluginRoot: fallback };
96034
96326
  const available = listResolvablePlugins(marketplacePath);
96035
96327
  const msg = available.length > 0 ? `Available: ${available.join(", ")}` : "No marketplace manifest found and no plugins/<name>/ directory.";
96036
96328
  throw new Error(`Plugin '${plugin}' not found. ${msg}`);
96037
96329
  }
96038
- function prepareTargetRulesyncInput(sourceRoot, target) {
96330
+ function prepareTargetRulesyncInput(sourceRoot, target, pluginName) {
96039
96331
  const targetRoot = join223(sourceRoot, ".targets", target);
96040
96332
  const targetRulesyncRoot = join223(targetRoot, ".rulesync");
96041
96333
  rmSync4(targetRoot, { recursive: true, force: true });
96042
96334
  copyDirectory(sourceRoot, targetRulesyncRoot, { skipDirectoryNames: new Set([".targets"]) });
96043
- transformRulesyncMarkdown(targetRulesyncRoot, target);
96335
+ transformRulesyncMarkdown(targetRulesyncRoot, target, pluginName);
96044
96336
  return targetRoot;
96045
96337
  }
96046
96338
  function rulesyncSourceRoot(inputRoot, fallbackRoot) {
@@ -96060,36 +96352,25 @@ function emitHooksForSurrogateTarget(target, rulesyncSourceDir, outputRoot, opti
96060
96352
  }
96061
96353
  return null;
96062
96354
  }
96063
- function transformRulesyncMarkdown(root, target) {
96064
- transformMarkdownDirectory(join223(root, "skills"), target);
96065
- transformMarkdownDirectory(join223(root, "commands"), target, { normalizeName: true, translateSlash: true });
96066
- transformMarkdownDirectory(join223(root, "subagents"), target, {
96067
- normalizeName: true,
96068
- piSubagent: target === "pi" || target === "omp"
96069
- });
96355
+ function transformRulesyncMarkdown(root, target, pluginName) {
96356
+ transformMarkdownDirectory(join223(root, "skills"), target, pluginName);
96070
96357
  }
96071
- function transformMarkdownDirectory(dir, target, options2 = {}) {
96358
+ function transformMarkdownDirectory(dir, target, pluginName) {
96072
96359
  if (!existsSync14(dir))
96073
96360
  return;
96074
96361
  for (const entry of readdirSync3(dir)) {
96075
96362
  const path11 = join223(dir, entry);
96076
- const stats = statSync5(path11);
96363
+ const stats = statSync6(path11);
96077
96364
  if (stats.isDirectory()) {
96078
- transformMarkdownDirectory(path11, target, options2);
96365
+ transformMarkdownDirectory(path11, target, pluginName);
96079
96366
  continue;
96080
96367
  }
96081
96368
  if (!entry.endsWith(".md"))
96082
96369
  continue;
96083
- const name = entry === "SKILL.md" ? basename13(dir) : entry.replace(/\.md$/, "");
96084
- let content = readFileSync13(path11, "utf-8");
96085
- if (options2.normalizeName)
96086
- content = normalizeFrontmatter(content, name);
96087
- if (options2.translateSlash)
96088
- content = translateSlashCommands(content, target);
96089
- content = rewriteColonRefs(content);
96090
- if (options2.piSubagent)
96091
- content = convertToPiSubagent(content);
96092
- writeFileSync8(path11, content);
96370
+ const content = readFileSync13(path11, "utf-8");
96371
+ const slashTranslated = translateSlashCommands(content, target);
96372
+ const transformed = rewriteSkillReferences(slashTranslated, pluginName);
96373
+ writeFileSync8(path11, transformed);
96093
96374
  }
96094
96375
  }
96095
96376
  function copyDirectory(source, destination, options2 = {}) {
@@ -96101,7 +96382,7 @@ function copyDirectory(source, destination, options2 = {}) {
96101
96382
  continue;
96102
96383
  const sourcePath = join223(source, entry);
96103
96384
  const destinationPath = join223(destination, entry);
96104
- if (statSync5(sourcePath).isDirectory()) {
96385
+ if (statSync6(sourcePath).isDirectory()) {
96105
96386
  copyDirectory(sourcePath, destinationPath, options2);
96106
96387
  } else {
96107
96388
  copyFileSync2(sourcePath, destinationPath);
@@ -96125,7 +96406,7 @@ async function validateHook(nameOrPath, opts) {
96125
96406
  }
96126
96407
  async function evaluateHook2(nameOrPath, opts) {
96127
96408
  const target = resolveTarget(opts);
96128
- return evaluate("hook", nameOrPath, {
96409
+ return evaluate3("hook", nameOrPath, {
96129
96410
  target,
96130
96411
  save: opts.save,
96131
96412
  ...opts.rubric ? { rubric: opts.rubric } : {},
@@ -96154,11 +96435,11 @@ async function emitHook(name, opts) {
96154
96435
  const global3 = opts.global !== false;
96155
96436
  const dryRun = opts.dryRun === true;
96156
96437
  const outputRoot = global3 ? homedir6() : process.cwd();
96157
- const pluginRoot = resolvePluginRoot(name);
96438
+ const pluginRoot = resolvePluginRoot(name).pluginRoot;
96158
96439
  const outputDir = ".rulesync";
96159
96440
  mapPluginToRulesync(pluginRoot, name, outputDir);
96160
96441
  if (target !== "pi" && target !== "omp" && target !== "hermes") {
96161
- const targetInputRoot = prepareTargetRulesyncInput(outputDir, target);
96442
+ const targetInputRoot = prepareTargetRulesyncInput(outputDir, target, name);
96162
96443
  const result = await runRulesync([target], ["hooks"], targetInputRoot, { global: global3, dryRun, verbose: false });
96163
96444
  return {
96164
96445
  count: result.hooksCount,
@@ -96166,7 +96447,7 @@ async function emitHook(name, opts) {
96166
96447
  };
96167
96448
  }
96168
96449
  const surrogateSourceTarget = target === "hermes" ? "opencode" : "pi";
96169
- const surrogateInputRoot = prepareTargetRulesyncInput(outputDir, surrogateSourceTarget);
96450
+ const surrogateInputRoot = prepareTargetRulesyncInput(outputDir, surrogateSourceTarget, name);
96170
96451
  const surrogateSourceDir = join225(surrogateInputRoot, ".rulesync");
96171
96452
  const hookResult = emitHooksForSurrogateTarget(target, surrogateSourceDir, outputRoot, { dryRun, global: global3 });
96172
96453
  if (!hookResult) {
@@ -96256,7 +96537,7 @@ async function magentValidate(opts) {
96256
96537
  }
96257
96538
  async function magentEvaluate(opts) {
96258
96539
  const target = resolveTarget(opts);
96259
- const report = await evaluate("magent", opts.nameOrPath, {
96540
+ const report = await evaluate3("magent", opts.nameOrPath, {
96260
96541
  target,
96261
96542
  save: opts.save,
96262
96543
  ...opts.rubric ? { rubric: opts.rubric } : {},
@@ -96400,7 +96681,7 @@ async function skillValidate(opts) {
96400
96681
  }
96401
96682
  async function skillEvaluate(opts) {
96402
96683
  const target = resolveTarget(opts);
96403
- const report = await evaluate("skill", opts.nameOrPath, {
96684
+ const report = await evaluate3("skill", opts.nameOrPath, {
96404
96685
  target,
96405
96686
  save: opts.save,
96406
96687
  ...opts.rubric ? { rubric: opts.rubric } : {},