@ai-sdlc/mcp-advisor 0.1.1 → 0.1.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/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
- const deps = { store, costTracker, sessions, repoPath };
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',
@@ -3,7 +3,7 @@ export function handleCheckFile(deps, input) {
3
3
  const warnings = [];
4
4
  let isHotspot = false;
5
5
  let isBlocked = false;
6
- const crossesModuleBoundary = false;
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,
@@ -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.1.1",
3
+ "version": "0.1.2",
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.1.1"
36
+ "@ai-sdlc/orchestrator": "0.1.2"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/better-sqlite3": "^7.6.0",