@ryuenn3123/agentic-senior-core 2.0.7 → 2.0.9
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/.agent-context/prompts/review-code.md +3 -3
- package/.agent-context/review-checklists/pr-checklist.md +11 -6
- package/.agent-context/rules/api-docs.md +34 -0
- package/.agent-context/skills/review-quality.md +3 -0
- package/.cursorrules +1 -1
- package/.gemini/instructions.md +1 -1
- package/.github/copilot-instructions.md +2 -2
- package/.windsurfrules +1 -1
- package/AGENTS.md +1 -1
- package/README.md +26 -2
- package/bin/agentic-senior-core.js +6 -0
- package/lib/cli/commands/init.mjs +13 -1
- package/lib/cli/commands/mcp.mjs +3 -0
- package/lib/cli/commands/upgrade.mjs +9 -1
- package/lib/cli/constants.mjs +2 -2
- package/lib/cli/utils.mjs +34 -2
- package/mcp.json +0 -1
- package/package.json +1 -1
- package/scripts/mcp-server.mjs +347 -0
- package/scripts/validate.mjs +90 -0
|
@@ -22,11 +22,11 @@ For EVERY violation found:
|
|
|
22
22
|
|
|
23
23
|
Output format:
|
|
24
24
|
## PR REVIEW RESULTS
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
PASS [Item]
|
|
26
|
+
FAIL [Item] (with Reasoning Chain)
|
|
27
27
|
|
|
28
28
|
## SECURITY AUDIT RESULTS
|
|
29
|
-
|
|
29
|
+
CRITICAL/HIGH/MEDIUM/LOW [Finding] — severity + fix
|
|
30
30
|
|
|
31
31
|
VERDICT: PASS / FAIL
|
|
32
32
|
```
|
|
@@ -13,13 +13,13 @@ Output format:
|
|
|
13
13
|
## PR REVIEW RESULTS
|
|
14
14
|
━━━━━━━━━━━━━━━━━━━
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
PASS [Item]
|
|
17
|
+
FAIL [Item]
|
|
18
|
+
Rule: [rule file + section]
|
|
19
|
+
Problem: [specific issue found]
|
|
20
|
+
Fix: [what to change]
|
|
21
21
|
|
|
22
|
-
VERDICT: PASS
|
|
22
|
+
VERDICT: PASS / FAIL (X/Y items passed)
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
---
|
|
@@ -95,3 +95,8 @@ VERDICT: PASS ✅ / FAIL ❌ (X/Y items passed)
|
|
|
95
95
|
- [ ] Complex business logic has comments explaining WHY
|
|
96
96
|
- [ ] Public functions/methods have JSDoc/docstrings
|
|
97
97
|
- [ ] README updated if new setup steps required
|
|
98
|
+
- [ ] No emoji in formal documentation or review summaries
|
|
99
|
+
- [ ] Documentation uses plain English and avoids AI cliches
|
|
100
|
+
- [ ] Performance/quality claims include source and timestamp
|
|
101
|
+
- [ ] Acronyms are expanded on first use
|
|
102
|
+
- [ ] Facts and assumptions are explicitly separated
|
|
@@ -25,6 +25,40 @@ REQUIRED: Documentation MUST be updated in the SAME commit as the endpoint chang
|
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
28
|
+
## Human Writing Standard (Mandatory)
|
|
29
|
+
|
|
30
|
+
This standard applies to API docs, README updates, release notes, and technical explanations.
|
|
31
|
+
|
|
32
|
+
### Style Baseline
|
|
33
|
+
1. Write for native English speakers.
|
|
34
|
+
2. Target an 8th-grade reading level.
|
|
35
|
+
3. Use clear, direct, plain language.
|
|
36
|
+
4. Keep sentence rhythm natural with short and medium sentences.
|
|
37
|
+
5. Sound confident, practical, and conversational.
|
|
38
|
+
|
|
39
|
+
### Required Behavior
|
|
40
|
+
1. Explain decisions the way a competent coworker would explain them out loud.
|
|
41
|
+
2. Cut unnecessary words and remove filler.
|
|
42
|
+
3. Use concrete verbs and everyday phrasing.
|
|
43
|
+
4. Rewrite and reorder content when flow is weak.
|
|
44
|
+
|
|
45
|
+
### Hard Bans
|
|
46
|
+
1. No emoji in formal artifacts.
|
|
47
|
+
2. No AI cliches: delve, leverage, robust, utilize, seamless.
|
|
48
|
+
3. No inflated, academic, or performative language.
|
|
49
|
+
4. No padding, hedging, or redundant phrasing.
|
|
50
|
+
|
|
51
|
+
### Critical Controls
|
|
52
|
+
1. Any claim about quality, performance, or reliability must include a measurable source and timestamp.
|
|
53
|
+
2. Expand acronyms on first use, then use terms consistently.
|
|
54
|
+
3. Separate facts from assumptions explicitly.
|
|
55
|
+
4. End major explanations with a clear next action.
|
|
56
|
+
|
|
57
|
+
### Final Check
|
|
58
|
+
Read the text out loud before shipping. If it sounds robotic, rewrite it.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
28
62
|
## Documentation Format: OpenAPI 3.1 (Non-Negotiable)
|
|
29
63
|
|
|
30
64
|
All APIs produce an OpenAPI 3.1 specification. Not 3.0, not proprietary formats, not "we'll add Swagger later."
|
|
@@ -19,6 +19,9 @@ Turn code review, planning, and benchmark output into explicit quality decisions
|
|
|
19
19
|
- Benchmark deltas are explicit
|
|
20
20
|
- Security findings stop release when critical
|
|
21
21
|
- Release readiness verdict includes blockers, owner, and due date
|
|
22
|
+
- Formal review artifacts use plain, human-first language and avoid AI cliches
|
|
23
|
+
- No emoji in formal review output, release notes, and governance summaries
|
|
24
|
+
- Claims include measurable evidence with source and timestamp
|
|
22
25
|
|
|
23
26
|
## Evidence
|
|
24
27
|
- PR review report
|
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.9
|
|
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/.gemini/instructions.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Adapter Mode: thin
|
|
4
4
|
Adapter Source: .instructions.md
|
|
5
|
-
Canonical Snapshot SHA256:
|
|
5
|
+
Canonical Snapshot SHA256: 08994f6e228b32d415dcc2024f31f0a076119a3cf87a4cd2fd2e78e86e5fbd3e
|
|
6
6
|
|
|
7
7
|
Canonical policy source: [.instructions.md](../.instructions.md).
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Adapter Mode: thin
|
|
4
4
|
Adapter Source: .instructions.md
|
|
5
|
-
Canonical Snapshot SHA256:
|
|
5
|
+
Canonical Snapshot SHA256: 08994f6e228b32d415dcc2024f31f0a076119a3cf87a4cd2fd2e78e86e5fbd3e
|
|
6
6
|
|
|
7
7
|
The canonical policy source for this repository is [.instructions.md](../.instructions.md).
|
|
8
8
|
|
|
@@ -18,4 +18,4 @@ The canonical policy source for this repository is [.instructions.md](../.instru
|
|
|
18
18
|
|
|
19
19
|
## Completion Gate
|
|
20
20
|
|
|
21
|
-
Run [.agent-context/review-checklists/pr-checklist.md](../.agent-context/review-checklists/pr-checklist.md) before declaring work complete.
|
|
21
|
+
Run [.agent-context/review-checklists/pr-checklist.md](../.agent-context/review-checklists/pr-checklist.md) before declaring work complete.
|
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.9
|
|
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/AGENTS.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Adapter Mode: thin
|
|
4
4
|
Adapter Source: .instructions.md
|
|
5
|
-
Canonical Snapshot SHA256:
|
|
5
|
+
Canonical Snapshot SHA256: 08994f6e228b32d415dcc2024f31f0a076119a3cf87a4cd2fd2e78e86e5fbd3e
|
|
6
6
|
|
|
7
7
|
This file is an adapter entrypoint for agent discovery.
|
|
8
8
|
The canonical policy source is [.instructions.md](.instructions.md).
|
package/README.md
CHANGED
|
@@ -119,6 +119,26 @@ npx @ryuenn3123/agentic-senior-core init --profile-pack startup
|
|
|
119
119
|
|
|
120
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!
|
|
121
121
|
|
|
122
|
+
Important behavior:
|
|
123
|
+
- `init` does not copy repository workflows from this project into your target repository.
|
|
124
|
+
- MCP server registration and trust/start are managed manually in IDE settings.
|
|
125
|
+
- If you want the MCP workspace scaffold, run `init` with `--mcp-template` (creates `.vscode/mcp.json`).
|
|
126
|
+
|
|
127
|
+
### MCP Setup in VS Code (No File Picker)
|
|
128
|
+
|
|
129
|
+
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.
|
|
130
|
+
|
|
131
|
+
1. Generate workspace MCP config:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
npx @ryuenn3123/agentic-senior-core init --mcp-template
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
2. Open Command Palette and run `MCP: Open Workspace Folder Configuration`.
|
|
138
|
+
3. Confirm the file is `.vscode/mcp.json` with server `agentic-senior-core`.
|
|
139
|
+
4. The generated server command is `npx -y @ryuenn3123/agentic-senior-core mcp`.
|
|
140
|
+
5. Open Chat Customizations > MCP Servers, then trust/start the server.
|
|
141
|
+
|
|
122
142
|
If you are totally new to concepts like blueprints and guardrails, no problem — just run:
|
|
123
143
|
```bash
|
|
124
144
|
npx @ryuenn3123/agentic-senior-core init --newbie
|
|
@@ -265,7 +285,8 @@ Our documentation has shifted into dedicated tracks to keep this README light:
|
|
|
265
285
|
- **Automated Guardrails:** CI blueprints include LLM-as-a-Judge flow using `pr-checklist.md`.
|
|
266
286
|
- **Pre-Publish Safety:** Built-in forbidden content checks detect hardcoded secrets and stray debugger artifacts before hitting the NPM registry.
|
|
267
287
|
- **Machine-Readable CI Output:** LLM Judge emits `JSON_REPORT` payloads and writes `.agent-context/state/llm-judge-report.json` for PR/MR annotation tooling.
|
|
268
|
-
- **MCP
|
|
288
|
+
- **MCP Runtime Server:** `scripts/mcp-server.mjs` exposes validate/test/release checks as MCP tools.
|
|
289
|
+
- **MCP Registration Model:** IDE MCP server registration is manual; workspace config lives in `.vscode/mcp.json` (`--mcp-template`).
|
|
269
290
|
|
|
270
291
|
---
|
|
271
292
|
|
|
@@ -276,7 +297,9 @@ Our documentation has shifted into dedicated tracks to keep this README light:
|
|
|
276
297
|
├── .cursorrules # Dynamic compiled governance entry point
|
|
277
298
|
├── .windsurfrules # Dynamic compiled governance entry point
|
|
278
299
|
├── .agent-override.md # Team-specific exceptions (scoped + expiry)
|
|
279
|
-
├── mcp.json #
|
|
300
|
+
├── mcp.json # Governance metadata and knowledge-layer contract
|
|
301
|
+
├── .vscode/
|
|
302
|
+
│ └── mcp.json # VS Code MCP workspace server configuration
|
|
280
303
|
├── AGENTS.md # Universal agent discovery
|
|
281
304
|
├── .github/copilot-instructions.md # GitHub Copilot entry point
|
|
282
305
|
├── .gemini/instructions.md # Antigravity / Gemini entry point
|
|
@@ -294,6 +317,7 @@ Our documentation has shifted into dedicated tracks to keep this README light:
|
|
|
294
317
|
├── scripts/
|
|
295
318
|
│ ├── validate.mjs # Repository validator
|
|
296
319
|
│ ├── llm-judge.mjs # LLM-as-a-Judge CI gate
|
|
320
|
+
│ ├── mcp-server.mjs # Local MCP stdio server (validate/test/release tools)
|
|
297
321
|
│ ├── init-project.sh # GitHub bootstrap script (Linux/macOS)
|
|
298
322
|
│ └── init-project.ps1 # GitHub bootstrap script (Windows)
|
|
299
323
|
├── docs/
|
|
@@ -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);
|
|
@@ -57,6 +57,7 @@ export function parseInitArguments(commandArguments) {
|
|
|
57
57
|
newbie: false,
|
|
58
58
|
tokenOptimize: true,
|
|
59
59
|
tokenAgent: 'copilot',
|
|
60
|
+
includeMcpTemplate: false,
|
|
60
61
|
};
|
|
61
62
|
|
|
62
63
|
for (let argumentIndex = 0; argumentIndex < commandArguments.length; argumentIndex++) {
|
|
@@ -160,6 +161,11 @@ export function parseInitArguments(commandArguments) {
|
|
|
160
161
|
continue;
|
|
161
162
|
}
|
|
162
163
|
|
|
164
|
+
if (currentArgument === '--mcp-template') {
|
|
165
|
+
parsedInitOptions.includeMcpTemplate = true;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
|
|
163
169
|
throw new Error(`Unknown option: ${currentArgument}`);
|
|
164
170
|
}
|
|
165
171
|
|
|
@@ -177,6 +183,7 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
177
183
|
const isTokenOptimizationEnabled = typeof initOptions.tokenOptimize === 'boolean'
|
|
178
184
|
? initOptions.tokenOptimize
|
|
179
185
|
: true;
|
|
186
|
+
const shouldIncludeMcpTemplate = initOptions.includeMcpTemplate === true;
|
|
180
187
|
const selectedTokenAgentName = normalizeAgentName(initOptions.tokenAgent || 'copilot');
|
|
181
188
|
|
|
182
189
|
if (resolvedTargetDirectoryPath.toLowerCase() === 'c:\\windows' || resolvedTargetDirectoryPath.toLowerCase() === 'c:\\windows\\system32') {
|
|
@@ -348,7 +355,9 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
348
355
|
? selectedProfile.defaultCi
|
|
349
356
|
: await askYesNo('Enable CI/CD guardrails and the LLM Judge policy?', userInterface, selectedProfile.defaultCi);
|
|
350
357
|
|
|
351
|
-
await copyGovernanceAssetsToTarget(resolvedTargetDirectoryPath
|
|
358
|
+
await copyGovernanceAssetsToTarget(resolvedTargetDirectoryPath, {
|
|
359
|
+
includeMcpTemplate: shouldIncludeMcpTemplate,
|
|
360
|
+
});
|
|
352
361
|
|
|
353
362
|
if (isTokenOptimizationEnabled) {
|
|
354
363
|
const detectedExternalProxy = detectRtkBinary();
|
|
@@ -419,6 +428,8 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
419
428
|
console.log(`- Blocking severities: ${formatBlockingSeverities(selectedProfile.blockingSeverities)}`);
|
|
420
429
|
console.log(`- Setup time: ${formatDuration(setupDurationMs)}`);
|
|
421
430
|
console.log('- Generated files: .cursorrules, .windsurfrules, and .agent-context/state/onboarding-report.json');
|
|
431
|
+
console.log(`- Repository workflows copied: no (workflows remain source-repo assets)`);
|
|
432
|
+
console.log(`- MCP template file: ${shouldIncludeMcpTemplate ? 'created (.vscode/mcp.json)' : 'not created by default (use --mcp-template)'}`);
|
|
422
433
|
if (isTokenOptimizationEnabled) {
|
|
423
434
|
console.log(`- Token optimization policy: enabled for ${selectedTokenAgentName}`);
|
|
424
435
|
} else {
|
|
@@ -427,6 +438,7 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
427
438
|
console.log('\nPlain-language summary:');
|
|
428
439
|
console.log(`I prepared a ${selectedProfile.displayName.toLowerCase()} governance pack for a ${toTitleCase(selectedResolvedStackFileName)} project using the ${toTitleCase(selectedResolvedBlueprintFileName)} blueprint.`);
|
|
429
440
|
console.log('Your AI tools will now receive one compiled rulebook plus the original source rules, and your review threshold is stored in .agent-context/policies/llm-judge-threshold.json.');
|
|
441
|
+
console.log('MCP server registration is manual inside your IDE settings, even when mcp.json exists.');
|
|
430
442
|
} catch (error) {
|
|
431
443
|
console.error('\n[FATAL] An error occurred during initialization. Attempting automatic rollback...');
|
|
432
444
|
try {
|
|
@@ -43,6 +43,7 @@ export function parseUpgradeArguments(commandArguments) {
|
|
|
43
43
|
targetDirectory: '.',
|
|
44
44
|
dryRun: false,
|
|
45
45
|
skipConfirmation: false,
|
|
46
|
+
includeMcpTemplate: false,
|
|
46
47
|
};
|
|
47
48
|
|
|
48
49
|
for (let argumentIndex = 0; argumentIndex < commandArguments.length; argumentIndex++) {
|
|
@@ -63,6 +64,11 @@ export function parseUpgradeArguments(commandArguments) {
|
|
|
63
64
|
continue;
|
|
64
65
|
}
|
|
65
66
|
|
|
67
|
+
if (currentArgument === '--mcp-template') {
|
|
68
|
+
parsedUpgradeOptions.includeMcpTemplate = true;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
|
|
66
72
|
throw new Error(`Unknown option: ${currentArgument}`);
|
|
67
73
|
}
|
|
68
74
|
|
|
@@ -95,7 +101,9 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
|
|
|
95
101
|
console.log(`\nAgentic-Senior-Core CLI v${CLI_VERSION}`);
|
|
96
102
|
console.log('Running upgrade assistant for an existing repository.');
|
|
97
103
|
|
|
98
|
-
await copyGovernanceAssetsToTarget(resolvedTargetDirectoryPath
|
|
104
|
+
await copyGovernanceAssetsToTarget(resolvedTargetDirectoryPath, {
|
|
105
|
+
includeMcpTemplate: upgradeOptions.includeMcpTemplate === true,
|
|
106
|
+
});
|
|
99
107
|
|
|
100
108
|
const stackFileNames = await collectFileNames(path.join(AGENT_CONTEXT_DIR, 'stacks'));
|
|
101
109
|
const blueprintFileNames = await collectFileNames(path.join(AGENT_CONTEXT_DIR, 'blueprints'));
|
package/lib/cli/constants.mjs
CHANGED
|
@@ -164,8 +164,8 @@ export const entryPointFiles = [
|
|
|
164
164
|
'.cursorrules',
|
|
165
165
|
'.windsurfrules',
|
|
166
166
|
'AGENTS.md',
|
|
167
|
+
'.github/copilot-instructions.md',
|
|
167
168
|
'.agent-override.md',
|
|
168
|
-
'mcp.json',
|
|
169
169
|
];
|
|
170
170
|
|
|
171
|
-
export const directoryCopies = ['.agent-context', '.
|
|
171
|
+
export const directoryCopies = ['.agent-context', '.gemini', '.agents'];
|
package/lib/cli/utils.mjs
CHANGED
|
@@ -29,8 +29,9 @@ export function printUsage() {
|
|
|
29
29
|
console.log('Usage:');
|
|
30
30
|
console.log(' agentic-senior-core launch');
|
|
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
|
-
console.log(' agentic-senior-core upgrade [target-directory] [--dry-run] [--yes]');
|
|
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,6 +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');
|
|
52
|
+
console.log(' --mcp-template Create .vscode/mcp.json workspace template (MCP trust/start remains manual in IDE)');
|
|
51
53
|
console.log(' --dry-run Preview upgrade without writing files');
|
|
52
54
|
console.log(' --yes Skip confirmation prompts for upgrade');
|
|
53
55
|
console.log(' --agent Target agent integration for token optimization mode');
|
|
@@ -96,7 +98,12 @@ export async function copyDirectory(sourceDirectoryPath, targetDirectoryPath) {
|
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
100
|
|
|
99
|
-
export async function copyGovernanceAssetsToTarget(
|
|
101
|
+
export async function copyGovernanceAssetsToTarget(
|
|
102
|
+
resolvedTargetDirectoryPath,
|
|
103
|
+
options = {}
|
|
104
|
+
) {
|
|
105
|
+
const shouldIncludeMcpTemplate = options.includeMcpTemplate === true;
|
|
106
|
+
|
|
100
107
|
for (const sourceDirectoryName of directoryCopies) {
|
|
101
108
|
const sourceDirectoryPath = path.join(REPO_ROOT, sourceDirectoryName);
|
|
102
109
|
if (!(await pathExists(sourceDirectoryPath))) {
|
|
@@ -121,6 +128,31 @@ export async function copyGovernanceAssetsToTarget(resolvedTargetDirectoryPath)
|
|
|
121
128
|
await ensureDirectory(path.dirname(targetFilePath));
|
|
122
129
|
await fs.copyFile(sourceFilePath, targetFilePath);
|
|
123
130
|
}
|
|
131
|
+
|
|
132
|
+
if (shouldIncludeMcpTemplate) {
|
|
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
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
124
156
|
}
|
|
125
157
|
|
|
126
158
|
export async function askChoice(promptMessage, options, userInterface) {
|
package/mcp.json
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,347 @@
|
|
|
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 writeMessage(payload) {
|
|
71
|
+
const serializedPayload = JSON.stringify(payload);
|
|
72
|
+
const payloadLength = Buffer.byteLength(serializedPayload, 'utf8');
|
|
73
|
+
process.stdout.write(`Content-Length: ${payloadLength}\r\n\r\n${serializedPayload}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function sendResponse(id, result) {
|
|
77
|
+
writeMessage({
|
|
78
|
+
jsonrpc: '2.0',
|
|
79
|
+
id,
|
|
80
|
+
result,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function sendError(id, code, message, data) {
|
|
85
|
+
writeMessage({
|
|
86
|
+
jsonrpc: '2.0',
|
|
87
|
+
id,
|
|
88
|
+
error: {
|
|
89
|
+
code,
|
|
90
|
+
message,
|
|
91
|
+
data,
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function normalizeToolName(rawToolName) {
|
|
97
|
+
return typeof rawToolName === 'string' ? rawToolName.trim() : '';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function buildCommandOutput(commandLabel, commandArguments, exitCode, stdoutContent, stderrContent) {
|
|
101
|
+
const outputSections = [
|
|
102
|
+
`Command: node ${commandArguments.join(' ')}`,
|
|
103
|
+
`Exit code: ${exitCode}`,
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
if (stdoutContent.trim().length > 0) {
|
|
107
|
+
outputSections.push(`STDOUT:\n${stdoutContent.trimEnd()}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (stderrContent.trim().length > 0) {
|
|
111
|
+
outputSections.push(`STDERR:\n${stderrContent.trimEnd()}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return [
|
|
115
|
+
`[${commandLabel}]`,
|
|
116
|
+
outputSections.join('\n\n'),
|
|
117
|
+
].join('\n\n');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function runNodeCommand(commandLabel, commandArguments) {
|
|
121
|
+
return new Promise((resolveResult) => {
|
|
122
|
+
const childProcess = spawn(process.execPath, commandArguments, {
|
|
123
|
+
cwd: REPOSITORY_ROOT,
|
|
124
|
+
env: process.env,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
let stdoutContent = '';
|
|
128
|
+
let stderrContent = '';
|
|
129
|
+
|
|
130
|
+
childProcess.stdout.on('data', (chunk) => {
|
|
131
|
+
stdoutContent += chunk.toString('utf8');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
childProcess.stderr.on('data', (chunk) => {
|
|
135
|
+
stderrContent += chunk.toString('utf8');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
childProcess.on('error', (error) => {
|
|
139
|
+
resolveResult({
|
|
140
|
+
content: [
|
|
141
|
+
{
|
|
142
|
+
type: 'text',
|
|
143
|
+
text: `[${commandLabel}] Failed to start command: ${error.message}`,
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
isError: true,
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
childProcess.on('close', (exitCode) => {
|
|
151
|
+
const normalizedExitCode = typeof exitCode === 'number' ? exitCode : 1;
|
|
152
|
+
resolveResult({
|
|
153
|
+
content: [
|
|
154
|
+
{
|
|
155
|
+
type: 'text',
|
|
156
|
+
text: buildCommandOutput(
|
|
157
|
+
commandLabel,
|
|
158
|
+
commandArguments,
|
|
159
|
+
normalizedExitCode,
|
|
160
|
+
stdoutContent,
|
|
161
|
+
stderrContent
|
|
162
|
+
),
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
isError: normalizedExitCode !== 0,
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function executeToolCall(toolName, toolArguments = {}) {
|
|
172
|
+
if (toolName === 'validate') {
|
|
173
|
+
return runNodeCommand('validate', ['./scripts/validate.mjs']);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (toolName === 'test') {
|
|
177
|
+
const requestedSuite = typeof toolArguments.suite === 'string'
|
|
178
|
+
? toolArguments.suite
|
|
179
|
+
: 'full';
|
|
180
|
+
|
|
181
|
+
const selectedSuite = TEST_SUITE_ARGS[requestedSuite] ? requestedSuite : 'full';
|
|
182
|
+
return runNodeCommand(`test:${selectedSuite}`, TEST_SUITE_ARGS[selectedSuite]);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (toolName === 'release_gate') {
|
|
186
|
+
return runNodeCommand('release_gate', ['./scripts/release-gate.mjs']);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (toolName === 'forbidden_content_check') {
|
|
190
|
+
return runNodeCommand('forbidden_content_check', ['./scripts/forbidden-content-check.mjs']);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
content: [
|
|
195
|
+
{
|
|
196
|
+
type: 'text',
|
|
197
|
+
text: `Unknown tool: ${toolName}`,
|
|
198
|
+
},
|
|
199
|
+
],
|
|
200
|
+
isError: true,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async function handleRequest(requestMessage) {
|
|
205
|
+
const requestId = requestMessage.id;
|
|
206
|
+
const requestMethod = requestMessage.method;
|
|
207
|
+
const requestParams = requestMessage.params || {};
|
|
208
|
+
|
|
209
|
+
if (typeof requestMethod !== 'string') {
|
|
210
|
+
if (typeof requestId !== 'undefined') {
|
|
211
|
+
sendError(requestId, -32600, 'Invalid Request');
|
|
212
|
+
}
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (requestMethod === 'initialize') {
|
|
217
|
+
const negotiatedProtocolVersion = typeof requestParams.protocolVersion === 'string'
|
|
218
|
+
? requestParams.protocolVersion
|
|
219
|
+
: DEFAULT_PROTOCOL_VERSION;
|
|
220
|
+
|
|
221
|
+
sendResponse(requestId, {
|
|
222
|
+
protocolVersion: negotiatedProtocolVersion,
|
|
223
|
+
capabilities: {
|
|
224
|
+
tools: {
|
|
225
|
+
listChanged: false,
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
serverInfo: {
|
|
229
|
+
name: 'agentic-senior-core',
|
|
230
|
+
version: PACKAGE_VERSION,
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (requestMethod === 'notifications/initialized') {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (requestMethod === 'ping') {
|
|
241
|
+
if (typeof requestId !== 'undefined') {
|
|
242
|
+
sendResponse(requestId, {});
|
|
243
|
+
}
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (requestMethod === 'tools/list') {
|
|
248
|
+
sendResponse(requestId, {
|
|
249
|
+
tools: TOOL_DEFINITIONS,
|
|
250
|
+
});
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (requestMethod === 'tools/call') {
|
|
255
|
+
const requestedToolName = normalizeToolName(requestParams.name);
|
|
256
|
+
|
|
257
|
+
if (!requestedToolName) {
|
|
258
|
+
sendError(requestId, -32602, 'Invalid params: tool name is required');
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const toolResult = await executeToolCall(requestedToolName, requestParams.arguments || {});
|
|
263
|
+
sendResponse(requestId, toolResult);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (typeof requestId !== 'undefined') {
|
|
268
|
+
sendError(requestId, -32601, `Method not found: ${requestMethod}`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function readNextFramedMessage() {
|
|
273
|
+
const headerEndIndex = incomingBuffer.indexOf('\r\n\r\n');
|
|
274
|
+
if (headerEndIndex === -1) {
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const rawHeader = incomingBuffer.slice(0, headerEndIndex).toString('utf8');
|
|
279
|
+
const headerLines = rawHeader.split('\r\n');
|
|
280
|
+
let contentLength = null;
|
|
281
|
+
|
|
282
|
+
for (const headerLine of headerLines) {
|
|
283
|
+
const separatorIndex = headerLine.indexOf(':');
|
|
284
|
+
if (separatorIndex === -1) {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const headerName = headerLine.slice(0, separatorIndex).trim().toLowerCase();
|
|
289
|
+
const headerValue = headerLine.slice(separatorIndex + 1).trim();
|
|
290
|
+
|
|
291
|
+
if (headerName === 'content-length') {
|
|
292
|
+
contentLength = Number.parseInt(headerValue, 10);
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (!Number.isFinite(contentLength) || contentLength < 0) {
|
|
298
|
+
incomingBuffer = Buffer.alloc(0);
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const bodyStartIndex = headerEndIndex + 4;
|
|
303
|
+
const frameEndIndex = bodyStartIndex + contentLength;
|
|
304
|
+
|
|
305
|
+
if (incomingBuffer.length < frameEndIndex) {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const rawMessage = incomingBuffer.slice(bodyStartIndex, frameEndIndex).toString('utf8');
|
|
310
|
+
incomingBuffer = incomingBuffer.slice(frameEndIndex);
|
|
311
|
+
return rawMessage;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function processIncomingBuffer() {
|
|
315
|
+
while (true) {
|
|
316
|
+
const framedMessage = readNextFramedMessage();
|
|
317
|
+
if (framedMessage === null) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
let parsedRequest;
|
|
322
|
+
try {
|
|
323
|
+
parsedRequest = JSON.parse(framedMessage);
|
|
324
|
+
} catch {
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
Promise.resolve(handleRequest(parsedRequest)).catch((error) => {
|
|
329
|
+
if (typeof parsedRequest?.id !== 'undefined') {
|
|
330
|
+
sendError(parsedRequest.id, -32603, 'Internal error', String(error?.message || error));
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
process.stdin.on('data', (chunk) => {
|
|
337
|
+
incomingBuffer = Buffer.concat([incomingBuffer, chunk]);
|
|
338
|
+
processIncomingBuffer();
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
process.stdin.on('end', () => {
|
|
342
|
+
process.exit(0);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
process.on('SIGINT', () => {
|
|
346
|
+
process.exit(0);
|
|
347
|
+
});
|
package/scripts/validate.mjs
CHANGED
|
@@ -39,6 +39,33 @@ const THIN_ADAPTER_PATHS = [
|
|
|
39
39
|
'.github/copilot-instructions.md',
|
|
40
40
|
'.gemini/instructions.md',
|
|
41
41
|
];
|
|
42
|
+
const FORMAL_ARTIFACT_PATHS = [
|
|
43
|
+
'.instructions.md',
|
|
44
|
+
'README.md',
|
|
45
|
+
'CHANGELOG.md',
|
|
46
|
+
'docs/deep_analysis_and_roadmap_backlog.md',
|
|
47
|
+
'.agent-context/rules/api-docs.md',
|
|
48
|
+
'.agent-context/review-checklists/pr-checklist.md',
|
|
49
|
+
'.agent-context/prompts/review-code.md',
|
|
50
|
+
'.agent-context/skills/review-quality.md',
|
|
51
|
+
'AGENTS.md',
|
|
52
|
+
'.github/copilot-instructions.md',
|
|
53
|
+
'.gemini/instructions.md',
|
|
54
|
+
];
|
|
55
|
+
const REQUIRED_HUMAN_WRITING_SNIPPETS = [
|
|
56
|
+
{
|
|
57
|
+
path: '.agent-context/rules/api-docs.md',
|
|
58
|
+
snippets: ['## Human Writing Standard (Mandatory)', 'No emoji in formal artifacts.'],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
path: '.agent-context/review-checklists/pr-checklist.md',
|
|
62
|
+
snippets: ['No emoji in formal documentation or review summaries', 'Documentation uses plain English and avoids AI cliches'],
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
path: 'docs/deep_analysis_and_roadmap_backlog.md',
|
|
66
|
+
snippets: ['## Part 6: Documentation and Explanation Standards (Mandatory)', 'No emoji in formal artifacts. This is mandatory.'],
|
|
67
|
+
},
|
|
68
|
+
];
|
|
42
69
|
|
|
43
70
|
const validationResult = {
|
|
44
71
|
passed: 0,
|
|
@@ -124,6 +151,7 @@ async function validateRequiredFiles() {
|
|
|
124
151
|
'scripts/benchmark-gate.mjs',
|
|
125
152
|
'scripts/benchmark-intelligence.mjs',
|
|
126
153
|
'scripts/governance-weekly-report.mjs',
|
|
154
|
+
'scripts/mcp-server.mjs',
|
|
127
155
|
'scripts/frontend-usability-audit.mjs',
|
|
128
156
|
'scripts/release-gate.mjs',
|
|
129
157
|
'scripts/generate-sbom.mjs',
|
|
@@ -148,6 +176,7 @@ async function validateRequiredFiles() {
|
|
|
148
176
|
'.agent-context/state/benchmark-watchlist.json',
|
|
149
177
|
'.agent-context/state/skill-platform.json',
|
|
150
178
|
'.agent-context/skills/index.json',
|
|
179
|
+
'.vscode/mcp.json',
|
|
151
180
|
'.github/workflows/release-gate.yml',
|
|
152
181
|
'.github/workflows/sbom-compliance.yml',
|
|
153
182
|
'.github/workflows/benchmark-intelligence.yml',
|
|
@@ -673,6 +702,8 @@ async function validateMcpConfiguration() {
|
|
|
673
702
|
const mcpConfiguration = JSON.parse(await readTextFile(join(ROOT_DIR, 'mcp.json')));
|
|
674
703
|
const lintServerCommand = mcpConfiguration.servers?.lint?.command;
|
|
675
704
|
const testServerCommand = mcpConfiguration.servers?.test?.command;
|
|
705
|
+
const workspaceMcpConfiguration = JSON.parse(await readTextFile(join(ROOT_DIR, '.vscode', 'mcp.json')));
|
|
706
|
+
const workspaceServerConfig = workspaceMcpConfiguration.servers?.['agentic-senior-core'];
|
|
676
707
|
|
|
677
708
|
if (lintServerCommand === 'node') {
|
|
678
709
|
pass('MCP lint server uses Node');
|
|
@@ -685,6 +716,64 @@ async function validateMcpConfiguration() {
|
|
|
685
716
|
} else {
|
|
686
717
|
fail('MCP test server must use Node');
|
|
687
718
|
}
|
|
719
|
+
|
|
720
|
+
if (workspaceMcpConfiguration.$schema === 'vscode://schemas/mcp') {
|
|
721
|
+
pass('Workspace MCP config uses trusted VS Code schema');
|
|
722
|
+
} else {
|
|
723
|
+
fail('Workspace MCP config must use $schema: vscode://schemas/mcp');
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
if (workspaceServerConfig?.command === 'node') {
|
|
727
|
+
pass('Workspace MCP server command uses Node');
|
|
728
|
+
} else {
|
|
729
|
+
fail('Workspace MCP server command must use Node');
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
if (Array.isArray(workspaceServerConfig?.args) && workspaceServerConfig.args.includes('./scripts/mcp-server.mjs')) {
|
|
733
|
+
pass('Workspace MCP server points to scripts/mcp-server.mjs');
|
|
734
|
+
} else {
|
|
735
|
+
fail('Workspace MCP server must include ./scripts/mcp-server.mjs argument');
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
async function validateHumanWritingGovernance() {
|
|
740
|
+
console.log('\nChecking human writing governance...');
|
|
741
|
+
|
|
742
|
+
const disallowedEmojiPattern = /[\u2705\u274C\u26A0\u{1F4CC}\u{1F536}\u{1F4CE}\u{1F534}\u{1F7E0}\u{1F7E1}\u{1F7E2}]/u;
|
|
743
|
+
|
|
744
|
+
for (const formalArtifactPath of FORMAL_ARTIFACT_PATHS) {
|
|
745
|
+
const absoluteFormalArtifactPath = join(ROOT_DIR, formalArtifactPath);
|
|
746
|
+
|
|
747
|
+
if (!(await fileExists(absoluteFormalArtifactPath))) {
|
|
748
|
+
fail(`Missing formal artifact for writing governance: ${formalArtifactPath}`);
|
|
749
|
+
continue;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
const formalArtifactContent = await readTextFile(absoluteFormalArtifactPath);
|
|
753
|
+
|
|
754
|
+
if (disallowedEmojiPattern.test(formalArtifactContent)) {
|
|
755
|
+
fail(`${formalArtifactPath} contains disallowed emoji symbols in formal text`);
|
|
756
|
+
} else {
|
|
757
|
+
pass(`${formalArtifactPath} has no disallowed emoji symbols`);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
for (const snippetRule of REQUIRED_HUMAN_WRITING_SNIPPETS) {
|
|
762
|
+
const absoluteRulePath = join(ROOT_DIR, snippetRule.path);
|
|
763
|
+
if (!(await fileExists(absoluteRulePath))) {
|
|
764
|
+
fail(`Missing writing governance source: ${snippetRule.path}`);
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
const writingRuleContent = await readTextFile(absoluteRulePath);
|
|
769
|
+
for (const requiredSnippet of snippetRule.snippets) {
|
|
770
|
+
if (writingRuleContent.includes(requiredSnippet)) {
|
|
771
|
+
pass(`${snippetRule.path} includes writing governance snippet: ${requiredSnippet}`);
|
|
772
|
+
} else {
|
|
773
|
+
fail(`${snippetRule.path} is missing writing governance snippet: ${requiredSnippet}`);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
688
777
|
}
|
|
689
778
|
|
|
690
779
|
async function validateInstructionAdapters() {
|
|
@@ -848,6 +937,7 @@ async function main() {
|
|
|
848
937
|
await validateVersionConsistency();
|
|
849
938
|
await validateDocumentationFlow();
|
|
850
939
|
await validateMcpConfiguration();
|
|
940
|
+
await validateHumanWritingGovernance();
|
|
851
941
|
await validateInstructionAdapters();
|
|
852
942
|
await validateTrustTierSchema();
|
|
853
943
|
await validateEvidenceBundles();
|