prpm 1.1.20 → 1.1.21

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 CHANGED
@@ -101,7 +101,8 @@ function addToLockfile(lockfile, packageId, packageInfo) {
101
101
  installedPath: packageInfo.installedPath,
102
102
  fromCollection: packageInfo.fromCollection,
103
103
  hookMetadata: packageInfo.hookMetadata,
104
- progressiveDisclosure: packageInfo.progressiveDisclosure
104
+ progressiveDisclosure: packageInfo.progressiveDisclosure,
105
+ pluginMetadata: packageInfo.pluginMetadata
105
106
  };
106
107
  lockfile.generated = (/* @__PURE__ */ new Date()).toISOString();
107
108
  }
@@ -518,6 +519,223 @@ var init_canonical = __esm({
518
519
  }
519
520
  });
520
521
 
522
+ // ../converters/dist/cursor-hooks-constants.js
523
+ function isValidCursorHookType(hookType) {
524
+ return VALID_CURSOR_HOOK_TYPES.includes(hookType);
525
+ }
526
+ function isValidHookMappingStrategy(strategy) {
527
+ return VALID_HOOK_MAPPING_STRATEGIES.includes(strategy);
528
+ }
529
+ function getScriptExtension(language) {
530
+ return SCRIPT_LANGUAGE_EXTENSIONS[language] || "sh";
531
+ }
532
+ var VALID_CURSOR_HOOK_TYPES, VALID_HOOK_MAPPING_STRATEGIES, SCRIPT_LANGUAGE_EXTENSIONS;
533
+ var init_cursor_hooks_constants = __esm({
534
+ "../converters/dist/cursor-hooks-constants.js"() {
535
+ "use strict";
536
+ init_cjs_shims();
537
+ VALID_CURSOR_HOOK_TYPES = [
538
+ "beforeShellExecution",
539
+ "afterShellExecution",
540
+ "beforeMCPExecution",
541
+ "afterMCPExecution",
542
+ "beforeReadFile",
543
+ "afterFileEdit",
544
+ "beforeSubmitPrompt",
545
+ "stop",
546
+ "afterAgentResponse",
547
+ "afterAgentThought",
548
+ "beforeTabFileRead",
549
+ "afterTabFileEdit"
550
+ ];
551
+ VALID_HOOK_MAPPING_STRATEGIES = ["auto", "strict", "skip"];
552
+ SCRIPT_LANGUAGE_EXTENSIONS = {
553
+ bash: "sh",
554
+ python: "py",
555
+ javascript: "js",
556
+ typescript: "js",
557
+ // TypeScript compiles to JS
558
+ binary: "bin"
559
+ };
560
+ }
561
+ });
562
+
563
+ // ../converters/dist/hook-mappings.js
564
+ function getQualityPenalty(quality) {
565
+ switch (quality) {
566
+ case "direct":
567
+ return 0;
568
+ case "semantic":
569
+ return 5;
570
+ case "none":
571
+ return 30;
572
+ }
573
+ }
574
+ function getHookMapping(sourceFormat, targetFormat, sourceHookType) {
575
+ const key = `${sourceFormat.toUpperCase()}_TO_${targetFormat.toUpperCase()}`;
576
+ switch (key) {
577
+ case "CLAUDE_TO_CURSOR":
578
+ return CLAUDE_TO_CURSOR[sourceHookType] || null;
579
+ case "CURSOR_TO_CLAUDE":
580
+ return CURSOR_TO_CLAUDE[sourceHookType] || null;
581
+ case "KIRO_TO_CURSOR":
582
+ return KIRO_TO_CURSOR[sourceHookType] || null;
583
+ case "CURSOR_TO_KIRO":
584
+ return CURSOR_TO_KIRO[sourceHookType] || null;
585
+ case "CLAUDE_TO_KIRO":
586
+ return CLAUDE_TO_KIRO[sourceHookType] || null;
587
+ case "KIRO_TO_CLAUDE":
588
+ return KIRO_TO_CLAUDE[sourceHookType] || null;
589
+ default:
590
+ return null;
591
+ }
592
+ }
593
+ function mapHook(sourceFormat, targetFormat, sourceHookType, strategy) {
594
+ if (sourceFormat === targetFormat) {
595
+ return {
596
+ mapped: true,
597
+ targetHookType: sourceHookType,
598
+ quality: "direct",
599
+ qualityPenalty: 0
600
+ };
601
+ }
602
+ if (strategy === "skip") {
603
+ return {
604
+ mapped: false,
605
+ targetHookType: null,
606
+ quality: "none",
607
+ warning: "Hook conversion skipped (--hook-mapping skip)",
608
+ qualityPenalty: 0
609
+ };
610
+ }
611
+ const mapping = getHookMapping(sourceFormat, targetFormat, sourceHookType);
612
+ if (!mapping) {
613
+ return {
614
+ mapped: false,
615
+ targetHookType: null,
616
+ quality: "none",
617
+ warning: `No mapping defined for ${sourceFormat} hook "${sourceHookType}" to ${targetFormat}`,
618
+ qualityPenalty: 30
619
+ };
620
+ }
621
+ if (strategy === "strict" && mapping.quality !== "direct") {
622
+ return {
623
+ mapped: false,
624
+ targetHookType: null,
625
+ quality: mapping.quality,
626
+ warning: `Hook "${sourceHookType}" not converted (strict mode requires direct match, found ${mapping.quality} match)`,
627
+ qualityPenalty: 30
628
+ };
629
+ }
630
+ if (!mapping.target) {
631
+ return {
632
+ mapped: false,
633
+ targetHookType: null,
634
+ quality: mapping.quality,
635
+ warning: `${sourceFormat} hook "${sourceHookType}" has no ${targetFormat} equivalent. ${mapping.notes}`,
636
+ qualityPenalty: getQualityPenalty(mapping.quality)
637
+ };
638
+ }
639
+ return {
640
+ mapped: true,
641
+ targetHookType: mapping.target,
642
+ quality: mapping.quality,
643
+ warning: mapping.quality === "semantic" ? `${sourceFormat} hook "${sourceHookType}" mapped to ${targetFormat} hook "${mapping.target}" (semantic match). ${mapping.notes}` : void 0,
644
+ qualityPenalty: getQualityPenalty(mapping.quality)
645
+ };
646
+ }
647
+ function mapHooks(sourceFormat, targetFormat, sourceHookTypes, strategy = "auto") {
648
+ const results = /* @__PURE__ */ new Map();
649
+ let totalQualityPenalty = 0;
650
+ const warnings = [];
651
+ for (const hookType of sourceHookTypes) {
652
+ const result = mapHook(sourceFormat, targetFormat, hookType, strategy);
653
+ results.set(hookType, result);
654
+ totalQualityPenalty += result.qualityPenalty;
655
+ if (result.warning) {
656
+ warnings.push(result.warning);
657
+ }
658
+ }
659
+ return { results, totalQualityPenalty, warnings };
660
+ }
661
+ var CLAUDE_TO_CURSOR, CURSOR_TO_CLAUDE, KIRO_TO_CURSOR, CURSOR_TO_KIRO, CLAUDE_TO_KIRO, KIRO_TO_CLAUDE;
662
+ var init_hook_mappings = __esm({
663
+ "../converters/dist/hook-mappings.js"() {
664
+ "use strict";
665
+ init_cjs_shims();
666
+ CLAUDE_TO_CURSOR = {
667
+ "session-start": {
668
+ target: null,
669
+ quality: "none",
670
+ notes: "Cursor has no session start hook - no equivalent lifecycle event"
671
+ },
672
+ "user-prompt-submit": {
673
+ target: "beforeSubmitPrompt",
674
+ quality: "direct",
675
+ notes: "Direct semantic match - both run before prompt submission"
676
+ },
677
+ "tool-call": {
678
+ target: "beforeMCPExecution",
679
+ quality: "semantic",
680
+ notes: "Semantic match - Claude tool-call maps to Cursor MCP execution"
681
+ },
682
+ "assistant-response": {
683
+ target: "afterAgentResponse",
684
+ quality: "direct",
685
+ notes: "Direct semantic match - both run after agent generates response"
686
+ }
687
+ };
688
+ CURSOR_TO_CLAUDE = {
689
+ "beforeShellExecution": { target: null, quality: "none", notes: "Claude has no shell execution hooks" },
690
+ "afterShellExecution": { target: null, quality: "none", notes: "Claude has no shell execution hooks" },
691
+ "beforeMCPExecution": { target: "tool-call", quality: "semantic", notes: "Maps to Claude tool-call event" },
692
+ "afterMCPExecution": { target: null, quality: "none", notes: "Claude has no post-tool hook" },
693
+ "beforeReadFile": { target: null, quality: "none", notes: "Claude has no file read hooks" },
694
+ "afterFileEdit": { target: null, quality: "none", notes: "Claude has no file edit hooks" },
695
+ "beforeSubmitPrompt": { target: "user-prompt-submit", quality: "direct", notes: "Direct semantic match" },
696
+ "stop": { target: null, quality: "none", notes: "Claude has no stop hook" },
697
+ "afterAgentResponse": { target: "assistant-response", quality: "direct", notes: "Direct semantic match" },
698
+ "afterAgentThought": { target: null, quality: "none", notes: "Claude has no thought hooks" },
699
+ "beforeTabFileRead": { target: null, quality: "none", notes: "Tab hooks are Cursor-specific" },
700
+ "afterTabFileEdit": { target: null, quality: "none", notes: "Tab hooks are Cursor-specific" }
701
+ };
702
+ KIRO_TO_CURSOR = {
703
+ "agentSpawn": { target: null, quality: "none", notes: "Cursor has no agent spawn hook" },
704
+ "userPromptSubmit": { target: "beforeSubmitPrompt", quality: "direct", notes: "Direct semantic match" },
705
+ "preToolUse": { target: "beforeMCPExecution", quality: "semantic", notes: "Kiro tools map to Cursor MCP" },
706
+ "postToolUse": { target: "afterMCPExecution", quality: "semantic", notes: "Kiro tools map to Cursor MCP" },
707
+ "stop": { target: "stop", quality: "direct", notes: "Direct semantic match" }
708
+ };
709
+ CURSOR_TO_KIRO = {
710
+ "beforeShellExecution": { target: null, quality: "none", notes: "Kiro has no shell hooks" },
711
+ "afterShellExecution": { target: null, quality: "none", notes: "Kiro has no shell hooks" },
712
+ "beforeMCPExecution": { target: "preToolUse", quality: "semantic", notes: "Cursor MCP maps to Kiro tools" },
713
+ "afterMCPExecution": { target: "postToolUse", quality: "semantic", notes: "Cursor MCP maps to Kiro tools" },
714
+ "beforeReadFile": { target: null, quality: "none", notes: "Kiro has no file read hooks" },
715
+ "afterFileEdit": { target: null, quality: "none", notes: "Kiro has no file edit hooks" },
716
+ "beforeSubmitPrompt": { target: "userPromptSubmit", quality: "direct", notes: "Direct semantic match" },
717
+ "stop": { target: "stop", quality: "direct", notes: "Direct semantic match" },
718
+ "afterAgentResponse": { target: null, quality: "none", notes: "Kiro has no response hooks" },
719
+ "afterAgentThought": { target: null, quality: "none", notes: "Kiro has no thought hooks" },
720
+ "beforeTabFileRead": { target: null, quality: "none", notes: "Tab hooks are Cursor-specific" },
721
+ "afterTabFileEdit": { target: null, quality: "none", notes: "Tab hooks are Cursor-specific" }
722
+ };
723
+ CLAUDE_TO_KIRO = {
724
+ "session-start": { target: "agentSpawn", quality: "semantic", notes: "Session start maps to agent spawn" },
725
+ "user-prompt-submit": { target: "userPromptSubmit", quality: "direct", notes: "Direct semantic match" },
726
+ "tool-call": { target: "preToolUse", quality: "semantic", notes: "Tool call maps to pre-tool use" },
727
+ "assistant-response": { target: null, quality: "none", notes: "Kiro has no response hooks" }
728
+ };
729
+ KIRO_TO_CLAUDE = {
730
+ "agentSpawn": { target: "session-start", quality: "semantic", notes: "Agent spawn maps to session start" },
731
+ "userPromptSubmit": { target: "user-prompt-submit", quality: "direct", notes: "Direct semantic match" },
732
+ "preToolUse": { target: "tool-call", quality: "semantic", notes: "Pre-tool use maps to tool call" },
733
+ "postToolUse": { target: null, quality: "none", notes: "Claude has no post-tool hook" },
734
+ "stop": { target: null, quality: "none", notes: "Claude has no stop hook" }
735
+ };
736
+ }
737
+ });
738
+
521
739
  // ../converters/dist/taxonomy-utils.js
522
740
  function detectSubtypeFromFrontmatter(frontmatter, explicitSubtype) {
523
741
  if (explicitSubtype) {
@@ -552,7 +770,7 @@ function normalizeFormat(sourceFormat) {
552
770
  return "copilot";
553
771
  if (normalized.includes("kiro"))
554
772
  return "kiro";
555
- if (normalized.includes("agents.md") || normalized.includes("agentsmd"))
773
+ if (normalized.includes("agents.md") || normalized.includes("agentsmd") || normalized.includes("agents-md"))
556
774
  return "agents.md";
557
775
  if (normalized.includes("gemini"))
558
776
  return "gemini";
@@ -882,6 +1100,154 @@ var init_from_cursor = __esm({
882
1100
  }
883
1101
  });
884
1102
 
1103
+ // ../converters/dist/from-cursor-hooks.js
1104
+ function fromCursorHooks(content, metadata) {
1105
+ let hooksConfig;
1106
+ try {
1107
+ hooksConfig = JSON.parse(content);
1108
+ } catch (error) {
1109
+ throw new Error(`Invalid Cursor hooks JSON: ${error instanceof Error ? error.message : "Unknown error"}`);
1110
+ }
1111
+ const hookSections = Object.entries(hooksConfig).map(([hookType, scriptPath]) => {
1112
+ if (!isValidCursorHookType(hookType)) {
1113
+ throw new Error(`Invalid hook type: ${hookType}. Valid types: ${VALID_CURSOR_HOOK_TYPES.join(", ")}`);
1114
+ }
1115
+ return {
1116
+ type: "cursor-hook",
1117
+ hookType,
1118
+ scriptPath,
1119
+ description: `Cursor ${hookType} hook`
1120
+ };
1121
+ });
1122
+ const pkg = {
1123
+ id: metadata.id,
1124
+ version: metadata.version,
1125
+ name: metadata.name,
1126
+ description: metadata.description || `Cursor hooks configuration`,
1127
+ author: metadata.author,
1128
+ organization: metadata.organization,
1129
+ tags: metadata.tags || ["cursor", "hooks"],
1130
+ format: "cursor",
1131
+ subtype: "hook",
1132
+ // Additional metadata
1133
+ license: metadata.license,
1134
+ repository: metadata.repository,
1135
+ homepage: metadata.homepage,
1136
+ documentation: metadata.documentation,
1137
+ keywords: metadata.keywords,
1138
+ category: metadata.category,
1139
+ dependencies: metadata.dependencies,
1140
+ peerDependencies: metadata.peerDependencies,
1141
+ engines: metadata.engines,
1142
+ content: {
1143
+ format: "canonical",
1144
+ version: "1.0",
1145
+ sections: hookSections
1146
+ },
1147
+ sourceFormat: "cursor"
1148
+ };
1149
+ return pkg;
1150
+ }
1151
+ var init_from_cursor_hooks = __esm({
1152
+ "../converters/dist/from-cursor-hooks.js"() {
1153
+ "use strict";
1154
+ init_cjs_shims();
1155
+ init_cursor_hooks_constants();
1156
+ }
1157
+ });
1158
+
1159
+ // ../converters/dist/from-claude-plugin.js
1160
+ function fromClaudePlugin(pluginJson, contents, metadata) {
1161
+ var _a, _b, _c;
1162
+ const sections = [];
1163
+ const metadataSection = {
1164
+ type: "metadata",
1165
+ data: {
1166
+ title: pluginJson.name || metadata.name,
1167
+ description: pluginJson.description || "",
1168
+ version: pluginJson.version || metadata.version || "1.0.0",
1169
+ author: pluginJson.author || metadata.author,
1170
+ // Store MCP servers in metadata for later extraction
1171
+ claudePlugin: {
1172
+ mcpServers: pluginJson.mcpServers,
1173
+ contents: {
1174
+ agents: contents.agents || [],
1175
+ skills: contents.skills || [],
1176
+ commands: contents.commands || []
1177
+ }
1178
+ }
1179
+ }
1180
+ };
1181
+ sections.push(metadataSection);
1182
+ if (pluginJson.description) {
1183
+ sections.push({
1184
+ type: "instructions",
1185
+ title: "Overview",
1186
+ content: pluginJson.description
1187
+ });
1188
+ }
1189
+ const contentsSummary = [];
1190
+ if ((_a = contents.agents) == null ? void 0 : _a.length) {
1191
+ contentsSummary.push(`- **Agents**: ${contents.agents.length} agents`);
1192
+ }
1193
+ if ((_b = contents.skills) == null ? void 0 : _b.length) {
1194
+ contentsSummary.push(`- **Skills**: ${contents.skills.length} skills`);
1195
+ }
1196
+ if ((_c = contents.commands) == null ? void 0 : _c.length) {
1197
+ contentsSummary.push(`- **Commands**: ${contents.commands.length} commands`);
1198
+ }
1199
+ if (pluginJson.mcpServers && Object.keys(pluginJson.mcpServers).length > 0) {
1200
+ contentsSummary.push(`- **MCP Servers**: ${Object.keys(pluginJson.mcpServers).join(", ")}`);
1201
+ }
1202
+ if (contentsSummary.length > 0) {
1203
+ sections.push({
1204
+ type: "context",
1205
+ title: "Plugin Contents",
1206
+ content: contentsSummary.join("\n")
1207
+ });
1208
+ }
1209
+ const pkg = {
1210
+ id: metadata.id,
1211
+ version: pluginJson.version || metadata.version || "1.0.0",
1212
+ name: pluginJson.name || metadata.name,
1213
+ description: pluginJson.description || "",
1214
+ author: pluginJson.author || metadata.author || "unknown",
1215
+ tags: pluginJson.keywords || metadata.tags || [],
1216
+ content: {
1217
+ format: "canonical",
1218
+ version: "1.0",
1219
+ sections
1220
+ },
1221
+ sourceFormat: "claude",
1222
+ metadata: {
1223
+ title: metadataSection.data.title,
1224
+ description: metadataSection.data.description,
1225
+ version: metadataSection.data.version,
1226
+ author: metadataSection.data.author,
1227
+ claudePlugin: metadataSection.data.claudePlugin
1228
+ }
1229
+ };
1230
+ setTaxonomy(pkg, "claude", "plugin");
1231
+ return pkg;
1232
+ }
1233
+ function parsePluginJson(content) {
1234
+ try {
1235
+ return JSON.parse(content);
1236
+ } catch (error) {
1237
+ throw new Error(`Failed to parse plugin.json: ${error instanceof Error ? error.message : String(error)}`);
1238
+ }
1239
+ }
1240
+ function extractMCPServers(pluginJson) {
1241
+ return pluginJson.mcpServers || {};
1242
+ }
1243
+ var init_from_claude_plugin = __esm({
1244
+ "../converters/dist/from-claude-plugin.js"() {
1245
+ "use strict";
1246
+ init_cjs_shims();
1247
+ init_taxonomy_utils();
1248
+ }
1249
+ });
1250
+
885
1251
  // ../converters/dist/from-continue.js
886
1252
  function fromContinue(content, metadata, explicitSubtype) {
887
1253
  const pkg = fromClaude(content, metadata, "continue", explicitSubtype);
@@ -7946,6 +8312,105 @@ var init_from_replit = __esm({
7946
8312
  }
7947
8313
  });
7948
8314
 
8315
+ // ../converters/dist/from-mcp-server.js
8316
+ function fromMCPServer(mcpServerJson, metadata) {
8317
+ var _a;
8318
+ const pkg = {
8319
+ id: metadata.id,
8320
+ version: mcpServerJson.version || metadata.version,
8321
+ name: mcpServerJson.name || metadata.name,
8322
+ description: mcpServerJson.description || metadata.description || "MCP Server package",
8323
+ author: mcpServerJson.author || metadata.author,
8324
+ organization: metadata.organization,
8325
+ tags: metadata.tags || ["mcp", "server"],
8326
+ license: mcpServerJson.license || metadata.license,
8327
+ repository: mcpServerJson.repository || metadata.repository,
8328
+ homepage: mcpServerJson.homepage || metadata.homepage
8329
+ };
8330
+ setTaxonomy(pkg, "mcp", "server");
8331
+ const sections = [];
8332
+ sections.push({
8333
+ type: "metadata",
8334
+ data: {
8335
+ title: pkg.name,
8336
+ description: pkg.description
8337
+ }
8338
+ });
8339
+ const serverDescriptions = [];
8340
+ for (const [serverName, serverConfig] of Object.entries(mcpServerJson.mcpServers)) {
8341
+ const serverType = serverConfig.type || "stdio";
8342
+ if (serverType === "stdio" && serverConfig.command) {
8343
+ const args = ((_a = serverConfig.args) == null ? void 0 : _a.join(" ")) || "";
8344
+ serverDescriptions.push(`- **${serverName}**: \`${serverConfig.command} ${args}\``);
8345
+ } else if ((serverType === "http" || serverType === "sse") && serverConfig.url) {
8346
+ serverDescriptions.push(`- **${serverName}**: ${serverConfig.url} (${serverType})`);
8347
+ }
8348
+ if (serverConfig.env && Object.keys(serverConfig.env).length > 0) {
8349
+ const envVars = Object.keys(serverConfig.env).join(", ");
8350
+ serverDescriptions.push(` - Environment: ${envVars}`);
8351
+ }
8352
+ }
8353
+ if (serverDescriptions.length > 0) {
8354
+ sections.push({
8355
+ type: "instructions",
8356
+ title: "MCP Servers",
8357
+ content: `This package provides the following MCP servers:
8358
+
8359
+ ${serverDescriptions.join("\n")}`
8360
+ });
8361
+ }
8362
+ pkg.metadata = {
8363
+ title: pkg.name,
8364
+ description: pkg.description,
8365
+ claudePlugin: {
8366
+ mcpServers: mcpServerJson.mcpServers
8367
+ }
8368
+ };
8369
+ pkg.content = {
8370
+ format: "canonical",
8371
+ version: "1.0",
8372
+ sections
8373
+ };
8374
+ return pkg;
8375
+ }
8376
+ function parseMCPServerJson(jsonString) {
8377
+ const parsed = JSON.parse(jsonString);
8378
+ if (!parsed.name) {
8379
+ throw new Error("MCP server package must have a name");
8380
+ }
8381
+ if (!parsed.mcpServers || typeof parsed.mcpServers !== "object") {
8382
+ throw new Error("MCP server package must have mcpServers configuration");
8383
+ }
8384
+ if (Object.keys(parsed.mcpServers).length === 0) {
8385
+ throw new Error("MCP server package must define at least one server");
8386
+ }
8387
+ for (const [serverName, serverConfig] of Object.entries(parsed.mcpServers)) {
8388
+ const config = serverConfig;
8389
+ const serverType = config.type || "stdio";
8390
+ if (serverType === "stdio" && !config.command) {
8391
+ throw new Error(`MCP server '${serverName}' of type stdio must have a command`);
8392
+ }
8393
+ if ((serverType === "http" || serverType === "sse") && !config.url) {
8394
+ throw new Error(`MCP server '${serverName}' of type ${serverType} must have a url`);
8395
+ }
8396
+ }
8397
+ return parsed;
8398
+ }
8399
+ function extractMCPServers2(pkg) {
8400
+ var _a, _b;
8401
+ if ((_b = (_a = pkg.metadata) == null ? void 0 : _a.claudePlugin) == null ? void 0 : _b.mcpServers) {
8402
+ return pkg.metadata.claudePlugin.mcpServers;
8403
+ }
8404
+ return null;
8405
+ }
8406
+ var init_from_mcp_server = __esm({
8407
+ "../converters/dist/from-mcp-server.js"() {
8408
+ "use strict";
8409
+ init_cjs_shims();
8410
+ init_taxonomy_utils();
8411
+ }
8412
+ });
8413
+
7949
8414
  // ../converters/dist/validation.js
7950
8415
  function loadSchema(format, subtype) {
7951
8416
  const cacheKey = subtype ? `${format}:${subtype}` : format;
@@ -7960,6 +8425,8 @@ function loadSchema(format, subtype) {
7960
8425
  "claude:slash-command": "claude-slash-command.schema.json",
7961
8426
  "claude:hook": "claude-hook.schema.json",
7962
8427
  "cursor:slash-command": "cursor-command.schema.json",
8428
+ "cursor:hook": "cursor-hooks.schema.json",
8429
+ // cursor + hook subtype uses cursor-hooks schema
7963
8430
  "kiro:hook": "kiro-hooks.schema.json",
7964
8431
  "kiro:agent": "kiro-agent.schema.json",
7965
8432
  "droid:skill": "droid-skill.schema.json",
@@ -7977,7 +8444,7 @@ function loadSchema(format, subtype) {
7977
8444
  "windsurf": "windsurf.schema.json",
7978
8445
  "copilot": "copilot.schema.json",
7979
8446
  "kiro": "kiro-steering.schema.json",
7980
- "agents-md": "agents-md.schema.json",
8447
+ "agents.md": "agents-md.schema.json",
7981
8448
  "gemini": "gemini.schema.json",
7982
8449
  "opencode": "opencode.schema.json",
7983
8450
  "ruler": "ruler.schema.json",
@@ -7987,6 +8454,7 @@ function loadSchema(format, subtype) {
7987
8454
  "zencoder": "zencoder.schema.json",
7988
8455
  "replit": "replit.schema.json",
7989
8456
  "canonical": "canonical.schema.json"
8457
+ // generic and mcp don't have specific schemas, will use fallback
7990
8458
  };
7991
8459
  schemaFilename = schemaMap[format] || `${format}.schema.json`;
7992
8460
  }
@@ -8079,7 +8547,8 @@ function parseMarkdownWithFrontmatter(markdown) {
8079
8547
  content: markdown
8080
8548
  };
8081
8549
  }
8082
- const frontmatterText = lines.slice(1, closingIndex + 1).join("\n");
8550
+ let frontmatterText = lines.slice(1, closingIndex + 1).join("\n");
8551
+ frontmatterText = frontmatterText.replace(/^(argument-hint:\s*)(\[[\w-]+\](?:\s+\[[\w-]+\])+)\s*$/m, (_, prefix, value) => `${prefix}"${value}"`);
8083
8552
  let frontmatter = {};
8084
8553
  try {
8085
8554
  const parsed = jsYaml.load(frontmatterText);
@@ -8093,7 +8562,7 @@ function parseMarkdownWithFrontmatter(markdown) {
8093
8562
  }
8094
8563
  function validateMarkdown(format, markdown, subtype) {
8095
8564
  const { frontmatter, content } = parseMarkdownWithFrontmatter(markdown);
8096
- if (format === "windsurf" || format === "agents-md" || format === "ruler") {
8565
+ if (format === "windsurf" || format === "agents.md" || format === "ruler") {
8097
8566
  return validateFormat(format, { content: markdown }, subtype);
8098
8567
  }
8099
8568
  return validateConversion(format, frontmatter, content, subtype);
@@ -8350,6 +8819,111 @@ var init_to_cursor = __esm({
8350
8819
  }
8351
8820
  });
8352
8821
 
8822
+ // ../converters/dist/to-cursor-hooks.js
8823
+ function toCursorHooks(pkg, options = {}) {
8824
+ var _a, _b, _c, _d;
8825
+ const warnings = [];
8826
+ const extractedScripts = [];
8827
+ let qualityScore = 100;
8828
+ const hookMappingStrategy = options.hookMappingStrategy || "auto";
8829
+ try {
8830
+ const hooksConfig = {};
8831
+ const cursorHookSections = pkg.content.sections.filter((section) => section.type === "cursor-hook");
8832
+ for (const section of cursorHookSections) {
8833
+ hooksConfig[section.hookType] = section.scriptPath;
8834
+ }
8835
+ const claudeHooks = pkg.content.sections.filter((section) => section.type === "hook");
8836
+ if (claudeHooks.length > 0 && hookMappingStrategy !== "skip") {
8837
+ for (const claudeHook of claudeHooks) {
8838
+ const mappingResult = mapHook("claude", "cursor", claudeHook.event, hookMappingStrategy);
8839
+ qualityScore -= mappingResult.qualityPenalty;
8840
+ if (mappingResult.warning) {
8841
+ warnings.push(mappingResult.warning);
8842
+ }
8843
+ if (mappingResult.mapped && mappingResult.targetHookType) {
8844
+ const scriptExt = getScriptExtension(claudeHook.language);
8845
+ const scriptPath = `./hooks/${claudeHook.event}.${scriptExt}`;
8846
+ hooksConfig[mappingResult.targetHookType] = scriptPath;
8847
+ extractedScripts.push({
8848
+ path: scriptPath,
8849
+ content: claudeHook.code,
8850
+ language: claudeHook.language,
8851
+ executable: true
8852
+ });
8853
+ warnings.push(`Mapped Claude hook "${claudeHook.event}" to Cursor hook "${mappingResult.targetHookType}". Script extracted to ${scriptPath}`);
8854
+ }
8855
+ }
8856
+ } else if (claudeHooks.length > 0 && hookMappingStrategy === "skip") {
8857
+ warnings.push(`${claudeHooks.length} Claude hook(s) skipped (--hook-mapping skip)`);
8858
+ }
8859
+ if (((_b = (_a = pkg.metadata) == null ? void 0 : _a.kiroAgent) == null ? void 0 : _b.hooks) && hookMappingStrategy !== "skip") {
8860
+ const kiroHooks = pkg.metadata.kiroAgent.hooks;
8861
+ for (const [kiroHookType, scriptPaths] of Object.entries(kiroHooks)) {
8862
+ if (!scriptPaths || !Array.isArray(scriptPaths) || scriptPaths.length === 0)
8863
+ continue;
8864
+ const mappingResult = mapHook("kiro", "cursor", kiroHookType, hookMappingStrategy);
8865
+ qualityScore -= mappingResult.qualityPenalty;
8866
+ if (mappingResult.warning) {
8867
+ warnings.push(mappingResult.warning);
8868
+ }
8869
+ if (mappingResult.mapped && mappingResult.targetHookType) {
8870
+ hooksConfig[mappingResult.targetHookType] = scriptPaths[0];
8871
+ }
8872
+ }
8873
+ } else if (((_d = (_c = pkg.metadata) == null ? void 0 : _c.kiroAgent) == null ? void 0 : _d.hooks) && hookMappingStrategy === "skip") {
8874
+ const kiroHookTypes = Object.keys(pkg.metadata.kiroAgent.hooks);
8875
+ warnings.push(`${kiroHookTypes.length} Kiro hook(s) skipped (--hook-mapping skip)`);
8876
+ }
8877
+ if (Object.keys(hooksConfig).length === 0) {
8878
+ warnings.push("No hooks converted to Cursor hooks format");
8879
+ qualityScore -= 50;
8880
+ }
8881
+ const unsupportedSections = pkg.content.sections.filter((section) => section.type !== "cursor-hook" && section.type !== "metadata" && section.type !== "hook");
8882
+ if (unsupportedSections.length > 0) {
8883
+ warnings.push(`${unsupportedSections.length} non-hook sections skipped (not supported in hooks.json format)`);
8884
+ qualityScore -= 10;
8885
+ }
8886
+ const content = JSON.stringify(hooksConfig, null, 2);
8887
+ return {
8888
+ content,
8889
+ format: "cursor",
8890
+ warnings: warnings.length > 0 ? warnings : void 0,
8891
+ lossyConversion: warnings.length > 0,
8892
+ qualityScore: Math.max(0, qualityScore),
8893
+ extractedScripts: extractedScripts.length > 0 ? extractedScripts : void 0
8894
+ };
8895
+ } catch (error) {
8896
+ warnings.push(`Conversion error: ${error instanceof Error ? error.message : String(error)}`);
8897
+ return {
8898
+ content: "{}",
8899
+ format: "cursor",
8900
+ warnings,
8901
+ lossyConversion: true,
8902
+ qualityScore: 0
8903
+ };
8904
+ }
8905
+ }
8906
+ function isCursorHooksFormat(content) {
8907
+ try {
8908
+ const parsed = JSON.parse(content);
8909
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
8910
+ return false;
8911
+ }
8912
+ const keys = Object.keys(parsed);
8913
+ return keys.length > 0 && keys.some((key) => VALID_CURSOR_HOOK_TYPES.includes(key));
8914
+ } catch {
8915
+ return false;
8916
+ }
8917
+ }
8918
+ var init_to_cursor_hooks = __esm({
8919
+ "../converters/dist/to-cursor-hooks.js"() {
8920
+ "use strict";
8921
+ init_cjs_shims();
8922
+ init_hook_mappings();
8923
+ init_cursor_hooks_constants();
8924
+ }
8925
+ });
8926
+
8353
8927
  // ../converters/dist/to-claude.js
8354
8928
  function toClaude(pkg, options = {}) {
8355
8929
  const warnings = [];
@@ -8406,7 +8980,8 @@ function convertContent2(pkg, warnings, options, isSlashCommand = false) {
8406
8980
  lines.push(`allowed-tools: ${claudeSlashCommand.allowedTools}`);
8407
8981
  }
8408
8982
  if (claudeSlashCommand.argumentHint) {
8409
- lines.push(`argument-hint: ${claudeSlashCommand.argumentHint}`);
8983
+ const hint = Array.isArray(claudeSlashCommand.argumentHint) ? `[${claudeSlashCommand.argumentHint.join(", ")}]` : claudeSlashCommand.argumentHint;
8984
+ lines.push(`argument-hint: ${hint}`);
8410
8985
  }
8411
8986
  if (claudeSlashCommand.description) {
8412
8987
  lines.push(`description: ${claudeSlashCommand.description}`);
@@ -8630,6 +9205,88 @@ var init_to_claude = __esm({
8630
9205
  }
8631
9206
  });
8632
9207
 
9208
+ // ../converters/dist/to-claude-plugin.js
9209
+ function toClaudePlugin(pkg) {
9210
+ var _a, _b, _c;
9211
+ const warnings = [];
9212
+ let qualityScore = 100;
9213
+ try {
9214
+ const metadata = pkg.content.sections.find((s) => s.type === "metadata");
9215
+ const storedPluginData = (metadata == null ? void 0 : metadata.type) === "metadata" ? metadata.data.claudePlugin : void 0;
9216
+ const pluginJson = {
9217
+ name: pkg.name || pkg.id,
9218
+ version: pkg.version,
9219
+ description: pkg.description || ((metadata == null ? void 0 : metadata.type) === "metadata" ? metadata.data.description : ""),
9220
+ author: pkg.author
9221
+ };
9222
+ if ((storedPluginData == null ? void 0 : storedPluginData.mcpServers) && Object.keys(storedPluginData.mcpServers).length > 0) {
9223
+ pluginJson.mcpServers = storedPluginData.mcpServers;
9224
+ }
9225
+ if (pkg.tags && pkg.tags.length > 0) {
9226
+ pluginJson.keywords = pkg.tags;
9227
+ }
9228
+ const pluginContents = (storedPluginData == null ? void 0 : storedPluginData.contents) || {
9229
+ agents: [],
9230
+ skills: [],
9231
+ commands: []
9232
+ };
9233
+ const content = JSON.stringify(pluginJson, null, 2);
9234
+ if (!pluginJson.description) {
9235
+ warnings.push("Missing description");
9236
+ qualityScore -= 5;
9237
+ }
9238
+ if (!pluginJson.mcpServers || Object.keys(pluginJson.mcpServers).length === 0) {
9239
+ warnings.push("No MCP servers configured");
9240
+ }
9241
+ const totalFiles = (((_a = pluginContents.agents) == null ? void 0 : _a.length) || 0) + (((_b = pluginContents.skills) == null ? void 0 : _b.length) || 0) + (((_c = pluginContents.commands) == null ? void 0 : _c.length) || 0);
9242
+ if (totalFiles === 0 && (!pluginJson.mcpServers || Object.keys(pluginJson.mcpServers).length === 0)) {
9243
+ warnings.push("Plugin has no agents, skills, commands, or MCP servers");
9244
+ qualityScore -= 20;
9245
+ }
9246
+ return {
9247
+ content,
9248
+ format: "claude",
9249
+ // format: claude + subtype: plugin
9250
+ warnings: warnings.length > 0 ? warnings : void 0,
9251
+ lossyConversion: false,
9252
+ // Plugin format preserves all data
9253
+ qualityScore,
9254
+ pluginJson,
9255
+ pluginContents
9256
+ };
9257
+ } catch (error) {
9258
+ warnings.push(`Conversion error: ${error instanceof Error ? error.message : String(error)}`);
9259
+ return {
9260
+ content: "{}",
9261
+ format: "claude",
9262
+ // format: claude + subtype: plugin
9263
+ warnings,
9264
+ lossyConversion: true,
9265
+ qualityScore: 0,
9266
+ pluginJson: { name: pkg.name || pkg.id },
9267
+ pluginContents: {}
9268
+ };
9269
+ }
9270
+ }
9271
+ function generatePluginJson(pluginJson) {
9272
+ return JSON.stringify(pluginJson, null, 2);
9273
+ }
9274
+ function createMinimalPluginJson(name, options) {
9275
+ return {
9276
+ name,
9277
+ version: (options == null ? void 0 : options.version) || "1.0.0",
9278
+ description: options == null ? void 0 : options.description,
9279
+ author: options == null ? void 0 : options.author,
9280
+ mcpServers: options == null ? void 0 : options.mcpServers
9281
+ };
9282
+ }
9283
+ var init_to_claude_plugin = __esm({
9284
+ "../converters/dist/to-claude-plugin.js"() {
9285
+ "use strict";
9286
+ init_cjs_shims();
9287
+ }
9288
+ });
9289
+
8633
9290
  // ../converters/dist/to-continue.js
8634
9291
  function toContinue(pkg) {
8635
9292
  var _a, _b;
@@ -10848,8 +11505,86 @@ var init_to_replit = __esm({
10848
11505
  }
10849
11506
  });
10850
11507
 
11508
+ // ../converters/dist/to-mcp-server.js
11509
+ function toMCPServer(pkg) {
11510
+ var _a, _b;
11511
+ const warnings = [];
11512
+ let qualityScore = 100;
11513
+ let mcpServers = {};
11514
+ if ((_b = (_a = pkg.metadata) == null ? void 0 : _a.claudePlugin) == null ? void 0 : _b.mcpServers) {
11515
+ mcpServers = pkg.metadata.claudePlugin.mcpServers;
11516
+ } else {
11517
+ warnings.push("No MCP servers defined in package metadata");
11518
+ qualityScore -= 50;
11519
+ }
11520
+ const mcpServerJson = {
11521
+ name: pkg.name,
11522
+ description: pkg.description,
11523
+ version: pkg.version,
11524
+ author: pkg.author,
11525
+ mcpServers
11526
+ };
11527
+ if (pkg.repository) {
11528
+ mcpServerJson.repository = pkg.repository;
11529
+ }
11530
+ if (pkg.homepage) {
11531
+ mcpServerJson.homepage = pkg.homepage;
11532
+ }
11533
+ if (pkg.license) {
11534
+ mcpServerJson.license = pkg.license;
11535
+ }
11536
+ if (!mcpServerJson.description) {
11537
+ warnings.push("Missing description");
11538
+ qualityScore -= 10;
11539
+ }
11540
+ if (Object.keys(mcpServers).length === 0) {
11541
+ warnings.push("No MCP servers defined - package will not add any servers");
11542
+ qualityScore -= 30;
11543
+ }
11544
+ for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
11545
+ const serverType = serverConfig.type || "stdio";
11546
+ if (serverType === "stdio" && !serverConfig.command) {
11547
+ warnings.push(`Server '${serverName}' is missing command for stdio type`);
11548
+ qualityScore -= 10;
11549
+ }
11550
+ if ((serverType === "http" || serverType === "sse") && !serverConfig.url) {
11551
+ warnings.push(`Server '${serverName}' is missing url for ${serverType} type`);
11552
+ qualityScore -= 10;
11553
+ }
11554
+ }
11555
+ const content = JSON.stringify(mcpServerJson, null, 2);
11556
+ return {
11557
+ content,
11558
+ format: "mcp",
11559
+ warnings: warnings.length > 0 ? warnings : void 0,
11560
+ lossyConversion: false,
11561
+ qualityScore: Math.max(0, qualityScore),
11562
+ mcpServerJson
11563
+ };
11564
+ }
11565
+ function generateMCPServerPackage(name, servers, options = {}) {
11566
+ const mcpServerJson = {
11567
+ name,
11568
+ description: options.description || `MCP server package: ${name}`,
11569
+ version: options.version || "1.0.0",
11570
+ author: options.author,
11571
+ repository: options.repository,
11572
+ homepage: options.homepage,
11573
+ license: options.license,
11574
+ mcpServers: servers
11575
+ };
11576
+ const cleaned = JSON.parse(JSON.stringify(mcpServerJson));
11577
+ return JSON.stringify(cleaned, null, 2);
11578
+ }
11579
+ var init_to_mcp_server = __esm({
11580
+ "../converters/dist/to-mcp-server.js"() {
11581
+ "use strict";
11582
+ init_cjs_shims();
11583
+ }
11584
+ });
11585
+
10851
11586
  // ../converters/dist/schema-files.js
10852
- var import_module, import_path6, schemaRequire, convertersPackagePath, convertersDir, loadSchema2, formatRegistrySchema, agentsMdSchema, canonicalSchema, claudeSchema, continueSchema, copilotSchema, cursorSchema, droidSchema, geminiMdSchema, geminiSchema, kiroSteeringSchema, opencodeSchema, rulerSchema, windsurfSchema, traeSchema, aiderSchema, zencoderSchema, replitSchema, claudeAgentSchema, claudeHookSchema, claudeSkillSchema, claudeSlashCommandSchema, cursorCommandSchema, droidHookSchema, droidSkillSchema, droidSlashCommandSchema, kiroAgentSchema, kiroHookSchema, opencodeSlashCommandSchema;
11587
+ var import_module, import_path6, schemaRequire, convertersPackagePath, convertersDir, loadSchema2, formatRegistrySchema, agentsMdSchema, canonicalSchema, claudeSchema, continueSchema, copilotSchema, cursorSchema, droidSchema, geminiMdSchema, geminiSchema, kiroSteeringSchema, opencodeSchema, rulerSchema, windsurfSchema, traeSchema, aiderSchema, zencoderSchema, replitSchema, claudeAgentSchema, claudeHookSchema, claudeSkillSchema, claudeSlashCommandSchema, cursorCommandSchema, cursorHooksSchema, droidHookSchema, droidSkillSchema, droidSlashCommandSchema, kiroAgentSchema, kiroHookSchema, opencodeSlashCommandSchema;
10853
11588
  var init_schema_files = __esm({
10854
11589
  "../converters/dist/schema-files.js"() {
10855
11590
  "use strict";
@@ -10883,6 +11618,7 @@ var init_schema_files = __esm({
10883
11618
  claudeSkillSchema = loadSchema2("claude-skill.schema.json");
10884
11619
  claudeSlashCommandSchema = loadSchema2("claude-slash-command.schema.json");
10885
11620
  cursorCommandSchema = loadSchema2("cursor-command.schema.json");
11621
+ cursorHooksSchema = loadSchema2("cursor-hooks.schema.json");
10886
11622
  droidHookSchema = loadSchema2("droid-hook.schema.json");
10887
11623
  droidSkillSchema = loadSchema2("droid-skill.schema.json");
10888
11624
  droidSlashCommandSchema = loadSchema2("droid-slash-command.schema.json");
@@ -10923,6 +11659,19 @@ var init_format_registry = __esm({
10923
11659
  }
10924
11660
  }
10925
11661
  },
11662
+ "cursor-hooks": {
11663
+ name: "Cursor Hooks",
11664
+ description: "Cursor agent hooks configuration",
11665
+ documentationUrl: "https://cursor.com/docs/agent/hooks",
11666
+ rootFiles: ["hooks.json"],
11667
+ subtypes: {
11668
+ hook: {
11669
+ directory: ".",
11670
+ filePatterns: ["hooks.json"],
11671
+ fileExtension: ".json"
11672
+ }
11673
+ }
11674
+ },
10926
11675
  claude: {
10927
11676
  name: "Claude Code",
10928
11677
  description: "Claude AI skills, agents, commands, and hooks",
@@ -10958,6 +11707,21 @@ var init_format_registry = __esm({
10958
11707
  }
10959
11708
  }
10960
11709
  },
11710
+ "claude-plugin": {
11711
+ name: "Claude Plugin",
11712
+ description: "Claude Code plugins containing agents, skills, commands, and MCP servers",
11713
+ documentationUrl: "https://code.claude.com/docs",
11714
+ rootFiles: [".claude-plugin/plugin.json"],
11715
+ subtypes: {
11716
+ plugin: {
11717
+ directory: ".claude",
11718
+ scanDirectory: ".claude-plugin",
11719
+ filePatterns: ["plugin.json"],
11720
+ nested: false,
11721
+ fileExtension: ".json"
11722
+ }
11723
+ }
11724
+ },
10961
11725
  continue: {
10962
11726
  name: "Continue",
10963
11727
  description: "Continue AI coding rules and prompts",
@@ -11237,8 +12001,14 @@ var init_format_registry = __esm({
11237
12001
  },
11238
12002
  mcp: {
11239
12003
  name: "MCP",
11240
- description: "Model Context Protocol tools",
12004
+ description: "Model Context Protocol servers and tools",
12005
+ defaultSubtype: "server",
11241
12006
  subtypes: {
12007
+ server: {
12008
+ directory: ".mcp",
12009
+ filePatterns: ["*.json", "mcp-server.json"],
12010
+ fileExtension: ".json"
12011
+ },
11242
12012
  tool: {
11243
12013
  directory: ".mcp/tools",
11244
12014
  filePatterns: ["*.json"],
@@ -11336,6 +12106,15 @@ var init_format_registry2 = __esm({
11336
12106
  // ../converters/dist/index.js
11337
12107
  var dist_exports = {};
11338
12108
  __export(dist_exports, {
12109
+ CLAUDE_TO_CURSOR: () => CLAUDE_TO_CURSOR,
12110
+ CLAUDE_TO_KIRO: () => CLAUDE_TO_KIRO,
12111
+ CURSOR_TO_CLAUDE: () => CURSOR_TO_CLAUDE,
12112
+ CURSOR_TO_KIRO: () => CURSOR_TO_KIRO,
12113
+ KIRO_TO_CLAUDE: () => KIRO_TO_CLAUDE,
12114
+ KIRO_TO_CURSOR: () => KIRO_TO_CURSOR,
12115
+ SCRIPT_LANGUAGE_EXTENSIONS: () => SCRIPT_LANGUAGE_EXTENSIONS,
12116
+ VALID_CURSOR_HOOK_TYPES: () => VALID_CURSOR_HOOK_TYPES,
12117
+ VALID_HOOK_MAPPING_STRATEGIES: () => VALID_HOOK_MAPPING_STRATEGIES,
11339
12118
  agentsMdSchema: () => agentsMdSchema,
11340
12119
  aiderSchema: () => aiderSchema,
11341
12120
  canonicalSchema: () => canonicalSchema,
@@ -11346,13 +12125,17 @@ __export(dist_exports, {
11346
12125
  claudeSlashCommandSchema: () => claudeSlashCommandSchema,
11347
12126
  continueSchema: () => continueSchema,
11348
12127
  copilotSchema: () => copilotSchema,
12128
+ createMinimalPluginJson: () => createMinimalPluginJson,
11349
12129
  cursorCommandSchema: () => cursorCommandSchema,
12130
+ cursorHooksSchema: () => cursorHooksSchema,
11350
12131
  cursorSchema: () => cursorSchema,
11351
12132
  detectSubtypeFromFrontmatter: () => detectSubtypeFromFrontmatter,
11352
12133
  droidHookSchema: () => droidHookSchema,
11353
12134
  droidSchema: () => droidSchema,
11354
12135
  droidSkillSchema: () => droidSkillSchema,
11355
12136
  droidSlashCommandSchema: () => droidSlashCommandSchema,
12137
+ extractMCPServers: () => extractMCPServers,
12138
+ extractMCPServersFromCanonical: () => extractMCPServers2,
11356
12139
  findFormatByRootFile: () => findFormatByRootFile,
11357
12140
  formatRegistry: () => formatRegistry,
11358
12141
  formatRegistrySchema: () => formatRegistrySchema,
@@ -11360,13 +12143,16 @@ __export(dist_exports, {
11360
12143
  fromAgentsMd: () => fromAgentsMd,
11361
12144
  fromAider: () => fromAider,
11362
12145
  fromClaude: () => fromClaude,
12146
+ fromClaudePlugin: () => fromClaudePlugin,
11363
12147
  fromContinue: () => fromContinue,
11364
12148
  fromCopilot: () => fromCopilot,
11365
12149
  fromCursor: () => fromCursor,
12150
+ fromCursorHooks: () => fromCursorHooks,
11366
12151
  fromDroid: () => fromDroid,
11367
12152
  fromGemini: () => fromGemini,
11368
12153
  fromKiro: () => fromKiro,
11369
12154
  fromKiroAgent: () => fromKiroAgent,
12155
+ fromMCPServer: () => fromMCPServer,
11370
12156
  fromOpencode: () => fromOpencode,
11371
12157
  fromReplit: () => fromReplit,
11372
12158
  fromRuler: () => fromRuler,
@@ -11375,6 +12161,8 @@ __export(dist_exports, {
11375
12161
  fromZencoder: () => fromZencoder,
11376
12162
  geminiMdSchema: () => geminiMdSchema,
11377
12163
  geminiSchema: () => geminiSchema,
12164
+ generateMCPServerPackage: () => generateMCPServerPackage,
12165
+ generatePluginJson: () => generatePluginJson,
11378
12166
  getDefaultSubtype: () => getDefaultSubtype,
11379
12167
  getDestinationDirectory: () => getDestinationDirectory,
11380
12168
  getFileExtension: () => getFileExtension,
@@ -11382,9 +12170,12 @@ __export(dist_exports, {
11382
12170
  getFormatConfig: () => getFormatConfig,
11383
12171
  getFormatNames: () => getFormatNames,
11384
12172
  getFormatRegistry: () => getFormatRegistry,
12173
+ getHookMapping: () => getHookMapping,
11385
12174
  getNestedIndicator: () => getNestedIndicator,
12175
+ getQualityPenalty: () => getQualityPenalty,
11386
12176
  getRootFiles: () => getRootFiles,
11387
12177
  getScanDirectory: () => getScanDirectory,
12178
+ getScriptExtension: () => getScriptExtension,
11388
12179
  getSubtypeConfig: () => getSubtypeConfig,
11389
12180
  getSubtypes: () => getSubtypes,
11390
12181
  isAgentsMdFormat: () => isAgentsMdFormat,
@@ -11393,20 +12184,27 @@ __export(dist_exports, {
11393
12184
  isContinueFormat: () => isContinueFormat,
11394
12185
  isCopilotFormat: () => isCopilotFormat,
11395
12186
  isCursorFormat: () => isCursorFormat,
12187
+ isCursorHooksFormat: () => isCursorHooksFormat,
11396
12188
  isKiroAgentFormat: () => isKiroAgentFormat,
11397
12189
  isKiroFormat: () => isKiroFormat,
11398
12190
  isNestedPackage: () => isNestedPackage,
11399
12191
  isReplitFormat: () => isReplitFormat,
11400
12192
  isRulerFormat: () => isRulerFormat,
11401
12193
  isTraeFormat: () => isTraeFormat,
12194
+ isValidCursorHookType: () => isValidCursorHookType,
12195
+ isValidHookMappingStrategy: () => isValidHookMappingStrategy,
11402
12196
  isWindsurfFormat: () => isWindsurfFormat,
11403
12197
  isZencoderFormat: () => isZencoderFormat,
11404
12198
  kiroAgentSchema: () => kiroAgentSchema,
11405
12199
  kiroHookSchema: () => kiroHookSchema,
11406
12200
  kiroSteeringSchema: () => kiroSteeringSchema,
12201
+ mapHook: () => mapHook,
12202
+ mapHooks: () => mapHooks,
11407
12203
  normalizeFormat: () => normalizeFormat,
11408
12204
  opencodeSchema: () => opencodeSchema,
11409
12205
  opencodeSlashCommandSchema: () => opencodeSlashCommandSchema,
12206
+ parseMCPServerJson: () => parseMCPServerJson,
12207
+ parsePluginJson: () => parsePluginJson,
11410
12208
  replitSchema: () => replitSchema,
11411
12209
  rulerSchema: () => rulerSchema,
11412
12210
  setTaxonomy: () => setTaxonomy,
@@ -11414,13 +12212,16 @@ __export(dist_exports, {
11414
12212
  toAider: () => toAider,
11415
12213
  toClaude: () => toClaude,
11416
12214
  toClaudeMd: () => toClaudeMd,
12215
+ toClaudePlugin: () => toClaudePlugin,
11417
12216
  toContinue: () => toContinue,
11418
12217
  toCopilot: () => toCopilot,
11419
12218
  toCursor: () => toCursor,
12219
+ toCursorHooks: () => toCursorHooks,
11420
12220
  toDroid: () => toDroid,
11421
12221
  toGemini: () => toGemini,
11422
12222
  toKiro: () => toKiro,
11423
12223
  toKiroAgent: () => toKiroAgent,
12224
+ toMCPServer: () => toMCPServer,
11424
12225
  toOpencode: () => toOpencode,
11425
12226
  toReplit: () => toReplit,
11426
12227
  toRuler: () => toRuler,
@@ -11439,8 +12240,12 @@ var init_dist = __esm({
11439
12240
  "use strict";
11440
12241
  init_cjs_shims();
11441
12242
  init_canonical();
12243
+ init_cursor_hooks_constants();
12244
+ init_hook_mappings();
11442
12245
  init_from_cursor();
12246
+ init_from_cursor_hooks();
11443
12247
  init_from_claude();
12248
+ init_from_claude_plugin();
11444
12249
  init_from_continue();
11445
12250
  init_from_copilot();
11446
12251
  init_from_kiro();
@@ -11455,8 +12260,11 @@ var init_dist = __esm({
11455
12260
  init_from_aider();
11456
12261
  init_from_zencoder();
11457
12262
  init_from_replit();
12263
+ init_from_mcp_server();
11458
12264
  init_to_cursor();
12265
+ init_to_cursor_hooks();
11459
12266
  init_to_claude();
12267
+ init_to_claude_plugin();
11460
12268
  init_to_continue();
11461
12269
  init_to_copilot();
11462
12270
  init_to_kiro();
@@ -11471,6 +12279,7 @@ var init_dist = __esm({
11471
12279
  init_to_aider();
11472
12280
  init_to_zencoder();
11473
12281
  init_to_replit();
12282
+ init_to_mcp_server();
11474
12283
  init_taxonomy_utils();
11475
12284
  init_validation();
11476
12285
  init_schema_files();
@@ -11829,6 +12638,123 @@ var init_agents_md_progressive = __esm({
11829
12638
  }
11830
12639
  });
11831
12640
 
12641
+ // src/core/mcp.ts
12642
+ function getMCPConfigPath(global2 = false, projectDir = process.cwd()) {
12643
+ if (global2) {
12644
+ return (0, import_path9.join)((0, import_os3.homedir)(), ".claude", "settings.json");
12645
+ }
12646
+ return (0, import_path9.join)(projectDir, ".mcp.json");
12647
+ }
12648
+ function readMCPConfig(configPath) {
12649
+ if (!(0, import_fs8.existsSync)(configPath)) {
12650
+ return { mcpServers: {} };
12651
+ }
12652
+ try {
12653
+ const content = (0, import_fs8.readFileSync)(configPath, "utf-8");
12654
+ return JSON.parse(content);
12655
+ } catch (error) {
12656
+ return { mcpServers: {} };
12657
+ }
12658
+ }
12659
+ function writeMCPConfig(configPath, config) {
12660
+ const dir = (0, import_path9.dirname)(configPath);
12661
+ if (!(0, import_fs8.existsSync)(dir)) {
12662
+ (0, import_fs8.mkdirSync)(dir, { recursive: true });
12663
+ }
12664
+ (0, import_fs8.writeFileSync)(configPath, JSON.stringify(config, null, 2) + "\n");
12665
+ }
12666
+ function mergeMCPServers(servers, global2 = false, projectDir = process.cwd()) {
12667
+ const result = {
12668
+ added: [],
12669
+ skipped: [],
12670
+ warnings: []
12671
+ };
12672
+ if (!servers || Object.keys(servers).length === 0) {
12673
+ return result;
12674
+ }
12675
+ const configPath = getMCPConfigPath(global2, projectDir);
12676
+ const config = readMCPConfig(configPath);
12677
+ if (!config.mcpServers) {
12678
+ config.mcpServers = {};
12679
+ }
12680
+ for (const [name, server] of Object.entries(servers)) {
12681
+ if (config.mcpServers[name]) {
12682
+ result.skipped.push(name);
12683
+ result.warnings.push(`MCP server '${name}' already exists, keeping existing configuration`);
12684
+ } else {
12685
+ config.mcpServers[name] = server;
12686
+ result.added.push(name);
12687
+ }
12688
+ }
12689
+ if (result.added.length > 0) {
12690
+ writeMCPConfig(configPath, config);
12691
+ }
12692
+ return result;
12693
+ }
12694
+ function removeMCPServers(servers, global2 = false, projectDir = process.cwd()) {
12695
+ const result = {
12696
+ removed: [],
12697
+ kept: [],
12698
+ warnings: []
12699
+ };
12700
+ if (!servers || Object.keys(servers).length === 0) {
12701
+ return result;
12702
+ }
12703
+ const configPath = getMCPConfigPath(global2, projectDir);
12704
+ if (!(0, import_fs8.existsSync)(configPath)) {
12705
+ return result;
12706
+ }
12707
+ const config = readMCPConfig(configPath);
12708
+ if (!config.mcpServers) {
12709
+ return result;
12710
+ }
12711
+ for (const [name, originalServer] of Object.entries(servers)) {
12712
+ const currentServer = config.mcpServers[name];
12713
+ if (!currentServer) {
12714
+ continue;
12715
+ }
12716
+ if (serversEqual(currentServer, originalServer)) {
12717
+ delete config.mcpServers[name];
12718
+ result.removed.push(name);
12719
+ } else {
12720
+ result.kept.push(name);
12721
+ result.warnings.push(`Keeping modified MCP server '${name}'`);
12722
+ }
12723
+ }
12724
+ if (Object.keys(config.mcpServers).length === 0) {
12725
+ delete config.mcpServers;
12726
+ }
12727
+ if (result.removed.length > 0) {
12728
+ writeMCPConfig(configPath, config);
12729
+ }
12730
+ return result;
12731
+ }
12732
+ function serversEqual(a, b) {
12733
+ return JSON.stringify(sortObject(a)) === JSON.stringify(sortObject(b));
12734
+ }
12735
+ function sortObject(obj) {
12736
+ const sorted = {};
12737
+ for (const key of Object.keys(obj).sort()) {
12738
+ const value = obj[key];
12739
+ if (value && typeof value === "object" && !Array.isArray(value)) {
12740
+ sorted[key] = sortObject(value);
12741
+ } else {
12742
+ sorted[key] = value;
12743
+ }
12744
+ }
12745
+ return sorted;
12746
+ }
12747
+ var import_fs8, import_path9, import_os3;
12748
+ var init_mcp = __esm({
12749
+ "src/core/mcp.ts"() {
12750
+ "use strict";
12751
+ init_cjs_shims();
12752
+ import_fs8 = require("fs");
12753
+ import_path9 = require("path");
12754
+ import_os3 = require("os");
12755
+ }
12756
+ });
12757
+
11832
12758
  // ../../node_modules/color-name/index.js
11833
12759
  var require_color_name = __commonJS({
11834
12760
  "../../node_modules/color-name/index.js"(exports2, module2) {
@@ -14123,7 +15049,9 @@ function getPackageIcon2(format, subtype) {
14123
15049
  "tool": "\u{1F527}",
14124
15050
  "hook": "\u{1FA9D}",
14125
15051
  "workflow": "\u{1F504}",
14126
- "template": "\u{1F4C4}"
15052
+ "template": "\u{1F4C4}",
15053
+ "plugin": "\u{1F50C}",
15054
+ "server": "\u{1F5A5}\uFE0F"
14127
15055
  };
14128
15056
  const formatIcons = {
14129
15057
  "claude": "\u{1F916}",
@@ -14181,7 +15109,9 @@ function getPackageLabel2(format, subtype) {
14181
15109
  "tool": "Tool",
14182
15110
  "hook": "Hook",
14183
15111
  "workflow": "Workflow",
14184
- "template": "Template"
15112
+ "template": "Template",
15113
+ "plugin": "Plugin",
15114
+ "server": "Server"
14185
15115
  };
14186
15116
  const formatLabel = formatLabels[format];
14187
15117
  const subtypeLabel = subtypeLabels[subtype];
@@ -14194,7 +15124,7 @@ function findMainFile(files, format, subtype) {
14194
15124
  const nestedIndicator = getNestedIndicator(format, subtype);
14195
15125
  if (nestedIndicator) {
14196
15126
  const match = files.find((f) => {
14197
- const filename = import_path10.default.basename(f.name);
15127
+ const filename = import_path11.default.basename(f.name);
14198
15128
  return filename.toLowerCase() === nestedIndicator.toLowerCase();
14199
15129
  });
14200
15130
  if (match) return match;
@@ -14203,7 +15133,7 @@ function findMainFile(files, format, subtype) {
14203
15133
  if (filePatterns) {
14204
15134
  for (const pattern of filePatterns) {
14205
15135
  for (const file of files) {
14206
- const filename = import_path10.default.basename(file.name);
15136
+ const filename = import_path11.default.basename(file.name);
14207
15137
  if (pattern.startsWith("*")) {
14208
15138
  const extension = pattern.slice(1);
14209
15139
  if (filename.endsWith(extension)) {
@@ -14234,7 +15164,7 @@ function findMainFile(files, format, subtype) {
14234
15164
  ];
14235
15165
  for (const pattern of fallbackPatterns) {
14236
15166
  for (const file of files) {
14237
- const filename = import_path10.default.basename(file.name);
15167
+ const filename = import_path11.default.basename(file.name);
14238
15168
  if (filename.toLowerCase() === pattern.toLowerCase()) {
14239
15169
  return file;
14240
15170
  }
@@ -14499,8 +15429,15 @@ This could indicate:
14499
15429
  try {
14500
15430
  switch (targetFormat2) {
14501
15431
  case "cursor":
14502
- const cursorResult = toCursor(canonicalPkg);
14503
- convertedContent = cursorResult.content;
15432
+ if (effectiveSubtype === "hook") {
15433
+ const cursorHooksResult = toCursorHooks(canonicalPkg, {
15434
+ hookMappingStrategy: options.hookMapping || "auto"
15435
+ });
15436
+ convertedContent = cursorHooksResult.content;
15437
+ } else {
15438
+ const cursorResult = toCursor(canonicalPkg);
15439
+ convertedContent = cursorResult.content;
15440
+ }
14504
15441
  break;
14505
15442
  case "claude":
14506
15443
  case "claude.md":
@@ -14586,7 +15523,120 @@ This could indicate:
14586
15523
  let destDir = "";
14587
15524
  let fileCount = 0;
14588
15525
  let hookMetadata = void 0;
14589
- if (format === "claude-md") {
15526
+ let pluginMetadata = void 0;
15527
+ const isClaudePlugin = pkg.format === "claude" && pkg.subtype === "plugin";
15528
+ if (isClaudePlugin) {
15529
+ console.log(` \u{1F50C} Installing Claude Plugin...`);
15530
+ const pluginJsonFile = extractedFiles.find(
15531
+ (f) => f.name === "plugin.json" || f.name === ".claude-plugin/plugin.json" || f.name.endsWith("/plugin.json")
15532
+ );
15533
+ let pluginConfig = {};
15534
+ if (pluginJsonFile) {
15535
+ try {
15536
+ pluginConfig = parsePluginJson(pluginJsonFile.content);
15537
+ } catch (err) {
15538
+ console.log(` \u26A0\uFE0F Warning: Could not parse plugin.json: ${err}`);
15539
+ }
15540
+ }
15541
+ const installedFiles = [];
15542
+ const agentFiles = extractedFiles.filter(
15543
+ (f) => f.name.startsWith("agents/") && f.name.endsWith(".md")
15544
+ );
15545
+ if (agentFiles.length > 0) {
15546
+ await import_promises2.default.mkdir(".claude/agents", { recursive: true });
15547
+ for (const file of agentFiles) {
15548
+ const filename = import_path11.default.basename(file.name);
15549
+ const destFile = `.claude/agents/${filename}`;
15550
+ await saveFile(destFile, file.content);
15551
+ installedFiles.push(destFile);
15552
+ }
15553
+ console.log(` \u2713 Installed ${agentFiles.length} agents to .claude/agents/`);
15554
+ }
15555
+ const skillFiles = extractedFiles.filter(
15556
+ (f) => f.name.startsWith("skills/") && (f.name.endsWith(".md") || f.name.includes("SKILL.md"))
15557
+ );
15558
+ if (skillFiles.length > 0) {
15559
+ for (const file of skillFiles) {
15560
+ const relativePath = file.name.replace(/^skills\//, "");
15561
+ const destFile = `.claude/skills/${relativePath}`;
15562
+ const destFileDir = import_path11.default.dirname(destFile);
15563
+ await import_promises2.default.mkdir(destFileDir, { recursive: true });
15564
+ await saveFile(destFile, file.content);
15565
+ installedFiles.push(destFile);
15566
+ }
15567
+ console.log(` \u2713 Installed ${skillFiles.length} skill files to .claude/skills/`);
15568
+ }
15569
+ const commandFiles = extractedFiles.filter(
15570
+ (f) => f.name.startsWith("commands/") && f.name.endsWith(".md")
15571
+ );
15572
+ if (commandFiles.length > 0) {
15573
+ await import_promises2.default.mkdir(".claude/commands", { recursive: true });
15574
+ for (const file of commandFiles) {
15575
+ const filename = import_path11.default.basename(file.name);
15576
+ const destFile = `.claude/commands/${filename}`;
15577
+ await saveFile(destFile, file.content);
15578
+ installedFiles.push(destFile);
15579
+ }
15580
+ console.log(` \u2713 Installed ${commandFiles.length} commands to .claude/commands/`);
15581
+ }
15582
+ if (pluginConfig.mcpServers && Object.keys(pluginConfig.mcpServers).length > 0) {
15583
+ const mcpResult = mergeMCPServers(
15584
+ pluginConfig.mcpServers,
15585
+ options.global || false,
15586
+ process.cwd()
15587
+ );
15588
+ if (mcpResult.added.length > 0) {
15589
+ console.log(` \u2713 Added MCP servers: ${mcpResult.added.join(", ")}`);
15590
+ }
15591
+ if (mcpResult.skipped.length > 0) {
15592
+ console.log(` \u26A0\uFE0F Skipped existing MCP servers: ${mcpResult.skipped.join(", ")}`);
15593
+ }
15594
+ pluginMetadata = {
15595
+ files: installedFiles,
15596
+ mcpServers: pluginConfig.mcpServers,
15597
+ mcpGlobal: options.global || false
15598
+ };
15599
+ } else {
15600
+ pluginMetadata = {
15601
+ files: installedFiles
15602
+ };
15603
+ }
15604
+ destPath = ".claude/";
15605
+ fileCount = installedFiles.length;
15606
+ } else if (effectiveFormat === "mcp" && effectiveSubtype === "server") {
15607
+ console.log(` \u{1F527} Installing MCP Server...`);
15608
+ const mcpServerFile = extractedFiles.find(
15609
+ (f) => f.name === "mcp-server.json" || f.name.endsWith("/mcp-server.json") || f.name.endsWith(".json") && !f.name.includes("/")
15610
+ );
15611
+ if (!mcpServerFile) {
15612
+ throw new Error("MCP server package must contain a JSON configuration file");
15613
+ }
15614
+ let mcpServerConfig;
15615
+ try {
15616
+ mcpServerConfig = parseMCPServerJson(mcpServerFile.content);
15617
+ } catch (error2) {
15618
+ throw new Error(`Failed to parse MCP server config: ${error2 instanceof Error ? error2.message : error2}`);
15619
+ }
15620
+ const mcpResult = mergeMCPServers(mcpServerConfig.mcpServers, options.global || false);
15621
+ if (mcpResult.added.length > 0) {
15622
+ const location = options.global ? "~/.claude/settings.json" : ".mcp.json";
15623
+ console.log(` \u2713 Added MCP servers to ${location}: ${mcpResult.added.join(", ")}`);
15624
+ }
15625
+ if (mcpResult.skipped.length > 0) {
15626
+ console.log(` \u26A0\uFE0F Skipped existing MCP servers: ${mcpResult.skipped.join(", ")}`);
15627
+ }
15628
+ for (const warning of mcpResult.warnings) {
15629
+ console.log(` \u26A0\uFE0F ${warning}`);
15630
+ }
15631
+ pluginMetadata = {
15632
+ files: [],
15633
+ // No files to track for MCP server packages
15634
+ mcpServers: mcpServerConfig.mcpServers,
15635
+ mcpGlobal: options.global || false
15636
+ };
15637
+ destPath = options.global ? "~/.claude/settings.json" : ".mcp.json";
15638
+ fileCount = Object.keys(mcpServerConfig.mcpServers).length;
15639
+ } else if (format === "claude-md") {
14590
15640
  if (extractedFiles.length !== 1) {
14591
15641
  throw new Error("CLAUDE.md format only supports single-file packages");
14592
15642
  }
@@ -14598,7 +15648,7 @@ This could indicate:
14598
15648
  destDir = getDestinationDir2(effectiveFormat, effectiveSubtype, pkg.name);
14599
15649
  if (locationOverride && effectiveFormat === "cursor") {
14600
15650
  const relativeDestDir = destDir.startsWith("./") ? destDir.slice(2) : destDir;
14601
- destDir = import_path10.default.join(locationOverride, relativeDestDir);
15651
+ destDir = import_path11.default.join(locationOverride, relativeDestDir);
14602
15652
  console.log(` \u{1F4C1} Installing Cursor package to custom location: ${destDir}`);
14603
15653
  }
14604
15654
  let mainFile = extractedFiles[0].content;
@@ -14619,7 +15669,7 @@ This could indicate:
14619
15669
  const manifestFilename = getManifestFilename(effectiveFormat);
14620
15670
  let targetPath = manifestFilename;
14621
15671
  if (locationOverride) {
14622
- targetPath = import_path10.default.join(locationOverride, `${manifestFilename.replace(".md", ".override.md")}`);
15672
+ targetPath = import_path11.default.join(locationOverride, `${manifestFilename.replace(".md", ".override.md")}`);
14623
15673
  console.log(` \u{1F4C1} Installing to custom location: ${targetPath}`);
14624
15674
  }
14625
15675
  destPath = targetPath;
@@ -14730,7 +15780,7 @@ This could indicate:
14730
15780
  destDir = getDestinationDir2(effectiveFormat, effectiveSubtype, pkg.name);
14731
15781
  if (locationOverride && effectiveFormat === "cursor") {
14732
15782
  const relativeDestDir = destDir.startsWith("./") ? destDir.slice(2) : destDir;
14733
- destDir = import_path10.default.join(locationOverride, relativeDestDir);
15783
+ destDir = import_path11.default.join(locationOverride, relativeDestDir);
14734
15784
  console.log(` \u{1F4C1} Installing Cursor package to custom location: ${destDir}`);
14735
15785
  }
14736
15786
  const packageName = stripAuthorNamespace2(packageId);
@@ -14856,7 +15906,9 @@ ${afterFrontmatter}`;
14856
15906
  fromCollection: options.fromCollection,
14857
15907
  hookMetadata,
14858
15908
  // Track hook installation metadata for uninstall
14859
- progressiveDisclosure: progressiveDisclosureMetadata
15909
+ progressiveDisclosure: progressiveDisclosureMetadata,
15910
+ pluginMetadata
15911
+ // Track plugin installation metadata for uninstall
14860
15912
  });
14861
15913
  setPackageIntegrity(updatedLockfile, packageId, tarball, effectiveFormat);
14862
15914
  await writeLockfile(updatedLockfile);
@@ -14878,6 +15930,16 @@ ${afterFrontmatter}`;
14878
15930
  console.log(` \u{1F4A1} The skill is available but not loaded into context by default`);
14879
15931
  console.log(` \u26A1 Your AI agent will activate this skill automatically when relevant based on its description`);
14880
15932
  }
15933
+ if (pluginMetadata) {
15934
+ console.log(`
15935
+ \u{1F50C} Plugin installation complete`);
15936
+ console.log(` \u{1F4E6} Installed ${pluginMetadata.files.length} file(s)`);
15937
+ if (pluginMetadata.mcpServers && Object.keys(pluginMetadata.mcpServers).length > 0) {
15938
+ const serverCount = Object.keys(pluginMetadata.mcpServers).length;
15939
+ const location = pluginMetadata.mcpGlobal ? "~/.claude/settings.json" : ".mcp.json";
15940
+ console.log(` \u{1F527} Configured ${serverCount} MCP server(s) in ${location}`);
15941
+ }
15942
+ }
14881
15943
  console.log(`
14882
15944
  \u{1F4A1} This package has been downloaded ${newDownloadCount.toLocaleString()} times`);
14883
15945
  success = true;
@@ -14905,9 +15967,9 @@ ${afterFrontmatter}`;
14905
15967
  }
14906
15968
  }
14907
15969
  function isPathSafe(targetDir, filePath) {
14908
- const resolvedPath = import_path10.default.resolve(targetDir, filePath);
14909
- const resolvedTarget = import_path10.default.resolve(targetDir);
14910
- return resolvedPath.startsWith(resolvedTarget + import_path10.default.sep) || resolvedPath === resolvedTarget;
15970
+ const resolvedPath = import_path11.default.resolve(targetDir, filePath);
15971
+ const resolvedTarget = import_path11.default.resolve(targetDir);
15972
+ return resolvedPath.startsWith(resolvedTarget + import_path11.default.sep) || resolvedPath === resolvedTarget;
14911
15973
  }
14912
15974
  function hasUnsafePathPatterns(filePath) {
14913
15975
  if (filePath.includes("..")) return true;
@@ -14931,7 +15993,7 @@ async function extractTarball(tarball, packageId) {
14931
15993
  } catch (error) {
14932
15994
  throw new CLIError(`Package decompression failed: ${error.message}`);
14933
15995
  }
14934
- const tmpDir = await import_promises2.default.mkdtemp(import_path10.default.join(import_os3.default.tmpdir(), "prpm-"));
15996
+ const tmpDir = await import_promises2.default.mkdtemp(import_path11.default.join(import_os4.default.tmpdir(), "prpm-"));
14935
15997
  const cleanup = async () => {
14936
15998
  try {
14937
15999
  await import_promises2.default.rm(tmpDir, { recursive: true, force: true });
@@ -15001,7 +16063,7 @@ async function collectExtractedFiles(rootDir, excludedNames, fs14) {
15001
16063
  if (!currentDir) continue;
15002
16064
  const entries = await fs14.readdir(currentDir, { withFileTypes: true });
15003
16065
  for (const entry of entries) {
15004
- const fullPath = import_path10.default.join(currentDir, entry.name);
16066
+ const fullPath = import_path11.default.join(currentDir, entry.name);
15005
16067
  if (entry.isDirectory()) {
15006
16068
  dirs.push(fullPath);
15007
16069
  continue;
@@ -15013,7 +16075,7 @@ async function collectExtractedFiles(rootDir, excludedNames, fs14) {
15013
16075
  continue;
15014
16076
  }
15015
16077
  const content = await fs14.readFile(fullPath, "utf-8");
15016
- const relativePath = import_path10.default.relative(rootDir, fullPath).split(import_path10.default.sep).join("/");
16078
+ const relativePath = import_path11.default.relative(rootDir, fullPath).split(import_path11.default.sep).join("/");
15017
16079
  files.push({
15018
16080
  name: relativePath,
15019
16081
  content
@@ -15047,11 +16109,11 @@ async function installFromLockfile(options) {
15047
16109
  console.log(` Installing ${displayName}...`);
15048
16110
  let locationOverride = options.location;
15049
16111
  if (!locationOverride && lockEntry.format === "agents.md" && lockEntry.installedPath) {
15050
- const baseName = import_path10.default.basename(lockEntry.installedPath);
16112
+ const baseName = import_path11.default.basename(lockEntry.installedPath);
15051
16113
  if (baseName === "AGENTS.override.md") {
15052
- locationOverride = import_path10.default.dirname(lockEntry.installedPath);
16114
+ locationOverride = import_path11.default.dirname(lockEntry.installedPath);
15053
16115
  } else if (baseName !== "AGENTS.md") {
15054
- locationOverride = import_path10.default.dirname(lockEntry.installedPath);
16116
+ locationOverride = import_path11.default.dirname(lockEntry.installedPath);
15055
16117
  }
15056
16118
  }
15057
16119
  const manifestFile = (_a = lockEntry.progressiveDisclosure) == null ? void 0 : _a.manifestPath;
@@ -15063,7 +16125,8 @@ async function installFromLockfile(options) {
15063
16125
  force: true,
15064
16126
  // Force reinstall when installing from lockfile
15065
16127
  location: locationOverride,
15066
- manifestFile
16128
+ manifestFile,
16129
+ hookMapping: options.hookMapping
15067
16130
  });
15068
16131
  successCount++;
15069
16132
  } catch (error) {
@@ -15094,7 +16157,7 @@ async function installFromLockfile(options) {
15094
16157
  }
15095
16158
  function createInstallCommand() {
15096
16159
  const command = new import_commander11.Command("install");
15097
- command.description("Install a package from the registry, or install all packages from prpm.lock if no package specified").argument("[package]", "Package to install (e.g., react-rules or react-rules@1.2.0). If omitted, installs all packages from prpm.lock").option("--version <version>", "Specific version to install").option("--as <format>", `Convert and install in specific format (${import_types.FORMATS.join(", ")})`).option("--format <format>", "Alias for --as").option("--location <path>", "Custom location for installed files (Agents.md or nested Cursor rules)").option("--subtype <subtype>", "Specify subtype when converting (skill, agent, rule, etc.)").option("--frozen-lockfile", "Fail if lock file needs to be updated (for CI)").option("--no-append", "Skip adding skill to manifest file (skill files only)").option("--manifest-file <filename>", "Custom manifest filename for progressive disclosure").action(async (packageSpec, options) => {
16160
+ command.description("Install a package from the registry, or install all packages from prpm.lock if no package specified").argument("[package]", "Package to install (e.g., react-rules or react-rules@1.2.0). If omitted, installs all packages from prpm.lock").option("--version <version>", "Specific version to install").option("--as <format>", `Convert and install in specific format (${import_types.FORMATS.join(", ")})`).option("--format <format>", "Alias for --as").option("--location <path>", "Custom location for installed files (Agents.md or nested Cursor rules)").option("--subtype <subtype>", "Specify subtype when converting (skill, agent, rule, etc.)").option("--hook-mapping <strategy>", "Hook mapping strategy: auto (default), strict, skip", "auto").option("--frozen-lockfile", "Fail if lock file needs to be updated (for CI)").option("--no-append", "Skip adding skill to manifest file (skill files only)").option("--manifest-file <filename>", "Custom manifest filename for progressive disclosure").action(async (packageSpec, options) => {
15098
16161
  const convertTo = options.format || options.as;
15099
16162
  const validFormats = import_types.FORMATS;
15100
16163
  if (convertTo && !validFormats.includes(convertTo)) {
@@ -15109,12 +16172,20 @@ function createInstallCommand() {
15109
16172
  prpm install my-package --format gemini.md # Convert to Gemini format
15110
16173
  prpm install my-package # Install in native format`, 1);
15111
16174
  }
16175
+ if (options.hookMapping && !isValidHookMappingStrategy(options.hookMapping)) {
16176
+ throw new CLIError(
16177
+ `Invalid hook mapping strategy: ${options.hookMapping}
16178
+
16179
+ Valid strategies: ${VALID_HOOK_MAPPING_STRATEGIES.join(", ")}`
16180
+ );
16181
+ }
15112
16182
  if (!packageSpec) {
15113
16183
  await installFromLockfile({
15114
16184
  as: convertTo,
15115
16185
  subtype: options.subtype,
15116
16186
  frozenLockfile: options.frozenLockfile,
15117
- location: options.location
16187
+ location: options.location,
16188
+ hookMapping: options.hookMapping
15118
16189
  });
15119
16190
  return;
15120
16191
  }
@@ -15125,12 +16196,13 @@ function createInstallCommand() {
15125
16196
  frozenLockfile: options.frozenLockfile,
15126
16197
  location: options.location,
15127
16198
  noAppend: options.noAppend,
15128
- manifestFile: options.manifestFile
16199
+ manifestFile: options.manifestFile,
16200
+ hookMapping: options.hookMapping
15129
16201
  });
15130
16202
  });
15131
16203
  return command;
15132
16204
  }
15133
- var import_commander11, import_chalk, import_registry_client5, import_stream, import_promises, tar, import_path10, import_zlib, import_promises2, import_os3, import_semver;
16205
+ var import_commander11, import_chalk, import_registry_client5, import_stream, import_promises, tar, import_path11, import_zlib, import_promises2, import_os4, import_semver;
15134
16206
  var init_install = __esm({
15135
16207
  "src/commands/install.ts"() {
15136
16208
  "use strict";
@@ -15147,16 +16219,17 @@ var init_install = __esm({
15147
16219
  tar = __toESM(require("tar"));
15148
16220
  init_errors();
15149
16221
  init_prompts();
15150
- import_path10 = __toESM(require("path"));
16222
+ import_path11 = __toESM(require("path"));
15151
16223
  import_zlib = __toESM(require("zlib"));
15152
16224
  import_promises2 = __toESM(require("fs/promises"));
15153
- import_os3 = __toESM(require("os"));
16225
+ import_os4 = __toESM(require("os"));
15154
16226
  import_semver = __toESM(require("semver"));
15155
16227
  init_collections();
15156
16228
  init_lockfile();
15157
16229
  init_cursor_config();
15158
16230
  init_claude_config();
15159
16231
  init_agents_md_progressive();
16232
+ init_mcp();
15160
16233
  init_dist();
15161
16234
  }
15162
16235
  });
@@ -15185,7 +16258,7 @@ function buildScanConfigs() {
15185
16258
  }
15186
16259
  async function extractMetadata2(filePath) {
15187
16260
  try {
15188
- const content = await import_fs12.promises.readFile(filePath, "utf-8");
16261
+ const content = await import_fs13.promises.readFile(filePath, "utf-8");
15189
16262
  const metadata = {};
15190
16263
  const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
15191
16264
  if (frontmatterMatch) {
@@ -15238,7 +16311,7 @@ function matchesPattern(filename, patterns) {
15238
16311
  }
15239
16312
  async function directoryExists2(dirPath) {
15240
16313
  try {
15241
- const stats = await import_fs12.promises.stat(dirPath);
16314
+ const stats = await import_fs13.promises.stat(dirPath);
15242
16315
  return stats.isDirectory();
15243
16316
  } catch {
15244
16317
  return false;
@@ -15246,7 +16319,7 @@ async function directoryExists2(dirPath) {
15246
16319
  }
15247
16320
  async function fileExists2(filePath) {
15248
16321
  try {
15249
- await import_fs12.promises.access(filePath);
16322
+ await import_fs13.promises.access(filePath);
15250
16323
  return true;
15251
16324
  } catch {
15252
16325
  return false;
@@ -15254,21 +16327,21 @@ async function fileExists2(filePath) {
15254
16327
  }
15255
16328
  async function scanDirectory2(config, cwd) {
15256
16329
  const packages = [];
15257
- const fullDir = import_path16.default.join(cwd, config.directory);
16330
+ const fullDir = import_path17.default.join(cwd, config.directory);
15258
16331
  if (!await directoryExists2(fullDir)) {
15259
16332
  return packages;
15260
16333
  }
15261
- const entries = await import_fs12.promises.readdir(fullDir, { withFileTypes: true });
16334
+ const entries = await import_fs13.promises.readdir(fullDir, { withFileTypes: true });
15262
16335
  if (config.nested) {
15263
16336
  for (const entry of entries) {
15264
16337
  if (!entry.isDirectory()) continue;
15265
- const packageDir = import_path16.default.join(fullDir, entry.name);
16338
+ const packageDir = import_path17.default.join(fullDir, entry.name);
15266
16339
  if (config.nestedIndicator) {
15267
- const indicatorPath = import_path16.default.join(packageDir, config.nestedIndicator);
16340
+ const indicatorPath = import_path17.default.join(packageDir, config.nestedIndicator);
15268
16341
  if (!await fileExists2(indicatorPath)) continue;
15269
16342
  const packageFiles = await collectPackageFiles(packageDir, config.directory, entry.name);
15270
16343
  const metadata = await extractMetadata2(indicatorPath);
15271
- const relativePath = import_path16.default.join(config.directory, entry.name, config.nestedIndicator);
16344
+ const relativePath = import_path17.default.join(config.directory, entry.name, config.nestedIndicator);
15272
16345
  packages.push({
15273
16346
  name: metadata.name || filenameToPackageName(entry.name),
15274
16347
  format: config.format,
@@ -15279,12 +16352,12 @@ async function scanDirectory2(config, cwd) {
15279
16352
  primaryFile: relativePath
15280
16353
  });
15281
16354
  } else {
15282
- const subEntries = await import_fs12.promises.readdir(packageDir, { withFileTypes: true });
16355
+ const subEntries = await import_fs13.promises.readdir(packageDir, { withFileTypes: true });
15283
16356
  for (const subEntry of subEntries) {
15284
16357
  if (!subEntry.isFile()) continue;
15285
16358
  if (!matchesPattern(subEntry.name, config.patterns)) continue;
15286
- const filePath = import_path16.default.join(packageDir, subEntry.name);
15287
- const relativePath = import_path16.default.join(config.directory, entry.name, subEntry.name);
16359
+ const filePath = import_path17.default.join(packageDir, subEntry.name);
16360
+ const relativePath = import_path17.default.join(config.directory, entry.name, subEntry.name);
15288
16361
  const metadata = await extractMetadata2(filePath);
15289
16362
  packages.push({
15290
16363
  name: metadata.name || filenameToPackageName(entry.name),
@@ -15302,8 +16375,8 @@ async function scanDirectory2(config, cwd) {
15302
16375
  for (const entry of entries) {
15303
16376
  if (!entry.isFile()) continue;
15304
16377
  if (!matchesPattern(entry.name, config.patterns)) continue;
15305
- const filePath = import_path16.default.join(fullDir, entry.name);
15306
- const relativePath = import_path16.default.join(config.directory, entry.name);
16378
+ const filePath = import_path17.default.join(fullDir, entry.name);
16379
+ const relativePath = import_path17.default.join(config.directory, entry.name);
15307
16380
  const metadata = await extractMetadata2(filePath);
15308
16381
  packages.push({
15309
16382
  name: metadata.name || filenameToPackageName(entry.name),
@@ -15321,24 +16394,24 @@ async function scanDirectory2(config, cwd) {
15321
16394
  async function collectPackageFiles(packageDir, baseDir, packageName) {
15322
16395
  const files = [];
15323
16396
  async function walkDir(dir, relativeBase) {
15324
- const entries = await import_fs12.promises.readdir(dir, { withFileTypes: true });
16397
+ const entries = await import_fs13.promises.readdir(dir, { withFileTypes: true });
15325
16398
  for (const entry of entries) {
15326
- const fullPath = import_path16.default.join(dir, entry.name);
15327
- const relativePath = import_path16.default.join(relativeBase, entry.name);
16399
+ const fullPath = import_path17.default.join(dir, entry.name);
16400
+ const relativePath = import_path17.default.join(relativeBase, entry.name);
15328
16401
  if (entry.isDirectory()) {
15329
16402
  if (["node_modules", "dist", ".git", "coverage"].includes(entry.name)) {
15330
16403
  continue;
15331
16404
  }
15332
16405
  await walkDir(fullPath, relativePath);
15333
16406
  } else if (entry.isFile()) {
15334
- const ext = import_path16.default.extname(entry.name).toLowerCase();
16407
+ const ext = import_path17.default.extname(entry.name).toLowerCase();
15335
16408
  if ([".md", ".json", ".js", ".ts", ".toml"].includes(ext)) {
15336
16409
  files.push(relativePath);
15337
16410
  }
15338
16411
  }
15339
16412
  }
15340
16413
  }
15341
- await walkDir(packageDir, import_path16.default.join(baseDir, packageName));
16414
+ await walkDir(packageDir, import_path17.default.join(baseDir, packageName));
15342
16415
  return files;
15343
16416
  }
15344
16417
  function buildRootManifestFiles() {
@@ -15360,7 +16433,7 @@ async function scanForPackages(cwd = process.cwd()) {
15360
16433
  allPackages.push(...packages);
15361
16434
  }
15362
16435
  for (const { file, format } of ROOT_MANIFEST_FILES) {
15363
- const filePath = import_path16.default.join(cwd, file);
16436
+ const filePath = import_path17.default.join(cwd, file);
15364
16437
  if (await fileExists2(filePath)) {
15365
16438
  const metadata = await extractMetadata2(filePath);
15366
16439
  allPackages.push({
@@ -15374,7 +16447,7 @@ async function scanForPackages(cwd = process.cwd()) {
15374
16447
  });
15375
16448
  }
15376
16449
  }
15377
- const copilotInstructionsPath = import_path16.default.join(cwd, ".github/copilot-instructions.md");
16450
+ const copilotInstructionsPath = import_path17.default.join(cwd, ".github/copilot-instructions.md");
15378
16451
  if (await fileExists2(copilotInstructionsPath)) {
15379
16452
  const metadata = await extractMetadata2(copilotInstructionsPath);
15380
16453
  allPackages.push({
@@ -15389,13 +16462,13 @@ async function scanForPackages(cwd = process.cwd()) {
15389
16462
  }
15390
16463
  return allPackages;
15391
16464
  }
15392
- var import_fs12, import_path16, SCAN_CONFIGS, ROOT_MANIFEST_FILES;
16465
+ var import_fs13, import_path17, SCAN_CONFIGS, ROOT_MANIFEST_FILES;
15393
16466
  var init_package_scanner = __esm({
15394
16467
  "src/core/package-scanner.ts"() {
15395
16468
  "use strict";
15396
16469
  init_cjs_shims();
15397
- import_fs12 = require("fs");
15398
- import_path16 = __toESM(require("path"));
16470
+ import_fs13 = require("fs");
16471
+ import_path17 = __toESM(require("path"));
15399
16472
  init_dist();
15400
16473
  SCAN_CONFIGS = buildScanConfigs();
15401
16474
  ROOT_MANIFEST_FILES = buildRootManifestFiles();
@@ -15405,8 +16478,8 @@ var init_package_scanner = __esm({
15405
16478
  // src/core/package-reconciler.ts
15406
16479
  async function readManifest(cwd = process.cwd()) {
15407
16480
  try {
15408
- const manifestPath = import_path17.default.join(cwd, "prpm.json");
15409
- const content = await import_fs13.promises.readFile(manifestPath, "utf-8");
16481
+ const manifestPath = import_path18.default.join(cwd, "prpm.json");
16482
+ const content = await import_fs14.promises.readFile(manifestPath, "utf-8");
15410
16483
  const raw = JSON.parse(content);
15411
16484
  if ("packages" in raw && Array.isArray(raw.packages)) {
15412
16485
  return {
@@ -15432,7 +16505,7 @@ async function readManifest(cwd = process.cwd()) {
15432
16505
  }
15433
16506
  async function fileExists3(filePath) {
15434
16507
  try {
15435
- await import_fs13.promises.access(filePath);
16508
+ await import_fs14.promises.access(filePath);
15436
16509
  return true;
15437
16510
  } catch {
15438
16511
  return false;
@@ -15488,7 +16561,7 @@ async function reconcilePackages(detected, manifest, cwd = process.cwd()) {
15488
16561
  const manifestPkg = manifest[mi];
15489
16562
  let anyFileExists = false;
15490
16563
  for (const file of manifestPkg.files) {
15491
- const fullPath = import_path17.default.join(cwd, file);
16564
+ const fullPath = import_path18.default.join(cwd, file);
15492
16565
  if (await fileExists3(fullPath)) {
15493
16566
  anyFileExists = true;
15494
16567
  break;
@@ -15557,7 +16630,7 @@ function createManifestFromDetected(packages, defaults) {
15557
16630
  files: pkg.files
15558
16631
  };
15559
16632
  }
15560
- const projectName = import_path17.default.basename(process.cwd()).toLowerCase().replace(/[^a-z0-9-]/g, "-");
16633
+ const projectName = import_path18.default.basename(process.cwd()).toLowerCase().replace(/[^a-z0-9-]/g, "-");
15561
16634
  return {
15562
16635
  name: `${projectName}-packages`,
15563
16636
  version: "1.0.0",
@@ -15568,13 +16641,13 @@ function createManifestFromDetected(packages, defaults) {
15568
16641
  packages: packages.map(detectedToManifest)
15569
16642
  };
15570
16643
  }
15571
- var import_fs13, import_path17;
16644
+ var import_fs14, import_path18;
15572
16645
  var init_package_reconciler = __esm({
15573
16646
  "src/core/package-reconciler.ts"() {
15574
16647
  "use strict";
15575
16648
  init_cjs_shims();
15576
- import_fs13 = require("fs");
15577
- import_path17 = __toESM(require("path"));
16649
+ import_fs14 = require("fs");
16650
+ import_path18 = __toESM(require("path"));
15578
16651
  }
15579
16652
  });
15580
16653
 
@@ -15689,12 +16762,12 @@ function getDefaultAuthor() {
15689
16762
  async function createExampleFiles(format, files, packageName) {
15690
16763
  const templates = EXAMPLE_TEMPLATES[format] || {};
15691
16764
  for (const file of files) {
15692
- const filePath = (0, import_path18.join)(process.cwd(), file);
15693
- const dirPath = (0, import_path18.join)(filePath, "..");
15694
- if (!(0, import_fs14.existsSync)(dirPath)) {
16765
+ const filePath = (0, import_path19.join)(process.cwd(), file);
16766
+ const dirPath = (0, import_path19.join)(filePath, "..");
16767
+ if (!(0, import_fs15.existsSync)(dirPath)) {
15695
16768
  await (0, import_promises8.mkdir)(dirPath, { recursive: true });
15696
16769
  }
15697
- if ((0, import_fs14.existsSync)(filePath)) {
16770
+ if ((0, import_fs15.existsSync)(filePath)) {
15698
16771
  console.log(` Skipping ${file} (already exists)`);
15699
16772
  continue;
15700
16773
  }
@@ -15708,8 +16781,8 @@ Add your content here.
15708
16781
  }
15709
16782
  }
15710
16783
  async function createReadme(config) {
15711
- const readmePath = (0, import_path18.join)(process.cwd(), "README.md");
15712
- if ((0, import_fs14.existsSync)(readmePath)) {
16784
+ const readmePath = (0, import_path19.join)(process.cwd(), "README.md");
16785
+ if ((0, import_fs15.existsSync)(readmePath)) {
15713
16786
  console.log(" Skipping README.md (already exists)");
15714
16787
  return;
15715
16788
  }
@@ -15818,8 +16891,8 @@ async function reviewMissingPackage(rl, pkg, index, total) {
15818
16891
  return await confirm(rl, "\n Remove from prpm.json?", true);
15819
16892
  }
15820
16893
  async function smartInit(options) {
15821
- const manifestPath = (0, import_path18.join)(process.cwd(), "prpm.json");
15822
- const hasManifest = (0, import_fs14.existsSync)(manifestPath);
16894
+ const manifestPath = (0, import_path19.join)(process.cwd(), "prpm.json");
16895
+ const hasManifest = (0, import_fs15.existsSync)(manifestPath);
15823
16896
  console.log("\nScanning for packages...\n");
15824
16897
  const detected = await scanForPackages();
15825
16898
  const existingManifest = hasManifest ? await readManifest() : null;
@@ -15969,8 +17042,8 @@ Create multi-package prpm.json with these ${detected.length} packages?` : "\nCre
15969
17042
  }
15970
17043
  }
15971
17044
  async function classicInit(options) {
15972
- const manifestPath = (0, import_path18.join)(process.cwd(), "prpm.json");
15973
- if ((0, import_fs14.existsSync)(manifestPath) && !options.force) {
17045
+ const manifestPath = (0, import_path19.join)(process.cwd(), "prpm.json");
17046
+ if ((0, import_fs15.existsSync)(manifestPath) && !options.force) {
15974
17047
  throw new Error(
15975
17048
  "prpm.json already exists. Use --force to overwrite, or run this command in a different directory."
15976
17049
  );
@@ -16228,7 +17301,7 @@ async function scanMode(directories, options) {
16228
17301
  console.log("\u{1F50D} Dry run - no changes made\n");
16229
17302
  return;
16230
17303
  }
16231
- const prpmJsonPath = options.output || (0, import_path18.join)(process.cwd(), "prpm.json");
17304
+ const prpmJsonPath = options.output || (0, import_path19.join)(process.cwd(), "prpm.json");
16232
17305
  let manifest;
16233
17306
  if (options.append) {
16234
17307
  try {
@@ -16330,15 +17403,15 @@ function createInitCommand() {
16330
17403
  });
16331
17404
  return command;
16332
17405
  }
16333
- var import_commander12, import_promises8, import_path18, import_fs14, readline4, import_process, FORMAT_EXAMPLES, EXAMPLE_TEMPLATES;
17406
+ var import_commander12, import_promises8, import_path19, import_fs15, readline4, import_process, FORMAT_EXAMPLES, EXAMPLE_TEMPLATES;
16334
17407
  var init_init = __esm({
16335
17408
  "src/commands/init.ts"() {
16336
17409
  "use strict";
16337
17410
  init_cjs_shims();
16338
17411
  import_commander12 = require("commander");
16339
17412
  import_promises8 = require("fs/promises");
16340
- import_path18 = require("path");
16341
- import_fs14 = require("fs");
17413
+ import_path19 = require("path");
17414
+ import_fs15 = require("fs");
16342
17415
  readline4 = __toESM(require("readline/promises"));
16343
17416
  import_process = require("process");
16344
17417
  init_types();
@@ -16355,6 +17428,16 @@ var init_init = __esm({
16355
17428
  description: "Claude AI skills and agents",
16356
17429
  files: [".claude/skills/example-skill/SKILL.md", "README.md"]
16357
17430
  },
17431
+ "claude-plugin": {
17432
+ description: "Claude Code plugins with agents, skills, commands, and MCP servers",
17433
+ files: [
17434
+ ".claude-plugin/plugin.json",
17435
+ ".claude-plugin/agents/example.md",
17436
+ ".claude-plugin/skills/example/SKILL.md",
17437
+ ".claude-plugin/commands/example.md",
17438
+ "README.md"
17439
+ ]
17440
+ },
16358
17441
  continue: {
16359
17442
  description: "Continue AI coding rules",
16360
17443
  files: [".continuerules", "README.md"]
@@ -16389,8 +17472,8 @@ var init_init = __esm({
16389
17472
  files: ["prompts/example.md", "README.md"]
16390
17473
  },
16391
17474
  mcp: {
16392
- description: "Model Context Protocol",
16393
- files: ["mcp.json", "README.md"]
17475
+ description: "Model Context Protocol servers",
17476
+ files: ["mcp-server.json", "README.md"]
16394
17477
  }
16395
17478
  };
16396
17479
  EXAMPLE_TEMPLATES = {
@@ -16434,6 +17517,69 @@ Explain when this skill should be invoked.
16434
17517
  ## Instructions
16435
17518
 
16436
17519
  Provide detailed instructions for the AI to follow when using this skill.
17520
+ `
17521
+ },
17522
+ "claude-plugin": {
17523
+ ".claude-plugin/plugin.json": `{
17524
+ "name": "Example Plugin",
17525
+ "description": "An example Claude plugin - replace with your actual plugin",
17526
+ "version": "1.0.0",
17527
+ "author": "Your Name",
17528
+ "mcpServers": {
17529
+ "example-server": {
17530
+ "command": "npx",
17531
+ "args": ["-y", "@example/mcp-server"],
17532
+ "env": {}
17533
+ }
17534
+ }
17535
+ }`,
17536
+ ".claude-plugin/agents/example.md": `---
17537
+ name: example-agent
17538
+ description: Example agent - replace with your actual agent
17539
+ ---
17540
+
17541
+ # Example Agent
17542
+
17543
+ This is an example Claude agent. Replace this content with your actual agent definition.
17544
+
17545
+ ## Role
17546
+
17547
+ Describe the agent's role and responsibilities.
17548
+
17549
+ ## Instructions
17550
+
17551
+ Provide detailed instructions for the agent to follow.
17552
+ `,
17553
+ ".claude-plugin/skills/example/SKILL.md": `---
17554
+ name: example-skill
17555
+ description: Example skill - replace with your actual skill
17556
+ tags: example, template
17557
+ ---
17558
+
17559
+ # Example Skill
17560
+
17561
+ This is an example skill bundled with the plugin.
17562
+
17563
+ ## What this skill does
17564
+
17565
+ Describe what this skill helps the AI accomplish.
17566
+
17567
+ ## Instructions
17568
+
17569
+ Provide detailed instructions for the AI to follow when using this skill.
17570
+ `,
17571
+ ".claude-plugin/commands/example.md": `---
17572
+ name: example-command
17573
+ description: Example slash command - replace with your actual command
17574
+ ---
17575
+
17576
+ # Example Command
17577
+
17578
+ This is an example slash command. It will be available as /example-command in Claude Code.
17579
+
17580
+ ## Usage
17581
+
17582
+ Describe how to use this command.
16437
17583
  `
16438
17584
  },
16439
17585
  windsurf: {
@@ -16623,6 +17769,23 @@ Provide clear instructions for the AI.
16623
17769
 
16624
17770
  Include examples if helpful.
16625
17771
  `
17772
+ },
17773
+ mcp: {
17774
+ "mcp-server.json": `{
17775
+ "name": "Example MCP Server",
17776
+ "description": "An example MCP server package - replace with your actual server configuration",
17777
+ "version": "1.0.0",
17778
+ "author": "Your Name",
17779
+ "mcpServers": {
17780
+ "example-server": {
17781
+ "command": "npx",
17782
+ "args": ["-y", "@example/mcp-server"],
17783
+ "env": {
17784
+ "API_KEY": "\${API_KEY}"
17785
+ }
17786
+ }
17787
+ }
17788
+ }`
16626
17789
  }
16627
17790
  };
16628
17791
  }
@@ -16631,8 +17794,8 @@ Include examples if helpful.
16631
17794
  // src/index.ts
16632
17795
  init_cjs_shims();
16633
17796
  var import_commander29 = require("commander");
16634
- var import_fs18 = require("fs");
16635
- var import_path22 = require("path");
17797
+ var import_fs19 = require("fs");
17798
+ var import_path23 = require("path");
16636
17799
 
16637
17800
  // src/commands/list.ts
16638
17801
  init_cjs_shims();
@@ -16792,9 +17955,10 @@ var import_commander2 = require("commander");
16792
17955
  init_lockfile();
16793
17956
  init_filesystem();
16794
17957
  init_types();
16795
- var import_fs8 = require("fs");
17958
+ var import_fs9 = require("fs");
16796
17959
  init_errors();
16797
17960
  init_agents_md_progressive();
17961
+ init_mcp();
16798
17962
  var readline = __toESM(require("readline"));
16799
17963
  async function promptForFormat(packageId, formats) {
16800
17964
  console.log(`
@@ -16890,10 +18054,43 @@ async function handleUninstall(name, options = {}) {
16890
18054
  }
16891
18055
  }
16892
18056
  }
18057
+ if (pkg.pluginMetadata) {
18058
+ const isMCPServerOnly = pkg.pluginMetadata.files.length === 0 && pkg.pluginMetadata.mcpServers;
18059
+ console.log(isMCPServerOnly ? ` \u{1F527} Uninstalling MCP server...` : ` \u{1F50C} Uninstalling Claude plugin...`);
18060
+ const { files, mcpServers, mcpGlobal } = pkg.pluginMetadata;
18061
+ let filesRemoved = 0;
18062
+ for (const filePath of files) {
18063
+ try {
18064
+ await import_fs9.promises.unlink(filePath);
18065
+ filesRemoved++;
18066
+ console.log(` \u{1F5D1}\uFE0F Deleted: ${filePath}`);
18067
+ } catch (error) {
18068
+ const err = error;
18069
+ if (err.code !== "ENOENT") {
18070
+ console.warn(` \u26A0\uFE0F Failed to delete ${filePath}: ${err.message}`);
18071
+ }
18072
+ }
18073
+ }
18074
+ if (filesRemoved > 0) {
18075
+ console.log(` \u{1F4E6} Removed ${filesRemoved} file(s)`);
18076
+ }
18077
+ if (mcpServers && Object.keys(mcpServers).length > 0) {
18078
+ const mcpResult = removeMCPServers(mcpServers, mcpGlobal || false);
18079
+ if (mcpResult.removed.length > 0) {
18080
+ const location = mcpGlobal ? "~/.claude/settings.json" : ".mcp.json";
18081
+ console.log(` \u{1F527} Removed ${mcpResult.removed.length} MCP server(s) from ${location}`);
18082
+ }
18083
+ for (const warning of mcpResult.warnings) {
18084
+ console.log(` \u26A0\uFE0F ${warning}`);
18085
+ }
18086
+ }
18087
+ console.log(`\u2705 Successfully uninstalled ${name}${formatDisplay}`);
18088
+ continue;
18089
+ }
16893
18090
  if (pkg.format === "claude" && pkg.subtype === "hook" && pkg.hookMetadata) {
16894
18091
  const settingsPath = pkg.installedPath || ".claude/settings.json";
16895
18092
  try {
16896
- const settingsContent = await import_fs8.promises.readFile(settingsPath, "utf-8");
18093
+ const settingsContent = await import_fs9.promises.readFile(settingsPath, "utf-8");
16897
18094
  const settings = JSON.parse(settingsContent);
16898
18095
  if (settings.hooks) {
16899
18096
  let removedCount = 0;
@@ -16910,7 +18107,7 @@ async function handleUninstall(name, options = {}) {
16910
18107
  }
16911
18108
  }
16912
18109
  }
16913
- await import_fs8.promises.writeFile(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
18110
+ await import_fs9.promises.writeFile(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
16914
18111
  console.log(` \u{1FA9D} Removed ${removedCount} hook(s) from ${settingsPath}`);
16915
18112
  }
16916
18113
  } catch (error) {
@@ -16935,12 +18132,12 @@ async function handleUninstall(name, options = {}) {
16935
18132
  throw new CLIError(`Cannot uninstall ${name}: installation path unknown`, 1);
16936
18133
  }
16937
18134
  try {
16938
- const stats = await import_fs8.promises.stat(targetPath);
18135
+ const stats = await import_fs9.promises.stat(targetPath);
16939
18136
  if (stats.isDirectory()) {
16940
- await import_fs8.promises.rm(targetPath, { recursive: true, force: true });
18137
+ await import_fs9.promises.rm(targetPath, { recursive: true, force: true });
16941
18138
  console.log(` \u{1F5D1}\uFE0F Deleted directory: ${targetPath}`);
16942
18139
  } else if (stats.isFile()) {
16943
- await import_fs8.promises.unlink(targetPath);
18140
+ await import_fs9.promises.unlink(targetPath);
16944
18141
  console.log(` \u{1F5D1}\uFE0F Deleted file: ${targetPath}`);
16945
18142
  }
16946
18143
  } catch (error) {
@@ -16969,17 +18166,17 @@ function createUninstallCommand() {
16969
18166
  // src/commands/index.ts
16970
18167
  init_cjs_shims();
16971
18168
  var import_commander3 = require("commander");
16972
- var import_fs9 = require("fs");
16973
- var import_path9 = __toESM(require("path"));
18169
+ var import_fs10 = require("fs");
18170
+ var import_path10 = __toESM(require("path"));
16974
18171
  init_lockfile();
16975
18172
  init_filesystem();
16976
18173
  init_errors();
16977
18174
  async function scanDirectory(dirPath, format, subtype) {
16978
18175
  try {
16979
- const files = await import_fs9.promises.readdir(dirPath, { withFileTypes: true });
18176
+ const files = await import_fs10.promises.readdir(dirPath, { withFileTypes: true });
16980
18177
  const results = [];
16981
18178
  for (const file of files) {
16982
- const fullPath = import_path9.default.join(dirPath, file.name);
18179
+ const fullPath = import_path10.default.join(dirPath, file.name);
16983
18180
  if (file.isFile()) {
16984
18181
  const id = generateId(file.name);
16985
18182
  results.push({
@@ -16992,11 +18189,11 @@ async function scanDirectory(dirPath, format, subtype) {
16992
18189
  const isCursorAgent = format === "cursor" && subtype === "agent";
16993
18190
  if (isClaudeType || isCursorAgent) {
16994
18191
  try {
16995
- const subFiles = await import_fs9.promises.readdir(fullPath, { withFileTypes: true });
18192
+ const subFiles = await import_fs10.promises.readdir(fullPath, { withFileTypes: true });
16996
18193
  for (const subFile of subFiles) {
16997
18194
  const isValidFile = subFile.isFile() && (subFile.name === "SKILL.md" || subFile.name === "AGENT.md" || subFile.name === "skill.md" || subFile.name === "agent.md");
16998
18195
  if (isValidFile) {
16999
- const subFilePath = import_path9.default.join(fullPath, subFile.name);
18196
+ const subFilePath = import_path10.default.join(fullPath, subFile.name);
17000
18197
  const id = file.name;
17001
18198
  results.push({
17002
18199
  filePath: subFilePath,
@@ -17058,7 +18255,7 @@ async function handleIndex(options = {}) {
17058
18255
  id: file.id,
17059
18256
  version: "0.0.0",
17060
18257
  // Local files don't have versions
17061
- tarballUrl: `file://${import_path9.default.resolve(file.filePath)}`,
18258
+ tarballUrl: `file://${import_path10.default.resolve(file.filePath)}`,
17062
18259
  format: dir.format,
17063
18260
  subtype: dir.subtype
17064
18261
  });
@@ -17316,7 +18513,9 @@ function getPackageIcon(format, subtype) {
17316
18513
  "tool": "\u{1F527}",
17317
18514
  "hook": "\u{1FA9D}",
17318
18515
  "workflow": "\u{1F504}",
17319
- "template": "\u{1F4C4}"
18516
+ "template": "\u{1F4C4}",
18517
+ "plugin": "\u{1F50C}",
18518
+ "server": "\u{1F5A5}\uFE0F"
17320
18519
  };
17321
18520
  const formatIcons = {
17322
18521
  "claude": "\u{1F916}",
@@ -17374,7 +18573,9 @@ function getPackageLabel(format, subtype) {
17374
18573
  "tool": "Tool",
17375
18574
  "hook": "Hook",
17376
18575
  "workflow": "Workflow",
17377
- "template": "Template"
18576
+ "template": "Template",
18577
+ "plugin": "Plugin",
18578
+ "server": "Server"
17378
18579
  };
17379
18580
  const formatLabel = formatLabels[format];
17380
18581
  const subtypeLabel = subtypeLabels[subtype];
@@ -17885,8 +19086,8 @@ init_install();
17885
19086
  init_cjs_shims();
17886
19087
  var import_commander13 = require("commander");
17887
19088
  var import_promises9 = require("fs/promises");
17888
- var import_path19 = require("path");
17889
- var import_fs15 = require("fs");
19089
+ var import_path20 = require("path");
19090
+ var import_fs16 = require("fs");
17890
19091
  var import_registry_client6 = require("@pr-pm/registry-client");
17891
19092
  init_user_config();
17892
19093
  init_telemetry();
@@ -17895,8 +19096,8 @@ init_errors();
17895
19096
  // src/utils/license-extractor.ts
17896
19097
  init_cjs_shims();
17897
19098
  var import_promises3 = require("fs/promises");
17898
- var import_path11 = require("path");
17899
- var import_fs10 = require("fs");
19099
+ var import_path12 = require("path");
19100
+ var import_fs11 = require("fs");
17900
19101
  var LICENSE_FILE_PATTERNS = [
17901
19102
  "LICENSE",
17902
19103
  "LICENSE.md",
@@ -17945,9 +19146,9 @@ function generateLicenseUrl(repositoryUrl, fileName) {
17945
19146
  async function extractLicenseInfo(repositoryUrl) {
17946
19147
  const cwd = process.cwd();
17947
19148
  for (const fileName of LICENSE_FILE_PATTERNS) {
17948
- const filePath = (0, import_path11.join)(cwd, fileName);
19149
+ const filePath = (0, import_path12.join)(cwd, fileName);
17949
19150
  try {
17950
- await (0, import_promises3.access)(filePath, import_fs10.constants.R_OK);
19151
+ await (0, import_promises3.access)(filePath, import_fs11.constants.R_OK);
17951
19152
  const text = await (0, import_promises3.readFile)(filePath, "utf-8");
17952
19153
  const type2 = detectLicenseType(text);
17953
19154
  const url = generateLicenseUrl(repositoryUrl, fileName);
@@ -17981,7 +19182,7 @@ function validateLicenseInfo(licenseInfo, packageName) {
17981
19182
  // src/utils/snippet-extractor.ts
17982
19183
  init_cjs_shims();
17983
19184
  var import_promises4 = require("fs/promises");
17984
- var import_path12 = require("path");
19185
+ var import_path13 = require("path");
17985
19186
  var MAX_SNIPPET_LENGTH = 2e3;
17986
19187
  async function extractSnippet(manifest) {
17987
19188
  const cwd = process.cwd();
@@ -17997,7 +19198,7 @@ async function extractSnippet(manifest) {
17997
19198
  const firstFile = manifest.files[0];
17998
19199
  fileName = typeof firstFile === "string" ? firstFile : firstFile.path;
17999
19200
  }
18000
- const fullPath = (0, import_path12.join)(cwd, fileName);
19201
+ const fullPath = (0, import_path13.join)(cwd, fileName);
18001
19202
  const stats = await (0, import_promises4.stat)(fullPath);
18002
19203
  if (stats.isDirectory()) {
18003
19204
  console.warn(`\u26A0\uFE0F Skipping snippet extraction: "${fullPath}" is a directory`);
@@ -18105,7 +19306,7 @@ function getFormatType(format) {
18105
19306
  "windsurf": "windsurf",
18106
19307
  "copilot": "copilot",
18107
19308
  "kiro": "kiro",
18108
- "agents-md": "agents-md",
19309
+ "agents.md": "agents.md",
18109
19310
  "canonical": "canonical"
18110
19311
  };
18111
19312
  return formatMap[format] || null;
@@ -18201,7 +19402,7 @@ async function validatePackageFiles(manifest) {
18201
19402
  return filePath.includes(".continue/") && filePath.endsWith(".json");
18202
19403
  } else if (formatType === "windsurf") {
18203
19404
  return filePath.includes(".windsurf/rules");
18204
- } else if (formatType === "agents-md") {
19405
+ } else if (formatType === "agents.md") {
18205
19406
  return filePath === "agents.md";
18206
19407
  } else if (formatType === "kiro") {
18207
19408
  return filePath.endsWith(".md") || filePath.endsWith(".json");
@@ -18217,7 +19418,7 @@ async function validatePackageFiles(manifest) {
18217
19418
  const result = await validateMarkdownFile(filePath, formatType);
18218
19419
  errors.push(...result.errors);
18219
19420
  warnings.push(...result.warnings);
18220
- } else if (formatType === "agents-md") {
19421
+ } else if (formatType === "agents.md") {
18221
19422
  const result = await validateMarkdownFile(filePath, formatType);
18222
19423
  errors.push(...result.errors);
18223
19424
  warnings.push(...result.warnings);
@@ -18258,7 +19459,7 @@ async function validatePackageFiles(manifest) {
18258
19459
  // src/utils/manifest-loader.ts
18259
19460
  init_cjs_shims();
18260
19461
  var import_promises6 = require("fs/promises");
18261
- var import_path14 = require("path");
19462
+ var import_path15 = require("path");
18262
19463
 
18263
19464
  // src/core/marketplace-converter.ts
18264
19465
  init_cjs_shims();
@@ -18424,19 +19625,19 @@ function validateMarketplaceJson(data) {
18424
19625
  init_cjs_shims();
18425
19626
  var import_ajv2 = __toESM(require("ajv"));
18426
19627
  var import_ajv_formats2 = __toESM(require("ajv-formats"));
18427
- var import_fs11 = require("fs");
18428
- var import_path13 = require("path");
19628
+ var import_fs12 = require("fs");
19629
+ var import_path14 = require("path");
18429
19630
  var schema2;
18430
19631
  var schemaCandidates = [
18431
19632
  // Source file layout (src/core → ../../schemas)
18432
- (0, import_path13.join)(__dirname, "../../schemas/prpm-manifest.schema.json"),
19633
+ (0, import_path14.join)(__dirname, "../../schemas/prpm-manifest.schema.json"),
18433
19634
  // Bundled layout (dist/index.js → ../schemas)
18434
- (0, import_path13.join)(__dirname, "../schemas/prpm-manifest.schema.json")
19635
+ (0, import_path14.join)(__dirname, "../schemas/prpm-manifest.schema.json")
18435
19636
  ];
18436
19637
  for (const candidate of schemaCandidates) {
18437
19638
  try {
18438
- if ((0, import_fs11.existsSync)(candidate)) {
18439
- schema2 = JSON.parse((0, import_fs11.readFileSync)(candidate, "utf-8"));
19639
+ if ((0, import_fs12.existsSync)(candidate)) {
19640
+ schema2 = JSON.parse((0, import_fs12.readFileSync)(candidate, "utf-8"));
18440
19641
  break;
18441
19642
  }
18442
19643
  } catch {
@@ -18490,7 +19691,7 @@ function getManifestSchema() {
18490
19691
 
18491
19692
  // src/utils/manifest-loader.ts
18492
19693
  async function findAndLoadManifests() {
18493
- const prpmJsonPath = (0, import_path14.join)(process.cwd(), "prpm.json");
19694
+ const prpmJsonPath = (0, import_path15.join)(process.cwd(), "prpm.json");
18494
19695
  let prpmJsonExists = false;
18495
19696
  try {
18496
19697
  const content = await (0, import_promises6.readFile)(prpmJsonPath, "utf-8");
@@ -18551,7 +19752,7 @@ async function findAndLoadManifests() {
18551
19752
  throw error;
18552
19753
  }
18553
19754
  }
18554
- const marketplaceJsonPath = (0, import_path14.join)(
19755
+ const marketplaceJsonPath = (0, import_path15.join)(
18555
19756
  process.cwd(),
18556
19757
  ".claude",
18557
19758
  "marketplace.json"
@@ -18571,7 +19772,7 @@ async function findAndLoadManifests() {
18571
19772
  return { manifests, collections: [], source: ".claude/marketplace.json" };
18572
19773
  } catch (error) {
18573
19774
  }
18574
- const marketplaceJsonPluginPath = (0, import_path14.join)(
19775
+ const marketplaceJsonPluginPath = (0, import_path15.join)(
18575
19776
  process.cwd(),
18576
19777
  ".claude-plugin",
18577
19778
  "marketplace.json"
@@ -18721,13 +19922,13 @@ function getSafePackageName(manifest, userInfo, fallbackName) {
18721
19922
  // src/utils/tarball-creator.ts
18722
19923
  init_cjs_shims();
18723
19924
  var import_promises7 = require("fs/promises");
18724
- var import_path15 = require("path");
19925
+ var import_path16 = require("path");
18725
19926
  var tar2 = __toESM(require("tar"));
18726
- var import_os4 = require("os");
19927
+ var import_os5 = require("os");
18727
19928
  var import_crypto2 = require("crypto");
18728
19929
  async function createTarball(manifest) {
18729
- const tmpDir = (0, import_path15.join)((0, import_os4.tmpdir)(), `prpm-${(0, import_crypto2.randomBytes)(8).toString("hex")}`);
18730
- const tarballPath = (0, import_path15.join)(tmpDir, "package.tar.gz");
19930
+ const tmpDir = (0, import_path16.join)((0, import_os5.tmpdir)(), `prpm-${(0, import_crypto2.randomBytes)(8).toString("hex")}`);
19931
+ const tarballPath = (0, import_path16.join)(tmpDir, "package.tar.gz");
18731
19932
  try {
18732
19933
  await (0, import_promises7.mkdir)(tmpDir, { recursive: true });
18733
19934
  const filePaths = normalizeFilePaths2(manifest.files);
@@ -18856,22 +20057,22 @@ async function handlePublish(options) {
18856
20057
  throw new CLIError('\u274C Not logged in. Run "prpm login" first.', 1);
18857
20058
  }
18858
20059
  console.log("\u{1F4E6} Publishing package...\n");
18859
- const prpmJsonPath = (0, import_path19.join)(process.cwd(), "prpm.json");
18860
- const marketplaceJsonPath = (0, import_path19.join)(
20060
+ const prpmJsonPath = (0, import_path20.join)(process.cwd(), "prpm.json");
20061
+ const marketplaceJsonPath = (0, import_path20.join)(
18861
20062
  process.cwd(),
18862
20063
  ".claude",
18863
20064
  "marketplace.json"
18864
20065
  );
18865
- const marketplaceJsonPluginPath = (0, import_path19.join)(
20066
+ const marketplaceJsonPluginPath = (0, import_path20.join)(
18866
20067
  process.cwd(),
18867
20068
  ".claude-plugin",
18868
20069
  "marketplace.json"
18869
20070
  );
18870
- const hasManifest = (0, import_fs15.existsSync)(prpmJsonPath) || (0, import_fs15.existsSync)(marketplaceJsonPath) || (0, import_fs15.existsSync)(marketplaceJsonPluginPath);
20071
+ const hasManifest = (0, import_fs16.existsSync)(prpmJsonPath) || (0, import_fs16.existsSync)(marketplaceJsonPath) || (0, import_fs16.existsSync)(marketplaceJsonPluginPath);
18871
20072
  if (!hasManifest) {
18872
20073
  console.log("No prpm.json found. Let's create one first.\n");
18873
20074
  await smartInit({});
18874
- if (!(0, import_fs15.existsSync)(prpmJsonPath)) {
20075
+ if (!(0, import_fs16.existsSync)(prpmJsonPath)) {
18875
20076
  throw new CLIError(
18876
20077
  "No prpm.json was created. Cannot publish without a manifest.",
18877
20078
  1
@@ -18883,7 +20084,7 @@ async function handlePublish(options) {
18883
20084
  const { manifests, collections, source } = await findAndLoadManifests();
18884
20085
  if (source === "prpm.json (multi-package)" || source === "prpm.json") {
18885
20086
  try {
18886
- const prpmJsonPath2 = (0, import_path19.join)(process.cwd(), "prpm.json");
20087
+ const prpmJsonPath2 = (0, import_path20.join)(process.cwd(), "prpm.json");
18887
20088
  const prpmContent = await (0, import_promises9.readFile)(prpmJsonPath2, "utf-8");
18888
20089
  const prpmManifest = JSON.parse(prpmContent);
18889
20090
  if (prpmManifest.scripts) {
@@ -21408,57 +22609,60 @@ function createStarredCommand() {
21408
22609
  init_cjs_shims();
21409
22610
  var import_commander27 = require("commander");
21410
22611
  var import_promises10 = require("fs/promises");
21411
- var import_path20 = require("path");
21412
- var import_fs16 = require("fs");
22612
+ var import_path21 = require("path");
22613
+ var import_fs17 = require("fs");
21413
22614
  var import_readline = require("readline");
21414
22615
  var import_chalk2 = __toESM(require_source());
21415
22616
  init_errors();
21416
22617
  init_dist();
21417
22618
  function getDefaultPath(format, filename, subtype, customName) {
21418
- const baseName = customName || (0, import_path20.basename)(filename, (0, import_path20.extname)(filename));
22619
+ const baseName = customName || (0, import_path21.basename)(filename, (0, import_path21.extname)(filename));
21419
22620
  switch (format) {
21420
22621
  case "cursor":
21421
22622
  if (subtype === "slash-command") {
21422
- return (0, import_path20.join)(process.cwd(), ".cursor", "commands", `${baseName}.md`);
22623
+ return (0, import_path21.join)(process.cwd(), ".cursor", "commands", `${baseName}.md`);
22624
+ }
22625
+ if (subtype === "hook") {
22626
+ return (0, import_path21.join)(process.cwd(), ".cursor", "hooks", "hooks.json");
21423
22627
  }
21424
- return (0, import_path20.join)(process.cwd(), ".cursor", "rules", `${baseName}.mdc`);
22628
+ return (0, import_path21.join)(process.cwd(), ".cursor", "rules", `${baseName}.mdc`);
21425
22629
  case "claude":
21426
22630
  if (subtype === "skill") {
21427
- return (0, import_path20.join)(process.cwd(), ".claude", "skills", baseName, "SKILL.md");
22631
+ return (0, import_path21.join)(process.cwd(), ".claude", "skills", baseName, "SKILL.md");
21428
22632
  } else if (subtype === "slash-command") {
21429
- return (0, import_path20.join)(process.cwd(), ".claude", "commands", `${baseName}.md`);
22633
+ return (0, import_path21.join)(process.cwd(), ".claude", "commands", `${baseName}.md`);
21430
22634
  } else {
21431
- return (0, import_path20.join)(process.cwd(), ".claude", "agents", `${baseName}.md`);
22635
+ return (0, import_path21.join)(process.cwd(), ".claude", "agents", `${baseName}.md`);
21432
22636
  }
21433
22637
  case "windsurf":
21434
- return (0, import_path20.join)(process.cwd(), ".windsurf", "rules", `${baseName}.md`);
22638
+ return (0, import_path21.join)(process.cwd(), ".windsurf", "rules", `${baseName}.md`);
21435
22639
  case "kiro":
21436
22640
  if (subtype === "hook") {
21437
- return (0, import_path20.join)(process.cwd(), ".kiro", "hooks", `${baseName}.kiro.hook`);
22641
+ return (0, import_path21.join)(process.cwd(), ".kiro", "hooks", `${baseName}.kiro.hook`);
21438
22642
  }
21439
22643
  if (subtype === "agent") {
21440
- return (0, import_path20.join)(process.cwd(), ".kiro", "agents", `${baseName}.json`);
22644
+ return (0, import_path21.join)(process.cwd(), ".kiro", "agents", `${baseName}.json`);
21441
22645
  }
21442
- return (0, import_path20.join)(process.cwd(), ".kiro", "steering", `${baseName}.md`);
22646
+ return (0, import_path21.join)(process.cwd(), ".kiro", "steering", `${baseName}.md`);
21443
22647
  case "copilot":
21444
- return (0, import_path20.join)(process.cwd(), ".github", "instructions", `${baseName}.instructions.md`);
22648
+ return (0, import_path21.join)(process.cwd(), ".github", "instructions", `${baseName}.instructions.md`);
21445
22649
  case "continue":
21446
22650
  if (subtype === "slash-command" || subtype === "prompt") {
21447
- return (0, import_path20.join)(process.cwd(), ".continue", "prompts", `${baseName}.md`);
22651
+ return (0, import_path21.join)(process.cwd(), ".continue", "prompts", `${baseName}.md`);
21448
22652
  }
21449
- return (0, import_path20.join)(process.cwd(), ".continue", "rules", `${baseName}.md`);
22653
+ return (0, import_path21.join)(process.cwd(), ".continue", "rules", `${baseName}.md`);
21450
22654
  case "agents.md":
21451
- return (0, import_path20.join)(process.cwd(), "agents.md");
22655
+ return (0, import_path21.join)(process.cwd(), "agents.md");
21452
22656
  case "gemini":
21453
- return (0, import_path20.join)(process.cwd(), ".gemini", "commands", `${baseName}.toml`);
22657
+ return (0, import_path21.join)(process.cwd(), ".gemini", "commands", `${baseName}.toml`);
21454
22658
  case "ruler":
21455
- return (0, import_path20.join)(process.cwd(), ".ruler", `${baseName}.md`);
22659
+ return (0, import_path21.join)(process.cwd(), ".ruler", `${baseName}.md`);
21456
22660
  default:
21457
22661
  throw new CLIError(`Unknown format: ${format}`);
21458
22662
  }
21459
22663
  }
21460
22664
  function detectFormat(content, filepath) {
21461
- const ext = (0, import_path20.extname)(filepath).toLowerCase();
22665
+ const ext = (0, import_path21.extname)(filepath).toLowerCase();
21462
22666
  if (ext === ".mdc" || filepath.includes(".cursor/rules") || filepath.includes(".cursor/commands")) {
21463
22667
  return "cursor";
21464
22668
  }
@@ -21480,7 +22684,7 @@ function detectFormat(content, filepath) {
21480
22684
  if (filepath.includes(".continue/rules") || filepath.includes(".continue/prompts") || filepath.includes(".continuerules")) {
21481
22685
  return "continue";
21482
22686
  }
21483
- if ((0, import_path20.basename)(filepath) === "agents.md") {
22687
+ if ((0, import_path21.basename)(filepath) === "agents.md") {
21484
22688
  return "agents.md";
21485
22689
  }
21486
22690
  if (ext === ".toml" || filepath.includes(".gemini/commands")) {
@@ -21489,6 +22693,7 @@ function detectFormat(content, filepath) {
21489
22693
  if (filepath.includes(".ruler/")) {
21490
22694
  return "ruler";
21491
22695
  }
22696
+ if (isCursorHooksFormat(content)) return "cursor-hooks";
21492
22697
  if (isClaudeFormat(content)) {
21493
22698
  if (content.includes("type: skill")) return "claude-skill";
21494
22699
  if (content.includes("type: agent")) return "claude-agent";
@@ -21555,6 +22760,9 @@ async function handleConvert(sourcePath, options) {
21555
22760
  case "cursor":
21556
22761
  canonicalPkg = fromCursor(content, metadata);
21557
22762
  break;
22763
+ case "cursor-hooks":
22764
+ canonicalPkg = fromCursorHooks(content, metadata);
22765
+ break;
21558
22766
  case "claude":
21559
22767
  case "claude-agent":
21560
22768
  case "claude-skill":
@@ -21597,7 +22805,13 @@ async function handleConvert(sourcePath, options) {
21597
22805
  let result;
21598
22806
  switch (options.to) {
21599
22807
  case "cursor":
21600
- result = toCursor(canonicalPkg);
22808
+ if (options.subtype === "hook") {
22809
+ result = toCursorHooks(canonicalPkg, {
22810
+ hookMappingStrategy: options.hookMapping || "auto"
22811
+ });
22812
+ } else {
22813
+ result = toCursor(canonicalPkg);
22814
+ }
21601
22815
  break;
21602
22816
  case "claude":
21603
22817
  result = toClaude(canonicalPkg);
@@ -21638,14 +22852,14 @@ async function handleConvert(sourcePath, options) {
21638
22852
  }
21639
22853
  console.log(import_chalk2.default.green(`\u2713 Converted from ${sourceFormat} to ${options.to}`));
21640
22854
  const outputPath = options.output || getDefaultPath(options.to, sourcePath, options.subtype, options.name);
21641
- if ((0, import_fs16.existsSync)(outputPath) && !options.yes) {
22855
+ if ((0, import_fs17.existsSync)(outputPath) && !options.yes) {
21642
22856
  const shouldOverwrite = await confirmOverwrite(outputPath);
21643
22857
  if (!shouldOverwrite) {
21644
22858
  console.log(import_chalk2.default.yellow("\n\u2716 Conversion cancelled"));
21645
22859
  return;
21646
22860
  }
21647
22861
  }
21648
- const outputDir = (0, import_path20.dirname)(outputPath);
22862
+ const outputDir = (0, import_path21.dirname)(outputPath);
21649
22863
  await (0, import_promises10.mkdir)(outputDir, { recursive: true });
21650
22864
  console.log(import_chalk2.default.dim("Writing converted file..."));
21651
22865
  await (0, import_promises10.writeFile)(outputPath, result.content, "utf-8");
@@ -21670,7 +22884,7 @@ async function handleConvert(sourcePath, options) {
21670
22884
  }
21671
22885
  }
21672
22886
  function createConvertCommand() {
21673
- const command = new import_commander27.Command("convert").description("Convert AI prompt files between formats").argument("<source>", "Source file path to convert").option("-t, --to <format>", "Target format (cursor, claude, windsurf, kiro, copilot, continue, agents.md, gemini, ruler)").option("-s, --subtype <subtype>", "Target subtype (agent, skill, slash-command, rule, prompt, etc.)").option("-o, --output <path>", "Output path (defaults to format-specific location)").option("-n, --name <name>", 'Custom output filename (without extension, e.g., "my-rule")').option("-y, --yes", "Skip confirmation prompts").action(async (source, options) => {
22887
+ const command = new import_commander27.Command("convert").description("Convert AI prompt files between formats").argument("<source>", "Source file path to convert").option("-t, --to <format>", "Target format (cursor, claude, windsurf, kiro, copilot, continue, agents.md, gemini, ruler)").option("-s, --subtype <subtype>", "Target subtype (agent, skill, slash-command, rule, hook, prompt, etc.)").option("-o, --output <path>", "Output path (defaults to format-specific location)").option("-n, --name <name>", 'Custom output filename (without extension, e.g., "my-rule")').option("--hook-mapping <strategy>", "Hook mapping strategy: auto (default), strict, skip", "auto").option("-y, --yes", "Skip confirmation prompts").action(async (source, options) => {
21674
22888
  try {
21675
22889
  if (!options.to) {
21676
22890
  throw new CLIError("Target format is required. Use --to <format>");
@@ -21680,7 +22894,16 @@ function createConvertCommand() {
21680
22894
  throw new CLIError(
21681
22895
  `Invalid format: ${options.to}
21682
22896
 
21683
- Valid formats: ${validFormats.join(", ")}`
22897
+ Valid formats: ${validFormats.join(", ")}
22898
+
22899
+ \u{1F4A1} For Cursor hooks, use: --to cursor --subtype hook`
22900
+ );
22901
+ }
22902
+ if (options.hookMapping && !isValidHookMappingStrategy(options.hookMapping)) {
22903
+ throw new CLIError(
22904
+ `Invalid hook mapping strategy: ${options.hookMapping}
22905
+
22906
+ Valid strategies: ${VALID_HOOK_MAPPING_STRATEGIES.join(", ")}`
21684
22907
  );
21685
22908
  }
21686
22909
  const validSubtypes = ["agent", "skill", "slash-command", "rule", "prompt", "workflow", "tool", "template", "collection", "chatmode", "hook"];
@@ -21696,7 +22919,8 @@ Valid subtypes: ${validSubtypes.join(", ")}`
21696
22919
  subtype: options.subtype,
21697
22920
  output: options.output,
21698
22921
  name: options.name,
21699
- yes: options.yes
22922
+ yes: options.yes,
22923
+ hookMapping: options.hookMapping
21700
22924
  });
21701
22925
  } catch (error) {
21702
22926
  if (error instanceof CLIError) {
@@ -21711,8 +22935,8 @@ Valid subtypes: ${validSubtypes.join(", ")}`
21711
22935
  // src/commands/export.ts
21712
22936
  init_cjs_shims();
21713
22937
  var import_commander28 = require("commander");
21714
- var import_fs17 = require("fs");
21715
- var import_path21 = require("path");
22938
+ var import_fs18 = require("fs");
22939
+ var import_path22 = require("path");
21716
22940
  var import_chalk3 = __toESM(require_source());
21717
22941
  init_errors();
21718
22942
  init_lockfile();
@@ -21728,17 +22952,17 @@ async function exportToRuler(options) {
21728
22952
  }
21729
22953
  console.log(import_chalk3.default.green(`\u2713 Found ${packages.length} installed package${packages.length === 1 ? "" : "s"}`));
21730
22954
  console.log();
21731
- const outputDir = options.output || (0, import_path21.join)(process.cwd(), ".ruler");
22955
+ const outputDir = options.output || (0, import_path22.join)(process.cwd(), ".ruler");
21732
22956
  let rulerExists = false;
21733
22957
  try {
21734
- await import_fs17.promises.access(outputDir);
22958
+ await import_fs18.promises.access(outputDir);
21735
22959
  rulerExists = true;
21736
22960
  } catch {
21737
22961
  }
21738
22962
  if (!rulerExists) {
21739
22963
  console.log(import_chalk3.default.yellow(`\u26A0 ${outputDir} directory not found`));
21740
22964
  console.log(import_chalk3.default.dim("Creating .ruler directory..."));
21741
- await import_fs17.promises.mkdir(outputDir, { recursive: true });
22965
+ await import_fs18.promises.mkdir(outputDir, { recursive: true });
21742
22966
  console.log(import_chalk3.default.green(`\u2713 Created ${outputDir}/`));
21743
22967
  console.log();
21744
22968
  }
@@ -21752,11 +22976,11 @@ async function exportToRuler(options) {
21752
22976
  continue;
21753
22977
  }
21754
22978
  try {
21755
- const content = await import_fs17.promises.readFile(pkg.installedPath, "utf-8");
22979
+ const content = await import_fs18.promises.readFile(pkg.installedPath, "utf-8");
21756
22980
  const rulerContent = createRulerFormat(pkg.id, pkg.version, content, pkg.format, pkg.subtype);
21757
22981
  const rulerFilename = `${packageName}.md`;
21758
- const rulerPath = (0, import_path21.join)(outputDir, rulerFilename);
21759
- await import_fs17.promises.writeFile(rulerPath, rulerContent, "utf-8");
22982
+ const rulerPath = (0, import_path22.join)(outputDir, rulerFilename);
22983
+ await import_fs18.promises.writeFile(rulerPath, rulerContent, "utf-8");
21760
22984
  console.log(import_chalk3.default.green(`\u2713 Exported ${pkg.id} \u2192 ${rulerFilename}`));
21761
22985
  exportedCount++;
21762
22986
  } catch (error) {
@@ -21795,9 +23019,9 @@ function createRulerFormat(packageId, version, content, format, subtype) {
21795
23019
  return frontmatter + contentWithoutFrontmatter;
21796
23020
  }
21797
23021
  async function ensureRulerConfig(rulerDir) {
21798
- const configPath = (0, import_path21.join)((0, import_path21.dirname)(rulerDir), "ruler.toml");
23022
+ const configPath = (0, import_path22.join)((0, import_path22.dirname)(rulerDir), "ruler.toml");
21799
23023
  try {
21800
- await import_fs17.promises.access(configPath);
23024
+ await import_fs18.promises.access(configPath);
21801
23025
  console.log(import_chalk3.default.dim("\u2139 ruler.toml already exists (not modified)"));
21802
23026
  } catch {
21803
23027
  const basicConfig = `# Ruler Configuration
@@ -21823,7 +23047,7 @@ async function ensureRulerConfig(rulerDir) {
21823
23047
  # [agents.github-copilot]
21824
23048
  # enabled = false
21825
23049
  `;
21826
- await import_fs17.promises.writeFile(configPath, basicConfig, "utf-8");
23050
+ await import_fs18.promises.writeFile(configPath, basicConfig, "utf-8");
21827
23051
  console.log(import_chalk3.default.green(`\u2713 Created ruler.toml configuration template`));
21828
23052
  }
21829
23053
  }
@@ -21893,8 +23117,8 @@ init_telemetry();
21893
23117
  init_errors();
21894
23118
  function getVersion() {
21895
23119
  try {
21896
- const packageJsonPath = (0, import_path22.join)(__dirname, "../package.json");
21897
- const packageJson = JSON.parse((0, import_fs18.readFileSync)(packageJsonPath, "utf-8"));
23120
+ const packageJsonPath = (0, import_path23.join)(__dirname, "../package.json");
23121
+ const packageJson = JSON.parse((0, import_fs19.readFileSync)(packageJsonPath, "utf-8"));
21898
23122
  return packageJson.version || "0.0.0";
21899
23123
  } catch {
21900
23124
  return "0.0.0";