@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 +1 -1
- package/.windsurfrules +1 -1
- package/README.md +88 -47
- package/bin/agentic-senior-core.js +6 -0
- package/lib/cli/commands/init.mjs +1 -1
- package/lib/cli/commands/mcp.mjs +3 -0
- package/lib/cli/utils.mjs +23 -9
- package/mcp.json +0 -1
- package/package.json +2 -2
- package/scripts/mcp-server.mjs +371 -0
- package/scripts/validate.mjs +23 -0
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.
|
|
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.
|
|
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
|
-
###
|
|
41
|
+
### Method 1 (Recommended): npm package
|
|
42
42
|
|
|
43
|
-
The
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
58
|
+
Use team defaults with profile packs:
|
|
59
59
|
|
|
60
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
111
|
+
### Newbie mode
|
|
85
112
|
|
|
86
|
-
|
|
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
|
-
|
|
116
|
+
npx @ryuenn3123/agentic-senior-core init --newbie
|
|
100
117
|
```
|
|
101
118
|
|
|
102
|
-
|
|
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
|
-
|
|
125
|
+
### MCP Setup in VS Code (No File Picker)
|
|
105
126
|
|
|
106
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
142
|
+
### CLI Command Reference
|
|
121
143
|
|
|
122
|
-
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
|
274
|
-
- **MCP Registration Model:** IDE MCP server registration is manual;
|
|
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 #
|
|
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
|
|
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 ? '
|
|
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 {
|
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
|
|
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
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ryuenn3123/agentic-senior-core",
|
|
3
|
-
"version": "2.0.
|
|
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
|
+
});
|
package/scripts/validate.mjs
CHANGED
|
@@ -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() {
|