@platformos/platformos-mcp-supervisor 0.2.0 → 0.2.1
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/CHANGELOG.md +1076 -0
- package/dist/transport/instructions.js +53 -104
- package/dist/transport/validate-code.d.ts +9 -5
- package/dist/transport/validate-code.js +0 -3
- package/package.json +13 -12
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
* every session.
|
|
26
26
|
*/
|
|
27
27
|
import { allChecks } from '@platformos/platformos-check-common';
|
|
28
|
+
import { MAX_BATCH_BYTES, MAX_BATCH_FILES } from '../validate/batch-bounds.js';
|
|
28
29
|
/**
|
|
29
30
|
* The coverage line, DERIVED so it cannot describe a build that no longer exists.
|
|
30
31
|
*
|
|
@@ -35,116 +36,64 @@ import { allChecks } from '@platformos/platformos-check-common';
|
|
|
35
36
|
function coverage() {
|
|
36
37
|
return `${allChecks.length} checks`;
|
|
37
38
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
HOW TO READ THE RESULT
|
|
52
|
-
|
|
53
|
-
must_fix_before_write
|
|
54
|
-
true -> Do NOT write the file. It will not parse, it will raise at runtime, or
|
|
55
|
-
the deploy converter will reject it — and a converter rejection fails the
|
|
56
|
-
WHOLE changeset, not just this file.
|
|
57
|
-
false -> Nothing BLOCKING was found. This is not a statement that the code is
|
|
58
|
-
correct, only that no known-fatal problem was detected. Keep your own
|
|
59
|
-
judgement.
|
|
60
|
-
|
|
61
|
-
status
|
|
62
|
-
ok | warning | error -> the file WAS checked; these describe what was found.
|
|
63
|
-
not_applicable -> the file was NOT checked at all. This is neither
|
|
64
|
-
approval nor refusal — it carries no opinion about the
|
|
65
|
-
file. Read not_applicable_reason before deciding:
|
|
66
|
-
outside_project - not inside the project this server serves
|
|
67
|
-
unsupported_type - not a file type platformOS lints
|
|
68
|
-
misplaced_source - a platformOS source outside every deployed subtree; nothing
|
|
69
|
-
checked it and nothing will load it either
|
|
70
|
-
ignored - excluded by the project's .platformos-check.yml
|
|
71
|
-
too_large - one buffer, or the request as a whole, is above its size
|
|
72
|
-
limit. Split the file, or send fewer files per call — the
|
|
73
|
-
reason text says which bound was hit
|
|
74
|
-
timed_out - validation was abandoned; retrying may work
|
|
75
|
-
internal_error - your REQUEST was malformed, or the validator hit a bug; the
|
|
76
|
-
reason text says which. A malformed request — both input
|
|
77
|
-
forms at once, neither, or one file listed twice — is yours
|
|
78
|
-
to fix and worth retrying once fixed.
|
|
39
|
+
/**
|
|
40
|
+
* The request caps, DERIVED for the same reason as the count above.
|
|
41
|
+
*
|
|
42
|
+
* `MAX_BATCH_FILES` already reaches the model as `maxItems` on the tool's schema, but
|
|
43
|
+
* `MAX_BATCH_BYTES` is computed from the cost model and appears in no schema and no prose —
|
|
44
|
+
* so a caller could only learn it by being refused. Stated together because a batch is
|
|
45
|
+
* planned against both at once, and derived so that moving the cost model moves this too.
|
|
46
|
+
*/
|
|
47
|
+
function bounds() {
|
|
48
|
+
return `${MAX_BATCH_FILES} files and ${Math.floor(MAX_BATCH_BYTES / 1024)} KiB`;
|
|
49
|
+
}
|
|
50
|
+
export const SERVER_INSTRUCTIONS = `Tool Purpose: Validates platformOS Liquid, GraphQL and YAML files in-memory to prevent broken deployments.
|
|
79
51
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
errors are real problems that do not stop the file working (an argument a partial
|
|
86
|
-
ignores, a missing asset, a missing image dimension). Fix them when you can; they
|
|
87
|
-
do not block the write.
|
|
88
|
-
Each finding names the check that produced it, and where see_also is present it links
|
|
89
|
-
that check's documentation — read it there rather than guessing at the rule.
|
|
90
|
-
A finding may carry fix (edits that are safe to apply as given) or suggestions
|
|
91
|
-
(alternatives to choose between). Their start_index / end_index are 0-based offsets
|
|
92
|
-
into the buffer you sent — NOT the 1-based line/column on the same finding. Apply
|
|
93
|
-
several edits from the end backwards, or account for the drift.
|
|
52
|
+
CRITICAL USAGE RULES
|
|
53
|
+
- Validate BEFORE writing: always pass the proposed in-memory buffer. NEVER write to disk first. This is the primary quality gate. Skipping this tool is the #1 cause of broken platformOS code.
|
|
54
|
+
- Audit existing code with the same call: pass a file's current contents to learn whether what is on disk is already broken. Its own findings are real, but impact is not — impact lints the dependants with your buffer and again without it and reports the difference, so an unchanged buffer yields an empty impact by construction, not by safety.
|
|
55
|
+
- Batch interdependent files: if one change touches several referencing files, send them together in the files array so cross-references resolve. Sent one at a time, a partial you are creating alongside its caller is reported missing. Up to ${bounds()} per request.
|
|
56
|
+
- No duplicates: List each file at most once per request. A changeset cannot hold two versions of one file, so a request naming one twice is refused.
|
|
94
57
|
|
|
95
|
-
|
|
96
|
-
Present ONLY when a file had so many findings that the lists were shortened to
|
|
97
|
-
keep the answer a reasonable size; absent means the lists are complete. It gives
|
|
98
|
-
the true total per affected list, so "returned: 40, total: 900" means 860 more
|
|
99
|
-
exist. The lists keep the TOP of the file, where a cascade's root cause usually
|
|
100
|
-
is. status and must_fix_before_write are always computed from ALL findings, never
|
|
101
|
-
from the shortened list, so a truncated answer is never a softer verdict — fix
|
|
102
|
-
what is listed and validate again to see the rest.
|
|
58
|
+
RESPONSE SCHEMA & ACTION DIRECTIVES
|
|
103
59
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
carries the check's own findings: same message, same severity, same documentation link, and
|
|
108
|
-
the same fixes, exactly as if you had validated that file yourself.
|
|
109
|
-
It reports only what your change INTRODUCED. A problem that file already had is never
|
|
110
|
-
listed, however severe — it is not this edit's doing, and it would bury the one that is.
|
|
111
|
-
A break in someone else's file does NOT set must_fix_before_write: your buffer may be
|
|
112
|
-
perfectly correct. Fix the callers, or decide not to; that is yours to weigh.
|
|
113
|
-
status computed the dependants were linted with your change and without it
|
|
114
|
-
not_applicable nothing can reference this file by name
|
|
115
|
-
unavailable could not be run: a failure, a deadline, or a file referenced from
|
|
116
|
-
more text than can be examined in time
|
|
117
|
-
disabled this server runs with --no-impact, so nothing was attempted
|
|
118
|
-
unchecked_dependants appears when a file has more dependants than one request will lint.
|
|
119
|
-
Those were never checked, so an otherwise-clean answer carrying it is a PARTIAL one.
|
|
120
|
-
NOTHING HERE IS A CLEARANCE. An empty impact means no break was found among the dependants
|
|
121
|
-
that are VISIBLE, and a dependant can be invisible: {% render partial_name %} picks its
|
|
122
|
-
target at runtime, so no analysis can resolve it.
|
|
123
|
-
This server never tells you nothing depends on a file — if you are about to delete or
|
|
124
|
-
rename one, search the project yourself.
|
|
60
|
+
must_fix_before_write (Boolean)
|
|
61
|
+
- true: FATAL. Do NOT write the file. The deploy converter refuses the WHOLE changeset, not just this file.
|
|
62
|
+
- false: nothing blocking was found. This is NOT a statement that the code is correct, only that no known-fatal problem was detected. Keep your own judgement.
|
|
125
63
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
64
|
+
status (String)
|
|
65
|
+
- ok | warning | error: the file WAS checked; these describe what was found.
|
|
66
|
+
- not_applicable: the file was NOT checked. Neither approval nor refusal — it carries no opinion about the file.
|
|
67
|
+
- not_applicable_reason: outside_project, unsupported_type, misplaced_source, ignored, too_large, timed_out, internal_error.
|
|
68
|
+
- next_step: the one to act on. It names the path, limit or deadline actually hit, and what to do about it.
|
|
69
|
+
- too_large: one buffer, or the request as a whole, is above its size limit. next_step says which, so shrink a file or send fewer per call accordingly.
|
|
70
|
+
- Retry: timed_out is worth another call. internal_error is two cases — a malformed request (both input forms at once, neither, or one file listed twice) is yours to fix and worth retrying once fixed; a validator bug is not, and no retry will change it.
|
|
130
71
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
72
|
+
errors, warnings, infos (Arrays)
|
|
73
|
+
- Each array is ordered by line then column WITHIN ITSELF. The three are not one sequence, so concatenating them does not walk the file in order. Columns count UTF-16 code units, so an emoji advances the column by 2.
|
|
74
|
+
- errors[] can be non-empty while must_fix_before_write is false: an argument a partial ignores, a missing asset, a missing image dimension are real but do not stop the file working.
|
|
75
|
+
- Fixes and suggestions carry start_index / end_index: 0-based offsets into the buffer you sent, NOT the 1-based line/column on the same finding.
|
|
76
|
+
- Action: to avoid offset drift, apply multiple edits from the bottom of the file upwards.
|
|
77
|
+
- Action: where see_also is present, read that check's documentation rather than guessing at the rule.
|
|
136
78
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
IS accepted by the platform.
|
|
79
|
+
truncated (Object)
|
|
80
|
+
- Present only when a file produced too many findings to return in full. The lists keep the TOP of the file, where a cascade's root cause usually is.
|
|
81
|
+
- Constraint: status and must_fix_before_write are ALWAYS computed from the true total of findings, never from the shortened list. Fix what is listed and re-validate to see the rest.
|
|
141
82
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
83
|
+
impact (Object)
|
|
84
|
+
- What this change BREAKS in files you are NOT editing — the one thing a per-file lint cannot see, since it only looks at the buffers you sent.
|
|
85
|
+
- It reports only what your change INTRODUCED. A problem the file already had is never listed, however severe.
|
|
86
|
+
- Constraint: a dependant break does NOT set must_fix_before_write. Your buffer may be perfectly correct; fix the callers or decide not to.
|
|
87
|
+
- impact.status:
|
|
88
|
+
- computed: the dependants were linted with your change and without it.
|
|
89
|
+
- not_applicable: no dependant the graph can find names this file. That is not a clearance.
|
|
90
|
+
- unavailable | disabled: the comparison never ran. An empty impact under either is NOT a finding of safety.
|
|
91
|
+
- unchecked_dependants: present when a file has more dependants than one request will lint, so an otherwise-clean answer carrying it is a PARTIAL one.
|
|
92
|
+
- NOTHING HERE IS A CLEARANCE. A dependant can be invisible: {% render partial_name %} picks its target at runtime, so no analysis can resolve it. This server never tells you nothing depends on a file — before renaming or deleting one, search the project yourself.
|
|
146
93
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
94
|
+
LIMITATIONS (what a clean result does NOT prove)
|
|
95
|
+
${coverage()} run against your buffer. Coverage is per project: checks can be enabled, disabled or ignored in .platformos-check.yml, so a clean result reflects that configuration rather than a fixed universal standard. Where a finding exists it explains itself and links its documentation, so what follows is only the SILENCES.
|
|
96
|
+
- An argument the documentation leaves untyped accepts more than one type and is never reported — which is every argument of every core Liquid filter, because those coerce rather than refuse. {{ 5 | upcase }} renders and is not reported.
|
|
97
|
+
- A model schema's property TYPE is checked and an unknown one is reported. The rest of the shape is not: an unrecognised top-level key is rejected on deploy and nothing reports it.
|
|
98
|
+
- Duplicate YAML keys are compared the way the platform's own parser resolves them, but NOT exhaustively — a few spellings collide on the platform and are not reported, so silence there does not prove two keys are distinct.`;
|
|
150
99
|
//# sourceMappingURL=instructions.js.map
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* This module owns only the MCP surface: schema, description, registration, and mapping
|
|
17
17
|
* input shape to output shape. All logic lives in `validate/`.
|
|
18
18
|
*/
|
|
19
|
-
import {
|
|
19
|
+
import { z } from 'zod';
|
|
20
20
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
21
21
|
import type { SupervisorContext } from '../context.js';
|
|
22
22
|
import type { ValidateCodeParams, ValidateCodeResult, ValidateFilesResult } from '../result/types.js';
|
|
@@ -35,11 +35,15 @@ import { MAX_BATCH_BYTES, MAX_BATCH_FILES } from '../validate/batch-bounds.js';
|
|
|
35
35
|
* that does not convert may as well not be advertised at all. Prefer a zod builtin
|
|
36
36
|
* over a `.refine` wherever one expresses the rule; `transport/validate-code.spec.ts`
|
|
37
37
|
* pins the emitted document end to end.
|
|
38
|
-
*
|
|
39
|
-
* Typed as `ZodRawShape` (not the inferred literal shape) so `registerTool` does not
|
|
40
|
-
* instantiate excessively deeply over the schema (TS2589 under zod 3.25).
|
|
41
38
|
*/
|
|
42
|
-
export declare const VALIDATE_CODE_INPUT:
|
|
39
|
+
export declare const VALIDATE_CODE_INPUT: {
|
|
40
|
+
file_path: z.ZodOptional<z.ZodString>;
|
|
41
|
+
content: z.ZodOptional<z.ZodString>;
|
|
42
|
+
files: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
43
|
+
file_path: z.ZodString;
|
|
44
|
+
content: z.ZodString;
|
|
45
|
+
}, z.core.$strip>>>;
|
|
46
|
+
};
|
|
43
47
|
/**
|
|
44
48
|
* The agent-facing prose, exported so tests can pin claims that must not rot. The
|
|
45
49
|
* description is the agent's whole understanding of this tool; a stale sentence
|
|
@@ -72,9 +72,6 @@ const EXAMPLE_PROMO = exampleOf(PlatformOSFileType.Partial, 'promo');
|
|
|
72
72
|
* that does not convert may as well not be advertised at all. Prefer a zod builtin
|
|
73
73
|
* over a `.refine` wherever one expresses the rule; `transport/validate-code.spec.ts`
|
|
74
74
|
* pins the emitted document end to end.
|
|
75
|
-
*
|
|
76
|
-
* Typed as `ZodRawShape` (not the inferred literal shape) so `registerTool` does not
|
|
77
|
-
* instantiate excessively deeply over the schema (TS2589 under zod 3.25).
|
|
78
75
|
*/
|
|
79
76
|
export const VALIDATE_CODE_INPUT = {
|
|
80
77
|
file_path: filePath()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformos/platformos-mcp-supervisor",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "platformOS Model Context Protocol (MCP) server exposing validate_code for LLM agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -26,9 +26,7 @@
|
|
|
26
26
|
"access": "public",
|
|
27
27
|
"@platformos:registry": "https://registry.npmjs.org"
|
|
28
28
|
},
|
|
29
|
-
"bin":
|
|
30
|
-
"platformos-mcp-supervisor": "dist/bin/platformos-mcp-supervisor.js"
|
|
31
|
-
},
|
|
29
|
+
"bin": "dist/bin/platformos-mcp-supervisor.js",
|
|
32
30
|
"files": [
|
|
33
31
|
"dist/**/*.js",
|
|
34
32
|
"dist/**/*.d.ts"
|
|
@@ -42,14 +40,17 @@
|
|
|
42
40
|
"type-check": "tsc --noEmit"
|
|
43
41
|
},
|
|
44
42
|
"dependencies": {
|
|
45
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
43
|
+
"@modelcontextprotocol/sdk": "^1.32.2",
|
|
46
44
|
"@platformos/liquid-html-parser": "0.2.0",
|
|
47
|
-
"@platformos/platformos-check-common": "1.
|
|
48
|
-
"@platformos/platformos-check-node": "1.
|
|
45
|
+
"@platformos/platformos-check-common": "1.2.0",
|
|
46
|
+
"@platformos/platformos-check-node": "1.2.0",
|
|
49
47
|
"@platformos/platformos-common": "0.2.0",
|
|
50
|
-
"@platformos/platformos-graph": "0.2.
|
|
51
|
-
"@platformos/platformos-language-server-common": "0.1.
|
|
52
|
-
"zod": "^
|
|
48
|
+
"@platformos/platformos-graph": "0.2.1",
|
|
49
|
+
"@platformos/platformos-language-server-common": "0.1.2",
|
|
50
|
+
"zod": "^4.6.7"
|
|
53
51
|
},
|
|
54
|
-
"devDependencies": {
|
|
55
|
-
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"typescript": "^5.9.0",
|
|
54
|
+
"vitest": "^4.0.18"
|
|
55
|
+
}
|
|
56
|
+
}
|