specguard-mcp 0.1.32 → 0.1.34
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/README.md +60 -4
- package/dist/src/config.d.ts +3 -1
- package/dist/src/config.js +3 -1
- package/dist/src/config.js.map +1 -1
- package/dist/src/support/specguard-api.d.ts +27 -3
- package/dist/src/support/specguard-api.js +63 -8
- package/dist/src/support/specguard-api.js.map +1 -1
- package/dist/src/tools/get-intent-schema.d.ts +3 -0
- package/dist/src/tools/get-intent-schema.js +264 -0
- package/dist/src/tools/get-intent-schema.js.map +1 -0
- package/dist/src/tools/get-server-version.d.ts +5 -2
- package/dist/src/tools/get-server-version.js +13 -5
- package/dist/src/tools/get-server-version.js.map +1 -1
- package/dist/src/tools/index.d.ts +31 -0
- package/dist/src/tools/index.js +33 -0
- package/dist/src/tools/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ refuses to boot and takes the tools that needed no configuration down with it.
|
|
|
32
32
|
|
|
33
33
|
| Variable | Needed by | Default | What it is |
|
|
34
34
|
| --- | --- | --- | --- |
|
|
35
|
-
| `SPECGUARD_ENDPOINT` | `get_repository_overview`, `get_server_version`, `list_repositories`, `add_repository`, `registrable_repositories` | — | your SpecGuard instance's root URL, **including the scheme** — e.g. `https://specguard.example.com`, or `http://localhost:3000`. A value with no scheme is refused by name (`SPECGUARD_ENDPOINT is not a usable URL: "sg.example.com"`) rather than surfacing later as an opaque failure. `SPECGUARD_URL` is accepted as an alias, and is the name every message uses when it is the one you set. A blank value counts as unset, so leaving `SPECGUARD_ENDPOINT` empty in a templated config falls through to `SPECGUARD_URL` instead of suppressing it. `get_server_version`
|
|
35
|
+
| `SPECGUARD_ENDPOINT` | `get_repository_overview`, `get_intent_schema`, `get_server_version`, `list_repositories`, `add_repository`, `registrable_repositories` | — | your SpecGuard instance's root URL, **including the scheme** — e.g. `https://specguard.example.com`, or `http://localhost:3000`. A value with no scheme is refused by name (`SPECGUARD_ENDPOINT is not a usable URL: "sg.example.com"`) rather than surfacing later as an opaque failure. `SPECGUARD_URL` is accepted as an alias, and is the name every message uses when it is the one you set. A blank value counts as unset, so leaving `SPECGUARD_ENDPOINT` empty in a templated config falls through to `SPECGUARD_URL` instead of suppressing it. `get_server_version` and `get_intent_schema` need only this variable — they send no API key, because the routes they read are unauthenticated by design |
|
|
36
36
|
| `SPECGUARD_API_KEY` | `get_repository_overview`, `near_duplicate_clusters` (default calls) | — | an agent/CI API key (`sgk_…`) issued by that deployment — a **per-repository** key, which is the single repository those tools answer about by default |
|
|
37
37
|
| `SPECGUARD_USER_API_KEY` | `list_repositories` (fallback), `add_repository`, `registrable_repositories`, `remove_repository` (fallback), `create_repository_api_key` (fallback), `revoke_repository_api_key` (fallback), `list_repository_api_keys` (fallback), `list_repository_agent_keys` (fallback), `revoke_repository_agent_key` (fallback), `list_repository_agent_keys_presented_revoked` (fallback), `list_repository_members` (fallback), `add_repository_member` (fallback), `update_repository_member_permissions` (fallback), `remove_repository_member` (fallback), `get_repository_overview` / `near_duplicate_clusters` **with** `repository` (fallback), `rename_repository` | — | a **user** API key (`sgu_…`), minted from that deployment's account page. A different credential from the one above, not a second place to put the same value: SpecGuard decides which of them a request may use from the token's prefix, before it reads anything, and answers `401` for the other one. Set whichever your tools need — both, if you use both |
|
|
38
38
|
| `SPECGUARD_AGENT_API_KEY` | `list_repositories` (preferred), `remove_repository` (preferred), `create_repository_api_key` (preferred), `revoke_repository_api_key` (preferred), `list_repository_api_keys` (preferred), `list_repository_agent_keys` (preferred), `revoke_repository_agent_key` (preferred), `list_repository_agent_keys_presented_revoked` (preferred), `list_repository_members` (preferred), `add_repository_member` (preferred), `update_repository_member_permissions` (preferred), `remove_repository_member` (preferred), `get_repository_overview` / `near_duplicate_clusters` **with** `repository` (preferred) | — | an **agent** API key (`sga_…`), minted from that deployment's account page (Agent keys panel) with an explicit set of repositories and permissions. It speaks for nobody: its reach is exactly the set granted onto it, fixed at mint time, and every read is bounded by that set server-side. This is the credential to give an automated agent — one key, many repositories, none of a person's rights. When it and `SPECGUARD_USER_API_KEY` are both set, every tool that answers either key — `list_repositories`, `remove_repository`, the members tools, the key-lifecycle tools, and `get_repository_overview` / `near_duplicate_clusters` **with** `repository` — uses **this** one, so discovery stays inside the set the other tools can reach |
|
|
@@ -90,6 +90,59 @@ tool call carrying findings — an agent told "the tool failed" retries the tool
|
|
|
90
90
|
a finding fixes the annotation. Only exit `2` is a tool error, and it carries the linter's stderr,
|
|
91
91
|
because the gem deliberately emits no document on that path.
|
|
92
92
|
|
|
93
|
+
### `get_intent_schema`
|
|
94
|
+
|
|
95
|
+
Serves the **OpenTestIntent schema document itself** — the contract an `@intent:` annotation is
|
|
96
|
+
validated against — read live from the deployment's own unauthenticated root-level schema mirror,
|
|
97
|
+
which hands back the canonical document's bytes verbatim.
|
|
98
|
+
|
|
99
|
+
Call it **before** writing or editing an annotation. This is the *reference*; `lint_intent_annotations`
|
|
100
|
+
is the *judge*, and a judge can only tell you that something you already wrote is wrong.
|
|
101
|
+
|
|
102
|
+
**Reading the contract is the only way to learn parts of it.** A refusal names the legal values of a
|
|
103
|
+
field you got *wrong*, and says nothing at all about a field you *omitted* — so the fastest way to
|
|
104
|
+
learn the rules from refusals alone is to submit values you believe are invalid. And an **optional**
|
|
105
|
+
property can never appear in any refusal: `required` does not name it, and a closed-object check
|
|
106
|
+
only ever reports the key you did send, so nothing you submit at any value causes the linter to
|
|
107
|
+
mention it. That part of the contract is reachable here and nowhere else in this toolset.
|
|
108
|
+
|
|
109
|
+
The answer is an **envelope** that carries the whole document in both shapes, derived from one
|
|
110
|
+
fetched body so they cannot disagree — plus the enforcement identity beside it:
|
|
111
|
+
|
|
112
|
+
| field | |
|
|
113
|
+
| --- | --- |
|
|
114
|
+
| `structured.schema` | the document **parsed** — the shape to read the field rules and any enumerated values off |
|
|
115
|
+
| `structured.enforced` | the identity the deployment itself serves from its `GET /version`: `schema_sha256`, the digest of the contract it actually enforces, and `schema_origin`, where those bytes come from on the server — or `null` when the deployment could not say |
|
|
116
|
+
| `text` | the served bytes **unchanged** — no re-encoding, no reformatting, so a digest taken over this text matches the canonical document's, which is the mirror's whole promise |
|
|
117
|
+
|
|
118
|
+
**The end-to-end check is derivable from this one tool.** Take a SHA-256 digest over `text` and
|
|
119
|
+
compare it with `enforced.schema_sha256`: a **match** means the reference you read is the contract
|
|
120
|
+
that will judge you; a **mismatch** means the bytes you received are *not* what the deployment
|
|
121
|
+
enforces — do not author annotations against them, and read `enforced.schema_origin` to see which
|
|
122
|
+
half of the disagreement is the server's. The tool serves both facts side by side and never
|
|
123
|
+
judges: a mismatch is never refused or warned here, because the judgment is yours.
|
|
124
|
+
|
|
125
|
+
**`enforced: null` means "this deployment could not say"** — its `/version` omits the identity
|
|
126
|
+
keys (a build predating the identity channel), answers non-2xx, or the identity fetch fails
|
|
127
|
+
entirely — and the document answer still stands in full. It is not the same null as a served
|
|
128
|
+
`schema_sha256: null` *inside* a present `enforced`: that is the deployment's own honest "I
|
|
129
|
+
enforce from this origin and cannot currently read it", passed through exactly as served.
|
|
130
|
+
|
|
131
|
+
Nothing in this bridge restates the schema's contents — not here, not in a tool description, not in
|
|
132
|
+
a test. The answer *is* the contract; any prose copy of it would be one release behind the document
|
|
133
|
+
this tool serves, and this repo deliberately vendors no copy of its own.
|
|
134
|
+
|
|
135
|
+
**A 404 means the deployment predates the mirror route: the endpoint is right and the build is old.**
|
|
136
|
+
The error text names the endpoint as possibly misconfigured, because a non-contract 404 body names
|
|
137
|
+
no cause — when the other tools work against the same endpoint, read it as *"the deployment needs
|
|
138
|
+
upgrading"*, not as a wrong URL. A **2xx** whose body will not parse is reported as a malformed
|
|
139
|
+
mirror instead, naming the route rather than your configuration: the response arrived, so the
|
|
140
|
+
endpoint is not the thing to go and fix.
|
|
141
|
+
|
|
142
|
+
**Needs no API key of any kind** — both routes it reads (the schema mirror and `GET /version`) are
|
|
143
|
+
unauthenticated by design, because a contract is not a secret — so it works with
|
|
144
|
+
`SPECGUARD_ENDPOINT` alone and sends no `Authorization` header. Takes no arguments.
|
|
145
|
+
|
|
93
146
|
### `get_repository_overview`
|
|
94
147
|
|
|
95
148
|
Asks SpecGuard what a repository's suite looks like **without running it** — the cold-start question
|
|
@@ -391,7 +444,10 @@ cancelled after two of four shards leaves a half-sized row in the history perman
|
|
|
391
444
|
|
|
392
445
|
Reports **which build of the SpecGuard deployment is answering**, read from the deployment's own
|
|
393
446
|
unauthenticated root-level `GET /version` — the figure the release bot's `VERSION` file carries,
|
|
394
|
-
served as
|
|
447
|
+
served as a JSON object and passed through verbatim. Since SPGD-1316 the body also carries the
|
|
448
|
+
enforced contract's identity beside the build (`schema_sha256` + `schema_origin`); this tool
|
|
449
|
+
passes the whole answer through without interpreting it — `get_intent_schema` is where the served
|
|
450
|
+
contract is read beside that identity and the two are compared.
|
|
395
451
|
|
|
396
452
|
**This is the server's build, not this bridge's.** The version in the initialize handshake's
|
|
397
453
|
`serverInfo` and the `specguard-mcp/<version>` User-Agent describe *this bridge* — a different
|
|
@@ -411,8 +467,8 @@ cause — when the other tools work against the same endpoint, read that error a
|
|
|
411
467
|
needs upgrading"*, not as a wrong URL.
|
|
412
468
|
|
|
413
469
|
**Needs no API key of any kind** — the route is unauthenticated by design — so it works with
|
|
414
|
-
`SPECGUARD_ENDPOINT` alone, and it
|
|
415
|
-
no arguments.
|
|
470
|
+
`SPECGUARD_ENDPOINT` alone, and it sends no `Authorization` header (as does `get_intent_schema`, the
|
|
471
|
+
other credential-free read here). Takes no arguments.
|
|
416
472
|
|
|
417
473
|
### `list_repositories`
|
|
418
474
|
|
package/dist/src/config.d.ts
CHANGED
|
@@ -322,7 +322,9 @@ export declare function requireUserOrAgentApiConfig(config: Config): Credentiall
|
|
|
322
322
|
* `Credential`: the server's root-level `GET /version` (SPGD-1197, specguard
|
|
323
323
|
* 08ab408) answers unauthenticated BY DESIGN — the platform's own doctrine
|
|
324
324
|
* places it outside the credential seam, at the root where the no-account
|
|
325
|
-
* reads (`/up`, the schema mirror) already live.
|
|
325
|
+
* reads (`/up`, the schema mirror) already live. SPGD-1331 made it serve a
|
|
326
|
+
* second such ask: the schema mirror named there is now wrapped too
|
|
327
|
+
* (`get_intent_schema`), through this same helper. Demanding a key here would
|
|
326
328
|
* invent a requirement the deployment does not have, and the
|
|
327
329
|
* credential-free config this returns is what keeps the transport from
|
|
328
330
|
* sending an `Authorization` header at all.
|
package/dist/src/config.js
CHANGED
|
@@ -190,7 +190,9 @@ export function requireUserOrAgentApiConfig(config) {
|
|
|
190
190
|
* `Credential`: the server's root-level `GET /version` (SPGD-1197, specguard
|
|
191
191
|
* 08ab408) answers unauthenticated BY DESIGN — the platform's own doctrine
|
|
192
192
|
* places it outside the credential seam, at the root where the no-account
|
|
193
|
-
* reads (`/up`, the schema mirror) already live.
|
|
193
|
+
* reads (`/up`, the schema mirror) already live. SPGD-1331 made it serve a
|
|
194
|
+
* second such ask: the schema mirror named there is now wrapped too
|
|
195
|
+
* (`get_intent_schema`), through this same helper. Demanding a key here would
|
|
194
196
|
* invent a requirement the deployment does not have, and the
|
|
195
197
|
* credential-free config this returns is what keeps the transport from
|
|
196
198
|
* sending an `Authorization` header at all.
|
package/dist/src/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,10 +9,34 @@ import { requireAgentApiConfig, requireApiConfig, requireEndpointApiConfig, requ
|
|
|
9
9
|
*
|
|
10
10
|
* The key is PRESENT-CONDITIONAL since SPGD-1200: every credentialled helper
|
|
11
11
|
* binds one and it rides every request as before, while a credential-free ask
|
|
12
|
-
* (`requireEndpointApiConfig
|
|
12
|
+
* (`requireEndpointApiConfig` — the unauthenticated `/version`, and since
|
|
13
|
+
* SPGD-1331 the schema mirror beside it) presents NO
|
|
13
14
|
* `Authorization` header at all rather than `Bearer ` with nothing after it.
|
|
14
15
|
*/
|
|
15
16
|
export declare function getJson(api: ApiConfig, path: string, query: Record<string, string | undefined>, fetchImpl: typeof globalThis.fetch): Promise<unknown>;
|
|
17
|
+
/**
|
|
18
|
+
* `GET` that hands back the RAW BODY TEXT — the read half of `deleteJson`'s
|
|
19
|
+
* argument, for a route whose bytes are the answer.
|
|
20
|
+
*
|
|
21
|
+
* `requestJson` JSON-parses every 2xx it sees and, when that parse fails,
|
|
22
|
+
* throws a sentence telling the operator to check that the endpoint points at
|
|
23
|
+
* a SpecGuard deployment "and not, say, a proxy or login page". That is the
|
|
24
|
+
* right diagnosis for a body that should have been JSON and was not; it is the
|
|
25
|
+
* WRONG one for a caller whose contract is the bytes themselves, because it
|
|
26
|
+
* names a cause (misconfigured endpoint) that the correct response in hand
|
|
27
|
+
* refutes. `deleteJson` already carries this shape for its own reason — its
|
|
28
|
+
* `204` has no body at all — and the argument generalises: what a SUCCESS body
|
|
29
|
+
* is for differs per caller, while the status check and the "reached and
|
|
30
|
+
* refused" hand-off to `describeFailure` do not.
|
|
31
|
+
*
|
|
32
|
+
* So this shares through `requestText` — the one total deadline, the abort,
|
|
33
|
+
* the reached-and-stopped vs could-not-reach split, and every crafted status
|
|
34
|
+
* sentence — and differs from `getJson` in exactly one thing: it returns what
|
|
35
|
+
* came back instead of what it parsed. A caller that wants a parsed value
|
|
36
|
+
* parses it, and owns the diagnosis for its own body, which is the only place
|
|
37
|
+
* that diagnosis can be correct.
|
|
38
|
+
*/
|
|
39
|
+
export declare function getText(api: ApiConfig, path: string, fetchImpl: typeof globalThis.fetch): Promise<string>;
|
|
16
40
|
/**
|
|
17
41
|
* `POST` with a JSON body — the write half of the transport, and deliberately
|
|
18
42
|
* the SAME function underneath.
|
|
@@ -55,8 +79,8 @@ export declare function patchJson(api: ApiConfig, path: string, body: Record<str
|
|
|
55
79
|
* "answered 204 but the body was not JSON" — the trap this verb specifically
|
|
56
80
|
* introduces, and the reason the DELETE path has its own success handling
|
|
57
81
|
* instead of sharing `requestJson`'s. The status check and the
|
|
58
|
-
* "reached and refused" hand-off to `describeFailure` are still shared
|
|
59
|
-
*
|
|
82
|
+
* "reached and refused" hand-off to `describeFailure` are still shared through
|
|
83
|
+
* `requestText`: only what happens to a SUCCESS body differs.
|
|
60
84
|
*/
|
|
61
85
|
export declare function deleteJson(api: ApiConfig, path: string, fetchImpl: typeof globalThis.fetch): Promise<string>;
|
|
62
86
|
/**
|
|
@@ -10,7 +10,8 @@ import { ApiError } from "../errors.js";
|
|
|
10
10
|
*
|
|
11
11
|
* The key is PRESENT-CONDITIONAL since SPGD-1200: every credentialled helper
|
|
12
12
|
* binds one and it rides every request as before, while a credential-free ask
|
|
13
|
-
* (`requireEndpointApiConfig
|
|
13
|
+
* (`requireEndpointApiConfig` — the unauthenticated `/version`, and since
|
|
14
|
+
* SPGD-1331 the schema mirror beside it) presents NO
|
|
14
15
|
* `Authorization` header at all rather than `Bearer ` with nothing after it.
|
|
15
16
|
*/
|
|
16
17
|
export async function getJson(api, path, query, fetchImpl) {
|
|
@@ -21,6 +22,31 @@ export async function getJson(api, path, query, fetchImpl) {
|
|
|
21
22
|
}
|
|
22
23
|
return requestJson(url, api, fetchImpl, { method: "GET" });
|
|
23
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* `GET` that hands back the RAW BODY TEXT — the read half of `deleteJson`'s
|
|
27
|
+
* argument, for a route whose bytes are the answer.
|
|
28
|
+
*
|
|
29
|
+
* `requestJson` JSON-parses every 2xx it sees and, when that parse fails,
|
|
30
|
+
* throws a sentence telling the operator to check that the endpoint points at
|
|
31
|
+
* a SpecGuard deployment "and not, say, a proxy or login page". That is the
|
|
32
|
+
* right diagnosis for a body that should have been JSON and was not; it is the
|
|
33
|
+
* WRONG one for a caller whose contract is the bytes themselves, because it
|
|
34
|
+
* names a cause (misconfigured endpoint) that the correct response in hand
|
|
35
|
+
* refutes. `deleteJson` already carries this shape for its own reason — its
|
|
36
|
+
* `204` has no body at all — and the argument generalises: what a SUCCESS body
|
|
37
|
+
* is for differs per caller, while the status check and the "reached and
|
|
38
|
+
* refused" hand-off to `describeFailure` do not.
|
|
39
|
+
*
|
|
40
|
+
* So this shares through `requestText` — the one total deadline, the abort,
|
|
41
|
+
* the reached-and-stopped vs could-not-reach split, and every crafted status
|
|
42
|
+
* sentence — and differs from `getJson` in exactly one thing: it returns what
|
|
43
|
+
* came back instead of what it parsed. A caller that wants a parsed value
|
|
44
|
+
* parses it, and owns the diagnosis for its own body, which is the only place
|
|
45
|
+
* that diagnosis can be correct.
|
|
46
|
+
*/
|
|
47
|
+
export async function getText(api, path, fetchImpl) {
|
|
48
|
+
return requestText(new URL(`${api.endpoint}${path}`), api, fetchImpl, { method: "GET" });
|
|
49
|
+
}
|
|
24
50
|
/**
|
|
25
51
|
* `POST` with a JSON body — the write half of the transport, and deliberately
|
|
26
52
|
* the SAME function underneath.
|
|
@@ -73,14 +99,11 @@ export async function patchJson(api, path, body, fetchImpl) {
|
|
|
73
99
|
* "answered 204 but the body was not JSON" — the trap this verb specifically
|
|
74
100
|
* introduces, and the reason the DELETE path has its own success handling
|
|
75
101
|
* instead of sharing `requestJson`'s. The status check and the
|
|
76
|
-
* "reached and refused" hand-off to `describeFailure` are still shared
|
|
77
|
-
*
|
|
102
|
+
* "reached and refused" hand-off to `describeFailure` are still shared through
|
|
103
|
+
* `requestText`: only what happens to a SUCCESS body differs.
|
|
78
104
|
*/
|
|
79
105
|
export async function deleteJson(api, path, fetchImpl) {
|
|
80
|
-
|
|
81
|
-
if (!response.ok)
|
|
82
|
-
throw describeFailure(response.status, body, api);
|
|
83
|
-
return body;
|
|
106
|
+
return requestText(new URL(`${api.endpoint}${path}`), api, fetchImpl, { method: "DELETE" });
|
|
84
107
|
}
|
|
85
108
|
/**
|
|
86
109
|
* `DELETE` that answers with a JSON body — the destructive verb's one non-empty
|
|
@@ -150,6 +173,26 @@ async function requestJson(url, api, fetchImpl, request) {
|
|
|
150
173
|
"or login page.", response.status);
|
|
151
174
|
}
|
|
152
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* The raw-body verbs' half of the response handling `requestJson` owns, in one
|
|
178
|
+
* place.
|
|
179
|
+
*
|
|
180
|
+
* Extracted when `getText` needed a home beside the JSON verbs rather than
|
|
181
|
+
* copied into it: the status check and the "reached and refused" hand-off to
|
|
182
|
+
* `describeFailure` are identical for both raw-body verbs, and what a SUCCESS
|
|
183
|
+
* body is for — the thing that differs per caller — stays out of here. There
|
|
184
|
+
* is deliberately NO not-JSON branch: for a bytes-are-the-answer contract,
|
|
185
|
+
* `requestJson`'s "was not JSON" diagnosis is wrong even when a parse would
|
|
186
|
+
* fail, because it names a cause (misconfigured endpoint) the correct response
|
|
187
|
+
* in hand refutes. A caller that wants a parsed value parses its own body and
|
|
188
|
+
* owns that judgment.
|
|
189
|
+
*/
|
|
190
|
+
async function requestText(url, api, fetchImpl, request) {
|
|
191
|
+
const { response, body } = await fetchWithTimeout(url, api, fetchImpl, request);
|
|
192
|
+
if (!response.ok)
|
|
193
|
+
throw describeFailure(response.status, body, api);
|
|
194
|
+
return body;
|
|
195
|
+
}
|
|
153
196
|
/** The three-clause guard both `*JsonObject` narrowings share. */
|
|
154
197
|
function asJsonObject(body) {
|
|
155
198
|
if (typeof body !== "object" || body === null || Array.isArray(body)) {
|
|
@@ -266,7 +309,19 @@ async function fetchWithTimeout(url, api, fetchImpl, request) {
|
|
|
266
309
|
fetchImpl(url, {
|
|
267
310
|
method: request.method,
|
|
268
311
|
headers: {
|
|
269
|
-
|
|
312
|
+
// What this bridge will accept, and every media type the deployment
|
|
313
|
+
// actually serves it — the header is a CLAIM, so it must not exclude
|
|
314
|
+
// a route this client calls. SpecGuard's own doctrine puts one read
|
|
315
|
+
// outside the JSON surface: the schema mirror answers
|
|
316
|
+
// `application/schema+json`, the media type draft-07 registers for a
|
|
317
|
+
// schema document, and it is served by a `render plain:` with an
|
|
318
|
+
// explicit content type, which does not negotiate. So the narrower
|
|
319
|
+
// header happened to work — the request succeeded while announcing
|
|
320
|
+
// it would not accept what came back. Widened rather than made
|
|
321
|
+
// per-call: the `Accept` of this transport is a property of the
|
|
322
|
+
// client, not of an individual call, which is the same argument
|
|
323
|
+
// `RequestSpec` makes for staying narrow.
|
|
324
|
+
Accept: "application/json, application/schema+json",
|
|
270
325
|
// The version rides the identity the platform's rejection triage
|
|
271
326
|
// stores verbatim (`specguard-mcp/<version>`), the same shape the
|
|
272
327
|
// sibling clients already send. Resolved per request — see
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"specguard-api.js","sourceRoot":"","sources":["../../../src/support/specguard-api.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,wBAAwB,EACxB,oBAAoB,EACpB,2BAA2B,GAI5B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC
|
|
1
|
+
{"version":3,"file":"specguard-api.js","sourceRoot":"","sources":["../../../src/support/specguard-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { ApiError } from "../errors.js";
|
|
2
|
+
import { getJsonObject, getText, requireEndpointApiConfig } from "../support/specguard-api.js";
|
|
3
|
+
/**
|
|
4
|
+
* The OpenTestIntent contract, READABLE — the reference this bridge was
|
|
5
|
+
* missing beside the judge it already had.
|
|
6
|
+
*
|
|
7
|
+
* == The gap this closes, and why refusals could not close it
|
|
8
|
+
*
|
|
9
|
+
* SpecGuard is structurally gated on `@intent:` annotations existing, and the
|
|
10
|
+
* only thing this bridge could say about one until now was whether an
|
|
11
|
+
* annotation the agent HAD ALREADY WRITTEN was wrong. `lint_intent_annotations`
|
|
12
|
+
* is a judge, not a reference: an agent authoring a new annotation had to
|
|
13
|
+
* guess, write the guess to a file, lint it, and read the refusal.
|
|
14
|
+
*
|
|
15
|
+
* Refusals are an INCOMPLETE teacher, and the sharpest asymmetry is that a
|
|
16
|
+
* WRONG enumerated value names the legal set in its error while an ABSENT one
|
|
17
|
+
* does not — so the fastest way to learn the contract through a judge is to
|
|
18
|
+
* submit a value you believe is invalid, which is a perverse thing for a
|
|
19
|
+
* toolset to reward. Worse, the schema declares an OPTIONAL property, and an
|
|
20
|
+
* optional property is underivable in principle from that surface: `required`
|
|
21
|
+
* never names it, and a closed-object refusal only ever reports the key you
|
|
22
|
+
* DID send. No input to the linter at any value causes it to be mentioned.
|
|
23
|
+
* That is the hole this tool exists to fill, and it is why this is a read of
|
|
24
|
+
* the contract rather than a nicer error message on the judge.
|
|
25
|
+
*
|
|
26
|
+
* == It MIRRORS; it does not carry a copy
|
|
27
|
+
*
|
|
28
|
+
* The bytes come from the deployment's own root-level, unauthenticated schema
|
|
29
|
+
* mirror — `SchemasController`, which renders the vendored document verbatim
|
|
30
|
+
* with an explicit `application/schema+json` content type and whose request
|
|
31
|
+
* spec pins the response to the file's bytes by digest. Vendoring the schema
|
|
32
|
+
* into this repo instead would mint a THIRD copy of a document whose entire
|
|
33
|
+
* design is one canonical source plus byte-identical mirrors, and it would
|
|
34
|
+
* drift silently — a bridge that answers from its own copy answers about
|
|
35
|
+
* itself, not about the deployment the agent is being judged by.
|
|
36
|
+
*
|
|
37
|
+
* For the same reason the contract's contents are not transcribed into this
|
|
38
|
+
* file's description, the README, or a test name. A second copy of a field
|
|
39
|
+
* list is one release behind the schema by construction. The tool is
|
|
40
|
+
* cross-referenced by name from elsewhere; its ANSWER is where the fields
|
|
41
|
+
* live.
|
|
42
|
+
*
|
|
43
|
+
* == Why the body is fetched raw, and why both shapes come off one value
|
|
44
|
+
*
|
|
45
|
+
* `getText` rather than `getJsonObject`, and the reason is a diagnosis rather
|
|
46
|
+
* than a preference: `requestJson`'s not-JSON sentence tells the operator to
|
|
47
|
+
* check that the endpoint points at a SpecGuard deployment "and not, say, a
|
|
48
|
+
* proxy or login page" — the wrong remedy for a response that arrived
|
|
49
|
+
* perfectly correctly and simply is not what that helper assumed. So this
|
|
50
|
+
* shares the deadline and the failure diagnosis and owns its own success
|
|
51
|
+
* handling, exactly as `deleteJson` does for its empty `204`.
|
|
52
|
+
*
|
|
53
|
+
* The verbatim body is then served as the text view and PARSED ONCE for the
|
|
54
|
+
* document view, both derived from the one fetched value as `tools/types.ts`
|
|
55
|
+
* requires. The text half is what keeps the mirror's promise intact across
|
|
56
|
+
* this bridge: a consumer digesting what it received gets the same digest the
|
|
57
|
+
* platform's own spec asserts, which a re-encode or a pretty-print would
|
|
58
|
+
* destroy. The structured half is the shape an agent actually reads a
|
|
59
|
+
* contract from — and `application/schema+json` carries the `+json`
|
|
60
|
+
* structured-syntax suffix precisely so a client dispatching on "is this
|
|
61
|
+
* JSON" still parses it.
|
|
62
|
+
*
|
|
63
|
+
* A 2xx body that will not parse is a genuinely malformed mirror and is
|
|
64
|
+
* reported as THAT, naming the route rather than the endpoint variable: the
|
|
65
|
+
* response arrived, so the configuration is not the thing to go and fix.
|
|
66
|
+
*
|
|
67
|
+
* == The enforcement identity beside it: a SECOND body, whose disagreement IS
|
|
68
|
+
* the check
|
|
69
|
+
*
|
|
70
|
+
* Since SPGD-1316 the deployment also answers WHICH CONTRACT IT ENFORCES:
|
|
71
|
+
* `GET /version` carries `schema_sha256` — the digest of the vendored document
|
|
72
|
+
* this process validates every ingested annotation against — and
|
|
73
|
+
* `schema_origin`, the repo-relative path those bytes come from. The pairing
|
|
74
|
+
* the platform's own controller names is exact: the same bytes are fetchable,
|
|
75
|
+
* unauthenticated, from this same host at the mirror route above, so a client
|
|
76
|
+
* can digest them itself and check the served answer. This tool is where that
|
|
77
|
+
* loop closes. Until now the bridge carried those keys invisibly —
|
|
78
|
+
* `get_server_version` passed them through, but the tool whose question IS the
|
|
79
|
+
* contract named no comparison target, and `schema_sha256` appeared nowhere on
|
|
80
|
+
* this surface — so the question "is the reference I read the contract that
|
|
81
|
+
* will judge me?" was underivable from this toolset at all.
|
|
82
|
+
*
|
|
83
|
+
* `run()` now makes BOTH fetches and serves the two facts side by side. The
|
|
84
|
+
* identity fetch is the exact helper on the exact route `get_server_version`
|
|
85
|
+
* uses — `getJsonObject` against `/version` — so nothing new is invented: no
|
|
86
|
+
* second tool on that route, no new transport, no new credential kind, no new
|
|
87
|
+
* dependency. What is new is the shape of the answer: `structured` becomes an
|
|
88
|
+
* envelope, `{ schema, enforced }`, with the server's own key names preserved
|
|
89
|
+
* verbatim so the family cross-check is one vocabulary.
|
|
90
|
+
*
|
|
91
|
+
* The one-body doctrine above is RECONCILED here, not violated: `text` and
|
|
92
|
+
* `structured.schema` are two views of the ONE mirror body and must not
|
|
93
|
+
* disagree, while the whole point of `enforced` is that it CAN — a mismatch
|
|
94
|
+
* between a SHA-256 digest over `text` and `enforced.schema_sha256` IS the
|
|
95
|
+
* finding, and `enforced.schema_origin` is the fact that says which half of
|
|
96
|
+
* the disagreement is the server's. The tool serves both facts and never
|
|
97
|
+
* judges: refusing or warning on a mismatch would blind the agent in exactly
|
|
98
|
+
* the mangled-transport case where both facts matter most, and the judgment
|
|
99
|
+
* is the reader's.
|
|
100
|
+
*
|
|
101
|
+
* == The identity leg is best-effort by design
|
|
102
|
+
*
|
|
103
|
+
* Its failure must never fail the tool whose primary answer is the document.
|
|
104
|
+
* Any of — a deployment predating the identity channel (its `/version` omits
|
|
105
|
+
* the keys), a non-2xx answer, a network failure, a body that will not parse —
|
|
106
|
+
* yields `enforced: null` with the document answer still standing in full. No
|
|
107
|
+
* throw, no sentinel. `null` means "this deployment could not say", and the
|
|
108
|
+
* description says so in the reader's terms. This inherits the server's own
|
|
109
|
+
* nil doctrine in both directions: a current deployment whose vendored schema
|
|
110
|
+
* cannot be read answers `schema_sha256: null` at 200 — an honest null INSIDE
|
|
111
|
+
* a present envelope, passed through as served — while `enforced: null` is
|
|
112
|
+
* the envelope-level absence, the deployment having said nothing at all. The
|
|
113
|
+
* two nulls answer different questions and are kept apart.
|
|
114
|
+
*
|
|
115
|
+
* == No arguments, no credential
|
|
116
|
+
*
|
|
117
|
+
* Neither route takes parameters and neither authenticates anything, so the
|
|
118
|
+
* tool advertises no argument and binds no key — the second consumer of
|
|
119
|
+
* `requireEndpointApiConfig` after `get_server_version`, sending no
|
|
120
|
+
* `Authorization` header on EITHER fetch even when every key variable is set.
|
|
121
|
+
* A contract is not a secret, and presenting a key an endpoint does not read
|
|
122
|
+
* is not authentication, it is leakage.
|
|
123
|
+
*/
|
|
124
|
+
const SCHEMA_PATH = "/schemas/open-test-intent.v1.json";
|
|
125
|
+
/**
|
|
126
|
+
* The identity route, beside the mirror route above — the exact path
|
|
127
|
+
* `get_server_version` reads, fetched here with the exact helper that tool
|
|
128
|
+
* uses. One route, one tool each: this is not a second tool on `/version`, it
|
|
129
|
+
* is the contract tool carrying the comparison target its own description
|
|
130
|
+
* invites the reader to compute.
|
|
131
|
+
*/
|
|
132
|
+
const VERSION_PATH = "/version";
|
|
133
|
+
const getIntentSchema = {
|
|
134
|
+
name: "get_intent_schema",
|
|
135
|
+
title: "OpenTestIntent schema",
|
|
136
|
+
description: "Serves the OpenTestIntent schema document itself — the CONTRACT an `@intent:` annotation is " +
|
|
137
|
+
"validated against — read live from the SpecGuard deployment's own unauthenticated root-level " +
|
|
138
|
+
"schema mirror, which serves the canonical document's bytes verbatim. Call this BEFORE writing " +
|
|
139
|
+
"or editing an annotation: it is the reference, while lint_intent_annotations is the judge, and " +
|
|
140
|
+
"a judge can only tell you that something you already wrote is wrong. Reading the contract is " +
|
|
141
|
+
"also the ONLY way to learn parts of it: a refusal names the legal values of a field you got " +
|
|
142
|
+
"wrong but says nothing about a field you omitted, and an OPTIONAL property can never appear in " +
|
|
143
|
+
"any refusal at all — nothing you submit, at any value, causes the linter to mention it. The " +
|
|
144
|
+
"answer is an envelope carrying the whole document in both shapes, derived from one fetched " +
|
|
145
|
+
"body so they cannot disagree: `structured.schema` is it parsed, which is what to read the " +
|
|
146
|
+
"field rules and any enumerated values off; `text` is the served bytes UNCHANGED, so a digest " +
|
|
147
|
+
"taken over it matches the canonical document's. Beside the document, `structured.enforced` " +
|
|
148
|
+
"carries the enforcement identity the deployment itself serves from its `GET /version` — " +
|
|
149
|
+
"`schema_sha256`, the digest of the contract it actually enforces, and `schema_origin`, where " +
|
|
150
|
+
"those bytes come from on the server — which makes the end-to-end check derivable from this " +
|
|
151
|
+
"one tool: take a SHA-256 digest over `text` and compare it with `enforced.schema_sha256`. A " +
|
|
152
|
+
"match means the reference you read IS the contract that will judge you; a mismatch means the " +
|
|
153
|
+
"bytes you received are NOT what the deployment enforces, and you must not author annotations " +
|
|
154
|
+
"against them — `enforced.schema_origin` names which half of the disagreement is the " +
|
|
155
|
+
"server's. The tool serves both facts side by side and never judges: a mismatch is never " +
|
|
156
|
+
"refused or warned here, because the judgment is the reader's and a hard failure would blind " +
|
|
157
|
+
"you in exactly the mangled-transport case where both facts matter most. `enforced` is null " +
|
|
158
|
+
"when this deployment could not say — its `/version` omits the identity keys (a build " +
|
|
159
|
+
"predating the identity channel), answers non-2xx, or the identity fetch fails entirely — and " +
|
|
160
|
+
"the document answer still stands in full; null means 'this deployment could not say', never " +
|
|
161
|
+
"a sentinel. Nothing here restates the schema's contents — the answer is the contract, and " +
|
|
162
|
+
"any prose copy of it would be one release behind. A 404 means this deployment PREDATES the " +
|
|
163
|
+
"mirror route: the endpoint is right and the build is old. The error text names the endpoint " +
|
|
164
|
+
"as possibly misconfigured because a non-contract 404 body names no cause — when the other " +
|
|
165
|
+
"tools work against the same endpoint, read it as 'the deployment needs upgrading', not as a " +
|
|
166
|
+
"wrong URL. Needs NO API key of any kind — both routes it reads are unauthenticated by " +
|
|
167
|
+
"design, because a contract is not a secret — so it works with SPECGUARD_ENDPOINT alone and " +
|
|
168
|
+
"sends no Authorization header. Takes no arguments.",
|
|
169
|
+
inputSchema: {
|
|
170
|
+
type: "object",
|
|
171
|
+
// No properties, deliberately — a document has no ask to narrow. Still
|
|
172
|
+
// CLOSED rather than merely empty, for the reason `get-server-version.ts`
|
|
173
|
+
// states: `server.ts` forwards `arguments` unvalidated and `run` ignores
|
|
174
|
+
// them, so an open schema would let an invented argument be silently
|
|
175
|
+
// dropped while the call is answered as if it had been honoured.
|
|
176
|
+
additionalProperties: false,
|
|
177
|
+
},
|
|
178
|
+
async run(_args, context) {
|
|
179
|
+
const api = requireEndpointApiConfig(context.config);
|
|
180
|
+
const document = await getText(api, SCHEMA_PATH, context.fetch);
|
|
181
|
+
const schema = parseSchemaDocument(document, api.endpoint);
|
|
182
|
+
return {
|
|
183
|
+
// The served bytes, unchanged — see this file's header. The document's
|
|
184
|
+
// two views come off this ONE value; `enforced` is the deliberate SECOND
|
|
185
|
+
// body, whose possible disagreement with a digest over this text IS the
|
|
186
|
+
// check.
|
|
187
|
+
text: document,
|
|
188
|
+
structured: { schema, enforced: await enforcedIdentity(api, context.fetch) },
|
|
189
|
+
};
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* The parse, with the diagnosis this route actually needs.
|
|
194
|
+
*
|
|
195
|
+
* Deliberately NOT `requestJson`'s: its sentence sends the operator to check
|
|
196
|
+
* `SPECGUARD_ENDPOINT` for pointing at a proxy or a login page, and a 200 from
|
|
197
|
+
* the schema route is evidence AGAINST that reading — the deployment answered,
|
|
198
|
+
* on the path, with a status that says it meant to. What is wrong is the
|
|
199
|
+
* document, so the message says the document, and names the route so the
|
|
200
|
+
* report has somewhere to go.
|
|
201
|
+
*
|
|
202
|
+
* The object narrowing is part of the same answer rather than a second failure
|
|
203
|
+
* mode bolted beside it: a schema document's root is a JSON object, and a
|
|
204
|
+
* mirror serving an array or a bare scalar is malformed in exactly the way
|
|
205
|
+
* this sentence describes.
|
|
206
|
+
*/
|
|
207
|
+
function parseSchemaDocument(body, endpoint) {
|
|
208
|
+
let parsed;
|
|
209
|
+
try {
|
|
210
|
+
parsed = JSON.parse(body);
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
throw new ApiError(`${endpoint}${SCHEMA_PATH} answered successfully but the document it served is not valid ` +
|
|
214
|
+
"JSON. The route was reached and answered, so this is a malformed schema mirror on the " +
|
|
215
|
+
"deployment rather than a configuration problem on this side.");
|
|
216
|
+
}
|
|
217
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
218
|
+
throw new ApiError(`${endpoint}${SCHEMA_PATH} answered successfully but the document it served is not a JSON ` +
|
|
219
|
+
"object, which a schema document's root must be. The route was reached and answered, so " +
|
|
220
|
+
"this is a malformed schema mirror on the deployment rather than a configuration problem " +
|
|
221
|
+
"on this side.");
|
|
222
|
+
}
|
|
223
|
+
return parsed;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* The enforcement identity, fetched BEST-EFFORT — the `enforced` half of the
|
|
227
|
+
* envelope.
|
|
228
|
+
*
|
|
229
|
+
* Success is narrow and everything else is the same `null`. The narrow path: a
|
|
230
|
+
* 2xx JSON object carrying BOTH identity keys. A build predating the identity
|
|
231
|
+
* channel answers `{"version": …}` alone, and an envelope built over a missing
|
|
232
|
+
* key would be a fabricated half-answer rather than an honest absence, so the
|
|
233
|
+
* pair is required together — the same all-or-nothing choice the singular/
|
|
234
|
+
* plural branch in the transport makes. The values are copied through verbatim
|
|
235
|
+
* under the server's own key names, INCLUDING a null digest: a deployment that
|
|
236
|
+
* cannot currently read its vendored schema answers `schema_sha256: null` at
|
|
237
|
+
* 200 by its own doctrine, and that honesty is not this bridge's to improve —
|
|
238
|
+
* a present envelope saying "I enforce from this origin and cannot currently
|
|
239
|
+
* read it" is strictly more actionable than the envelope-level null below.
|
|
240
|
+
*
|
|
241
|
+
* Everything else — a non-2xx answer, an unreachable deployment, a timeout, a
|
|
242
|
+
* body that will not parse or is not an object, a `/version` that predates the
|
|
243
|
+
* route entirely — lands in the catch and returns `null`. That is deliberate:
|
|
244
|
+
* the identity leg is best-effort BY DESIGN, and its failure must never fail
|
|
245
|
+
* the tool whose primary answer is the document. `null` means "this deployment
|
|
246
|
+
* could not say", never a sentinel.
|
|
247
|
+
*/
|
|
248
|
+
async function enforcedIdentity(api, fetchImpl) {
|
|
249
|
+
try {
|
|
250
|
+
const version = await getJsonObject(api, VERSION_PATH, {}, fetchImpl);
|
|
251
|
+
if ("schema_sha256" in version && "schema_origin" in version) {
|
|
252
|
+
return {
|
|
253
|
+
schema_sha256: version["schema_sha256"],
|
|
254
|
+
schema_origin: version["schema_origin"],
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
export default getIntentSchema;
|
|
264
|
+
//# sourceMappingURL=get-intent-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-intent-schema.js","sourceRoot":"","sources":["../../../src/tools/get-intent-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -44,8 +44,11 @@ import type { ToolDefinition } from "./types.js";
|
|
|
44
44
|
* the tool advertises no argument and requires no key: it is the first tool
|
|
45
45
|
* here served by `requireEndpointApiConfig`, and the transport sends no
|
|
46
46
|
* `Authorization` header for it. The body is passed through verbatim —
|
|
47
|
-
* reshaping
|
|
48
|
-
*
|
|
47
|
+
* reshaping it would be a second copy of the platform's own identity answer,
|
|
48
|
+
* one release behind it. Since SPGD-1316 that body also carries the enforced
|
|
49
|
+
* contract's identity (`schema_sha256` + `schema_origin`) beside the build;
|
|
50
|
+
* this tool does not interpret it — `get_intent_schema` serves the contract
|
|
51
|
+
* beside that identity, which is where the pair is compared.
|
|
49
52
|
*/
|
|
50
53
|
declare const getServerVersion: ToolDefinition;
|
|
51
54
|
export default getServerVersion;
|
|
@@ -44,15 +44,23 @@ import { getJsonObject, requireEndpointApiConfig } from "../support/specguard-ap
|
|
|
44
44
|
* the tool advertises no argument and requires no key: it is the first tool
|
|
45
45
|
* here served by `requireEndpointApiConfig`, and the transport sends no
|
|
46
46
|
* `Authorization` header for it. The body is passed through verbatim —
|
|
47
|
-
* reshaping
|
|
48
|
-
*
|
|
47
|
+
* reshaping it would be a second copy of the platform's own identity answer,
|
|
48
|
+
* one release behind it. Since SPGD-1316 that body also carries the enforced
|
|
49
|
+
* contract's identity (`schema_sha256` + `schema_origin`) beside the build;
|
|
50
|
+
* this tool does not interpret it — `get_intent_schema` serves the contract
|
|
51
|
+
* beside that identity, which is where the pair is compared.
|
|
49
52
|
*/
|
|
50
53
|
const getServerVersion = {
|
|
51
54
|
name: "get_server_version",
|
|
52
55
|
title: "Server version",
|
|
53
56
|
description: "Reports WHICH BUILD of the SpecGuard DEPLOYMENT is answering, read from the deployment's own " +
|
|
54
57
|
"unauthenticated root-level `GET /version` — the figure the release bot's VERSION file carries, " +
|
|
55
|
-
|
|
58
|
+
"served as a JSON object and passed through verbatim. Since SPGD-1316 that body also carries " +
|
|
59
|
+
"the enforced contract's identity beside the build — `schema_sha256`, the digest of the " +
|
|
60
|
+
"OpenTestIntent document this deployment validates annotations against, and `schema_origin`, " +
|
|
61
|
+
"where those bytes come from on the server — and the whole object is passed through without " +
|
|
62
|
+
"interpreting it; get_intent_schema is where the served contract is read beside that identity " +
|
|
63
|
+
"and the two are compared. " +
|
|
56
64
|
"This is the SERVER's build, NOT this bridge's: the version in the initialize handshake's " +
|
|
57
65
|
"`serverInfo` and the `specguard-mcp/<version>` User-Agent describe this bridge, a different " +
|
|
58
66
|
"component released on its own cadence, so never read one as the other. Pinning which build's " +
|
|
@@ -65,8 +73,8 @@ const getServerVersion = {
|
|
|
65
73
|
"names the endpoint as possibly misconfigured because a non-contract 404 body names no cause — " +
|
|
66
74
|
"when the other tools work against the same endpoint, read that error as 'the deployment needs " +
|
|
67
75
|
"upgrading', not as a wrong URL. Needs NO API key of any kind — the route is unauthenticated by " +
|
|
68
|
-
"design — so it works with `SPECGUARD_ENDPOINT` alone, and it
|
|
69
|
-
"
|
|
76
|
+
"design — so it works with `SPECGUARD_ENDPOINT` alone, and it sends no `Authorization` header " +
|
|
77
|
+
"(as does get_intent_schema, the other credential-free read here). Takes no arguments.",
|
|
70
78
|
inputSchema: {
|
|
71
79
|
type: "object",
|
|
72
80
|
// No properties, deliberately — see this file's header. Still CLOSED rather
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-server-version.js","sourceRoot":"","sources":["../../../src/tools/get-server-version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAGtF
|
|
1
|
+
{"version":3,"file":"get-server-version.js","sourceRoot":"","sources":["../../../src/tools/get-server-version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAGtF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,MAAM,gBAAgB,GAAmB;IACvC,IAAI,EAAE,oBAAoB;IAC1B,KAAK,EAAE,gBAAgB;IACvB,WAAW,EACT,+FAA+F;QAC/F,iGAAiG;QACjG,8FAA8F;QAC9F,yFAAyF;QACzF,8FAA8F;QAC9F,6FAA6F;QAC7F,+FAA+F;QAC/F,4BAA4B;QAC5B,2FAA2F;QAC3F,8FAA8F;QAC9F,+FAA+F;QAC/F,iGAAiG;QACjG,0FAA0F;QAC1F,gGAAgG;QAChG,+FAA+F;QAC/F,8FAA8F;QAC9F,iGAAiG;QACjG,gGAAgG;QAChG,gGAAgG;QAChG,iGAAiG;QACjG,+FAA+F;QAC/F,uFAAuF;IACzF,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,4EAA4E;QAC5E,0EAA0E;QAC1E,0EAA0E;QAC1E,0EAA0E;QAC1E,mDAAmD;QACnD,oBAAoB,EAAE,KAAK;KAC5B;IAED,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO;QACtB,MAAM,GAAG,GAAG,wBAAwB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAErD,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAEvE,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACrC,UAAU,EAAE,MAAM;SACnB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -200,6 +200,37 @@ import type { ToolDefinition } from "./types.js";
|
|
|
200
200
|
* unchanged and still binding: the endpoint was verified-shipped on
|
|
201
201
|
* `origin/main` before this entry wrapped it. What moved was the platform,
|
|
202
202
|
* not the bar.
|
|
203
|
+
*
|
|
204
|
+
* == The contract itself, readable at last
|
|
205
|
+
*
|
|
206
|
+
* - `get_intent_schema` wraps the root-level `GET
|
|
207
|
+
* /schemas/open-test-intent.v1.json` (shipped: `specguard/config/routes.rb`,
|
|
208
|
+
* `SchemasController`, spec-covered by
|
|
209
|
+
* `spec/requests/open_test_intent_schema_spec.rb`).
|
|
210
|
+
*
|
|
211
|
+
* The second credential-free entry, and the one that gives this registry a
|
|
212
|
+
* REFERENCE beside the JUDGE it opened with. `lint_intent_annotations` can
|
|
213
|
+
* only say that an annotation already written is wrong, and its refusals are
|
|
214
|
+
* an incomplete teacher — a wrong enumerated value names the legal set, an
|
|
215
|
+
* omitted field does not, and the schema's OPTIONAL property is underivable
|
|
216
|
+
* in principle from a closed-object refusal, which only ever reports a key
|
|
217
|
+
* that WAS sent. Serving the document closes that hole without touching the
|
|
218
|
+
* judge.
|
|
219
|
+
*
|
|
220
|
+
* It mirrors rather than vendors, deliberately: the schema's design is one
|
|
221
|
+
* canonical source plus byte-identical mirrors, so a copy inside this bridge
|
|
222
|
+
* would be a third one, drifting silently and answering about itself instead
|
|
223
|
+
* of about the deployment the agent is judged by. That is also why it forced
|
|
224
|
+
* the transport's raw-body READ (`getText`): `requestJson`'s not-JSON
|
|
225
|
+
* sentence blames the endpoint for pointing at a proxy or a login page, which
|
|
226
|
+
* is the wrong remedy for a response that arrived correctly — the same
|
|
227
|
+
* argument `deleteJson`'s empty `204` made, generalised. The shared `Accept`
|
|
228
|
+
* header was widened in the same slice to admit `application/schema+json`, the
|
|
229
|
+
* media type this route actually serves: the header is a claim this client
|
|
230
|
+
* makes, and it must not exclude a route this client calls. The standing rule
|
|
231
|
+
* is unchanged and still binding — the route was verified-shipped, spec-covered
|
|
232
|
+
* and root-level before this entry wrapped it, and `/check-intent` (a comment
|
|
233
|
+
* in `routes.rb`) stays out.
|
|
203
234
|
*/
|
|
204
235
|
export declare const TOOLS: readonly ToolDefinition[];
|
|
205
236
|
export type { ToolContext, ToolDefinition, ToolResult } from "./types.js";
|
package/dist/src/tools/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import addRepository from "./add-repository.js";
|
|
2
2
|
import addRepositoryMember from "./add-repository-member.js";
|
|
3
3
|
import createRepositoryApiKey from "./create-repository-api-key.js";
|
|
4
|
+
import getIntentSchema from "./get-intent-schema.js";
|
|
4
5
|
import getServerVersion from "./get-server-version.js";
|
|
5
6
|
import lintIntentAnnotations from "./lint-intent-annotations.js";
|
|
6
7
|
import listRepositories from "./list-repositories.js";
|
|
@@ -218,9 +219,41 @@ import updateRepositoryMemberPermissions from "./update-repository-member-permis
|
|
|
218
219
|
* unchanged and still binding: the endpoint was verified-shipped on
|
|
219
220
|
* `origin/main` before this entry wrapped it. What moved was the platform,
|
|
220
221
|
* not the bar.
|
|
222
|
+
*
|
|
223
|
+
* == The contract itself, readable at last
|
|
224
|
+
*
|
|
225
|
+
* - `get_intent_schema` wraps the root-level `GET
|
|
226
|
+
* /schemas/open-test-intent.v1.json` (shipped: `specguard/config/routes.rb`,
|
|
227
|
+
* `SchemasController`, spec-covered by
|
|
228
|
+
* `spec/requests/open_test_intent_schema_spec.rb`).
|
|
229
|
+
*
|
|
230
|
+
* The second credential-free entry, and the one that gives this registry a
|
|
231
|
+
* REFERENCE beside the JUDGE it opened with. `lint_intent_annotations` can
|
|
232
|
+
* only say that an annotation already written is wrong, and its refusals are
|
|
233
|
+
* an incomplete teacher — a wrong enumerated value names the legal set, an
|
|
234
|
+
* omitted field does not, and the schema's OPTIONAL property is underivable
|
|
235
|
+
* in principle from a closed-object refusal, which only ever reports a key
|
|
236
|
+
* that WAS sent. Serving the document closes that hole without touching the
|
|
237
|
+
* judge.
|
|
238
|
+
*
|
|
239
|
+
* It mirrors rather than vendors, deliberately: the schema's design is one
|
|
240
|
+
* canonical source plus byte-identical mirrors, so a copy inside this bridge
|
|
241
|
+
* would be a third one, drifting silently and answering about itself instead
|
|
242
|
+
* of about the deployment the agent is judged by. That is also why it forced
|
|
243
|
+
* the transport's raw-body READ (`getText`): `requestJson`'s not-JSON
|
|
244
|
+
* sentence blames the endpoint for pointing at a proxy or a login page, which
|
|
245
|
+
* is the wrong remedy for a response that arrived correctly — the same
|
|
246
|
+
* argument `deleteJson`'s empty `204` made, generalised. The shared `Accept`
|
|
247
|
+
* header was widened in the same slice to admit `application/schema+json`, the
|
|
248
|
+
* media type this route actually serves: the header is a claim this client
|
|
249
|
+
* makes, and it must not exclude a route this client calls. The standing rule
|
|
250
|
+
* is unchanged and still binding — the route was verified-shipped, spec-covered
|
|
251
|
+
* and root-level before this entry wrapped it, and `/check-intent` (a comment
|
|
252
|
+
* in `routes.rb`) stays out.
|
|
221
253
|
*/
|
|
222
254
|
export const TOOLS = [
|
|
223
255
|
lintIntentAnnotations,
|
|
256
|
+
getIntentSchema,
|
|
224
257
|
getRepositoryOverview,
|
|
225
258
|
getServerVersion,
|
|
226
259
|
listRepositories,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,mBAAmB,MAAM,4BAA4B,CAAC;AAC7D,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,gBAAgB,MAAM,yBAAyB,CAAC;AACvD,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,uBAAuB,MAAM,iCAAiC,CAAC;AACtE,OAAO,uCAAuC,MAAM,mDAAmD,CAAC;AACxG,OAAO,qBAAqB,MAAM,+BAA+B,CAAC;AAClE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,qBAAqB,MAAM,0BAA0B,CAAC;AAC7D,OAAO,uBAAuB,MAAM,+BAA+B,CAAC;AACpE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,sBAAsB,MAAM,+BAA+B,CAAC;AACnE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,wBAAwB,MAAM,kCAAkC,CAAC;AACxE,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,iCAAiC,MAAM,2CAA2C,CAAC;AAG1F
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,mBAAmB,MAAM,4BAA4B,CAAC;AAC7D,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,eAAe,MAAM,wBAAwB,CAAC;AACrD,OAAO,gBAAgB,MAAM,yBAAyB,CAAC;AACvD,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,uBAAuB,MAAM,iCAAiC,CAAC;AACtE,OAAO,uCAAuC,MAAM,mDAAmD,CAAC;AACxG,OAAO,qBAAqB,MAAM,+BAA+B,CAAC;AAClE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,qBAAqB,MAAM,0BAA0B,CAAC;AAC7D,OAAO,uBAAuB,MAAM,+BAA+B,CAAC;AACpE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,sBAAsB,MAAM,+BAA+B,CAAC;AACnE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,wBAAwB,MAAM,kCAAkC,CAAC;AACxE,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,iCAAiC,MAAM,2CAA2C,CAAC;AAG1F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwOG;AACH,MAAM,CAAC,MAAM,KAAK,GAA8B;IAC9C,qBAAqB;IACrB,eAAe;IACf,qBAAqB;IACrB,gBAAgB;IAChB,gBAAgB;IAChB,aAAa;IACb,uBAAuB;IACvB,gBAAgB;IAChB,sBAAsB;IACtB,sBAAsB;IACtB,qBAAqB;IACrB,qBAAqB;IACrB,qBAAqB;IACrB,mBAAmB;IACnB,iCAAiC;IACjC,sBAAsB;IACtB,gBAAgB;IAChB,uBAAuB;IACvB,uCAAuC;IACvC,wBAAwB;CACzB,CAAC"}
|