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 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`, `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), `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` uses **this** one, so discovery stays inside the set the other tools can reach |
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 `role`, ordered by `full_name` ascending unless `sort`
371
- asks otherwise. The first four are
372
- deliberately the same four fields, under the same names, that `get_repository_overview` serves in its
373
- own `repository` block, so a client that reads one reads the other. `role` has one value per
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. An
379
- empty list means no access, not an error.
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 `SPECGUARD_USER_API_KEY` (`sgu_…`)the same **person** key `add_repository` reads, and
547
- a different one from the `sgk_…` key `get_repository_overview` uses; `list_repositories` also
548
- accepts that key but does not require it (its agent key wins when both are set).
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 third: the first tool that reads the OTHER credential
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
- * Duplicate clustering was once under this same forbid, on the same standing
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 sixth-through-eighth section below records their
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 fifth: the read half of the registration gate
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 user-scoped surface as it now stands is therefore three tools: read the
90
- * list, read the gate's answer, write a registration. The standing rule is
91
- * unchanged and still binding, which is what keeps the rest out:
92
- * `DELETE /api/v1/repositories/:id` and the API-key endpoints (SPGD-754) are
93
- * NOT on `origin/main`, so they may not be wrapped here however useful a tool
94
- * for them would be. What moved was the platform, not the bar.
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
- * == The sixth through eighth: removal and the key lifecycle
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
- * == The ninth through twelfth: member management
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
- * == The thirteenth: rename
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 fourteenth through sixteenth: the agent-key family
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,
@@ -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 third: the first tool that reads the OTHER credential
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
- * Duplicate clustering was once under this same forbid, on the same standing
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 sixth-through-eighth section below records their
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 fifth: the read half of the registration gate
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 user-scoped surface as it now stands is therefore three tools: read the
106
- * list, read the gate's answer, write a registration. The standing rule is
107
- * unchanged and still binding, which is what keeps the rest out:
108
- * `DELETE /api/v1/repositories/:id` and the API-key endpoints (SPGD-754) are
109
- * NOT on `origin/main`, so they may not be wrapped here however useful a tool
110
- * for them would be. What moved was the platform, not the bar.
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
- * == The sixth through eighth: removal and the key lifecycle
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
- * == The ninth through twelfth: member management
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
- * == The thirteenth: rename
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 fourteenth through sixteenth: the agent-key family
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4KG;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"}
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
- * and `role`, and says why: the first four are DELIBERATELY the same four
97
- * fields, under the same names, that `GET /api/v1/repository` serves in its own
98
- * `repository` block, so a client that has read one knows how to read the other.
99
- * Renaming or flattening anything here would spend that parity on the last hop.
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
- * and `role`, and says why: the first four are DELIBERATELY the same four
98
- * fields, under the same names, that `GET /api/v1/repository` serves in its own
99
- * `repository` block, so a client that has read one knows how to read the other.
100
- * Renaming or flattening anything here would spend that parity on the last hop.
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 `role`. " +
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":"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"}
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, requireUserApiConfig } from "../support/specguard-api.js";
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
- "Needs SPECGUARD_USER_API_KEY (an sgu_… key), the same credential `add_repository` " +
48
- "writes with and a DIFFERENT one from the sgk_… repository key " +
49
- "`get_repository_overview` uses.",
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 = requireUserApiConfig(context.config);
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,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAC/E,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,oFAAoF;QACpF,gEAAgE;QAChE,iCAAiC;IACnC,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,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,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"}
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.13",
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
  },