supermind-claude 2.1.1 → 4.0.2
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-plugin/plugin.json +21 -0
- package/README.md +34 -46
- package/agents/code-reviewer.md +81 -0
- package/cli/commands/doctor.js +415 -79
- package/cli/commands/install.js +16 -17
- package/cli/commands/skill.js +164 -0
- package/cli/commands/uninstall.js +32 -3
- package/cli/commands/update.js +25 -4
- package/cli/index.js +16 -4
- package/cli/lib/agents.js +413 -0
- package/cli/lib/executor.js +365 -0
- package/cli/lib/hooks.js +8 -1
- package/cli/lib/logger.js +1 -1
- package/cli/lib/planning.js +502 -0
- package/cli/lib/platform.js +4 -0
- package/cli/lib/plugin.js +127 -0
- package/cli/lib/settings.js +2 -40
- package/cli/lib/skills.js +39 -2
- package/cli/lib/vendor-skills.js +594 -0
- package/hooks/bash-permissions.js +196 -176
- package/hooks/context-monitor.js +79 -0
- package/hooks/improvement-logger.js +94 -0
- package/hooks/pre-merge-checklist.js +102 -0
- package/hooks/session-start.js +109 -5
- package/hooks/statusline-command.js +115 -29
- package/package.json +4 -2
- package/skills/anti-rationalization/SKILL.md +38 -0
- package/skills/brainstorming/SKILL.md +165 -0
- package/skills/code-review/SKILL.md +144 -0
- package/skills/executing-plans/SKILL.md +138 -0
- package/skills/finishing-branches/SKILL.md +144 -0
- package/skills/project/SKILL.md +533 -0
- package/skills/quick/SKILL.md +178 -0
- package/skills/supermind/SKILL.md +58 -4
- package/skills/supermind-init/SKILL.md +48 -2
- package/skills/systematic-debugging/SKILL.md +129 -0
- package/skills/tdd/SKILL.md +179 -0
- package/skills/using-git-worktrees/SKILL.md +138 -0
- package/skills/verification-before-completion/SKILL.md +54 -0
- package/skills/writing-plans/SKILL.md +169 -0
- package/templates/CLAUDE.md +124 -62
- package/cli/lib/plugins.js +0 -23
package/cli/commands/doctor.js
CHANGED
|
@@ -2,124 +2,460 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
|
-
const { PATHS } = require('../lib/platform');
|
|
5
|
+
const { PATHS, getPackageRoot } = require('../lib/platform');
|
|
6
6
|
const logger = require('../lib/logger');
|
|
7
|
-
const { SUPERMIND_PLUGINS } = require('../lib/settings');
|
|
8
7
|
const { getHookFiles } = require('../lib/hooks');
|
|
9
|
-
const { getSkillDirs } = require('../lib/skills');
|
|
8
|
+
const { getSkillDirs, getAgentFiles } = require('../lib/skills');
|
|
9
|
+
const { PLUGIN_KEY } = require('../lib/plugin');
|
|
10
|
+
const { readSettings } = require('../lib/settings');
|
|
10
11
|
const { version } = require('../../package.json');
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
const { GREEN, RED, BOLD, R } = require('../lib/logger');
|
|
14
|
+
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Helpers
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
function section(title) {
|
|
20
|
+
console.log(`\n ${BOLD}${title}${R}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function ok(label) {
|
|
24
|
+
logger.success(label);
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function fail(label, detail) {
|
|
29
|
+
logger.error(`${label}${detail ? ' — ' + detail : ''}`);
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Individual checks
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
function checkNode() {
|
|
38
|
+
const major = parseInt(process.versions.node.split('.')[0], 10);
|
|
39
|
+
return major >= 18
|
|
40
|
+
? ok(`Node.js v${process.versions.node} (>= 18 required)`)
|
|
41
|
+
: fail(`Node.js v${process.versions.node}`, '>= 18 required');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function checkClaudeHome() {
|
|
45
|
+
return fs.existsSync(PATHS.claudeHome)
|
|
46
|
+
? ok('~/.claude/ directory structure OK')
|
|
47
|
+
: fail('~/.claude/ directory missing');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function checkSettings() {
|
|
51
|
+
if (!fs.existsSync(PATHS.settings)) return fail('settings.json missing');
|
|
52
|
+
try {
|
|
53
|
+
JSON.parse(fs.readFileSync(PATHS.settings, 'utf-8'));
|
|
54
|
+
return ok('settings.json valid');
|
|
55
|
+
} catch (err) {
|
|
56
|
+
return fail('settings.json invalid', err.message);
|
|
17
57
|
}
|
|
18
|
-
return pass;
|
|
19
58
|
}
|
|
20
59
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
60
|
+
// Template
|
|
61
|
+
function checkTemplate() {
|
|
62
|
+
return fs.existsSync(path.join(PATHS.templatesDir, 'CLAUDE.md'))
|
|
63
|
+
? ok('CLAUDE.md template')
|
|
64
|
+
: fail('CLAUDE.md template missing');
|
|
65
|
+
}
|
|
24
66
|
|
|
25
|
-
|
|
26
|
-
|
|
67
|
+
// Sessions directory writable
|
|
68
|
+
function checkSessions() {
|
|
69
|
+
if (!fs.existsSync(PATHS.sessionsDir)) {
|
|
70
|
+
return fail('Sessions directory missing');
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
fs.accessSync(PATHS.sessionsDir, fs.constants.W_OK);
|
|
74
|
+
return ok('Sessions directory writable');
|
|
75
|
+
} catch (err) {
|
|
76
|
+
return fail('Sessions directory not writable', err.message);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
27
79
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
80
|
+
// Improvement log writable
|
|
81
|
+
function checkImprovementLog() {
|
|
82
|
+
try {
|
|
83
|
+
fs.appendFileSync(PATHS.improvementLog, '', { flag: 'a' });
|
|
84
|
+
return ok('Improvement log writable');
|
|
85
|
+
} catch (err) {
|
|
86
|
+
return fail('Improvement log not writable', err.message);
|
|
31
87
|
}
|
|
88
|
+
}
|
|
32
89
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
90
|
+
// Skills: verify all methodology skills installed with SKILL.md
|
|
91
|
+
function checkSkills() {
|
|
92
|
+
section('Skills');
|
|
93
|
+
let expectedDirs;
|
|
94
|
+
try {
|
|
95
|
+
expectedDirs = getSkillDirs();
|
|
96
|
+
} catch (err) {
|
|
97
|
+
logger.warn(`Could not enumerate skills from package: ${err.message}`);
|
|
98
|
+
expectedDirs = [
|
|
99
|
+
'supermind', 'quick', 'project', 'brainstorming', 'tdd',
|
|
100
|
+
'systematic-debugging', 'anti-rationalization', 'verification-before-completion',
|
|
101
|
+
'code-review', 'writing-plans', 'executing-plans', 'finishing-branches',
|
|
102
|
+
'using-git-worktrees', 'supermind-init', 'supermind-living-docs',
|
|
103
|
+
];
|
|
104
|
+
}
|
|
36
105
|
|
|
37
|
-
|
|
38
|
-
|
|
106
|
+
const missing = [];
|
|
107
|
+
for (const dir of expectedDirs) {
|
|
108
|
+
const skillPath = path.join(PATHS.skillsDir, dir);
|
|
109
|
+
const hasDir = fs.existsSync(skillPath);
|
|
110
|
+
const hasSkillMd = hasDir && fs.existsSync(path.join(skillPath, 'SKILL.md'));
|
|
111
|
+
if (!hasDir || !hasSkillMd) missing.push(dir);
|
|
112
|
+
}
|
|
39
113
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
114
|
+
const installed = expectedDirs.length - missing.length;
|
|
115
|
+
if (missing.length === 0) {
|
|
116
|
+
ok(`${installed}/${expectedDirs.length} skills installed`);
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
fail(`${installed}/${expectedDirs.length} skills installed — missing: ${missing.join(', ')}`);
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
43
122
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
123
|
+
// Agents: verify agent definitions exist
|
|
124
|
+
function checkAgents() {
|
|
125
|
+
section('Agents');
|
|
126
|
+
let expectedFiles;
|
|
127
|
+
try {
|
|
128
|
+
expectedFiles = getAgentFiles();
|
|
129
|
+
} catch (err) {
|
|
130
|
+
logger.warn(`Could not enumerate agents from package: ${err.message}`);
|
|
131
|
+
expectedFiles = ['code-reviewer.md'];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const missing = [];
|
|
135
|
+
for (const file of expectedFiles) {
|
|
136
|
+
if (!fs.existsSync(path.join(PATHS.agentsDir, file))) missing.push(file);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const installed = expectedFiles.length - missing.length;
|
|
140
|
+
if (missing.length === 0) {
|
|
141
|
+
ok(`${installed}/${expectedFiles.length} agents installed`);
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
fail(`${installed}/${expectedFiles.length} agents installed — missing: ${missing.join(', ')}`);
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Hooks: verify all 8 hooks exist and are registered in settings.json
|
|
149
|
+
function checkHooks() {
|
|
150
|
+
section('Hooks');
|
|
151
|
+
let expectedFiles;
|
|
152
|
+
try {
|
|
153
|
+
expectedFiles = getHookFiles();
|
|
154
|
+
} catch (err) {
|
|
155
|
+
logger.warn(`Could not enumerate hooks from package: ${err.message}`);
|
|
156
|
+
expectedFiles = [
|
|
157
|
+
'bash-permissions.js', 'session-start.js', 'session-end.js',
|
|
158
|
+
'cost-tracker.js', 'statusline-command.js', 'context-monitor.js',
|
|
159
|
+
'pre-merge-checklist.js', 'improvement-logger.js',
|
|
160
|
+
];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Check files on disk
|
|
164
|
+
const missingFiles = [];
|
|
165
|
+
for (const file of expectedFiles) {
|
|
166
|
+
if (!fs.existsSync(path.join(PATHS.hooksDir, file))) missingFiles.push(file);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Check registration in settings.json
|
|
170
|
+
const settings = readSettings();
|
|
171
|
+
if (!settings || Object.keys(settings).length === 0) {
|
|
172
|
+
if (missingFiles.length > 0) {
|
|
173
|
+
fail(`Hooks — missing files: ${missingFiles.join(', ')}`);
|
|
174
|
+
} else {
|
|
175
|
+
ok(`${expectedFiles.length}/${expectedFiles.length} hooks installed`);
|
|
176
|
+
}
|
|
177
|
+
logger.warn('Hook registration check skipped — settings.json empty or unreadable');
|
|
178
|
+
return missingFiles.length === 0;
|
|
179
|
+
}
|
|
180
|
+
const settingsJson = JSON.stringify(settings);
|
|
181
|
+
const unregistered = [];
|
|
182
|
+
for (const file of expectedFiles) {
|
|
183
|
+
// statusline-command.js is registered under statusLine, not hooks
|
|
184
|
+
if (file === 'statusline-command.js') {
|
|
185
|
+
if (!settings.statusLine || !JSON.stringify(settings.statusLine).includes(file)) {
|
|
186
|
+
unregistered.push(file);
|
|
187
|
+
}
|
|
188
|
+
} else if (!settingsJson.includes(file)) {
|
|
189
|
+
unregistered.push(file);
|
|
51
190
|
}
|
|
52
191
|
}
|
|
53
192
|
|
|
54
|
-
|
|
55
|
-
|
|
193
|
+
const fileOk = missingFiles.length === 0;
|
|
194
|
+
const regOk = unregistered.length === 0;
|
|
195
|
+
const total = expectedFiles.length;
|
|
196
|
+
|
|
197
|
+
if (fileOk && regOk) {
|
|
198
|
+
ok(`${total}/${total} hooks installed and registered`);
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
const issues = [];
|
|
202
|
+
if (!fileOk) issues.push(`missing files: ${missingFiles.join(', ')}`);
|
|
203
|
+
if (!regOk) issues.push(`not registered: ${unregistered.join(', ')}`);
|
|
204
|
+
fail(`Hooks — ${issues.join('; ')}`);
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Context monitor: verify hook exists, optionally check metrics file
|
|
209
|
+
function checkContextMonitor() {
|
|
210
|
+
section('Context monitor');
|
|
211
|
+
const hookExists = fs.existsSync(path.join(PATHS.hooksDir, 'context-monitor.js'));
|
|
212
|
+
if (!hookExists) {
|
|
213
|
+
fail('context-monitor.js hook missing');
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const metricsPath = path.join(PATHS.claudeHome, 'context-metrics.json');
|
|
218
|
+
if (fs.existsSync(metricsPath)) {
|
|
219
|
+
ok('active (metrics file present)');
|
|
220
|
+
} else {
|
|
221
|
+
ok('installed (metrics written during active sessions)');
|
|
222
|
+
}
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Plugin manifest: verify registration and cached manifest
|
|
227
|
+
function checkPlugin() {
|
|
228
|
+
section('Plugin manifest');
|
|
229
|
+
|
|
230
|
+
const pluginsPath = path.join(PATHS.claudeHome, 'plugins', 'installed_plugins.json');
|
|
231
|
+
if (!fs.existsSync(pluginsPath)) {
|
|
232
|
+
return fail('not registered — installed_plugins.json missing');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
let registry;
|
|
56
236
|
try {
|
|
57
|
-
|
|
237
|
+
registry = JSON.parse(fs.readFileSync(pluginsPath, 'utf-8'));
|
|
58
238
|
} catch (err) {
|
|
59
|
-
|
|
60
|
-
expectedHooks = [];
|
|
239
|
+
return fail('installed_plugins.json invalid', err.message);
|
|
61
240
|
}
|
|
62
|
-
|
|
63
|
-
|
|
241
|
+
|
|
242
|
+
const entry = registry.plugins && registry.plugins[PLUGIN_KEY];
|
|
243
|
+
if (!entry || !Array.isArray(entry) || entry.length === 0) {
|
|
244
|
+
return fail('not registered in installed_plugins.json');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const installPath = entry[0].installPath;
|
|
248
|
+
if (!installPath) {
|
|
249
|
+
return fail('plugin registry entry missing installPath');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const manifestPath = path.join(installPath, '.claude-plugin', 'plugin.json');
|
|
253
|
+
if (!fs.existsSync(manifestPath)) {
|
|
254
|
+
return fail('manifest missing from cache');
|
|
64
255
|
}
|
|
65
256
|
|
|
66
|
-
// Skills present
|
|
67
|
-
let expectedSkills;
|
|
68
257
|
try {
|
|
69
|
-
|
|
258
|
+
JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
|
|
259
|
+
return ok('valid');
|
|
70
260
|
} catch (err) {
|
|
71
|
-
|
|
72
|
-
expectedSkills = [];
|
|
261
|
+
return fail('plugin.json manifest invalid', err.message);
|
|
73
262
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Executor engine: verify core modules exist in package
|
|
266
|
+
function checkExecutorEngine() {
|
|
267
|
+
section('Executor engine');
|
|
268
|
+
const root = getPackageRoot();
|
|
269
|
+
const modules = ['cli/lib/executor.js', 'cli/lib/agents.js', 'cli/lib/planning.js'];
|
|
270
|
+
const missing = modules.filter(m => !fs.existsSync(path.join(root, m)));
|
|
271
|
+
|
|
272
|
+
if (missing.length === 0) {
|
|
273
|
+
return ok('modules present');
|
|
77
274
|
}
|
|
275
|
+
return fail(`missing: ${missing.join(', ')}`);
|
|
276
|
+
}
|
|
78
277
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
278
|
+
// Safety layer: verify blocklist model
|
|
279
|
+
function checkSafety() {
|
|
280
|
+
section('Safety layer');
|
|
281
|
+
const hookPath = path.join(PATHS.hooksDir, 'bash-permissions.js');
|
|
282
|
+
if (!fs.existsSync(hookPath)) {
|
|
283
|
+
return fail('bash-permissions.js not found');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
let content;
|
|
287
|
+
try {
|
|
288
|
+
content = fs.readFileSync(hookPath, 'utf-8');
|
|
289
|
+
} catch (err) {
|
|
290
|
+
return fail('bash-permissions.js unreadable', err.message);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const blocklist = content.includes('BLOCKED') || content.includes('blocklist');
|
|
294
|
+
if (!blocklist) {
|
|
295
|
+
return fail('bash-permissions.js does not use blocklist model');
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return ok('blocklist model');
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// .planning/ check: project-specific, not an error if absent
|
|
302
|
+
function checkPlanning() {
|
|
303
|
+
section('Planning');
|
|
304
|
+
const projectDir = process.env.PROJECT_DIR || process.cwd();
|
|
305
|
+
const planningDir = path.join(projectDir, '.planning');
|
|
306
|
+
|
|
307
|
+
if (!fs.existsSync(planningDir)) {
|
|
308
|
+
return ok('no active session');
|
|
86
309
|
}
|
|
87
310
|
|
|
88
|
-
|
|
89
|
-
run('CLAUDE.md template', fs.existsSync(path.join(PATHS.templatesDir, 'CLAUDE.md')));
|
|
311
|
+
let allOk = true;
|
|
90
312
|
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
313
|
+
// Verify roadmap.md — read once, reuse for active phase detection
|
|
314
|
+
const roadmapPath = path.join(planningDir, 'roadmap.md');
|
|
315
|
+
let roadmapContent = null;
|
|
316
|
+
if (fs.existsSync(roadmapPath)) {
|
|
94
317
|
try {
|
|
95
|
-
fs.
|
|
96
|
-
|
|
97
|
-
|
|
318
|
+
roadmapContent = fs.readFileSync(roadmapPath, 'utf-8');
|
|
319
|
+
ok('roadmap.md present');
|
|
320
|
+
} catch (err) {
|
|
321
|
+
fail('roadmap.md unreadable', err.message);
|
|
322
|
+
allOk = false;
|
|
98
323
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
324
|
+
} else {
|
|
325
|
+
fail('roadmap.md missing from .planning/');
|
|
326
|
+
allOk = false;
|
|
327
|
+
}
|
|
102
328
|
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
329
|
+
// Verify config.json
|
|
330
|
+
const configPath = path.join(planningDir, 'config.json');
|
|
331
|
+
if (fs.existsSync(configPath)) {
|
|
332
|
+
try {
|
|
333
|
+
JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
334
|
+
ok('config.json valid');
|
|
335
|
+
} catch (err) {
|
|
336
|
+
fail('config.json invalid', err.message);
|
|
337
|
+
allOk = false;
|
|
338
|
+
}
|
|
339
|
+
} else {
|
|
340
|
+
fail('config.json missing from .planning/');
|
|
341
|
+
allOk = false;
|
|
110
342
|
}
|
|
111
343
|
|
|
112
|
-
//
|
|
344
|
+
// Report active phase if detectable
|
|
345
|
+
if (roadmapContent) {
|
|
346
|
+
const activeMatch = roadmapContent.match(/\|\s*(\d+)\s*\|[^|]*\|\s*(?:in.progress|active|executing)/i);
|
|
347
|
+
if (activeMatch) {
|
|
348
|
+
logger.info(`Active phase: ${activeMatch[1]}`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return allOk;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Version marker
|
|
356
|
+
function checkVersion() {
|
|
357
|
+
section('Version');
|
|
113
358
|
let installedVersion = 'not found';
|
|
114
359
|
try {
|
|
115
360
|
installedVersion = fs.readFileSync(PATHS.versionFile, 'utf-8').trim();
|
|
116
361
|
} catch (err) {
|
|
117
|
-
if (err.code !== 'ENOENT') {
|
|
118
|
-
installedVersion = `error: ${err.message}`;
|
|
119
|
-
}
|
|
362
|
+
if (err.code !== 'ENOENT') installedVersion = `error: ${err.message}`;
|
|
120
363
|
}
|
|
121
|
-
run('Version marker', installedVersion === version, installedVersion !== version ? `installed: ${installedVersion}, package: ${version}` : undefined);
|
|
122
364
|
|
|
123
|
-
|
|
124
|
-
|
|
365
|
+
if (installedVersion === version) {
|
|
366
|
+
return ok(`v${version}`);
|
|
367
|
+
}
|
|
368
|
+
return fail(`Version mismatch — installed: ${installedVersion}, package: ${version}`);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Vendor skills (optional, returns failure count)
|
|
372
|
+
function checkVendorSkills() {
|
|
373
|
+
let vendorSkills;
|
|
374
|
+
try {
|
|
375
|
+
vendorSkills = require('../lib/vendor-skills');
|
|
376
|
+
} catch {
|
|
377
|
+
return 0; // Module not available — no vendor skills to check
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
try {
|
|
381
|
+
const result = vendorSkills.verifySkills();
|
|
382
|
+
if (result.valid.length === 0 && result.missing.length === 0) return 0;
|
|
383
|
+
section('Vendor skills');
|
|
384
|
+
let failures = 0;
|
|
385
|
+
for (const name of result.valid) { ok(name); }
|
|
386
|
+
for (const name of result.missing) { fail(name, 'directory not found'); failures++; }
|
|
387
|
+
return failures;
|
|
388
|
+
} catch (err) {
|
|
389
|
+
section('Vendor skills');
|
|
390
|
+
fail('Vendor skill verification failed', err.message);
|
|
391
|
+
return 1;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Docker (optional, warn only)
|
|
396
|
+
function checkDocker() {
|
|
397
|
+
try {
|
|
398
|
+
// Static command, no user input — safe to use execSync
|
|
399
|
+
require('child_process').execSync('docker compose version', { stdio: 'pipe', timeout: 5000 });
|
|
400
|
+
ok('Docker available');
|
|
401
|
+
} catch {
|
|
402
|
+
logger.warn('Docker not available (optional — needed for AIRIS mode)');
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// ---------------------------------------------------------------------------
|
|
407
|
+
// Main
|
|
408
|
+
// ---------------------------------------------------------------------------
|
|
409
|
+
|
|
410
|
+
module.exports = function doctor(flags) {
|
|
411
|
+
logger.banner();
|
|
412
|
+
console.log(' Running health checks...');
|
|
413
|
+
|
|
414
|
+
let failed = 0;
|
|
415
|
+
const run = (fn) => {
|
|
416
|
+
try {
|
|
417
|
+
if (!fn()) failed++;
|
|
418
|
+
} catch (err) {
|
|
419
|
+
fail(`${fn.name || 'check'} crashed`, err.message);
|
|
420
|
+
failed++;
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
// Foundation
|
|
425
|
+
run(checkNode);
|
|
426
|
+
run(checkClaudeHome);
|
|
427
|
+
run(checkSettings);
|
|
428
|
+
run(checkTemplate);
|
|
429
|
+
run(checkSessions);
|
|
430
|
+
run(checkImprovementLog);
|
|
431
|
+
|
|
432
|
+
// Components
|
|
433
|
+
run(checkSkills);
|
|
434
|
+
run(checkAgents);
|
|
435
|
+
run(checkHooks);
|
|
436
|
+
|
|
437
|
+
// Subsystems
|
|
438
|
+
run(checkContextMonitor);
|
|
439
|
+
run(checkPlugin);
|
|
440
|
+
run(checkExecutorEngine);
|
|
441
|
+
run(checkSafety);
|
|
442
|
+
|
|
443
|
+
// Project-specific
|
|
444
|
+
run(checkPlanning);
|
|
445
|
+
|
|
446
|
+
// Version
|
|
447
|
+
run(checkVersion);
|
|
448
|
+
|
|
449
|
+
// Optional (don't count as failures for overall health)
|
|
450
|
+
failed += checkVendorSkills();
|
|
451
|
+
checkDocker();
|
|
452
|
+
|
|
453
|
+
// Overall
|
|
454
|
+
console.log('');
|
|
455
|
+
if (failed === 0) {
|
|
456
|
+
console.log(` ${GREEN}${BOLD}Overall: healthy ✓${R}\n`);
|
|
457
|
+
} else {
|
|
458
|
+
console.log(` ${RED}${BOLD}Overall: ${failed} issue${failed === 1 ? '' : 's'} found${R}\n`);
|
|
459
|
+
process.exit(1);
|
|
460
|
+
}
|
|
125
461
|
};
|
package/cli/commands/install.js
CHANGED
|
@@ -5,10 +5,10 @@ const { PATHS, ensureDir } = require('../lib/platform');
|
|
|
5
5
|
const logger = require('../lib/logger');
|
|
6
6
|
const { readSettings, writeSettings, backupSettings, mergeSettings } = require('../lib/settings');
|
|
7
7
|
const { installHooks, getHookSettings } = require('../lib/hooks');
|
|
8
|
-
const { installSkills, removeLegacySkills } = require('../lib/skills');
|
|
9
|
-
const { getPluginDefaults } = require('../lib/plugins');
|
|
8
|
+
const { installSkills, removeLegacySkills, installAgents } = require('../lib/skills');
|
|
10
9
|
const { setupMcp } = require('../lib/mcp');
|
|
11
10
|
const { installTemplates } = require('../lib/templates');
|
|
11
|
+
const { installPlugin } = require('../lib/plugin');
|
|
12
12
|
const { version } = require('../../package.json');
|
|
13
13
|
|
|
14
14
|
module.exports = async function install(flags) {
|
|
@@ -20,6 +20,7 @@ module.exports = async function install(flags) {
|
|
|
20
20
|
ensureDir(PATHS.claudeHome);
|
|
21
21
|
ensureDir(PATHS.hooksDir);
|
|
22
22
|
ensureDir(PATHS.skillsDir);
|
|
23
|
+
ensureDir(PATHS.agentsDir);
|
|
23
24
|
ensureDir(PATHS.sessionsDir);
|
|
24
25
|
logger.success(`Claude home: ${PATHS.claudeHome}`);
|
|
25
26
|
|
|
@@ -34,10 +35,8 @@ module.exports = async function install(flags) {
|
|
|
34
35
|
backupSettings();
|
|
35
36
|
const existing = readSettings();
|
|
36
37
|
const hookSettings = getHookSettings();
|
|
37
|
-
const pluginDefaults = getPluginDefaults();
|
|
38
38
|
const defaults = {
|
|
39
39
|
...hookSettings,
|
|
40
|
-
...pluginDefaults,
|
|
41
40
|
alwaysThinkingEnabled: true,
|
|
42
41
|
effortLevel: 'high',
|
|
43
42
|
};
|
|
@@ -50,19 +49,15 @@ module.exports = async function install(flags) {
|
|
|
50
49
|
const hookFiles = installHooks();
|
|
51
50
|
logger.info(`${hookFiles.length} hooks installed`);
|
|
52
51
|
|
|
53
|
-
// Step 4: Skills
|
|
54
|
-
logger.step(4, TOTAL, 'Installing skills...');
|
|
52
|
+
// Step 4: Skills & agents
|
|
53
|
+
logger.step(4, TOTAL, 'Installing skills and agents...');
|
|
55
54
|
removeLegacySkills();
|
|
56
55
|
const skillDirs = installSkills();
|
|
57
|
-
|
|
56
|
+
const agentFiles = installAgents();
|
|
57
|
+
logger.info(`${skillDirs.length} skill directories, ${agentFiles.length} agent definitions installed`);
|
|
58
58
|
|
|
59
|
-
// Step 5:
|
|
60
|
-
logger.step(5, TOTAL, '
|
|
61
|
-
const pluginNames = Object.keys(pluginDefaults.enabledPlugins).map(k => k.split('@')[0]);
|
|
62
|
-
logger.success(pluginNames.join(', '));
|
|
63
|
-
|
|
64
|
-
// Step 6: MCP servers
|
|
65
|
-
logger.step(6, TOTAL, 'MCP server setup...');
|
|
59
|
+
// Step 5: MCP servers
|
|
60
|
+
logger.step(5, TOTAL, 'MCP server setup...');
|
|
66
61
|
const mcpConfig = await setupMcp(flags);
|
|
67
62
|
if (mcpConfig.mcpServers) {
|
|
68
63
|
merged = readSettings();
|
|
@@ -70,17 +65,21 @@ module.exports = async function install(flags) {
|
|
|
70
65
|
writeSettings(merged);
|
|
71
66
|
}
|
|
72
67
|
|
|
73
|
-
// Step
|
|
74
|
-
logger.step(
|
|
68
|
+
// Step 6: Templates
|
|
69
|
+
logger.step(6, TOTAL, 'Installing templates...');
|
|
75
70
|
installTemplates(mcpConfig.mode);
|
|
76
71
|
|
|
72
|
+
// Step 7: Plugin manifest
|
|
73
|
+
logger.step(7, TOTAL, 'Registering plugin...');
|
|
74
|
+
installPlugin();
|
|
75
|
+
|
|
77
76
|
// Write version marker
|
|
78
77
|
fs.writeFileSync(PATHS.versionFile, version);
|
|
79
78
|
|
|
80
79
|
// Summary
|
|
81
80
|
console.log(`\n${'\x1b[32m'}\u2713 Supermind v${version} installed successfully${'\x1b[0m'}\n`);
|
|
82
81
|
console.log(' Next steps:');
|
|
83
|
-
console.log(' 1. Restart Claude Code to activate
|
|
82
|
+
console.log(' 1. Restart Claude Code to activate hooks');
|
|
84
83
|
console.log(' 2. In any project, run /supermind-init to set up project docs');
|
|
85
84
|
console.log(' 3. Run: npx supermind-claude doctor to verify installation\n');
|
|
86
85
|
};
|