@ryuenn3123/agentic-senior-core 2.0.8 → 2.0.10

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/.cursorrules CHANGED
@@ -1,6 +1,6 @@
1
1
  # AGENTIC-SENIOR-CORE DYNAMIC GOVERNANCE RULESET
2
2
 
3
- Generated by Agentic-Senior-Core CLI v2.0.8
3
+ Generated by Agentic-Senior-Core CLI v2.0.10
4
4
  Timestamp: 2026-04-08T14:58:53.570Z
5
5
  Selected profile: beginner
6
6
  Selected policy file: .agent-context/policies/llm-judge-threshold.json
package/.windsurfrules CHANGED
@@ -1,6 +1,6 @@
1
1
  # AGENTIC-SENIOR-CORE DYNAMIC GOVERNANCE RULESET
2
2
 
3
- Generated by Agentic-Senior-Core CLI v2.0.8
3
+ Generated by Agentic-Senior-Core CLI v2.0.10
4
4
  Timestamp: 2026-04-08T14:58:53.570Z
5
5
  Selected profile: beginner
6
6
  Selected policy file: .agent-context/policies/llm-judge-threshold.json
package/README.md CHANGED
@@ -38,34 +38,61 @@ AI: *Creates properly layered modules with Zod validation, typed errors,
38
38
 
39
39
  ## Quick Start
40
40
 
41
- ### Zero-Install: GitHub Template (New user friendly!)
41
+ ### Method 1 (Recommended): npm package
42
42
 
43
- The absolute fastest way to start your next top-tier project is to use this repository as a template.
44
- The **Use this template** button is in the GitHub repository header (top-right area), not inside this README text.
45
- If you prefer a direct link, open: **[Create from template](https://github.com/fatidaprilian/Agentic-Senior-Core/generate)**.
46
- Your new repository will instantly possess all the rules, configurations, and AI context files directly out of the box — zero CLI needed.
43
+ The npm package is already published. For most users, this is the default path.
47
44
 
48
- ### Option 0: NPM Install (Local or Global)
45
+ ```bash
46
+ npm exec --yes @ryuenn3123/agentic-senior-core launch
47
+ npm exec --yes @ryuenn3123/agentic-senior-core init
48
+ npx @ryuenn3123/agentic-senior-core init
49
+ ```
49
50
 
50
- If you already know you want the CLI from npm, use one of these paths:
51
+ If you prefer a global install:
51
52
 
52
53
  ```bash
53
- npm exec --yes @ryuenn3123/agentic-senior-core init
54
54
  npm install -g @ryuenn3123/agentic-senior-core
55
55
  agentic-senior-core init
56
56
  ```
57
57
 
58
- ### Option 1: Interactive via GitHub Source (Pre-publish friendly)
58
+ Use team defaults with profile packs:
59
59
 
60
- If npm package publication is not ready yet, run the CLI directly from GitHub and still keep the full interactive experience.
60
+ ```bash
61
+ npx @ryuenn3123/agentic-senior-core init --profile-pack startup
62
+ ```
63
+
64
+ ### Method 2: GitHub template and source execution
65
+
66
+ Use this method if your team prefers source-based bootstrap or template-first onboarding.
67
+
68
+ GitHub template:
69
+ - **[Create from template](https://github.com/fatidaprilian/Agentic-Senior-Core/generate)**
70
+
71
+ GitHub source execution (interactive):
61
72
 
62
73
  ```bash
63
74
  npm exec --yes --package=github:fatidaprilian/Agentic-Senior-Core agentic-senior-core init .
64
75
  ```
65
76
 
66
- This gives the same interactive prompts to choose your profile (`beginner`, `balanced`, `strict`), stack, blueprint, and CI guardrails.
77
+ GitHub bootstrap scripts:
78
+ - Windows: `scripts/init-project.ps1`
79
+ - Linux/macOS: `scripts/init-project.sh`
80
+
81
+ Windows PowerShell:
82
+
83
+ ```powershell
84
+ powershell -ExecutionPolicy Bypass -File .\scripts\init-project.ps1 -TargetDirectory . -Profile balanced -Stack typescript -Blueprint api-nextjs -Ci true
85
+ ```
86
+
87
+ Linux/macOS Bash:
88
+
89
+ ```bash
90
+ bash ./scripts/init-project.sh . --profile balanced --stack typescript --blueprint api-nextjs --ci true
91
+ ```
92
+
93
+ ### Preset starters
67
94
 
68
- If you want a plug-and-play starter instead of answering every question, use a preset:
95
+ Use presets when you want faster onboarding with less manual selection.
69
96
 
70
97
  ```bash
71
98
  npx @ryuenn3123/agentic-senior-core init --preset frontend-web
@@ -81,53 +108,51 @@ Expanded preset catalog:
81
108
  - `mobile-react-native`, `mobile-flutter`, `observability-platform`
82
109
  - `typescript-nestjs-service`, `java-enterprise-api`, `dotnet-enterprise-api`, `php-laravel-api`, `kubernetes-platform`
83
110
 
84
- ### Option 2: GitHub Bootstrap Scripts (No npx required)
111
+ ### Newbie mode
85
112
 
86
- Run directly from this repository bootstrap script and inject rules into your project root.
87
-
88
- Bootstrap script paths: `scripts/init-project.ps1` (Windows) and `scripts/init-project.sh` (Linux/macOS).
89
-
90
- Windows PowerShell:
91
-
92
- ```powershell
93
- powershell -ExecutionPolicy Bypass -File .\scripts\init-project.ps1 -TargetDirectory . -Profile balanced -Stack typescript -Blueprint api-nextjs -Ci true
94
- ```
95
-
96
- Linux/macOS Bash:
113
+ If you are new to stacks, blueprints, and guardrails, run:
97
114
 
98
115
  ```bash
99
- bash ./scripts/init-project.sh . --profile balanced --stack typescript --blueprint api-nextjs --ci true
116
+ npx @ryuenn3123/agentic-senior-core init --newbie
100
117
  ```
101
118
 
102
- Both scripts clone Agentic-Senior-Core into a temporary directory, run the same CLI engine, then clean up automatically.
119
+ ### Important behavior
120
+
121
+ - `init` does not copy repository workflows from this project into your target repository.
122
+ - MCP server registration and trust/start are manual in IDE settings.
123
+ - MCP workspace scaffold is opt-in via `--mcp-template` and creates `.vscode/mcp.json`.
103
124
 
104
- If you want interactive selection, omit `-Profile`, `-Stack`, `-Blueprint`, and `-Ci` on the script command.
125
+ ### MCP Setup in VS Code (No File Picker)
105
126
 
106
- ### Option 3: Interactive Auto-Setup via npm/npx (Post-publish)
127
+ If you are looking for a file picker in the MCP UI, that is expected because VS Code uses MCP server registration, not generic JSON file import.
107
128
 
108
- If you have an existing project and want to infuse it with Staff-level context:
129
+ 1. Generate workspace MCP config:
109
130
 
110
131
  ```bash
111
- npx @ryuenn3123/agentic-senior-core init
132
+ npx @ryuenn3123/agentic-senior-core init --mcp-template
112
133
  ```
113
134
 
114
- Use team defaults (V2.0 track) with profile packs:
135
+ 2. Open Command Palette and run `MCP: Open Workspace Folder Configuration`.
136
+ 3. Confirm the file is `.vscode/mcp.json` with server `agentic-senior-core`.
137
+ 4. The generated server command is `npx -y @ryuenn3123/agentic-senior-core mcp`.
138
+ 5. Open Chat Customizations > MCP Servers, then trust/start the server.
115
139
 
116
- ```bash
117
- npx @ryuenn3123/agentic-senior-core init --profile-pack startup
118
- ```
140
+ If logs repeatedly show `Waiting for server to respond to initialize request`, upgrade to the latest package version and regenerate the workspace config with `--mcp-template`.
119
141
 
120
- The CLI is smart. It auto-detects your current development stack, helps you build a governance profile (select from `beginner`, `balanced`, or `strict`), and writes the compiled rules straight to your root automatically!
142
+ ### CLI Command Reference
121
143
 
122
- Important behavior:
123
- - `init` does not copy repository workflows from this project into your target repository.
124
- - MCP server registration is manual in IDE settings.
125
- - If you want the MCP file scaffold, run `init` with `--mcp-template`.
144
+ All available commands:
126
145
 
127
- If you are totally new to concepts like blueprints and guardrails, no problem — just run:
128
- ```bash
129
- npx @ryuenn3123/agentic-senior-core init --newbie
130
- ```
146
+ | Command | Purpose | Example |
147
+ |---------|---------|---------|
148
+ | `launch` | Numbered onboarding launcher | `agentic-senior-core launch` |
149
+ | `init` | Initialize governance in a project | `agentic-senior-core init . --profile balanced` |
150
+ | `upgrade` | Upgrade existing governance safely | `agentic-senior-core upgrade . --dry-run` |
151
+ | `optimize` | Manage token optimization profile | `agentic-senior-core optimize . --show` |
152
+ | `mcp` | Start local MCP stdio server runtime | `agentic-senior-core mcp` |
153
+ | `rollback` | Roll back from backup snapshot | `agentic-senior-core rollback .` |
154
+ | `skill` | Select domain skill pack by tier | `agentic-senior-core skill frontend --tier advance` |
155
+ | `--version` | Print CLI version | `agentic-senior-core --version` |
131
156
 
132
157
  ### Skill Selector
133
158
 
@@ -270,8 +295,8 @@ Our documentation has shifted into dedicated tracks to keep this README light:
270
295
  - **Automated Guardrails:** CI blueprints include LLM-as-a-Judge flow using `pr-checklist.md`.
271
296
  - **Pre-Publish Safety:** Built-in forbidden content checks detect hardcoded secrets and stray debugger artifacts before hitting the NPM registry.
272
297
  - **Machine-Readable CI Output:** LLM Judge emits `JSON_REPORT` payloads and writes `.agent-context/state/llm-judge-report.json` for PR/MR annotation tooling.
273
- - **MCP Self-Healing Loop:** `mcp.json` defines diagnostics + fix proposal workflow when lint/CI fails.
274
- - **MCP Registration Model:** IDE MCP server registration is manual; `mcp.json` is an optional template file (`--mcp-template`).
298
+ - **MCP Runtime Server:** `scripts/mcp-server.mjs` exposes validate/test/release checks as MCP tools.
299
+ - **MCP Registration Model:** IDE MCP server registration is manual; workspace config lives in `.vscode/mcp.json` (`--mcp-template`).
275
300
 
276
301
  ---
277
302
 
@@ -282,7 +307,9 @@ Our documentation has shifted into dedicated tracks to keep this README light:
282
307
  ├── .cursorrules # Dynamic compiled governance entry point
283
308
  ├── .windsurfrules # Dynamic compiled governance entry point
284
309
  ├── .agent-override.md # Team-specific exceptions (scoped + expiry)
285
- ├── mcp.json # Optional MCP template file (copied with --mcp-template)
310
+ ├── mcp.json # Governance metadata and knowledge-layer contract
311
+ ├── .vscode/
312
+ │ └── mcp.json # VS Code MCP workspace server configuration
286
313
  ├── AGENTS.md # Universal agent discovery
287
314
  ├── .github/copilot-instructions.md # GitHub Copilot entry point
288
315
  ├── .gemini/instructions.md # Antigravity / Gemini entry point
@@ -300,6 +327,7 @@ Our documentation has shifted into dedicated tracks to keep this README light:
300
327
  ├── scripts/
301
328
  │ ├── validate.mjs # Repository validator
302
329
  │ ├── llm-judge.mjs # LLM-as-a-Judge CI gate
330
+ │ ├── mcp-server.mjs # Local MCP stdio server (validate/test/release tools)
303
331
  │ ├── init-project.sh # GitHub bootstrap script (Linux/macOS)
304
332
  │ └── init-project.ps1 # GitHub bootstrap script (Windows)
305
333
  ├── docs/
@@ -337,6 +365,19 @@ npm run report:quality-trend
337
365
  npm run report:governance-weekly
338
366
  ```
339
367
 
368
+ ## Release and npm Publish Flow
369
+
370
+ This repository publishes to npm automatically through GitHub Actions on every push to `main`.
371
+
372
+ Release checklist:
373
+ 1. Bump `package.json` version.
374
+ 2. Add matching release notes in `CHANGELOG.md`.
375
+ 3. Push to `main`.
376
+
377
+ Important notes:
378
+ - If the npm version already exists, publish will fail.
379
+ - Publish requires valid `NPM_TOKEN` in repository secrets.
380
+
340
381
  ---
341
382
 
342
383
  ## Roadmap
@@ -362,7 +403,7 @@ npm run report:governance-weekly
362
403
 
363
404
  ### Current Forward Plan
364
405
  - V2.0: Skill marketplace trust tiers, transactional installs, rollback safety, and launch-menu onboarding.
365
- - V2.5: Cross-model benchmark harness and anti-regression quality gates.
406
+ - V2.5: Cross-model benchmark harness, anti-regression quality gates, and advanced frontend design quality track (non-template UI direction, stronger UX craft, and frontend parity beyond baseline benchmark repos).
366
407
  - V3.0: Enterprise governance cloud, policy drift detection, and org-level override registry.
367
408
 
368
409
  Detailed timeline and success metrics: [docs/roadmap.md](docs/roadmap.md)
@@ -11,6 +11,7 @@ import { CLI_VERSION } from '../lib/cli/constants.mjs';
11
11
  import { printUsage } from '../lib/cli/utils.mjs';
12
12
  import { runLaunchCommand } from '../lib/cli/commands/launch.mjs';
13
13
  import { runRollbackCommand } from '../lib/cli/commands/rollback.mjs';
14
+ import { runMcpServerCommand } from '../lib/cli/commands/mcp.mjs';
14
15
  import { runOptimizeCommand, parseOptimizeArguments } from '../lib/cli/commands/optimize.mjs';
15
16
  import { runInitCommand, parseInitArguments } from '../lib/cli/commands/init.mjs';
16
17
  import { runUpgradeCommand, parseUpgradeArguments } from '../lib/cli/commands/upgrade.mjs';
@@ -63,6 +64,11 @@ async function main() {
63
64
  return;
64
65
  }
65
66
 
67
+ if (commandArgument === 'mcp') {
68
+ await runMcpServerCommand();
69
+ return;
70
+ }
71
+
66
72
  console.error(`Unknown command: ${commandArgument}`);
67
73
  printUsage();
68
74
  exit(1);
@@ -429,7 +429,7 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
429
429
  console.log(`- Setup time: ${formatDuration(setupDurationMs)}`);
430
430
  console.log('- Generated files: .cursorrules, .windsurfrules, and .agent-context/state/onboarding-report.json');
431
431
  console.log(`- Repository workflows copied: no (workflows remain source-repo assets)`);
432
- console.log(`- MCP template file: ${shouldIncludeMcpTemplate ? 'copied (mcp.json)' : 'not copied by default (use --mcp-template)'}`);
432
+ console.log(`- MCP template file: ${shouldIncludeMcpTemplate ? 'created (.vscode/mcp.json)' : 'not created by default (use --mcp-template)'}`);
433
433
  if (isTokenOptimizationEnabled) {
434
434
  console.log(`- Token optimization policy: enabled for ${selectedTokenAgentName}`);
435
435
  } else {
@@ -0,0 +1,3 @@
1
+ export async function runMcpServerCommand() {
2
+ await import('../../../scripts/mcp-server.mjs');
3
+ }
package/lib/cli/utils.mjs CHANGED
@@ -31,6 +31,7 @@ export function printUsage() {
31
31
  console.log(' agentic-senior-core init [target-directory] [--preset <name>] [--profile <beginner|balanced|strict>] [--profile-pack <name>] [--stack <name>] [--blueprint <name>] [--ci <true|false>] [--newbie] [--token-optimize] [--no-token-optimize] [--token-agent <name>]');
32
32
  console.log(' agentic-senior-core upgrade [target-directory] [--dry-run] [--yes] [--mcp-template]');
33
33
  console.log(' agentic-senior-core optimize [target-directory] [--agent <copilot|claude|cursor|windsurf|gemini|codex|cline>] [--enable|--disable] [--show]');
34
+ console.log(' agentic-senior-core mcp');
34
35
  console.log(' agentic-senior-core rollback [target-directory]');
35
36
  console.log(' agentic-senior-core skill [domain] [--tier <standard|advance|expert|above>] [--json]');
36
37
  console.log(' agentic-senior-core --version');
@@ -48,7 +49,7 @@ export function printUsage() {
48
49
  console.log(' --token-optimize Explicitly enable token optimization policy during init (default behavior)');
49
50
  console.log(' --token-agent Set token optimization agent target (copilot, claude, cursor, windsurf, gemini, codex, cline)');
50
51
  console.log(' --no-token-optimize Disable token optimization policy during init');
51
- console.log(' --mcp-template Also copy mcp.json template (MCP server registration in IDE is still manual)');
52
+ console.log(' --mcp-template Create .vscode/mcp.json workspace template (MCP trust/start remains manual in IDE)');
52
53
  console.log(' --dry-run Preview upgrade without writing files');
53
54
  console.log(' --yes Skip confirmation prompts for upgrade');
54
55
  console.log(' --agent Target agent integration for token optimization mode');
@@ -129,14 +130,27 @@ export async function copyGovernanceAssetsToTarget(
129
130
  }
130
131
 
131
132
  if (shouldIncludeMcpTemplate) {
132
- const sourceMcpPath = path.join(REPO_ROOT, 'mcp.json');
133
- const targetMcpPath = path.join(resolvedTargetDirectoryPath, 'mcp.json');
134
-
135
- if (
136
- await pathExists(sourceMcpPath)
137
- && path.resolve(sourceMcpPath) !== path.resolve(targetMcpPath)
138
- ) {
139
- await fs.copyFile(sourceMcpPath, targetMcpPath);
133
+ const vscodeDirectoryPath = path.join(resolvedTargetDirectoryPath, '.vscode');
134
+ const workspaceMcpConfigurationPath = path.join(vscodeDirectoryPath, 'mcp.json');
135
+
136
+ const workspaceMcpConfiguration = {
137
+ $schema: 'vscode://schemas/mcp',
138
+ servers: {
139
+ 'agentic-senior-core': {
140
+ type: 'stdio',
141
+ command: 'npx',
142
+ args: ['-y', '@ryuenn3123/agentic-senior-core', 'mcp'],
143
+ },
144
+ },
145
+ };
146
+
147
+ if (!(await pathExists(workspaceMcpConfigurationPath))) {
148
+ await ensureDirectory(vscodeDirectoryPath);
149
+ await fs.writeFile(
150
+ workspaceMcpConfigurationPath,
151
+ JSON.stringify(workspaceMcpConfiguration, null, 2) + '\n',
152
+ 'utf8'
153
+ );
140
154
  }
141
155
  }
142
156
  }
package/mcp.json CHANGED
@@ -1,5 +1,4 @@
1
1
  {
2
- "$schema": "https://modelcontextprotocol.io/schemas/mcp.json",
3
2
  "version": "1.0",
4
3
  "name": "agentic-senior-core",
5
4
  "description": "MCP configuration for governance-aware diagnostics and self-healing workflows with full knowledge injection.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryuenn3123/agentic-senior-core",
3
- "version": "2.0.8",
3
+ "version": "2.0.10",
4
4
  "type": "module",
5
5
  "description": "Force your AI Agent to code like a Staff Engineer, not a Junior.",
6
6
  "bin": {
@@ -53,6 +53,6 @@
53
53
  "report:quality-trend": "node ./scripts/quality-trend-report.mjs",
54
54
  "report:governance-weekly": "node ./scripts/governance-weekly-report.mjs",
55
55
  "validate": "node ./scripts/validate.mjs",
56
- "test": "node --test ./tests/cli-smoke.test.mjs ./tests/llm-judge.test.mjs ./tests/enterprise-ops.test.mjs ./tests/skill-tier-gate.test.mjs"
56
+ "test": "node --test ./tests/cli-smoke.test.mjs ./tests/mcp-server.test.mjs ./tests/llm-judge.test.mjs ./tests/enterprise-ops.test.mjs ./tests/skill-tier-gate.test.mjs"
57
57
  }
58
58
  }
@@ -0,0 +1,371 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync } from 'node:fs';
4
+ import { spawn } from 'node:child_process';
5
+ import { dirname, resolve } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const SCRIPT_FILE_PATH = fileURLToPath(import.meta.url);
9
+ const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '..');
10
+ const PACKAGE_VERSION = JSON.parse(
11
+ readFileSync(resolve(REPOSITORY_ROOT, 'package.json'), 'utf8')
12
+ ).version;
13
+ const DEFAULT_PROTOCOL_VERSION = '2024-11-05';
14
+
15
+ const TEST_SUITE_ARGS = {
16
+ full: ['--test', './tests/cli-smoke.test.mjs', './tests/llm-judge.test.mjs', './tests/enterprise-ops.test.mjs', './tests/skill-tier-gate.test.mjs'],
17
+ cli: ['--test', './tests/cli-smoke.test.mjs'],
18
+ enterprise: ['--test', './tests/enterprise-ops.test.mjs'],
19
+ 'llm-judge': ['--test', './tests/llm-judge.test.mjs'],
20
+ 'skill-tier': ['--test', './tests/skill-tier-gate.test.mjs'],
21
+ };
22
+
23
+ const TOOL_DEFINITIONS = [
24
+ {
25
+ name: 'validate',
26
+ description: 'Run repository validation checks.',
27
+ inputSchema: {
28
+ type: 'object',
29
+ properties: {},
30
+ additionalProperties: false,
31
+ },
32
+ },
33
+ {
34
+ name: 'test',
35
+ description: 'Run test suites (full or targeted).',
36
+ inputSchema: {
37
+ type: 'object',
38
+ properties: {
39
+ suite: {
40
+ type: 'string',
41
+ enum: ['full', 'cli', 'enterprise', 'llm-judge', 'skill-tier'],
42
+ description: 'Target test suite. Defaults to full.',
43
+ },
44
+ },
45
+ additionalProperties: false,
46
+ },
47
+ },
48
+ {
49
+ name: 'release_gate',
50
+ description: 'Run release gate checks.',
51
+ inputSchema: {
52
+ type: 'object',
53
+ properties: {},
54
+ additionalProperties: false,
55
+ },
56
+ },
57
+ {
58
+ name: 'forbidden_content_check',
59
+ description: 'Run forbidden content scan used by publish gate.',
60
+ inputSchema: {
61
+ type: 'object',
62
+ properties: {},
63
+ additionalProperties: false,
64
+ },
65
+ },
66
+ ];
67
+
68
+ let incomingBuffer = Buffer.alloc(0);
69
+
70
+ function findHeaderTerminator(buffer) {
71
+ const crlfHeaderEndIndex = buffer.indexOf('\r\n\r\n');
72
+ if (crlfHeaderEndIndex !== -1) {
73
+ return {
74
+ headerEndIndex: crlfHeaderEndIndex,
75
+ delimiterLength: 4,
76
+ lineSeparator: '\r\n',
77
+ };
78
+ }
79
+
80
+ const lfHeaderEndIndex = buffer.indexOf('\n\n');
81
+ if (lfHeaderEndIndex !== -1) {
82
+ return {
83
+ headerEndIndex: lfHeaderEndIndex,
84
+ delimiterLength: 2,
85
+ lineSeparator: '\n',
86
+ };
87
+ }
88
+
89
+ return null;
90
+ }
91
+
92
+ function writeMessage(payload) {
93
+ const serializedPayload = JSON.stringify(payload);
94
+ const payloadLength = Buffer.byteLength(serializedPayload, 'utf8');
95
+ process.stdout.write(`Content-Length: ${payloadLength}\r\n\r\n${serializedPayload}`);
96
+ }
97
+
98
+ function sendResponse(id, result) {
99
+ writeMessage({
100
+ jsonrpc: '2.0',
101
+ id,
102
+ result,
103
+ });
104
+ }
105
+
106
+ function sendError(id, code, message, data) {
107
+ writeMessage({
108
+ jsonrpc: '2.0',
109
+ id,
110
+ error: {
111
+ code,
112
+ message,
113
+ data,
114
+ },
115
+ });
116
+ }
117
+
118
+ function normalizeToolName(rawToolName) {
119
+ return typeof rawToolName === 'string' ? rawToolName.trim() : '';
120
+ }
121
+
122
+ function buildCommandOutput(commandLabel, commandArguments, exitCode, stdoutContent, stderrContent) {
123
+ const outputSections = [
124
+ `Command: node ${commandArguments.join(' ')}`,
125
+ `Exit code: ${exitCode}`,
126
+ ];
127
+
128
+ if (stdoutContent.trim().length > 0) {
129
+ outputSections.push(`STDOUT:\n${stdoutContent.trimEnd()}`);
130
+ }
131
+
132
+ if (stderrContent.trim().length > 0) {
133
+ outputSections.push(`STDERR:\n${stderrContent.trimEnd()}`);
134
+ }
135
+
136
+ return [
137
+ `[${commandLabel}]`,
138
+ outputSections.join('\n\n'),
139
+ ].join('\n\n');
140
+ }
141
+
142
+ function runNodeCommand(commandLabel, commandArguments) {
143
+ return new Promise((resolveResult) => {
144
+ const childProcess = spawn(process.execPath, commandArguments, {
145
+ cwd: REPOSITORY_ROOT,
146
+ env: process.env,
147
+ });
148
+
149
+ let stdoutContent = '';
150
+ let stderrContent = '';
151
+
152
+ childProcess.stdout.on('data', (chunk) => {
153
+ stdoutContent += chunk.toString('utf8');
154
+ });
155
+
156
+ childProcess.stderr.on('data', (chunk) => {
157
+ stderrContent += chunk.toString('utf8');
158
+ });
159
+
160
+ childProcess.on('error', (error) => {
161
+ resolveResult({
162
+ content: [
163
+ {
164
+ type: 'text',
165
+ text: `[${commandLabel}] Failed to start command: ${error.message}`,
166
+ },
167
+ ],
168
+ isError: true,
169
+ });
170
+ });
171
+
172
+ childProcess.on('close', (exitCode) => {
173
+ const normalizedExitCode = typeof exitCode === 'number' ? exitCode : 1;
174
+ resolveResult({
175
+ content: [
176
+ {
177
+ type: 'text',
178
+ text: buildCommandOutput(
179
+ commandLabel,
180
+ commandArguments,
181
+ normalizedExitCode,
182
+ stdoutContent,
183
+ stderrContent
184
+ ),
185
+ },
186
+ ],
187
+ isError: normalizedExitCode !== 0,
188
+ });
189
+ });
190
+ });
191
+ }
192
+
193
+ async function executeToolCall(toolName, toolArguments = {}) {
194
+ if (toolName === 'validate') {
195
+ return runNodeCommand('validate', ['./scripts/validate.mjs']);
196
+ }
197
+
198
+ if (toolName === 'test') {
199
+ const requestedSuite = typeof toolArguments.suite === 'string'
200
+ ? toolArguments.suite
201
+ : 'full';
202
+
203
+ const selectedSuite = TEST_SUITE_ARGS[requestedSuite] ? requestedSuite : 'full';
204
+ return runNodeCommand(`test:${selectedSuite}`, TEST_SUITE_ARGS[selectedSuite]);
205
+ }
206
+
207
+ if (toolName === 'release_gate') {
208
+ return runNodeCommand('release_gate', ['./scripts/release-gate.mjs']);
209
+ }
210
+
211
+ if (toolName === 'forbidden_content_check') {
212
+ return runNodeCommand('forbidden_content_check', ['./scripts/forbidden-content-check.mjs']);
213
+ }
214
+
215
+ return {
216
+ content: [
217
+ {
218
+ type: 'text',
219
+ text: `Unknown tool: ${toolName}`,
220
+ },
221
+ ],
222
+ isError: true,
223
+ };
224
+ }
225
+
226
+ async function handleRequest(requestMessage) {
227
+ const requestId = requestMessage.id;
228
+ const requestMethod = requestMessage.method;
229
+ const requestParams = requestMessage.params || {};
230
+
231
+ if (typeof requestMethod !== 'string') {
232
+ if (typeof requestId !== 'undefined') {
233
+ sendError(requestId, -32600, 'Invalid Request');
234
+ }
235
+ return;
236
+ }
237
+
238
+ if (requestMethod === 'initialize') {
239
+ const negotiatedProtocolVersion = typeof requestParams.protocolVersion === 'string'
240
+ ? requestParams.protocolVersion
241
+ : DEFAULT_PROTOCOL_VERSION;
242
+
243
+ sendResponse(requestId, {
244
+ protocolVersion: negotiatedProtocolVersion,
245
+ capabilities: {
246
+ tools: {
247
+ listChanged: false,
248
+ },
249
+ },
250
+ serverInfo: {
251
+ name: 'agentic-senior-core',
252
+ version: PACKAGE_VERSION,
253
+ },
254
+ });
255
+ return;
256
+ }
257
+
258
+ if (requestMethod === 'notifications/initialized') {
259
+ return;
260
+ }
261
+
262
+ if (requestMethod === 'ping') {
263
+ if (typeof requestId !== 'undefined') {
264
+ sendResponse(requestId, {});
265
+ }
266
+ return;
267
+ }
268
+
269
+ if (requestMethod === 'tools/list') {
270
+ sendResponse(requestId, {
271
+ tools: TOOL_DEFINITIONS,
272
+ });
273
+ return;
274
+ }
275
+
276
+ if (requestMethod === 'tools/call') {
277
+ const requestedToolName = normalizeToolName(requestParams.name);
278
+
279
+ if (!requestedToolName) {
280
+ sendError(requestId, -32602, 'Invalid params: tool name is required');
281
+ return;
282
+ }
283
+
284
+ const toolResult = await executeToolCall(requestedToolName, requestParams.arguments || {});
285
+ sendResponse(requestId, toolResult);
286
+ return;
287
+ }
288
+
289
+ if (typeof requestId !== 'undefined') {
290
+ sendError(requestId, -32601, `Method not found: ${requestMethod}`);
291
+ }
292
+ }
293
+
294
+ function readNextFramedMessage() {
295
+ const headerTerminator = findHeaderTerminator(incomingBuffer);
296
+ if (!headerTerminator) {
297
+ return null;
298
+ }
299
+
300
+ const { headerEndIndex, delimiterLength, lineSeparator } = headerTerminator;
301
+
302
+ const rawHeader = incomingBuffer.slice(0, headerEndIndex).toString('utf8');
303
+ const headerLines = rawHeader.split(lineSeparator);
304
+ let contentLength = null;
305
+
306
+ for (const headerLine of headerLines) {
307
+ const separatorIndex = headerLine.indexOf(':');
308
+ if (separatorIndex === -1) {
309
+ continue;
310
+ }
311
+
312
+ const headerName = headerLine.slice(0, separatorIndex).trim().toLowerCase();
313
+ const headerValue = headerLine.slice(separatorIndex + 1).trim();
314
+
315
+ if (headerName === 'content-length') {
316
+ contentLength = Number.parseInt(headerValue, 10);
317
+ break;
318
+ }
319
+ }
320
+
321
+ if (!Number.isFinite(contentLength) || contentLength < 0) {
322
+ incomingBuffer = Buffer.alloc(0);
323
+ return null;
324
+ }
325
+
326
+ const bodyStartIndex = headerEndIndex + delimiterLength;
327
+ const frameEndIndex = bodyStartIndex + contentLength;
328
+
329
+ if (incomingBuffer.length < frameEndIndex) {
330
+ return null;
331
+ }
332
+
333
+ const rawMessage = incomingBuffer.slice(bodyStartIndex, frameEndIndex).toString('utf8');
334
+ incomingBuffer = incomingBuffer.slice(frameEndIndex);
335
+ return rawMessage;
336
+ }
337
+
338
+ function processIncomingBuffer() {
339
+ while (true) {
340
+ const framedMessage = readNextFramedMessage();
341
+ if (framedMessage === null) {
342
+ return;
343
+ }
344
+
345
+ let parsedRequest;
346
+ try {
347
+ parsedRequest = JSON.parse(framedMessage);
348
+ } catch {
349
+ continue;
350
+ }
351
+
352
+ Promise.resolve(handleRequest(parsedRequest)).catch((error) => {
353
+ if (typeof parsedRequest?.id !== 'undefined') {
354
+ sendError(parsedRequest.id, -32603, 'Internal error', String(error?.message || error));
355
+ }
356
+ });
357
+ }
358
+ }
359
+
360
+ process.stdin.on('data', (chunk) => {
361
+ incomingBuffer = Buffer.concat([incomingBuffer, chunk]);
362
+ processIncomingBuffer();
363
+ });
364
+
365
+ process.stdin.on('end', () => {
366
+ process.exit(0);
367
+ });
368
+
369
+ process.on('SIGINT', () => {
370
+ process.exit(0);
371
+ });
@@ -151,6 +151,7 @@ async function validateRequiredFiles() {
151
151
  'scripts/benchmark-gate.mjs',
152
152
  'scripts/benchmark-intelligence.mjs',
153
153
  'scripts/governance-weekly-report.mjs',
154
+ 'scripts/mcp-server.mjs',
154
155
  'scripts/frontend-usability-audit.mjs',
155
156
  'scripts/release-gate.mjs',
156
157
  'scripts/generate-sbom.mjs',
@@ -175,11 +176,13 @@ async function validateRequiredFiles() {
175
176
  '.agent-context/state/benchmark-watchlist.json',
176
177
  '.agent-context/state/skill-platform.json',
177
178
  '.agent-context/skills/index.json',
179
+ '.vscode/mcp.json',
178
180
  '.github/workflows/release-gate.yml',
179
181
  '.github/workflows/sbom-compliance.yml',
180
182
  '.github/workflows/benchmark-intelligence.yml',
181
183
  '.github/workflows/governance-weekly-report.yml',
182
184
  'tests/cli-smoke.test.mjs',
185
+ 'tests/mcp-server.test.mjs',
183
186
  'tests/llm-judge.test.mjs',
184
187
  'tests/enterprise-ops.test.mjs',
185
188
  'LICENSE',
@@ -700,6 +703,8 @@ async function validateMcpConfiguration() {
700
703
  const mcpConfiguration = JSON.parse(await readTextFile(join(ROOT_DIR, 'mcp.json')));
701
704
  const lintServerCommand = mcpConfiguration.servers?.lint?.command;
702
705
  const testServerCommand = mcpConfiguration.servers?.test?.command;
706
+ const workspaceMcpConfiguration = JSON.parse(await readTextFile(join(ROOT_DIR, '.vscode', 'mcp.json')));
707
+ const workspaceServerConfig = workspaceMcpConfiguration.servers?.['agentic-senior-core'];
703
708
 
704
709
  if (lintServerCommand === 'node') {
705
710
  pass('MCP lint server uses Node');
@@ -712,6 +717,24 @@ async function validateMcpConfiguration() {
712
717
  } else {
713
718
  fail('MCP test server must use Node');
714
719
  }
720
+
721
+ if (workspaceMcpConfiguration.$schema === 'vscode://schemas/mcp') {
722
+ pass('Workspace MCP config uses trusted VS Code schema');
723
+ } else {
724
+ fail('Workspace MCP config must use $schema: vscode://schemas/mcp');
725
+ }
726
+
727
+ if (workspaceServerConfig?.command === 'node') {
728
+ pass('Workspace MCP server command uses Node');
729
+ } else {
730
+ fail('Workspace MCP server command must use Node');
731
+ }
732
+
733
+ if (Array.isArray(workspaceServerConfig?.args) && workspaceServerConfig.args.includes('./scripts/mcp-server.mjs')) {
734
+ pass('Workspace MCP server points to scripts/mcp-server.mjs');
735
+ } else {
736
+ fail('Workspace MCP server must include ./scripts/mcp-server.mjs argument');
737
+ }
715
738
  }
716
739
 
717
740
  async function validateHumanWritingGovernance() {