@massa-ai/opencode-plugin 1.61.0 → 1.62.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/agent-profiles/{open_models/massa-ai-builder.md → balanced/builder.md} +2 -3
  2. package/agent-profiles/balanced/code-explorer.md +103 -0
  3. package/agent-profiles/balanced/code-reviewer.md +135 -0
  4. package/agent-profiles/balanced/{massa-ai-designer.md → designer.md} +33 -16
  5. package/agent-profiles/balanced/judge.md +149 -0
  6. package/agent-profiles/balanced/product-manager.md +109 -0
  7. package/agent-profiles/balanced/test-engineer.md +102 -0
  8. package/agent-profiles/cheap/{massa-ai-builder.md → builder.md} +2 -3
  9. package/agent-profiles/cheap/code-explorer.md +103 -0
  10. package/agent-profiles/cheap/code-reviewer.md +135 -0
  11. package/agent-profiles/cheap/{massa-ai-designer.md → designer.md} +33 -16
  12. package/agent-profiles/cheap/judge.md +149 -0
  13. package/agent-profiles/cheap/product-manager.md +109 -0
  14. package/agent-profiles/cheap/test-engineer.md +102 -0
  15. package/agent-profiles/heavy/{massa-ai-builder.md → builder.md} +2 -3
  16. package/agent-profiles/heavy/code-explorer.md +103 -0
  17. package/agent-profiles/heavy/code-reviewer.md +135 -0
  18. package/agent-profiles/heavy/{massa-ai-designer.md → designer.md} +33 -16
  19. package/agent-profiles/heavy/judge.md +149 -0
  20. package/agent-profiles/heavy/product-manager.md +109 -0
  21. package/agent-profiles/heavy/test-engineer.md +102 -0
  22. package/agent-profiles/home/{massa-ai-builder.md → builder.md} +2 -3
  23. package/agent-profiles/home/code-explorer.md +103 -0
  24. package/agent-profiles/home/code-reviewer.md +135 -0
  25. package/agent-profiles/{open_models/massa-ai-designer.md → home/designer.md} +33 -16
  26. package/agent-profiles/home/judge.md +149 -0
  27. package/agent-profiles/home/product-manager.md +109 -0
  28. package/agent-profiles/home/test-engineer.md +102 -0
  29. package/agent-profiles/local_models/{massa-ai-builder.md → builder.md} +2 -3
  30. package/agent-profiles/local_models/code-explorer.md +103 -0
  31. package/agent-profiles/local_models/code-reviewer.md +135 -0
  32. package/agent-profiles/local_models/{massa-ai-designer.md → designer.md} +33 -16
  33. package/agent-profiles/local_models/judge.md +149 -0
  34. package/agent-profiles/local_models/product-manager.md +109 -0
  35. package/agent-profiles/local_models/test-engineer.md +102 -0
  36. package/agent-profiles/{balanced/massa-ai-builder.md → open_models/builder.md} +2 -3
  37. package/agent-profiles/open_models/code-explorer.md +103 -0
  38. package/agent-profiles/open_models/code-reviewer.md +135 -0
  39. package/agent-profiles/{home/massa-ai-designer.md → open_models/designer.md} +33 -16
  40. package/agent-profiles/open_models/judge.md +149 -0
  41. package/agent-profiles/open_models/product-manager.md +109 -0
  42. package/agent-profiles/open_models/test-engineer.md +102 -0
  43. package/agent-profiles/work/{massa-ai-builder.md → builder.md} +2 -3
  44. package/agent-profiles/work/code-explorer.md +103 -0
  45. package/agent-profiles/work/code-reviewer.md +135 -0
  46. package/agent-profiles/work/{massa-ai-designer.md → designer.md} +33 -16
  47. package/agent-profiles/work/judge.md +149 -0
  48. package/agent-profiles/work/product-manager.md +109 -0
  49. package/agent-profiles/work/test-engineer.md +102 -0
  50. package/agents/{massa-ai-builder.md → builder.md} +2 -3
  51. package/agents/code-explorer.md +103 -0
  52. package/agents/code-reviewer.md +135 -0
  53. package/agents/{massa-ai-designer.md → designer.md} +33 -16
  54. package/agents/judge.md +149 -0
  55. package/agents/product-manager.md +109 -0
  56. package/agents/test-engineer.md +102 -0
  57. package/command/{massa-ai-adr.md → massa-ai-create-adr.md} +3 -3
  58. package/command/{massa-ai-to-prd.md → massa-ai-create-prd.md} +3 -3
  59. package/command/{massa-ai-rfc.md → massa-ai-create-rfc.md} +3 -3
  60. package/command/{massa-ai-tdd.md → massa-ai-create-tdd.md} +3 -3
  61. package/command/{massa-ai-ticket.md → massa-ai-create-ticket.md} +3 -3
  62. package/command/massa-ai-product-discovery.md +13 -0
  63. package/dist/config-cli.js +221 -132
  64. package/package.json +3 -3
  65. package/agent-profiles/balanced/massa-ai-architecture-specialist.md +0 -64
  66. package/agent-profiles/balanced/massa-ai-audit-specialist.md +0 -81
  67. package/agent-profiles/balanced/massa-ai-context-curator.md +0 -66
  68. package/agent-profiles/balanced/massa-ai-documentation-agent.md +0 -64
  69. package/agent-profiles/balanced/massa-ai-furps-analyst.md +0 -70
  70. package/agent-profiles/balanced/massa-ai-investigator.md +0 -67
  71. package/agent-profiles/balanced/massa-ai-judge.md +0 -98
  72. package/agent-profiles/balanced/massa-ai-meta-judge.md +0 -86
  73. package/agent-profiles/balanced/massa-ai-mobile-specialist.md +0 -81
  74. package/agent-profiles/balanced/massa-ai-navigator.md +0 -74
  75. package/agent-profiles/balanced/massa-ai-plan-critic.md +0 -89
  76. package/agent-profiles/balanced/massa-ai-planner.md +0 -64
  77. package/agent-profiles/balanced/massa-ai-requirements-analyst.md +0 -63
  78. package/agent-profiles/balanced/massa-ai-reviewer.md +0 -65
  79. package/agent-profiles/balanced/massa-ai-test-engineer.md +0 -66
  80. package/agent-profiles/balanced/massa-ai-verification-agent.md +0 -64
  81. package/agent-profiles/cheap/massa-ai-architecture-specialist.md +0 -64
  82. package/agent-profiles/cheap/massa-ai-audit-specialist.md +0 -81
  83. package/agent-profiles/cheap/massa-ai-context-curator.md +0 -66
  84. package/agent-profiles/cheap/massa-ai-documentation-agent.md +0 -64
  85. package/agent-profiles/cheap/massa-ai-furps-analyst.md +0 -70
  86. package/agent-profiles/cheap/massa-ai-investigator.md +0 -67
  87. package/agent-profiles/cheap/massa-ai-judge.md +0 -98
  88. package/agent-profiles/cheap/massa-ai-meta-judge.md +0 -86
  89. package/agent-profiles/cheap/massa-ai-mobile-specialist.md +0 -81
  90. package/agent-profiles/cheap/massa-ai-navigator.md +0 -74
  91. package/agent-profiles/cheap/massa-ai-plan-critic.md +0 -89
  92. package/agent-profiles/cheap/massa-ai-planner.md +0 -64
  93. package/agent-profiles/cheap/massa-ai-requirements-analyst.md +0 -63
  94. package/agent-profiles/cheap/massa-ai-reviewer.md +0 -65
  95. package/agent-profiles/cheap/massa-ai-test-engineer.md +0 -66
  96. package/agent-profiles/cheap/massa-ai-verification-agent.md +0 -64
  97. package/agent-profiles/heavy/massa-ai-architecture-specialist.md +0 -64
  98. package/agent-profiles/heavy/massa-ai-audit-specialist.md +0 -81
  99. package/agent-profiles/heavy/massa-ai-context-curator.md +0 -66
  100. package/agent-profiles/heavy/massa-ai-documentation-agent.md +0 -64
  101. package/agent-profiles/heavy/massa-ai-furps-analyst.md +0 -70
  102. package/agent-profiles/heavy/massa-ai-investigator.md +0 -67
  103. package/agent-profiles/heavy/massa-ai-judge.md +0 -98
  104. package/agent-profiles/heavy/massa-ai-meta-judge.md +0 -86
  105. package/agent-profiles/heavy/massa-ai-mobile-specialist.md +0 -81
  106. package/agent-profiles/heavy/massa-ai-navigator.md +0 -74
  107. package/agent-profiles/heavy/massa-ai-plan-critic.md +0 -89
  108. package/agent-profiles/heavy/massa-ai-planner.md +0 -64
  109. package/agent-profiles/heavy/massa-ai-requirements-analyst.md +0 -63
  110. package/agent-profiles/heavy/massa-ai-reviewer.md +0 -65
  111. package/agent-profiles/heavy/massa-ai-test-engineer.md +0 -66
  112. package/agent-profiles/heavy/massa-ai-verification-agent.md +0 -64
  113. package/agent-profiles/home/massa-ai-architecture-specialist.md +0 -64
  114. package/agent-profiles/home/massa-ai-audit-specialist.md +0 -81
  115. package/agent-profiles/home/massa-ai-context-curator.md +0 -66
  116. package/agent-profiles/home/massa-ai-documentation-agent.md +0 -64
  117. package/agent-profiles/home/massa-ai-furps-analyst.md +0 -70
  118. package/agent-profiles/home/massa-ai-investigator.md +0 -67
  119. package/agent-profiles/home/massa-ai-judge.md +0 -98
  120. package/agent-profiles/home/massa-ai-meta-judge.md +0 -86
  121. package/agent-profiles/home/massa-ai-mobile-specialist.md +0 -81
  122. package/agent-profiles/home/massa-ai-navigator.md +0 -74
  123. package/agent-profiles/home/massa-ai-plan-critic.md +0 -89
  124. package/agent-profiles/home/massa-ai-planner.md +0 -64
  125. package/agent-profiles/home/massa-ai-requirements-analyst.md +0 -63
  126. package/agent-profiles/home/massa-ai-reviewer.md +0 -65
  127. package/agent-profiles/home/massa-ai-test-engineer.md +0 -66
  128. package/agent-profiles/home/massa-ai-verification-agent.md +0 -64
  129. package/agent-profiles/local_models/massa-ai-architecture-specialist.md +0 -64
  130. package/agent-profiles/local_models/massa-ai-audit-specialist.md +0 -81
  131. package/agent-profiles/local_models/massa-ai-context-curator.md +0 -66
  132. package/agent-profiles/local_models/massa-ai-documentation-agent.md +0 -64
  133. package/agent-profiles/local_models/massa-ai-furps-analyst.md +0 -70
  134. package/agent-profiles/local_models/massa-ai-investigator.md +0 -67
  135. package/agent-profiles/local_models/massa-ai-judge.md +0 -98
  136. package/agent-profiles/local_models/massa-ai-meta-judge.md +0 -86
  137. package/agent-profiles/local_models/massa-ai-mobile-specialist.md +0 -81
  138. package/agent-profiles/local_models/massa-ai-navigator.md +0 -74
  139. package/agent-profiles/local_models/massa-ai-plan-critic.md +0 -89
  140. package/agent-profiles/local_models/massa-ai-planner.md +0 -64
  141. package/agent-profiles/local_models/massa-ai-requirements-analyst.md +0 -63
  142. package/agent-profiles/local_models/massa-ai-reviewer.md +0 -65
  143. package/agent-profiles/local_models/massa-ai-test-engineer.md +0 -66
  144. package/agent-profiles/local_models/massa-ai-verification-agent.md +0 -64
  145. package/agent-profiles/open_models/massa-ai-architecture-specialist.md +0 -64
  146. package/agent-profiles/open_models/massa-ai-audit-specialist.md +0 -81
  147. package/agent-profiles/open_models/massa-ai-context-curator.md +0 -66
  148. package/agent-profiles/open_models/massa-ai-documentation-agent.md +0 -64
  149. package/agent-profiles/open_models/massa-ai-furps-analyst.md +0 -70
  150. package/agent-profiles/open_models/massa-ai-investigator.md +0 -67
  151. package/agent-profiles/open_models/massa-ai-judge.md +0 -98
  152. package/agent-profiles/open_models/massa-ai-meta-judge.md +0 -86
  153. package/agent-profiles/open_models/massa-ai-mobile-specialist.md +0 -81
  154. package/agent-profiles/open_models/massa-ai-navigator.md +0 -74
  155. package/agent-profiles/open_models/massa-ai-plan-critic.md +0 -89
  156. package/agent-profiles/open_models/massa-ai-planner.md +0 -64
  157. package/agent-profiles/open_models/massa-ai-requirements-analyst.md +0 -63
  158. package/agent-profiles/open_models/massa-ai-reviewer.md +0 -65
  159. package/agent-profiles/open_models/massa-ai-test-engineer.md +0 -66
  160. package/agent-profiles/open_models/massa-ai-verification-agent.md +0 -64
  161. package/agent-profiles/work/massa-ai-architecture-specialist.md +0 -64
  162. package/agent-profiles/work/massa-ai-audit-specialist.md +0 -81
  163. package/agent-profiles/work/massa-ai-context-curator.md +0 -66
  164. package/agent-profiles/work/massa-ai-documentation-agent.md +0 -64
  165. package/agent-profiles/work/massa-ai-furps-analyst.md +0 -70
  166. package/agent-profiles/work/massa-ai-investigator.md +0 -67
  167. package/agent-profiles/work/massa-ai-judge.md +0 -98
  168. package/agent-profiles/work/massa-ai-meta-judge.md +0 -86
  169. package/agent-profiles/work/massa-ai-mobile-specialist.md +0 -81
  170. package/agent-profiles/work/massa-ai-navigator.md +0 -74
  171. package/agent-profiles/work/massa-ai-plan-critic.md +0 -89
  172. package/agent-profiles/work/massa-ai-planner.md +0 -64
  173. package/agent-profiles/work/massa-ai-requirements-analyst.md +0 -63
  174. package/agent-profiles/work/massa-ai-reviewer.md +0 -65
  175. package/agent-profiles/work/massa-ai-test-engineer.md +0 -66
  176. package/agent-profiles/work/massa-ai-verification-agent.md +0 -64
  177. package/agents/massa-ai-architecture-specialist.md +0 -64
  178. package/agents/massa-ai-audit-specialist.md +0 -81
  179. package/agents/massa-ai-context-curator.md +0 -66
  180. package/agents/massa-ai-documentation-agent.md +0 -64
  181. package/agents/massa-ai-furps-analyst.md +0 -70
  182. package/agents/massa-ai-investigator.md +0 -67
  183. package/agents/massa-ai-judge.md +0 -98
  184. package/agents/massa-ai-meta-judge.md +0 -86
  185. package/agents/massa-ai-mobile-specialist.md +0 -81
  186. package/agents/massa-ai-navigator.md +0 -74
  187. package/agents/massa-ai-plan-critic.md +0 -89
  188. package/agents/massa-ai-planner.md +0 -64
  189. package/agents/massa-ai-requirements-analyst.md +0 -63
  190. package/agents/massa-ai-reviewer.md +0 -65
  191. package/agents/massa-ai-test-engineer.md +0 -66
  192. package/agents/massa-ai-verification-agent.md +0 -64
  193. package/command/massa-ai-discovery.md +0 -13
  194. package/command/massa-ai-general.md +0 -13
  195. package/command/massa-ai-maestro-audit.md +0 -13
  196. package/command/massa-ai-maestro-fix.md +0 -13
  197. package/command/massa-ai-maestro.md +0 -13
@@ -2193,12 +2193,12 @@ function isHost(v) {
2193
2193
  return typeof v === "string" && HOSTS.includes(v);
2194
2194
  }
2195
2195
  var CURSOR_SKIP_REASON = "all tiers inherit \u2014 Cursor publishes no resolvable model IDs";
2196
- function fileLayout(host, activeDir, activeGlob, variantsRoot) {
2196
+ function fileLayout(host, activeDir, activeExt, variantsRoot) {
2197
2197
  return {
2198
2198
  host,
2199
2199
  route: "files",
2200
2200
  activeDir,
2201
- activeGlob,
2201
+ activeExt,
2202
2202
  variantsRoot,
2203
2203
  variantDir: (profile) => path6.join(variantsRoot, profile)
2204
2204
  };
@@ -2212,19 +2212,19 @@ function resolveHostLayout(host, opts = {}) {
2212
2212
  case "claude": {
2213
2213
  const marketplaceRoot = opts.marketplaceRoot?.claude;
2214
2214
  if (override === undefined && marketplaceRoot !== undefined) {
2215
- return fileLayout(host, path6.join(marketplaceRoot, "agents"), "massa-ai-*.md", path6.join(marketplaceRoot, "agent-profiles"));
2215
+ return fileLayout(host, path6.join(marketplaceRoot, "agents"), ".md", path6.join(marketplaceRoot, "agent-profiles"));
2216
2216
  }
2217
2217
  const root = override ?? path6.join(targetHome, ".claude");
2218
- return fileLayout(host, path6.join(root, "agents"), "massa-ai-*.md", path6.join(root, "massa-ai", "agent-profiles"));
2218
+ return fileLayout(host, path6.join(root, "agents"), ".md", path6.join(root, "massa-ai", "agent-profiles"));
2219
2219
  }
2220
2220
  case "codex": {
2221
2221
  const root = override ?? path6.join(targetHome, ".codex");
2222
- return fileLayout(host, path6.join(root, "agents"), "massa-ai-*.toml", path6.join(root, "massa-ai", "agent-profiles"));
2222
+ return fileLayout(host, path6.join(root, "agents"), ".toml", path6.join(root, "massa-ai", "agent-profiles"));
2223
2223
  }
2224
2224
  case "opencode": {
2225
2225
  const root = override ?? path6.join(targetHome, ".config", "opencode");
2226
2226
  const pluginsDir = path6.join(root, "plugins", "massa-ai");
2227
- return fileLayout(host, path6.join(root, "agents"), "massa-ai-*.md", path6.join(pluginsDir, "agent-profiles"));
2227
+ return fileLayout(host, path6.join(root, "agents"), ".md", path6.join(pluginsDir, "agent-profiles"));
2228
2228
  }
2229
2229
  }
2230
2230
  }
@@ -2427,8 +2427,8 @@ function acquireLock(stateFilePath, options = {}) {
2427
2427
  }
2428
2428
  }
2429
2429
  // ../../packages/shared/dist/profile-switch/engine.js
2430
- import fs7 from "fs";
2431
- import path11 from "path";
2430
+ import fs8 from "fs";
2431
+ import path12 from "path";
2432
2432
  import os7 from "os";
2433
2433
  import crypto3 from "crypto";
2434
2434
  import { execFileSync as execFileSync2 } from "child_process";
@@ -2558,10 +2558,93 @@ function readInstalledPluginVersion(opts = {}) {
2558
2558
  return selectRecord(records)?.version ?? null;
2559
2559
  }
2560
2560
 
2561
- // ../../packages/shared/dist/profile-switch/doctor.js
2561
+ // ../../packages/shared/dist/profile-switch/ownership.js
2562
2562
  import fs6 from "fs";
2563
- import os6 from "os";
2564
2563
  import path10 from "path";
2564
+ var OWNED_MARKER_MD = "<!-- massa-ai-owned: true -->";
2565
+ var OWNED_MARKER_TOML = "# massa-ai-owned";
2566
+ var LEGACY_AGENT_NAMES = [
2567
+ "architecture-specialist",
2568
+ "audit-specialist",
2569
+ "builder",
2570
+ "context-curator",
2571
+ "designer",
2572
+ "documentation-agent",
2573
+ "furps-analyst",
2574
+ "investigator",
2575
+ "judge",
2576
+ "meta-judge",
2577
+ "mobile-specialist",
2578
+ "navigator",
2579
+ "plan-critic",
2580
+ "planner",
2581
+ "requirements-analyst",
2582
+ "reviewer",
2583
+ "test-engineer",
2584
+ "verification-agent"
2585
+ ];
2586
+ function isLegacyAgentName(fileName) {
2587
+ const base = path10.basename(fileName).replace(/\.[^.]*$/, "");
2588
+ return base.startsWith("massa-ai-") && LEGACY_AGENT_NAMES.includes(base.slice("massa-ai-".length));
2589
+ }
2590
+ function hasOwnedMarker(content) {
2591
+ const lines = content.split(`
2592
+ `);
2593
+ if (lines[0] !== "---")
2594
+ return false;
2595
+ const close = lines.indexOf("---", 1);
2596
+ return close !== -1 && lines[close + 1] === OWNED_MARKER_MD;
2597
+ }
2598
+ function isRegularFile(filePath) {
2599
+ try {
2600
+ return fs6.lstatSync(filePath).isFile();
2601
+ } catch {
2602
+ return false;
2603
+ }
2604
+ }
2605
+ function isOwnedAgentFile(filePath) {
2606
+ if (!isRegularFile(filePath))
2607
+ return false;
2608
+ if (!filePath.endsWith(".toml") && isLegacyAgentName(filePath))
2609
+ return true;
2610
+ let content;
2611
+ try {
2612
+ content = fs6.readFileSync(filePath, "utf8");
2613
+ } catch {
2614
+ return false;
2615
+ }
2616
+ if (filePath.endsWith(".toml"))
2617
+ return content.split(`
2618
+ `)[0] === OWNED_MARKER_TOML;
2619
+ return hasOwnedMarker(content);
2620
+ }
2621
+ function isOwnedAgentLink(linkPath) {
2622
+ try {
2623
+ if (!fs6.lstatSync(linkPath).isSymbolicLink())
2624
+ return false;
2625
+ } catch {
2626
+ return false;
2627
+ }
2628
+ if (isLegacyAgentName(linkPath))
2629
+ return true;
2630
+ const base = path10.basename(linkPath);
2631
+ const target = fs6.readlinkSync(linkPath);
2632
+ if (target.endsWith(`/opencode-plugin/agents/${base}`))
2633
+ return true;
2634
+ const escaped = base.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2635
+ if (new RegExp(`/plugins/massa-ai/agent-profiles/.*/${escaped}$`).test(target))
2636
+ return true;
2637
+ try {
2638
+ return fs6.statSync(linkPath).isFile() && hasOwnedMarker(fs6.readFileSync(linkPath, "utf8"));
2639
+ } catch {
2640
+ return false;
2641
+ }
2642
+ }
2643
+
2644
+ // ../../packages/shared/dist/profile-switch/doctor.js
2645
+ import fs7 from "fs";
2646
+ import os6 from "os";
2647
+ import path11 from "path";
2565
2648
 
2566
2649
  // ../../packages/shared/dist/profile-switch/frontmatter.js
2567
2650
  function parseFrontmatter(raw) {
@@ -2623,7 +2706,7 @@ function unquoteScalar(s) {
2623
2706
  var ENV_OVERRIDE_VARS = ["CLAUDE_CODE_SUBAGENT_MODEL"];
2624
2707
  function readTextFile(filePath) {
2625
2708
  try {
2626
- return fs6.readFileSync(filePath, "utf8");
2709
+ return fs7.readFileSync(filePath, "utf8");
2627
2710
  } catch {
2628
2711
  return null;
2629
2712
  }
@@ -2639,7 +2722,7 @@ function readJsonFile(filePath) {
2639
2722
  }
2640
2723
  }
2641
2724
  function readPluginVersion(pluginRoot) {
2642
- const manifest = readJsonFile(path10.join(pluginRoot, ".claude-plugin", "plugin.json"));
2725
+ const manifest = readJsonFile(path11.join(pluginRoot, ".claude-plugin", "plugin.json"));
2643
2726
  return typeof manifest?.version === "string" ? manifest.version : null;
2644
2727
  }
2645
2728
  function detectEnvOverride(env) {
@@ -2652,19 +2735,19 @@ function detectEnvOverride(env) {
2652
2735
  return null;
2653
2736
  }
2654
2737
  function readRoles(liveRoot, activeProfile) {
2655
- const agentsDir = path10.join(liveRoot, "agents");
2738
+ const agentsDir = path11.join(liveRoot, "agents");
2656
2739
  let entries;
2657
2740
  try {
2658
- entries = fs6.readdirSync(agentsDir, { withFileTypes: true });
2741
+ entries = fs7.readdirSync(agentsDir, { withFileTypes: true });
2659
2742
  } catch {
2660
2743
  return [];
2661
2744
  }
2662
2745
  const roles = [];
2663
2746
  for (const entry of entries) {
2664
- if (!entry.isFile() || !entry.name.startsWith("massa-ai-") || !entry.name.endsWith(".md")) {
2747
+ if (!entry.name.endsWith(".md") || !isOwnedAgentFile(path11.join(agentsDir, entry.name))) {
2665
2748
  continue;
2666
2749
  }
2667
- const activeRaw = readTextFile(path10.join(agentsDir, entry.name));
2750
+ const activeRaw = readTextFile(path11.join(agentsDir, entry.name));
2668
2751
  let model = null;
2669
2752
  let effort = null;
2670
2753
  if (activeRaw !== null) {
@@ -2676,7 +2759,7 @@ function readRoles(liveRoot, activeProfile) {
2676
2759
  }
2677
2760
  let staleVariant = false;
2678
2761
  if (activeProfile && activeRaw !== null) {
2679
- const variantRaw = readTextFile(path10.join(liveRoot, "agent-profiles", activeProfile, entry.name));
2762
+ const variantRaw = readTextFile(path11.join(liveRoot, "agent-profiles", activeProfile, entry.name));
2680
2763
  if (variantRaw !== null) {
2681
2764
  staleVariant = variantRaw !== activeRaw;
2682
2765
  }
@@ -2688,7 +2771,7 @@ function readRoles(liveRoot, activeProfile) {
2688
2771
  function runtimeDriftReport(opts = {}) {
2689
2772
  const targetHome = opts.targetHome ?? os6.homedir();
2690
2773
  const host = opts.host ?? "claude";
2691
- const stateFilePath = opts.stateFilePath ?? path10.join(targetHome, ".config", "massa-ai", "install-state.json");
2774
+ const stateFilePath = opts.stateFilePath ?? path11.join(targetHome, ".config", "massa-ai", "install-state.json");
2692
2775
  let state = opts.state ?? null;
2693
2776
  if (state === null) {
2694
2777
  try {
@@ -2750,7 +2833,7 @@ function namedError3(name, message) {
2750
2833
  var UnknownProfileError = (profile, known) => namedError3("UnknownProfileError", `unknown profile "${profile}" \u2014 installed: ${known.length > 0 ? known.join(", ") : "none"}`);
2751
2834
  var NoHostsDetectedError = () => namedError3("NoHostsDetectedError", "no installed hosts found");
2752
2835
  function defaultStatePath(targetHome) {
2753
- return path11.join(targetHome, ".config", "massa-ai", "install-state.json");
2836
+ return path12.join(targetHome, ".config", "massa-ai", "install-state.json");
2754
2837
  }
2755
2838
  function resolveCommon(opts) {
2756
2839
  const targetHome = opts.targetHome ?? os7.homedir();
@@ -2761,7 +2844,7 @@ function marketplaceRoots(targetHome, state) {
2761
2844
  return state.platforms.claude?.installRoute === "marketplace" ? { claude: resolveClaudeMarketplaceRoot({ targetHome }) ?? undefined } : {};
2762
2845
  }
2763
2846
  function claudeMarketplaceUnresolvedReason(targetHome) {
2764
- const registryPath = path11.join(targetHome, ".claude", "plugins", "installed_plugins.json");
2847
+ const registryPath = path12.join(targetHome, ".claude", "plugins", "installed_plugins.json");
2765
2848
  return `claude installRoute is "marketplace" but no install root could be resolved from ${registryPath} ` + "\u2014 re-run the Claude plugin installer, or verify the plugin registry file";
2766
2849
  }
2767
2850
  function listProfiles(opts = {}) {
@@ -2802,7 +2885,7 @@ function listProfiles(opts = {}) {
2802
2885
  ...claudeDriftFields(host)
2803
2886
  };
2804
2887
  }
2805
- const installed = fs7.existsSync(layout.activeDir);
2888
+ const installed = fs8.existsSync(layout.activeDir);
2806
2889
  const availableProfiles = listVariantProfiles(layout);
2807
2890
  const platform = state.platforms[host];
2808
2891
  return {
@@ -2819,20 +2902,20 @@ function listProfiles(opts = {}) {
2819
2902
  return { hosts };
2820
2903
  }
2821
2904
  function listVariantProfiles(layout) {
2822
- if (!fs7.existsSync(layout.variantsRoot))
2905
+ if (!fs8.existsSync(layout.variantsRoot))
2823
2906
  return [];
2824
- return fs7.readdirSync(layout.variantsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
2907
+ return fs8.readdirSync(layout.variantsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
2825
2908
  }
2826
- function matchesGlob(filename, glob) {
2827
- const starIdx = glob.indexOf("*");
2828
- if (starIdx === -1)
2829
- return filename === glob;
2830
- const prefix = glob.slice(0, starIdx);
2831
- const suffix = glob.slice(starIdx + 1);
2832
- return filename.length >= prefix.length + suffix.length && filename.startsWith(prefix) && filename.endsWith(suffix);
2909
+ function matchingFileNames(dir, ext) {
2910
+ return fs8.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(ext) && !isLegacyAgentName(e.name) && isOwnedAgentFile(path12.join(dir, e.name))).map((e) => e.name);
2833
2911
  }
2834
- function matchingFileNames(dir, glob) {
2835
- return fs7.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && matchesGlob(e.name, glob)).map((e) => e.name);
2912
+ function destIsAbsent(dest) {
2913
+ try {
2914
+ fs8.lstatSync(dest);
2915
+ return false;
2916
+ } catch {
2917
+ return true;
2918
+ }
2836
2919
  }
2837
2920
  function detectGitAvailability(dir) {
2838
2921
  try {
@@ -2860,7 +2943,7 @@ function gitTrackedFileNames(dir, filenames) {
2860
2943
  var GUARD_PASS = { blocked: false, unchecked: false };
2861
2944
  var GUARD_UNCHECKED = { blocked: false, unchecked: true };
2862
2945
  function checkTrackedPathGuard(activeDir, filenames) {
2863
- if (filenames.length === 0 || !fs7.existsSync(activeDir))
2946
+ if (filenames.length === 0 || !fs8.existsSync(activeDir))
2864
2947
  return GUARD_PASS;
2865
2948
  const availability = detectGitAvailability(activeDir);
2866
2949
  if (availability === "no-git")
@@ -2871,53 +2954,45 @@ function checkTrackedPathGuard(activeDir, filenames) {
2871
2954
  if (tracked.size === 0)
2872
2955
  return GUARD_PASS;
2873
2956
  const offending = filenames.find((name) => tracked.has(name));
2874
- return { blocked: true, path: path11.join(activeDir, offending), unchecked: false };
2957
+ return { blocked: true, path: path12.join(activeDir, offending), unchecked: false };
2875
2958
  }
2876
2959
  function assertStateWritable(stateFilePath) {
2877
- const dir = path11.dirname(stateFilePath);
2960
+ const dir = path12.dirname(stateFilePath);
2878
2961
  try {
2879
- fs7.mkdirSync(dir, { recursive: true });
2962
+ fs8.mkdirSync(dir, { recursive: true });
2880
2963
  } catch (err) {
2881
2964
  throw UnwritableInstallStateError(stateFilePath, err.message);
2882
2965
  }
2883
- const checkPath = fs7.existsSync(stateFilePath) ? stateFilePath : dir;
2966
+ const checkPath = fs8.existsSync(stateFilePath) ? stateFilePath : dir;
2884
2967
  try {
2885
- fs7.accessSync(checkPath, fs7.constants.W_OK);
2968
+ fs8.accessSync(checkPath, fs8.constants.W_OK);
2886
2969
  } catch (err) {
2887
2970
  throw UnwritableInstallStateError(stateFilePath, err.message);
2888
2971
  }
2889
2972
  }
2890
2973
  function copyFileRouteVariant(layout, variantDir) {
2891
- fs7.mkdirSync(layout.activeDir, { recursive: true });
2974
+ fs8.mkdirSync(layout.activeDir, { recursive: true });
2892
2975
  let changed = 0;
2893
- for (const entry of fs7.readdirSync(variantDir, { withFileTypes: true })) {
2894
- if (!entry.isFile() || !matchesGlob(entry.name, layout.activeGlob))
2976
+ for (const name of matchingFileNames(variantDir, layout.activeExt)) {
2977
+ const dest = path12.join(layout.activeDir, name);
2978
+ if (!destIsAbsent(dest) && !isOwnedAgentFile(dest))
2895
2979
  continue;
2896
- fs7.copyFileSync(path11.join(variantDir, entry.name), path11.join(layout.activeDir, entry.name));
2980
+ fs8.copyFileSync(path12.join(variantDir, name), dest);
2897
2981
  changed++;
2898
2982
  }
2899
2983
  return changed;
2900
2984
  }
2901
2985
  function repointOpencodeVariant(layout, variantDir) {
2902
- fs7.mkdirSync(layout.activeDir, { recursive: true });
2986
+ fs8.mkdirSync(layout.activeDir, { recursive: true });
2903
2987
  let changed = 0;
2904
- for (const entry of fs7.readdirSync(variantDir, { withFileTypes: true })) {
2905
- if (!entry.isFile() || !matchesGlob(entry.name, layout.activeGlob))
2906
- continue;
2907
- const dest = path11.join(layout.activeDir, entry.name);
2908
- const target = path11.resolve(path11.join(variantDir, entry.name));
2909
- let destExists = true;
2910
- let destIsSymlink = false;
2911
- try {
2912
- destIsSymlink = fs7.lstatSync(dest).isSymbolicLink();
2913
- } catch {
2914
- destExists = false;
2915
- }
2916
- if (destExists && !destIsSymlink)
2988
+ for (const name of matchingFileNames(variantDir, layout.activeExt)) {
2989
+ const dest = path12.join(layout.activeDir, name);
2990
+ const target = path12.resolve(path12.join(variantDir, name));
2991
+ if (!destIsAbsent(dest) && !isOwnedAgentLink(dest))
2917
2992
  continue;
2918
2993
  const tmp = `${dest}.massa-ai-switch.${crypto3.randomUUID()}`;
2919
- fs7.symlinkSync(target, tmp);
2920
- fs7.renameSync(tmp, dest);
2994
+ fs8.symlinkSync(target, tmp);
2995
+ fs8.renameSync(tmp, dest);
2921
2996
  changed++;
2922
2997
  }
2923
2998
  return changed;
@@ -2957,13 +3032,13 @@ function switchProfile(opts) {
2957
3032
  if (fileHosts.length === 0) {
2958
3033
  return { profile: opts.profile, dryRun, hosts: orderRows(universe, skipRows), restartRequired: false };
2959
3034
  }
2960
- const installedFileHosts = fileHosts.filter((h) => fs7.existsSync(h.layout.activeDir));
3035
+ const installedFileHosts = fileHosts.filter((h) => fs8.existsSync(h.layout.activeDir));
2961
3036
  if (installedFileHosts.length === 0)
2962
3037
  throw NoHostsDetectedError();
2963
3038
  const withAvailability = fileHosts.map((h) => {
2964
- const variantsRootExists = fs7.existsSync(h.layout.variantsRoot);
3039
+ const variantsRootExists = fs8.existsSync(h.layout.variantsRoot);
2965
3040
  const variantDir = h.layout.variantDir(opts.profile);
2966
- const available = variantsRootExists && fs7.existsSync(variantDir) && fs7.statSync(variantDir).isDirectory();
3041
+ const available = variantsRootExists && fs8.existsSync(variantDir) && fs8.statSync(variantDir).isDirectory();
2967
3042
  return { ...h, variantsRootExists, variantDir, available };
2968
3043
  });
2969
3044
  if (!withAvailability.some((h) => h.available)) {
@@ -3002,7 +3077,7 @@ function switchProfile(opts) {
3002
3077
  rows.push({ host: h.host, status: "would-switch" });
3003
3078
  continue;
3004
3079
  }
3005
- const candidateNames = matchingFileNames(h.variantDir, h.layout.activeGlob);
3080
+ const candidateNames = matchingFileNames(h.variantDir, h.layout.activeExt);
3006
3081
  const guard = checkTrackedPathGuard(h.layout.activeDir, candidateNames);
3007
3082
  if (guard.blocked) {
3008
3083
  rows.push({
@@ -3043,12 +3118,12 @@ function reportSucceeded(report) {
3043
3118
  return report.hosts.every((h) => h.status === "switched" || h.status === "would-switch" || h.status === "skipped");
3044
3119
  }
3045
3120
  // ../../packages/shared/dist/profile-switch/variant-sync.js
3046
- import fs8 from "fs";
3047
- import path12 from "path";
3121
+ import fs9 from "fs";
3122
+ import path13 from "path";
3048
3123
  import os8 from "os";
3049
3124
  import crypto4 from "crypto";
3050
3125
  function defaultStatePath2(targetHome) {
3051
- return path12.join(targetHome, ".config", "massa-ai", "install-state.json");
3126
+ return path13.join(targetHome, ".config", "massa-ai", "install-state.json");
3052
3127
  }
3053
3128
  function marketplaceRoots2(targetHome, state) {
3054
3129
  return state.platforms.claude?.installRoute === "marketplace" ? { claude: resolveClaudeMarketplaceRoot({ targetHome }) ?? undefined } : {};
@@ -3056,13 +3131,13 @@ function marketplaceRoots2(targetHome, state) {
3056
3131
  var tempFileCounter2 = 0;
3057
3132
  function writeFileIntoDirAtomically(destDir, destName, content) {
3058
3133
  const unique = `${process.pid}.${++tempFileCounter2}.${crypto4.randomBytes(6).toString("hex")}`;
3059
- const tempFile = path12.join(destDir, `.${destName}.${unique}.tmp`);
3134
+ const tempFile = path13.join(destDir, `.${destName}.${unique}.tmp`);
3060
3135
  try {
3061
- fs8.writeFileSync(tempFile, content);
3062
- fs8.renameSync(tempFile, path12.join(destDir, destName));
3136
+ fs9.writeFileSync(tempFile, content);
3137
+ fs9.renameSync(tempFile, path13.join(destDir, destName));
3063
3138
  } catch (error) {
3064
3139
  try {
3065
- fs8.unlinkSync(tempFile);
3140
+ fs9.unlinkSync(tempFile);
3066
3141
  } catch {}
3067
3142
  throw error;
3068
3143
  }
@@ -3070,20 +3145,20 @@ function writeFileIntoDirAtomically(destDir, destName, content) {
3070
3145
  function isSafeDirName(name) {
3071
3146
  if (name === "." || name === "..")
3072
3147
  return false;
3073
- if (name.includes("/") || name.includes("\\") || name.includes(path12.sep))
3148
+ if (name.includes("/") || name.includes("\\") || name.includes(path13.sep))
3074
3149
  return false;
3075
- return path12.basename(name) === name;
3150
+ return path13.basename(name) === name;
3076
3151
  }
3077
3152
  function syncHost(host, sourceRoot, targetHome, marketplaceRoot) {
3078
3153
  const layout = resolveHostLayout(host, { targetHome, marketplaceRoot });
3079
3154
  if (layout.route === "skip") {
3080
3155
  return { host, status: "skipped", profiles: [], retained: [], files: 0, reason: layout.reason };
3081
3156
  }
3082
- const srcDir = path12.join(sourceRoot, "apps", `${host}-plugin`, "agent-profiles");
3083
- if (!fs8.existsSync(srcDir) || !fs8.statSync(srcDir).isDirectory()) {
3157
+ const srcDir = path13.join(sourceRoot, "apps", `${host}-plugin`, "agent-profiles");
3158
+ if (!fs9.existsSync(srcDir) || !fs9.statSync(srcDir).isDirectory()) {
3084
3159
  return { host, status: "skipped", profiles: [], retained: [], files: 0, reason: "no generated variants for this host" };
3085
3160
  }
3086
- if (!fs8.existsSync(layout.variantsRoot)) {
3161
+ if (!fs9.existsSync(layout.variantsRoot)) {
3087
3162
  return {
3088
3163
  host,
3089
3164
  status: "skipped",
@@ -3095,24 +3170,24 @@ function syncHost(host, sourceRoot, targetHome, marketplaceRoot) {
3095
3170
  }
3096
3171
  const profiles = [];
3097
3172
  let files = 0;
3098
- for (const entry of fs8.readdirSync(srcDir, { withFileTypes: true })) {
3173
+ for (const entry of fs9.readdirSync(srcDir, { withFileTypes: true })) {
3099
3174
  if (!entry.isDirectory())
3100
3175
  continue;
3101
3176
  if (!isSafeDirName(entry.name))
3102
3177
  continue;
3103
- const srcProfileDir = path12.join(srcDir, entry.name);
3104
- const destProfileDir = path12.join(layout.variantsRoot, entry.name);
3105
- fs8.mkdirSync(destProfileDir, { recursive: true });
3106
- for (const fileEntry of fs8.readdirSync(srcProfileDir, { withFileTypes: true })) {
3178
+ const srcProfileDir = path13.join(srcDir, entry.name);
3179
+ const destProfileDir = path13.join(layout.variantsRoot, entry.name);
3180
+ fs9.mkdirSync(destProfileDir, { recursive: true });
3181
+ for (const fileEntry of fs9.readdirSync(srcProfileDir, { withFileTypes: true })) {
3107
3182
  if (!fileEntry.isFile())
3108
3183
  continue;
3109
- const content = fs8.readFileSync(path12.join(srcProfileDir, fileEntry.name));
3184
+ const content = fs9.readFileSync(path13.join(srcProfileDir, fileEntry.name));
3110
3185
  writeFileIntoDirAtomically(destProfileDir, fileEntry.name, content);
3111
3186
  files++;
3112
3187
  }
3113
3188
  profiles.push(entry.name);
3114
3189
  }
3115
- const retained = fs8.readdirSync(layout.variantsRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && !profiles.includes(e.name)).map((e) => e.name).sort();
3190
+ const retained = fs9.readdirSync(layout.variantsRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && !profiles.includes(e.name)).map((e) => e.name).sort();
3116
3191
  return { host, status: "synced", profiles: profiles.sort(), retained, files };
3117
3192
  }
3118
3193
  function syncGeneratedVariants(opts) {
@@ -3140,14 +3215,14 @@ function syncGeneratedVariants(opts) {
3140
3215
  });
3141
3216
  }
3142
3217
  // ../../packages/shared/dist/profile-switch/repo-root.js
3143
- import fs9 from "fs";
3144
- import path13 from "path";
3218
+ import fs10 from "fs";
3219
+ import path14 from "path";
3145
3220
  function findRepoRootWithMarker(startDir, marker, maxLevels) {
3146
3221
  let dir = startDir;
3147
3222
  for (let i = 0;i <= maxLevels; i++) {
3148
- if (fs9.existsSync(path13.join(dir, marker)))
3223
+ if (fs10.existsSync(path14.join(dir, marker)))
3149
3224
  return dir;
3150
- const parent = path13.dirname(dir);
3225
+ const parent = path14.dirname(dir);
3151
3226
  if (parent === dir)
3152
3227
  break;
3153
3228
  dir = parent;
@@ -3158,7 +3233,6 @@ function findRepoRootWithMarker(startDir, marker, maxLevels) {
3158
3233
  var BOOTSTRAP_RULE_IDS = [
3159
3234
  "caveman",
3160
3235
  "massa-ai-router",
3161
- "persona-router",
3162
3236
  "dedupe-guardrails",
3163
3237
  "plan-challenge",
3164
3238
  "conversation-feedback",
@@ -3166,6 +3240,10 @@ var BOOTSTRAP_RULE_IDS = [
3166
3240
  "english-code",
3167
3241
  "code-comments"
3168
3242
  ];
3243
+ var RETIRED_RULE_IDS = ["persona-router"];
3244
+ function isRetiredRuleId(value) {
3245
+ return RETIRED_RULE_IDS.includes(value);
3246
+ }
3169
3247
  function isBootstrapRuleId(value) {
3170
3248
  return typeof value === "string" && BOOTSTRAP_RULE_IDS.includes(value);
3171
3249
  }
@@ -3180,11 +3258,6 @@ var BOOTSTRAP_RULES = [
3180
3258
  defaultEnabled: true,
3181
3259
  description: "Load the massa-ai skill as the workflow router before substantive work."
3182
3260
  },
3183
- {
3184
- id: "persona-router",
3185
- defaultEnabled: true,
3186
- description: "Select one cataloged specialist persona after massa-ai context is available."
3187
- },
3188
3261
  {
3189
3262
  id: "dedupe-guardrails",
3190
3263
  defaultEnabled: true,
@@ -3235,14 +3308,17 @@ function namedError4(name, message) {
3235
3308
  err.name = name;
3236
3309
  return err;
3237
3310
  }
3238
- var UnknownRuleError = (id, known = BOOTSTRAP_RULE_IDS) => namedError4("UnknownRuleError", `unknown bootstrap rule "${id}" \u2014 valid ids: ${known.join(", ")}`);
3311
+ var UnknownRuleError = (id, known = BOOTSTRAP_RULE_IDS) => {
3312
+ const what = isRetiredRuleId(id) ? `bootstrap rule "${id}" was retired and can no longer be toggled` : `unknown bootstrap rule "${id}"`;
3313
+ return namedError4("UnknownRuleError", `${what} \u2014 valid ids: ${known.join(", ")}`);
3314
+ };
3239
3315
  function assertKnownRuleId(id) {
3240
3316
  if (!isBootstrapRuleId(id))
3241
3317
  throw UnknownRuleError(id, BOOTSTRAP_RULE_IDS);
3242
3318
  }
3243
3319
  // ../../packages/shared/dist/bootstrap/state.js
3244
3320
  init_config_loader();
3245
- import fs10 from "fs";
3321
+ import fs11 from "fs";
3246
3322
  var BOOTSTRAP_STATE_KEY = "bootstrap";
3247
3323
  var BOOTSTRAP_RULES_KEY = "rules";
3248
3324
  var BOOTSTRAP_STATE_PATH = `${BOOTSTRAP_STATE_KEY}.${BOOTSTRAP_RULES_KEY}`;
@@ -3266,6 +3342,8 @@ function resolveBootstrapState(doc) {
3266
3342
  return { state, ignoredStateKeys: [BOOTSTRAP_STATE_PATH] };
3267
3343
  }
3268
3344
  for (const [key, value] of Object.entries(rules)) {
3345
+ if (isRetiredRuleId(key))
3346
+ continue;
3269
3347
  if (!isBootstrapRuleId(key) || typeof value !== "boolean") {
3270
3348
  ignored.push(key);
3271
3349
  continue;
@@ -3276,7 +3354,7 @@ function resolveBootstrapState(doc) {
3276
3354
  }
3277
3355
  function readConfigBytes() {
3278
3356
  try {
3279
- return fs10.readFileSync(getConfigPath(), "utf-8");
3357
+ return fs11.readFileSync(getConfigPath(), "utf-8");
3280
3358
  } catch (error) {
3281
3359
  if (error?.code === "ENOENT")
3282
3360
  return "";
@@ -3324,7 +3402,7 @@ function setBootstrapRuleEnabled(id, enabled) {
3324
3402
  };
3325
3403
  }
3326
3404
  // ../../packages/shared/dist/bootstrap/render.js
3327
- import path14 from "path";
3405
+ import path15 from "path";
3328
3406
  var BOOTSTRAP_BLOCK_START = "<!-- massa-ai:bootstrap:start -->";
3329
3407
  var BOOTSTRAP_BLOCK_END = "<!-- massa-ai:bootstrap:end -->";
3330
3408
  var CONTRACT_FILENAME = "MASSA-AI.md";
@@ -3356,19 +3434,19 @@ var HOST_CONFIG_DIR = {
3356
3434
  function resolveHostRoot(host, targetHome, hostRoot) {
3357
3435
  requireAbsoluteTargetHome(targetHome);
3358
3436
  if (hostRoot === undefined)
3359
- return path14.join(targetHome, ...HOST_CONFIG_DIR[host]);
3360
- const relative = path14.relative(targetHome, hostRoot);
3361
- if (!path14.isAbsolute(hostRoot) || relative === "" || relative.startsWith("..") || path14.isAbsolute(relative)) {
3437
+ return path15.join(targetHome, ...HOST_CONFIG_DIR[host]);
3438
+ const relative = path15.relative(targetHome, hostRoot);
3439
+ if (!path15.isAbsolute(hostRoot) || relative === "" || relative.startsWith("..") || path15.isAbsolute(relative)) {
3362
3440
  throw new BootstrapRenderError("HostRootOutsideTargetHomeError", `hostRoot must be an absolute directory inside targetHome, got "${hostRoot}" for targetHome "${targetHome}"`, [hostRoot, targetHome]);
3363
3441
  }
3364
3442
  return hostRoot;
3365
3443
  }
3366
3444
  function bootstrapContractPath(host, targetHome, hostRoot) {
3367
- return path14.join(resolveHostRoot(host, targetHome, hostRoot), CONTRACT_FILENAME);
3445
+ return path15.join(resolveHostRoot(host, targetHome, hostRoot), CONTRACT_FILENAME);
3368
3446
  }
3369
3447
  function bootstrapStateFilePath(targetHome) {
3370
3448
  requireAbsoluteTargetHome(targetHome);
3371
- return path14.join(targetHome, ".config", "massa-ai", "config.json");
3449
+ return path15.join(targetHome, ".config", "massa-ai", "config.json");
3372
3450
  }
3373
3451
  function renderBootstrap(options) {
3374
3452
  const { source, state, host, targetHome, hostRoot } = options;
@@ -3391,7 +3469,7 @@ ${body}`;
3391
3469
  return { contract, pointer };
3392
3470
  }
3393
3471
  function requireAbsoluteTargetHome(targetHome) {
3394
- if (!path14.isAbsolute(targetHome)) {
3472
+ if (!path15.isAbsolute(targetHome)) {
3395
3473
  throw new BootstrapRenderError("TargetHomeNotAbsoluteError", `targetHome must be an absolute path, got "${targetHome}"`, [targetHome]);
3396
3474
  }
3397
3475
  }
@@ -3544,8 +3622,8 @@ function buildBootstrapReport(input) {
3544
3622
  }
3545
3623
  // ../../packages/shared/dist/bootstrap/engine.js
3546
3624
  init_config_loader();
3547
- import fs11 from "fs";
3548
- import path15 from "path";
3625
+ import fs12 from "fs";
3626
+ import path16 from "path";
3549
3627
  var INSTALL_STATE_FILENAME = "install-state.json";
3550
3628
  var WIRING_REMEDY = "scripts/install-skills.sh --apply";
3551
3629
 
@@ -3562,7 +3640,7 @@ function applyBootstrapState(options) {
3562
3640
  const dryRun = options.dryRun ?? false;
3563
3641
  const warn = options.onWarning ?? ((message) => console.warn(message));
3564
3642
  const configPath = bootstrapStateFilePath(targetHome);
3565
- const installStatePath = path15.join(path15.dirname(configPath), INSTALL_STATE_FILENAME);
3643
+ const installStatePath = path16.join(path16.dirname(configPath), INSTALL_STATE_FILENAME);
3566
3644
  const { platforms } = readInstallState(installStatePath);
3567
3645
  const installed = HOSTS.filter((host) => platforms[host] !== undefined);
3568
3646
  if (installed.length === 0) {
@@ -3655,22 +3733,22 @@ function applyHost(input) {
3655
3733
  }
3656
3734
  function wiringArtifact(host, targetHome, hostRoot) {
3657
3735
  const root = resolveHostRoot(host, targetHome, hostRoot);
3658
- const contractPath = path15.join(root, CONTRACT_FILENAME);
3736
+ const contractPath = path16.join(root, CONTRACT_FILENAME);
3659
3737
  switch (host) {
3660
3738
  case "claude":
3661
- return { file: path15.join(root, "CLAUDE.md"), token: `@${CONTRACT_FILENAME}` };
3739
+ return { file: path16.join(root, "CLAUDE.md"), token: `@${CONTRACT_FILENAME}` };
3662
3740
  case "codex":
3663
3741
  case "cursor":
3664
- return { file: path15.join(root, "AGENTS.md"), token: contractPath };
3742
+ return { file: path16.join(root, "AGENTS.md"), token: contractPath };
3665
3743
  case "opencode":
3666
3744
  return { file: openCodeConfigPath(root), token: `"${contractPath}"` };
3667
3745
  }
3668
3746
  }
3669
3747
  function openCodeConfigPath(root) {
3670
- const json = path15.join(root, "opencode.json");
3671
- if (fs11.existsSync(json))
3748
+ const json = path16.join(root, "opencode.json");
3749
+ if (fs12.existsSync(json))
3672
3750
  return json;
3673
- return path15.join(root, "opencode.jsonc");
3751
+ return path16.join(root, "opencode.jsonc");
3674
3752
  }
3675
3753
  function isWired(host, targetHome, hostRoot) {
3676
3754
  const artifact = wiringArtifact(host, targetHome, hostRoot);
@@ -3683,7 +3761,7 @@ function notWiredReason(host, targetHome, hostRoot) {
3683
3761
  }
3684
3762
  function readFileOrNull(filePath) {
3685
3763
  try {
3686
- return fs11.readFileSync(filePath, "utf-8");
3764
+ return fs12.readFileSync(filePath, "utf-8");
3687
3765
  } catch {
3688
3766
  return null;
3689
3767
  }
@@ -3729,11 +3807,11 @@ function formatBootstrapReport(report) {
3729
3807
  init_config_loader();
3730
3808
  // src/config-cli.ts
3731
3809
  init_inference_providers();
3732
- import { promises as fs12 } from "fs";
3733
- import path16 from "path";
3810
+ import { promises as fs13 } from "fs";
3811
+ import path17 from "path";
3734
3812
  import os9 from "os";
3735
3813
  import { fileURLToPath } from "url";
3736
- var __dirname2 = path16.dirname(fileURLToPath(import.meta.url));
3814
+ var __dirname2 = path17.dirname(fileURLToPath(import.meta.url));
3737
3815
  var WRITABLE_PROVIDERS = ["ollama", "lmstudio", "mistral", "openai", "google", "cohere"];
3738
3816
  var GENERATOR_MARKER = "scripts/generate-subagent-artifacts.ts";
3739
3817
  var GENERATOR_MARKER_MAX_LEVELS = 6;
@@ -3767,8 +3845,8 @@ Commands:
3767
3845
  --model <name> Model name
3768
3846
  --base-url <url> Base URL (for ollama/lmstudio)
3769
3847
 
3770
- agents Manage the 18 subagent specialist definitions
3771
- agents install [--user|--project] Write 18 agent .md files
3848
+ agents Manage the 7 subagent specialist definitions
3849
+ agents install [--user|--project] Write 7 agent .md files
3772
3850
  agents uninstall [--user|--project] Remove only massa-ai-owned agents
3773
3851
 
3774
3852
  profile list List shipped model profiles + per-host active profile
@@ -4045,18 +4123,30 @@ Using defaults:`);
4045
4123
  return 1;
4046
4124
  }
4047
4125
  const scope = typeof options.project === "boolean" ? "project" : "user";
4048
- const agentsDir = scope === "project" ? path16.join(process.cwd(), ".opencode/agents") : path16.join(process.env.XDG_CONFIG_HOME && process.env.XDG_CONFIG_HOME.trim() || path16.join(os9.homedir(), ".config"), "opencode", "agents");
4049
- const sourceAgentsDir = path16.resolve(__dirname2, "..", "agents");
4126
+ const agentsDir = scope === "project" ? path17.join(process.cwd(), ".opencode/agents") : path17.join(process.env.XDG_CONFIG_HOME && process.env.XDG_CONFIG_HOME.trim() || path17.join(os9.homedir(), ".config"), "opencode", "agents");
4127
+ const sourceAgentsDir = path17.resolve(__dirname2, "..", "agents");
4050
4128
  if (subcommand === "install") {
4051
- await fs12.mkdir(agentsDir, { recursive: true });
4129
+ await fs13.mkdir(agentsDir, { recursive: true });
4052
4130
  let count = 0;
4053
- const entries = await fs12.readdir(sourceAgentsDir);
4131
+ const entries = await fs13.readdir(sourceAgentsDir);
4054
4132
  for (const entry of entries) {
4055
- if (!entry.startsWith("massa-ai-") || !entry.endsWith(".md"))
4133
+ if (!entry.endsWith(".md"))
4134
+ continue;
4135
+ const src = path17.join(sourceAgentsDir, entry);
4136
+ const dest = path17.join(agentsDir, entry);
4137
+ let destExists = true;
4138
+ try {
4139
+ await fs13.lstat(dest);
4140
+ } catch {
4141
+ destExists = false;
4142
+ }
4143
+ if (destExists && !isOwnedAgentFile(dest) && !isOwnedAgentLink(dest)) {
4144
+ console.warn(`\u26A0 ${dest} exists and is not massa-ai-owned \u2014 skipped`);
4056
4145
  continue;
4057
- const src = path16.join(sourceAgentsDir, entry);
4058
- const dest = path16.join(agentsDir, entry);
4059
- await fs12.copyFile(src, dest);
4146
+ }
4147
+ if (isOwnedAgentLink(dest))
4148
+ await fs13.unlink(dest);
4149
+ await fs13.copyFile(src, dest);
4060
4150
  count++;
4061
4151
  }
4062
4152
  console.log(`+ ${count} subagent specialists (generated from skills/agents/*/SKILL.md)`);
@@ -4064,14 +4154,13 @@ Using defaults:`);
4064
4154
  } else {
4065
4155
  let removed = 0;
4066
4156
  try {
4067
- const entries = await fs12.readdir(agentsDir);
4157
+ const entries = await fs13.readdir(agentsDir);
4068
4158
  for (const entry of entries) {
4069
- if (!entry.startsWith("massa-ai-") || !entry.endsWith(".md"))
4159
+ if (!entry.endsWith(".md"))
4070
4160
  continue;
4071
- const filePath = path16.join(agentsDir, entry);
4072
- const content = await fs12.readFile(filePath, "utf8");
4073
- if (content.includes("massa-ai-owned: true")) {
4074
- await fs12.unlink(filePath);
4161
+ const filePath = path17.join(agentsDir, entry);
4162
+ if (isOwnedAgentFile(filePath) || isOwnedAgentLink(filePath)) {
4163
+ await fs13.unlink(filePath);
4075
4164
  removed++;
4076
4165
  }
4077
4166
  }
@@ -4181,7 +4270,7 @@ Using defaults:`);
4181
4270
  return 1;
4182
4271
  }
4183
4272
  const targetOpt = typeof options.target === "string" ? options.target : undefined;
4184
- const targetHome = targetOpt === undefined ? os9.homedir() : path16.resolve(targetOpt);
4273
+ const targetHome = targetOpt === undefined ? os9.homedir() : path17.resolve(targetOpt);
4185
4274
  if (targetHome !== os9.homedir() && options.yes !== true) {
4186
4275
  console.error(`Error: --target ${targetHome} is not your home (${os9.homedir()}) \u2014 pass --yes to confirm writing there`);
4187
4276
  return 1;
@@ -4201,7 +4290,7 @@ Using defaults:`);
4201
4290
  const report = applyBootstrapState({
4202
4291
  targetHome,
4203
4292
  dryRun,
4204
- sourcePath: repoRoot === null ? undefined : path16.join(repoRoot, "skills", "AGENTS.md")
4293
+ sourcePath: repoRoot === null ? undefined : path17.join(repoRoot, "skills", "AGENTS.md")
4205
4294
  });
4206
4295
  console.log(formatBootstrapReport(report));
4207
4296
  return bootstrapReportSucceeded(report) ? 0 : 1;