@avesta-hq/prevention 0.5.0 → 0.6.0-pre.3

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.md CHANGED
@@ -68,7 +68,7 @@
68
68
 
69
69
  ## MCP Server Integration
70
70
 
71
- This project uses Prevention as an MCP server with 15 tools, 26 agents, and 34 skills that provide all methodology knowledge (TDD, Clean Architecture, test pyramid, CI/CD, etc.) on demand.
71
+ This project uses Prevention as two MCP servers: a local server (12 tools for workflow orchestration) and a remote server (3 tools for content delivery skills, prompts, catalog).
72
72
 
73
73
  **When starting work:**
74
74
 
@@ -76,10 +76,13 @@ This project uses Prevention as an MCP server with 15 tools, 26 agents, and 34 s
76
76
  2. The workflow tracks your phase (vision → plan → atdd → tdd → review → ship)
77
77
  3. Gates enforce that prerequisites are met before advancing
78
78
 
79
- **Key tools:**
79
+ **Key tools (local):**
80
80
 
81
81
  - `avesta_get_status` — Current phase, gates, next action
82
82
  - `avesta_dispatch` — Route tasks to the right workflow step
83
+
84
+ **Key tools (remote — `prevention-content`):**
85
+
83
86
  - `avesta_get_catalog` — All available commands and skills
84
87
  - `avesta_get_skill` — Deep knowledge on any practice (testing, architecture, CI/CD)
85
88
 
@@ -131,7 +131,7 @@ function configureStatusLine(targetDir) {
131
131
  writeSettings(targetDir, settings);
132
132
  }
133
133
 
134
- function configureMcpServer(targetDir, binaryPath) {
134
+ function configureMcpServer(targetDir, binaryPath, options = {}) {
135
135
  const mcpJsonPath = path.join(targetDir, '.mcp.json');
136
136
  let mcpConfig = {};
137
137
  if (fs.existsSync(mcpJsonPath)) {
@@ -140,12 +140,52 @@ function configureMcpServer(targetDir, binaryPath) {
140
140
 
141
141
  if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
142
142
 
143
- if (binaryPath) {
144
- mcpConfig.mcpServers['prevention'] = { command: path.resolve(binaryPath) };
143
+ // Local MCP server: workflow orchestration tools
144
+ // Pass through API/MCP URLs so the server process can reach them
145
+ const env = {};
146
+ if (process.env.AVESTA_API_URL) env.AVESTA_API_URL = process.env.AVESTA_API_URL;
147
+ if (process.env.AVESTA_MCP_URL) env.AVESTA_MCP_URL = process.env.AVESTA_MCP_URL;
148
+ const hasEnv = Object.keys(env).length > 0;
149
+
150
+ if (options.localSource) {
151
+ // Dev mode: run from source via tsx
152
+ const entry = { command: 'npx', args: ['tsx', options.localSource] };
153
+ if (hasEnv) entry.env = env;
154
+ mcpConfig.mcpServers['prevention'] = entry;
155
+ } else if (binaryPath) {
156
+ const entry = { command: path.resolve(binaryPath) };
157
+ if (hasEnv) entry.env = env;
158
+ mcpConfig.mcpServers['prevention'] = entry;
145
159
  } else {
146
- mcpConfig.mcpServers['prevention'] = { command: 'npx', args: ['@avesta-hq/prevention', 'serve'] };
160
+ const entry = { command: 'npx', args: ['@avesta-hq/prevention', 'serve'] };
161
+ if (hasEnv) entry.env = env;
162
+ mcpConfig.mcpServers['prevention'] = entry;
147
163
  }
148
164
 
165
+ // Remote MCP server: content delivery (skills, prompts, catalog)
166
+ // Pre-populate auth token from existing session if available
167
+ const remoteUrl = process.env.AVESTA_MCP_URL || 'https://prevention-production.up.railway.app/mcp';
168
+ const existingRemote = mcpConfig.mcpServers['prevention-content'];
169
+ const existingToken = existingRemote?.headers?.Authorization;
170
+ let authToken = existingToken || '';
171
+ if (!authToken) {
172
+ try {
173
+ const sessionPath = path.join(require('os').homedir(), '.avesta', 'session.json');
174
+ if (fs.existsSync(sessionPath)) {
175
+ const session = JSON.parse(fs.readFileSync(sessionPath, 'utf8'));
176
+ if (session.access_token) {
177
+ authToken = `Bearer ${session.access_token}`;
178
+ }
179
+ }
180
+ } catch {}
181
+ }
182
+ const headers = authToken ? { Authorization: authToken } : {};
183
+ mcpConfig.mcpServers['prevention-content'] = {
184
+ type: 'http',
185
+ url: remoteUrl,
186
+ headers,
187
+ };
188
+
149
189
  fs.writeFileSync(mcpJsonPath, JSON.stringify(mcpConfig, null, 2) + '\n');
150
190
  }
151
191
 
@@ -19,6 +19,7 @@ const path = require('path');
19
19
  const { execSync } = require('child_process');
20
20
  const { PACKAGE_ROOT, COMMANDS_DIR, AGENTS_DIR, AVESTA_DIR, copyDir, getVersion } = require('./utils');
21
21
  const {
22
+ configureMcpServer,
22
23
  configureSessionStartHook,
23
24
  configureEnforcementHooks,
24
25
  configureStatusLine,
@@ -34,7 +35,7 @@ function testLocal(targetDir) {
34
35
  console.log(` Target: ${targetDir}\n`);
35
36
 
36
37
  // Step 1: Rebuild embedded assets
37
- console.log(' [1/5] Rebuilding catalog + embedded assets...');
38
+ console.log(' [1/6] Rebuilding catalog + embedded assets...');
38
39
  try {
39
40
  execSync('pnpm run prebuild:assets', { cwd: cdAgentRoot, stdio: 'pipe' });
40
41
  console.log(' ✓ Assets rebuilt');
@@ -45,7 +46,7 @@ function testLocal(targetDir) {
45
46
  }
46
47
 
47
48
  // Step 2: Copy agents + commands
48
- console.log(' [2/5] Copying agents and commands...');
49
+ console.log(' [2/6] Copying agents and commands...');
49
50
  const claudeDir = path.join(targetDir, '.claude');
50
51
  if (!fs.existsSync(claudeDir)) fs.mkdirSync(claudeDir, { recursive: true });
51
52
 
@@ -62,40 +63,42 @@ function testLocal(targetDir) {
62
63
  const agentCount = fs.existsSync(AGENTS_DIR) ? fs.readdirSync(AGENTS_DIR).filter(f => f.endsWith('.md')).length : 0;
63
64
  console.log(` ✓ Copied ${commandCount} commands, ${agentCount} agents`);
64
65
 
65
- // Step 3: Configure MCP server to use local source via tsx
66
- console.log(' [3/5] Configuring MCP server (local source)...');
67
- const mcpJsonPath = path.join(targetDir, '.mcp.json');
68
- let mcpConfig = {};
69
- if (fs.existsSync(mcpJsonPath)) {
70
- try { mcpConfig = JSON.parse(fs.readFileSync(mcpJsonPath, 'utf8')); } catch {}
71
- }
72
- if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
73
-
66
+ // Step 3: Configure MCP servers (local source + remote content)
67
+ console.log(' [3/6] Configuring MCP servers (local source + remote content)...');
74
68
  const mcpServerPath = path.join(cdAgentRoot, 'src', 'mcp-server.ts');
75
- mcpConfig.mcpServers['prevention'] = {
76
- command: 'npx',
77
- args: ['tsx', mcpServerPath],
78
- };
79
- fs.writeFileSync(mcpJsonPath, JSON.stringify(mcpConfig, null, 2) + '\n');
80
- console.log(` ✓ MCP server → npx tsx ${mcpServerPath}`);
69
+ configureMcpServer(targetDir, null, { localSource: mcpServerPath });
70
+ console.log(` ✓ Local MCP server → npx tsx ${mcpServerPath}`);
71
+ const remoteUrl = process.env.AVESTA_MCP_URL || 'https://prevention-production.up.railway.app/mcp';
72
+ console.log(` ✓ Remote MCP server → ${remoteUrl}`);
81
73
 
82
74
  // Step 4: Configure hooks (pointing at local CLI)
83
- console.log(' [4/5] Configuring hooks...');
75
+ console.log(' [4/6] Configuring hooks...');
84
76
  configureSessionStartHook(targetDir);
85
77
  configureEnforcementHooks(targetDir);
86
78
  configureStatusLine(targetDir);
87
79
  ensureClaudeMdSection(targetDir);
88
80
 
89
- // Step 5: Show result
90
- console.log(' [5/5] Verifying setup...');
81
+ // Step 5: Write version
82
+ console.log(' [5/6] Writing version...');
83
+ const versionFile = path.join(targetDir, '.avesta', 'version.json');
84
+ const versionDir = path.dirname(versionFile);
85
+ if (!fs.existsSync(versionDir)) fs.mkdirSync(versionDir, { recursive: true });
86
+ fs.writeFileSync(versionFile, JSON.stringify({ version: getVersion(), updated_at: new Date().toISOString() }, null, 2));
87
+ console.log(` ✓ Version ${getVersion()}`);
88
+
89
+ // Step 6: Show result
90
+ console.log(' [6/6] Verifying setup...');
91
91
  const settings = JSON.parse(fs.readFileSync(path.join(claudeDir, 'settings.json'), 'utf8'));
92
92
  const hookTypes = Object.keys(settings.hooks || {});
93
93
  console.log(` ✓ Hooks configured: ${hookTypes.join(', ')}`);
94
94
 
95
+ const mcpJsonPath = path.join(targetDir, '.mcp.json');
95
96
  const mcpFinal = JSON.parse(fs.readFileSync(mcpJsonPath, 'utf8'));
96
97
  const mcpCmd = mcpFinal.mcpServers?.prevention?.command || '?';
97
98
  const mcpArgs = (mcpFinal.mcpServers?.prevention?.args || []).join(' ');
98
- console.log(` ✓ MCP server: ${mcpCmd} ${mcpArgs}`);
99
+ console.log(` ✓ Local MCP: ${mcpCmd} ${mcpArgs}`);
100
+ const remoteEntry = mcpFinal.mcpServers?.['prevention-content'];
101
+ console.log(` ✓ Remote MCP: ${remoteEntry?.url || 'not configured'}`);
99
102
 
100
103
  console.log(`
101
104
  ✅ Local test environment ready! (v${getVersion()})
@@ -105,9 +108,10 @@ function testLocal(targetDir) {
105
108
 
106
109
  To test:
107
110
  1. Open Claude Code in ${targetDir}
108
- 2. Run /avesta-init backend (or frontend)
109
- 3. Test skill enforcement: /avesta-red should block writes until skills loaded
110
- 4. Test gate enforcement: git commit should be blocked without review gate
111
+ 2. Run avesta login to authenticate (connects remote content server)
112
+ 3. Run /avesta-init backend (or frontend)
113
+ 4. Test skill enforcement: /avesta-red should block writes until skills loaded
114
+ 5. Test gate enforcement: git commit should be blocked without review gate
111
115
 
112
116
  To revert to published version:
113
117
  node ${path.join(cdAgentRoot, 'bin', 'cli.js')} update
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@avesta-hq/prevention",
3
- "version": "0.5.0",
3
+ "version": "0.6.0-pre.3",
4
4
  "description": "XP/CD development agent commands for Claude Code - achieve Elite DORA metrics through disciplined TDD and Continuous Delivery practices",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -16,14 +16,7 @@
16
16
  ],
17
17
  "author": "Avesta Technologies",
18
18
  "license": "UNLICENSED",
19
- "repository": {
20
- "type": "git",
21
- "url": "git+https://github.com/avesta-hq/prevention.git"
22
- },
23
- "homepage": "https://github.com/avesta-hq/prevention#readme",
24
- "bugs": {
25
- "url": "https://github.com/avesta-hq/prevention/issues"
26
- },
19
+ "homepage": "https://avestahq.com/prevention",
27
20
  "bin": {
28
21
  "prevention": "./bin/cli.js"
29
22
  },