@platformos/platformos-mcp-supervisor 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/args.d.ts +22 -0
- package/dist/bin/args.js +41 -0
- package/dist/bin/platformos-mcp-supervisor.d.ts +2 -0
- package/dist/bin/platformos-mcp-supervisor.js +38 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +6 -0
- package/dist/lint/lint.d.ts +11 -0
- package/dist/lint/lint.js +47 -0
- package/dist/logger.d.ts +8 -0
- package/dist/logger.js +7 -0
- package/dist/result/assemble.d.ts +13 -0
- package/dist/result/assemble.js +25 -0
- package/dist/result/types.d.ts +155 -0
- package/dist/result/types.js +18 -0
- package/dist/transport/server.d.ts +26 -0
- package/dist/transport/server.js +42 -0
- package/dist/transport/validate-code.d.ts +26 -0
- package/dist/transport/validate-code.js +49 -0
- package/package.json +54 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure CLI argument + project-directory resolution for the bin.
|
|
3
|
+
*
|
|
4
|
+
* Kept separate from the bin entrypoint (which runs `main()` on import) so it
|
|
5
|
+
* can be unit-tested without booting a server.
|
|
6
|
+
*/
|
|
7
|
+
export interface ParsedArgs {
|
|
8
|
+
projectDir?: string;
|
|
9
|
+
help: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Parse `--project <dir>` / `--project=<dir>` / `--help` / `-h` from a
|
|
13
|
+
* `process.argv.slice(2)`-style array. Unknown flags are tolerated so a
|
|
14
|
+
* forward-compatible client can pass extras without breaking the bin.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseArgs(argv: ReadonlyArray<string>): ParsedArgs;
|
|
17
|
+
/**
|
|
18
|
+
* Resolve the project directory by precedence:
|
|
19
|
+
* 1. `--project` argument, 2. `POS_SUPERVISOR_PROJECT_DIR`, 3. cwd.
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveProjectDir(args: ParsedArgs, env: NodeJS.ProcessEnv, cwd: string): string;
|
|
22
|
+
export declare const HELP = "platformos-mcp-supervisor \u2014 MCP stdio server exposing validate_code\n\nUsage:\n platformos-mcp-supervisor [--project <dir>]\n\nOptions:\n --project <dir> Project root to validate against\n (env: POS_SUPERVISOR_PROJECT_DIR; default: current directory)\n -h, --help Show this help\n";
|
package/dist/bin/args.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse `--project <dir>` / `--project=<dir>` / `--help` / `-h` from a
|
|
3
|
+
* `process.argv.slice(2)`-style array. Unknown flags are tolerated so a
|
|
4
|
+
* forward-compatible client can pass extras without breaking the bin.
|
|
5
|
+
*/
|
|
6
|
+
export function parseArgs(argv) {
|
|
7
|
+
let projectDir;
|
|
8
|
+
let help = false;
|
|
9
|
+
for (let i = 0; i < argv.length; i++) {
|
|
10
|
+
const arg = argv[i];
|
|
11
|
+
if (arg === '--help' || arg === '-h') {
|
|
12
|
+
help = true;
|
|
13
|
+
}
|
|
14
|
+
else if (arg === '--project') {
|
|
15
|
+
projectDir = argv[i + 1];
|
|
16
|
+
i++;
|
|
17
|
+
}
|
|
18
|
+
else if (arg.startsWith('--project=')) {
|
|
19
|
+
projectDir = arg.slice('--project='.length);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return { projectDir, help };
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the project directory by precedence:
|
|
26
|
+
* 1. `--project` argument, 2. `POS_SUPERVISOR_PROJECT_DIR`, 3. cwd.
|
|
27
|
+
*/
|
|
28
|
+
export function resolveProjectDir(args, env, cwd) {
|
|
29
|
+
return args.projectDir ?? env.POS_SUPERVISOR_PROJECT_DIR ?? cwd;
|
|
30
|
+
}
|
|
31
|
+
export const HELP = `platformos-mcp-supervisor — MCP stdio server exposing validate_code
|
|
32
|
+
|
|
33
|
+
Usage:
|
|
34
|
+
platformos-mcp-supervisor [--project <dir>]
|
|
35
|
+
|
|
36
|
+
Options:
|
|
37
|
+
--project <dir> Project root to validate against
|
|
38
|
+
(env: POS_SUPERVISOR_PROJECT_DIR; default: current directory)
|
|
39
|
+
-h, --help Show this help
|
|
40
|
+
`;
|
|
41
|
+
//# sourceMappingURL=args.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI entrypoint for the platformOS MCP supervisor.
|
|
4
|
+
*
|
|
5
|
+
* Resolves the project directory by precedence:
|
|
6
|
+
* 1. `--project <dir>` / `--project=<dir>` (wins)
|
|
7
|
+
* 2. `POS_SUPERVISOR_PROJECT_DIR` environment variable
|
|
8
|
+
* 3. `process.cwd()` — the directory the MCP client launched the bin from
|
|
9
|
+
*
|
|
10
|
+
* Boots `startServer` and lets Node keep the process alive: `server.connect()`
|
|
11
|
+
* registers the stdio transport but does not block, so the SIGINT/SIGTERM
|
|
12
|
+
* handlers installed inside `startServer` own the lifetime.
|
|
13
|
+
*
|
|
14
|
+
* The source lives under `src/bin/` (tsconfig `rootDir` is `src`); the build
|
|
15
|
+
* emits `dist/bin/platformos-mcp-supervisor.js`, which `package.json#bin`
|
|
16
|
+
* references. tsc preserves the shebang so the dist file is executable.
|
|
17
|
+
*
|
|
18
|
+
* Pure arg/dir resolution lives in `./args` so it can be unit-tested without
|
|
19
|
+
* importing this module (which boots the server on load).
|
|
20
|
+
*/
|
|
21
|
+
import { createLogger } from '../logger.js';
|
|
22
|
+
import { startServer } from '../transport/server.js';
|
|
23
|
+
import { HELP, parseArgs, resolveProjectDir } from './args.js';
|
|
24
|
+
async function main() {
|
|
25
|
+
const args = parseArgs(process.argv.slice(2));
|
|
26
|
+
if (args.help) {
|
|
27
|
+
process.stderr.write(HELP);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const log = createLogger('platformos-mcp-supervisor');
|
|
31
|
+
const projectDir = resolveProjectDir(args, process.env, process.cwd());
|
|
32
|
+
await startServer({ projectDir, log });
|
|
33
|
+
}
|
|
34
|
+
main().catch((err) => {
|
|
35
|
+
process.stderr.write(`fatal: ${err?.stack ?? String(err)}\n`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=platformos-mcp-supervisor.js.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Public surface of @platformos/platformos-mcp-supervisor. */
|
|
2
|
+
export { startServer } from './transport/server.js';
|
|
3
|
+
export type { ServerOptions, ServerHandle } from './transport/server.js';
|
|
4
|
+
export { registerValidateCode, VALIDATE_CODE_INPUT } from './transport/validate-code.js';
|
|
5
|
+
export type { SupervisorContext } from './transport/validate-code.js';
|
|
6
|
+
export { createLogger } from './logger.js';
|
|
7
|
+
export type { Logger } from './logger.js';
|
|
8
|
+
export * from './result/types.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Public surface of @platformos/platformos-mcp-supervisor. */
|
|
2
|
+
export { startServer } from './transport/server.js';
|
|
3
|
+
export { registerValidateCode, VALIDATE_CODE_INPUT } from './transport/validate-code.js';
|
|
4
|
+
export { createLogger } from './logger.js';
|
|
5
|
+
export * from './result/types.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ValidateCodeDiagnostic } from '../result/types.js';
|
|
2
|
+
export interface RunLintParams {
|
|
3
|
+
/** Absolute project root the buffer is validated against. */
|
|
4
|
+
projectDir: string;
|
|
5
|
+
/** File under edit — absolute, or relative to `projectDir`. */
|
|
6
|
+
filePath: string;
|
|
7
|
+
/** In-memory buffer contents. */
|
|
8
|
+
content: string;
|
|
9
|
+
}
|
|
10
|
+
/** Lint the buffer and return the mapped diagnostics for the file. */
|
|
11
|
+
export declare function runLint(params: RunLintParams): Promise<ValidateCodeDiagnostic[]>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lint adapter — the only I/O boundary on the request path.
|
|
3
|
+
*
|
|
4
|
+
* Lints an in-memory buffer in the context of its on-disk project via the
|
|
5
|
+
* check-node `lintBuffer` seam (a direct `check()` call — no LSP, no
|
|
6
|
+
* subprocess) and maps the structured check-common `Offense[]` into the
|
|
7
|
+
* agent-facing `ValidateCodeDiagnostic` shape.
|
|
8
|
+
*
|
|
9
|
+
* This is the minimal "lint only" slice: it carries detection results
|
|
10
|
+
* (check code, severity, message, range) straight through. Ergonomic
|
|
11
|
+
* enrichment (hints, confidence, fix translation, see-also) is added later in
|
|
12
|
+
* `enrich/`; for now diagnostics have no `fix` / `hint`, and the structured
|
|
13
|
+
* `Offense.fix` / `suggest` are intentionally not translated.
|
|
14
|
+
*/
|
|
15
|
+
import { isAbsolute, join } from 'node:path';
|
|
16
|
+
import { lintBuffer, Severity } from '@platformos/platformos-check-node';
|
|
17
|
+
const SEVERITY = {
|
|
18
|
+
[Severity.ERROR]: 'error',
|
|
19
|
+
[Severity.WARNING]: 'warning',
|
|
20
|
+
[Severity.INFO]: 'info',
|
|
21
|
+
};
|
|
22
|
+
/** Lint the buffer and return the mapped diagnostics for the file. */
|
|
23
|
+
export async function runLint(params) {
|
|
24
|
+
const { projectDir, filePath, content } = params;
|
|
25
|
+
const absoluteFilePath = isAbsolute(filePath) ? filePath : join(projectDir, filePath);
|
|
26
|
+
const offenses = await lintBuffer({ root: projectDir, filePath: absoluteFilePath, content });
|
|
27
|
+
return offenses.map(toDiagnostic);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Map a check-common `Offense` to a `ValidateCodeDiagnostic`.
|
|
31
|
+
*
|
|
32
|
+
* check-common positions are 0-based for BOTH line and character
|
|
33
|
+
* (`getPosition` uses `line-column` with `origin: 0`); the agent surface uses
|
|
34
|
+
* 1-based line + 1-based column, so both get `+ 1`.
|
|
35
|
+
*/
|
|
36
|
+
function toDiagnostic(offense) {
|
|
37
|
+
return {
|
|
38
|
+
check: offense.check,
|
|
39
|
+
severity: SEVERITY[offense.severity],
|
|
40
|
+
message: offense.message,
|
|
41
|
+
line: offense.start.line + 1,
|
|
42
|
+
column: offense.start.character + 1,
|
|
43
|
+
end_line: offense.end.line + 1,
|
|
44
|
+
end_column: offense.end.character + 1,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=lint.js.map
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* stderr-only logger.
|
|
3
|
+
*
|
|
4
|
+
* stdout is reserved for the MCP JSON-RPC stream — anything written there
|
|
5
|
+
* corrupts the transport. Every operational log line therefore goes to stderr.
|
|
6
|
+
*/
|
|
7
|
+
export type Logger = (message: string) => void;
|
|
8
|
+
export declare function createLogger(prefix?: string): Logger;
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result assembly (minimal "lint only" slice).
|
|
3
|
+
*
|
|
4
|
+
* Buckets the mapped diagnostics into errors / warnings / infos and derives the
|
|
5
|
+
* `status` + `must_fix_before_write` envelope. PURE — no I/O, consumes only the
|
|
6
|
+
* diagnostic list and the shared result types.
|
|
7
|
+
*
|
|
8
|
+
* The ergonomic transforms (clustering, scorecard, the explicit
|
|
9
|
+
* blocking-warning set, `next_step`, tips, domain_guide, structural) are added
|
|
10
|
+
* in later tasks; they are left empty/null here.
|
|
11
|
+
*/
|
|
12
|
+
import type { ValidateCodeDiagnostic, ValidateCodeMode, ValidateCodeResult } from './types.js';
|
|
13
|
+
export declare function assembleResult(diagnostics: ValidateCodeDiagnostic[], _mode: ValidateCodeMode): ValidateCodeResult;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function assembleResult(diagnostics,
|
|
2
|
+
// Reserved: `full`/`quick` do not yet change output (no heavier stages exist).
|
|
3
|
+
_mode) {
|
|
4
|
+
const errors = diagnostics.filter((d) => d.severity === 'error');
|
|
5
|
+
const warnings = diagnostics.filter((d) => d.severity === 'warning');
|
|
6
|
+
const infos = diagnostics.filter((d) => d.severity === 'info');
|
|
7
|
+
const status = errors.length > 0 ? 'error' : warnings.length > 0 ? 'warning' : 'ok';
|
|
8
|
+
return {
|
|
9
|
+
status,
|
|
10
|
+
// Minimal gate: any error blocks the write. The richer blocking-warning set
|
|
11
|
+
// is defined in the result-assembly task.
|
|
12
|
+
must_fix_before_write: errors.length > 0,
|
|
13
|
+
errors,
|
|
14
|
+
warnings,
|
|
15
|
+
infos,
|
|
16
|
+
proposed_fixes: [],
|
|
17
|
+
clusters: [],
|
|
18
|
+
scorecard: [],
|
|
19
|
+
parse_error: null,
|
|
20
|
+
tips: [],
|
|
21
|
+
domain_guide: null,
|
|
22
|
+
structural: null,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=assemble.js.map
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `validate_code` result contract — the agent-facing surface of the
|
|
3
|
+
* supervisor.
|
|
4
|
+
*
|
|
5
|
+
* This is intentionally separate from check-common's `Offense`: `Offense` is a
|
|
6
|
+
* stable, minimal detection type consumed by editors/CLI/browser, whereas
|
|
7
|
+
* `ValidateCodeResult` is an LLM-ergonomics surface that may churn as agent
|
|
8
|
+
* behaviour is tuned. The `result/` layer assembles this shape from enriched
|
|
9
|
+
* diagnostics + advisories via order-independent pure transforms.
|
|
10
|
+
*
|
|
11
|
+
* Field names mirror the v1 supervisor so the parity safety net (TASK-8.5) can
|
|
12
|
+
* compare unchanged-contract fields against the captured baselines. Fields
|
|
13
|
+
* marked "TASK-8" are part of the contract but are only populated once the
|
|
14
|
+
* supervisor's per-domain layer and rule library are restored; the minimal
|
|
15
|
+
* TASK-7 build leaves them empty / null.
|
|
16
|
+
*/
|
|
17
|
+
export type ValidateCodeMode = 'full' | 'quick';
|
|
18
|
+
export type ValidateCodeStatus = 'ok' | 'warning' | 'error';
|
|
19
|
+
export type ValidateCodeSeverity = 'error' | 'warning' | 'info';
|
|
20
|
+
/** Tool input. */
|
|
21
|
+
export interface ValidateCodeParams {
|
|
22
|
+
/** Path of the file under edit (absolute, or relative to the project root). */
|
|
23
|
+
file_path: string;
|
|
24
|
+
/** The file contents to validate (the in-memory buffer). */
|
|
25
|
+
content: string;
|
|
26
|
+
/** Depth of analysis. Defaults to `full`. */
|
|
27
|
+
mode?: ValidateCodeMode;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* An agent-facing fix. Translated from a check-common `FixDescription` (the
|
|
31
|
+
* structured edits the engine already computed); the supervisor never
|
|
32
|
+
* regenerates edit text from scratch.
|
|
33
|
+
*
|
|
34
|
+
* - `text_edit` — replace `[start_index, end_index)` with `new_text`.
|
|
35
|
+
* - `insert` — insert `new_text` at `start_index` (`end_index === start_index`).
|
|
36
|
+
* - `guidance` — prose only; no machine-applicable edit.
|
|
37
|
+
*/
|
|
38
|
+
export type AgentFix = {
|
|
39
|
+
type: 'text_edit' | 'insert';
|
|
40
|
+
description?: string;
|
|
41
|
+
/** 0-based offset into the file. */
|
|
42
|
+
start_index: number;
|
|
43
|
+
/** 0-based offset into the file. */
|
|
44
|
+
end_index: number;
|
|
45
|
+
new_text: string;
|
|
46
|
+
} | {
|
|
47
|
+
type: 'guidance';
|
|
48
|
+
description: string;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* A diagnostic as surfaced to the agent. Carries the structured check-common
|
|
52
|
+
* fields (`check`, `severity`, range, `message`) plus the supervisor's
|
|
53
|
+
* ergonomic enrichment (`hint`, `suggestion`, `confidence`, `fix`, `see_also`).
|
|
54
|
+
* Line/column are 1-based (converted from check-common's 0-based offsets in the
|
|
55
|
+
* `result/` layer).
|
|
56
|
+
*/
|
|
57
|
+
export interface ValidateCodeDiagnostic {
|
|
58
|
+
/** The check code, e.g. `MissingPartial`, or a `pos-supervisor:` advisory code. */
|
|
59
|
+
check: string;
|
|
60
|
+
severity: ValidateCodeSeverity;
|
|
61
|
+
message: string;
|
|
62
|
+
/** 1-based line of the diagnostic start. */
|
|
63
|
+
line: number;
|
|
64
|
+
/** 1-based column of the diagnostic start. */
|
|
65
|
+
column: number;
|
|
66
|
+
/** 1-based line of the diagnostic end, when known. */
|
|
67
|
+
end_line?: number;
|
|
68
|
+
/** 1-based column of the diagnostic end, when known. */
|
|
69
|
+
end_column?: number;
|
|
70
|
+
/** Markdown explanation for the agent. */
|
|
71
|
+
hint?: string;
|
|
72
|
+
/** A short, one-line "did you mean / use this" pointer. */
|
|
73
|
+
suggestion?: string;
|
|
74
|
+
/** Static confidence in [0, 1] that this diagnostic + its fix are correct. */
|
|
75
|
+
confidence?: number;
|
|
76
|
+
/** A single concrete fix for this diagnostic, when one is available. */
|
|
77
|
+
fix?: AgentFix;
|
|
78
|
+
/** A pointer to another supervisor tool / doc that helps resolve this. */
|
|
79
|
+
see_also?: SeeAlso;
|
|
80
|
+
}
|
|
81
|
+
export interface SeeAlso {
|
|
82
|
+
tool?: string;
|
|
83
|
+
args?: Record<string, unknown>;
|
|
84
|
+
reason?: string;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* A proposed fix shown to the agent at the top level of the result. Carries the
|
|
88
|
+
* originating `check` so the agent can correlate it with a diagnostic.
|
|
89
|
+
*/
|
|
90
|
+
export type ProposedFix = AgentFix & {
|
|
91
|
+
check?: string | null;
|
|
92
|
+
};
|
|
93
|
+
/** A group of related diagnostics sharing a root cause, with a unified remedy. */
|
|
94
|
+
export interface DiagnosticCluster {
|
|
95
|
+
check: string;
|
|
96
|
+
count: number;
|
|
97
|
+
unified_fix?: string;
|
|
98
|
+
}
|
|
99
|
+
/** An advisory note about the file's architecture (doc-block coverage, layout correctness, …). */
|
|
100
|
+
export interface ScorecardNote {
|
|
101
|
+
category: string;
|
|
102
|
+
status: 'ok' | 'warning' | 'info';
|
|
103
|
+
reason: string;
|
|
104
|
+
}
|
|
105
|
+
export interface TipEntry {
|
|
106
|
+
id: string;
|
|
107
|
+
severity: string;
|
|
108
|
+
message: string;
|
|
109
|
+
}
|
|
110
|
+
export interface DomainGuideGotcha {
|
|
111
|
+
id: string;
|
|
112
|
+
message: string;
|
|
113
|
+
severity: string;
|
|
114
|
+
applies_to_errors?: string[];
|
|
115
|
+
}
|
|
116
|
+
export interface DomainGuide {
|
|
117
|
+
domain: string;
|
|
118
|
+
rule?: string;
|
|
119
|
+
triggered_gotchas: DomainGuideGotcha[];
|
|
120
|
+
}
|
|
121
|
+
export interface ValidateCodeStructuralSnapshot {
|
|
122
|
+
renders_used: string[];
|
|
123
|
+
filters_used: string[];
|
|
124
|
+
tags_used: string[];
|
|
125
|
+
translation_keys: string[];
|
|
126
|
+
doc_params: string[];
|
|
127
|
+
slug: string | null;
|
|
128
|
+
layout: string | null;
|
|
129
|
+
method: string | null;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The full `validate_code` result. Serialized as a single JSON text block over
|
|
133
|
+
* the MCP stdio transport.
|
|
134
|
+
*/
|
|
135
|
+
export interface ValidateCodeResult {
|
|
136
|
+
status: ValidateCodeStatus;
|
|
137
|
+
/**
|
|
138
|
+
* When true the agent MUST NOT write the file. Set by any error or any
|
|
139
|
+
* "blocking" warning (the blocking set is defined explicitly in `result/`).
|
|
140
|
+
*/
|
|
141
|
+
must_fix_before_write: boolean;
|
|
142
|
+
errors: ValidateCodeDiagnostic[];
|
|
143
|
+
warnings: ValidateCodeDiagnostic[];
|
|
144
|
+
infos: ValidateCodeDiagnostic[];
|
|
145
|
+
proposed_fixes: ProposedFix[];
|
|
146
|
+
clusters: DiagnosticCluster[];
|
|
147
|
+
scorecard: ScorecardNote[];
|
|
148
|
+
/** Deterministic prose telling the agent what to do next. */
|
|
149
|
+
next_step?: string;
|
|
150
|
+
/** Parse-failure message when the file could not be parsed at all; null/absent otherwise. */
|
|
151
|
+
parse_error?: string | null;
|
|
152
|
+
tips?: TipEntry[];
|
|
153
|
+
domain_guide?: DomainGuide | null;
|
|
154
|
+
structural?: ValidateCodeStructuralSnapshot | null;
|
|
155
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `validate_code` result contract — the agent-facing surface of the
|
|
3
|
+
* supervisor.
|
|
4
|
+
*
|
|
5
|
+
* This is intentionally separate from check-common's `Offense`: `Offense` is a
|
|
6
|
+
* stable, minimal detection type consumed by editors/CLI/browser, whereas
|
|
7
|
+
* `ValidateCodeResult` is an LLM-ergonomics surface that may churn as agent
|
|
8
|
+
* behaviour is tuned. The `result/` layer assembles this shape from enriched
|
|
9
|
+
* diagnostics + advisories via order-independent pure transforms.
|
|
10
|
+
*
|
|
11
|
+
* Field names mirror the v1 supervisor so the parity safety net (TASK-8.5) can
|
|
12
|
+
* compare unchanged-contract fields against the captured baselines. Fields
|
|
13
|
+
* marked "TASK-8" are part of the contract but are only populated once the
|
|
14
|
+
* supervisor's per-domain layer and rule library are restored; the minimal
|
|
15
|
+
* TASK-7 build leaves them empty / null.
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP stdio server lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* `startServer` wires an `McpServer` to a `StdioServerTransport`, registers the
|
|
5
|
+
* `validate_code` tool, and installs SIGINT/SIGTERM handlers. It is the
|
|
6
|
+
* embedding surface; the bin (`bin/platformos-mcp-supervisor.ts`) is the
|
|
7
|
+
* user-facing surface.
|
|
8
|
+
*/
|
|
9
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
10
|
+
import { type Logger } from '../logger.js';
|
|
11
|
+
import { type SupervisorContext } from './validate-code.js';
|
|
12
|
+
export interface ServerOptions {
|
|
13
|
+
/** Absolute project root that buffers are validated against. */
|
|
14
|
+
projectDir: string;
|
|
15
|
+
/** Logger sink (stderr by default). */
|
|
16
|
+
log?: Logger;
|
|
17
|
+
/** Advertised server version. */
|
|
18
|
+
version?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ServerHandle {
|
|
21
|
+
server: McpServer;
|
|
22
|
+
context: SupervisorContext;
|
|
23
|
+
/** Tear down the transport. Idempotent. */
|
|
24
|
+
shutdown: (reason?: string) => Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
export declare function startServer(opts: ServerOptions): Promise<ServerHandle>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP stdio server lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* `startServer` wires an `McpServer` to a `StdioServerTransport`, registers the
|
|
5
|
+
* `validate_code` tool, and installs SIGINT/SIGTERM handlers. It is the
|
|
6
|
+
* embedding surface; the bin (`bin/platformos-mcp-supervisor.ts`) is the
|
|
7
|
+
* user-facing surface.
|
|
8
|
+
*/
|
|
9
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
10
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
11
|
+
import { createLogger } from '../logger.js';
|
|
12
|
+
import { registerValidateCode } from './validate-code.js';
|
|
13
|
+
const SERVER_NAME = 'platformos-mcp-supervisor';
|
|
14
|
+
const DEFAULT_VERSION = '0.0.1';
|
|
15
|
+
export async function startServer(opts) {
|
|
16
|
+
const log = opts.log ?? createLogger(SERVER_NAME);
|
|
17
|
+
const context = { projectDir: opts.projectDir, log };
|
|
18
|
+
const server = new McpServer({ name: SERVER_NAME, version: opts.version ?? DEFAULT_VERSION });
|
|
19
|
+
registerValidateCode(server, context);
|
|
20
|
+
const transport = new StdioServerTransport();
|
|
21
|
+
await server.connect(transport);
|
|
22
|
+
log(`listening on stdio (project: ${opts.projectDir})`);
|
|
23
|
+
let closed = false;
|
|
24
|
+
const shutdown = async (reason) => {
|
|
25
|
+
if (closed)
|
|
26
|
+
return;
|
|
27
|
+
closed = true;
|
|
28
|
+
if (reason)
|
|
29
|
+
log(`shutting down (${reason})`);
|
|
30
|
+
await server.close();
|
|
31
|
+
};
|
|
32
|
+
installSignalHandlers(shutdown);
|
|
33
|
+
return { server, context, shutdown };
|
|
34
|
+
}
|
|
35
|
+
function installSignalHandlers(shutdown) {
|
|
36
|
+
for (const signal of ['SIGINT', 'SIGTERM']) {
|
|
37
|
+
process.once(signal, () => {
|
|
38
|
+
void shutdown(signal).finally(() => process.exit(0));
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registration of the `validate_code` MCP tool.
|
|
3
|
+
*
|
|
4
|
+
* Current slice: the handler runs the real lint (`check()` via the check-node
|
|
5
|
+
* seam) and returns the detection results mapped into `ValidateCodeResult`.
|
|
6
|
+
* The ergonomic stages (enrich → advise → richer result assembly) are layered
|
|
7
|
+
* in by later tasks; the handler shape stays the same.
|
|
8
|
+
*/
|
|
9
|
+
import { type ZodRawShape } from 'zod';
|
|
10
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
11
|
+
import type { Logger } from '../logger.js';
|
|
12
|
+
/** Per-server context threaded into the handler. */
|
|
13
|
+
export interface SupervisorContext {
|
|
14
|
+
/** Absolute project root the buffer is validated against. */
|
|
15
|
+
projectDir: string;
|
|
16
|
+
log: Logger;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* zod raw shape for the tool input (validated by the MCP SDK before dispatch).
|
|
20
|
+
*
|
|
21
|
+
* Typed as `ZodRawShape` (not the inferred literal shape) so the SDK's
|
|
22
|
+
* `registerTool` does not perform excessively deep type instantiation over the
|
|
23
|
+
* schema; the handler casts the validated args to `ValidateCodeParams`.
|
|
24
|
+
*/
|
|
25
|
+
export declare const VALIDATE_CODE_INPUT: ZodRawShape;
|
|
26
|
+
export declare function registerValidateCode(server: McpServer, ctx: SupervisorContext): void;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registration of the `validate_code` MCP tool.
|
|
3
|
+
*
|
|
4
|
+
* Current slice: the handler runs the real lint (`check()` via the check-node
|
|
5
|
+
* seam) and returns the detection results mapped into `ValidateCodeResult`.
|
|
6
|
+
* The ergonomic stages (enrich → advise → richer result assembly) are layered
|
|
7
|
+
* in by later tasks; the handler shape stays the same.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { runLint } from '../lint/lint.js';
|
|
11
|
+
import { assembleResult } from '../result/assemble.js';
|
|
12
|
+
/**
|
|
13
|
+
* zod raw shape for the tool input (validated by the MCP SDK before dispatch).
|
|
14
|
+
*
|
|
15
|
+
* Typed as `ZodRawShape` (not the inferred literal shape) so the SDK's
|
|
16
|
+
* `registerTool` does not perform excessively deep type instantiation over the
|
|
17
|
+
* schema; the handler casts the validated args to `ValidateCodeParams`.
|
|
18
|
+
*/
|
|
19
|
+
export const VALIDATE_CODE_INPUT = {
|
|
20
|
+
file_path: z
|
|
21
|
+
.string()
|
|
22
|
+
.describe('Path of the file under edit (absolute, or relative to the project root).'),
|
|
23
|
+
content: z.string().describe('The file contents to validate (the in-memory buffer).'),
|
|
24
|
+
mode: z
|
|
25
|
+
.enum(['full', 'quick'])
|
|
26
|
+
.optional()
|
|
27
|
+
.describe('Analysis depth. `full` (default) runs the heavier ergonomic stages; `quick` is lint + enrichment.'),
|
|
28
|
+
};
|
|
29
|
+
const DESCRIPTION = 'Validate a platformOS Liquid/GraphQL/YAML file before writing it. Returns structured errors, ' +
|
|
30
|
+
'warnings, infos, proposed fixes, and a must_fix_before_write gate.';
|
|
31
|
+
export function registerValidateCode(server, ctx) {
|
|
32
|
+
server.registerTool('validate_code', { description: DESCRIPTION, inputSchema: VALIDATE_CODE_INPUT }, async (args) => toToolResult(await runValidateCode(ctx, args)));
|
|
33
|
+
}
|
|
34
|
+
/** Lint the buffer via the check-node seam and assemble the result. */
|
|
35
|
+
async function runValidateCode(ctx, params) {
|
|
36
|
+
const mode = params.mode ?? 'full';
|
|
37
|
+
ctx.log(`validate_code: ${params.file_path} (${mode})`);
|
|
38
|
+
const diagnostics = await runLint({
|
|
39
|
+
projectDir: ctx.projectDir,
|
|
40
|
+
filePath: params.file_path,
|
|
41
|
+
content: params.content,
|
|
42
|
+
});
|
|
43
|
+
return assembleResult(diagnostics, mode);
|
|
44
|
+
}
|
|
45
|
+
/** Wrap a result in the MCP text-content envelope (every result is one JSON text block). */
|
|
46
|
+
function toToolResult(result) {
|
|
47
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=validate-code.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@platformos/platformos-mcp-supervisor",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "platformOS Model Context Protocol (MCP) server exposing validate_code for LLM agents.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"author": "platformOS",
|
|
15
|
+
"homepage": "https://github.com/Platform-OS/platformos-tools/tree/master/packages/platformos-mcp-supervisor#readme",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/Platform-OS/platformos-tools.git",
|
|
19
|
+
"directory": "packages/platformos-mcp-supervisor"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/Platform-OS/platformos-tools/issues"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public",
|
|
27
|
+
"@platformos:registry": "https://registry.npmjs.org"
|
|
28
|
+
},
|
|
29
|
+
"bin": {
|
|
30
|
+
"platformos-mcp-supervisor": "dist/bin/platformos-mcp-supervisor.js"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist/**/*.js",
|
|
34
|
+
"dist/**/*.d.ts",
|
|
35
|
+
"dist/data/**/*"
|
|
36
|
+
],
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "yarn build:ts",
|
|
39
|
+
"build:ci": "yarn build",
|
|
40
|
+
"build:ts": "tsc -b tsconfig.build.json",
|
|
41
|
+
"dev": "tsc --watch",
|
|
42
|
+
"test": "vitest",
|
|
43
|
+
"type-check": "tsc --noEmit"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
47
|
+
"@platformos/platformos-check-common": "0.0.20",
|
|
48
|
+
"@platformos/platformos-check-docs-updater": "0.0.20",
|
|
49
|
+
"@platformos/platformos-check-node": "0.0.20",
|
|
50
|
+
"@platformos/platformos-graph": "0.0.20",
|
|
51
|
+
"zod": "^3.23.8"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {}
|
|
54
|
+
}
|