specguard-mcp 0.1.13 → 0.1.15
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 +34 -11
- package/dist/src/tools/index.d.ts +25 -22
- package/dist/src/tools/index.js +25 -22
- package/dist/src/tools/index.js.map +1 -1
- package/dist/src/tools/list-repositories.d.ts +45 -5
- package/dist/src/tools/list-repositories.js +60 -6
- package/dist/src/tools/list-repositories.js.map +1 -1
- package/dist/src/tools/remove-repository.js +11 -5
- package/dist/src/tools/remove-repository.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -34,8 +34,8 @@ refuses to boot and takes the tools that needed no configuration down with it.
|
|
|
34
34
|
| --- | --- | --- | --- |
|
|
35
35
|
| `SPECGUARD_ENDPOINT` | `get_repository_overview`, `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 |
|
|
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
|
-
| `SPECGUARD_USER_API_KEY` | `list_repositories` (fallback), `add_repository`, `registrable_repositories`, `remove_repository
|
|
38
|
-
| `SPECGUARD_AGENT_API_KEY` | `list_repositories` (preferred), `get_repository_overview` / `near_duplicate_clusters` **with** `repository` | — | 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, `list_repositories`
|
|
37
|
+
| `SPECGUARD_USER_API_KEY` | `list_repositories` (fallback), `add_repository`, `registrable_repositories`, `remove_repository` (fallback), `create_repository_api_key`, `revoke_repository_api_key`, `list_repository_agent_keys`, `revoke_repository_agent_key`, `list_repository_agent_keys_presented_revoked`, `list_repository_members`, `add_repository_member`, `update_repository_member_permissions`, `remove_repository_member`, `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
|
+
| `SPECGUARD_AGENT_API_KEY` | `list_repositories` (preferred), `remove_repository` (preferred), `get_repository_overview` / `near_duplicate_clusters` **with** `repository` | — | 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, `list_repositories` and `remove_repository` use **this** one, so discovery stays inside the set the other tools can reach |
|
|
39
39
|
| `SPECGUARD_LINT_COMMAND` | `lint_intent_annotations` | `specguard-lint` | the command that runs the linter. Most Ruby projects need `bundle exec specguard-lint` |
|
|
40
40
|
| `SPECGUARD_TIMEOUT_MS` | HTTP tools | `30000` | how long a call to SpecGuard may take |
|
|
41
41
|
|
|
@@ -367,16 +367,35 @@ blank value is no ask: passing an empty string and omitting the argument make th
|
|
|
367
367
|
| `sort` | `"stale"` — re-order stalest-first: repositories CI has never ingested a run for first, then least-recently-ingested, with `full_name` breaking ties so two calls agree element for element. The same entries, a different order; the default order stays `full_name` ascending |
|
|
368
368
|
|
|
369
369
|
The body comes back as SpecGuard serves it — `{"repositories": […]}`, each entry carrying `id`,
|
|
370
|
-
`full_name`, `name`, `registered_at` and `
|
|
371
|
-
asks otherwise. The
|
|
372
|
-
|
|
373
|
-
|
|
370
|
+
`full_name`, `name`, `registered_at`, `role`, `delivery_health` and `latest_run`, ordered by
|
|
371
|
+
`full_name` ascending unless `sort` asks otherwise. The identity fields are deliberately the same
|
|
372
|
+
fields, under the same names, that `get_repository_overview` serves in its own `repository` block,
|
|
373
|
+
so a client that reads one reads the other.
|
|
374
|
+
|
|
375
|
+
`delivery_health` is the entry's delivery verdict — `refusing` beside `last_rejection_at` — served
|
|
376
|
+
on **every** entry, so this one call triages ingest-pipeline health across the whole reachable set
|
|
377
|
+
instead of paying one `get_repository_overview` call per repository. It is the coarse sibling of
|
|
378
|
+
the overview's fuller per-repository block. A quiet verdict is a finding, not a gap:
|
|
379
|
+
`refusing: false` means nothing was refused, never that delivery is untracked.
|
|
380
|
+
|
|
381
|
+
`latest_run` is the entry's newest run — when CI last reported, on what branch and commit, how big
|
|
382
|
+
the suite is, how much of it SpecGuard can read, and the run-level cost scalars. `null` means CI
|
|
383
|
+
has **never reported** for that repository — never a run that found an empty suite.
|
|
384
|
+
|
|
385
|
+
`role` has one value per
|
|
374
386
|
credential kind: under a **user** key (`sgu_…`) it is `owner` or `member` — the list mixes
|
|
375
387
|
repositories this person owns with repositories somebody shared with them, and nothing else tells
|
|
376
388
|
them apart — while under an **agent** key (`sga_…`) every entry is `agent`, the value that says the
|
|
377
389
|
ownership question does not apply because the key speaks for nobody (branching on owner/member
|
|
378
|
-
correctly reads false for both). Read it before assuming a repository is one you may administer.
|
|
379
|
-
|
|
390
|
+
correctly reads false for both). Read it before assuming a repository is one you may administer.
|
|
391
|
+
|
|
392
|
+
Under an **agent** key the top level also carries `credential.capabilities` — the calling key's own
|
|
393
|
+
grant, read through the server's policy, so an agent key learns what it was granted here instead of
|
|
394
|
+
discovering its permissions by hitting refusals; under a **user** key the block is absent, not
|
|
395
|
+
`null` — a person key has no mint-time permission set, and a null would assert one exists and is
|
|
396
|
+
empty.
|
|
397
|
+
|
|
398
|
+
An empty list means no access, not an error.
|
|
380
399
|
|
|
381
400
|
**It reads a different key from `get_repository_overview` — either of two, whichever is set.**
|
|
382
401
|
`SPECGUARD_AGENT_API_KEY` (`sga_…`) when it is set: the answer is then the repository set granted
|
|
@@ -543,9 +562,13 @@ Authorization is the `repo.delete` capability at **either surface** — an owner
|
|
|
543
562
|
`repo.delete`, may remove the repository. A member without it is refused `403` with SpecGuard's own
|
|
544
563
|
sentence, verbatim. The repository's CI keys stop authenticating the moment it succeeds.
|
|
545
564
|
|
|
546
|
-
It reads
|
|
547
|
-
|
|
548
|
-
|
|
565
|
+
It reads either of two credentials, whichever is set — and a different one from the `sgk_…` key
|
|
566
|
+
`get_repository_overview` uses. `SPECGUARD_AGENT_API_KEY` (`sga_…`) when it is set: the call then
|
|
567
|
+
reaches only the repositories granted onto that key at mint time, and only where the grant carries
|
|
568
|
+
`repo.delete` — a repository outside that set is answered `404` in SpecGuard's own words.
|
|
569
|
+
`SPECGUARD_USER_API_KEY` (`sgu_…`) when no agent key is set: the same **person** key `add_repository`
|
|
570
|
+
reads. With both set the **agent** key wins, so the removal answers inside the same set
|
|
571
|
+
`list_repositories` reports.
|
|
549
572
|
|
|
550
573
|
### `create_repository_api_key`
|
|
551
574
|
|
|
@@ -20,7 +20,7 @@ import type { ToolDefinition } from "./types.js";
|
|
|
20
20
|
* the two halves of the surface — one local subprocess, one authenticated HTTP
|
|
21
21
|
* call — so the shape is proven on both kinds of capability rather than on one.
|
|
22
22
|
*
|
|
23
|
-
* == The
|
|
23
|
+
* == The first tool that reads the OTHER credential
|
|
24
24
|
*
|
|
25
25
|
* - `list_repositories` wraps `GET /api/v1/repositories` (shipped:
|
|
26
26
|
* `specguard/config/routes.rb`, `Api::V1::UserRepositoriesController`).
|
|
@@ -43,15 +43,7 @@ import type { ToolDefinition } from "./types.js";
|
|
|
43
43
|
* not offering the tool, because the agent has already committed to a plan by
|
|
44
44
|
* the time it finds out.
|
|
45
45
|
*
|
|
46
|
-
*
|
|
47
|
-
* rule — no tool may wrap what has not shipped. That half retired when the
|
|
48
|
-
* platform moved: SPGD-703 (`specguard` `c43dc19`, 2026-08-28) shipped
|
|
49
|
-
* `GET /api/v1/repository?near_duplicates=`, serving
|
|
50
|
-
* `RepositoryOverview#serialized_near_duplicates` behind an opt-in ask, and
|
|
51
|
-
* `near_duplicate_clusters` below wraps it. What moved was the platform, not
|
|
52
|
-
* the bar.
|
|
53
|
-
*
|
|
54
|
-
* == The fourth: the first tool that WRITES
|
|
46
|
+
* == The first tool that WRITES
|
|
55
47
|
*
|
|
56
48
|
* - `add_repository` wraps `POST /api/v1/repositories` (shipped:
|
|
57
49
|
* `specguard/config/routes.rb`, `Api::V1::UserRepositoriesController#create`).
|
|
@@ -69,10 +61,10 @@ import type { ToolDefinition } from "./types.js";
|
|
|
69
61
|
* The standing rule is unchanged and still binding. What once kept `DELETE
|
|
70
62
|
* /api/v1/repositories/:id` and the API-key endpoints out under it — "not on
|
|
71
63
|
* `origin/main`, so they may not be wrapped" — stopped being true when SPGD-754
|
|
72
|
-
* shipped them, and the
|
|
64
|
+
* shipped them, and the removal-and-key-lifecycle section below records their
|
|
73
65
|
* wrapping. What moved was the platform, not the bar.
|
|
74
66
|
*
|
|
75
|
-
* == The
|
|
67
|
+
* == The read half of the registration gate
|
|
76
68
|
*
|
|
77
69
|
* - `registrable_repositories` wraps `GET /api/v1/repositories/registrable`
|
|
78
70
|
* (shipped: `specguard/config/routes.rb:117`,
|
|
@@ -86,14 +78,14 @@ import type { ToolDefinition } from "./types.js";
|
|
|
86
78
|
* carrying the same `{error, message}` contract — the identical defect, given
|
|
87
79
|
* the identical remedy.
|
|
88
80
|
*
|
|
89
|
-
* The
|
|
90
|
-
*
|
|
91
|
-
* unchanged and still binding,
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
81
|
+
* The registration gate was the newest user-scoped entry when it landed; the
|
|
82
|
+
* sections below record how the surface grew after it. The standing rule is
|
|
83
|
+
* unchanged and still binding, and what it keeps out today is what has not
|
|
84
|
+
* shipped — `/check-intent` has no backing endpoint (`routes.rb` mounts it as
|
|
85
|
+
* a comment only), so it stays unwrapped. What moved was the platform, not
|
|
86
|
+
* the bar.
|
|
95
87
|
*
|
|
96
|
-
* ==
|
|
88
|
+
* == Removal and the key lifecycle
|
|
97
89
|
*
|
|
98
90
|
* - `remove_repository` wraps `DELETE /api/v1/repositories/:id`, and
|
|
99
91
|
* `create_repository_api_key` / `revoke_repository_api_key` wrap the two
|
|
@@ -113,7 +105,18 @@ import type { ToolDefinition } from "./types.js";
|
|
|
113
105
|
* as a comment only). A tool advertised in `tools/list` remains a promise an
|
|
114
106
|
* agent will act on.
|
|
115
107
|
*
|
|
116
|
-
* ==
|
|
108
|
+
* == Near-duplicate clusters: the forbid that retired
|
|
109
|
+
*
|
|
110
|
+
* - `near_duplicate_clusters` wraps `GET /api/v1/repository?near_duplicates=`
|
|
111
|
+
* (shipped: SPGD-703, `specguard` `c43dc19`, 2026-08-28), serving
|
|
112
|
+
* `RepositoryOverview#serialized_near_duplicates` behind an opt-in ask.
|
|
113
|
+
*
|
|
114
|
+
* Duplicate clustering was once under the same forbid that still keeps
|
|
115
|
+
* `/check-intent` out — the standing rule: no tool may wrap what has not
|
|
116
|
+
* shipped. That half retired when the platform moved and this entry became
|
|
117
|
+
* wrappable. What moved was the platform, not the bar.
|
|
118
|
+
*
|
|
119
|
+
* == Member management
|
|
117
120
|
*
|
|
118
121
|
* - `list_repository_members`, `add_repository_member`,
|
|
119
122
|
* `update_repository_member_permissions` and `remove_repository_member`
|
|
@@ -132,7 +135,7 @@ import type { ToolDefinition } from "./types.js";
|
|
|
132
135
|
* stays scoped to the repository (a foreign id is refused 404), and there is
|
|
133
136
|
* no name-based lookup.
|
|
134
137
|
*
|
|
135
|
-
* ==
|
|
138
|
+
* == Rename
|
|
136
139
|
*
|
|
137
140
|
* - `rename_repository` wraps `PATCH /api/v1/repositories/:id` (shipped:
|
|
138
141
|
* SPGD-878, `specguard@origin/main` e026793, PR #266).
|
|
@@ -148,7 +151,7 @@ import type { ToolDefinition } from "./types.js";
|
|
|
148
151
|
* remove-and-re-register, which destroys every key, run and intent; this one
|
|
149
152
|
* keeps them.
|
|
150
153
|
*
|
|
151
|
-
* == The
|
|
154
|
+
* == The agent-key family
|
|
152
155
|
*
|
|
153
156
|
* - `list_repository_agent_keys` and `revoke_repository_agent_key` wrap the
|
|
154
157
|
* inventory and revoke of `user_repository_agent_keys` (shipped: SPGD-1004,
|
package/dist/src/tools/index.js
CHANGED
|
@@ -36,7 +36,7 @@ import updateRepositoryMemberPermissions from "./update-repository-member-permis
|
|
|
36
36
|
* the two halves of the surface — one local subprocess, one authenticated HTTP
|
|
37
37
|
* call — so the shape is proven on both kinds of capability rather than on one.
|
|
38
38
|
*
|
|
39
|
-
* == The
|
|
39
|
+
* == The first tool that reads the OTHER credential
|
|
40
40
|
*
|
|
41
41
|
* - `list_repositories` wraps `GET /api/v1/repositories` (shipped:
|
|
42
42
|
* `specguard/config/routes.rb`, `Api::V1::UserRepositoriesController`).
|
|
@@ -59,15 +59,7 @@ import updateRepositoryMemberPermissions from "./update-repository-member-permis
|
|
|
59
59
|
* not offering the tool, because the agent has already committed to a plan by
|
|
60
60
|
* the time it finds out.
|
|
61
61
|
*
|
|
62
|
-
*
|
|
63
|
-
* rule — no tool may wrap what has not shipped. That half retired when the
|
|
64
|
-
* platform moved: SPGD-703 (`specguard` `c43dc19`, 2026-08-28) shipped
|
|
65
|
-
* `GET /api/v1/repository?near_duplicates=`, serving
|
|
66
|
-
* `RepositoryOverview#serialized_near_duplicates` behind an opt-in ask, and
|
|
67
|
-
* `near_duplicate_clusters` below wraps it. What moved was the platform, not
|
|
68
|
-
* the bar.
|
|
69
|
-
*
|
|
70
|
-
* == The fourth: the first tool that WRITES
|
|
62
|
+
* == The first tool that WRITES
|
|
71
63
|
*
|
|
72
64
|
* - `add_repository` wraps `POST /api/v1/repositories` (shipped:
|
|
73
65
|
* `specguard/config/routes.rb`, `Api::V1::UserRepositoriesController#create`).
|
|
@@ -85,10 +77,10 @@ import updateRepositoryMemberPermissions from "./update-repository-member-permis
|
|
|
85
77
|
* The standing rule is unchanged and still binding. What once kept `DELETE
|
|
86
78
|
* /api/v1/repositories/:id` and the API-key endpoints out under it — "not on
|
|
87
79
|
* `origin/main`, so they may not be wrapped" — stopped being true when SPGD-754
|
|
88
|
-
* shipped them, and the
|
|
80
|
+
* shipped them, and the removal-and-key-lifecycle section below records their
|
|
89
81
|
* wrapping. What moved was the platform, not the bar.
|
|
90
82
|
*
|
|
91
|
-
* == The
|
|
83
|
+
* == The read half of the registration gate
|
|
92
84
|
*
|
|
93
85
|
* - `registrable_repositories` wraps `GET /api/v1/repositories/registrable`
|
|
94
86
|
* (shipped: `specguard/config/routes.rb:117`,
|
|
@@ -102,14 +94,14 @@ import updateRepositoryMemberPermissions from "./update-repository-member-permis
|
|
|
102
94
|
* carrying the same `{error, message}` contract — the identical defect, given
|
|
103
95
|
* the identical remedy.
|
|
104
96
|
*
|
|
105
|
-
* The
|
|
106
|
-
*
|
|
107
|
-
* unchanged and still binding,
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
97
|
+
* The registration gate was the newest user-scoped entry when it landed; the
|
|
98
|
+
* sections below record how the surface grew after it. The standing rule is
|
|
99
|
+
* unchanged and still binding, and what it keeps out today is what has not
|
|
100
|
+
* shipped — `/check-intent` has no backing endpoint (`routes.rb` mounts it as
|
|
101
|
+
* a comment only), so it stays unwrapped. What moved was the platform, not
|
|
102
|
+
* the bar.
|
|
111
103
|
*
|
|
112
|
-
* ==
|
|
104
|
+
* == Removal and the key lifecycle
|
|
113
105
|
*
|
|
114
106
|
* - `remove_repository` wraps `DELETE /api/v1/repositories/:id`, and
|
|
115
107
|
* `create_repository_api_key` / `revoke_repository_api_key` wrap the two
|
|
@@ -129,7 +121,18 @@ import updateRepositoryMemberPermissions from "./update-repository-member-permis
|
|
|
129
121
|
* as a comment only). A tool advertised in `tools/list` remains a promise an
|
|
130
122
|
* agent will act on.
|
|
131
123
|
*
|
|
132
|
-
* ==
|
|
124
|
+
* == Near-duplicate clusters: the forbid that retired
|
|
125
|
+
*
|
|
126
|
+
* - `near_duplicate_clusters` wraps `GET /api/v1/repository?near_duplicates=`
|
|
127
|
+
* (shipped: SPGD-703, `specguard` `c43dc19`, 2026-08-28), serving
|
|
128
|
+
* `RepositoryOverview#serialized_near_duplicates` behind an opt-in ask.
|
|
129
|
+
*
|
|
130
|
+
* Duplicate clustering was once under the same forbid that still keeps
|
|
131
|
+
* `/check-intent` out — the standing rule: no tool may wrap what has not
|
|
132
|
+
* shipped. That half retired when the platform moved and this entry became
|
|
133
|
+
* wrappable. What moved was the platform, not the bar.
|
|
134
|
+
*
|
|
135
|
+
* == Member management
|
|
133
136
|
*
|
|
134
137
|
* - `list_repository_members`, `add_repository_member`,
|
|
135
138
|
* `update_repository_member_permissions` and `remove_repository_member`
|
|
@@ -148,7 +151,7 @@ import updateRepositoryMemberPermissions from "./update-repository-member-permis
|
|
|
148
151
|
* stays scoped to the repository (a foreign id is refused 404), and there is
|
|
149
152
|
* no name-based lookup.
|
|
150
153
|
*
|
|
151
|
-
* ==
|
|
154
|
+
* == Rename
|
|
152
155
|
*
|
|
153
156
|
* - `rename_repository` wraps `PATCH /api/v1/repositories/:id` (shipped:
|
|
154
157
|
* SPGD-878, `specguard@origin/main` e026793, PR #266).
|
|
@@ -164,7 +167,7 @@ import updateRepositoryMemberPermissions from "./update-repository-member-permis
|
|
|
164
167
|
* remove-and-re-register, which destroys every key, run and intent; this one
|
|
165
168
|
* keeps them.
|
|
166
169
|
*
|
|
167
|
-
* == The
|
|
170
|
+
* == The agent-key family
|
|
168
171
|
*
|
|
169
172
|
* - `list_repository_agent_keys` and `revoke_repository_agent_key` wrap the
|
|
170
173
|
* inventory and revoke of `user_repository_agent_keys` (shipped: SPGD-1004,
|
|
@@ -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,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,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,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,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+KG;AACH,MAAM,CAAC,MAAM,KAAK,GAA8B;IAC9C,qBAAqB;IACrB,qBAAqB;IACrB,gBAAgB;IAChB,aAAa;IACb,uBAAuB;IACvB,gBAAgB;IAChB,sBAAsB;IACtB,sBAAsB;IACtB,qBAAqB;IACrB,qBAAqB;IACrB,mBAAmB;IACnB,iCAAiC;IACjC,sBAAsB;IACtB,gBAAgB;IAChB,uBAAuB;IACvB,uCAAuC;IACvC,wBAAwB;CACzB,CAAC"}
|
|
@@ -92,11 +92,51 @@ import type { ToolDefinition } from "./types.js";
|
|
|
92
92
|
*
|
|
93
93
|
* Same rule as every other tool here (`types.ts`: "A thin client that reshapes
|
|
94
94
|
* its upstream is not thin"), and it has real content on this body. The
|
|
95
|
-
* controller serves each entry as `id`, `full_name`, `name`, `registered_at
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
95
|
+
* controller serves each entry as `id`, `full_name`, `name`, `registered_at`,
|
|
96
|
+
* `role`, `delivery_health` and `latest_run`
|
|
97
|
+
* (`Api::V1::UserRepositoriesController#serialize`), and it says why about the
|
|
98
|
+
* identity fields: `id`, `full_name`, `name` and `registered_at` are
|
|
99
|
+
* DELIBERATELY the same fields, under the same names, that
|
|
100
|
+
* `GET /api/v1/repository` serves in its own `repository` block, so a client
|
|
101
|
+
* that has read one knows how to read the other. Renaming or flattening
|
|
102
|
+
* anything here would spend that parity on the last hop. The rest of each
|
|
103
|
+
* entry — and the block beside `repositories:` at the top level — is payload an
|
|
104
|
+
* agent must know ARRIVES: a description that omits it sends the agent to pay
|
|
105
|
+
* per-repository calls for data this one call already handed it (SPGD-1067).
|
|
106
|
+
*
|
|
107
|
+
* `delivery_health` rides EVERY entry (`#delivery_verdicts`): `{refusing,
|
|
108
|
+
* last_rejection_at}` — the staleness verdict `get_repository_overview` serves
|
|
109
|
+
* in its fuller per-repository block, spelled here as the one-call fleet
|
|
110
|
+
* triage. "Which of my repositories has a refusing ingest pipeline?" is
|
|
111
|
+
* answerable from THIS call alone, never one overview call per repository. A
|
|
112
|
+
* quiet verdict is a finding, not a gap, on the same rule the overview's
|
|
113
|
+
* description states: `refusing: false` is "nothing was refused", not
|
|
114
|
+
* "delivery is untracked".
|
|
115
|
+
*
|
|
116
|
+
* `latest_run` is the entry's newest run at the serializer's LIST depth
|
|
117
|
+
* (`LatestRunSerializer::LIST_DEPTH`): when CI last reported, on what branch
|
|
118
|
+
* and commit, how big the suite is, how much of it SpecGuard can read, and the
|
|
119
|
+
* run-level cost scalars — the drill-ins stay on the overview's full depth.
|
|
120
|
+
* `null` means CI has NEVER reported for that repository, and on this list the
|
|
121
|
+
* key is PRESENT-and-null (`#index` always passes the block;
|
|
122
|
+
* `LatestRunSerializer#body` returns nil for a nil run), the serializer's
|
|
123
|
+
* "nil, not a zeroed block" rule — a repository CI has never run must not read
|
|
124
|
+
* byte-identically to one that ran and found an empty suite. The ABSENT-key arm
|
|
125
|
+
* of that same marker belongs to `#update`'s rename receipt, not to this list.
|
|
126
|
+
*
|
|
127
|
+
* `credential` is the block that is NOT repository-scoped: under an `sga_` key
|
|
128
|
+
* the TOP level carries `credential: {capabilities}` — the calling key's own
|
|
129
|
+
* grant (SPGD-977), with every capability in `RepositoryPolicy::CAPABILITIES`
|
|
130
|
+
* ASKED of `AgentApiKeyPolicy` server-side, so the booleans cannot disagree
|
|
131
|
+
* with a 403 the same key would get (an empty permission set thereby reads
|
|
132
|
+
* affirmatively — `view` true, every further verb false, the machine
|
|
133
|
+
* counterpart of the account page's "read only" — rather than a copy of the
|
|
134
|
+
* stored permissions array, which under-states and over-states the grant at
|
|
135
|
+
* once). Its only other carrier is the minting person's browser account page,
|
|
136
|
+
* so before it a machine credential's only discovery path for its own
|
|
137
|
+
* permissions was 403 trial-and-error. Under an `sgu_` key the block is ABSENT
|
|
138
|
+
* rather than nulled — a person key has no mint-time permission set, and a null
|
|
139
|
+
* would assert one exists and is empty.
|
|
100
140
|
*
|
|
101
141
|
* `role` is the field this surface adds, and its value depends on WHICH
|
|
102
142
|
* credential answered — three values, one per credential kind, and all three
|
|
@@ -93,11 +93,51 @@ import { optionalString } from "./args.js";
|
|
|
93
93
|
*
|
|
94
94
|
* Same rule as every other tool here (`types.ts`: "A thin client that reshapes
|
|
95
95
|
* its upstream is not thin"), and it has real content on this body. The
|
|
96
|
-
* controller serves each entry as `id`, `full_name`, `name`, `registered_at
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
96
|
+
* controller serves each entry as `id`, `full_name`, `name`, `registered_at`,
|
|
97
|
+
* `role`, `delivery_health` and `latest_run`
|
|
98
|
+
* (`Api::V1::UserRepositoriesController#serialize`), and it says why about the
|
|
99
|
+
* identity fields: `id`, `full_name`, `name` and `registered_at` are
|
|
100
|
+
* DELIBERATELY the same fields, under the same names, that
|
|
101
|
+
* `GET /api/v1/repository` serves in its own `repository` block, so a client
|
|
102
|
+
* that has read one knows how to read the other. Renaming or flattening
|
|
103
|
+
* anything here would spend that parity on the last hop. The rest of each
|
|
104
|
+
* entry — and the block beside `repositories:` at the top level — is payload an
|
|
105
|
+
* agent must know ARRIVES: a description that omits it sends the agent to pay
|
|
106
|
+
* per-repository calls for data this one call already handed it (SPGD-1067).
|
|
107
|
+
*
|
|
108
|
+
* `delivery_health` rides EVERY entry (`#delivery_verdicts`): `{refusing,
|
|
109
|
+
* last_rejection_at}` — the staleness verdict `get_repository_overview` serves
|
|
110
|
+
* in its fuller per-repository block, spelled here as the one-call fleet
|
|
111
|
+
* triage. "Which of my repositories has a refusing ingest pipeline?" is
|
|
112
|
+
* answerable from THIS call alone, never one overview call per repository. A
|
|
113
|
+
* quiet verdict is a finding, not a gap, on the same rule the overview's
|
|
114
|
+
* description states: `refusing: false` is "nothing was refused", not
|
|
115
|
+
* "delivery is untracked".
|
|
116
|
+
*
|
|
117
|
+
* `latest_run` is the entry's newest run at the serializer's LIST depth
|
|
118
|
+
* (`LatestRunSerializer::LIST_DEPTH`): when CI last reported, on what branch
|
|
119
|
+
* and commit, how big the suite is, how much of it SpecGuard can read, and the
|
|
120
|
+
* run-level cost scalars — the drill-ins stay on the overview's full depth.
|
|
121
|
+
* `null` means CI has NEVER reported for that repository, and on this list the
|
|
122
|
+
* key is PRESENT-and-null (`#index` always passes the block;
|
|
123
|
+
* `LatestRunSerializer#body` returns nil for a nil run), the serializer's
|
|
124
|
+
* "nil, not a zeroed block" rule — a repository CI has never run must not read
|
|
125
|
+
* byte-identically to one that ran and found an empty suite. The ABSENT-key arm
|
|
126
|
+
* of that same marker belongs to `#update`'s rename receipt, not to this list.
|
|
127
|
+
*
|
|
128
|
+
* `credential` is the block that is NOT repository-scoped: under an `sga_` key
|
|
129
|
+
* the TOP level carries `credential: {capabilities}` — the calling key's own
|
|
130
|
+
* grant (SPGD-977), with every capability in `RepositoryPolicy::CAPABILITIES`
|
|
131
|
+
* ASKED of `AgentApiKeyPolicy` server-side, so the booleans cannot disagree
|
|
132
|
+
* with a 403 the same key would get (an empty permission set thereby reads
|
|
133
|
+
* affirmatively — `view` true, every further verb false, the machine
|
|
134
|
+
* counterpart of the account page's "read only" — rather than a copy of the
|
|
135
|
+
* stored permissions array, which under-states and over-states the grant at
|
|
136
|
+
* once). Its only other carrier is the minting person's browser account page,
|
|
137
|
+
* so before it a machine credential's only discovery path for its own
|
|
138
|
+
* permissions was 403 trial-and-error. Under an `sgu_` key the block is ABSENT
|
|
139
|
+
* rather than nulled — a person key has no mint-time permission set, and a null
|
|
140
|
+
* would assert one exists and is empty.
|
|
101
141
|
*
|
|
102
142
|
* `role` is the field this surface adds, and its value depends on WHICH
|
|
103
143
|
* credential answered — three values, one per credential kind, and all three
|
|
@@ -130,13 +170,27 @@ const listRepositories = {
|
|
|
130
170
|
"ask about\", which no other tool here can give, because every other tool is already scoped " +
|
|
131
171
|
"to one repository by its key. " +
|
|
132
172
|
"Each entry carries `id`, `full_name` (`org/repo`, and the handle every other surface names " +
|
|
133
|
-
"a repository by), `name`, `registered_at` and `
|
|
173
|
+
"a repository by), `name`, `registered_at`, `role`, `delivery_health` and `latest_run`. " +
|
|
174
|
+
"`delivery_health` is the entry's delivery verdict — `refusing` beside `last_rejection_at` — " +
|
|
175
|
+
"served on every entry, so this one call triages ingest-pipeline health across the whole " +
|
|
176
|
+
"reachable set (the coarse sibling of get_repository_overview's fuller per-repository block) " +
|
|
177
|
+
"instead of paying one overview call per repository. A quiet verdict is a finding, not a " +
|
|
178
|
+
"gap: `refusing: false` means nothing was refused, never that delivery is untracked. " +
|
|
179
|
+
"`latest_run` is the entry's newest run — when CI last reported, on what branch and commit, " +
|
|
180
|
+
"how big the suite is, how much of it SpecGuard can read, and the run-level cost scalars; " +
|
|
181
|
+
"`null` means CI has never reported for that repository, never a run that found an empty " +
|
|
182
|
+
"suite. " +
|
|
134
183
|
"`role` has one value per credential kind. Under a PERSON key (`sgu_…`) it is `owner` or " +
|
|
135
184
|
"`member`: the list mixes repositories this person owns with repositories somebody shared " +
|
|
136
185
|
"with them, and nothing else distinguishes the two. Under an AGENT key (`sga_…`) every " +
|
|
137
186
|
"entry is `agent` — the value that says the ownership question does not apply because the " +
|
|
138
187
|
"key speaks for nobody; branching on owner/member correctly reads false for both. Read it " +
|
|
139
188
|
"before assuming a repository is yours to administer. " +
|
|
189
|
+
"Under an AGENT key the top level also carries `credential.capabilities` — the calling " +
|
|
190
|
+
"key's own grant, read through the server's policy, so an agent key sees what it was " +
|
|
191
|
+
"granted here instead of discovering its permissions by hitting refusals; under a PERSON " +
|
|
192
|
+
"key the block is ABSENT, not `null`, because a person key has no mint-time permission " +
|
|
193
|
+
"set. " +
|
|
140
194
|
"Three optional asks narrow WITHIN that set — none of them can widen it — all optional, " +
|
|
141
195
|
"composable on one call: `q` (case-insensitive substring on `full_name`), " +
|
|
142
196
|
"`role: \"owned\"` or `\"shared\"` (one half of the owned/shared mix — note the ask is " +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-repositories.js","sourceRoot":"","sources":["../../../src/tools/list-repositories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AACzF,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG3C
|
|
1
|
+
{"version":3,"file":"list-repositories.js","sourceRoot":"","sources":["../../../src/tools/list-repositories.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { deleteJson,
|
|
1
|
+
import { deleteJson, requireUserOrAgentApiConfig } from "../support/specguard-api.js";
|
|
2
2
|
import { requireString } from "./args.js";
|
|
3
3
|
/**
|
|
4
4
|
* `DELETE /api/v1/repositories/:id` as a tool — shipped in the platform
|
|
@@ -44,9 +44,15 @@ const removeRepository = {
|
|
|
44
44
|
"cannot be brought back. " +
|
|
45
45
|
"Takes `repository_id` — the numeric id `add_repository` and `list_repositories` " +
|
|
46
46
|
"report, not the `org/repo` handle. " +
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
47
|
+
"It authenticates with EITHER of this server's two repository-administration credentials, " +
|
|
48
|
+
"whichever is set: SPECGUARD_AGENT_API_KEY (an sga_… key — the call then reaches only the " +
|
|
49
|
+
"repositories granted onto that key at mint time, and only where the grant carries " +
|
|
50
|
+
"`repo.delete`; a repository outside that set answers 404 in SpecGuard's own words, never " +
|
|
51
|
+
"a probe here) and, when that is not set, SPECGUARD_USER_API_KEY (an sgu_… key, the same " +
|
|
52
|
+
"credential `add_repository` writes with). With both set the agent key wins, so the " +
|
|
53
|
+
"removal answers inside the same set `list_repositories` reports. " +
|
|
54
|
+
"Either way it is a DIFFERENT credential from the sgk_… repository key " +
|
|
55
|
+
"`get_repository_overview` uses; SpecGuard refuses each in the other's place.",
|
|
50
56
|
inputSchema: {
|
|
51
57
|
type: "object",
|
|
52
58
|
properties: {
|
|
@@ -66,7 +72,7 @@ const removeRepository = {
|
|
|
66
72
|
},
|
|
67
73
|
async run(args, context) {
|
|
68
74
|
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
69
|
-
const api =
|
|
75
|
+
const api = requireUserOrAgentApiConfig(context.config);
|
|
70
76
|
const body = await deleteJson(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}`, context.fetch);
|
|
71
77
|
// 204 with no body. Nothing upstream to pass through, so the result says
|
|
72
78
|
// what the verb did — in the tool's own words, because the deployment's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remove-repository.js","sourceRoot":"","sources":["../../../src/tools/remove-repository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"remove-repository.js","sourceRoot":"","sources":["../../../src/tools/remove-repository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AACtF,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,gBAAgB,GAAmB;IACvC,IAAI,EAAE,mBAAmB;IACzB,KAAK,EAAE,mBAAmB;IAC1B,WAAW,EACT,iFAAiF;QACjF,sFAAsF;QACtF,8EAA8E;QAC9E,0DAA0D;QAC1D,mFAAmF;QACnF,sFAAsF;QACtF,uFAAuF;QACvF,kFAAkF;QAClF,0BAA0B;QAC1B,kFAAkF;QAClF,qCAAqC;QACrC,2FAA2F;QAC3F,2FAA2F;QAC3F,oFAAoF;QACpF,2FAA2F;QAC3F,0FAA0F;QAC1F,qFAAqF;QACrF,mEAAmE;QACnE,wEAAwE;QACxE,8EAA8E;IAChF,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,+EAA+E;oBAC/E,+EAA+E;oBAC/E,sEAAsE;aACzE;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,CAAC;QAC3B,qEAAqE;QACrE,0EAA0E;QAC1E,yEAAyE;QACzE,gEAAgE;QAChE,oBAAoB,EAAE,KAAK;KAC5B;IAED,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO;QACrB,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC,CAAC;QAE3E,MAAM,GAAG,GAAG,2BAA2B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAExD,MAAM,IAAI,GAAG,MAAM,UAAU,CAC3B,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,EAAE,EAC1D,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,yEAAyE;QACzE,wEAAwE;QACxE,iCAAiC;QACjC,OAAO;YACL,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,uEAAuE,CAAC,CAAC,CAAC,IAAI;YAClG,UAAU,EAAE,EAAE,aAAa,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE;SAC3D,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specguard-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "MCP server exposing SpecGuard suite intelligence to AI coding agents",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"type": "module",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"scripts": {
|
|
20
20
|
"build": "tsc --project tsconfig.build.json",
|
|
21
21
|
"typecheck": "tsc --noEmit",
|
|
22
|
-
"pretest": "tsc --project tsconfig.test.json",
|
|
22
|
+
"pretest": "rm -rf .test-build && tsc --project tsconfig.test.json",
|
|
23
23
|
"test": "files=$(find .test-build/test -name '*.test.js'); [ -n \"$files\" ] || { echo 'specguard-mcp: no compiled test files found — did pretest run?'; exit 1; }; node --test $files",
|
|
24
24
|
"prepare": "npm run build"
|
|
25
25
|
},
|