specguard-mcp 0.1.10 → 0.1.11

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,7 +34,7 @@ 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` | — | an agent/CI API key (`sgk_…`) issued by that deployment |
37
- | `SPECGUARD_USER_API_KEY` | `list_repositories`, `add_repository`, `registrable_repositories`, `remove_repository`, `create_repository_api_key`, `revoke_repository_api_key`, `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 |
37
+ | `SPECGUARD_USER_API_KEY` | `list_repositories`, `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
38
  | `SPECGUARD_LINT_COMMAND` | `lint_intent_annotations` | `specguard-lint` | the command that runs the linter. Most Ruby projects need `bundle exec specguard-lint` |
39
39
  | `SPECGUARD_TIMEOUT_MS` | HTTP tools | `30000` | how long a call to SpecGuard may take |
40
40
 
@@ -539,6 +539,81 @@ means the key is revoked.
539
539
  It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
540
540
  `add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
541
541
 
542
+ ### `list_repository_agent_keys`
543
+
544
+ Lists the agent keys (`sga_…` keys) covering a SpecGuard repository — the keys minted for people
545
+ or automation principals from the /account page, each covering one or more repositories. One row
546
+ per live key: `id`, `name`, `owner`, `token_hint`, `repository_count` (how many repositories the
547
+ key's grant covers — the blast radius), `permissions` and `created_at`.
548
+
549
+ | argument | |
550
+ | --- | --- |
551
+ | `repository_id` | the repository whose agent keys to list — its numeric `id`, as `add_repository` returns and `list_repositories` reports, not the `org/repo` handle |
552
+
553
+ **The `id` here is the only way to name an agent key on this bridge.** Agent keys have no mint
554
+ tool — the platform mints them web-only at /account, deliberately — so unlike `sgk_` keys there is
555
+ no create response to read an id from. List first, then `revoke_repository_agent_key`. Revoked keys
556
+ leave this listing (a retained revoked row is not a credential); whether a dead token is still
557
+ arriving is `list_repository_agent_keys_presented_revoked`'s question.
558
+
559
+ `token_hint` is a hint, never the token — the plaintext existed for exactly one response at mint
560
+ time and nothing persisted it. Authorization is the `keys_manage` capability; a caller without it
561
+ is refused `403` with SpecGuard's own sentence, verbatim.
562
+
563
+ It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
564
+ `add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
565
+
566
+ ### `revoke_repository_agent_key`
567
+
568
+ Revokes one agent key (`sga_…`) on a SpecGuard repository. **Irreversible, and the blast radius is
569
+ the key's whole stored set:** an agent key's grant (repository set + permission set) is stored once
570
+ at mint time, so this one call cuts the token on EVERY repository the key covers, not just
571
+ `repository_id`. Check `repository_count` on `list_repository_agent_keys` before cutting a
572
+ multi-repository key.
573
+
574
+ | argument | |
575
+ | --- | --- |
576
+ | `repository_id` | the repository whose key-administration scope the call is made under — its numeric `id`, as `add_repository` returns and `list_repositories` reports, not the `org/repo` handle. The cut itself lands on every repository in the key's stored set |
577
+ | `key_id` | the id of the agent key to revoke, as served by `list_repository_agent_keys` — the only id source, because agent keys have no mint tool on this bridge |
578
+
579
+ This endpoint answers **`200` with the disclosure body**, not the empty `204` the sgk_ sibling
580
+ `revoke_repository_api_key` serves: an `agent_key` block carrying `revoked_at`, `repository_count`
581
+ and the still-existing `repositories` names (plus `deleted_repository_count` when repositories
582
+ have been deleted since mint) — the API's substitute for the web confirm dialog, so the body
583
+ itself is the confirmation.
584
+
585
+ The `key_id` is scoped to `repository_id`: a key whose stored set does not cover this repository,
586
+ or one already revoked, is refused `404`, never a cross-repository cut. Authorization is the
587
+ `keys_manage` capability; a caller without it is refused `403` with SpecGuard's own sentence,
588
+ verbatim.
589
+
590
+ It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
591
+ `add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
592
+
593
+ ### `list_repository_agent_keys_presented_revoked`
594
+
595
+ Lists REVOKED agent keys whose token is still arriving at the deployment after revocation — the
596
+ verify half of offboarding. Run it after `revoke_repository_agent_key` to learn whether the dead
597
+ token is still being presented somewhere: each row carries `id`, `name`, `owner`, `token_hint`
598
+ (hunt this in whatever secret stores may still hold the dead token, and update them),
599
+ `repository_count`, `revoked_at` and `last_refused_at`.
600
+
601
+ | argument | |
602
+ | --- | --- |
603
+ | `repository_id` | the repository to triage — its numeric `id`, as `add_repository` returns and `list_repositories` reports, not the `org/repo` handle |
604
+
605
+ Two readings, stated plainly: **`last_refused_at` is the last observed presentation** — a recency,
606
+ never a claim that something is presenting the token right now. And **an empty
607
+ `{"agent_keys": []}` is an answer** — nothing is still arriving — not an absence of tracking; read
608
+ it as the offboarding having fully taken.
609
+
610
+ `token_hint` is a hint, never the token — the plaintext existed for exactly one response at mint
611
+ time and nothing persisted it. Authorization is the `keys_manage` capability; a caller without it
612
+ is refused `403` with SpecGuard's own sentence, verbatim.
613
+
614
+ It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
615
+ `add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
616
+
542
617
  ### `list_repository_members`
543
618
 
544
619
  Lists who has access to a SpecGuard repository: one row per member with their `id` (the
@@ -54,6 +54,23 @@ export declare function patchJson(api: ApiConfig, path: string, body: Record<str
54
54
  * verbatim: only what happens to a SUCCESS body differs.
55
55
  */
56
56
  export declare function deleteJson(api: ApiConfig, path: string, fetchImpl: typeof globalThis.fetch): Promise<string>;
57
+ /**
58
+ * `DELETE` that answers with a JSON body — the destructive verb's one non-empty
59
+ * answer, routed through `requestJson` rather than `deleteJson`'s raw-body
60
+ * handling.
61
+ *
62
+ * Every DELETE this surface served until now answered `204` with NO body — the
63
+ * reason `deleteJson` exists and returns raw text. The agent-key revoke
64
+ * (`DELETE /api/v1/repositories/:repository_id/agent_keys/:id`) answers `200`
65
+ * WITH a JSON disclosure body: the platform's substitute for the confirm dialog
66
+ * the web face shows, naming the full stored set the cut just landed on. The
67
+ * body is the point of the response, so this verb parses it — and re-deriving
68
+ * the status check and the not-JSON diagnosis here would be a third copy of the
69
+ * one check `requestJson` owns, which is exactly the argument `patchJson`'s
70
+ * header makes for its own 200-with-body case. `deleteJson` stays exported and
71
+ * byte-unchanged for the endpoints that legitimately answer empty.
72
+ */
73
+ export declare function deleteJsonObject(api: ApiConfig, path: string, fetchImpl: typeof globalThis.fetch): Promise<Record<string, unknown>>;
57
74
  /**
58
75
  * `postJson`, narrowed exactly as `getJsonObject` narrows `getJson`.
59
76
  *
@@ -77,6 +77,25 @@ export async function deleteJson(api, path, fetchImpl) {
77
77
  throw describeFailure(response.status, body, api);
78
78
  return body;
79
79
  }
80
+ /**
81
+ * `DELETE` that answers with a JSON body — the destructive verb's one non-empty
82
+ * answer, routed through `requestJson` rather than `deleteJson`'s raw-body
83
+ * handling.
84
+ *
85
+ * Every DELETE this surface served until now answered `204` with NO body — the
86
+ * reason `deleteJson` exists and returns raw text. The agent-key revoke
87
+ * (`DELETE /api/v1/repositories/:repository_id/agent_keys/:id`) answers `200`
88
+ * WITH a JSON disclosure body: the platform's substitute for the confirm dialog
89
+ * the web face shows, naming the full stored set the cut just landed on. The
90
+ * body is the point of the response, so this verb parses it — and re-deriving
91
+ * the status check and the not-JSON diagnosis here would be a third copy of the
92
+ * one check `requestJson` owns, which is exactly the argument `patchJson`'s
93
+ * header makes for its own 200-with-body case. `deleteJson` stays exported and
94
+ * byte-unchanged for the endpoints that legitimately answer empty.
95
+ */
96
+ export async function deleteJsonObject(api, path, fetchImpl) {
97
+ return asJsonObject(await requestJson(new URL(`${api.endpoint}${path}`), api, fetchImpl, { method: "DELETE" }));
98
+ }
80
99
  /**
81
100
  * `postJson`, narrowed exactly as `getJsonObject` narrows `getJson`.
82
101
  *
@@ -1 +1 @@
1
- {"version":3,"file":"specguard-api.js","sourceRoot":"","sources":["../../../src/support/specguard-api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"specguard-api.js","sourceRoot":"","sources":["../../../src/support/specguard-api.ts"],"names":[],"mappings":"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"}
@@ -146,6 +146,30 @@ import type { ToolDefinition } from "./types.js";
146
146
  * may not rename it. Before this tool the bridge's only rename path was
147
147
  * remove-and-re-register, which destroys every key, run and intent; this one
148
148
  * keeps them.
149
+ *
150
+ * == The fourteenth through sixteenth: the agent-key family
151
+ *
152
+ * - `list_repository_agent_keys` and `revoke_repository_agent_key` wrap the
153
+ * inventory and revoke of `user_repository_agent_keys` (shipped: SPGD-1004,
154
+ * specguard `dfb9892`), and `list_repository_agent_keys_presented_revoked`
155
+ * wraps the still-presented triage over the same controller (shipped:
156
+ * SPGD-1023, specguard `533e77b`).
157
+ *
158
+ * The `sga_` noun's first bridge tools, and the gap they close is the one the
159
+ * platform controller's own header records: a `keys.manage` holder could
160
+ * already mint and revoke `sgk_` keys through this bridge but could not even
161
+ * LIST the agent keys covering a repository, so the offboarding arc — a
162
+ * departed member's agent key authenticating indefinitely — was not
163
+ * completable over the bridge at all. The family also forced the transport's
164
+ * third DELETE shape: this revoke answers `200` WITH a JSON disclosure body
165
+ * (the API's substitute for the web confirm dialog — the response that
166
+ * performs the cut also names every repository it landed on), so it routes
167
+ * through `deleteJsonObject` — `requestJson`'s parse — rather than
168
+ * `deleteJson`'s raw-body handling, which the empty-204 endpoints keep
169
+ * unchanged. And the id the revoke needs is learnable ONLY from the listing:
170
+ * minting is deliberately web-only at /account, so unlike the `sgk_` pair
171
+ * there is no create response to read an id from — the list and revoke
172
+ * descriptions say so rather than leaving it implicit.
149
173
  */
150
174
  export declare const TOOLS: readonly ToolDefinition[];
151
175
  export type { ToolContext, ToolDefinition, ToolResult } from "./types.js";
@@ -3,6 +3,8 @@ import addRepositoryMember from "./add-repository-member.js";
3
3
  import createRepositoryApiKey from "./create-repository-api-key.js";
4
4
  import lintIntentAnnotations from "./lint-intent-annotations.js";
5
5
  import listRepositories from "./list-repositories.js";
6
+ import listRepositoryAgentKeys from "./list-repository-agent-keys.js";
7
+ import listRepositoryAgentKeysPresentedRevoked from "./list-repository-agent-keys-presented-revoked.js";
6
8
  import listRepositoryMembers from "./list-repository-members.js";
7
9
  import nearDuplicateClusters from "./near-duplicate-clusters.js";
8
10
  import getRepositoryOverview from "./repository-overview.js";
@@ -10,6 +12,7 @@ import registrableRepositories from "./registrable-repositories.js";
10
12
  import removeRepository from "./remove-repository.js";
11
13
  import removeRepositoryMember from "./remove-repository-member.js";
12
14
  import renameRepository from "./rename-repository.js";
15
+ import revokeRepositoryAgentKey from "./revoke-repository-agent-key.js";
13
16
  import revokeRepositoryApiKey from "./revoke-repository-api-key.js";
14
17
  import updateRepositoryMemberPermissions from "./update-repository-member-permissions.js";
15
18
  /**
@@ -159,6 +162,30 @@ import updateRepositoryMemberPermissions from "./update-repository-member-permis
159
162
  * may not rename it. Before this tool the bridge's only rename path was
160
163
  * remove-and-re-register, which destroys every key, run and intent; this one
161
164
  * keeps them.
165
+ *
166
+ * == The fourteenth through sixteenth: the agent-key family
167
+ *
168
+ * - `list_repository_agent_keys` and `revoke_repository_agent_key` wrap the
169
+ * inventory and revoke of `user_repository_agent_keys` (shipped: SPGD-1004,
170
+ * specguard `dfb9892`), and `list_repository_agent_keys_presented_revoked`
171
+ * wraps the still-presented triage over the same controller (shipped:
172
+ * SPGD-1023, specguard `533e77b`).
173
+ *
174
+ * The `sga_` noun's first bridge tools, and the gap they close is the one the
175
+ * platform controller's own header records: a `keys.manage` holder could
176
+ * already mint and revoke `sgk_` keys through this bridge but could not even
177
+ * LIST the agent keys covering a repository, so the offboarding arc — a
178
+ * departed member's agent key authenticating indefinitely — was not
179
+ * completable over the bridge at all. The family also forced the transport's
180
+ * third DELETE shape: this revoke answers `200` WITH a JSON disclosure body
181
+ * (the API's substitute for the web confirm dialog — the response that
182
+ * performs the cut also names every repository it landed on), so it routes
183
+ * through `deleteJsonObject` — `requestJson`'s parse — rather than
184
+ * `deleteJson`'s raw-body handling, which the empty-204 endpoints keep
185
+ * unchanged. And the id the revoke needs is learnable ONLY from the listing:
186
+ * minting is deliberately web-only at /account, so unlike the `sgk_` pair
187
+ * there is no create response to read an id from — the list and revoke
188
+ * descriptions say so rather than leaving it implicit.
162
189
  */
163
190
  export const TOOLS = [
164
191
  lintIntentAnnotations,
@@ -175,5 +202,8 @@ export const TOOLS = [
175
202
  updateRepositoryMemberPermissions,
176
203
  removeRepositoryMember,
177
204
  renameRepository,
205
+ listRepositoryAgentKeys,
206
+ listRepositoryAgentKeysPresentedRevoked,
207
+ revokeRepositoryAgentKey,
178
208
  ];
179
209
  //# sourceMappingURL=index.js.map
@@ -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,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,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,iCAAiC,MAAM,2CAA2C,CAAC;AAG1F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmJG;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;CACjB,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2KG;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"}
@@ -0,0 +1,39 @@
1
+ import type { ToolDefinition } from "./types.js";
2
+ /**
3
+ * `GET /api/v1/repositories/:repository_id/agent_keys/presented_revoked` as a
4
+ * tool — shipped in the platform (`specguard/config/routes.rb`,
5
+ * `Api::V1::UserRepositoryAgentKeysController#presented_revoked`, SPGD-1023,
6
+ * `533e77b`).
7
+ *
8
+ * == The verify half of the offboarding arc
9
+ *
10
+ * The listing and the revoke answer "what is live" and "cut this one"; neither
11
+ * can answer the question a revoker is left holding — "is the dead token still
12
+ * arriving?" — because both read LIVE rows only. The stamp this triage serves,
13
+ * `last_refused_at`, is written by the 401 failure path on RETAINED revoked
14
+ * rows, so it cannot ride a live row at all. This read is the bridge's only
15
+ * window onto it, behind the same `keys_manage` gate the other two actions
16
+ * answer to.
17
+ *
18
+ * == Two honesty clauses the description carries verbatim
19
+ *
20
+ * `last_refused_at` is the LAST observed presentation — a recency, never a
21
+ * present-tense claim that a client is presenting the token now. And an empty
22
+ * `{"agent_keys": []}` is an ANSWER — "no revoked key is still being
23
+ * presented" — not an absence of tracking; the endpoint serves the negative
24
+ * deliberately so the two are distinguishable. A tool that summarised an
25
+ * empty answer into a count of its own would erase exactly that distinction,
26
+ * which is why this one passes the body through.
27
+ *
28
+ * == Rows, pass-through
29
+ *
30
+ * One row per still-presented revoked key covering this repository: `id`,
31
+ * `name`, `owner`, `token_hint`, `repository_count` (the STORED set's size —
32
+ * the same blast-radius figure the revoke response discloses), `revoked_at`
33
+ * and `last_refused_at`. `token_hint` is what the remedy hunts for in the
34
+ * secret store — update whichever of them still holds the dead token — and it
35
+ * is never the token: the plaintext existed for exactly one response at mint
36
+ * time and nothing persisted it.
37
+ */
38
+ declare const listRepositoryAgentKeysPresentedRevoked: ToolDefinition;
39
+ export default listRepositoryAgentKeysPresentedRevoked;
@@ -0,0 +1,89 @@
1
+ import { getJsonObject, requireUserApiConfig } from "../support/specguard-api.js";
2
+ import { requireString } from "./args.js";
3
+ /**
4
+ * `GET /api/v1/repositories/:repository_id/agent_keys/presented_revoked` as a
5
+ * tool — shipped in the platform (`specguard/config/routes.rb`,
6
+ * `Api::V1::UserRepositoryAgentKeysController#presented_revoked`, SPGD-1023,
7
+ * `533e77b`).
8
+ *
9
+ * == The verify half of the offboarding arc
10
+ *
11
+ * The listing and the revoke answer "what is live" and "cut this one"; neither
12
+ * can answer the question a revoker is left holding — "is the dead token still
13
+ * arriving?" — because both read LIVE rows only. The stamp this triage serves,
14
+ * `last_refused_at`, is written by the 401 failure path on RETAINED revoked
15
+ * rows, so it cannot ride a live row at all. This read is the bridge's only
16
+ * window onto it, behind the same `keys_manage` gate the other two actions
17
+ * answer to.
18
+ *
19
+ * == Two honesty clauses the description carries verbatim
20
+ *
21
+ * `last_refused_at` is the LAST observed presentation — a recency, never a
22
+ * present-tense claim that a client is presenting the token now. And an empty
23
+ * `{"agent_keys": []}` is an ANSWER — "no revoked key is still being
24
+ * presented" — not an absence of tracking; the endpoint serves the negative
25
+ * deliberately so the two are distinguishable. A tool that summarised an
26
+ * empty answer into a count of its own would erase exactly that distinction,
27
+ * which is why this one passes the body through.
28
+ *
29
+ * == Rows, pass-through
30
+ *
31
+ * One row per still-presented revoked key covering this repository: `id`,
32
+ * `name`, `owner`, `token_hint`, `repository_count` (the STORED set's size —
33
+ * the same blast-radius figure the revoke response discloses), `revoked_at`
34
+ * and `last_refused_at`. `token_hint` is what the remedy hunts for in the
35
+ * secret store — update whichever of them still holds the dead token — and it
36
+ * is never the token: the plaintext existed for exactly one response at mint
37
+ * time and nothing persisted it.
38
+ */
39
+ const listRepositoryAgentKeysPresentedRevoked = {
40
+ name: "list_repository_agent_keys_presented_revoked",
41
+ title: "List still-presented revoked agent keys",
42
+ description: "Lists REVOKED agent keys whose token is still arriving at the deployment after revocation — " +
43
+ "the verify half of offboarding: run it after `revoke_repository_agent_key` to learn whether " +
44
+ "the dead token is still being presented somewhere. Each row carries `id`, `name`, `owner`, " +
45
+ "`token_hint` (hunt THIS in whatever secret stores may still hold the dead token, and update " +
46
+ "them), `repository_count`, `revoked_at` and `last_refused_at`. " +
47
+ "`last_refused_at` is the LAST observed presentation — a recency, never a present-tense claim " +
48
+ "that something is presenting the token right now. " +
49
+ "An empty `{\"agent_keys\": []}` is an ANSWER — nothing is still arriving — not an absence of " +
50
+ "tracking; read it as the offboarding having fully taken. " +
51
+ "`token_hint` is a hint, never the token — the plaintext existed for exactly one response at " +
52
+ "mint time and nothing persisted it. " +
53
+ "Authorization is the `keys_manage` capability — a caller without it is refused 403 in " +
54
+ "SpecGuard's own words. " +
55
+ "Takes `repository_id` (the numeric id `list_repositories` reports, not the `org/repo` handle). " +
56
+ "Needs SPECGUARD_USER_API_KEY (an sgu_… key), the same credential the other key-administration " +
57
+ "tools read and a DIFFERENT one from the sgk_… repository key `get_repository_overview` uses.",
58
+ inputSchema: {
59
+ type: "object",
60
+ properties: {
61
+ repository_id: {
62
+ type: "string",
63
+ description: "The repository to triage — its numeric id, as `add_repository` returns and " +
64
+ "`list_repositories` reports, not the `org/repo` handle.",
65
+ },
66
+ },
67
+ required: ["repository_id"],
68
+ // Closed for the reason every tool here states: `server.ts` forwards
69
+ // `arguments` unvalidated, so an open schema would let a misspelled argument
70
+ // be dropped silently.
71
+ additionalProperties: false,
72
+ },
73
+ async run(args, context) {
74
+ const repositoryId = requireString(args["repository_id"], "repository_id");
75
+ const api = requireUserApiConfig(context.config);
76
+ const body = await getJsonObject(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/agent_keys/presented_revoked`, {}, context.fetch);
77
+ // Passed through unreshaped, the standing rule (`types.ts`: "A thin client
78
+ // that reshapes its upstream is not thin") — and the empty answer passes
79
+ // through with it: `{"agent_keys": []}` is the endpoint saying "nothing is
80
+ // still arriving", and a summary of it would erase the distinction between
81
+ // that answer and an absence of tracking.
82
+ return {
83
+ text: JSON.stringify(body, null, 2),
84
+ structured: body,
85
+ };
86
+ },
87
+ };
88
+ export default listRepositoryAgentKeysPresentedRevoked;
89
+ //# sourceMappingURL=list-repository-agent-keys-presented-revoked.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-repository-agent-keys-presented-revoked.js","sourceRoot":"","sources":["../../../src/tools/list-repository-agent-keys-presented-revoked.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,uCAAuC,GAAmB;IAC9D,IAAI,EAAE,8CAA8C;IACpD,KAAK,EAAE,yCAAyC;IAChD,WAAW,EACT,8FAA8F;QAC9F,8FAA8F;QAC9F,6FAA6F;QAC7F,8FAA8F;QAC9F,iEAAiE;QACjE,+FAA+F;QAC/F,oDAAoD;QACpD,+FAA+F;QAC/F,2DAA2D;QAC3D,8FAA8F;QAC9F,sCAAsC;QACtC,wFAAwF;QACxF,yBAAyB;QACzB,iGAAiG;QACjG,gGAAgG;QAChG,8FAA8F;IAChG,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,6EAA6E;oBAC7E,yDAAyD;aAC5D;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,CAAC;QAC3B,qEAAqE;QACrE,6EAA6E;QAC7E,uBAAuB;QACvB,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,aAAa,CAC9B,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,+BAA+B,EACvF,EAAE,EACF,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,2EAA2E;QAC3E,yEAAyE;QACzE,2EAA2E;QAC3E,2EAA2E;QAC3E,0CAA0C;QAC1C,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACnC,UAAU,EAAE,IAAI;SACjB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,uCAAuC,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { ToolDefinition } from "./types.js";
2
+ /**
3
+ * `GET /api/v1/repositories/:repository_id/agent_keys` as a tool — shipped in
4
+ * the platform (`specguard/config/routes.rb`,
5
+ * `Api::V1::UserRepositoryAgentKeysController#index`, SPGD-1004, `dfb9892`).
6
+ *
7
+ * == The id source is THIS listing, and only this listing
8
+ *
9
+ * Agent keys have no mint tool on this bridge — deliberately: the platform
10
+ * mints them web-only at /account (the controller header states the rule), so
11
+ * unlike `sgk_` keys there is no create response to read an id from. The `id`
12
+ * each row serves is therefore the ONLY way an agent can name an agent key to
13
+ * `revoke_repository_agent_key`, and the description says so rather than
14
+ * leaving it implicit — an agent that arrives needing to cut a key without
15
+ * having listed first has no fallback path.
16
+ *
17
+ * == Rows, pass-through
18
+ *
19
+ * The endpoint answers `{agent_keys: [...]}`, one row per LIVE key covering
20
+ * this repository: `id`, `name`, `owner`, `token_hint`, `repository_count`
21
+ * (the size of the key's stored set — the blast radius a revoke would land
22
+ * on), `permissions` (rendered the way the web panel renders it, "read only"
23
+ * for the minimal grant) and `created_at`. `token_hint` is a hint and never
24
+ * the token: the plaintext existed for exactly one response at mint time and
25
+ * nothing persisted it. Revoked rows leave the listing — a retained revoked
26
+ * row is not a credential — and the still-presented triage over those rows is
27
+ * `list_repository_agent_keys_presented_revoked`.
28
+ *
29
+ * == No client-side capability probing
30
+ *
31
+ * The server gates at `current_repository(:keys_manage)`, the same gate the
32
+ * `sgk_` key pair answers to: a caller who cannot administer this
33
+ * repository's keys is refused 403 in SpecGuard's own words, and a caller who
34
+ * cannot see the repository at all gets the nil-is-404 fork. This tool
35
+ * predicts neither; it reports what came back.
36
+ */
37
+ declare const listRepositoryAgentKeys: ToolDefinition;
38
+ export default listRepositoryAgentKeys;
@@ -0,0 +1,86 @@
1
+ import { getJsonObject, requireUserApiConfig } from "../support/specguard-api.js";
2
+ import { requireString } from "./args.js";
3
+ /**
4
+ * `GET /api/v1/repositories/:repository_id/agent_keys` as a tool — shipped in
5
+ * the platform (`specguard/config/routes.rb`,
6
+ * `Api::V1::UserRepositoryAgentKeysController#index`, SPGD-1004, `dfb9892`).
7
+ *
8
+ * == The id source is THIS listing, and only this listing
9
+ *
10
+ * Agent keys have no mint tool on this bridge — deliberately: the platform
11
+ * mints them web-only at /account (the controller header states the rule), so
12
+ * unlike `sgk_` keys there is no create response to read an id from. The `id`
13
+ * each row serves is therefore the ONLY way an agent can name an agent key to
14
+ * `revoke_repository_agent_key`, and the description says so rather than
15
+ * leaving it implicit — an agent that arrives needing to cut a key without
16
+ * having listed first has no fallback path.
17
+ *
18
+ * == Rows, pass-through
19
+ *
20
+ * The endpoint answers `{agent_keys: [...]}`, one row per LIVE key covering
21
+ * this repository: `id`, `name`, `owner`, `token_hint`, `repository_count`
22
+ * (the size of the key's stored set — the blast radius a revoke would land
23
+ * on), `permissions` (rendered the way the web panel renders it, "read only"
24
+ * for the minimal grant) and `created_at`. `token_hint` is a hint and never
25
+ * the token: the plaintext existed for exactly one response at mint time and
26
+ * nothing persisted it. Revoked rows leave the listing — a retained revoked
27
+ * row is not a credential — and the still-presented triage over those rows is
28
+ * `list_repository_agent_keys_presented_revoked`.
29
+ *
30
+ * == No client-side capability probing
31
+ *
32
+ * The server gates at `current_repository(:keys_manage)`, the same gate the
33
+ * `sgk_` key pair answers to: a caller who cannot administer this
34
+ * repository's keys is refused 403 in SpecGuard's own words, and a caller who
35
+ * cannot see the repository at all gets the nil-is-404 fork. This tool
36
+ * predicts neither; it reports what came back.
37
+ */
38
+ const listRepositoryAgentKeys = {
39
+ name: "list_repository_agent_keys",
40
+ title: "List repository agent keys",
41
+ description: "Lists the agent keys (`sga_…` keys) covering a SpecGuard repository: one row per live key " +
42
+ "with its `id`, `name`, `owner`, `token_hint`, `repository_count` (how many repositories the " +
43
+ "key's grant covers — the blast radius), `permissions` and `created_at`. " +
44
+ "Agent keys have NO mint tool on this bridge — minting is deliberately web-only — so the `id` " +
45
+ "this listing serves is the ONLY way to name a key to `revoke_repository_agent_key`: list " +
46
+ "first, then revoke. " +
47
+ "Revoked keys leave this listing (a retained revoked row is not a credential); whether a dead " +
48
+ "token is still arriving is `list_repository_agent_keys_presented_revoked`'s question. " +
49
+ "`token_hint` is a hint, never the token — the plaintext existed for exactly one response at " +
50
+ "mint time and nothing persisted it. " +
51
+ "Authorization is the `keys_manage` capability — a caller without it is refused 403 in " +
52
+ "SpecGuard's own words. " +
53
+ "Takes `repository_id` (the numeric id `list_repositories` reports, not the `org/repo` handle). " +
54
+ "Needs SPECGUARD_USER_API_KEY (an sgu_… key), the same credential the other key-administration " +
55
+ "tools read and a DIFFERENT one from the sgk_… repository key `get_repository_overview` uses.",
56
+ inputSchema: {
57
+ type: "object",
58
+ properties: {
59
+ repository_id: {
60
+ type: "string",
61
+ description: "The repository whose agent keys to list — its numeric id, as `add_repository` " +
62
+ "returns and `list_repositories` reports, not the `org/repo` handle.",
63
+ },
64
+ },
65
+ required: ["repository_id"],
66
+ // Closed for the reason every tool here states: `server.ts` forwards
67
+ // `arguments` unvalidated, so an open schema would let a misspelled argument
68
+ // be dropped silently.
69
+ additionalProperties: false,
70
+ },
71
+ async run(args, context) {
72
+ const repositoryId = requireString(args["repository_id"], "repository_id");
73
+ const api = requireUserApiConfig(context.config);
74
+ const body = await getJsonObject(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/agent_keys`, {}, context.fetch);
75
+ // Passed through unreshaped, the standing rule (`types.ts`: "A thin client
76
+ // that reshapes its upstream is not thin") — the rows are the controller's
77
+ // own serialization, and the `id` an agent needs for the revoke is one of
78
+ // the fields a reshape could drop.
79
+ return {
80
+ text: JSON.stringify(body, null, 2),
81
+ structured: body,
82
+ };
83
+ },
84
+ };
85
+ export default listRepositoryAgentKeys;
86
+ //# sourceMappingURL=list-repository-agent-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-repository-agent-keys.js","sourceRoot":"","sources":["../../../src/tools/list-repository-agent-keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,uBAAuB,GAAmB;IAC9C,IAAI,EAAE,4BAA4B;IAClC,KAAK,EAAE,4BAA4B;IACnC,WAAW,EACT,4FAA4F;QAC5F,8FAA8F;QAC9F,0EAA0E;QAC1E,+FAA+F;QAC/F,2FAA2F;QAC3F,sBAAsB;QACtB,+FAA+F;QAC/F,wFAAwF;QACxF,8FAA8F;QAC9F,sCAAsC;QACtC,wFAAwF;QACxF,yBAAyB;QACzB,iGAAiG;QACjG,gGAAgG;QAChG,8FAA8F;IAChG,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,gFAAgF;oBAChF,qEAAqE;aACxE;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,CAAC;QAC3B,qEAAqE;QACrE,6EAA6E;QAC7E,uBAAuB;QACvB,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,aAAa,CAC9B,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,aAAa,EACrE,EAAE,EACF,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,2EAA2E;QAC3E,2EAA2E;QAC3E,0EAA0E;QAC1E,mCAAmC;QACnC,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACnC,UAAU,EAAE,IAAI;SACjB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
@@ -0,0 +1,45 @@
1
+ import type { ToolDefinition } from "./types.js";
2
+ /**
3
+ * `DELETE /api/v1/repositories/:repository_id/agent_keys/:id` as a tool —
4
+ * shipped in the platform (`specguard/config/routes.rb`,
5
+ * `Api::V1::UserRepositoryAgentKeysController#destroy`, SPGD-1004, `dfb9892`).
6
+ *
7
+ * == The blast radius is the whole stored set
8
+ *
9
+ * An agent key's grant — a repository set and a permission set — is chosen
10
+ * once at mint time and stored ONCE, so revocation cuts the token on EVERY
11
+ * repository in the set, not only the one this call names. On the web a
12
+ * confirm dialog names that set BEFORE the cut; over the API there is no
13
+ * dialog, so the disclosure travels in the response that performs it: count
14
+ * first, then the still-existing names, with `deleted_repository_count`
15
+ * present only when repositories have been deleted since mint and dropped out
16
+ * of the names. The tool passes the body through rather than answering with a
17
+ * summary of its own — the deployment already wrote the confirmation, and a
18
+ * second wording of it is a second fact free to drift from the first.
19
+ *
20
+ * == 200 WITH a body, not the sibling's 204
21
+ *
22
+ * `revoke_repository_api_key` says "a 204 means revoked" because every
23
+ * endpoint this bridge's DELETEs served until now answered empty. This one
24
+ * deliberately does not: the disclosure body IS the confirmation, so the call
25
+ * routes through `deleteJsonObject` — `requestJson`'s parse — rather than
26
+ * `deleteJson`'s raw-text handling. The difference is carried in the
27
+ * description because a caller pattern-matching on the sibling's contract
28
+ * would otherwise misread the shape of success here.
29
+ *
30
+ * == The id is scoped, and both forks are 404
31
+ *
32
+ * `AgentApiKey.live.find` + `covers?` — a key id that is revoked already (a
33
+ * retained revoked row is not a credential) or whose stored set does not cover
34
+ * THIS repository is a 404, never a cross-repository cut. The bridge relies on
35
+ * that server scoping entirely and adds no client-side check of its own, for
36
+ * the reason every tool here states: the server is the gate.
37
+ *
38
+ * == The id source
39
+ *
40
+ * No mint tool exists (deliberately web-only), so the id comes from
41
+ * `list_repository_agent_keys` alone — stated in the description rather than
42
+ * left implicit.
43
+ */
44
+ declare const revokeRepositoryAgentKey: ToolDefinition;
45
+ export default revokeRepositoryAgentKey;
@@ -0,0 +1,104 @@
1
+ import { deleteJsonObject, requireUserApiConfig } from "../support/specguard-api.js";
2
+ import { requireString } from "./args.js";
3
+ /**
4
+ * `DELETE /api/v1/repositories/:repository_id/agent_keys/:id` as a tool —
5
+ * shipped in the platform (`specguard/config/routes.rb`,
6
+ * `Api::V1::UserRepositoryAgentKeysController#destroy`, SPGD-1004, `dfb9892`).
7
+ *
8
+ * == The blast radius is the whole stored set
9
+ *
10
+ * An agent key's grant — a repository set and a permission set — is chosen
11
+ * once at mint time and stored ONCE, so revocation cuts the token on EVERY
12
+ * repository in the set, not only the one this call names. On the web a
13
+ * confirm dialog names that set BEFORE the cut; over the API there is no
14
+ * dialog, so the disclosure travels in the response that performs it: count
15
+ * first, then the still-existing names, with `deleted_repository_count`
16
+ * present only when repositories have been deleted since mint and dropped out
17
+ * of the names. The tool passes the body through rather than answering with a
18
+ * summary of its own — the deployment already wrote the confirmation, and a
19
+ * second wording of it is a second fact free to drift from the first.
20
+ *
21
+ * == 200 WITH a body, not the sibling's 204
22
+ *
23
+ * `revoke_repository_api_key` says "a 204 means revoked" because every
24
+ * endpoint this bridge's DELETEs served until now answered empty. This one
25
+ * deliberately does not: the disclosure body IS the confirmation, so the call
26
+ * routes through `deleteJsonObject` — `requestJson`'s parse — rather than
27
+ * `deleteJson`'s raw-text handling. The difference is carried in the
28
+ * description because a caller pattern-matching on the sibling's contract
29
+ * would otherwise misread the shape of success here.
30
+ *
31
+ * == The id is scoped, and both forks are 404
32
+ *
33
+ * `AgentApiKey.live.find` + `covers?` — a key id that is revoked already (a
34
+ * retained revoked row is not a credential) or whose stored set does not cover
35
+ * THIS repository is a 404, never a cross-repository cut. The bridge relies on
36
+ * that server scoping entirely and adds no client-side check of its own, for
37
+ * the reason every tool here states: the server is the gate.
38
+ *
39
+ * == The id source
40
+ *
41
+ * No mint tool exists (deliberately web-only), so the id comes from
42
+ * `list_repository_agent_keys` alone — stated in the description rather than
43
+ * left implicit.
44
+ */
45
+ const revokeRepositoryAgentKey = {
46
+ name: "revoke_repository_agent_key",
47
+ title: "Revoke repository agent key",
48
+ description: "Revokes one agent key (`sga_…` key) on a SpecGuard repository. IRREVERSIBLE, and the blast " +
49
+ "radius is the key's WHOLE stored set: the grant (repository set + permission set) is stored " +
50
+ "once at mint time, so this one call cuts the token on EVERY repository the key covers, not " +
51
+ "just `repository_id` — check `repository_count` on `list_repository_agent_keys` BEFORE " +
52
+ "cutting a multi-repository key. " +
53
+ "Answers `200` WITH the disclosure body — an `agent_key` block carrying `revoked_at`, " +
54
+ "`repository_count` and the still-existing `repositories` names, plus " +
55
+ "`deleted_repository_count` when some have been deleted since mint — NOT the empty 204 the " +
56
+ "sgk_ sibling `revoke_repository_api_key` serves; the body itself is the confirmation. " +
57
+ "The `key_id` is scoped to `repository_id`: a key whose stored set does not cover this " +
58
+ "repository, or one already revoked, is refused 404, never a cross-repository cut. " +
59
+ "Agent keys have NO mint tool on this bridge (minting is deliberately web-only), so take " +
60
+ "`key_id` from `list_repository_agent_keys` — list first, then revoke. " +
61
+ "Authorization is the `keys_manage` capability — a caller without it is refused 403 in " +
62
+ "SpecGuard's own words. " +
63
+ "Takes `repository_id` (the numeric id `list_repositories` reports) and `key_id`. " +
64
+ "Needs SPECGUARD_USER_API_KEY (an sgu_… key), the same credential the other key-administration " +
65
+ "tools read and a DIFFERENT one from the sgk_… repository key `get_repository_overview` uses.",
66
+ inputSchema: {
67
+ type: "object",
68
+ properties: {
69
+ repository_id: {
70
+ type: "string",
71
+ description: "The repository whose key-administration scope the call is made under — its numeric " +
72
+ "id, as `add_repository` returns and `list_repositories` reports, not the `org/repo` " +
73
+ "handle. The CUT, however, lands on every repository in the key's stored set.",
74
+ },
75
+ key_id: {
76
+ type: "string",
77
+ description: "The id of the agent key to revoke, as served by `list_repository_agent_keys` — " +
78
+ "the only id source, because agent keys have no mint tool on this bridge. Scoped to " +
79
+ "`repository_id`: a key whose stored set excludes this repository, or one already " +
80
+ "revoked, is refused 404.",
81
+ },
82
+ },
83
+ required: ["repository_id", "key_id"],
84
+ // Closed for the reason every tool here states — and on a DESTRUCTIVE path,
85
+ // a silently dropped misspelled argument must not be able to leave the
86
+ // agent believing it revoked a key the call never named.
87
+ additionalProperties: false,
88
+ },
89
+ async run(args, context) {
90
+ const repositoryId = requireString(args["repository_id"], "repository_id");
91
+ const keyId = requireString(args["key_id"], "key_id");
92
+ const api = requireUserApiConfig(context.config);
93
+ // The 200 disclosure body, passed through unreshaped in both halves — the
94
+ // deployment already wrote the confirmation (the stored set, count first),
95
+ // and this is the API's substitute for the web confirm dialog.
96
+ const disclosure = await deleteJsonObject(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/agent_keys/${encodeURIComponent(keyId)}`, context.fetch);
97
+ return {
98
+ text: JSON.stringify(disclosure, null, 2),
99
+ structured: disclosure,
100
+ };
101
+ },
102
+ };
103
+ export default revokeRepositoryAgentKey;
104
+ //# sourceMappingURL=revoke-repository-agent-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revoke-repository-agent-key.js","sourceRoot":"","sources":["../../../src/tools/revoke-repository-agent-key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,MAAM,wBAAwB,GAAmB;IAC/C,IAAI,EAAE,6BAA6B;IACnC,KAAK,EAAE,6BAA6B;IACpC,WAAW,EACT,6FAA6F;QAC7F,8FAA8F;QAC9F,6FAA6F;QAC7F,yFAAyF;QACzF,kCAAkC;QAClC,uFAAuF;QACvF,uEAAuE;QACvE,4FAA4F;QAC5F,wFAAwF;QACxF,wFAAwF;QACxF,oFAAoF;QACpF,0FAA0F;QAC1F,wEAAwE;QACxE,wFAAwF;QACxF,yBAAyB;QACzB,mFAAmF;QACnF,gGAAgG;QAChG,8FAA8F;IAChG,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,qFAAqF;oBACrF,sFAAsF;oBACtF,8EAA8E;aACjF;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,iFAAiF;oBACjF,qFAAqF;oBACrF,mFAAmF;oBACnF,0BAA0B;aAC7B;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,EAAE,QAAQ,CAAC;QACrC,4EAA4E;QAC5E,uEAAuE;QACvE,yDAAyD;QACzD,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;QAC3E,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;QAEtD,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,0EAA0E;QAC1E,2EAA2E;QAC3E,+DAA+D;QAC/D,MAAM,UAAU,GAAG,MAAM,gBAAgB,CACvC,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,eAAe,kBAAkB,CAAC,KAAK,CAAC,EAAE,EAClG,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,UAAU,EAAE,UAAU;SACvB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,wBAAwB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specguard-mcp",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "MCP server exposing SpecGuard suite intelligence to AI coding agents",
5
5
  "license": "ISC",
6
6
  "type": "module",