@ai-sdlc/mcp-advisor 0.1.1 → 0.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/dist/server.js +11 -2
- package/dist/tools/check-file.js +35 -1
- package/dist/tools/check-task.js +19 -0
- package/dist/types.d.ts +3 -1
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP server factory — creates and wires the advisor server.
|
|
3
3
|
*/
|
|
4
|
+
import { join } from 'node:path';
|
|
4
5
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
5
6
|
import Database from 'better-sqlite3';
|
|
6
7
|
import { StateStore } from '@ai-sdlc/orchestrator/state';
|
|
7
|
-
import { CostTracker } from '@ai-sdlc/orchestrator';
|
|
8
|
+
import { CostTracker, loadConfig } from '@ai-sdlc/orchestrator';
|
|
8
9
|
import { SessionManager } from './session.js';
|
|
9
10
|
import { registerAllTools } from './tools/index.js';
|
|
10
11
|
import { registerAllResources } from './resources/index.js';
|
|
@@ -14,7 +15,15 @@ export async function createMcpServer(opts) {
|
|
|
14
15
|
const costTracker = new CostTracker(store);
|
|
15
16
|
const sessions = new SessionManager();
|
|
16
17
|
const repoPath = opts?.repoPath ?? process.cwd();
|
|
17
|
-
|
|
18
|
+
// Load AI-SDLC config (best-effort — tools work in degraded mode without it)
|
|
19
|
+
let config;
|
|
20
|
+
try {
|
|
21
|
+
config = loadConfig(join(repoPath, '.ai-sdlc'));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Config not available or invalid
|
|
25
|
+
}
|
|
26
|
+
const deps = { store, costTracker, sessions, repoPath, config };
|
|
18
27
|
const server = new McpServer({
|
|
19
28
|
name: 'ai-sdlc-advisor',
|
|
20
29
|
version: '0.1.0',
|
package/dist/tools/check-file.js
CHANGED
|
@@ -3,7 +3,7 @@ export function handleCheckFile(deps, input) {
|
|
|
3
3
|
const warnings = [];
|
|
4
4
|
let isHotspot = false;
|
|
5
5
|
let isBlocked = false;
|
|
6
|
-
|
|
6
|
+
let crossesModuleBoundary = false;
|
|
7
7
|
// Check hotspots
|
|
8
8
|
const hotspots = deps.store.getHotspots(deps.repoPath, 100);
|
|
9
9
|
const matchingHotspot = hotspots.find((h) => h.filePath === input.filePath || input.filePath.endsWith(h.filePath));
|
|
@@ -26,6 +26,40 @@ export function handleCheckFile(deps, input) {
|
|
|
26
26
|
// raw data not parseable
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
+
// Check blocked paths from autonomy policy config
|
|
30
|
+
if (deps.config?.autonomyPolicy) {
|
|
31
|
+
const policy = deps.config.autonomyPolicy;
|
|
32
|
+
// Check all levels' blocked paths
|
|
33
|
+
for (const level of policy.spec.levels) {
|
|
34
|
+
const blockedPaths = level.guardrails.blockedPaths ?? [];
|
|
35
|
+
for (const bp of blockedPaths) {
|
|
36
|
+
const base = bp.replace(/\/?\*\*$/, '');
|
|
37
|
+
if (input.filePath === base ||
|
|
38
|
+
input.filePath.startsWith(base.endsWith('/') ? base : `${base}/`)) {
|
|
39
|
+
isBlocked = true;
|
|
40
|
+
crossesModuleBoundary = true;
|
|
41
|
+
warnings.push(`File matches blocked path "${bp}" per autonomy policy (level ${level.level}).`);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Check module graph from complexity profile
|
|
48
|
+
const profile2 = deps.store.getLatestComplexityProfile(deps.repoPath);
|
|
49
|
+
if (profile2?.rawData) {
|
|
50
|
+
try {
|
|
51
|
+
const raw = JSON.parse(profile2.rawData);
|
|
52
|
+
if (raw.moduleGraph?.modules) {
|
|
53
|
+
const fileModule = raw.moduleGraph.modules.find((m) => input.filePath.startsWith(m.path));
|
|
54
|
+
if (fileModule) {
|
|
55
|
+
warnings.push(`File is in module "${fileModule.name ?? fileModule.path}". Cross-module changes need extra review.`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// raw data not parseable
|
|
61
|
+
}
|
|
62
|
+
}
|
|
29
63
|
return {
|
|
30
64
|
filePath: input.filePath,
|
|
31
65
|
isHotspot,
|
package/dist/tools/check-task.js
CHANGED
|
@@ -27,6 +27,25 @@ export function handleCheckTask(deps, input) {
|
|
|
27
27
|
if (issueNumber == null) {
|
|
28
28
|
advisoryNotes.push('No issue linked to this session — work will be unattributed.');
|
|
29
29
|
}
|
|
30
|
+
// Populate constraints from AI-SDLC config
|
|
31
|
+
if (deps.config?.autonomyPolicy) {
|
|
32
|
+
const policy = deps.config.autonomyPolicy;
|
|
33
|
+
const level = policy.spec.levels.find((l) => l.level === (autonomyLevel ?? 0));
|
|
34
|
+
if (level) {
|
|
35
|
+
if (level.guardrails.blockedPaths?.length) {
|
|
36
|
+
constraints.push(`Blocked paths: ${level.guardrails.blockedPaths.join(', ')}`);
|
|
37
|
+
}
|
|
38
|
+
if (level.guardrails.maxLinesPerPR) {
|
|
39
|
+
constraints.push(`Max lines per PR: ${level.guardrails.maxLinesPerPR}`);
|
|
40
|
+
}
|
|
41
|
+
constraints.push(`Approval required: ${level.guardrails.requireApproval}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (deps.config?.qualityGate) {
|
|
45
|
+
for (const gate of deps.config.qualityGate.spec.gates) {
|
|
46
|
+
constraints.push(`Quality gate: ${gate.name} (${gate.enforcement})`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
30
49
|
return {
|
|
31
50
|
issueNumber,
|
|
32
51
|
autonomyLevel,
|
package/dist/types.d.ts
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
* Shared dependency injection types for tools and resources.
|
|
3
3
|
*/
|
|
4
4
|
import type { StateStore } from '@ai-sdlc/orchestrator/state';
|
|
5
|
-
import type { CostTracker } from '@ai-sdlc/orchestrator';
|
|
5
|
+
import type { CostTracker, AiSdlcConfig } from '@ai-sdlc/orchestrator';
|
|
6
6
|
import type { SessionManager } from './session.js';
|
|
7
7
|
export interface ServerDeps {
|
|
8
8
|
store: StateStore;
|
|
9
9
|
costTracker: CostTracker;
|
|
10
10
|
sessions: SessionManager;
|
|
11
11
|
repoPath: string;
|
|
12
|
+
/** Loaded AI-SDLC config (if available). */
|
|
13
|
+
config?: AiSdlcConfig;
|
|
12
14
|
}
|
|
13
15
|
//# sourceMappingURL=types.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdlc/mcp-advisor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "MCP server bridging human-directed AI sessions with the AI-SDLC orchestrator",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
34
34
|
"better-sqlite3": "^11.0.0",
|
|
35
35
|
"zod": "^3.23.0",
|
|
36
|
-
"@ai-sdlc/orchestrator": "0.
|
|
36
|
+
"@ai-sdlc/orchestrator": "0.2.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/better-sqlite3": "^7.6.0",
|