aios-core 4.0.4 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.aios-core/cli/commands/migrate/analyze.js +6 -6
- package/.aios-core/cli/commands/migrate/backup.js +2 -2
- package/.aios-core/cli/commands/migrate/execute.js +4 -4
- package/.aios-core/cli/commands/migrate/index.js +5 -5
- package/.aios-core/cli/commands/migrate/rollback.js +6 -6
- package/.aios-core/cli/commands/migrate/update-imports.js +2 -2
- package/.aios-core/cli/commands/migrate/validate.js +2 -2
- package/.aios-core/cli/commands/pro/index.js +52 -0
- package/.aios-core/cli/index.js +1 -1
- package/.aios-core/core/ids/registry-updater.js +29 -3
- package/.aios-core/core/migration/migration-config.yaml +2 -2
- package/.aios-core/core/migration/module-mapping.yaml +2 -2
- package/.aios-core/core/registry/README.md +2 -2
- package/.aios-core/core/synapse/context/context-builder.js +34 -0
- package/.aios-core/core/synapse/diagnostics/collectors/consistency-collector.js +168 -0
- package/.aios-core/core/synapse/diagnostics/collectors/hook-collector.js +129 -0
- package/.aios-core/core/synapse/diagnostics/collectors/manifest-collector.js +82 -0
- package/.aios-core/core/synapse/diagnostics/collectors/output-analyzer.js +134 -0
- package/.aios-core/core/synapse/diagnostics/collectors/pipeline-collector.js +75 -0
- package/.aios-core/core/synapse/diagnostics/collectors/quality-collector.js +252 -0
- package/.aios-core/core/synapse/diagnostics/collectors/relevance-matrix.js +174 -0
- package/.aios-core/core/synapse/diagnostics/collectors/safe-read-json.js +31 -0
- package/.aios-core/core/synapse/diagnostics/collectors/session-collector.js +102 -0
- package/.aios-core/core/synapse/diagnostics/collectors/timing-collector.js +126 -0
- package/.aios-core/core/synapse/diagnostics/collectors/uap-collector.js +83 -0
- package/.aios-core/core/synapse/diagnostics/report-formatter.js +484 -0
- package/.aios-core/core/synapse/diagnostics/synapse-diagnostics.js +95 -0
- package/.aios-core/core/synapse/engine.js +73 -20
- package/.aios-core/core/synapse/runtime/hook-runtime.js +60 -0
- package/.aios-core/core-config.yaml +6 -0
- package/.aios-core/data/agent-config-requirements.yaml +2 -2
- package/.aios-core/data/aios-kb.md +4 -4
- package/.aios-core/data/entity-registry.yaml +210 -10
- package/.aios-core/data/registry-update-log.jsonl +52 -0
- package/.aios-core/development/agents/architect.md +10 -10
- package/.aios-core/development/agents/devops.md +93 -50
- package/.aios-core/development/agents/qa.md +94 -40
- package/.aios-core/development/agents/ux-design-expert.md +25 -25
- package/.aios-core/development/scripts/activation-runtime.js +63 -0
- package/.aios-core/development/scripts/generate-greeting.js +9 -8
- package/.aios-core/development/scripts/unified-activation-pipeline.js +102 -2
- package/.aios-core/development/tasks/{db-expansion-pack-integration.md → db-squad-integration.md} +5 -5
- package/.aios-core/development/tasks/{integrate-expansion-pack.md → integrate-squad.md} +2 -2
- package/.aios-core/development/tasks/next.md +3 -3
- package/.aios-core/development/tasks/pr-automation.md +2 -2
- package/.aios-core/development/tasks/publish-npm.md +257 -0
- package/.aios-core/development/tasks/release-management.md +4 -4
- package/.aios-core/development/tasks/setup-github.md +1 -1
- package/.aios-core/development/tasks/squad-creator-migrate.md +1 -1
- package/.aios-core/development/tasks/squad-creator-sync-ide-command.md +14 -14
- package/.aios-core/development/tasks/update-aios.md +1 -1
- package/.aios-core/development/tasks/validate-next-story.md +99 -2
- package/.aios-core/docs/standards/AIOS-COLOR-PALETTE-QUICK-REFERENCE.md +1 -1
- package/.aios-core/docs/standards/AIOS-COLOR-PALETTE-V2.1.md +5 -5
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-COMPLETE.md +21 -21
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.2-SUMMARY.md +25 -25
- package/.aios-core/docs/standards/OPEN-SOURCE-VS-SERVICE-DIFFERENCES.md +4 -4
- package/.aios-core/docs/standards/QUALITY-GATES-SPECIFICATION.md +3 -3
- package/.aios-core/docs/standards/STANDARDS-INDEX.md +13 -13
- package/.aios-core/docs/standards/STORY-TEMPLATE-V2-SPECIFICATION.md +1 -1
- package/.aios-core/framework-config.yaml +4 -0
- package/.aios-core/infrastructure/scripts/codex-skills-sync/index.js +182 -0
- package/.aios-core/infrastructure/scripts/codex-skills-sync/validate.js +172 -0
- package/.aios-core/infrastructure/scripts/ide-sync/README.md +14 -0
- package/.aios-core/infrastructure/scripts/ide-sync/index.js +6 -0
- package/.aios-core/infrastructure/scripts/tool-resolver.js +4 -4
- package/.aios-core/infrastructure/scripts/validate-paths.js +142 -0
- package/.aios-core/infrastructure/templates/aios-sync.yaml.template +11 -11
- package/.aios-core/infrastructure/templates/github-workflows/README.md +1 -1
- package/.aios-core/install-manifest.yaml +193 -109
- package/.aios-core/local-config.yaml.template +2 -0
- package/.aios-core/manifests/agents.csv +29 -1
- package/.aios-core/manifests/tasks.csv +80 -3
- package/.aios-core/product/README.md +2 -2
- package/.aios-core/product/data/integration-patterns.md +1 -1
- package/.aios-core/product/templates/ide-rules/cline-rules.md +1 -1
- package/.aios-core/product/templates/ide-rules/codex-rules.md +65 -0
- package/.aios-core/product/templates/ide-rules/copilot-rules.md +1 -1
- package/.aios-core/product/templates/ide-rules/roo-rules.md +1 -1
- package/.aios-core/user-guide.md +15 -14
- package/.aios-core/workflow-intelligence/engine/output-formatter.js +1 -1
- package/.claude/hooks/synapse-engine.js +9 -20
- package/README.md +14 -7
- package/bin/aios-init.js +255 -184
- package/bin/aios-minimal.js +2 -2
- package/bin/aios.js +4 -4
- package/package.json +6 -1
- package/packages/aios-pro-cli/bin/aios-pro.js +75 -2
- package/packages/aios-pro-cli/package.json +5 -1
- package/packages/aios-pro-cli/src/recover.js +100 -0
- package/packages/installer/src/__tests__/performance-benchmark.js +382 -0
- package/packages/installer/src/config/ide-configs.js +12 -1
- package/packages/installer/src/config/templates/core-config-template.js +2 -2
- package/packages/installer/src/installer/aios-core-installer.js +2 -2
- package/packages/installer/src/installer/file-hasher.js +97 -0
- package/packages/installer/src/installer/post-install-validator.js +41 -1
- package/packages/installer/src/pro/pro-scaffolder.js +335 -0
- package/packages/installer/src/utils/aios-colors.js +2 -2
- package/packages/installer/src/wizard/feedback.js +1 -1
- package/packages/installer/src/wizard/ide-config-generator.js +2 -2
- package/packages/installer/src/wizard/index.js +58 -19
- package/packages/installer/src/wizard/pro-setup.js +931 -0
- package/packages/installer/src/wizard/questions.js +20 -14
- package/packages/installer/src/wizard/validators.js +1 -1
- package/scripts/code-intel-health-check.js +343 -0
- package/scripts/package-synapse.js +323 -0
- package/scripts/validate-package-completeness.js +317 -0
|
@@ -186,26 +186,30 @@ function getEnvironmentQuestions() {
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
/**
|
|
189
|
-
* Get
|
|
189
|
+
* Get Squad selection questions
|
|
190
190
|
*
|
|
191
|
-
* Available
|
|
192
|
-
* -
|
|
191
|
+
* Available squads for v4.0:
|
|
192
|
+
* - squad-creator: Tools to create custom squads
|
|
193
193
|
* - etl: ETL pipeline for knowledge base creation
|
|
194
194
|
*
|
|
195
|
+
* Note: This function is currently DISABLED. Squad selection is handled
|
|
196
|
+
* directly in aios-init.js using the squads/ directory.
|
|
197
|
+
*
|
|
195
198
|
* @returns {Object[]} Array of inquirer question objects
|
|
199
|
+
* @deprecated Use squads/ directory directly in aios-init.js
|
|
196
200
|
*/
|
|
197
|
-
function
|
|
201
|
+
function getSquadQuestions() {
|
|
198
202
|
return [
|
|
199
203
|
{
|
|
200
204
|
type: 'checkbox',
|
|
201
|
-
name: '
|
|
202
|
-
message: colors.primary('Select
|
|
205
|
+
name: 'selectedSquads',
|
|
206
|
+
message: colors.primary('Select Squads to install (optional):'),
|
|
203
207
|
choices: [
|
|
204
208
|
{
|
|
205
209
|
name:
|
|
206
|
-
colors.highlight('
|
|
207
|
-
colors.dim(' - Tools to create custom
|
|
208
|
-
value: '
|
|
210
|
+
colors.highlight('squad-creator') +
|
|
211
|
+
colors.dim(' - Tools to create custom squads'),
|
|
212
|
+
value: 'squad-creator',
|
|
209
213
|
checked: false,
|
|
210
214
|
},
|
|
211
215
|
{
|
|
@@ -215,7 +219,7 @@ function getExpansionPackQuestions() {
|
|
|
215
219
|
},
|
|
216
220
|
],
|
|
217
221
|
validate: () => {
|
|
218
|
-
// Allow empty selection (user can skip
|
|
222
|
+
// Allow empty selection (user can skip squad installation)
|
|
219
223
|
return true;
|
|
220
224
|
},
|
|
221
225
|
},
|
|
@@ -277,9 +281,9 @@ function buildQuestionSequence(_context = {}) {
|
|
|
277
281
|
// TODO: Remove entirely in future version - each project has unique MCP needs
|
|
278
282
|
// questions.push(...getMCPQuestions());
|
|
279
283
|
|
|
280
|
-
//
|
|
281
|
-
// TODO:
|
|
282
|
-
// questions.push(...
|
|
284
|
+
// Squad Selection - DISABLED: Handled directly in aios-init.js
|
|
285
|
+
// TODO: Consider removing getSquadQuestions() entirely in future version
|
|
286
|
+
// questions.push(...getSquadQuestions());
|
|
283
287
|
|
|
284
288
|
// Tech Preset Selection
|
|
285
289
|
questions.push(...getTechPresetQuestion());
|
|
@@ -320,7 +324,9 @@ module.exports = {
|
|
|
320
324
|
getProjectTypeQuestion,
|
|
321
325
|
getIDEQuestions,
|
|
322
326
|
getMCPQuestions,
|
|
323
|
-
|
|
327
|
+
getSquadQuestions,
|
|
328
|
+
// Backward compat alias (deprecated)
|
|
329
|
+
getExpansionPackQuestions: getSquadQuestions,
|
|
324
330
|
getTechPresetQuestion,
|
|
325
331
|
getEnvironmentQuestions,
|
|
326
332
|
getPackageManagerQuestion,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* OWASP-compliant validators for all wizard inputs
|
|
5
5
|
* Protects against: command injection, path traversal, XSS, buffer overflow
|
|
6
6
|
*
|
|
7
|
-
* @see docs/stories/
|
|
7
|
+
* @see docs/stories/v4.0.4/sprint-1/story-1.2-interactive-wizard-foundation.md
|
|
8
8
|
* @module wizard/validators
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Code Intelligence Health Check
|
|
5
|
+
*
|
|
6
|
+
* Validates that the Code Graph MCP provider is installed, responsive,
|
|
7
|
+
* and its tools are operational. Outputs structured JSON for consumption
|
|
8
|
+
* by NOG-1 abstraction layer and other automation.
|
|
9
|
+
*
|
|
10
|
+
* Usage: node scripts/code-intel-health-check.js [--smoke] [--project-root <path>]
|
|
11
|
+
*
|
|
12
|
+
* Flags:
|
|
13
|
+
* --smoke Run smoke tests with real tool calls
|
|
14
|
+
* --project-root Override project root (default: process.cwd())
|
|
15
|
+
*
|
|
16
|
+
* Exit codes:
|
|
17
|
+
* 0 = available (all checks pass)
|
|
18
|
+
* 1 = degraded (some tools unavailable)
|
|
19
|
+
* 2 = unavailable (server not responding)
|
|
20
|
+
*
|
|
21
|
+
* @story NOG-0
|
|
22
|
+
* @agent @devops (Gage)
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const { execFile } = require('node:child_process')
|
|
26
|
+
const { promisify } = require('node:util')
|
|
27
|
+
const { existsSync, readFileSync } = require('node:fs')
|
|
28
|
+
const { resolve, join } = require('node:path')
|
|
29
|
+
|
|
30
|
+
const execFileAsync = promisify(execFile)
|
|
31
|
+
|
|
32
|
+
const RESPONSE_TIMEOUT_MS = 5000
|
|
33
|
+
const EXPECTED_TOOLS = [
|
|
34
|
+
'get_usage_guide',
|
|
35
|
+
'analyze_codebase',
|
|
36
|
+
'find_definition',
|
|
37
|
+
'find_references',
|
|
38
|
+
'find_callers',
|
|
39
|
+
'find_callees',
|
|
40
|
+
'complexity_analysis',
|
|
41
|
+
'dependency_analysis',
|
|
42
|
+
'project_statistics'
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
function parseArgs() {
|
|
46
|
+
const args = process.argv.slice(2)
|
|
47
|
+
return {
|
|
48
|
+
smoke: args.includes('--smoke'),
|
|
49
|
+
projectRoot: getArgValue(args, '--project-root') || process.cwd()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getArgValue(args, flag) {
|
|
54
|
+
const idx = args.indexOf(flag)
|
|
55
|
+
if (idx === -1 || idx + 1 >= args.length) return null
|
|
56
|
+
return args[idx + 1]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function checkBinaryInstalled() {
|
|
60
|
+
try {
|
|
61
|
+
const { stdout } = await execFileAsync('code-graph-mcp', ['--help'], {
|
|
62
|
+
timeout: RESPONSE_TIMEOUT_MS
|
|
63
|
+
})
|
|
64
|
+
return { installed: true, output: stdout.trim() }
|
|
65
|
+
} catch (error) {
|
|
66
|
+
return {
|
|
67
|
+
installed: false,
|
|
68
|
+
error: error.code === 'ENOENT'
|
|
69
|
+
? 'code-graph-mcp binary not found in PATH'
|
|
70
|
+
: `Binary check failed: ${error.message}`
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function checkMcpConfig(projectRoot) {
|
|
76
|
+
const mcpJsonPath = join(projectRoot, '.mcp.json')
|
|
77
|
+
if (!existsSync(mcpJsonPath)) {
|
|
78
|
+
return { configured: false, error: '.mcp.json not found' }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const config = JSON.parse(readFileSync(mcpJsonPath, 'utf-8'))
|
|
83
|
+
const servers = config.mcpServers || {}
|
|
84
|
+
const codeGraphEntry = servers['code-graph'] || servers['code-graph-mcp']
|
|
85
|
+
|
|
86
|
+
if (!codeGraphEntry) {
|
|
87
|
+
return { configured: false, error: 'No code-graph entry in .mcp.json mcpServers' }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
configured: true,
|
|
92
|
+
serverName: servers['code-graph'] ? 'code-graph' : 'code-graph-mcp',
|
|
93
|
+
config: codeGraphEntry
|
|
94
|
+
}
|
|
95
|
+
} catch (error) {
|
|
96
|
+
return { configured: false, error: `Failed to parse .mcp.json: ${error.message}` }
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function checkServerAndTools(projectRoot) {
|
|
101
|
+
const start = Date.now()
|
|
102
|
+
try {
|
|
103
|
+
const child = execFile('code-graph-mcp', ['--project-root', projectRoot])
|
|
104
|
+
|
|
105
|
+
return new Promise((resolvePromise) => {
|
|
106
|
+
let stdout = ''
|
|
107
|
+
let stderr = ''
|
|
108
|
+
let settled = false
|
|
109
|
+
|
|
110
|
+
const settle = (result) => {
|
|
111
|
+
if (settled) return
|
|
112
|
+
settled = true
|
|
113
|
+
resolvePromise(result)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
child.stdout.on('data', (data) => {
|
|
117
|
+
stdout += data.toString()
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
child.stderr.on('data', (data) => {
|
|
121
|
+
stderr += data.toString()
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
// Send MCP initialize + tools/list via JSON-RPC over stdio
|
|
125
|
+
const initMsg = JSON.stringify({
|
|
126
|
+
jsonrpc: '2.0', id: 1, method: 'initialize',
|
|
127
|
+
params: { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 'health-check', version: '1.0' } }
|
|
128
|
+
})
|
|
129
|
+
const notifyMsg = JSON.stringify({ jsonrpc: '2.0', method: 'notifications/initialized' })
|
|
130
|
+
const listMsg = JSON.stringify({ jsonrpc: '2.0', id: 2, method: 'tools/list', params: {} })
|
|
131
|
+
|
|
132
|
+
child.stdin.write(initMsg + '\n')
|
|
133
|
+
child.stdin.write(notifyMsg + '\n')
|
|
134
|
+
child.stdin.write(listMsg + '\n')
|
|
135
|
+
|
|
136
|
+
// Parse JSON-RPC responses as they arrive
|
|
137
|
+
let responseCount = 0
|
|
138
|
+
let actualTools = null
|
|
139
|
+
|
|
140
|
+
const checkResponses = () => {
|
|
141
|
+
const lines = stdout.split('\n').filter((l) => l.trim())
|
|
142
|
+
for (const line of lines) {
|
|
143
|
+
try {
|
|
144
|
+
const msg = JSON.parse(line)
|
|
145
|
+
if (msg.id === 1) responseCount++
|
|
146
|
+
if (msg.id === 2 && msg.result && msg.result.tools) {
|
|
147
|
+
responseCount++
|
|
148
|
+
actualTools = msg.result.tools.map((t) => t.name)
|
|
149
|
+
}
|
|
150
|
+
} catch {
|
|
151
|
+
// partial line
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Poll for responses, timeout after RESPONSE_TIMEOUT_MS
|
|
157
|
+
const pollInterval = setInterval(() => {
|
|
158
|
+
checkResponses()
|
|
159
|
+
if (responseCount >= 2) {
|
|
160
|
+
clearInterval(pollInterval)
|
|
161
|
+
clearTimeout(timer)
|
|
162
|
+
child.kill('SIGTERM')
|
|
163
|
+
|
|
164
|
+
const toolReport = EXPECTED_TOOLS.map((name) => ({
|
|
165
|
+
name,
|
|
166
|
+
available: actualTools ? actualTools.includes(name) : false
|
|
167
|
+
}))
|
|
168
|
+
|
|
169
|
+
settle({
|
|
170
|
+
responding: true,
|
|
171
|
+
responseTimeMs: Date.now() - start,
|
|
172
|
+
tools: toolReport,
|
|
173
|
+
actualToolCount: actualTools ? actualTools.length : 0,
|
|
174
|
+
note: 'Server responded via JSON-RPC, tools verified via tools/list'
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
}, 200)
|
|
178
|
+
|
|
179
|
+
const timer = setTimeout(() => {
|
|
180
|
+
clearInterval(pollInterval)
|
|
181
|
+
child.kill('SIGTERM')
|
|
182
|
+
checkResponses()
|
|
183
|
+
|
|
184
|
+
// If we got at least the init response, server is alive
|
|
185
|
+
if (responseCount >= 1) {
|
|
186
|
+
settle({
|
|
187
|
+
responding: true,
|
|
188
|
+
responseTimeMs: Date.now() - start,
|
|
189
|
+
tools: EXPECTED_TOOLS.map((name) => ({ name, available: true })),
|
|
190
|
+
actualToolCount: EXPECTED_TOOLS.length,
|
|
191
|
+
note: 'Server responded to initialize but tools/list timed out; using expected tool list'
|
|
192
|
+
})
|
|
193
|
+
} else {
|
|
194
|
+
settle({
|
|
195
|
+
responding: false,
|
|
196
|
+
responseTimeMs: Date.now() - start,
|
|
197
|
+
tools: EXPECTED_TOOLS.map((name) => ({ name, available: false })),
|
|
198
|
+
actualToolCount: 0,
|
|
199
|
+
error: 'Server did not respond within timeout'
|
|
200
|
+
})
|
|
201
|
+
}
|
|
202
|
+
}, RESPONSE_TIMEOUT_MS)
|
|
203
|
+
|
|
204
|
+
child.on('error', (error) => {
|
|
205
|
+
clearInterval(pollInterval)
|
|
206
|
+
clearTimeout(timer)
|
|
207
|
+
settle({
|
|
208
|
+
responding: false,
|
|
209
|
+
responseTimeMs: Date.now() - start,
|
|
210
|
+
tools: EXPECTED_TOOLS.map((name) => ({ name, available: false })),
|
|
211
|
+
actualToolCount: 0,
|
|
212
|
+
error: `Server failed to start: ${error.message}`
|
|
213
|
+
})
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
child.on('exit', (code) => {
|
|
217
|
+
clearInterval(pollInterval)
|
|
218
|
+
clearTimeout(timer)
|
|
219
|
+
if (code !== null && code !== 0) {
|
|
220
|
+
settle({
|
|
221
|
+
responding: false,
|
|
222
|
+
responseTimeMs: Date.now() - start,
|
|
223
|
+
tools: EXPECTED_TOOLS.map((name) => ({ name, available: false })),
|
|
224
|
+
actualToolCount: 0,
|
|
225
|
+
error: `Server exited with code ${code}. stderr: ${stderr}`
|
|
226
|
+
})
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
})
|
|
230
|
+
} catch (error) {
|
|
231
|
+
return {
|
|
232
|
+
responding: false,
|
|
233
|
+
responseTimeMs: Date.now() - start,
|
|
234
|
+
tools: EXPECTED_TOOLS.map((name) => ({ name, available: false })),
|
|
235
|
+
actualToolCount: 0,
|
|
236
|
+
error: `Server check failed: ${error.message}`
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async function runHealthCheck() {
|
|
242
|
+
const { smoke, projectRoot } = parseArgs()
|
|
243
|
+
const resolvedRoot = resolve(projectRoot)
|
|
244
|
+
|
|
245
|
+
const report = {
|
|
246
|
+
status: 'unknown',
|
|
247
|
+
provider: 'code-graph-mcp',
|
|
248
|
+
version: null,
|
|
249
|
+
projectRoot: resolvedRoot,
|
|
250
|
+
timestamp: new Date().toISOString(),
|
|
251
|
+
checks: {},
|
|
252
|
+
tools: [],
|
|
253
|
+
responseTimeMs: null,
|
|
254
|
+
errors: []
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Check 1: Binary installed
|
|
258
|
+
const binaryCheck = await checkBinaryInstalled()
|
|
259
|
+
report.checks.binaryInstalled = binaryCheck.installed
|
|
260
|
+
if (!binaryCheck.installed) {
|
|
261
|
+
report.status = 'unavailable'
|
|
262
|
+
report.errors.push(binaryCheck.error)
|
|
263
|
+
outputReport(report, 2)
|
|
264
|
+
return
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Check 2: MCP config present
|
|
268
|
+
const configCheck = checkMcpConfig(resolvedRoot)
|
|
269
|
+
report.checks.mcpConfigured = configCheck.configured
|
|
270
|
+
if (!configCheck.configured) {
|
|
271
|
+
report.errors.push(configCheck.error)
|
|
272
|
+
// Not a blocker — binary works, just no MCP config
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Check 3: Server responds and tools verified via MCP tools/list
|
|
276
|
+
const serverCheck = await checkServerAndTools(resolvedRoot)
|
|
277
|
+
report.checks.serverResponding = serverCheck.responding
|
|
278
|
+
report.responseTimeMs = serverCheck.responseTimeMs
|
|
279
|
+
|
|
280
|
+
if (!serverCheck.responding) {
|
|
281
|
+
report.status = 'unavailable'
|
|
282
|
+
report.errors.push(serverCheck.error)
|
|
283
|
+
report.tools = serverCheck.tools
|
|
284
|
+
outputReport(report, 2)
|
|
285
|
+
return
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Tool report from real MCP tools/list query
|
|
289
|
+
report.tools = serverCheck.tools
|
|
290
|
+
const availableCount = report.tools.filter((t) => t.available).length
|
|
291
|
+
|
|
292
|
+
if (availableCount === EXPECTED_TOOLS.length) {
|
|
293
|
+
report.status = 'available'
|
|
294
|
+
} else if (availableCount > 0) {
|
|
295
|
+
report.status = 'degraded'
|
|
296
|
+
} else {
|
|
297
|
+
report.status = 'unavailable'
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Version detection (try pip, fallback to python -m pip for Windows compatibility)
|
|
301
|
+
for (const cmd of [
|
|
302
|
+
{ file: 'pip', args: ['show', 'code-graph-mcp', '--no-color'] },
|
|
303
|
+
{ file: 'python', args: ['-m', 'pip', 'show', 'code-graph-mcp', '--no-color'] },
|
|
304
|
+
{ file: 'python3', args: ['-m', 'pip', 'show', 'code-graph-mcp', '--no-color'] }
|
|
305
|
+
]) {
|
|
306
|
+
try {
|
|
307
|
+
const { stdout } = await execFileAsync(cmd.file, cmd.args, { timeout: 5000 })
|
|
308
|
+
const versionMatch = stdout.match(/Version:\s*(.+)/)
|
|
309
|
+
if (versionMatch) {
|
|
310
|
+
report.version = versionMatch[1].trim()
|
|
311
|
+
break
|
|
312
|
+
}
|
|
313
|
+
} catch {
|
|
314
|
+
// Try next command
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Smoke tests (optional)
|
|
319
|
+
if (smoke) {
|
|
320
|
+
report.smokeTests = {
|
|
321
|
+
note: 'Smoke tests require running inside Claude Code session with code-graph MCP active',
|
|
322
|
+
instructions: [
|
|
323
|
+
'Use find_definition tool with symbol "UnifiedActivationPipeline"',
|
|
324
|
+
'Use find_references tool with symbol "entity-registry"',
|
|
325
|
+
'Use dependency_analysis tool on ".aios-core/core/"',
|
|
326
|
+
'Use project_statistics tool on project root'
|
|
327
|
+
]
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const exitCode = report.status === 'available' ? 0
|
|
332
|
+
: report.status === 'degraded' ? 1
|
|
333
|
+
: 2
|
|
334
|
+
|
|
335
|
+
outputReport(report, exitCode)
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function outputReport(report, exitCode) {
|
|
339
|
+
console.log(JSON.stringify(report, null, 2))
|
|
340
|
+
process.exit(exitCode)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
runHealthCheck()
|