@monoes/monomindcli 2.9.24 → 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.
- package/.claude/helpers/control-start.cjs +15 -1
- package/.claude/helpers/handlers/edit-handler.cjs +3 -2
- package/.claude/helpers/handlers/route-handler.cjs +19 -4
- package/.claude/helpers/hook-handler.cjs +2 -0
- package/.claude/helpers/utils/monograph.cjs +8 -0
- package/.claude/skills/mastermind/SKILL.md +21 -0
- package/.claude/skills/mastermind/references/antigravity-tools.md +60 -0
- package/.claude/skills/mastermind/references/claude-code-tools.md +50 -0
- package/.claude/skills/mastermind/references/codex-tools.md +64 -0
- package/.claude/skills/mastermind/references/copilot-tools.md +49 -0
- package/.claude/skills/mastermind/references/gemini-tools.md +63 -0
- package/.claude/skills/mastermind/references/pi-tools.md +28 -0
- package/.claude/skills/mastermind-org/SKILL.md +16 -0
- package/dist/src/commands/browse.d.ts +2 -10
- package/dist/src/commands/browse.d.ts.map +1 -1
- package/dist/src/commands/browse.js +7 -2
- package/dist/src/commands/browse.js.map +1 -1
- package/dist/src/commands/doctor.d.ts.map +1 -1
- package/dist/src/commands/doctor.js +16 -1
- package/dist/src/commands/doctor.js.map +1 -1
- package/dist/src/commands/index.d.ts +1 -1
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/commands/index.js +10 -1
- package/dist/src/commands/index.js.map +1 -1
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +63 -5
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/mastermind.d.ts +10 -0
- package/dist/src/commands/mastermind.d.ts.map +1 -0
- package/dist/src/commands/mastermind.js +62 -0
- package/dist/src/commands/mastermind.js.map +1 -0
- package/dist/src/commands/platforms.d.ts +9 -7
- package/dist/src/commands/platforms.d.ts.map +1 -1
- package/dist/src/commands/platforms.js +225 -571
- package/dist/src/commands/platforms.js.map +1 -1
- package/dist/src/commands/status.d.ts.map +1 -1
- package/dist/src/commands/status.js +7 -1
- package/dist/src/commands/status.js.map +1 -1
- package/dist/src/commands/update.d.ts.map +1 -1
- package/dist/src/commands/update.js +22 -0
- package/dist/src/commands/update.js.map +1 -1
- package/dist/src/init/codex-generator.d.ts.map +1 -1
- package/dist/src/init/codex-generator.js +5 -3
- package/dist/src/init/codex-generator.js.map +1 -1
- package/dist/src/init/executor.d.ts +6 -0
- package/dist/src/init/executor.d.ts.map +1 -1
- package/dist/src/init/executor.js +32 -3
- package/dist/src/init/executor.js.map +1 -1
- package/dist/src/init/mcp-generator.d.ts.map +1 -1
- package/dist/src/init/mcp-generator.js +5 -40
- package/dist/src/init/mcp-generator.js.map +1 -1
- package/dist/src/init/shared.d.ts.map +1 -1
- package/dist/src/init/shared.js +6 -5
- package/dist/src/init/shared.js.map +1 -1
- package/dist/src/init/types.d.ts +4 -0
- package/dist/src/init/types.d.ts.map +1 -1
- package/dist/src/init/types.js.map +1 -1
- package/dist/src/init/upgrade.d.ts.map +1 -1
- package/dist/src/init/upgrade.js +11 -1
- package/dist/src/init/upgrade.js.map +1 -1
- package/dist/src/init/write-antigravity.d.ts.map +1 -1
- package/dist/src/init/write-antigravity.js +5 -50
- package/dist/src/init/write-antigravity.js.map +1 -1
- package/dist/src/init/write-claude.d.ts.map +1 -1
- package/dist/src/init/write-claude.js +4 -88
- package/dist/src/init/write-claude.js.map +1 -1
- package/dist/src/init/write-codex.d.ts.map +1 -1
- package/dist/src/init/write-codex.js +20 -12
- package/dist/src/init/write-codex.js.map +1 -1
- package/dist/src/init/write-kimicode.d.ts.map +1 -1
- package/dist/src/init/write-kimicode.js +4 -48
- package/dist/src/init/write-kimicode.js.map +1 -1
- package/dist/src/knowledge/document-pipeline.d.ts.map +1 -1
- package/dist/src/knowledge/document-pipeline.js +6 -4
- package/dist/src/knowledge/document-pipeline.js.map +1 -1
- package/dist/src/knowledge/eval/harness.d.ts.map +1 -1
- package/dist/src/knowledge/eval/harness.js +9 -11
- package/dist/src/knowledge/eval/harness.js.map +1 -1
- package/dist/src/mastermind/manifest-data.d.ts +10 -0
- package/dist/src/mastermind/manifest-data.d.ts.map +1 -0
- package/dist/src/mastermind/manifest-data.js +67 -0
- package/dist/src/mastermind/manifest-data.js.map +1 -0
- package/dist/src/mastermind/manifest.d.ts +22 -0
- package/dist/src/mastermind/manifest.d.ts.map +1 -0
- package/dist/src/mastermind/manifest.js +36 -0
- package/dist/src/mastermind/manifest.js.map +1 -0
- package/dist/src/mcp-client.d.ts.map +1 -1
- package/dist/src/mcp-client.js +2 -0
- package/dist/src/mcp-client.js.map +1 -1
- package/dist/src/mcp-tools/index.d.ts +1 -0
- package/dist/src/mcp-tools/index.d.ts.map +1 -1
- package/dist/src/mcp-tools/index.js +1 -0
- package/dist/src/mcp-tools/index.js.map +1 -1
- package/dist/src/mcp-tools/platforms-tools.d.ts +5 -0
- package/dist/src/mcp-tools/platforms-tools.d.ts.map +1 -0
- package/dist/src/mcp-tools/platforms-tools.js +38 -0
- package/dist/src/mcp-tools/platforms-tools.js.map +1 -0
- package/dist/src/memory/intelligence.d.ts.map +1 -1
- package/dist/src/memory/intelligence.js +54 -20
- package/dist/src/memory/intelligence.js.map +1 -1
- package/dist/src/memory/memory-bridge.d.ts.map +1 -1
- package/dist/src/memory/memory-bridge.js +3 -2
- package/dist/src/memory/memory-bridge.js.map +1 -1
- package/dist/src/memory/memory-kg.js +3 -3
- package/dist/src/memory/memory-kg.js.map +1 -1
- package/dist/src/monovector/diff-classifier.d.ts +2 -2
- package/dist/src/monovector/diff-classifier.d.ts.map +1 -1
- package/dist/src/monovector/diff-classifier.js.map +1 -1
- package/dist/src/orgrt/session.d.ts.map +1 -1
- package/dist/src/orgrt/session.js +54 -24
- package/dist/src/orgrt/session.js.map +1 -1
- package/dist/src/orgrt/task-dag.d.ts.map +1 -1
- package/dist/src/orgrt/task-dag.js +5 -1
- package/dist/src/orgrt/task-dag.js.map +1 -1
- package/dist/src/platform-adapters/core.d.ts +20 -0
- package/dist/src/platform-adapters/core.d.ts.map +1 -0
- package/dist/src/platform-adapters/core.js +34 -0
- package/dist/src/platform-adapters/core.js.map +1 -0
- package/dist/src/platform-adapters/discovery.d.ts +15 -0
- package/dist/src/platform-adapters/discovery.d.ts.map +1 -0
- package/dist/src/platform-adapters/discovery.js +64 -0
- package/dist/src/platform-adapters/discovery.js.map +1 -0
- package/dist/src/platform-adapters/docs.d.ts +4 -0
- package/dist/src/platform-adapters/docs.d.ts.map +1 -0
- package/dist/src/platform-adapters/docs.js +34 -0
- package/dist/src/platform-adapters/docs.js.map +1 -0
- package/dist/src/platform-adapters/hook-bridge.d.ts +44 -0
- package/dist/src/platform-adapters/hook-bridge.d.ts.map +1 -0
- package/dist/src/platform-adapters/hook-bridge.js +133 -0
- package/dist/src/platform-adapters/hook-bridge.js.map +1 -0
- package/dist/src/platform-adapters/merge.d.ts +32 -0
- package/dist/src/platform-adapters/merge.d.ts.map +1 -0
- package/dist/src/platform-adapters/merge.js +209 -0
- package/dist/src/platform-adapters/merge.js.map +1 -0
- package/dist/src/platform-adapters/migration.d.ts +31 -0
- package/dist/src/platform-adapters/migration.d.ts.map +1 -0
- package/dist/src/platform-adapters/migration.js +402 -0
- package/dist/src/platform-adapters/migration.js.map +1 -0
- package/dist/src/platform-adapters/operations.d.ts +23 -0
- package/dist/src/platform-adapters/operations.d.ts.map +1 -0
- package/dist/src/platform-adapters/operations.js +405 -0
- package/dist/src/platform-adapters/operations.js.map +1 -0
- package/dist/src/platform-adapters/registry.d.ts +9 -0
- package/dist/src/platform-adapters/registry.d.ts.map +1 -0
- package/dist/src/platform-adapters/registry.js +614 -0
- package/dist/src/platform-adapters/registry.js.map +1 -0
- package/dist/src/platform-adapters/renderers/agents.d.ts +5 -0
- package/dist/src/platform-adapters/renderers/agents.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/agents.js +46 -0
- package/dist/src/platform-adapters/renderers/agents.js.map +1 -0
- package/dist/src/platform-adapters/renderers/aider.d.ts +2 -0
- package/dist/src/platform-adapters/renderers/aider.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/aider.js +3 -0
- package/dist/src/platform-adapters/renderers/aider.js.map +1 -0
- package/dist/src/platform-adapters/renderers/antigravity.d.ts +2 -0
- package/dist/src/platform-adapters/renderers/antigravity.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/antigravity.js +3 -0
- package/dist/src/platform-adapters/renderers/antigravity.js.map +1 -0
- package/dist/src/platform-adapters/renderers/claude.d.ts +2 -0
- package/dist/src/platform-adapters/renderers/claude.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/claude.js +3 -0
- package/dist/src/platform-adapters/renderers/claude.js.map +1 -0
- package/dist/src/platform-adapters/renderers/codex.d.ts +2 -0
- package/dist/src/platform-adapters/renderers/codex.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/codex.js +3 -0
- package/dist/src/platform-adapters/renderers/codex.js.map +1 -0
- package/dist/src/platform-adapters/renderers/commands.d.ts +13 -0
- package/dist/src/platform-adapters/renderers/commands.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/commands.js +78 -0
- package/dist/src/platform-adapters/renderers/commands.js.map +1 -0
- package/dist/src/platform-adapters/renderers/copilot.d.ts +2 -0
- package/dist/src/platform-adapters/renderers/copilot.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/copilot.js +3 -0
- package/dist/src/platform-adapters/renderers/copilot.js.map +1 -0
- package/dist/src/platform-adapters/renderers/cursor.d.ts +2 -0
- package/dist/src/platform-adapters/renderers/cursor.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/cursor.js +3 -0
- package/dist/src/platform-adapters/renderers/cursor.js.map +1 -0
- package/dist/src/platform-adapters/renderers/droid.d.ts +2 -0
- package/dist/src/platform-adapters/renderers/droid.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/droid.js +3 -0
- package/dist/src/platform-adapters/renderers/droid.js.map +1 -0
- package/dist/src/platform-adapters/renderers/experimental.d.ts +6 -0
- package/dist/src/platform-adapters/renderers/experimental.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/experimental.js +9 -0
- package/dist/src/platform-adapters/renderers/experimental.js.map +1 -0
- package/dist/src/platform-adapters/renderers/factory.d.ts +14 -0
- package/dist/src/platform-adapters/renderers/factory.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/factory.js +53 -0
- package/dist/src/platform-adapters/renderers/factory.js.map +1 -0
- package/dist/src/platform-adapters/renderers/gemini.d.ts +2 -0
- package/dist/src/platform-adapters/renderers/gemini.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/gemini.js +3 -0
- package/dist/src/platform-adapters/renderers/gemini.js.map +1 -0
- package/dist/src/platform-adapters/renderers/hooks.d.ts +37 -0
- package/dist/src/platform-adapters/renderers/hooks.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/hooks.js +166 -0
- package/dist/src/platform-adapters/renderers/hooks.js.map +1 -0
- package/dist/src/platform-adapters/renderers/index.d.ts +8 -0
- package/dist/src/platform-adapters/renderers/index.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/index.js +39 -0
- package/dist/src/platform-adapters/renderers/index.js.map +1 -0
- package/dist/src/platform-adapters/renderers/instructions.d.ts +6 -0
- package/dist/src/platform-adapters/renderers/instructions.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/instructions.js +31 -0
- package/dist/src/platform-adapters/renderers/instructions.js.map +1 -0
- package/dist/src/platform-adapters/renderers/kimi.d.ts +2 -0
- package/dist/src/platform-adapters/renderers/kimi.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/kimi.js +3 -0
- package/dist/src/platform-adapters/renderers/kimi.js.map +1 -0
- package/dist/src/platform-adapters/renderers/kiro.d.ts +2 -0
- package/dist/src/platform-adapters/renderers/kiro.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/kiro.js +3 -0
- package/dist/src/platform-adapters/renderers/kiro.js.map +1 -0
- package/dist/src/platform-adapters/renderers/mcp.d.ts +29 -0
- package/dist/src/platform-adapters/renderers/mcp.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/mcp.js +69 -0
- package/dist/src/platform-adapters/renderers/mcp.js.map +1 -0
- package/dist/src/platform-adapters/renderers/openclaw.d.ts +2 -0
- package/dist/src/platform-adapters/renderers/openclaw.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/openclaw.js +3 -0
- package/dist/src/platform-adapters/renderers/openclaw.js.map +1 -0
- package/dist/src/platform-adapters/renderers/opencode.d.ts +2 -0
- package/dist/src/platform-adapters/renderers/opencode.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/opencode.js +3 -0
- package/dist/src/platform-adapters/renderers/opencode.js.map +1 -0
- package/dist/src/platform-adapters/renderers/skills.d.ts +11 -0
- package/dist/src/platform-adapters/renderers/skills.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/skills.js +60 -0
- package/dist/src/platform-adapters/renderers/skills.js.map +1 -0
- package/dist/src/platform-adapters/renderers/status.d.ts +23 -0
- package/dist/src/platform-adapters/renderers/status.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/status.js +63 -0
- package/dist/src/platform-adapters/renderers/status.js.map +1 -0
- package/dist/src/platform-adapters/renderers/vscode.d.ts +2 -0
- package/dist/src/platform-adapters/renderers/vscode.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/vscode.js +3 -0
- package/dist/src/platform-adapters/renderers/vscode.js.map +1 -0
- package/dist/src/platform-adapters/renderers/zed.d.ts +2 -0
- package/dist/src/platform-adapters/renderers/zed.d.ts.map +1 -0
- package/dist/src/platform-adapters/renderers/zed.js +3 -0
- package/dist/src/platform-adapters/renderers/zed.js.map +1 -0
- package/dist/src/platform-adapters/types.d.ts +105 -0
- package/dist/src/platform-adapters/types.d.ts.map +1 -0
- package/dist/src/platform-adapters/types.js +13 -0
- package/dist/src/platform-adapters/types.js.map +1 -0
- package/dist/src/platform-adapters/verification-ledger.d.ts +8 -0
- package/dist/src/platform-adapters/verification-ledger.d.ts.map +1 -0
- package/dist/src/platform-adapters/verification-ledger.js +24 -0
- package/dist/src/platform-adapters/verification-ledger.js.map +1 -0
- package/dist/src/ui/markdown.js +10 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/dist/src/ui/data/mastermind-sessions.json +0 -1
|
@@ -1,639 +1,293 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
*
|
|
45
|
-
*
|
|
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
|
-
|
|
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
|
|
159
|
-
|
|
160
|
-
const
|
|
161
|
-
const
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
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
|
|
226
|
-
|
|
227
|
-
|
|
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
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
-
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
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
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
|
|
328
|
-
|
|
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
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
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
|
-
|
|
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
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
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
|
-
|
|
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
|
|
458
|
-
const
|
|
459
|
-
|
|
460
|
-
|
|
128
|
+
async function handleUninstall(ctx) {
|
|
129
|
+
const targets = requireTargets(ctx);
|
|
130
|
+
if (!Array.isArray(targets))
|
|
131
|
+
return targets;
|
|
461
132
|
try {
|
|
462
|
-
|
|
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 (
|
|
465
|
-
|
|
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
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
return
|
|
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
|
-
|
|
481
|
-
|
|
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
|
|
502
|
-
const
|
|
503
|
-
|
|
504
|
-
|
|
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
|
-
|
|
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 (
|
|
509
|
-
|
|
510
|
-
return { success: false, exitCode: 1 };
|
|
181
|
+
catch (reason) {
|
|
182
|
+
return resultError(reason);
|
|
511
183
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
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
|
|
518
|
-
|
|
519
|
-
|
|
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
|
-
|
|
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
|
|
546
|
-
{
|
|
547
|
-
|
|
548
|
-
|
|
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: '
|
|
559
|
-
description: '
|
|
204
|
+
name: 'scope',
|
|
205
|
+
description: 'Scope',
|
|
560
206
|
type: 'string',
|
|
561
|
-
|
|
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: '
|
|
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: '
|
|
571
|
-
options:
|
|
572
|
-
|
|
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
|
-
|
|
579
|
-
description: '
|
|
235
|
+
name: 'enable-hooks',
|
|
236
|
+
description: 'Opt in to deterministic hooks',
|
|
237
|
+
type: 'boolean',
|
|
238
|
+
default: false,
|
|
580
239
|
},
|
|
581
240
|
{
|
|
582
|
-
|
|
583
|
-
description: '
|
|
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
|
|
591
|
-
options:
|
|
592
|
-
|
|
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
|
-
|
|
599
|
-
description: '
|
|
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: '
|
|
606
|
-
description: '
|
|
607
|
-
options:
|
|
608
|
-
|
|
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:
|
|
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
|
-
|
|
632
|
-
description: '
|
|
279
|
+
name: 'setup',
|
|
280
|
+
description: 'Deprecated legacy detection shim',
|
|
281
|
+
options: targetOptions,
|
|
282
|
+
action: handleSetup,
|
|
633
283
|
},
|
|
634
284
|
{
|
|
635
|
-
|
|
636
|
-
description: '
|
|
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
|
};
|