@monoes/monomindcli 2.9.25 → 2.9.27

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 (254) hide show
  1. package/.claude/helpers/control-start.cjs +15 -1
  2. package/.claude/helpers/handlers/edit-handler.cjs +3 -2
  3. package/.claude/helpers/handlers/route-handler.cjs +19 -4
  4. package/.claude/helpers/hook-handler.cjs +2 -0
  5. package/.claude/helpers/utils/monograph.cjs +8 -0
  6. package/.claude/skills/mastermind/SKILL.md +21 -0
  7. package/.claude/skills/mastermind/references/antigravity-tools.md +60 -0
  8. package/.claude/skills/mastermind/references/claude-code-tools.md +50 -0
  9. package/.claude/skills/mastermind/references/codex-tools.md +64 -0
  10. package/.claude/skills/mastermind/references/copilot-tools.md +49 -0
  11. package/.claude/skills/mastermind/references/gemini-tools.md +63 -0
  12. package/.claude/skills/mastermind/references/pi-tools.md +28 -0
  13. package/.claude/skills/mastermind-org/SKILL.md +16 -0
  14. package/dist/src/commands/browse.d.ts +2 -10
  15. package/dist/src/commands/browse.d.ts.map +1 -1
  16. package/dist/src/commands/browse.js +7 -2
  17. package/dist/src/commands/browse.js.map +1 -1
  18. package/dist/src/commands/doctor.d.ts.map +1 -1
  19. package/dist/src/commands/doctor.js +16 -1
  20. package/dist/src/commands/doctor.js.map +1 -1
  21. package/dist/src/commands/index.d.ts +1 -1
  22. package/dist/src/commands/index.d.ts.map +1 -1
  23. package/dist/src/commands/index.js +10 -1
  24. package/dist/src/commands/index.js.map +1 -1
  25. package/dist/src/commands/init.d.ts.map +1 -1
  26. package/dist/src/commands/init.js +63 -5
  27. package/dist/src/commands/init.js.map +1 -1
  28. package/dist/src/commands/mastermind.d.ts +10 -0
  29. package/dist/src/commands/mastermind.d.ts.map +1 -0
  30. package/dist/src/commands/mastermind.js +62 -0
  31. package/dist/src/commands/mastermind.js.map +1 -0
  32. package/dist/src/commands/platforms.d.ts +9 -7
  33. package/dist/src/commands/platforms.d.ts.map +1 -1
  34. package/dist/src/commands/platforms.js +225 -571
  35. package/dist/src/commands/platforms.js.map +1 -1
  36. package/dist/src/commands/status.d.ts.map +1 -1
  37. package/dist/src/commands/status.js +7 -1
  38. package/dist/src/commands/status.js.map +1 -1
  39. package/dist/src/commands/update.d.ts.map +1 -1
  40. package/dist/src/commands/update.js +22 -0
  41. package/dist/src/commands/update.js.map +1 -1
  42. package/dist/src/init/codex-generator.d.ts.map +1 -1
  43. package/dist/src/init/codex-generator.js +5 -3
  44. package/dist/src/init/codex-generator.js.map +1 -1
  45. package/dist/src/init/executor.d.ts +6 -0
  46. package/dist/src/init/executor.d.ts.map +1 -1
  47. package/dist/src/init/executor.js +32 -3
  48. package/dist/src/init/executor.js.map +1 -1
  49. package/dist/src/init/mcp-generator.d.ts.map +1 -1
  50. package/dist/src/init/mcp-generator.js +5 -40
  51. package/dist/src/init/mcp-generator.js.map +1 -1
  52. package/dist/src/init/shared.d.ts.map +1 -1
  53. package/dist/src/init/shared.js +6 -5
  54. package/dist/src/init/shared.js.map +1 -1
  55. package/dist/src/init/types.d.ts +4 -0
  56. package/dist/src/init/types.d.ts.map +1 -1
  57. package/dist/src/init/types.js.map +1 -1
  58. package/dist/src/init/upgrade.d.ts.map +1 -1
  59. package/dist/src/init/upgrade.js +11 -1
  60. package/dist/src/init/upgrade.js.map +1 -1
  61. package/dist/src/init/write-antigravity.d.ts.map +1 -1
  62. package/dist/src/init/write-antigravity.js +5 -50
  63. package/dist/src/init/write-antigravity.js.map +1 -1
  64. package/dist/src/init/write-claude.d.ts.map +1 -1
  65. package/dist/src/init/write-claude.js +4 -88
  66. package/dist/src/init/write-claude.js.map +1 -1
  67. package/dist/src/init/write-codex.d.ts.map +1 -1
  68. package/dist/src/init/write-codex.js +12 -8
  69. package/dist/src/init/write-codex.js.map +1 -1
  70. package/dist/src/init/write-kimicode.d.ts.map +1 -1
  71. package/dist/src/init/write-kimicode.js +4 -48
  72. package/dist/src/init/write-kimicode.js.map +1 -1
  73. package/dist/src/knowledge/document-pipeline.d.ts.map +1 -1
  74. package/dist/src/knowledge/document-pipeline.js +6 -4
  75. package/dist/src/knowledge/document-pipeline.js.map +1 -1
  76. package/dist/src/knowledge/eval/harness.d.ts.map +1 -1
  77. package/dist/src/knowledge/eval/harness.js +9 -11
  78. package/dist/src/knowledge/eval/harness.js.map +1 -1
  79. package/dist/src/mastermind/manifest-data.d.ts +10 -0
  80. package/dist/src/mastermind/manifest-data.d.ts.map +1 -0
  81. package/dist/src/mastermind/manifest-data.js +67 -0
  82. package/dist/src/mastermind/manifest-data.js.map +1 -0
  83. package/dist/src/mastermind/manifest.d.ts +22 -0
  84. package/dist/src/mastermind/manifest.d.ts.map +1 -0
  85. package/dist/src/mastermind/manifest.js +36 -0
  86. package/dist/src/mastermind/manifest.js.map +1 -0
  87. package/dist/src/mcp-client.d.ts.map +1 -1
  88. package/dist/src/mcp-client.js +2 -0
  89. package/dist/src/mcp-client.js.map +1 -1
  90. package/dist/src/mcp-tools/index.d.ts +1 -0
  91. package/dist/src/mcp-tools/index.d.ts.map +1 -1
  92. package/dist/src/mcp-tools/index.js +1 -0
  93. package/dist/src/mcp-tools/index.js.map +1 -1
  94. package/dist/src/mcp-tools/platforms-tools.d.ts +5 -0
  95. package/dist/src/mcp-tools/platforms-tools.d.ts.map +1 -0
  96. package/dist/src/mcp-tools/platforms-tools.js +38 -0
  97. package/dist/src/mcp-tools/platforms-tools.js.map +1 -0
  98. package/dist/src/memory/intelligence.d.ts.map +1 -1
  99. package/dist/src/memory/intelligence.js +54 -20
  100. package/dist/src/memory/intelligence.js.map +1 -1
  101. package/dist/src/memory/memory-bridge.d.ts.map +1 -1
  102. package/dist/src/memory/memory-bridge.js +3 -2
  103. package/dist/src/memory/memory-bridge.js.map +1 -1
  104. package/dist/src/memory/memory-kg.js +3 -3
  105. package/dist/src/memory/memory-kg.js.map +1 -1
  106. package/dist/src/monovector/diff-classifier.d.ts +2 -2
  107. package/dist/src/monovector/diff-classifier.d.ts.map +1 -1
  108. package/dist/src/monovector/diff-classifier.js.map +1 -1
  109. package/dist/src/orgrt/session.d.ts.map +1 -1
  110. package/dist/src/orgrt/session.js +54 -24
  111. package/dist/src/orgrt/session.js.map +1 -1
  112. package/dist/src/orgrt/task-dag.d.ts.map +1 -1
  113. package/dist/src/orgrt/task-dag.js +5 -1
  114. package/dist/src/orgrt/task-dag.js.map +1 -1
  115. package/dist/src/platform-adapters/core.d.ts +20 -0
  116. package/dist/src/platform-adapters/core.d.ts.map +1 -0
  117. package/dist/src/platform-adapters/core.js +34 -0
  118. package/dist/src/platform-adapters/core.js.map +1 -0
  119. package/dist/src/platform-adapters/discovery.d.ts +15 -0
  120. package/dist/src/platform-adapters/discovery.d.ts.map +1 -0
  121. package/dist/src/platform-adapters/discovery.js +64 -0
  122. package/dist/src/platform-adapters/discovery.js.map +1 -0
  123. package/dist/src/platform-adapters/docs.d.ts +4 -0
  124. package/dist/src/platform-adapters/docs.d.ts.map +1 -0
  125. package/dist/src/platform-adapters/docs.js +34 -0
  126. package/dist/src/platform-adapters/docs.js.map +1 -0
  127. package/dist/src/platform-adapters/hook-bridge.d.ts +44 -0
  128. package/dist/src/platform-adapters/hook-bridge.d.ts.map +1 -0
  129. package/dist/src/platform-adapters/hook-bridge.js +133 -0
  130. package/dist/src/platform-adapters/hook-bridge.js.map +1 -0
  131. package/dist/src/platform-adapters/merge.d.ts +32 -0
  132. package/dist/src/platform-adapters/merge.d.ts.map +1 -0
  133. package/dist/src/platform-adapters/merge.js +209 -0
  134. package/dist/src/platform-adapters/merge.js.map +1 -0
  135. package/dist/src/platform-adapters/migration.d.ts +31 -0
  136. package/dist/src/platform-adapters/migration.d.ts.map +1 -0
  137. package/dist/src/platform-adapters/migration.js +402 -0
  138. package/dist/src/platform-adapters/migration.js.map +1 -0
  139. package/dist/src/platform-adapters/operations.d.ts +23 -0
  140. package/dist/src/platform-adapters/operations.d.ts.map +1 -0
  141. package/dist/src/platform-adapters/operations.js +405 -0
  142. package/dist/src/platform-adapters/operations.js.map +1 -0
  143. package/dist/src/platform-adapters/registry.d.ts +9 -0
  144. package/dist/src/platform-adapters/registry.d.ts.map +1 -0
  145. package/dist/src/platform-adapters/registry.js +614 -0
  146. package/dist/src/platform-adapters/registry.js.map +1 -0
  147. package/dist/src/platform-adapters/renderers/agents.d.ts +5 -0
  148. package/dist/src/platform-adapters/renderers/agents.d.ts.map +1 -0
  149. package/dist/src/platform-adapters/renderers/agents.js +46 -0
  150. package/dist/src/platform-adapters/renderers/agents.js.map +1 -0
  151. package/dist/src/platform-adapters/renderers/aider.d.ts +2 -0
  152. package/dist/src/platform-adapters/renderers/aider.d.ts.map +1 -0
  153. package/dist/src/platform-adapters/renderers/aider.js +3 -0
  154. package/dist/src/platform-adapters/renderers/aider.js.map +1 -0
  155. package/dist/src/platform-adapters/renderers/antigravity.d.ts +2 -0
  156. package/dist/src/platform-adapters/renderers/antigravity.d.ts.map +1 -0
  157. package/dist/src/platform-adapters/renderers/antigravity.js +3 -0
  158. package/dist/src/platform-adapters/renderers/antigravity.js.map +1 -0
  159. package/dist/src/platform-adapters/renderers/claude.d.ts +2 -0
  160. package/dist/src/platform-adapters/renderers/claude.d.ts.map +1 -0
  161. package/dist/src/platform-adapters/renderers/claude.js +3 -0
  162. package/dist/src/platform-adapters/renderers/claude.js.map +1 -0
  163. package/dist/src/platform-adapters/renderers/codex.d.ts +2 -0
  164. package/dist/src/platform-adapters/renderers/codex.d.ts.map +1 -0
  165. package/dist/src/platform-adapters/renderers/codex.js +3 -0
  166. package/dist/src/platform-adapters/renderers/codex.js.map +1 -0
  167. package/dist/src/platform-adapters/renderers/commands.d.ts +13 -0
  168. package/dist/src/platform-adapters/renderers/commands.d.ts.map +1 -0
  169. package/dist/src/platform-adapters/renderers/commands.js +78 -0
  170. package/dist/src/platform-adapters/renderers/commands.js.map +1 -0
  171. package/dist/src/platform-adapters/renderers/copilot.d.ts +2 -0
  172. package/dist/src/platform-adapters/renderers/copilot.d.ts.map +1 -0
  173. package/dist/src/platform-adapters/renderers/copilot.js +3 -0
  174. package/dist/src/platform-adapters/renderers/copilot.js.map +1 -0
  175. package/dist/src/platform-adapters/renderers/cursor.d.ts +2 -0
  176. package/dist/src/platform-adapters/renderers/cursor.d.ts.map +1 -0
  177. package/dist/src/platform-adapters/renderers/cursor.js +3 -0
  178. package/dist/src/platform-adapters/renderers/cursor.js.map +1 -0
  179. package/dist/src/platform-adapters/renderers/droid.d.ts +2 -0
  180. package/dist/src/platform-adapters/renderers/droid.d.ts.map +1 -0
  181. package/dist/src/platform-adapters/renderers/droid.js +3 -0
  182. package/dist/src/platform-adapters/renderers/droid.js.map +1 -0
  183. package/dist/src/platform-adapters/renderers/experimental.d.ts +6 -0
  184. package/dist/src/platform-adapters/renderers/experimental.d.ts.map +1 -0
  185. package/dist/src/platform-adapters/renderers/experimental.js +9 -0
  186. package/dist/src/platform-adapters/renderers/experimental.js.map +1 -0
  187. package/dist/src/platform-adapters/renderers/factory.d.ts +14 -0
  188. package/dist/src/platform-adapters/renderers/factory.d.ts.map +1 -0
  189. package/dist/src/platform-adapters/renderers/factory.js +53 -0
  190. package/dist/src/platform-adapters/renderers/factory.js.map +1 -0
  191. package/dist/src/platform-adapters/renderers/gemini.d.ts +2 -0
  192. package/dist/src/platform-adapters/renderers/gemini.d.ts.map +1 -0
  193. package/dist/src/platform-adapters/renderers/gemini.js +3 -0
  194. package/dist/src/platform-adapters/renderers/gemini.js.map +1 -0
  195. package/dist/src/platform-adapters/renderers/hooks.d.ts +37 -0
  196. package/dist/src/platform-adapters/renderers/hooks.d.ts.map +1 -0
  197. package/dist/src/platform-adapters/renderers/hooks.js +166 -0
  198. package/dist/src/platform-adapters/renderers/hooks.js.map +1 -0
  199. package/dist/src/platform-adapters/renderers/index.d.ts +8 -0
  200. package/dist/src/platform-adapters/renderers/index.d.ts.map +1 -0
  201. package/dist/src/platform-adapters/renderers/index.js +39 -0
  202. package/dist/src/platform-adapters/renderers/index.js.map +1 -0
  203. package/dist/src/platform-adapters/renderers/instructions.d.ts +6 -0
  204. package/dist/src/platform-adapters/renderers/instructions.d.ts.map +1 -0
  205. package/dist/src/platform-adapters/renderers/instructions.js +31 -0
  206. package/dist/src/platform-adapters/renderers/instructions.js.map +1 -0
  207. package/dist/src/platform-adapters/renderers/kimi.d.ts +2 -0
  208. package/dist/src/platform-adapters/renderers/kimi.d.ts.map +1 -0
  209. package/dist/src/platform-adapters/renderers/kimi.js +3 -0
  210. package/dist/src/platform-adapters/renderers/kimi.js.map +1 -0
  211. package/dist/src/platform-adapters/renderers/kiro.d.ts +2 -0
  212. package/dist/src/platform-adapters/renderers/kiro.d.ts.map +1 -0
  213. package/dist/src/platform-adapters/renderers/kiro.js +3 -0
  214. package/dist/src/platform-adapters/renderers/kiro.js.map +1 -0
  215. package/dist/src/platform-adapters/renderers/mcp.d.ts +29 -0
  216. package/dist/src/platform-adapters/renderers/mcp.d.ts.map +1 -0
  217. package/dist/src/platform-adapters/renderers/mcp.js +69 -0
  218. package/dist/src/platform-adapters/renderers/mcp.js.map +1 -0
  219. package/dist/src/platform-adapters/renderers/openclaw.d.ts +2 -0
  220. package/dist/src/platform-adapters/renderers/openclaw.d.ts.map +1 -0
  221. package/dist/src/platform-adapters/renderers/openclaw.js +3 -0
  222. package/dist/src/platform-adapters/renderers/openclaw.js.map +1 -0
  223. package/dist/src/platform-adapters/renderers/opencode.d.ts +2 -0
  224. package/dist/src/platform-adapters/renderers/opencode.d.ts.map +1 -0
  225. package/dist/src/platform-adapters/renderers/opencode.js +3 -0
  226. package/dist/src/platform-adapters/renderers/opencode.js.map +1 -0
  227. package/dist/src/platform-adapters/renderers/skills.d.ts +11 -0
  228. package/dist/src/platform-adapters/renderers/skills.d.ts.map +1 -0
  229. package/dist/src/platform-adapters/renderers/skills.js +60 -0
  230. package/dist/src/platform-adapters/renderers/skills.js.map +1 -0
  231. package/dist/src/platform-adapters/renderers/status.d.ts +23 -0
  232. package/dist/src/platform-adapters/renderers/status.d.ts.map +1 -0
  233. package/dist/src/platform-adapters/renderers/status.js +63 -0
  234. package/dist/src/platform-adapters/renderers/status.js.map +1 -0
  235. package/dist/src/platform-adapters/renderers/vscode.d.ts +2 -0
  236. package/dist/src/platform-adapters/renderers/vscode.d.ts.map +1 -0
  237. package/dist/src/platform-adapters/renderers/vscode.js +3 -0
  238. package/dist/src/platform-adapters/renderers/vscode.js.map +1 -0
  239. package/dist/src/platform-adapters/renderers/zed.d.ts +2 -0
  240. package/dist/src/platform-adapters/renderers/zed.d.ts.map +1 -0
  241. package/dist/src/platform-adapters/renderers/zed.js +3 -0
  242. package/dist/src/platform-adapters/renderers/zed.js.map +1 -0
  243. package/dist/src/platform-adapters/types.d.ts +105 -0
  244. package/dist/src/platform-adapters/types.d.ts.map +1 -0
  245. package/dist/src/platform-adapters/types.js +13 -0
  246. package/dist/src/platform-adapters/types.js.map +1 -0
  247. package/dist/src/platform-adapters/verification-ledger.d.ts +8 -0
  248. package/dist/src/platform-adapters/verification-ledger.d.ts.map +1 -0
  249. package/dist/src/platform-adapters/verification-ledger.js +24 -0
  250. package/dist/src/platform-adapters/verification-ledger.js.map +1 -0
  251. package/dist/src/ui/markdown.js +10 -0
  252. package/dist/tsconfig.tsbuildinfo +1 -1
  253. package/package.json +1 -1
  254. package/dist/src/ui/data/mastermind-sessions.json +0 -1
@@ -1,639 +1,293 @@
1
- /**
2
- * CLI Platforms Command
3
- * Install/uninstall Monograph context instructions for 14 AI coding platforms
4
- *
5
- * github.com/monoes/monomind
6
- */
7
- import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
8
- import { homedir } from 'node:os';
9
- import { basename, dirname, join, resolve } from 'node:path';
1
+ /** Evidence-gated platform adapter lifecycle commands. */
2
+ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { basename, join, resolve } from 'node:path';
10
4
  import { output } from '../output.js';
11
- export const SUPPORTED_PLATFORMS = [
12
- 'claude',
13
- 'gemini',
14
- 'cursor',
15
- 'vscode',
16
- 'copilot',
17
- 'opencode',
18
- 'aider',
19
- 'kiro',
20
- 'trae',
21
- 'claw',
22
- 'droid',
23
- 'antigravity',
24
- 'hermes',
25
- 'codex',
26
- ];
27
- const PLATFORM_CONFIG_FILES = {
28
- claude: ['CLAUDE.md'],
29
- gemini: ['GEMINI.md'],
30
- cursor: ['.cursorrules', '.cursor/rules/monomind.mdc'],
31
- vscode: ['.github/copilot-instructions.md'],
32
- copilot: ['.github/copilot-instructions.md'],
33
- opencode: ['AGENTS.md'],
34
- aider: ['.aider.conf.yml'],
35
- kiro: ['.kiro/steering/monomind.md'],
36
- trae: ['.trae/rules/monomind.md'],
37
- claw: ['.claw/config.md'],
38
- droid: ['DROID.md'],
39
- antigravity: ['.agents/rules/monomind.md'],
40
- hermes: ['HERMES.md'],
41
- codex: ['AGENTS.md'],
42
- };
5
+ import { renderCompatibilityMatrix } from '../platform-adapters/docs.js';
6
+ import { installPlatform, migrateLegacyInstall, planInstall, runPlatformsDoctor, uninstallPlatform, upgradePlatforms, } from '../platform-adapters/operations.js';
7
+ import { PLATFORM_IDS, PLATFORM_REGISTRY, resolvePlatformId, } from '../platform-adapters/registry.js';
8
+ export const SUPPORTED_PLATFORMS = PLATFORM_IDS;
43
9
  /**
44
- * YAML/MDC frontmatter to prepend for platform rule files that require it.
45
- * Cursor .mdc files use MDC YAML frontmatter; agy workspace rules use alwaysApply.
10
+ * Compatibility helper retained for callers that package portable skill roots.
11
+ * Adapter operations only materialize the router; distribution remains
12
+ * manifest-owned and never installs prompt-injection hooks.
46
13
  */
47
- const FILE_FRONTMATTER = {
48
- '.cursor/rules/monomind.mdc': [
49
- '---',
50
- 'description: Monomind monograph knowledge graph integration',
51
- 'alwaysApply: true',
52
- '---',
53
- ].join('\n'),
54
- '.agents/rules/monomind.md': [
55
- '---',
56
- 'name: monomind-integration',
57
- 'alwaysApply: true',
58
- 'description: Enable monomind monograph knowledge graph',
59
- '---',
60
- ].join('\n'),
61
- };
62
- const MONOMIND_BLOCK_START = '<!-- monomind:start -->';
63
- const MONOMIND_BLOCK_END = '<!-- monomind:end -->';
64
- function getMonomindInstructions(relPath) {
65
- const body = `${MONOMIND_BLOCK_START}
66
- # Monograph Knowledge Graph
67
-
68
- This repository is indexed by Monograph. Before starting complex tasks:
69
- - Use \`monograph_query\` to search the knowledge graph
70
- - Use \`monograph_neighbors\` to explore dependencies
71
- - Use \`monograph_impact\` to understand change blast radius
72
-
73
- Graph is at \`.monomind/monograph.db\`. Rebuild with: \`npx monograph build\`
74
-
75
- # Mastermind Skills
76
-
77
- If mastermind skills are installed, invoke the matching skill BEFORE any response or action.
78
- Even a 1% chance a skill applies means you must check first.
79
-
80
- Skills live in \`~/.agents/skills/\` (Codex/Gemini/Copilot/Cursor) or \`~/.claude/skills/\` (Claude Code).
81
- Load the relevant \`SKILL.md\` before acting on any non-trivial task.
82
- ${MONOMIND_BLOCK_END}
83
- `;
84
- const frontmatter = relPath ? FILE_FRONTMATTER[relPath] : undefined;
85
- return frontmatter ? `${frontmatter}\n\n${body}` : body;
86
- }
87
- // The mastermind-activate script (embedded so setup can write it to platform-specific locations).
88
- // Walks up from process.cwd() to find master.md, extracts the MASTERMIND PROTOCOL section,
89
- // and writes it to stdout for SessionStart hook injection.
90
- const MASTERMIND_ACTIVATE_SCRIPT = `'use strict';
91
- const fs = require('fs');
92
- const path = require('path');
93
-
94
- function findMasterPath() {
95
- const candidates = [];
96
- if (process.env.CLAUDE_PROJECT_DIR) candidates.push(process.env.CLAUDE_PROJECT_DIR);
97
- let dir = process.cwd();
98
- for (let i = 0; i < 12; i++) {
99
- candidates.push(dir);
100
- const parent = path.dirname(dir);
101
- if (parent === dir) break;
102
- dir = parent;
103
- }
104
- for (const base of candidates) {
105
- const p = path.join(base, '.claude', 'commands', 'mastermind', 'master.md');
106
- if (fs.existsSync(p)) return p;
107
- }
108
- return null;
109
- }
110
-
111
- function extractProtocol(content) {
112
- const marker = '\\n---\\n\\n**If $ARGUMENTS is empty:**';
113
- const idx = content.indexOf(marker);
114
- if (idx !== -1) return content.slice(0, idx).trim();
115
- const fallback = content.indexOf('\\n**MASTERMIND** —');
116
- if (fallback !== -1) return content.slice(0, fallback).trim();
117
- return content.trim();
118
- }
119
-
120
- const masterPath = findMasterPath();
121
- if (!masterPath) process.exit(0);
122
-
123
- try {
124
- let raw = fs.readFileSync(masterPath, 'utf8');
125
- const body = raw.replace(/^---[\\s\\S]*?---\\s*/, '');
126
- const protocol = extractProtocol(body);
127
- if (protocol) process.stdout.write(protocol + '\\n');
128
- } catch { process.exit(0); }
129
- `;
130
- // ──────────────────────────────────────────────────────────────
131
- // Skills packaging helpers
132
- // ──────────────────────────────────────────────────────────────
133
- /** Walk up from cwd to find the mastermind commands directory. */
134
- function findMastermindSourceDir() {
135
- let dir = process.cwd();
136
- for (let i = 0; i < 12; i++) {
137
- const candidate = join(dir, '.claude', 'commands', 'mastermind');
138
- if (existsSync(candidate))
139
- return candidate;
140
- const parent = dirname(dir);
141
- if (parent === dir)
142
- break;
143
- dir = parent;
144
- }
145
- return null;
146
- }
147
- /**
148
- * Copy mastermind skill files into targetDir as <skill-name>/SKILL.md packages.
149
- * Files starting with _ are internal helpers and are skipped.
150
- * master.md → targetDir/mastermind/SKILL.md (root routing skill)
151
- * build.md → targetDir/mastermind-build/SKILL.md
152
- *
153
- * Also copies the references/ subdir alongside mastermind/SKILL.md so
154
- * platforms that follow relative links (e.g. agy's antigravity-tools.md) can resolve them.
155
- */
156
- function installMastermindSkills(targetDir, sourceDir) {
14
+ export function installMastermindSkills(targetDir, sourceDir) {
157
15
  const written = [];
158
- const files = readdirSync(sourceDir).filter((f) => f.endsWith('.md') && !f.startsWith('_'));
159
- for (const file of files) {
160
- const name = basename(file, '.md');
161
- const skillDir = name === 'master' ? join(targetDir, 'mastermind') : join(targetDir, `mastermind-${name}`);
162
- const destFile = join(skillDir, 'SKILL.md');
163
- if (!existsSync(destFile)) {
164
- mkdirSync(skillDir, { recursive: true });
165
- const content = readFileSync(join(sourceDir, file), 'utf8');
166
- writeFileSync(destFile, content, 'utf8');
167
- written.push(destFile);
168
- }
169
- // Copy references/ alongside the mastermind umbrella skill (checked independently)
170
- if (name === 'master') {
171
- const refSrc = join(sourceDir, 'references');
172
- if (existsSync(refSrc)) {
173
- const refDest = join(skillDir, 'references');
174
- mkdirSync(refDest, { recursive: true });
175
- for (const ref of readdirSync(refSrc).filter((f) => f.endsWith('.md'))) {
176
- const destRef = join(refDest, ref);
177
- if (!existsSync(destRef)) {
178
- writeFileSync(destRef, readFileSync(join(refSrc, ref), 'utf8'), 'utf8');
179
- written.push(destRef);
180
- }
181
- }
182
- }
16
+ for (const source of readdirSync(sourceDir).filter((file) => file.endsWith('.md') && !file.startsWith('_'))) {
17
+ const name = basename(source, '.md');
18
+ const skillName = name === 'master' ? 'mastermind' : `mastermind-${name}`;
19
+ const destination = join(targetDir, skillName, 'SKILL.md');
20
+ const content = '---\nname: ' +
21
+ skillName +
22
+ '\ndescription: "Mastermind ' +
23
+ name +
24
+ ' workflow."\n---\n\n' +
25
+ readFileSync(join(sourceDir, source), 'utf8');
26
+ const existing = existsSync(destination) ? readFileSync(destination, 'utf8') : '';
27
+ if (existing !== content) {
28
+ mkdirSync(join(targetDir, skillName), { recursive: true });
29
+ writeFileSync(destination, content, 'utf8');
30
+ written.push(destination);
183
31
  }
184
32
  }
185
33
  return written;
186
34
  }
187
- // ──────────────────────────────────────────────────────────────
188
- // Global setup helpers (platform-specific, user-level config)
189
- // ──────────────────────────────────────────────────────────────
190
- function setupCodex(activateScriptPath) {
191
- const home = homedir();
192
- const codexDir = join(home, '.codex');
193
- mkdirSync(codexDir, { recursive: true });
194
- // Write the activate script
195
- writeFileSync(activateScriptPath, MASTERMIND_ACTIVATE_SCRIPT, 'utf8');
196
- // Merge a [[hooks]] entry into ~/.codex/config.toml
197
- const configPath = join(codexDir, 'config.toml');
198
- const hookBlock = [
199
- '',
200
- '# monomind:start',
201
- '[[hooks]]',
202
- 'event = "SessionStart"',
203
- 'matcher = ""',
204
- '[[hooks.hooks]]',
205
- 'type = "command"',
206
- `command = "node ${activateScriptPath}"`,
207
- 'statusMessage = "Loading mastermind protocol"',
208
- 'timeout = 5000',
209
- '# monomind:end',
210
- ].join('\n');
211
- const config = existsSync(configPath) ? readFileSync(configPath, 'utf8') : '';
212
- const written = [];
213
- if (!config.includes('# monomind:start')) {
214
- writeFileSync(configPath, config + hookBlock, 'utf8');
215
- written.push(configPath, activateScriptPath);
216
- }
217
- // Install mastermind skills to ~/.agents/skills/ (shared cross-runtime dir)
218
- const sourceDir = findMastermindSourceDir();
219
- if (sourceDir) {
220
- const skillsDir = join(home, '.agents', 'skills');
221
- written.push(...installMastermindSkills(skillsDir, sourceDir));
222
- }
223
- return written;
35
+ function scopeFrom(ctx) {
36
+ return ctx.flags.scope === 'user' ? 'user' : 'project';
224
37
  }
225
- function setupCursor(activateScriptPath, repoPath) {
226
- // Write the activate script to ~/.cursor/
227
- writeFileSync(activateScriptPath, MASTERMIND_ACTIVATE_SCRIPT, 'utf8');
228
- // Merge SessionStart hook into .cursor/settings.json (project-level)
229
- const settingsPath = join(repoPath, '.cursor', 'settings.json');
230
- mkdirSync(dirname(settingsPath), { recursive: true });
231
- let settings = {};
232
- if (existsSync(settingsPath)) {
233
- try {
234
- settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
235
- }
236
- catch (e) {
237
- if (process.env.DEBUG || process.env.MONOMIND_DEBUG)
238
- console.error('[setupCursor] failed to parse existing .cursor/settings.json, overwriting with empty:', e);
239
- }
240
- }
241
- const hooks = settings.hooks ?? {};
242
- const sessionStart = hooks.SessionStart ?? [];
243
- const alreadyAdded = sessionStart.some((h) => typeof h === 'object' &&
244
- h !== null &&
245
- h.hooks?.some?.((inner) => typeof inner === 'object' &&
246
- inner !== null &&
247
- inner.command?.includes('monomind-activate')));
248
- const written = [];
249
- if (!alreadyAdded) {
250
- sessionStart.push({
251
- matcher: '',
252
- hooks: [{ type: 'command', command: `node "${activateScriptPath}"`, timeout: 5000 }],
253
- });
254
- hooks.SessionStart = sessionStart;
255
- settings.hooks = hooks;
256
- writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
257
- written.push(settingsPath, activateScriptPath);
258
- }
259
- // Install mastermind skills to ~/.agents/skills/ (Cursor shares the cross-runtime dir)
260
- const sourceDir = findMastermindSourceDir();
261
- if (sourceDir) {
262
- const skillsDir = join(homedir(), '.agents', 'skills');
263
- written.push(...installMastermindSkills(skillsDir, sourceDir));
264
- }
265
- return written;
38
+ function targetFrom(ctx) {
39
+ const raw = ctx.flags.platform;
40
+ return typeof raw === 'string' ? resolvePlatformId(raw) : undefined;
266
41
  }
267
- function setupAntigravity() {
268
- const home = homedir();
269
- const pluginDir = join(home, '.gemini', 'antigravity-cli', 'plugins', 'monomind');
270
- const rulesDir = join(pluginDir, 'rules');
271
- mkdirSync(rulesDir, { recursive: true });
272
- const pluginJson = join(pluginDir, 'plugin.json');
273
- const ruleFile = join(rulesDir, 'mastermind.md');
274
- const written = [];
275
- if (!existsSync(pluginJson)) {
276
- writeFileSync(pluginJson, JSON.stringify({
277
- name: 'monomind',
278
- version: '1.0.0',
279
- description: 'Monomind monograph knowledge graph and mastermind skills for Antigravity CLI',
280
- }, null, 2), 'utf8');
281
- written.push(pluginJson);
282
- }
283
- if (!existsSync(ruleFile)) {
284
- writeFileSync(ruleFile, [
285
- '---',
286
- 'name: monomind-integration',
287
- 'alwaysApply: true',
288
- 'description: Enable monomind monograph and mastermind skills',
289
- '---',
290
- '',
291
- '# Monomind Integration',
292
- '',
293
- 'This project uses Monograph for knowledge graph navigation.',
294
- 'Before starting complex tasks, use `view_file` on `.monomind/monograph.db` context',
295
- 'and invoke the relevant mastermind skill SKILL.md before acting.',
296
- '',
297
- '## Monograph',
298
- '- `monograph_query` — BM25 search the knowledge graph',
299
- '- `monograph_impact` — blast radius before any change',
300
- '- `monograph_neighbors` — explore dependencies',
301
- '',
302
- '## Mastermind Skills',
303
- 'Check `~/.gemini/skills/` for installed mastermind skills.',
304
- 'Load SKILL.md with `view_file` (IsSkillFile: true) before acting on non-trivial tasks.',
305
- ].join('\n'), 'utf8');
306
- written.push(ruleFile);
307
- }
308
- // Install mastermind skills to ~/.gemini/skills/ (agy's skill dir)
309
- const sourceDir = findMastermindSourceDir();
310
- if (sourceDir) {
311
- const skillsDir = join(home, '.gemini', 'skills');
312
- written.push(...installMastermindSkills(skillsDir, sourceDir));
42
+ function targetsFrom(ctx) {
43
+ if (ctx.flags.all === true)
44
+ return [...PLATFORM_IDS];
45
+ const target = targetFrom(ctx);
46
+ return target ? [target] : undefined;
47
+ }
48
+ function mutationRequest(ctx, platform) {
49
+ return {
50
+ platform,
51
+ all: ctx.flags.all === true,
52
+ scope: scopeFrom(ctx),
53
+ path: resolve(typeof ctx.flags.path === 'string' ? ctx.flags.path : ctx.cwd),
54
+ yes: ctx.flags.yes === true,
55
+ dryRun: ctx.flags['dry-run'] === true,
56
+ enableHooks: ctx.flags['enable-hooks'] === true,
57
+ enableBlockingHooks: ctx.flags['enable-blocking-hooks'] === true,
58
+ removeLegacy: ctx.flags['remove-legacy'] === true,
59
+ };
60
+ }
61
+ function resultError(reason) {
62
+ output.error(reason instanceof Error ? reason.message : String(reason));
63
+ return { success: false, exitCode: 1 };
64
+ }
65
+ function printResults(results) {
66
+ for (const result of results) {
67
+ result.changed.forEach((path) => output.success(`Updated ${path}`));
68
+ result.skipped.forEach((path) => output.info(`Skipped ${path}`));
69
+ result.diagnostics.forEach((diagnostic) => output.info(diagnostic));
313
70
  }
314
- return written;
315
71
  }
316
- async function handleSetup(ctx) {
317
- const platform = ctx.flags.platform;
318
- const all = ctx.flags.all;
319
- let repoPath;
72
+ function requireTargets(ctx) {
73
+ const targets = targetsFrom(ctx);
74
+ if (targets)
75
+ return targets;
76
+ return resultError(typeof ctx.flags.platform === 'string'
77
+ ? `Unknown platform: ${ctx.flags.platform}`
78
+ : 'Specify --platform <id|alias> or --all');
79
+ }
80
+ async function handlePlan(ctx) {
81
+ const targets = requireTargets(ctx);
82
+ if (!Array.isArray(targets))
83
+ return targets;
320
84
  try {
321
- repoPath = resolveRepoPath(ctx.flags.path ?? '.');
322
- }
323
- catch (err) {
324
- output.error(`Invalid --path: ${err instanceof Error ? err.message : String(err)}`);
325
- return { success: false, exitCode: 1 };
85
+ const plans = await Promise.all(targets.map((platform) => planInstall({ ...mutationRequest(ctx, platform), platform })));
86
+ if (ctx.flags.json === true)
87
+ output.printJson(plans);
88
+ else
89
+ plans.forEach((plan) => {
90
+ output.info(`Plan: ${plan.intents.length} artifact(s)`);
91
+ plan.diagnostics.forEach((diagnostic) => output.info(diagnostic));
92
+ });
93
+ return { success: true, data: plans };
326
94
  }
327
- if (!platform && !all) {
328
- output.error('Specify --platform <name> or --all');
329
- output.info(`Platforms with global setup: cursor, codex, antigravity`);
330
- return { success: false, exitCode: 1 };
95
+ catch (reason) {
96
+ return resultError(reason);
331
97
  }
332
- const targets = all ? [...SUPPORTED_PLATFORMS] : [platform];
333
- const home = homedir();
334
- let totalFiles = 0;
335
- for (const p of targets) {
336
- let written = [];
337
- try {
338
- if (p === 'codex') {
339
- written = setupCodex(join(home, '.codex', 'monomind-activate.cjs'));
340
- }
341
- else if (p === 'cursor') {
342
- written = setupCursor(join(home, '.cursor', 'monomind-activate.cjs'), repoPath);
343
- }
344
- else if (p === 'antigravity') {
345
- written = setupAntigravity();
346
- }
347
- else {
348
- output.info(`[${p}] No global setup needed — use \`platforms install\``);
349
- continue;
350
- }
351
- }
352
- catch (err) {
353
- output.error(`[${p}] Setup failed: ${err instanceof Error ? err.message : String(err)}`);
354
- continue;
355
- }
356
- if (written.length > 0) {
357
- for (const f of written)
358
- output.success(`[${p}] ✓ ${f}`);
359
- totalFiles += written.length;
360
- }
361
- else {
362
- output.info(`[${p}] Already set up — skipped`);
363
- }
364
- }
365
- output.success(`Done. ${totalFiles} file(s) written.`);
366
- return { success: true };
367
98
  }
368
- /**
369
- * Maximum size for a platform config file we will read or append to.
370
- * Platform config files (CLAUDE.md, .cursorrules, etc.) are never legitimately
371
- * larger than a few hundred KB — a 1 MB cap prevents OOM when the flag points
372
- * at an enormous file such as a binary or a DB dump.
373
- */
374
- const MAX_CONFIG_FILE_BYTES = 1 * 1024 * 1024; // 1 MB
375
- /**
376
- * Resolve and validate the user-supplied --path flag.
377
- *
378
- * SECURITY: the flag is attacker-controlled. Without validation an adversary can
379
- * pass --path /etc to overwrite system files, or --path "../../.." to escape
380
- * the project. We resolve to an absolute path and reject anything that isn't
381
- * a directory (or doesn't exist yet under a parent that does exist).
382
- * We do NOT further restrict the path to cwd because a legitimate use case is
383
- * "install into another repo at an absolute path", but we do require the
384
- * resolved path to be a directory (or the parent to exist) so that the caller
385
- * cannot aim the flag at a file.
386
- */
387
- function resolveRepoPath(rawPath) {
388
- // Prevent shell-injection via null bytes or unusual separators
389
- if (rawPath.includes('\0'))
390
- throw new Error('Invalid path: contains null byte');
391
- const resolved = resolve(rawPath);
392
- // If the path exists it must be a directory
393
- if (existsSync(resolved)) {
394
- const st = statSync(resolved);
395
- if (!st.isDirectory())
396
- throw new Error(`--path must be a directory, got a file: ${resolved}`);
99
+ async function handleInstall(ctx) {
100
+ const targets = requireTargets(ctx);
101
+ if (!Array.isArray(targets))
102
+ return targets;
103
+ try {
104
+ const results = ctx.flags.all === true
105
+ ? await upgradePlatforms(mutationRequest(ctx))
106
+ : [await installPlatform({ ...mutationRequest(ctx, targets[0]), platform: targets[0] })];
107
+ printResults(results);
108
+ return { success: true, data: results };
397
109
  }
398
- return resolved;
399
- }
400
- /**
401
- * Validate that fullPath is contained within repoRoot (path traversal defence).
402
- * relPath comes from our own PLATFORM_CONFIG_FILES map, but we validate anyway
403
- * to guard against future changes that introduce dynamic paths.
404
- */
405
- function assertWithinRoot(fullPath, repoRoot) {
406
- if (!fullPath.startsWith(`${repoRoot}/`) && fullPath !== repoRoot) {
407
- throw new Error(`Path escapes repository root: ${fullPath}`);
110
+ catch (reason) {
111
+ return resultError(reason);
408
112
  }
409
113
  }
410
- function installPlatform(platform, repoPath) {
411
- const files = PLATFORM_CONFIG_FILES[platform];
412
- const written = [];
413
- for (const relPath of files) {
414
- const instructions = getMonomindInstructions(relPath);
415
- const fullPath = resolve(join(repoPath, relPath));
416
- assertWithinRoot(fullPath, repoPath);
417
- const dir = dirname(fullPath);
418
- mkdirSync(dir, { recursive: true });
419
- if (existsSync(fullPath)) {
420
- // Guard against reading oversized files (e.g. the flag points at a data file)
421
- const fileStat = statSync(fullPath);
422
- if (fileStat.size > MAX_CONFIG_FILE_BYTES) {
423
- throw new Error(`Config file too large to read (${fileStat.size} bytes): ${relPath}`);
424
- }
425
- const existing = readFileSync(fullPath, 'utf8');
426
- if (existing.includes(MONOMIND_BLOCK_START))
427
- continue;
428
- writeFileSync(fullPath, `${existing}\n${instructions}`, 'utf8');
429
- }
430
- else {
431
- writeFileSync(fullPath, instructions, 'utf8');
432
- }
433
- written.push(relPath);
114
+ async function handleUpgrade(ctx) {
115
+ const targets = requireTargets(ctx);
116
+ if (!Array.isArray(targets))
117
+ return targets;
118
+ try {
119
+ const request = mutationRequest(ctx, ctx.flags.all === true ? undefined : targets[0]);
120
+ const results = await upgradePlatforms(request);
121
+ printResults(results);
122
+ return { success: true, data: results };
434
123
  }
435
- return written;
436
- }
437
- function uninstallPlatform(platform, repoPath) {
438
- const files = PLATFORM_CONFIG_FILES[platform];
439
- const blockRe = new RegExp(`\\n?${MONOMIND_BLOCK_START}[\\s\\S]*?${MONOMIND_BLOCK_END}\\n?`, 'g');
440
- const cleaned = [];
441
- for (const relPath of files) {
442
- const fullPath = resolve(join(repoPath, relPath));
443
- assertWithinRoot(fullPath, repoPath);
444
- if (!existsSync(fullPath))
445
- continue;
446
- // Guard against reading oversized files
447
- const fileStat = statSync(fullPath);
448
- if (fileStat.size > MAX_CONFIG_FILE_BYTES) {
449
- throw new Error(`Config file too large to read (${fileStat.size} bytes): ${relPath}`);
450
- }
451
- const content = readFileSync(fullPath, 'utf8');
452
- writeFileSync(fullPath, content.replace(blockRe, ''), 'utf8');
453
- cleaned.push(relPath);
124
+ catch (reason) {
125
+ return resultError(reason);
454
126
  }
455
- return cleaned;
456
127
  }
457
- async function handleInstall(ctx) {
458
- const platform = ctx.flags.platform;
459
- const all = ctx.flags.all;
460
- let repoPath;
128
+ async function handleUninstall(ctx) {
129
+ const targets = requireTargets(ctx);
130
+ if (!Array.isArray(targets))
131
+ return targets;
461
132
  try {
462
- repoPath = resolveRepoPath(ctx.flags.path ?? '.');
133
+ const request = mutationRequest(ctx, ctx.flags.all === true ? undefined : targets[0]);
134
+ const results = await uninstallPlatform(request);
135
+ printResults(results);
136
+ return { success: true, data: results };
463
137
  }
464
- catch (err) {
465
- output.error(`Invalid --path: ${err instanceof Error ? err.message : String(err)}`);
466
- return { success: false, exitCode: 1 };
467
- }
468
- if (!platform && !all) {
469
- output.error('Specify --platform <name> or --all');
470
- output.info(`Supported platforms: ${SUPPORTED_PLATFORMS.join(', ')}`);
471
- return { success: false, exitCode: 1 };
138
+ catch (reason) {
139
+ return resultError(reason);
472
140
  }
473
- const targets = all ? [...SUPPORTED_PLATFORMS] : [platform];
474
- const invalid = targets.filter((p) => !SUPPORTED_PLATFORMS.includes(p));
475
- if (invalid.length > 0) {
476
- output.error(`Unknown platform(s): ${invalid.join(', ')}`);
477
- output.info(`Supported platforms: ${SUPPORTED_PLATFORMS.join(', ')}`);
478
- return { success: false, exitCode: 1 };
141
+ }
142
+ async function handleDoctor(ctx) {
143
+ const raw = typeof ctx.flags.platform === 'string' ? ctx.flags.platform : undefined;
144
+ const platform = targetFrom(ctx);
145
+ if (raw && !platform)
146
+ return resultError(`Unknown platform: ${raw}`);
147
+ try {
148
+ const reports = await runPlatformsDoctor({
149
+ platform,
150
+ path: resolve(typeof ctx.flags.path === 'string' ? ctx.flags.path : ctx.cwd),
151
+ scope: scopeFrom(ctx),
152
+ });
153
+ if (ctx.flags.json === true)
154
+ output.printJson(reports);
155
+ else
156
+ reports.forEach((report) => {
157
+ const state = report.artifacts.map((artifact) => artifact.state).join(', ') || 'no declared artifacts';
158
+ output.info(`${report.platform}: ${state}`);
159
+ report.diagnostics.forEach((diagnostic) => output.info(diagnostic));
160
+ });
161
+ return { success: true, data: reports };
479
162
  }
480
- let totalFiles = 0;
481
- for (const p of targets) {
482
- let written;
483
- try {
484
- written = installPlatform(p, repoPath);
485
- }
486
- catch (err) {
487
- output.error(`[${p}] Install failed: ${err instanceof Error ? err.message : String(err)}`);
488
- continue;
489
- }
490
- if (written.length > 0) {
491
- output.success(`[${p}] Installed Monograph context → ${written.join(', ')}`);
492
- totalFiles += written.length;
493
- }
494
- else {
495
- output.info(`[${p}] Already installed — skipped`);
496
- }
163
+ catch (reason) {
164
+ return resultError(reason);
497
165
  }
498
- output.success(`Done. ${totalFiles} file(s) updated.`);
499
- return { success: true };
500
166
  }
501
- async function handleUninstall(ctx) {
502
- const platform = ctx.flags.platform;
503
- const all = ctx.flags.all;
504
- let repoPath;
167
+ async function handleSetup(ctx) {
168
+ const targets = requireTargets(ctx);
169
+ if (!Array.isArray(targets))
170
+ return targets;
171
+ output.info('platforms setup is deprecated and no longer writes SessionStart hooks or global plugins.');
172
+ output.info('Use platforms doctor, then platforms install --scope user --yes.');
505
173
  try {
506
- repoPath = resolveRepoPath(ctx.flags.path ?? '.');
174
+ const result = await migrateLegacyInstall({
175
+ ...mutationRequest(ctx, ctx.flags.all === true ? undefined : targets[0]),
176
+ dryRun: true,
177
+ });
178
+ printResults(result);
179
+ return { success: true, data: result };
507
180
  }
508
- catch (err) {
509
- output.error(`Invalid --path: ${err instanceof Error ? err.message : String(err)}`);
510
- return { success: false, exitCode: 1 };
181
+ catch (reason) {
182
+ return resultError(reason);
511
183
  }
512
- if (!platform && !all) {
513
- output.error('Specify --platform <name> or --all');
514
- output.info(`Supported platforms: ${SUPPORTED_PLATFORMS.join(', ')}`);
515
- return { success: false, exitCode: 1 };
184
+ }
185
+ async function handleDocs(ctx) {
186
+ const rendered = renderCompatibilityMatrix(PLATFORM_REGISTRY);
187
+ if (ctx.flags.check !== true) {
188
+ output.writeln(rendered);
189
+ return { success: true, data: rendered };
516
190
  }
517
- const targets = all ? [...SUPPORTED_PLATFORMS] : [platform];
518
- const invalid = targets.filter((p) => !SUPPORTED_PLATFORMS.includes(p));
519
- if (invalid.length > 0) {
520
- output.error(`Unknown platform(s): ${invalid.join(', ')}`);
521
- output.info(`Supported platforms: ${SUPPORTED_PLATFORMS.join(', ')}`);
191
+ const path = resolve(ctx.cwd, 'docs', 'platforms', 'compatibility.md');
192
+ if (!existsSync(path) || readFileSync(path, 'utf8') !== rendered) {
193
+ output.error('Platform compatibility documentation is stale; regenerate it from the platform registry.');
522
194
  return { success: false, exitCode: 1 };
523
195
  }
524
- let totalFiles = 0;
525
- for (const p of targets) {
526
- let cleaned;
527
- try {
528
- cleaned = uninstallPlatform(p, repoPath);
529
- }
530
- catch (err) {
531
- output.error(`[${p}] Uninstall failed: ${err instanceof Error ? err.message : String(err)}`);
532
- continue;
533
- }
534
- if (cleaned.length > 0) {
535
- output.success(`[${p}] Removed Monograph context from ${cleaned.join(', ')}`);
536
- totalFiles += cleaned.length;
537
- }
538
- else {
539
- output.info(`[${p}] Nothing to remove — skipped`);
540
- }
541
- }
542
- output.success(`Done. ${totalFiles} file(s) cleaned.`);
196
+ output.success('Platform compatibility documentation is current.');
543
197
  return { success: true };
544
198
  }
545
- const platformOptions = [
546
- {
547
- name: 'platform',
548
- description: `Target platform (${SUPPORTED_PLATFORMS.join(', ')})`,
549
- type: 'string',
550
- },
551
- {
552
- name: 'all',
553
- description: 'Apply to all 14 supported platforms',
554
- type: 'boolean',
555
- default: false,
556
- },
199
+ const targetOptions = [
200
+ { name: 'platform', description: 'Target platform id or legacy alias', type: 'string' },
201
+ { name: 'all', description: 'Apply to all supported platforms', type: 'boolean', default: false },
202
+ { name: 'path', description: 'Project root', type: 'string', default: '.' },
557
203
  {
558
- name: 'path',
559
- description: 'Path to the repository root (default: current directory)',
204
+ name: 'scope',
205
+ description: 'Scope',
560
206
  type: 'string',
561
- default: '.',
207
+ choices: ['project', 'user'],
208
+ default: 'project',
562
209
  },
563
210
  ];
211
+ const mutationOptions = [
212
+ ...targetOptions,
213
+ { name: 'yes', description: 'Authorize user-scope mutation', type: 'boolean', default: false },
214
+ { name: 'dry-run', description: 'Plan without writing files', type: 'boolean', default: false },
215
+ ];
564
216
  export const platformsCommand = {
565
217
  name: 'platforms',
566
- description: 'Install or uninstall Monograph context instructions for AI coding platforms',
218
+ description: 'Plan and apply evidence-gated Monomind platform integrations',
567
219
  subcommands: [
220
+ {
221
+ name: 'plan',
222
+ description: 'Render a read-only adapter plan',
223
+ options: [
224
+ ...targetOptions,
225
+ { name: 'json', description: 'Print JSON', type: 'boolean', default: false },
226
+ ],
227
+ action: handlePlan,
228
+ },
568
229
  {
569
230
  name: 'install',
570
- description: 'Inject Monograph knowledge-graph instructions into platform config file(s)',
571
- options: platformOptions,
572
- examples: [
573
- {
574
- command: 'monomind platforms install --platform claude',
575
- description: 'Install for Claude',
576
- },
231
+ description: 'Apply a platform plan',
232
+ options: [
233
+ ...mutationOptions,
577
234
  {
578
- command: 'monomind platforms install --all',
579
- description: 'Install for all 14 platforms',
235
+ name: 'enable-hooks',
236
+ description: 'Opt in to deterministic hooks',
237
+ type: 'boolean',
238
+ default: false,
580
239
  },
581
240
  {
582
- command: 'monomind platforms install --platform cursor --path /path/to/repo',
583
- description: 'Install for Cursor in a specific repo',
241
+ name: 'enable-blocking-hooks',
242
+ description: 'Permit blocking hook decisions',
243
+ type: 'boolean',
244
+ default: false,
584
245
  },
585
246
  ],
586
247
  action: handleInstall,
587
248
  },
249
+ {
250
+ name: 'upgrade',
251
+ description: 'Reapply managed platform artifacts',
252
+ options: mutationOptions,
253
+ action: handleUpgrade,
254
+ },
588
255
  {
589
256
  name: 'uninstall',
590
- description: 'Remove Monograph knowledge-graph instructions from platform config file(s)',
591
- options: platformOptions,
592
- examples: [
593
- {
594
- command: 'monomind platforms uninstall --platform claude',
595
- description: 'Uninstall for Claude',
596
- },
257
+ description: 'Remove only Monomind-owned artifacts',
258
+ options: [
259
+ ...mutationOptions,
597
260
  {
598
- command: 'monomind platforms uninstall --all',
599
- description: 'Uninstall from all 14 platforms',
261
+ name: 'remove-legacy',
262
+ description: 'Remove marker-verified legacy artifacts',
263
+ type: 'boolean',
264
+ default: false,
600
265
  },
601
266
  ],
602
267
  action: handleUninstall,
603
268
  },
604
269
  {
605
- name: 'setup',
606
- description: 'Write global (user-level) SessionStart hooks and plugin packages for cursor, codex, and antigravity',
607
- options: platformOptions,
608
- examples: [
609
- {
610
- command: 'monomind platforms setup --platform codex',
611
- description: 'Wire SessionStart hook into ~/.codex/config.toml',
612
- },
613
- {
614
- command: 'monomind platforms setup --platform cursor',
615
- description: 'Wire SessionStart hook into .cursor/settings.json',
616
- },
617
- {
618
- command: 'monomind platforms setup --platform antigravity',
619
- description: 'Install monomind plugin into ~/.gemini/antigravity-cli/plugins/',
620
- },
270
+ name: 'doctor',
271
+ description: 'Inspect platform state without writes',
272
+ options: [
273
+ ...targetOptions,
274
+ { name: 'json', description: 'Print JSON', type: 'boolean', default: false },
621
275
  ],
622
- action: handleSetup,
623
- },
624
- ],
625
- examples: [
626
- {
627
- command: 'monomind platforms install --all',
628
- description: 'Install Monograph context for all platforms',
276
+ action: handleDoctor,
629
277
  },
630
278
  {
631
- command: 'monomind platforms setup --platform codex',
632
- description: 'Wire Codex SessionStart hook (run once per machine)',
279
+ name: 'setup',
280
+ description: 'Deprecated legacy detection shim',
281
+ options: targetOptions,
282
+ action: handleSetup,
633
283
  },
634
284
  {
635
- command: 'monomind platforms uninstall --platform cursor',
636
- description: 'Remove context from Cursor config',
285
+ name: 'docs',
286
+ description: 'Render or verify generated platform compatibility documentation',
287
+ options: [
288
+ { name: 'check', description: 'Fail when the checked-in matrix is stale', type: 'boolean' },
289
+ ],
290
+ action: handleDocs,
637
291
  },
638
292
  ],
639
293
  };